00xx

01xx

02xx

03xx

04xx

05xx

07xx

08xx

09xx

10xx

11xx

12xx

13xx

00xx

28: Substitution processes

32: Some meditations on Advanced Programming

35: Over de sequentialiteit van procesbeschrijvingen

37: A review of the IBM 1620 Data Processing System

41: Het vectorgeheugen

51: Multiprogrammering en de X8

54: Multiprogrammering en de X8 (Vervolg van EWD51)

57: Multiprogrammering en de X8 (Vervolg van EWD54)

62: Notitie over de aansluiting en de programmering van de teleprinter

65: Over Jansen

68: Some comments on the aims of MIRFAC

69: Over stapeladministratie

70: Over stapeladministratie. II

71: Over pagina-administratie

72: Over trommelpaginatransporten

74: Over seinpalen

75: Over standaardroutines

77: Het controlerende communicatieapparaat

82: Een ponsbandorganisatie voor de X8

84: Over paginaadministratie

86: Bezettingsadministratie der trommelpagina’s

89: Over formal locations

91: Samenvatting van oordeel over het “Voorstel tot aanschaffing van een digitale informatieverwerkende machine voor de afdeling der elektrotechniek”

96: Embedding complex arithmetic

EWD 28

SUBSTITUTION PROCESSES

by

Edsger W. Dijkstra

(Preliminary Publication.)

Januari 1962

Rekenafdeling
Stichting "Mathematisch Centrum"
2de Boerhaavestraat 49
AMSTERDAM
The Netherlands

SUBSTITUTION PROCESSES

A machine defines (by its very structure) a language, viz. its input language: conversely, the semantic definition of a language specifies a machine that understands it. In other words: machine and language are two faces of one and the same coin. I am going to describe such a coin. I leave it entirely to you to decide which of these two aspects of the subject matter of my talk you think the most important as it is rather ridiculous in both aspects. The language I am going to sketch is prohibitively difficult for a human user and the machine I am going to describe is of a perverse inefficiency.

Therefore, if my mental construction, nevertheless, has a right to exist it should derive this from other qualities. My machine derives this, to my taste and judgement at least, from its extreme simplicity and elegance, from the uniform way in which it performs its (at first glance) rather different operations; the justification for my language are its clearness and the unusually high degree of ambiguity, derived from a strict sequential interpretation and an explicit indication in the program to perform operations, which are usually implicitly understood (and therefore apt to misunderstanding). If one wishes to do so one may regard my machine and my language as being conceived for the purpose of clarification.

Before I really start with my description I should like to warn you for two intentional omissions. The system I am going to present is the result of a careful choice between a great number of "neighbouring possibilities". I shall not give my motivations for these choices, I shall even leave the consciously rejected alternatives unmentioned. In other words, I refrain from introducing my system at least in some respects as, say, a "local optimum". As this diminishes the convincing power of my presentation, I personally regret this omission. I have to omit these motivations, however, for the sake of brevity.

The other question I shall not touch is the question how to implement this system with the aid of a conventional machine. One might even raise the question —as I did myself to check that I was not thinking nonsense— whether it can be implemented at all, no matter how crudely. You have to take my word for it that it can be done. I have worked out a method of implementation to a degree that could convince, I think, the most suspicious auditor of the possibility. But it is my intention not to show you the particulars of this implementation, because I had to incorporate too many arbitrary decisions in which, when mentioned, would only divert the attention from the essentials. In particular, the question of storage allocation will remain untouched.

My Machine operates on (and under control of) units of information which I call "words". Without loss of generality I can restrict myself to a finite number of different words, each represented by the same number of bits.

The machine distinguishes between different kinds of words, say numbers, operators, variables and separators. For the time being we shall confine our attention to the first of these, "number words" and "operator words".

A normal arithmetical operation, say the addition or multiplication of two numbers, has two number words as input and one word, also representing a number, as output. The rules according to which a numerical value should be attached to (i.e. derived from the bits of) a number word are embodied in the workings of the arithmetic unit, which has the usual property that these same rules apply to both input and output: the output of the arithmetic unit can be fed into it again at some later stage of the process. As we assume that the properties of the arithmetic unit are constant in time, we may say that the number words have "a fixed meaning". As the fixed interpretation of number words is coupled to the constant properties of the arithmetic unit it is not so surprising that we shall denote the basic arithmetic operations by operator words ("+", "-", "*", "/", etc.) the meaning of which can also be regarded as fixed.

The machine works under control of a program which primarily consists of a string of words. For the time being I shall confine myself to pieces of program prescribing the evaluation of arithmetic expressions.

Let us consider the expression that would normally be written down as

      5   +   39   /   ( 7   +   2   *   3 )   –   6      ;

in the usual postfix notation (also known under the name "Reversed Polish Notation") this would give rise to the following sequence of numbers and operators (successive items in this sequence for the sake of representation on paper being separated by spaces)

      5   39   7   2   3   *   +   /   +   6   –        .

The well known mechanism especially devised for the sequence evaluation of such an expression is what I prefer to call a "stack". (This device has been invented and generalized independently by so many people that it is known now under a great variety of names, such as "push down list", "nesting store", "cellar", "last-in-first-out-memory" etc.) If we regard the above sequence of numbers and operators as the string of words representing a piece of program, the machine reads this string word by word from left to right. If it reads a number word, this number (i.e. a copy of this number word) is added to the top of the stack, if it reads an operator word, the operation in question is performed at the top of the stack. In illustration I give on successive lines the successive pictures of the top of the stack is at the right hand side of the line.

 .....   5     
 .....   5   39
 .....   5   39   7
 .....   5   39   7   2
 .....   5   39   7   2   3
 .....   5   39   7   6
 .....   5   39   13
 .....   5   3
 .....   8
 .....   8   6
 .....   2

and the net result of the execution of this little piece of program is that the value of the expression has been added to the stack.

As clearly shown in the above example the machine starts by copying the program text word by word into the top of the stack. Sooner or later this has to be interrupted, otherwise our machine would just be a copying machine. In the above system the process of copying is interrupted by the occurrence of an arbitrary operator in the program text. The function of an operator, therefore, is a double one: firstly it indicates that the copying has to be interrupted for a while, because now an operation has to be performed, secondly it specifies this operation. I propose to separate these two completely different functions: from now on arithmetic operators are primarily treated in exactly the same way as numbers are treated, i.e. the operator word is copied into the stack as well. Every time the process of copying has to be interrupted I shall indicate this in the program explicitly by the insertion of a special word, introduced now and represented by "E" (from "Evaluate"). My machine now takes the following form. It reads the program text word by word, from left to right. By "reading" is meant the following: if the word read is unequal to "E" a copy of it is added to the stack, if the word read is equal to "E", it is not copied but, instead, the operation takes place as specified (primarily) by the top word of the stack.

According to these rules the program prescribing the evaluation of the expression of our previous example will now consist of the following string of words

      5   39   7   2   3   *   E   +   E   /   E   +   E   6   –   E

and under control of this piece of program text (i.e. when this string of words is "read by the machine") the top of the stack will be in succession as shown in the following lines:

 .....   5
 .....   5   39
 .....   5   39   7
 .....   5   39   7   2
 .....   5   39   7   2   3
 .....   5   39   7   2   3 * 
 .....   5   39   7   6
 .....   5   39   7   6   +
 .....   5   39   13
 .....   5   39   13 /
 .....   5   3
 .....   5   3   +
 .....   8
 .....   8   6
 .....   8   6   –
 .....   2

As said above the machine performs the operation specified by the top word of the stack when it reads the word "E" in the program text. We shall restrict ourselves to such programs that at such a moment the top word of the stack is indeed an operator word (and not, for instance, a number word). Furthermore we shall restrict ourselves to the case that the immediately underlying stack words be in accordance with any requirements that the execution of the operator at the top may set. (For instance, in the case of the binary arithmetic operations illustrated above the two immediately underlying words must be numbers.)

In other words: if an operand of an arithmetic operation happens to be an expression we substitute for this expression its numerical value before the operation is called into action, thus appealing to the fact that, primarily, the arithmetic operations are defined only when supplied with numerical operands.

We regard the replacement of a (sub)expression by its numerical value as a "substitution", and we indicate explicitly when these substitutions have to be performed, although, linguistically speaking, this rather abundant: "3 + 4" will always be equal to "7", no matter when we perform this addition.

This situation, however, radically changes as soon as variables —in contrast to constant numbers— are taken into account. (In the following we shall denote variables with small letters, reserving capital letters for "special words", such as "E" and others, to be introduced below.) Let us assume that we have to compute the value of the expression

     "  x + 4  "

at a moment that the value of the variable x equals 3. This means that in the above expression we must substitute for "x" its numerical value at that moment; only after having done so we can perform the arithmetic substitution (" 3+4 " being replaced by " 7 "). Given something dependent on x (viz. the expression " x+4 ") we create a result (viz. " 7 ") which, thanks to the fact that we have substituted for x its present value, is made independent of the future history of x. We have fixed an "instantaneous picture" of the variable x. Obviously I insist upon indicating explicitly when this instantaneous picture of the variable x (which is varying in time!) has to be taken.

Now we are going to harvest the first fruits of our labor for the mechanism for this explicit indication is already introduced. The piece of program prescribing the evaluation of the expression

     "  x + 4  "

now takes the following form:

     "  x   E   4   +   E  "

and under the above assumption the successive pictures of the stack are

.....   x
.....   3
.....   3   4
.....   3   4   +
.....   7

Our machine invites us to describe the fact that "the value of the variable x equals 3" in slightly other wordings, viz. that the state of the process is such that reading the word "E" at a moment that the top word of the stack is "x" results in the replacement of this top word by the number word "3". The variable on the top of the stack is thus regarded as a variable operator which, upon evaluation, is replaced by something dependent on the state of the process at that moment; in this case it is an operator the execution of which sets no special requirements to the immediately underlying stack words. (The similarity between operators and variables will be further stressed by our next example.)

All words read in the text are added to the stack except the word "E" which causes the machine to perform a substitution. For reason to be explained below we should like to have also the possibility of adding the word "E" to the stack. The framework for this extension, however, is already present. We introduce a special operator, denoted by the word "P" (from "Postponement"), which effects upon evaluation a fixed substitution, vis. its replacement by the word "E". We shall illustrate the use of the operator "P" in the next example.

In this example we have three variables, named "x", "y" and "plinus". Suppose the state of the process to be such that reading "plinus E" generates the word "+" on top of the stack. When reading the text:

      "  x   P   E   y   P   E   plinus   E   P   E  "

the top of the stack will show in succession

.....   x
.....   x   P
.....   x   E
.....   x   E   y
.....   x   E   y   P
.....   x   E   y   E
.....   x   E   y   E   plinus
.....   x   E   y   E   +
.....   x   E   y   E   +   P
.....   x   E   y   E   +   E

and the top of the stack thus contains the string of words which, when read as a piece of program, would effectuate the evaluation of the expression " x + y ". If the value of the variable "plinus" would have been "–" we would have generated (the string of words corresponding to) the expression " x – y ".

What we have done amounts to a partial evaluation of the expression " x plinus y ", the result again being an expression. In our previous examples the final addition to the stack always consisted of a single number. But a number is a trivial example of an expression and generating not only numbers but also more general expressions as intermediate results is therefore an obvious extension of normal practice.

Up till now we have described the generation of words on top of the stack but not what we are going to do with these words. Furthermore we have assumed that with respect to given variable the process could be in such a state that evaluation of this variable would give rise to a previously defined substitution, but how this definition should take place is not mentioned in the above. These two gaps in our picture will both be filled by the introduction of the assignment operators.

For the assignment of a single word value, as in " x := 3 " we could write in our program

      "  3  x  :=  E  "

resulting into the stack pictures:

.....   3
.....   3   x
.....   3   x   :=

Upon evaluation of the assignment operator ":=" the machine investigates the immediately underlying word. This must be the variable to which an assignment has to take place; the next underlying word is assigned to this variable (a process, about which more below) and the three words on top of the stack (which have now been processed) are removed from the stack. Until further notice —i.e. a new assignment to the variable "x"— the evaluation of this variable will result in the replacement of the top word of the stack by the word "3".

But for the interchanging of left and right hand side this is closely analogous to the assignment statement as known in ALGOL 60. But we need more than that for, in general, the assigned value will not consist out of a single word, but out of a string of words and we must therefore have a means of indicating how deep in the stack the assigned value extends. The simplest way to do this is to insert in the stack a marker, say the special word "T" (from "Terminal") at the bottom side of the assigned value. Furthermore we introduce another assignment operator ":-" (called the "string assignment" in contrast to the "word assignment" introduced in the previous paragraph). Upon evaluation of this operator the machine investigates the top of the stack in downward direction. The first word (immediately under the operator ":-") must be the variable to which a value has to be assigned. Thereafter the machine continues its word by word investigation in the downward direction until it meets the special marker "T": the words passed in this way form together the string that acts as the assigned value.

The simplest way to add a "T" to the stack would be just to insert the word "T" in the proper place in the program under control of which the stack is being filled. This arrangement, however, will not do; for reasons to be explained later we need the possibility of generating a "T" on top of the stack under control of a program that itself does not contain this word. We can do this with the same trick that enabled us to generate an "E" on top of the stack. We introduce a new operator, denoted by the word "S" (say from "Separator" or because it precedes the "T" in the alphabet) which upon evaluation is replaced by the word "T" and we make it a rule that this will be the only way in which words "T" are added to the stack.

Using all this we have an alternative to write the assignment statement " x := 3 ", viz.

      "  S   E   3   x   :-   E  "

giving in the top of the stack in succession:

.....   S
.....   T
.....   T 3
.....   T 3 x
.....   T 3 x :-
.....

The net effect of this is equivalent to the previous form using the word assignment ":=".

Let us use the more powerful assignment in an example which is an extension of one of our earlier ones, viz. the one describing the partial evaluation of the expression " x plinus y ". The result of this partial evaluation was an expression depending on the variables "x" and "y" and suppose that we want to call this expression "z". For this purpose we write in the program:

      " S   E   x   P   E   y   P   E   plinus   E   P   E   z   :-   E " .

When the last "E" of this string is going to be read the top of the stack will be as follows (under the same assumption with respect to the value of "plinus":

.....   T   x   E   y   E   +   E   z   :-

and after the execution of this assignment the above words will have been removed from the stack, the word "T" inclusive. Until further notice the evaluation of the variable "z" will imply the execution (the "reading") of the string assigned to it. Upon evaluation of the variable "z" the machine therefore must have access to the first word of this string; when it starts reading this string, however, it must detect the last word of this string. We propose that the assignment operator sees to this by adding again an end marker and for this purpose we can use the very same word "T". Upon evaluation of the variable "z" the string assigned to it will be read as a piece of program, from left to right until the end marker "T" is met. The new situation resulting from the last assignment can conveniently be represented by:

      "   z   →   x   E   y   E   +   E   T   "      .

In exactly the same way our previous assignments

      "   3   x   :=   E   "    or    "   S   E   3   x   :-   E   "

will both give rise to the situation, represented by

      "   x   →   3   T   "      .

One of the most illuminating aspects of this arrangement is that the usual distinction between "numbers" and "instructions" has completely vanished. The value of a variable is defined as a piece of program, evaluation of this variable implies the execution of this piece of program.

Furthermore we should like to draw attention to a certain form of duality between the assignment on the one hand and reading a text on the other. When the machine reads a piece of program text, the top of the stack is filled under control of this program text. In the assignment "readable text" is created under control of the contents of the stack. The duality can also be illustrated by taking into consideration the accessibility requirements. The words in the stack need only be accessible in the direction from top to bottom. If an assignment statement converts the top of the stack into readable text, however, the consecutive words thereby become accessible in the other direction.

Finally, the stack is reserved for "anonymous intermediate results", whereas readable text —in principle, at least— is always "named", for we create it by assigning it to a variable.

The attentive reader will have noticed that, along with the representation of the value of a variable, we have silently introduced two more complications in our machine.

The first one, the occurrence of the word "T" in program text and the machine's "immediate reaction" to it is a relatively simple one. As we have described the organization, the word "T", when read in the text, is not copied on top of the stack! Instead, it causes the machine to go on reading at the first word following in the string after the "E" that caused this evaluation of the variable in question. In other words, it acts as a "Return" at the end of a closed subroutine.

But the evaluation of a variable may call for the evaluation of other variables (even for the evaluation of itself): the pragmatic definition of the evaluation of a variable is basically a recursive one and the mechanisms one needs to follow a recursive definition is ..... another stack! I call this second stack "the stack of activations" in contrast to the first which I call "the anonymous stack". One of the functions of the stack of activations is to control the reading process. When the evaluation of a variable starts the stack of activations expands, when the corresponding word "T" is read, it shrinks to its previous size. (In the usual terminology of machine structure: the stack of activations contains a stack of "order counter values", its top element being, by definition, "the present order counter"; in the same terminology its older elements act as a stack containing the "return addresses".)

Note. We could try to merge our two stacks into one. This merging would present itself in a completely natural fashion if the two should expand and shrink "in phase" with one another. In general, however, this is not the case and trying to merge the two stacks into a single one would give a highly unnatural construction.

We shall use the stack of activations for yet another purpose, to satisfy a very fundamental need, viz. the creation of new variables. In the above I have used special words ("x", "y", "plinus" etc.) to denote variables and I have carefully avoided to use the term "identifier". I have used the term "variable" in connection with a single, unique object, existing for some period of time and capable of taking on different values in succession. This concept of a variable is to be distinguished carefully from the "identifier" as used in ALGOL 60, because one and the same identifier may be used to point to a host of objects, to a great number of different variables

First of all we meet the fact that one and the same identifier may play different roles thanks to the fact that it occurs in more than one declaration. A lexicographical rule then tells us which one of these declarations applies everywhere, where the identifier in question may be used. This form of multiple use of one and the same identifier could be removed by a simple process of renaming.

But there is a much more subtle case of "multiple use of one and the same identifier", viz. as soon as a certain block occurs in one or more nested activations (as in the case of a a recursive procedure). In other words: one and the same identifier then refers sometimes to this variable, sometimes to another.

In actual fact: the identifier stands for a variable and in order to indicate clearly for which variable it stands I intend to denote explicitly the moment when a variable has to be substituted for an identifier.

For the sake of convenience —to be more exact: convenience for the machine and not for the hypothetical user— I intend to use the same identifiers for the local variables of every activation. (What I call "an activation" is closely analogous to a block or procedure body, as known in ALGOL 60.) I use for this purpose the special identifier words "L0", "L1","L2", etc..

If the machine starts the evaluation of a variable, the stack of activations increases with one item. At the start this item also contains a note that up till now no local variables have been introduced in this activation.

If the machine reads the word "E" at a moment that the top of the anonymous stack contains one of the identifier words (say "L2") then it investigates the top item of the stack of activations. If it is the first time that this identifier has to be evaluated in the present activation the machine creates a new variable for it (and may give this variable an empty value) and makes in the youngest item of the stack of activations a note to this effect. Then it replaces the top word of the anonymous stack by the variable just created for it. At a next evaluation of the same identifier at a moment that the same activation is still (or again) the present one, the machine finds in the top item of the stack of activations the note left there at the first evaluation of this identifier and the top word of the stack is replaced by the same variable.

Now we can show a more complicated example. Let the values of the variables "x", "y" and "complus" be as represented by:

 "   x   →   10   23   T   "

 "   y   →     5    –2   T   "

"   complus   →   L0   E   :=   E

                L1   E   :=   E

                L2   E   :=   E

                L1   E   E   +   E

                L2   E   E   L0   E   E   +   E

                T   "      .

If we now read the text

      "   S   E   x   E   y   E   complus   E   z   :-   E   "

the net effect will be that we can represent the new value of "z" by:

      "   z   →   15   21   T   "

and what we have done can be interpreted as the addition of two complex numbers.

In ALGOL terminology: "complus" is a procedure with four numerical parameters, all called by value. The simple structure of the process allows the first of these to remain anonymous even in the procedure body. Furthermore, it is a kind of "type procedure", be it one that, syntactically speaking, takes the place of two primaries.

Let me end with a trivial example. Suppose that we want to write "plus" instead of "+". After the assignment

       "   S   E   +   P   E   plus   :-   E   "

which gives rise to the situation

       "   plus   →   +   E   T   "

the expressions

       "   x   E   y   E   plus   E   "

and

       "   x   E   y   E   +   E   "

are completely equivalent. This example is included to show as clearly as possible the arbitrariness of our primitives.

Conclusion.

I am fully aware that the sketch is definitely incomplete. Particularly conditional reaction and some equivalent of the go to statement should be incorporated if one wishes to make a system out of this. For the moment I leave these out and I do so for two reasons. Firstly for the sake of brevity and secondly because I have not decided yet: for I know of several possible ways but none of them fully satisfies me.

With some versions of these facilities I have made slightly more elaborate programs. They showed me both the power and the weakness of my Language, its power being its flexibility and its unambiguity, its weakness being the fact that using it intelligently proved to be far above at least my powers.

If nevertheless I claim attention for this project I don't do so only because it charms me and may charm others as well. This report is the condensation of my meditations after we had completed our implementation of ALGOL 60. This implementation was conceived at high speed and the main justification for the numerous decisions taken in those hectic months was the recognition that our conceived constructions would lead to our goal and would do the job, in some way or another. The Machine described in this report, however, represents an extreme of the continuous spectrum of possible implementations of an algorithmic language which (as is the case with ALGOL 60) caters for recursiveness. In this quality it has been very clarifying for me personally: it has helped me a great deal in the appreciation of the various (initially disconnected) tricks we have incorporated intuitively and it has clearly shown us a number of alternative solutions. Therefore the hope is justified that translator construction and machine design in the future will benefit from these considerations.

Furthermore, the Machine presented here is so ridiculously inefficient that every practical implementation of a practical algorithmic language in all probability can be regarded as an optimization of it, an optimization which is permissible thanks to certain restrictions in the language. It may be useful to compare a proposed language with my language; during the process of language construction it may be helpful in the timely detection of "expensive features". Whether such an expensive feature will be included or not is more or less a political question but quite apart from how such a question is answered it is nice to know what one is doing.

Finally the language described in this report (or a language devised along similar lines) may prove to be a suitable means for the formalization of the semantic definition of an algebraic language. The lack of such a rigorous semantic definition is one of the recognized shortcomings of the official "Report on the Algorithmic Language ALGOL 60" and having seen the tremendous amount of trouble caused by this defect, I most sincerely hope that this report will contribute to the effort to avoid this mistake the next time an algorithmic language will be devised.

Acknowledgements.

A great number of people have contributed to this, consciously or not. Besides all my colleagues at the Computation Department of the Mathematical Centre, Amsterdam, I should like to mention Dr.M.V.Wilkes and Prof.J.McCarthy, who proved to be inspiring listeners, and in particular Mr.M.Woodger: his judgement and his comments (I remember his lack of enthusiasm for my first trials in this direction now with gratitude) have been a great help for me.

Transcription by Ken Dyck.
Last revised on Mon, 17 Dec 2007.

EWD32

Some meditations on Advanced Programming

In case you expect me to give a complete, well-balanced and neutral survey of the advanced programming activities of the world, I must warn you that I don't feel inclined, nor entitled to do so.

My title already indicates that I am going to meditate on the subject, which is something quite different from giving a survey. Perhaps the title of my paper would have been more outspoken if it had been "My meditations on Advanced Programming" for I intend to present a picture in the way I wish to see it; and I should like to do so in all honesty without any claim to objectivity. I intend to do so because I have a feeling that I serve you better by giving you an honest personal conviction than by presenting you with the colourless average of conflicting current opinions of other people.

You will observe that I fail to give you a generally acceptable definition of the subject "Advanced Programming". I think that in my own appreciation of the subject the description "Advancing Programming" would have been a better qualification. I do like many activities which are worthy, I think, of the name "Advanced Programming" but I don't like these activities so much for the sake of their output, the programs that have resulted from them, as for what these activities can teach us. And if I am willing to study them, to meditate upon them, I am willing to do so in the hope this study or these meditations will give me a clearer understanding of the programmer's task, of his ends and his means. Therefore I should like to draw your attention in particular to those efforts and considerations which try to improve "the state of the Art" of programming, maybe to such an extent that at some time in the future we may speak of "the state of the Science of Programming".

And a little look around us will convince us that this improvement is very urgent, for on the whole the programmer's world is a very dark one with only just the first patches of a brighter sky appearing at the horizon. For the present-day darkness in the programmer's world the programmers themselves are responsible and nobody else. But before we put too much blame on them, look for a moment how their world came into existence.

When the first automatic electronic computers started to work more or less properly, mankind was faced with a new technical wonder, with a most impressive achievement of technical skill. And, as a result, everybody was highly impressed and rightly so. Under these circumstances it was completely natural that the structure of these early machines was mainly decided by the technical possibilities at that time. And under these circumstances it would have been an undreamt of undecency if programmers had dared to suggest that those clever designers had not built at all the machines that programmers should like to have. Therefore this thought hardly struck the programmers' minds. On the contrary: faced on the one hand with the new computers and on the other hand heaps of problems waiting for their solution, they have done their utmost best to accomplish the task with the equipment that had become available. They have accepted the full challenge. The potentialities of the computers have exhausted to slightly beyond their utmost limits, the nearly impossible jobs have yet been done by using the machines in all kinds of curious and tricky ways, which were completely unintended and even not foreseen by the designers. In this atmosphere of pioneering, programming has arisen not as a science but as a craft, as an occupation where man, under the pressure of the circumstances was guided more by opportunism than by sound principles. This —I should like to call it "unhygienic"— creativity and shrewdness of the programmers has had a very bad influence on machine designers, for after some time they felt free to include all kinds of curious facilities of doubtful usability, reassuring themselves by their experience that, no matter how crazy a facility they provided, always a more crazy programmer would emerge that would manage to turn it into something profitable —as if this were sufficient justification for its inclusion.

In the mean time programming established itself as a discipline where on the whole standards for quality were extremely crude and primitive. The main —and often only— possible virtues of a program were its quantitative characteristics, viz. its speed and its storage requirements. Space and time became the exclusive aspects of efficiency. And in various places these standards are still in full vigour: not so long ago I heard of two cases, one where a machine was not bought because its multiplication speed was too low —and this may be a valid argument— and another case where a certain machine was selected because its multiplication was so fast. And this last decision was taken without the validity of this criterion being questioned.

Apart from the programs that have been produced, the programmers' contribution to human knowledge has been fairly useless. They have concocted thousands and thousands of ingenious tricks but they have given this chaotic contribution without a mechanism to appreciate, to evaluate these tricks, to sort them out. And as many of these tricks could only be played by virtue of some special property of some special machine their value was rather volatile. But the tricks were defended in the name of the semi-god "Efficiency" and for a long time there was hardly an inkling that there could be anything wrong with tricks. The programmer was judged by his ability to invent and his willingness to apply tricks. And also this opinion is still a wide-spread phenomenon: in advertisements asking for programmers and in psychological tests for this job it is often required that the man should be "puzzle-minded", this in strong contrast to the opinion of the slowly growing group of people who think it more valuable that the man should have a clear and systematic mind.

But, as I told you, the sky above the programmer's world is brightening slowly. Before I am going to draw your attention to some discoveries that are responsible for this improvement I should like to state as my opinion that it is relatively unimportant whether these discoveries are really new discoveries or whether they are rediscoveries of things perfectly well known to people like, say, Turing or von Neumann. For in the latter case the important and new thing is that a greater number of people become aware of such a fact and that a greater number of people realize that these considerations are not just theoretical considerations but that they may have tangible, practical results. In this light one might feel inclined to summarize the achievements of advanced programming as some purely educational successes: "At last programmers have started to educate one another to at least some extent.". I shall not protest against this summary provided one agrees with my opinion that mutual education is one of the major difficult tasks of mankind.

One important rediscovery is that of the well-known equivalence of designing a machine and making a program. At this moment one might well ask oneself why I ask attention for such a well-known fact. Well, I have very good reasons to do so, for it has a great potential influence which is often overlooked: it enables the man that regards himself as a programmer to contribute to the field that is generally regarded as "machine design". And this is a very fortunate circumstance.

Some fifteen or ten years ago the design and construction of a new, unique computer was a well-established and respectable occupation for University Laboratories. And each of these "laboratory machines" were, in their own private ways, revolutionary contraptions. From then onwards this custom died out and design and construction of automatic computers became more and more an exclusively industrial activity. Five years ago most of us felt this as a perfectly natural development: construction of new computers became an extremely costly affair and it was generally felt that the time had come to leave this activity to the specialized industries. Now, five years later, we can only regret this development, for the computers on the market today are, on the whole, very disappointing. All right, they are faster, they are much more reliable than the old laboratory machine, but, on the other hand, they are often boring, uninspiring and hopelessly old-fashioned as well. For instance, the commercial requirement that all the programs made for some older machine from the same manufacturer should, without any modification, be acceptable to the new machine has led to the design of new machines the order code of which included the order code of the previous one in its entirety. Such a policy, however is a never failing mechanism to prolong the lifetime of previous mistakes. Some time ago we were offered the slogans about "the computers of the second generation", but to my taste many of them were as dull as their parents. Apparently a nice computer has at least one property in common with a gentleman, viz. that it takes at least three generations to produce one! Most of the industries, particularly the bigger ones, proved to be very conservative and reactionary. They seem to design for the customer that believes the salesman who tells him that machine so-and-so is just the machine he wants. But the poor customer who happened to know already, all by himself, what he wants is often forced to accept a machine with which he is already disgusted before the thing is installed in his establishment. Under the present circumstances, it is, commercially speaking, apparently not too attractive to put a nice computer on the market. This is a sorry state of affairs, many a programmer suffers regularly from the monstrosity of his tool and we can only hope for a better future with nicer machines. In the mean time he can program; taking some efficiency considerations for granted he can force his machine to behave as he wishes: when making a programming system he designs a machine as it should have been. Thanks to the logical equivalence between designing a machine and making a program, programmers can contribute to future machine design, by exploring on paper, in software, the possibilities of machines with a more revolutionary structure.

The equivalence of making a program and designing a machine has another, may be far-reaching consequence of a much more practical nature. It is not unusual to regard a classical computer as a sequential computer coupled to a number of communication mechanisms for input and output. Such a communication mechanism, however, performs in itself a sequential process - usually of a cyclic nature, but that feature is of no importance now. For this reason we can regard a classical machine, communication mechanism included, as a group of loosely connected sequential machines, with interlocks, where necessary, to prevent them to get too much out of phase with one another. The next step is to use the central computer not for only one sequential process but to equip it with the possibility to divide its attention between an arbitrary number of such loosely connected sequential processes. One can do so with complete preservation of the symmetry between the sequential processes to which a distinct piece of hardware corresponds on the one hand and those taken care of by the central computer on the other hand. Or even by one of the central processors, as the case may be. The difference between a modest and an ambitious installation may be that a couple of sequential processes, that in the modest installation are performed by the central computer, are performed by private hardware in the ambitious installation. But the above mentioned equivalence between designing a machine and making a program, between performing a process either by hardware or by software, should be exploited to guarantee that the program acceptable for the one installation is also acceptable for the other. The above considerations are important because a machine rigorously designed along the above lines would greatly facilitate the manufacturer's task to equip his product with the required software. The moral of this is that, if at the present moment many manufacturers have great difficulties in fulfilling their software obligations and if one of the main sources of their trouble is that no two installations of the same machine are identical, their trouble could very well be a self-inflicted pain.

In this connection I should like to mention that I am fully aware of the fact that my previous picture of the commercial computer market was somewhat one-sided. Many of you will realize that at least one of the commercial products shows a great number of the "nice properties" just mentioned. In my opinion, this particular computer should be regarded as one of the brightest patches in the sky.

Now I am turning my attention to one of the most important facts that happened in the programmers world since the UNESCO Conference in 1959, viz. the publication of the famous "Report on the Algorithmic Language ALGOL 60", edited by Dr Peter Naur. I shall not discuss here the merits of the language ALGOL 60, nor shall I go into the question whether it has reached its original aims or not. I intend to restrict myself to a discussion of the consequences of this publication, of the influence it has had in the world of programming. For, this influence has been tremendous. In a short summary I could formulate as follows: through its merits ALGOL 60 has inspired a great number of people to make translators for it, through its defects it has induced a great number of people to think about the aims of a "Programming Language". ALGOL 60, in all probability and in accordance with the wish of its authors, will be superseded by some better language in due time, but much, much longer we shall be able to trace its educational effects.

Programming language, translator and computer, these three together for a tool, and in thinking about this tool as a whole, new dimensions have been added to the old concept of "reliability". In connection with the third of the three components, viz. the computer, concern about its reliability is as old as computers themselves, the acceptance test is a well-known phenomenon.

But what is the value of an acceptance test? It is certainly no guarantee that the machine is correct, that the machine acts according to its specifications. It only says that in these specific test programs the machine worked correctly. If the design is based on some critical assumption, we can only conclude, that in these test programs the corresponding critical situations apparently did not arise. If the design still contains logical errors, we can conclude, that in these specific test programs these logical errors apparently did not matter. But as a user, we are not interested in the test programs, we are interested in our own programs. And from the successful acceptance test we should like to conclude that the machine works correctly in our programs also! But we cannot draw this conclusion. The best thing that a successful acceptance test can do is to strengthen our believe in the machine's correctness, to increase the plausibility that it will perform any program in accordance with the specifications. The basic property of the program of the user is that it will certainly require from the machine to perform actions it has never done before. Machine designers have seen this difficulty quite clearly. They have realized that the successful acceptance test has only value as far as future programs are concerned, provided the actions performed in the test programs can be regarded as representative for all its possible operations. And they can only be representative by virtue of the clean and systematic structure of the machine itself. The above is common knowledge among machine designers; curiously enough, this is not true for translator makers, for whose activity the same considerations apply.

In order that the tool, consisting of programming language, translator and machine, be a reliable tool, it is, of course, mandatory that all its components be reliable. One should expect that the translator maker, who in contrast to the machine designer has to deal with logical errors only, should do his job at least as well as the machine builder. But I am afraid that the converse is true. At the Rome Conference last spring I was surprised to hear that the extensive translators for symbolic languages constructed in the United States continued to show up errors for years. I was shocked, however, when I saw the fatalistic mood in which this sorry state was accepted as the most natural thing in the world. This same attitude is reflected in the terms of reference of an ISO committee which deals with the standardization of programming languages: there one finds the recommendation to construct for any standard language a set of standard test examples on which any new translator for such a language could be tried out. But no hint that the correct processing of these standard test examples obviously is only a trivial minimum requirement, no trace of the consideration that our belief in the correctness of a translator can never be found on successful tests alone, but is ultimately derived from the clean and systematic structure of the translator and from nothing else. In deciding between reliability of the translation process on the one hand and the production of an efficient object program on the other hand the choice often has been decided in favour of the latter. But I have the impression that the pendulum is now swinging backwards.

For instance: if one gets a much more powerful machine in one's establishment than the one one had before, one can react to this in two different ways. The classical reaction is that the new machine is so much more expensive, that it is ever so much more mandatory that no expensive computing time of the new machine should be wasted, that the new machine should be used as effectively as possible, etc. etc.. On the other hand one can also reason as follows: as the new machine is much faster, time does not matter so very much any more; as in the new computer the cost per operation is less than in the previous one, it becomes more realistic to investigate whether we can invest some of the machine's speed in other things than in sheer production, say in convenience for the user —what we do already when we use a convenient programming language— or in elegance and reliability of the translator, thus increasing the quality of our output.

Also it is more widely recognised now than a couple of years ago that the construction of an optimizing translator is, essentially, a nasty job. Optimizing means improving the object program, i.e. making a more efficient object program than the one produced by straightforward, but reliable and trustworthy translation techniques. Optimization means "taking advantage of a special situation". Well, if one optimizes in one respect, it is not an impossible burden to verify that the shortcut introduced in the object program does not lead to undesired results. If, however, one optimizes in two different respects, the duty of verification becomes much harder, for one has to verify not only that the two methods are correct in themselves, but one must also check that they do not interfere with one another. If one optimizes in more different respects, the task to create confidence in the translator's correctness explodes exponentially. As a result it is no longer possible to recommend a computer by pointing to, say, the size of the translators available for it. On the contrary: the more extensive and shrewd a translator is, the more doubtful is its quality. And further: for the necessity of such extensive optimization efforts one might, finally, blame the computer in question: if we really need such an intricate process as an optimizing translation to load our programs one feels inclined to defend the opinion that, apparently, the computer is not too well suited for its task. In short, the construction of intricate optimizing translators is an act the wisdom of which is subject to doubt and there is certainly a virtue in efforts to remove the need for them, e.g. the design of computers where these optimization tricks don't pay, or at least don't pay so much.

With regard to the structure of a translator, ALGOL 60 has acted a great promoter of non-optimizing translators. The fact is that the language as it stands is certainly not an open invitation for optimization efforts. For those that thought they knew how to write optimizing translators —be it for less flexible languages— this has been one of the reasons to reject ALGOL 60 as a serious tool. In my opinion these people bet on the wrong horse. I don't agree with them although I can sympathize with them: if one has solved a problem one tends to get attached to it and if one likes one's solution for it, it is, of course, a little bit hard to switch over to an attitude in which the problem is not considered worth solving any more. The experience with ALGOL 60 translation has taught us still another thing. Some translator makers could not refrain from optimizing, but finding the task as such too difficult to do they tried to ease matters by introducing additional restrictions into the language. The fact that their translators had only to deal with a restricted language, however, did not speed up the translator construction: the task to exploit the restrictions to full advantage has prevented this.

Smoothly we have arrived at the third component of our tool, viz. the language: also the language should be a reliable one. In other words it should assist the programmer as much as possible in the most difficult aspect of his task, viz. to convince himself —and those others who are really interested— that the program he has written down defines indeed the process he wanted to define. Obviously the language rules may not contain traps of the kind of which there are still some in ALGOL 60, where, for instance, "real array" may be abbreviated into "array", but "own real array" may not be abbreviated into "own array". The next obvious requirement is that those rules which define a legal text don't leave any doubt as to whether a given text is legal or not, e.g. if there should be a restriction with respect to recursive use of a procedure, it should be clear under what conditions these restrictions apply, in particular when the term "recursive use" applies. I mention this particular example because here it is by no means obvious. Finally, when faced with an undoubtedly legal text we want to be quite sure what it means. This implies that the semantic definition should be as rigorous as possible. In short: we need a complete and unambiguous pragmatic definition of the language, stating explicitly how to react to any text. So much for the necessity that the tool be reliable.

As my very last remark I should like to stress that the tool as a whole should have still another quality. It is a much more subtle one; whether we appreciate it or not depends much more on our personal taste and education and I shall not even try to define it. The tool should be charming, it should be elegant, it should be worthy of our love. This is no joke, I am terribly serious about this. In this respect the programmer does not differ from any other craftsman: unless he loves his tools it is highly improbable that he will ever create something of superior quality.

At the same time these considerations tell us the greatest virtues a program can show: Elegance and Beauty.

transcribed by Tristram Brelstaff
revised 20-Sep-2012

EWD35

Over de sequentialiteit van procesbeschrijvingen.

Het is niet ongebruikelijk, wanneer een spreker zijn voordracht begint met een inleiding. Omdat ik mij hier mogelijk richt tot een gehoor, dat als geheel minder vertrouwd is met de problematiek, die ik wil aansnijden en de terminologie, die ik zal moeten gebruiken, wilde ik in dit geval ter introductie graag twee inleidingen houden, nl. een om de achtergrond van de problemen te schilderen en een tweede, om U een gevoel te geven voor de aard van de logische problemen, die wij tegen het lijf zullen lopen.

Mijn eerste inleiding is een historische. Eerst moet ik U vertellen, wat U zich moet voorstellen bij een sequentiële procesbeschrijving. U kent allen dergelijke procesbeschrijvingen. Beschouw bv. de beschrijving van de constructie van de hoogtelijn uit het hoekpunt C van de driehoek ABC. Deze kan als volgt luiden:

1) trek de cirkel met middelpunt A en straal = AC;
2) trek de cirkel met middelpunt B en straal = BC;
3) trek de rechte, die bepaald is door de snijpunten van de onder 1) en 2) genoemde cirkels.

Dit is een beschrijving ten bate van iemand, wiens "parate kennis" de constructie van de hoogtelijn niet omvat; ten bate van hem is de constructie van de hoogtelijn opgebouwd uit een aantal handelingen van een beperkter repertoire, handelingen, die hij in de opgegeven volgorde, de een na de ander, dwz. sequentieel, kan uitvoeren. Het zal het oplettende lezertje niet ontgaan zijn, dat wij hierbij meer gespecificeerd hebben, dan strikt noodzakelijk: het is wel essentieel, dat handeling 3) pas uitgevoerd wordt, nadat handelingen 1) en 2) voltooid zijn, handelingen 1) en 2) hadden best in de omgekeerde volgorde plaats mogen vinden, sterker, een tekenaar. die twee passers tegelijkertijd bedienen kan, bij wijze van spreken met elke hand één, mag handelingen 1) en 2) simultaan uitvoeren. Maar deze vrijheid is in onze procesbeschrijving geheel onder tafel geraakt.

Nu een numerieker voorbeeld, dat iets meer aansluit bij de denkwereld, waarin de straks te behandelen problemen actueel zijn geworden. Gegeven de waarden van de variabelen a, b, c en d, gevraagd te berekenen de waarde van de variabele x, bepaald door de formule "x:=(a+b)*(c+d)". Wanneer het uitvoeren van deze waardetoekenning niet tot het primitieve repertoire van de rekenaar —en denkt U nu langzamerhand maar aan de rekenmachine— behoort, dan dient dit rekenvoorschrift uit elementairdere stappen opgebouwd te worden, bv.:

1) bereken t1:= a + b;
2) bereken t2:= c + d ,
3) bereken x:= t1 * t2.
Dit rekenvoorschrift bevat precies dezelfde overbepaaldheid als onze hoogtelijn-constructie: de volgorde van de eerste twee stappen doet niet ter zake, zij zouden zelfs simultaan uitgevoerd kunnen worden.

De bovenstaande procesbeschrijving is representatief voor de werkingswijze van meer klassieke rekenautomaten. Het repertoire van elementaire operaties is, omdat voor elke operatie speciale technische voorzieningen vereist zijn, eindig en om financiële redenen zelfs heel beperkt; deze machines danken hun enorme flexibiliteit aan het feit, dat willekeurig ingewikkelde algebraïsche expressies als boven geïllustreerd uitgewerkt kunnen worden door een sequens van dergelijke elementaire operaties. Inhaerent aan deze sequentiële beschrijving van het proces is, dat men meer specificeert, dan strikt noodzakelijk. Dit heeft lange tijd niet gehinderd, maar in de laatste jaren is daar verandering in gekomen, en wel door twee oorzaken: verandering van de structuur van machines en de komst van een nieuwe klasse problemen, waarvoor men deze machines zou willen inzetten.

De klassieke sequentiële machine doet "een ding tegelijk" en verricht de ene functie na de andere. Om der wille van de efficiency is: men voor specifieke functies meer specifieke apparatuur gaan bouwen, maar als je er dan aan vast houdt, dat de verschillende operaties strict sequentieel uitgevoerd zullen worden, dan dringt zich van een machine plotseling het beeld op van een samenspel van N organen, waarvan er op elk discreet ogenblik maar 1 of 2 werken. Als N groot is, betekent dit, dat het merendeel van je machine het merendeel van de tijd stilstaat en dat is kennelijk niet de bedoeling.

De tweede oorzaak is de komst van een nieuwe categorie van problemen; oorspronkelijk werden rekenautomaten alleen gebruikt voor van te voren volledig gedefinieerde processen, en de machine kon het proces vervolgens op zijn eigen houtje, in zijn eigen tempo uitvoeren. Zodra men echter het informatieverwerkende proces samen wil laten spelen met een of ander ander proces —bv. een chemisch proces, dat door de rekenautomaat gestuurd moet worden— dan treden er heel andere problemen op. Aanhakend bij ons voorbeeld van de berekening van x:=(a + b)*(c + d) zijn we dan niet meer in de omstandigheid, dat het er niet meer toe doet, welke som het eerste gevormd wordt. Als de gegevens a,b,c en d op onbekende momenten door de omgeving van de rekenautomaat verschaft worden en het de taak van de machine is, om de waarde van x zo snel mogelijk af te leveren, dan betekent dit, dat de automaat een deelberekening maar vast uit moet voeren, zodra de daarvoor vereiste gegevens binnen zijn: welke optelling men dan eerst uitgevoerd wil hebben, zal afhangen van de volgorde, waarin de gegevens a, b, c en d ter beschikking komen. Dit was mijn eerste inleiding en ik hoop U hiermee een idee gegeven te hebben, van wat U zich bij een sequentiële procesbeschrijving voor moet stellen, en waarom de vraag gesteld is naar minder strict sequentiële procesbeschrijvingen.

Nu mijn tweede inleiding, die bedoeld is om U van meet af aan enig idee te geven van de logische problemen, die we door het verlaten van de stricte sequentialiteit ons op de hals zullen halen.

Evenals in een normaal stuk algebra variabelen met letters, algemeen "namen", aangeduid worden, heeft men in het proces van informatieverwerking aanhoudend de plicht tot identificatie, de plicht om bij de naam het hierdoor benoemde object te vinden. Onder omstandigheden zou men graag willen beschikken over het selectieproces, waarover de juffrouw in de klas beschikt, wanneer zij zegt "Jantje, kom eens voor het bord." Aangenomen, dat de klas als geheel oplet en gehoorzaam is, werkt dit proces feilloos onder de aanname, dat er 1 en slechts 1 Jantje in de klas zit. Het bijzondere van dit selectiemechanisme is, dat het werkt ongeacht het aantal kinderen in de klas. Deze idylle is helaas technisch niet of hoogstens gebrekkig te verwezenlijken, en wij krijgen een probleemstelling, die meer in overeenstemming is met de werkelijkheid, wanneer de kinderen niet spontaan op het noemen van hun naam reageren en de juffrouw, wanneer zij Jantje voor het bord wil hebben, genoodzaakt is om Jantje bij het oor te vatten en daaraan voor het bord te slepen. Als dit nu een ouderwetse school is, waarin ieder kind zijn vaste plaats in de klas heeft, dan kan de juffrouw, als zij aan het begin van het jaar de kinderen op hun plaats gezet heeft, ze voor haar eigen gemak herdopen, en de naam "Jantje" —die voor het vinden van het jongetje niet erg behulpzaam is— vervangen door een identificatie, die blijkens zijn structuur meteen definieert, welk oor ze vatten moet: ze kan het jongetje noemen "derde rij, tweede bank". Dit is in wezen de techniek, die in klassieke automaten bij klassieke toepassingen gevolgd wordt. In modernere toepassingen kan men dit niet meer doen, en moet men bv. opgewassen zijn tegen de problemen, die de juffrouw krijgt, als de kinderen kunnen kiezen, waar ze gaan zitten.

Om het de juffrouw niet onmogelijk te maken, nemen we aan dat elk der onwillige kinderen een naamplaatje opgespeld heeft. AIs de juffrouw nu Jantje voor het bord wil hebben, moet zij dus Jantje opzoeken. De juffrouw werkt sequentieel, kan slechts een naamplaatje tegelijkertijd lezen, en de juffrouw werkt systematisch: zij heeft voor zichzelf de banken op een of andere manier uniek geordend en als zij Jantje wil hebben, dan loopt zij de banken in deze volgorde af, zich steeds afvragend "Ben jij Jantje?", zo nee, dan gaat ze naar de volgende bank. Dit proces werkt feilloos, mits wij kunnen garanderen, dat de kinderen tijdens de rondgang van de juffrouw niet gaan verzitten, mits wij kunnen garanderen, dat de twee processen "kindlocalisatie" en "kinderpermutatie" niet simultaan uitgevoerd worden. Want U begrijpt ook wel, dat Jantje, zodra hij door heeft, dat hij de gezochte figuur is, achter in de klas gaat zitten en zodra de juffrouw de voorste helft van de klas doorzocht heeft, springt hij gauw naar voren. Wij kunnen de juffrouw verfijnen en haar, als ze de hele klas doorzocht heeft en Jantje niet gevonden heeft met frisse moed van voren af aan laten beginnen, maar dit is geen oplossing, want Jantje springt dan gauw weer naar achteren. Nu zou U kunnen opmerken, dat als die permutaties nu niet met zoveel kwaadwilligheid, maar slechts random uitgevoerd werden, dat dan de verwachtingstijd voor het localiseren van Jantje eindig blijft, ja zelfs door zijn vrijheid rond te springen niet groter is geworden. Deze opmerking, hoe hoopvol, brengt geen soulaas. Zij die zich verdiept hebben in de "Theory of computability" weten hoeveel gewicht gehecht wordt aan een eindige, dwz. een gegarandeerd eindigende algorithme, en zij zullen begrijpen, dat een proces, dat potentieel oneindig lang doortolt, geen aantrekkelijk element is. Veel erger is, dat het in de praktijk veelal de vraag is, of wij de permutaties van de kinderen wel als random mogen beschouwen. Als de kans eindig is, dat als de juffrouw een keer door de klas geweest is, de kinderen weer precies zo zitten als toen de juffrouw begon te zoeken, dan kon dit best eens de eerste periode van een zuiver periodiek verschijnsel zijn.

Maar zelfs als wij het risico, dat we Jantje nooit zullen vinden voor lief nemen, dan nog is haar ellende niet te overzien, want naast het risico, dat ze Jantje niet vindt, loopt ze het veel grotere gevaar, dat ze het verkeerde kind voor het bord sleurt, nl. als de kinderen tussen het moment, dat zij voldaan geconstateerd heeft "Zo, jij ben dus Jantje" en het moment, dat zij, op grond van deze constatering haar hand naar het bijbehorend oor heeft uitgestoken, nog gauw van plaats verwisselen. In een informatieverwerkend proces zou dit neerkomen op een ramp. En dit is het einde van mijn tweede inleiding, waarvan ik hoop, dat zij U enig idee gegeven heeft van het soort probleem, dat wij tegen zullen komen.

Aan het einde van mijn eerste inleiding heb ik twee oorzaken genoemd, die voor een groeiende belangstelling in minder strict sequentiële procesbeschrijvingen verantwoordelijk waren. Ik heb ze slechts luchtig aangestipt en het is U misschien niet opgevallen, dat ze aan bijna tegengestelde entourages ontleend waren. In het eerste geval noemde ik de toenemende complexiteit van machines, die nu opgebouwd zijn uit een aantal min of meer autonoom werkende onderdelen en de opgave was, om deze samen één proces uit te laten voeren. In het tweede geval, waar we de automaat in een z.g. "real time application" bekeken, werd het beeld opgeroepen van één enkel apparaat, dat de mogelijkheid had bij een verandering van de externe urgentiesituatie over te schakelen op het nu urgentste van zijn mogelijke taken. Deze twee arrangementen, een samenspel van een aantal machines aan één proces en omgekeerd, één machine zijn aandacht verdelend over een aantal processen, zijn lange tijd als elkaar wezensvreemd beschouwd. Men heeft er zelfs verschillende namen voor uitgevonden, het ene noemt men "parallel programming" en het andere noemt men "multiprogramming maar U moet mij niet meer vragen wat wat, want dat kan ik niet meer onthouden, sinds ik ontdekt heb dat de logische problemen, die zij door de non-sequentialiteit van de procesdefinitie oproepen, in beide gevallen exact dezelfde zijn.

Ik zal mij in het volgende bedienen van het beeld van een aantal, onderling zwak gekoppelde, op zichzelf sequentiële machines, daarbij aansluitend op de eerste entourage. Maar dit is slechts een beschrijvingswijze, want met wat ik in het vervolg een machine zal noemen komt niet noodzakelijkerwijze een discreet aanwijsbaar stuk apparatuur overeen: in het volgende zijn mijn onderscheiden machines mogelijk heel abstract en representeren zij niet meer dan een opzichzelf sequentieel deelproces. Dit komt onder andere daarin tot uiting, dat ik een grote voorliefde zal tonen voor een samenspel van N machines, N willekeurig. Als ik de term machine alleen maar bezigde voor een aanwijsbaar functioneel stuk apparatuur, dan zou ik het aantal machines voor elke installatie als vrij constant mogen beschouwen. Nu echter een machine, als personifiëring van een opzichzelf sequentiële deeltaak, door de gebruiker ad libitum gecreëerd kan worden, is een dergelijke vaste bovengrens niet meer acceptabel. Ik ga dus praten over het samenspel van N machines, N niet alleen willekeurig, maar als het moet zelfs tijdens het proces variabel. Overtollige machines kunnen vernietigd worden, nieuwe machines kunnen naar behoefte er bij gecreëerd worden en in het samenspel der overigen worden opgenomen. Ik hoop, dat U thans op mijn gezag wilt aannemen, danwel na afloop zelf inziet, dat wij ons zonder de algemeenheid te schaden kunnen beperken tot sequentiële machines, die een of ander cyclisch proces uitvoeren.

Laat ons beginnen met een heel eenvoudig probleem. Gegeven twee machines A en B, beide bezig met een cyclisch proces. In de cyclus van machine A komt een zeker critisch traject voor, TA genaamd, en in die van machine B komt een critisch traject TB voor. De opgave is om er voor te zorgen, dat nooit gelijktijdig de beide machines elk aan hun critische traject bezig zijn. (In termen van onze tweede inleiding: machine A zou kunnen zijn de juffrouw, traject TA het selectieproces van een nieuwe leerling, die voor het bord gehaald moet worden, terwijl het traject TB het proces "kinderpermutatie" representeert.) Er mogen geen veronderstellingen gemaakt worden over de relatieve snelheden der machines A en B, de snelheid, waarmee zij werken hoeft zelfs niet constant te zijn. Het is duidelijk, dat wij de wederzijdse uitsluiting van het critische traject slechts kunnen realiseren, als de twee machines op een of andere manier met elkaar kunnen communiceren. Voor deze communicatie stellen wij enig gemeenschappelijk geheugen ter beschikking, dwz. een aantal variabelen, die voor beide machines in beide richtingen toegankelijk zijn, dwz. waaraan beide machines een waarde kunnen toekennen en waarvan beide machines naar de heersende waarde kunnen informeren. Deze twee handelingen, toekennen van een nieuwe waarde en informeren naar de heersende waarde gelden als ondeelbare handelingen, dwz. als beide machines "tegelijkertijd" een waarde aan een gemeenschappelijke variabele willen toekennen, dan is de waarde na afloop of de ene, of de andere toegekende waarde, maar niet een of ander mengsel. Evenzo: als de ene machine informeert naar de waarde van een gemeenschappelijke variabele op het moment, dat de andere machine er een nieuwe waarde aan toekent, dan dringt tot de vragende machine of de oude, of de nieuwe, maar niet een wilde waarde door. Het zal blijken, dat we ons voor dit doel kunnen beperken tot gemeenschappelijke logische variabelen, dwz. variabelen met slechts twee mogelijke waarden, die we in aansluiting op standaardtechnieken met "true" respectievelijk "false" aangeven. Voorts nemen wij aan, dat beide machines slechts naar 1 gemeenschappelijke variabele tegelijkertijd kunnen refereren, en dan ook alleen of om een nieuwe, waarde toe te kennen of om naar de heersende waarde te informeren. In figuur 1 is in blokschemavorm een tentatieve oplossing gegeven voor de structuur van de programma's voor beide machines. Elk blok heeft zijn ingang boven en zijn uitgang onder. Bij een blok met een dubbele uitgang wordt de keuze bepaald door de waarde van de zojuist aangevraagde logische variabele: heeft deze de waarde true, dan is de uitgang rechtsonder bedoeld, heeft deze de waarde false, dan kiezen we de uitgang linksonder.

Er komen in dit schema twee gemeenschappelijke logische variabelen voor, LA en LB. LA betekent: machine A is in zijn critische sectie, LB betekent: machine B is in zijn critische sectie. De schema's in fig 1 zijn duidelijk. In het blok bovenaan wacht machine A indien hij daar aankomt op een ogenblik, dat machine B in sectie TB bezig is, totdat machine B zijn critische traject heeft verlaten, wat door de toekenning "LB:= false" gemarkeerd wordt, waardoor dan de wacht van machine A wordt opgeheven. En omgekeerd. De schema's mogen dan eenvoudig zijn, ze zijn helaas ook fout, want ze zijn wat te optimistisch: ze sluiten nl. niet uit, dat beide machines tegelijkertijd in hun respectievelijke critische trajecten terecht komen. Als, beide machines buiten hun critische traject zijn —zeg ergens in het blanco gelaten blok— dan zijn zowel LA als LB false. Komen ze nu tegelijkertijd in hun bovenste blok, dan vinden ze beide, dat de andere machine hen geen strobreed in de weg legt, en ze gaan beide door en komen tegelijkertijd in hun critische sectie.

We zijn dus wat te optimistisch geweest. De fout is geweest, dat de ene machine niet wist, of de ander al naar zijn staat van vordering informeerde. De schema's van fig.2 maken een veel betrouwbaardere indruk en het is gemakkelijk te verifiëren, dat zij volslagen veilig zijn. Bv. machine A kan slechts aan traject TA beginnen, nadat tijdens het true-zijn van LA geconstateerd is, dat LB false is, en ongeacht hoe snel na deze kennis van machine A dit feit weer obsoleet wordt, doordat machine B gauw zijn bovenste blok "LB:= true" uitvoert, machine A kan dan veilig traject TA ingaan, omdat machine B toch netjes opgehouden wordt totdat LA na afloop van traject TA op false gezet wordt. Deze oplossing is dus volkomen veilig, maar we moeten niet denken, dat we hiermee het probleem opgelost hebben, want deze oplossing is te veilig, er bestaat nl. de kans, dat het hele samenspel van deze machines vastloopt. Als zij tegelijkertijd het bovenste blok van hun schema uitvoeren, dan lopen beide machines in de daarop volgende wacht en blijven tot in eeuwigheid van dagen beleefd voor dezelfde deur staan, zeggende "Na U" ,"Na U". We zijn te pessimistisch geweest.

U ziet, dat het probleem niet triviaal is. Het was mij althans, na deze twee probeersels, helemaal niet zonneklaar, dat er een veilige oplossing bestond, die niet tevens de mogelijkheid van een doodlopende weg in zich hield. Ik heb het probleem toen in deze vorm aan mijn toenmalige collegae van de Rekenafdeling van het Mathematisch Centrum voorgelegd, er bij vertellend, dat ik niet wist, of het oplosbaar was. Aan Dr. T.J. Dekker komt de eer toe als eerste een oplossing gevonden te hebben, die bovendien symmetrisch in de beide machines was. Deze oplossing is weergegeven in fig. 3. Er is een derde logische variabele ingevoerd, nl. AP, die betekent, dat in geval van twijfel machine A prioriteit heeft. Door de asymmetrische betekenis van deze logische variabele zijn gedeelten van deze programma's min of meer elkaars spiegelbeeld, functioneel is de oplossing echter helemaal symmetrisch en is niet de ene machine bevoorrecht boven de ander. Om te bewijzen, dat deze oplossing aan de gestelde eisen voldoet, constateren we eerst, dat de trajecten TA en TB voorafgegaan worden door de sluis, die we in figuur 2 al als veilig herkend hebben. Simultane uitvoering is dus onmogelijk. We hoeven slechts te verifiëren, dat het nu bovendien uitgesloten is, dat beide machines voor hun critische sectie blijven wachten. In deze wachtcycli wordt de waarde van AP niet gewijzigd. Beperken we ons tot het geval, dat AP true is, dan kan machine A slechts blijven cyclen als ook LB true is; onder de voorwaarde AP true kan machine B echter alleen rond blijven lopen in de cyclus, die LB op false zet, dwz. machine A uit zijn cyclus forceert. In het geval AP false verloopt de analyse op dezelfde manier. Omdat AP als logische variabele of true of false is, is daarmee de mogelijkheid van eeuwig op elkaar blijyen wachten eveneens uitgesloten. Q.E.D.

Dekker's oplossing dateert uit 1959 en bijna drie jaar heeft deze oplossing voortgeleefd als "curiositeit", totdat dit soort problematiek aan het begin van 1962 voor mij plotseling weer actueel werd en Dekker's oplossing als uitgangspunt van mijn volgende pogingen gefungeerd heeft.

De probleemstelling was inmiddels wel drastisch veranderd. In 1959 was het de vraag of de beschreven communicatiemogelijkheid tussen twee machines het mogelijk maakte om twee machines zodanig te koppelen, dat de uitvoeringen van de critische trajecten elkaar in de tijd wederzijds uitsloten. In 1962 werd een veel wijdere groep problemen bekeken en werd bovendien de vraagstelling veranderd in "Welke communicatiemogelijkheden tussen machines zijn gewenst, om dit soort spelletjes zo sierlijk mogelijk te spelen?"

Dekker's oplossing heeft op verschillende manieren als uitgangspunt gefungeerd. Omdat het in deze oplossing onduidelijk is, hoe men te werk moet gaan, wanneer het aantal machines uitgebreid wordt, en de opgave blijft om te garanderen, dat er op elk moment hoogstens 1 critische sectie onder behandeling is, was zij een aansporing om naar andere wegen te zoeken. Door een analyse van de moeilijkheden, die Dekker moest overwinnen, konden wij een aanwijzing krijgen wat een hoopvollere weg zou zijn om in te slaan.

De moeilijkheden ontstaan, doordat als een van de machines geinformeerd heeft naar de waarde van een gemeenschappelijke logische variabele, deze informatie onmiddellijk daarna al weer obsoleet kan zijn, nog voordat de informerende machine er effectief op gereageerd heeft, in het bijzonder: nog voordat de informerende machine aan zijn partners heeft kunnen meedelen, dat hij van de waarde van een gemeenschappelijke variabele. "een momentopname gemaakt heeft". De hint, die uit deze bespiegeling gehaald kan worden, is dat men moet zoeken naar machtigere "elementaire" operaties op de gemeenschappelijke variabelen, in het bijzonder naar operaties, waarin voor de informatietransport tussen machine en gemeenschappelijk geheugen niet meer de beperking van het éénrichtingverkeer geldt.

De meestbelovende operatie, die we hebben kunnen bedenken, is de operatie "falsify". Deze informeert naar de waarde van een logische variabele en het feit, dat deze operatie is uitgevoerd wordt in de helft van de gevallen kenbaar gemaakt: de operatie falsify laat de logische variabele, waarop hij geopereerd heeft nl. met de waarde "false" achter.

De operatie "falsify" kan als volgt gedefinieerd worden:

"boolean procedure falsify(S); boolean S;

begin boolean Q; falsify:= Q:= S; if Q then S:= false end" ,

mits we hierbij vermelden, dat de operatie falsify, in weerwil van zijn sequentiële definitie, beschouwd moet worden als elementaire opdracht van het repertoire der machines, waarbij "elementair" in dit geval betekent, dat gedurende de operatie falsify door één van de machines de logische variabele in kwestie ontoegankelijk is voor alle andere machines.

Dat deze operatie een stap in de goede richting is, volgt wel uit het feit, dat we nu meteen de oplossing hebben voor een wolkje machines X₁, X₂, X₃, ..... , elk met zijn critisch traject TXi, die elkaar nu alle in de tijd moeten uitsluiten. We kunnen dit spelen met 1 gemeenschappelijke logische variabele, zeg SX die aangeeft, dat geen van de machines in zijn critische traject bezig is. De programma's vertonen nu alle dezelfde structuur:

"LXi: if non falsify(SX) then goto LXi; TXi; SX:= true; proces Xi; goto LXi"

waarbij we de aandacht er op vestigen, dat in de programma's voor de aparte machines Xi nergens tot uiting komt, hoeveel machines Xi er eigenlijk zijn: we kunnen dus door loutere toevoeging het wolkje machines Xi uitbreiden.

Het geprogrammeerde wachtcyclusje, dat hierin voorkomt, is natuurlijk heel aardig, maar het beantwoordt wat weinig aan ons doel. Een wachtcyclusje is immers de manier om een machine "zonder effect" bezig te houden. Maar als we nu bedenken, dat het merendeel van deze machines door een centrale computer gesimuleerd zal worden, zodat elke actie in de ene machine slechts plaats kan vinden ten koste van de effectieve snelheid van de andere machines, dan is het wel erg begrotelijk om in een wachtcyclusje aandacht van de centrale computer op te gaan eisen voor iets volslagen nutteloos. Zolang het wachtcyclusje niet verlaten kan worden, mag wat ons betreft de snelheid van deze wachtende machine tot nul zakken, Om dit tot uitdrukking te brengen voeren we in plaats van het wachtcyclusje een statement in, een elementaire opdracht van het repertoire van de machines, die heel heel lang kan duren. We geven dit aan met een P (van Passering); vooruitlopend op latere behoeften representeren we de statement "SX:= true" door "V(SX) -met de V van Vrijgave. (Deze terminologie is ontleend aan het spoorwegwezen: in een eerder stadium heetten de gemeenschappelijke logische variabelen "Seinpalen" en als hun naam met een S begint, dan is dat nog een reminiscentie daaraan.) De text van de programma's luidt in deze nieuwe notatie:

"LXi: P(SX); TXi; V(SX); proces Xi; goto LXi" .

De operatie P is een tentatieve passering. Het is een operatie, die slechts beëindigd kan worden op een moment, dat de er bij opgegeven logische variabele de waarde true heeft, beindiging van de operatie P houdt tevens in, dat aan de logische variabele in kwestie weer de waarde false wordt toegekend. Operaties P kunnen wel simultaan plaatsvinden, het beindigen van een P-operatie wordt echter weer beschouwd als een ondeelbare gebeurtenis.

De invoering van de operatie V is meer dan een verkorte schrijfwijze invoeren. Immers: toen wij het wachtcyclusje met behulp van de operatie falsify nog hadden, rustte de detectieplicht ten aanzien van het gelijk true worden van de gemeenschappelijke logische variabelen op de individuele machines, die op deze gebeurtenis stonden te wachten en in die zin was het wachten een tamelijk actieve bezigheid op een betrekkelijk neutrale gebeurtenis. Met de invoering van de P-operatie hebben wij zo ongeveer bereikt, dat wij tegen een machine, die voorlopig niet verder kan, zeggen: "Ga maar slapen, we maken je wel weer wakker, als je verder mag." Maar dit betekent, dat het op true zetten van een gemeenschappelijke logische variabele, waarop misschien een machine staat te wachten, niet meer een neutrale gebeurtenis is als ieder andere waardetoekenning: hier kan nl. het neveneffect aan verbonden moeten worden, dat een van de "slapende" machines "gewekt" moet worden. Het betekent, dat de logische variabelen, die gedurende false-zijn één of meer machines op kunnen houden, niet permanent geobserveerd hoeven te worden, mits bij overgang naar de waarde true een "centrale wekker" op deze overgang attent gemaakt kan worden. Als de centrale wekker per gemeenschappelijke logische variabele een administratie bij houdt, welke machines op elke logische variabele op het ogenblik wachten, dan kan de centrale wekker, mits deze expliciet op het true worden van een dergelijke gemeenschappelijke logische variabele geattendeerd wordt, snel decideren, of er op grond van deze overgang een slapende machine gewekt kan worden en zo ja welke. De operatie V kan nu opgevat worden als een combinatie van het toekennen van de waarde true aan een seinpaal, plus het attenderen van de centrale wekker op deze gebeurtenis. Het is duidelijk, dat deze centrale wekker zijn werk niet kan doen, als we toestaan, dat de gemeenschappelijke logische variabelen ook nog, door normale waardetoekenningen (van het neutrale type "S:= true"), "stiekem", ondershands gewijzigd kunnen worden. Om dit verbod te onderstrepen, noem ik de gemeenschappelijke logische variabelen van nu af aan "seinpalen" en stel ik, dat de enige mogelijkheid, waarop een machine met een bestaande seinpaal zal kunnen communiceren, zal zijn de P-operatie en de V-operatie.

En hiermede is de operatie "falsify", die ons door de aantrekkelijkheid van zijn eenvoud bij de begripsvorming zo behulpzaam is geweest, weer van het toneel verdwenen en de vraag is gerechtvaardigd, of we door de introductie van de seinpaal, die slechts via de operaties P en V toegankelijk is, het kind niet met het badwater hebben weggegooid. Dit is gelukkig niet het geval. Door de operatie "falsify" van het elementaire repertoire van de onderscheiden machines af te voeren en daar de operaties P en V voor in de plaats te geven, hebben wij niets verloren: wil de invoering van de operaties P en V niet een lege geste zijn, dan moet er dus minstens 1 seinpaal zijn, waarop zij kunnen werken. Deze ene seinpaal —noem hem "SG", de Seinpaal Generaal— is echter al voldoende om de operatie falsify op een willekeurige gemeenschappelijke logische variabele toe te voegen aan het repertoire van alle machines. Immers:

Als wij in elke machine definiëren:

"boolean procedure falsify(GB);

      boolean GB;

begin boolean Q;

       P(SG); falsify:= Q:= GB;

      if Q then GB:= false; V(SG)

end"

en wij voorts afspreken, dat elke referentie naar een gemeenschappelijke logische variabele in elke machine ingekapseld zal worden tussen de statements "P(SG)" en "V(SG)" (zodat de assignment "GB1:= true" nu de vorm zal hebben "P(SG); GB1:= true; V(SG)", dan hebben wij hiermee verzekerd dat aan de bijvoorwaarde voldaan is, dat "gedurende de operatie falsify door één van de machines de logische variabele in kwestie ontoegankelijk is voor alle andere machines." We hebben met de ruil dus niet in eigen vlees gesneden.

Wij gaan nu laten zien, dat de operaties P en V in hun toepassingsgebied niet beperkt zijn tot wederzijdse uitsluiting, maar dat we ze ook kunnen gebruiken, om twee machines ten opzichte van elkaar te synchroniseren. Stel, dat wij twee cyclische machines hebben, zeg X en Y, die elk in hun cyclus 'n critische sectie hebben, zeg TX resp. TY, waarbij de volgende eisen gesteld zijn:

1) de uitvoering van de critische sectie TX mag in de tijd niet samenvallen met die van TY;

2) de uitvoeringen van de secties TX en TY moeten alternerende gebeurtenissen zijn (op deze voorwaarde doelden we, toen we spraken van "onderlinge synchronisatie").

Als U zich een entourage wilt voorstellen, waarin men voor dit probleem gesteld wordt, denkt U dan maar aan het volgende. Proces X is een cijferproducerend proces (een rekenproces), proces Y is een cijferconsumerend proces (een schrijfmachine) en deze twee processen zijn gekoppeld door een "toonbank" met de capaciteit van één cijfer. De handeling TX is het neerleggen van het volgende te typen cijfer op een lege toonbank, het stuk TY representeert het afnemen van het cijfer van de volle toonbank. De stricte alternering vloeit voort uit de eis dat enerzijds geen enkel aan de toonbank aangeboden cijfer "weg mag raken" maar inderdaad getypt moet worden, en dat anderzijds -als er een tijdje geen aanbod is- de schrijfmachine niet zijn tijd moet gaan vullen met het nog maar eens typen van het laatste cijfer.

Wij kunnen dit bereiken met twee seinpalen, zeg SX en SY, waarbij: SX betekent, dat nu eerst een sectie TX aan de beurt is, en SY betekent, dat er nu eerst een sectie TY aan de beurt is. Voor machines X en Y luiden de programma's nu:

"LX: P(SX); TX; V(SY); proces X; goto LX"        en

"LY: P(SY); TY; V(SX); proces Y; goto LY"    .

Wij kunnen dit direct op twee verschillende manieren uitbreiden. Indien wij de machine X vervangen door een wolkje machines Xi, die allemaal van dezelfde toonbank gebruik willen maken om hun productie te lozen, en de machine Y vervangen door een wolkje machines, die allemaal bereid zijn, om informatie van de toonbank af te nemen (ongeacht, door welke van de machines Xi het er op is gelegd, het beeld van de schrijfmachines gaat hier dus niet meer op), dan luiden de programma's voor machines Xi en Yj analoog aan de boven gegeven programma's:

"LXi: P(SX); TXi; V(SY); proces Xi; goto LXi"     en

"LYj: P(SY); TYj; V(SX); proces Yj; goto LYj"    .

Hadden we ook nog een groepje machines Zk gehad, en was de opgave geweest, dat de uitvoering van een TX-sectie, een TY-sectie en een TZ-sectie elkaar in die volgorde cyclisch moesten opvolgen, dan hadden de programma's geluid:

"LXi: P(SX); TXi; V(SY); proces Xi; goto LXi"     en

"LYj: P(SY); TYj; V(SZ); proces Yj; goto LYj"     en

"LZk: P(SZ); TZk; V(SX); proces Zk; goto LZk"   .

Wij merken hierbij op, dat in de laatste twee voorbeeldjes de machines Xi gelijk zijn: zij representeren uitsluitend, dat de handelingen TX ergens door geïnterspatiëerd moeten worden, zij laten in het midden, hoe complex deze tussenliggende handelingen gerealiseerd zullen worden.

Een volgende opgave moge aantonen, dat onze operaties P en V in hun huidige vorm nog niet helemaal machtig genoeg zijn. Wij beschouwen daartoe de volgende configuratie. We hebben twee machines A en B, elk met hun critische sectie TA respectievelijk TB; deze secties zijn volledig onafhankelijk van elkaar, maar er is nog een derde machine C in het spel met zijn critische sectie TC en de uitvoering van TC mag in de tijd niet samen vallen met die van TA, noch met die van TB. We kunnen dit doen met twee seinpalen zeg: SA en SB. Voor machines A en B is het programma eenvoudig, nl.

"LA: P(SA); TA; V(SA); proces A; goto LA"      en

"LB: P(SB); TB; V(SB); proces B; goto LB" ,

maar voor machine C is het volgende programma. hoewel veilig, onacceptabel:

"LC: P(SA); P(SB); TC; V(SB); V(SA); proces C; goto LC" .

Immers: machine C zou de statement P(SA) succesvol voltooid kunnen hebben op een moment, dat machine B in sectie TB bezig is. Zolang sectie TB nu nog niet voltooid is, kan machine C niet verder —dat is correct— maar ook machine A kan zijn sectie TA niet meer uitvoeren en dat is niet correct: indirect, via machine C zijn hier de secties TA en TB toch weer gekoppeld. Door de operatie P(SA) van machine C is de seinpaal SA overhaast op false gezet, daarmee machine A onnodig hinderend.

Wij gaan daarom de operaties P en V uitbreiden tot operaties, die we een willekeurig aantal argumenten mee kunnen geven —daarmee de grenzen van ALGOL 60 overschrijdend, maar dat doet er in dit verband bitter weinig toe. Voor de V-operatie is de betekenis duidelijk: het is niet anders dan de simultaneous assignment, die aan alle meegegeven seinpalen gelijktijdig de waarde true toekent. De P-operatie met een aantal argumenten, bv. "P(S1, S2, S3)", is een operatie, die slechts beëindigd kan worden op een ogenblik, dat alle meegegeven seinpalen de waarde true hebben (in ons voorbeeld dus een ogenblik, waarop geldt: "S1 and S2 and S3"), beindiging van een P-operatie houdt dan in, dat aan alle meegegeven seinpalen simultaan de waarde false toegekend wordt. Ook na deze uitbreiding wordt de beindiging van een P-operatie weer beschouwd als een ondeelbare gebeurtenis.

Met deze uitbreiding zijn we in staat machine C zodanig te definiëren, dat het gesignaleerde bezwaar niet meer optreedt:

"LC: P(SA, SB); TC; V(SA; SB); proces C; goto LC".

Tenslotte wil ik, hoewel dit beslist niet de toepassing is, waarvoor de P- en V-operaties geconcipieerd zijn, laten zien, hoe we hiermee het scalair product van twee vectoren kunnen berekenen, zonder dat we ons vast leggen op de volgorde, waarin de producten der elementen bij elkaar opgeteld worden.

Stel, dat we uit willen rekenen de som SIGMA(i,1,5,A[i] * B[i]) —in woorden: de som, voor i lopend van 1 t/m 5, van (A[i] * B[i])—;

stel, dat ingevoerd zijn de 7 seinpalen: Ssom, Sklaar en de vijf seinpalen Sterm[i] met i=1,2,3,4 en 5; alle 7 met de beginwaarde false;

stel, dat inmiddels gecreerd zijn vijf machines van de structuur (i=1,2,3,4,5):

"Lterm[i]: P(Ssom, Sterm[i]);

scapro:= scapro + A[i] * B[i];

n:= n - 1;

if n = 0 then V(Sklaar) else V(Ssom);

goto Lterm[i] " ,

alle bezig aan hun —enige— P-operatie;

Beschouw nu een zesde machine, die onder bovengenoemde voorwaarden juist zal beginnen aan de volgende statements:

".....; n:= 5;

  scapro:= 0;

  V(Ssom, Sterm[1], Sterm[2], Sterm[3], Sterm[4], Sterm[5]);

  "programma, dat genoemde seinpalen, scalairen en vectorelementen
          ongemoeid laat";

  P(Sklaar);...."

Als de laatste P-operatie van de zesde machine voltooid is, heeft n de waarde 0, scapro heeft de waarde van de gevraagde som en alle seinpalen en de vijf eerstgenoemde machines zijn terug in hun oorspronkelijke toestand.

transcribed by Gerrit Jan Veltink
revised Mon, 22 Mar 2010

EWD37

A review of the IBM 1620 Data Processing System

It is a good custom that scientific articles are reviewed and that no publisher ever thinks about starting a lawsuit or any other measures of vengeance against the author of a very unfavourable review of one of his publications.

With this in mind it is somewhat curious that it is not customary to review digital computers. Reviews of these scientific instruments are in some respects much more important: it is a pity if you have bought the wrong book, but it is much, much worse if you have bought the wrong computer.

The idea that computer reviews ought to be written and published is with me for some time already. The final impuls[e] to write such a review has been the discovery of two "Letters to the Editor" of the Communications of the A.C.M., both expressing praise and appreciation for the same computer, viz. the IBM 1620. They are the letter from Fred Gruenberger, C.A.C.M.,Vol 5, April 1962, pg 221 ("Besides being extremely ingenious....") and the letter from Daniel Herrick and Neal Butler, C.A.C.M.,Vol 5, September 1962, pg 496 ("We wish to join Fred Gruenberger of the RAND Corporation in praising the variable word length IBM 1620....."). It is my considered opinion, however, that this machine embodies some very fundamental mistakes and certainly after the publication of the two letters mentioned above I regard it as my duty not to remain silent any longer. Manufacturers should be warned for these mistakes in order not to be tempted to incorporate them in their future designs, also machine users should be warned for these mistakes in order to help them in not chosing the wrong machine and in order to create a climate where machines will be judged more by their fundamental properties.

After the two praising letters I can be short about its virtues; I should like to add that as soon as the troubles of installation are over, it is an extremely reliable machine.

Before going on I should like to explain why I may have objections to "superfluous features". Suppose that a machine contains a certain feature and that I can show, for instance, that it is impossible to use it intelligently or that its use gives rise to undesirable programming conventions; suppose furthermore that the defender of the design agrees to my objections but defends the feature by pointing out that, if I do not like the feature, I do not need to use it, implying that no harm can be done by something "extra". In that stage of the discussion I shall stress that the design would have been better without the feature under discussion. If it is impossible to use it intelligently every effort to do so is spoilt and the programmer would have been better of[f] without it. If its use gives rise to undesirable programming conventions, also in that case the programmer had better ignore the feature completely.

The IBM 1620 contains a beautiful example of such a harmful "superfluous feature". Besides a general mechanism for calling subroutines, it has a special instruction ("Branch and Transmit") to call in subroutines, an instruction by which control is transferred to the subroutine after the return address has been saved: for the benefit of the end of such a subroutine the order code contains a complementary instruction ("Branch Back") which takes care of the return jump. So far, so good, but the blunder is that the return address is saved in a special return address register, the contents of which are accessible only via the instruction "Branch Back" and in no other way! Before I got acquainted with the IBM 1620 I thought that in the mean time everybody knew that the most essential property of a general purpose information processing machine is that it allows you in principle to process any piece of information in whatever way you like. I was most astonished (and appal[l]ed ) when I discovered that the design of the IBM 1620 Data Processing System has not remained faithful to this fundamental requirement: it is just impossible to write a program only inspecting the value of the return address register. As a result, the incorporation of this feature in a program containing many nested subroutine calls requires that the programmer decides, once and for all, on which level the feature will be used. The special feature has two so-called advantages: the calling sequence requires less memory space and the execution time of the call is reduced. Alas, the subroutine which is called in most frequently is, in general, not identical with the subroutine which is called in from the maximum number of different places in the program and the poor programmer who tries to decide intelligently on which level he shall make use of the special feature "Branch and Transmit" is faced with a fairly undecidable problem. Needless to say that, once the use of the feature has been incorporated in the program, program modifications become unnecessarily tricky or even impossible without rewriting major parts of the program.

There are more reasons why the machine is not worthy of the qualification "general purpose machine", in particular as far as its facilities for paper tape input and output are concerned. The tape reader has been equipped with a number of special properties which make it completely useless as soon as one wants to process an arbitrary punched tape, viz. special properties such as:

a built in parity check

automatic skipping of a specific punching (in IBM terminology identified by "TAPE FEED"

continuing to read until a specific punching is encountered (in IBM terminology identified by "END OF LINE"

The tape punch has similar pecularities. As a result the machine cannot be used to process tapes made by some automatic measuring apparatus or to produce tapes for some tape control[l]ed machinery, unless the tape conventions of these pieces of equipment do not violate the restrictions set by the IBM 1620.

Tape reading has another curious property. One can start tape reading and successive characters from the tape are stored on consecutive (pairs of) digit locations in the memory, starting at a known location. The reading process stops as soon as the character "END OF LINE" is met on the tape. This terminal character, however, is not stored in the memory, another character, named "Record Mark" is stored instead. After completion of the tape read operation the number of characters read (or the address of the location of the terminal character) is lost and if the machine wants to detect how many characters have been read from the tape, it must scan the memory. But now a curious problem arises: the terminal Record XXX Mark which has been stored is indistinguishable from previous Record Marks which might have been read from the tape, and therefore the machine is faced with a problem that shows a striking resemblance to the prototype of an improper algorithm: a man asking the way and getting the answer "You go straight on and turn to the right just before the last steel bridge.". As a result one comes to the shocking conclusion that it is impossible to use the IBM 1620 Data Processing System for one of the most trivial jobs: the reproduction of a punched paper tape, impossible even when it is known that the characters on the tape all belong to the restricted set of the IBM 1620.

On the remark in the Reference Manual "The IBM 1620 is a variable field length computer in the complete sense of the term." I should like to give two comments. I agree that variable field length (plus a non-negligible additional burden on the programmer) in principle admits more economic storage utilization. But the design of the IBM 1620 has turned out in such a way that it is very doubtful whether this gain can be attained. The store is divided into locations of five bits, each location requiring six magnetic cores, because every location has its own parity bit. To store numerical data one needs one location, i.e. 6 cores, for every decimal digit, which compares rather unfavourably with the 3.4 cores needed in the case of binary words. It seems to me very doubtful whether cunning exploitation of the variable length feature will be able to compensate this initial loss, in particular because the gain must come from the way in which the data are stored: the program is stored in fixed length two address instructions each requiring the considerable amount of 72 cores! The full waste of core storage is certainly attained in the processing of FORTRAN programs, where fixed and floating point variables have their fixed length of 4 and 10 locations respectively. My second remark on the variable field length pertains to the way chosen to specify the field length, a way which I regard the more objectionable, the more I think about it. One of the bits of each location has the special function of "a flag bit"; a variable field length operation starts by an addressed location and processes consecutive locations from there onward until a location has been processed with its flag bit = 1. An alternative solution (as e.g. in the Philco 1000) would have been to state separately and in advance, somewhere else, the length of the field in question. First of all, the method of the flag bit tends to be rather uneconomic as far as number of cores concerned, because

the field length is effectively given in a "unary number system"

the field length is stored all over again with every field, which is apparently a waste as soon as a great number of fields of known equal length are to be stored.

The next objection to the flag bit, which is of a more fundamental nature, also applies to the special function of the Record Mark, a character which —one level higher— may be used to end the operation "Transmit Record". Information stored in the memory of a machine shows a certain hierarchical structure: on the one hand we have —on a vertain level— "the information proper", on the other hand we have "the addressing information" specifying place and/or extent of the information proper. The flagbits and the Record Marks play with respect to the fields and records the role of "addressing information" In the IBM 1620 (as in some other machines) the correspondence between the information proper and some of the addressing information is established by a fixed convention in terms of relative position. This would be all right if the information proper were only regarded "from one single point of view", but a basic property of a general information processing process is that information can and will be regarded from many different points of view. If addressing information has to be stored in a position uniquely fixed relative to the information proper, such a change of "point of view" will, in general, imply extensive, clumsy manipulations on the addressing information in this case on the flag bits or on the Record Marks. If somebody tries to make a program shifting the arbitrary contents of a given sequence of memory locations to another place in the memory, he will realize the full impact of my objection.

The IBM 1620 is not the only machine on the market, where (part of) the addressing information and the corresponding information proper are positionally dependent. Because such machines can scarcely be used whenever the way in which the information proper is to be addressed changes frequently, their field of application is virtually restricted to rather straightforward jobs; they are, for instance, no longer qualified to take the place of a university computer. I always wonder whether the designers of such machines have been aware of the restrictive consequences of the technique in question; if so, it is hard to respect their conscious decision to stick to it, if not, are they the people that should have been designing machines? I always wonder......

From the letter of F.Gruenberger I quoted "Besides being extremely ingenious...". In contrast to this opinion I should like to state that, in more than one respect, I regard the design as rather crude. I shall give two examples.

Addition of two numbers is performed serially from right to left. If a short number (source) is added to a longer one (destination) the addition needs only to be continued to the left of the most significant digit of the source so long as the carry is unequal to zero. In the IBM 1620, however, the process is always continued to the bitter end of the destination.

The instruction for the punching of a piece of paper tape always ends by punching a character "END OF LINE". To punch a sequence of characters unequal to "END OF LINE" one is therefore forced first to build up the sequence on consecutive locations in the memory and then to punch out this sequence by means of a single punch instruction. But when this punching takes place (at the conservative speed of 7 char./sec!) the machine itself stands idle.

With this last example in mind one must come to the conclusion that the software provided by the manufacturer is just ridiculous. Even the processing of SPS (standing for "Symbolic Programming System", although it is hardly more than just machine code with mnemonic letter combinations for the different instructions) implies the punching out of the "translated" program. One of the SPS-processors punches the translated program in portions of a fixed length of 80 characters, although the last 8 are never used (and sometimes not even one or more preceding multiples of 12).

Concluding remarks

As the reader will understand, my recent study of the IBM 1620 has been a shocking experience: I knew that it was a rather small machine but I had never suspected that it would embody so many basic blunders. Personally, I cannot undergo such an experience without asking myself what its morals are.

One of the facts we have to face is that this machine, despite of its poor qualities, has been bought or rented. Either the customer is incompetent to judge what he is buying, or the contracts are signed by the wrong persons; in both cases the conclusion is that the fact, that other people have chosen a particular machine, is no guarantee whatsoever as far as its quality is concerned. Well, this is hardly surprising. (For this fact one could try the explanation that the machine, although limited gives "value for its money". But this is belied by the machine itself, for even a modest expert can see, that it also give "nuisance for tis money": for instance, without the additional "END OF LINE" character at the end of the punch instruction the machine would have been cheaper and more sound at the same time.)

The next fact that we have to face is that this machine, despite of its poor qualities, has been produced, in this case even by a big firm with a long and considerable experience. The straightforward conclusion is, that nor the size nor the experience is a guarantee as far as the quality of the product is concerned. Well, we can think of various explanations for this apparent inconsistency, but the most obvious explanation predicts still more blunders in the more ambitious and more complicated products of the manufacturer in question.

Januari 1963

E.W.Dijkstra
Technological University
Department of Mathematics
Postbox 513
E I N D H O V E N
The Netherlands

Literature: IBM Reference Manual 1620 Data Processing System, printed in the Netherlands A 26-4500-1.

Transcription by Ken Dyck
Last revised on 20-Sep-2011 .

EWD 41

DUTCH-ENGLISH DICTIONARY OF PRINCIPAL KEYWORDS

Boom, Tak, Twijg
Tree, Branch, Twig

Kernengeheugen
Core storage

Seinpaal
Semaphore

Trommelgeheugen
Drum storage

Het vectorgeheugen.

    In de meeste multi-programmeringssystemen, die ik gezien heb, moet elk individueel programma zijn geheugenbehoefte opgeven in de vorm van "zoveel aansluitende geheugenplaatsen". Dynamische wijziging van dit aantal stoot meestal op moeilijkheden - vooral als een programma in de loop van zijn uitvoering tot de ontdekking zou komen, dat het eigenlijk wat meer zou willen hebben.

    Mijn opmerking is de volgende: elk programma drukt hier zijn behoefte aan geheugen uit als behoefte aan een vector van gegeven lengte en zodra een aantal van deze programma's samen in eenzelfde geheugen georganiseerd worden, dan beschikt deze overkoepelende organisatie dus over een of andere techniek om een aantal vectoren in een lineair geheugen onder te brengen. Ik zou de koppeling "een individueel, sequentiëel programma versus een enkele vector" willen laten vervallen en elk individueel programma de mogelijkheid willen geven, zijn geheugenbehoefte in termen van zo veel vectoren als het maar wil, uit te laten drukken.

    Dit heeft enkele potentiële voordelen. Teneerste is het een grote uitzondering, wanneer de behoefte aan geheugen, die door een bepaald proces gesteld wordt, zich op de meest natuurlijke wijze als een enkele vector laat uitdrukken. Men zou, ook bij uni-programmering, van een dergelijke faciliteit veel plezier kunnen hebben. Tentweede schept dit de mogelijkheid tot een wat natuurlijkere eenheid, waarin hoeveelheden informatie van random access geheugen naar, zeg trommel, gedumpt kunnen worden. Tenderde zijn de individuele programma's zo evident niet in termen van physische adressen geformuleerd, dat verwacht mag worden, dat herindeling van het physische geheugen met grotere vrijheid kan geschieden.

    In het volgende zal de aanwezigheid van een "tweeslachtig geheugen" (mijn vertaling van "two level store") nauwelijks ter sprake komen. Over de strategie, volgens welke de informatie over beide vormen van geheugen verdeeld zal moeten worden, zal ik het niet hebben; over de administratie van de trommelindeling evenmin.

    Mijn voornaamste zorgen zijn voorlopig:

(a) dat de programma's in hun formulering - dwz. de manier, waarop ze in het kerngeheugen gerepresenteerd worden - zich beperken tot het "eigene", voor zichzelf wezenlijke; maw. dat deze formulering onafhankelijk is van de wijze, waarop dit programma in zijn omgeving is ingebed;
(b) dat de effectieve orde der adressering niet explodeert;
(c) dat de administratieve taken, die voortvloeien uit de plicht bij herindeling van het geheugen de administratie bij te werken, duidelijk omschreven blijft;
(d) dat duidelijk is, welke de "korrelgrootte" is van de programma's, dwz. welke handelingen niet door herindeling van het geheugen verstoord mogen worden. We zouden in practische moeilijkheden kunnen geraken, als de uitvoering van een korrel willekeurig lang zou mogen duren, we zouden een contradictie krijgen, als de uitvoering van een korrel ... herindeling van het geheugen noodzakelijk zou maken!
(e) tenslotte een practische zorg: het vinden van een terminologie om hierover te kunnen praten.

    Ter vermijding van een babylonische spraakverwarring eerst de volgende afspraak: ik zal het woord "adres" alleen gebruiken in de betekenis van "physisch adres", de bitrij, die het selectieregister van een geheugen ingestuurd kan worden. Elk programma zal zijn elementen identificeren als "nummer zoveel van een vector" en dit rangnummer zal ik een "index" noemen.

    Een vector ter lengte N bestaat uit N elementen, onderling onderscheiden door een indexwaarde i; hierbij gelden de ongelijkheden  0 <= i <=  N - 1. De identificatie van de vector - noodzakelijk indien er in een gegeven context meer vectoren voorkomen - is mogelijk, doordat aan elke vector een zg. "basis" is toegekend en een basis, als element van een andere vector weer door een rangnummer identificeerbaar is.

    (De bedoeling is, dat een vector in kerngeheugen een aantal consecutieve geheugenplaatsen zal beslaan; de basis van deze vector bevat dan onder andere beginadres en lengte van de er op steunende vector.)

    Het bestaan van een basis is het recht om over een vector te mogen praten; de identificatie (dwz. de indexrij) van de basis fungeert als identificatie van deze vector. Hel zal later duidelijk worden, dat een basis - hoewel het een indiceerbaar element van een vector is - niet beschouwd mag worden als een willekeurig element, dat informatie representeert, die beschouwd mag worden als subject matter van het proces. (Een gedeelte van de basis zou zijn het beginadres van de er op steunende vector, maar physische adressen hebben in de context van het programma geen betekenis!) Wij hebben dus twee typen elementen: elementen, waarop het programma vrijelijk opereren mag (getallen) en bases. Om een aantal redenen leggen wij ons de beperking op, dat er geen gemengde vectoren zullen zijn: alle elementen van dezelfde vector moeten van hetzelfde type zijn. Zijn de elementen getallen, dan spreken we zo nodig over een "twijg", zijn de elementen bases van andere vectoren, dan noemen we de vector een "tak". (Een basis bevat, behalve lengte en beginadres, ook een specificatie van het type van de er op steunende vector.)

    Elke context veronderstelt de toegankelijkheid van een "impliciete basis", nl. de basis van de vector, waarin de eerste index van een indexrij als rangnummer geinterpreteerd zal worden.

    Toelaatbare operaties op vectorbases zijn: definitie van het type van de er op steunende vector; definitie van de lengte van de er op steunende vector.

    Als een bestaande vector verlengd wordt, worden er enige "ongedefiniëerde" elementen aan toegevoegd; als het de verlenging van een tak is, worden er dus "ongedefiniëerde" bases toegevoegd. Een ongedefiniëerde basis bevat op de plaats de typespecificatie de notitie "nog ongespecificeerd". Na deze introductie van de basis mag het type van de er op steunende vector één keer gedefiniëerd worden. (We sluiten typeveranderingen dus uit voor bestaande vectoren, ook in het geval, dat de vector op dat ogenblik de lengte 0 had.) Een ongespecificeerde vector is iets anders dan een lege vector: hoewel er alleen maar "niks" uit zou kunnen komen, heb ik toch bezwaar tegen optellingen als "0 koeien plus 0 ganzen".

    Als een bestaande vector verkort wordt, gaat er een aantal van de hoogstgenummerde elementen van deze vector verloren; was de vector een tak, dan gaan met de bases, die afgevoerd worden, alle vectoren verloren, die daar op hebben gerust (en als daar weer takken onder waren, alle vectoren, die daar weer op rusten etc.)

    (De in de eervorige alinea genoemde restrictie wat betreft constantheid van type, kan men ondervangen, door als extra operatie op een vectorbasis in te voeren: het ongespecificeerd maken. Zo er al iets op deze basis rustte, gaat dat bij de ongespecificeerdmakerij verloren. Andere oplossing is, om deze ongespecificeerdmakerij geimpliceerd te laten zijn bij typewisseling. Of dit allemaal erg belangrijk is, waag ik te betwijfelen.)

    Operaties op vectorbases geschieden onder opgave van de indexrij, die de basis in kwestie identificeert; is deze indexrij leeg, dan is per definitie de impliciete basis bedoeld. Context zal dus in het algemeen beginnen, de impliciete basis te definiëren als basis van een tak van zekere lengte. Daarmee is een willekeurig aantal nieuwe bases geintroduceerd en daarmee is de mogelijkheid geschapen, om nieuwe vectoren te introduceren.

    Referentie naar element i van een vector met lengte N, waarbij i niet voldoet aan  0 <= i <= N - 1  is onzin en heeft geen betekenis: het is dan ook de bedoeling dat elke selectie van een vectorelement impliceert, dat er getest wordt, of er aan deze ongelijkheden voldaan is. (Je eist van elk programma een zekere mate van consistentie; is hieraan voldaan, dan heeft de gebruikelijke vorm van "Memory protect" om het programma van meneer Jansen te beschermen tegen de capriolen van meneer Pieterse geen enkele zin meer. Immers, meneer Pieterse beschikt niet meer over de terminologie om meneer Jansen te hinderen.)

    Het is duidelijk, hoe elke context op deze manier zijn locale variabelen op uiterst flexibele manier kan invoeren en bespelen. Op de impliciete basis wordt een boompje geplant, dat tijdens zijn bestaan kan groeien en besnoeid kan worden. Nu wordt het echter de hoogste tijd om te zien, hoe onze context met het locale boompje past in zijn omgeving. De impliciete basis, waarover wij gesproken hebben, is nl. geen absoluut machinegegeven: als wij een zo grote stap terug doen, dat wij het gehele geheugen van de machine kunnen overzien, dan is wat intern, dwz. in een gegeven context als impliciete basis fungeert, extern een element, dat zijn plaats in de totale boom heeft en als ieder ander element geidentificeerd wordt door een indexrij van een of andere lengte.

    Bovendien: zonder uitzondering kunnen we stellen, dat elke context niet "self-contained" zal zijn, maar slechts kan werken bij gratie van voorafgaande specificatie van een aantal parameters. Een programma, dat een van de communicatieapparaten gebruikt, zal dit communicatieapparaat als "formeel" apparaat toespreken; bij activering moet er als overeenkomstige actuele parameter een specifiek apparaat meegegeven worden. Ook dit valt allemaal onder "inpassing in de omgeving".

    Om de samenwerking van een gegeven context te bewerkstelligen met grootheden (vectoren, communicatieapparaten), die intern een formele naam hebben en extern een naam, die is uitgedrukt in een terminologie, die intern geen betekenis heeft, heb ik na rijp beraad en lange aarzeling een nieuw soort vector ingevoerd, de zg. "parametervector".

    Bepaalde context kan slechts werken, als zij de beschikking heeft over en de impliciete basis en de bijbehorende parametervector. Omdat dit een onafscheidelijk tweetal is, stel ik voor ze samen in dezelfde vector onder te brengen. (De overige vectoren, takken en twijgen, waren homogeen. We voeren dus nu in de parametertak, een vector met een heel specifieke indeling, bv. het nulde element is de impliciete basis, het eerste element is de heersende waarde van de opdrachtteller en de overige elementen zijn parameters. Het zou me niet verbazen, als het begin van de parametervector een heel geschikte bergplaats was voor nog wat meer impliciete "toestandsvariabelen".) Algemeen begint de parametervector met een vast aantal (minstens 1) vectorbases, eventueel een vast aantal elementen voor toestandsvariabelen, en tenslotte een aantal parameters. Als een vector parametervector is, dan is dat in zijn basis vermeld. In het programma wordt naar de formele parameters verwezen door
(a) een indicatie, dat het hier een formele parameter betreft; dit selecteert de parametervector;
(b) een index, die de parameter specificeert.

    Het idee is, dat een gegeven context A een context B als volgt activeert. Context A reserveert een parametervector, vult daarin alle parameters in en laat dan de machine overspringen naar de nieuwe parametervector annex nieuwe impliciete basis.

    Ik wil nu speciaal even nagaan, hoe we een bestaande vector aan een nieuwe context als parameter meegeven. Ik wil dit doen, door op de bijbehorende plaats van de parametervector een copie van de basis van de vector in te vullen. Dit is heel griezelig, maar voor mijn gevoel moet ik dit doen.

    Laten we even teruggaan naar het idee van de impliciete basis: een bepaald programma is geformuleerd in termen van zijn impliciete basis en spreekt zich er niet over uit, hoe lang de indexrij is, die in de externe wereld deze impliciete basis volledig identificeert. De selectie tengevolge van een indexrij in specifieke context zou dus betekenen, dat je deze indexrij in gedachten vooraf zou moeten laten gaan door de indexrij, die nodig is om in de omgeving de impliciete basis te vinden. Dat zou betekenen, dat de efficiency, waarmee een programma uitgevoerd wordt afhangt van de afstand tot de wortel van de boom en dat was niet de bedoeling.

    Zodra ik echter vectorbases copiëer, dan moet ik er wel voor zorgen, dat bij wijziging van deze basis - verschuiving van de er op steunende vector bv. - dit niet alleen in de originele, unieke basis, maar ook tot zijn copieën doordringt.

    Het idee van de aparte parametervector is ingevoerd om bij wijziging van een basis te weten, dat je slechts parametervectoren hoeft te scannen om te kijken, of je elementen tegenkomt, die mee gewijzigd moeten worden. Ik geloof, dat dit sneller uitkomt, dan bij elke copiëring bij de bron vermelden, waar de copie staat, te meer daar je bij een basis met een enkel nog wel bezuiniging kunt bereiken. (Je kunt bij elke basis een "gecopiëerd-bit" invoeren. De ene waarde betekent: deze basis is beslist niet gecopiëerd, de andere waarde betekent: deze basis is mogelijk wel gecopiëerd. Bij elke copiëring van een basis vermeld je dit feit bij deze basis. Een basis kan op deze manier op een gegeven ogenblik een aantal copieën hebben, maar dat tel je niet. Als sommige van deze copieën door vectorverkorting verdwijnen, dan laat je dat verdwijnen voorlopig onopgemerkt. (Zolang de basis niet gewijzigd wordt, doet de mogelijke copiëring er ook niet zo veel toe.) Pas als je de vector gaat verschuiven, kijk je naar de copiëringsbit. Als deze staat in de stand "mogelijk een copie", dan onderzoek je de mogelijke parametervectoren, om te kijken of je wat hebt bij te werken. Vind je inderdaad copieën, dan werk je deze bij, anders zet je de "gecopiëerdbit" weer terug.)

    Zolang de ene context slechts sequentiëel andere contexten activeert - de ene procedure slechts aanroept als de vorige helemaal klaar is - kan deze activerende context volstaan met slechts een enkele parametervector. Ook voor het geval, dat een bepaalde context wil beschikken over meer parametervectoren, is er, als ik me niet vergis, wel een acceptabele conventie te vinden, zodat in een bepaalde context de parametervectoren gemakkelijk te vinden zijn.

    Als je een subroutine aanroept, moet je daarbij vermelden, welke subroutine je dan aanroept. Evenzo wilde ik bij activering van een bepaald programma dit programma meegeven als parameter van het activeringsmechanisme. Ik beschouw een programma als een vector en we spreken bv. af, dat we de basis van deze vector copiëren op de plaats van de eerste parameter, voordat we de machine laten overgaan op de nieuwe parametervector.

     Tot slot een paar opmerkingen.

    Het in parallelle programmering activeren van een nieuw programma kun je beschouwen als een operatie, waarvan het "gewoon aanroepen van een subroutine" een bijzonder geval is. Eén van de parameters laat je een seinpaal zijn, die voor de activering (voor de aanroep) door het buitenste programma op FALSE gezet wordt. Vervolgens activeert het buitenste programma de subroutine en blijft dan hangen op een passering van deze seinpaal. De subroutine eindigt met zijn voltooiing aan te geven door de seinpaal in kwestie op TRUE te zetten, zodat het aanroepende programma pas doorgaat, als de subroutine voltooid is. Na doorgang kan het aanroepende programma deze activering - deze wachtende machine - weer van de masterwachtlijst afvoeren. Ik betwijfel, of dit de meest practische manier is om subroutines aan te roepen, maar het is wel verhelderend, dat het in wezen niets anders is dan het toevoegen van een nieuw programma aan de wachtlijst.

    Ik ben er in stilte van uitgegaan, dat de aanwezigheid van een vector in de kernen zou impliceren, dat zijn basis zich ook op de kernen bevindt. Liefst hield ik alle takken op de kernen, ook de parametertakken. Parametertakken allemaal op de kernen houden is daarom wel prettig, omdat verschuiving kan impliceren, dat je in parametertakken ver van de wortel nog correcties moet aanbrengen. Als het noodzakelijk is, om parametertakken op de trommel te dumpen, dan is daar overigens nog nog wel wat aan te doen. Dan moet je bij elke parameter in de tak tevens vermelden, welke indexrij in de context, die de parameter gevuld heeft, deze parameter heeft aangehaald. Dan moet je bij terughalen van de parameterrij van de trommel je realiseren, dat je nu een parametertak van de trommel haalt, dat daarop correcties eventueel niet zijn bijgehouden, maar je hebt dan alle gegevens op kernen, om de parameterrij, die een tijd lang op de trommel "geslapen heeft" weer up to date te maken.

    In welke terminologie de wachtende programma's op de wachtlijst van de master onthouden moeten worden is voor mij nog een open vraag; hetzelfde geldt voor de geprogrammeerde seinpalen.

    Ik heb vergeten te vermelden, dat ik met opzet het uit te voeren programma als parameter aan het activeringsmechanisme meegeef, en dat ik een dergelijk programma beschouw als een constante vector. (Hier kun je voor zorgen, door in het programma zelf niet de terminologie ter beschikking te stellen, waarmee het zich zou kunnen overschrijven. Onze ALGOL-programma's overschrijven zichzelf ook niet.) Het is nl. heel aantrekkelijk, om een programma, dat output-limited is, in een aantal activeringen tegelijkertijd aan het werk te hebben, zonder het programma meer dan eens op de kernen te hebben staan. (Wat dachten we van het vertaalproces? Of het "consoleprogramma" als je meer dan één console hebt?)

    De grondgedachte bij de kernenbezetting is, dat een vector helemaal wel, of helemaal niet op de kernen te vinden is. Dat noteer je dan in de basis. Dat je op deze manier geen vectoren in zou kunnen voeren, die langer zijn dan de omvang van het kernengeheugen, is een hinderlijkheid, die echter automatisch op te lossen is (door een impliciete ordeverhoging; dat dit gebeurd is, kun je eveneens in de basis aangeven.)

    Tenslotte: ik heb zo'n gevoel, dat de transporttijden van en naar langzaam geheugen wel eens een bottleneck zouden kunnen worden. Als je een vector uit het langzame geheugen hebt overgenomen, kun je met een bit in de basis aangeven, dat de copie nog "gaaf" is; schrijf je in die vector, of verander je zijn lengte, dat zet je die bit in de andere stand. Op die manier kun je je vrijwat nodeloos terugtransporteren wel besparen. Als de tijd tussen aanvraag en begin van het feitelijke transport lang is vergeleken bij de feitelijke transporttijd (omdat de trommel in de verkeerde stand staat) kon het wel eens de moeite lonen, om aangevraagde transporten even te verzamelen en desnoods via programma te sorteren. Dit kan wel eens zoveel te meer noodzakelijk zijn, omdat een heleboel vectoren kort zullen zijn vergeleken bij de capaciteit van een heel trommelspoor.

Slotopmerkingen.

    Ik ben mij maar al te goed bewust, dat in het voorafgaande geen afgerond plan is beschreven. Integendeel: dit laat nog zoveel vraagtekens over, dat uitwerking een considerabele hoeveelheid werk zal zijn. Voordat ik mij daar in stort, wil ik graag de opinie van wat andere mensen hebben, hoe uitvoerbaar of hoe heilloos dit hun voorkomt.

    Ik kan me voorstellen, dat de lezer het gevoel heeft een kijkje achter de schermen van andermans nachtmerrie gekregen te hebben. Het misschien niet overtuigende verweer, dat ik daartegenover stellen kan, is, dat toen het ALGOL-complex voor de X1 in zijn huidige vorm begon te dagen, ons de eerste drie weken ook de rillingen over de rug liepen. Het kan achteraf wel eens heel goed geweest zijn, dat wij slechts etappegewijze met de consequenties van die aanpak geconfronteerd zijn geworden; anders had het ons meer moeite gekost de euvele moed op te brengen. In mijn niet zeldzame momenten van twijfel put ik wel moed (of moet ik zeggen: overmoed?) uit die ervaring.

    Er is nog een reden, waarom ik dit plan nu graag aan anderen wil voorleggen. Van het hele veld problemen, heb ik er een paar uitgekozen en er over gedacht, hoe je die zou kunnen oplossen. Ik heb me daar alleen maar in kunnen verdiepen, door er maar eens van uit te gaan dat de rest wel oplosbaar is. Je hoopt natuurlijk, dat in de keuze van waar je eerst naar kijkt, je intuitie je niet bedriegt, maar je loopt natuurlijk altijd de kans, dat je een paar heel wezenlijke moeilijkheden onbewust naar achteren schuift omdat je er geen verstandig woord over weet te zeggen.

    Vandaar, dat dit stuk besloten wordt met een verzoek om commentaar.

                                                           E.W.Dijkstra

transcribed by Johan E. Mebius
revised Sun, 28 Mar 2010

EWD 51

MULTIPROGAMMERING EN DE X8

DIRECTE TOEGANG TOT DELEN EN SECTIES  -  DIRECT ACCESS TO INSTALMENTS AND SECTIONS

DEEL 1: EWD51

  0  
  1  
 1.1 
 1.2 
 1.3 
  2  
 2.1 
 2.2 
 2.3 

DEEL 2: EWD54

 2.4 
  3  
 3.1 
 3.2 

DEEL 3: EWD57

 3.3 
  4  
 4.0 
 4.1 
 4.2 
 4.3 
 4.4 

DUTCH-ENGLISH DICTIONARY OF PRINCIPAL KEYWORDS

Seinpaal
Semaphore

Verhogen (V)
To raise, To increase

Prolagen (P),
a neologism coming from
To try and lower,

Probeer te verlagen
To try and decrease

Ingreep
Interrupt, Interruption

Multiprogrammering en de X8
X8 Nr. 17.

0. Inleiding.

     Om te beginnen beschouwen wij een aantal "zwak gekoppelde", onderling asynchrone, in zich zelf sequenti�le processen. Zonder schade te doen aan de algemeenheid kunnen we ons tot cyclische processen beperken. 

     De zwakke koppeling zal daaruit bestaan dat deze processen informatie met elkaar kunnen uitwisselen, dwz. toegang hebben tot enig gemeenschappelijk geheugen. Wanneer deze processen samen van eenzelfde faciliteit bij toerbeurt gebruik zouden willen maken, of wanneer het ene proces informatie wil consumeren, die door een ander proces geproduceerd moet worden, dan volgen hieruit zekere synchronisatie-eisen. We moeten zorgen, dat de processen elkaar niet storen of, in het geval van informatieuitwisseling, niet te ver ten opzichte van elkaar uit de pas geraken. 

     In het eerste gedeelte wordt in de opzet volledig in het midden gelaten, door welke apparatuur deze onderscheiden processen gerealiseerd worden. De uiteindelijke bedoeling is, om in aansluiting met de gegeven - en ik moet er aan toevoegen: concipi�erbare - werkelijkheid sommige van deze cyclische processen door een specifiek stuk hardware te laten uitvoeren, terwijl de overige processen door de centrale computer verzorgd zullen worden. In het eerste gedeelte is dit onderscheid niet van belang; wel belangrijk is, dat een "cyclisch proces" een geprogrammeerde conceptie kan zijn en dat het aantal cyclische processen, dat op elk gegeven moment in het spel betrokken is, in de tijd kan vari�ren. 

     In 1. zal ik in de plaats van "cyclisch proces" spreken van "machine", ter onderstreping van het feit, dat we ons deze processen als grotendeels (of volslagen) autonoom moeten voorstellen. In het licht van het vorige moeten we er ons dus niet over verbazen, als er een paar machines bijgeschapen worden of er een paar machines geannihileerd worden. Later, als we dichter bij de realisatie met behulp van beperkte hardware komen, dan zullen we onderscheid maken tussen "concrete machines" - dwz. cyclische processen, waaraan een specifiek stuk hardware beantwoordt zoals bv. een communicatieapparaat - en "abstracte machines", die tezamen door de centrale computer gesimuleerd worden. Voor deze simulator-generaal zal ik het woord computer reserveren. Deze simulatie roept, met het oog op efficienter gebruik van de totale installatie, strategieproblemen op, waarvan ik me op dit ogenblik met nadruk distanciëer. Voordat ik nl. het strategieprobleem überhaupt wil bekijken, dwz. voordat ik er ook maar over denken wil, hoe de computer zijn vrijheid zou kunnen uitbuiten, wil ik eerst zijn "onvrijheid" geformaliseerd zien, wil ik een passend formalisme hebben, waarin de logisch noodzakelijke "interlocks" tussen de diverse machines geformuleerd kunnen worden. 

     In 2. zullen we een begin maken met de analyse van de simulatie door één computer van de verzamelde abstracte machines. Hier zien wij overigens heel duidelijk, dat over de onderlinge snelheidsverhoudingen der verschillende machines geen veronderstellingen gemaakt mogen worden: als een van de abstracte machines werkt, staan de andere stil (werken de andere oneindig langzaam). 

1. Seinpalen

     De onderlinge temporele restricties worden vastgelegd in zg. "seinpalen". Een seinpaal is een integer, die voor minstens twee verschillende machines toegankelijk is; de mogelijkheden, waarop iedere indiviuele machine met de seinpalen kan communiceren, is echter beperkt tot een tweetal, de operaties P en V. 

1.1. De operatie V ("Verhoog"). 

     De operatie V kan betrekking hebben op een willekeurig aantal verschillende seinpalen, dus bv. "V (S1, S2, S3)". Als deze operatie in een van de machines voorkomt - in ons voorbeeld moeten dan S1, S2, S3 voor deze machine toegankelijke seinpalen zijn - dan is het effect dat alle opgegeven seinpalen in ��n ondeelbare handeling met 1 verhoogd worden. 

1.2. De operatie P ("Prolaag"). 

     De operatie P kan betrekking hebben op een willekeurig aantal seinpalen, dus bv. "P (S1, S2, S3)". Als deze operatie in een van de machines voorkomt - in ons voorbeeld moeten dan S1, S2 en S3 voor deze machine toegankelijk zijn - dan begint een operatie die slechts beeindigd kan worden op een moment, dat alle opgegeven seinpalen positief zijn. Beeindiging van een P-operatie impliceert, dat alle opgegeven seinpalen met 1 verlaagd worden en deze beeindiging geldt als ��n ondeelbare handeling. Ook voor de operatie P beperken we ons tot het geval, dat de erbij opgegeven seinpalen verschillend zijn. 

1.3. Enige voorbeelden van het gebruik van seinpalen. 

     Opm. Vele seinpalen nemen slechts de waarden 0 en 1 aan. In dat geval de operatie V als "baanvak vrijgeven"; de operatie P - een tentatieve passering - kan slechts voltooid worden, als de betrokken seinpaal (of seinpalen) op veilig staat (staan) en passering impliceert dan een op onveilig zetten. De terminologie is ten duidelijkste ontleend aan het spoorwegwezen - althans aan mijn voorstelling daarvan. 

1.3.1. Als wij een klasje machines Xi hebben (X0, X1, X2, ...) en in elke machine komt een critische sectie TXi voor, critisch in die zin, dat geen twee critische secties tegelijkertijd onder bewerking mogen zijn, dan kunnen we dit bereiken met een seinpaal, zeg SX, die in dit simpele geval tweewaardig zal zijn: 

     SX = 0 zal betekenen: een van de machines is aan zijn critische sectie bezig.

     SX = 1 zal betekenen: geen van de machines is aan zijn critische sectie bezig.

De omschrijving van alle machines is gelijkluidend: 

     "LXi: P(SX); TXi, V(SX); rest proces Xi; goto LXi". 

     Als we alle machines op hun gelabelde punt ("aan het begin van de regel") zouden starten met de beginwaarde SX = 2, dan zouden we verwezenlijkt hebben, dat ongeacht de omvang van het klasje machines Xi er nooit meer dan twee simultaan aan hun critische secties bezig zouden zijn. Dir is kennelijk een generalisatie van de probleemstelling van wederzijdse uitsluiting. (Het is precies de situatie van bv. n tape decks aan twee kanalen.) 

     Wij vestigen er de aandacht op, dat de formulering der individuele machines Xi onafhankelijk is van de omvang van het klasje machines Xi, iets wat met het oog op de dynamische variatie van deze omvang wel hoogst gewenst is. 

1.3.2. Nu beschouwen we een groepje machines Xi en een groepje machines Yi, elk met hun critische sectie TXi resp. TYj. Uitvoering van een der critische secties dient uitvoering van alle andere critische secties uit te sluiten, maar tevens eisen we, dat de uitvoering van een TX-sectie en een TY-sectie alternerende gebeurtenissen zijn. 

     We kunnen dit bereiken met twee tweewaardige seinpalen, zeg SX en Sy. 

SX = 1 betekent dat nu eerst een TX-sectie aan de beurt is. 

SY = 1 betekent dat nu eerst een TY-sectie aan de beurt is. 

     De programma's voor de machines luiden: 

     "LXi: P(SX); TXi; V(SY); proces Xi; goto LXi" en 

     "LYj: P(SY); TYj; V(SX); proces Yj; goto LYj". 

     Als de machines alle op het begin van de regel gestart worden moet SX = 1 en SY = 0 zijn of andersom.

Opm. Hadden we ook nog een groepje machines Zk gehad en was de opgave geweest, dat de uitvoering van een TX-sectie, een TY-sectie en een TZ-sectie elkaar in die volgorde moesten opvolgen, dan haden de programma's geluid: 

     "LXi: P(SX); TXi; V(SY); proces Xi; goto LXi" 

     "LYj: P(SY); TYj; V(SZ); proces Yj; goto LYj" 

     "LZk: P(SZ); TZk; V(SX); proces Zk; goto LZk". 

     Wij vestigen er de aandacht op, dat in deze uitbreiding de tekst van de machines Xi niet is veranderd. 

1.3.3. Nu beschouwen we een klasje machines Xi, die informatieeenheden willen lozen in een cyclische buffer meet een capaciteit van N informatieeenheden; voorst een klasje machines Yj, die informatieeenheden uit deze buffer willen verwerken. 

     Omdat vullen van de buffer administratieve maatregelen met de "vulwijzer" impliceert - en voor legen mutatis mutandis hetzelfde geldt - eisen we bovendien, dat vullen slechts door 1 machine Xi tegelijkertijd kan geschieden en evenzo, dat legen slechts door ��n machine Yj tegelijkertijd kan geschieden. 

     We voeren hiervoor in vier seinpalen: 

SX1 = aantal vrije plaatsen in de buffer (aanvankelijk = N) 

SX2 = 0 als ��n van de machines Xi vult, anders 1 

SY1 = aantal gevulde plaatsen in de buffer (aanvankelijk = 0) 

SY2 = 0 als ��n van de machines Yj leegt, anders 1. 

Er zal gelden N - 1 <= SX1 + SY1 <= N. De machines zijn nu: 

"LXi: P (SX1, SX2); vul volgende plaats van de buffer; V (SY1, SX2); proces Xi; goto LXi" 

"LYj: P (SY1, SY2); leeg volgende plaats van de buffer; V (SX1, SY2); proces Yj; goto Yj" 

     In het voorafgaande is het verschil tussen abstracte en concrete machines helemaal op de achtergrond gebleven, juist om te laten zien, dat ze, van een zeker macroscopisch standpunt bezien, volslagen gelijkwaardig zijn. Wij gaan dit onderscheid nu wel maken om te analyseren met wat voor soort hardware dit gerealiseerd zou kunnen worden. 

2. Onderscheid tussen abstracte en concrete machines. 

     Een abstracte machine is een of ander geprogrammeerd sequenti�el proces, een concrete machine is een transputapparaat. (Transput is input of output.) 

     Wij interesseren ons vanzelfsprekend speciaal voor het bespelen van seinpalen die de synchronisatie tussen de computer - dwz. het aggregaat van abstracte machines - en een transputmachine anderzijds regelen. 

     Voor elke seinpaal van dit type is een vaste geheugenplaats gereserveerd. Deze toevoeging komt op twee manieren tot uiting: enerzijds in de manier, waarop het transputapparaat is aangesloten, anderzijds in het programma, dat de samenwerking met dit transputapparaat verzorgt. Beide processen moeten immers tot deze gemeenschappelijke seinpaal toegang hebben. 

     Wij beperken ons nu tot twee soorten seinpalen, nl. de seinpaal, waarop de P-operatie door de computer en de V-operatie door de transputmachine wordt uitgevoerd en de seinpaal, waarbij dit juist andersom is. 

     De afbeelding van de seinpaal in een geheugenplaats ligt heel erg voor de hand: in het algemeen is het een integer, die onthouden moet worden.

Als de seinpaal in het geheugen staat, zijn er vanzelfsprekende opdrachten, waarmee de computer toegang tot de seinpaal kan krijgen. Bovendien zou de transputmachine - als alle - in elk geval al autonoom toegang hebben tot het geheugen. Het basismechanisme voor de seinpaalbespeling is er dus helemaal. Een verder voordeel van een geheugenplaats is de vanzelfsprekende mogelijkheid tot tot uitbreiding van het aantal transputmachines (en bijbehorende seinpalen) gegeven. Er is echter 1 complicatie, waarbij we wel even stil mogen staan: van de waarde van een seinpaal - preciezer: van het positief zijn of niet - moet een sturende invloed uitgaan. We kunnen dus niet volstaan met de seinpaal op kernen op te bergen [en] verder niets meer. Aan al deze seinpalen wordt daarom een flip-flop toegevoegd, die een derivaat van de seinpaal zal zijn, nl. = 1 als de seinpaal positief is en anders = 0. (Zolang we ons beperken tot de non-negatieve seinpalen is de enige andere mogelijkheid = 0. We zullen omdat het hier hardware faciliteiten betreft ons geen nodeloze beperkingen opleggen en in onze definities steeds ook negatieve seinpalen toelaten, dwz. we voeren teken-tests uit en geen nul-tests.) 

     Een dergelijke toegevoegde flip-flop lost dan wel het probleem op hoe we aan een seinpaal op kernen een sturende invloed kunnen geven, het confronteert ons echter wel met de taak te zorgen, dat als de seinpaal in het geheugen gewijzigd wordt, deze flip-flop zonodig aan de nieuwe toestand wordt aangepast. 

     Hiervoor zijn twee mogelijkheden 

(a) we bevorderen de combinatie van seinaalwijziging ene flip-flop-aanpassing tot de status van ondeelbare handeling. 

(b) we gaan bij de separate aanpassing van de flip-flop aan de nieuwe seinpaalwaarde zo omzichtig te werk, dat tijdelijke discrepantie geen brokken kan opleveren. 

     Waar het transputapparaat een seinpaal wijzigt kiezen we de eerste methode, waar de computer een seinpaal wijzigt kiezen we de tweede methode. De eerste methode is voor de transputmachine niet moeilijk te verwezenlijken, want de transputmachine heeft immers de mogelijkheid om het geheugen op te eisen - althans met een grotere prioriteit dan de computer. Voor de machine is de eerste oplossing minder leuk, want de computer kon al bij de seinpalen via normale opdrachten. De automatisch aanpassing van de flip-flop zou dus betekenen, dat er op de adresbits een extra uitcodering zou moeten komen; dit si niet zoerg aantrekkelijk als we bedenken, dat dit aantal seinpalen toeneemt als er meer apparatuur wordt aangesloten. Verkozen is daarom de methode, waarbijde machine met aparte - matig geadresseerde - opdrachten op elk van de individuele toegevoegde flip-flops kan opereren. 

2.1. De P-operatie door de transput-machine. 

     Zij t de integer in het kerngeheugen, die de seinpaal representeert, Zij T de bijbehorende flip-flop, die 1 is, als 0 < t is. T fungeert dan als "Actie-flip-flop" voor de communicatiemachine, die op een passend ogenblik in zijn cyclus zal uitvoeren: 

     "if T = 1 then begin t := t - 1; if t <= 0 then T := 0 end". 

De P-operatie door de transputmachine impliceert bij voltooiing het accepteren van een startopdracht. (Over het wachten als T = 0 laat ik me hier niet uit, bv. of het apparaat werkelijk stilstaat of een dode slag maakt, want dat is in dit verband onbelangrijk. Essenti�el is, dat de transputmachine bij T = 0 de seinpaal t en de flip-flop T ongemoeid zal laten.) 

     Deze P-operatie - onderdeel van het consumeren van de volgende startopdracht - heeft als mogelijk gevolg, dat het opnemen van de volgende startopdracht via de assignment T := 0 verder wordt tegengehouden, nl. als de voorraad is uitgeput.

     Additionele spelregels zijn: 

(a) dat deze handeling vanuit de computer bezien moet worden als ondeelbare handeling - dit schept zijn voordelen - maar dat anderzijds de computer niet over de mogelijkheid zal beschikken om deze handeling over een aantal opdrachten te verbieden - en dit schept zijn problemen. Dit laatste vloeit voort uit het feit, dat de transputmachine bij autonoom geheugencontact absolute prioriteit boven de machine heeft (in overeenstemming met het feit, dat je op dit microscopische niveau essenti�le haastsituaties moet kunnen toestaan). 

(b) dat bij beinvloeding van t en T door de computer het pertinent verboden is als, hoe kort maar ook, ten onrechte T = 1 zou gelden. Op dat moment zou nl. meteen het transputapparaat ten onrechte gestart kunnen worden. 

     Dit betekent, dat de computer de V-operatie niet mag uitvoeren door het programma 

     "t := t + 1; C := 0 < t;
      if C then T := 1" 

(Opm. De algol-programma'tjes, waarmee we de actie van de machine beschrijven hebben als neven-eigenschap, dat met elke regel 1 X8-opdracht overeenkomt; dit maakt het duidelijker om te zien, waar het transputapparaat - tussen de opdrachten nl. - er tussen door kan komen. Men lette erop, dat de telling aan t met een (conditiezettende) additieve opdracht wordt uitgevoerd; daarmee is althans de telling een ondeelbare handeling en kunnen de tellende operaties van computer en transputmachine niet met elkaar interfereren.) 

     Als het bovenstaande programma wordt uitgevoerd op een moment, dat T = 1 is, bestaat er immers de kans, dat na de test op het teken van de nieuwe waarde van t en voor de assignment T := 1 het transputapparaat zoveel P-operaties uitvoert, dat t tot nul wordt afgelaagd en in overeenstemming daarmee T := 0 verricht wordt, waarna de computer op grond van een inmiddels obsoleet gegeven alsnog T := 1 uitvoert. 

     De weg uit deze ellende is 

     "t := t + 1;
      if T = 0 then
      begin if 0 < t
              then T := 1 end" 

     De rechtvaardiging van dit stukje programma is nu als volgt. Eerst testen we T; als T = 1 is, dan was 0 < t; door de optelling is t alleen maar groter geworden en het eventueel aanpassen van T ligt nu op de weg van de transputmachine. Maar als we T = 0 aantreffen, dan kan de transputmachine de operatie P niet meer uitvoeren, zodat van die kant t en T ongemoeid gelaten worden en de computer rustig de test kan uitvoeren. 

     In de praktijk van de X8 zal het nog een stapje ingewikkelder uitgevoerd worden. Een dergelijke "Actie-flip-flop" als T zal zich, om de communicatielijn niet nodeloos te belasten niet in de basismachine, maar in de transputmachine in kwestie bevinden. Dit maakt de vraagopdracht "T = 0" een minder aantrekkelijke propositie. Daarom wordt in het geheugen een copie van T bijgehouden, ST genaamd. 

     De P-handeling door het transputapparaat wordt nu: 

     "if T = 1 then begin t := t - 1; if t < 0 then ST := T := 0 end" 

en de V-handeling door de computer wordt 

    "t := t + 1; 
     if ST = 0 then
     begin if 0 < t then
              begin ST := 1;
                       T := 1
              end 
     end"

waarbij we erop moeten letten, dat de assignment aan ST voor de assignment aan T wordt uitgevoerd. 

     Om het aantal geheugencontacten van de transputmachine te beperken is het gewenst om ST en t in hetzelfde woord te representeren, maar dan zo, dat de operatie t := t + 1 ST niet wijzigt. Dit kan bv. door het woord in te delen: 

     d[26] = ST, d[25]...d[0] = (2^25 - 1) + t 

De test "t <= 0" komt dan neer op de test "d[25] = 0". 

2.2. De V-operatie door de transputmachine. 

Weer zullen we de seinpaal aanduiden met t en de bijbehorende flip-flop met T en zal gelden T = 1 als 0 < t. De V-opdracht is nu eenvoudig 

     "t := t + 1; if 0 < t then T := 1" 

door het transput-mechanisme uit te voeren als een ondeelbare, door de computer niet tegen te houden handeling. 

     De P-operatie zal de computer alleen uitvoeren als T = 1; de computer kan zich, bij gratie van doofheid, echter permitteren, om tijdelijk T = 0 te zetten. 

     De voltooiing van de P-operatie door de computer bestaat nu uit het volgende stukje programma 

     "t := t - 1;
      T := 0;
      if 0 < t then
                 T := 1" 

     Essenti�el is hierbij aangenomen 

(a) dat het geen kwaad kan, als T ten onrechte een tijdje = 0 is; 

(b) dat als transputmachine en computer "tegelijkertijd" proberen om de assignment "T := 1" uit te voeren, dat dan na afloop zeker "T = 1" zal gelden. 

     Om aan te tonen dat bovenstaand stukje programma na afloop onder alle omstandigheden de waarde T in overeenstemming met t achterlaat, hoeven we niet te veronderstellen dat T aanvankelijk positief was. (Als we de eerste twee statements omdraaien, dan moet ik dat wel aannemen; een helderder inzicht in dit soort spelletjes is nog steeds zeer gewenst!) We kunnen desgewenst dit programma ook gebruiken om via "t := t - n" een zg. negatieve voorgift te geven. 

     De redenering is als volgt. Elke V-operatie voor de assignment T := 0 uit uit bovenstaand programma'tje doet niet ter zake, omdat daarna in elk geval T := 0 uitgevoerd wordt. Als tijdens de assignment T := 0 t positief is, dan zal de computer uiteindelijk de statement T := 1 uitvoeren. Door tussengeschoven operaties V kan t immers dan alleen maar nog groter worden en T wordt dus correct achtergelaten. Als tijdens de assignment T := 0 daarentegen t non-positief is, dan moeten wij twee gevallen onderscheiden. Als ondanks eventuele tussengeschoven V-operaties t non-positief blijft, dan zullen zowel transputmachine als computer T verder ongemoeid laten en dus zal T correct = 0 achtergelaten worden. 

Als door ondergeschoven V-operaties daarentegen t positief wordt, dan zal in elk geval door te transputmachine op het moment van omslag T := 1 uitgevoerd worden (en mogelijk ten overvloede ook nog een keer door de computer, nl. als t ten tijde van de test al positief is). In dit laatste geval wordt T dus gegarandeerd correct = 1 achtergelaten.

     Na deze analyses van V- resp. P-operatie door de computer vertrouw ik 

(a) dat de lezer zich van de waterdichtheid overtuigd heeft 

(b) dat de lezer mij de uitvoerigheid, waarmee ik dit heb uitgesponnen, niet kwalijk neemt. Integendeel zelfs. 

     Als de P-operatie door de machine uitgevoerd moet worden, dan is de bijbehorende flip-flop T een zg. ingreep-flip-flop. Een ingreep-flip-flop zit in de basismachine, kan door de computer in beide richtingen gezet worden, kan door de transputmachine op 1 gezet worden. (Dit in tegenstelling tot een actie-flip-flop, zie 2.1.) 

2.3. Hardware ten behoeve van de ingreep-controle. 

     Ingreep-flip-flops kunnen (zie 2.2.) individueel in beide richtingen gezet worden. 

     Aan elke ingreep-flip-flop is een luisterbit toegevoegd. Ook deze is als flip-flop uitgevoerd; ook de luisterbits kunnen individueel in beide richtingen gezet worden door de computer. 

     Ingreep-flip-flops, zoewl als luisterbits kunnen woordsgewijs worden uitgelezen via een communicatie-opdracht. (Zolang het er minder dan 27 per type zijn, dan doen we dit met een woord voor elk type.) Overeenkomstige flip-flops hebben in deze woorden dezelfde positie. 

     Ten slotte is er een doof-horendbit in de computer, die tevens beschikt over de opdrachten "maak doof" en "maak horend". 

     Als voldaan is aan de volgende twee voorwaarden: 

(a) de machine is horend 

(b) het collatie-resultaat van ingreepwoord(en) en (overeenkomstige) luisterwoord(en)  is ≠ 0 

dan vindt een ingreep plaats, dwz.

inplaats van normaal de volgende opdracht aan te halen, wordt een subroutinesprong in het opdrachtregister geplaatst, die met onderdrukking van de ophoging van de opdrachtteller wordt uitgevoerd; tevens wordt de machine door deze actie automatisch doof.

Opm. Hieruit zou volgen, dat een ingreep alleen maar plaats kan vinden op een plek in het programma, waar de machine horend is. Als tijdens de laatste opdracht voor de ingreep al besloten is, dat deze ingreep plaats zal vinden, dan is het mogelijk moeilijk om op deze decisie terug te komen, als de laatste opdracht nu juist de opdracht "maak doof" was. De oplossing is om bij het wegbergen van de link ook de "doof-horendheid" te redden en bij de voortzetting van het onderbroken programma "herstellend" terug te springen. Bij de X1 is gebleken, dat "vertraagde actie" van de opdrachten "maak doof" en "maak horend" mits deze vertraging zich slechts over 1 opdracht uitstrekt, geen enkele moeilijkheid oplevert. 

     Het programma'tje voor de aflaging van T in 2.2. zal in doofheid geschieden; vandaar dat T vrijelijk even een verkeerde waarde mag hebben. 

     De luisterbits stellen ons in staat ingreep-flip-flops - eventueel tijdelijk - te negeren, wanneer er nl. - nog - geen belangstelling voor bestaat.

transcribed by Johan E. Mebius
revised Thu, 29 Mar 2007

EWD 54

MULTIPROGAMMERING EN DE X8

DIRECTE TOEGANG TOT DELEN EN SECTIES  -  DIRECT ACCESS TO INSTALMENTS AND SECTIONS

DEEL 1: EWD51

  0  
  1  
 1.1 
 1.2 
 1.3 
  2  
 2.1 
 2.2 
 2.3 

DEEL 2: EWD54

 2.4 
  3  
 3.1 
 3.2 

DEEL 3: EWD57

 3.3 
  4  
 4.0 
 4.1 
 4.2 
 4.3 
 4.4 

DUTCH-ENGLISH DICTIONARY OF PRINCIPAL KEYWORDS

Seinpaal
Semaphore

Verhogen (V)
To raise, To increase

Prolagen (P),
a neologism coming from 
To try and lower,

Probeer te verlagen
To try and decrease

Ingreep
Interrupt, Interruption

Kernen
Core storage,
Main storage

Trommelgeheugen
Drum storage

Multiprogrammering en de X8, aflevering 2.
(Vervolg van EWD51)

X8 Nr. 18.

2.4.  Cumulatie van startopdrachten en terugmeldingen.

     Als de seinpalen, die de synchronisatie met de externe apparatuur beheersen, maximaal tweewaardig zouden zijn, zouden we de haastsituatie onvoldoende uitgebannen hebben. De essenti�le haastsituatie mag dan wel uitgebannen zijn, de "morele" haastsituatie blijft nog over. Een voorbeeld moge dit toelichten. 

     Stel, dat we een aantal trommeltransporten moeten uitvoeren in overigens willekeurige volgorde. Bij het eerste transport heb je geen weet van de stand van de trommel en zal de machine gemiddeld een halve omwenteling moeten wachten; na voltooiing van dit transport weet je echter drommels goed, hoe de trommel staat en is het niet onverleidelijk om te proberen deze kennis te gebruiken, dwz. de transporten in een zodanige volgorde uit te voeren, dat de wachttijden zo mogelijk wat kort gehouden kunnen worden. 

     Als je nu een organisatie voor trommeltransporten hebt, die van het volgende transport pas notitie kan nemen - door tussenkomst van een dan via programma aangeboden volgende startopdracht - als het vorige transport volslagen is afgehandeld, dan kweekt het streven, die volgende startopdracht dan ook op tijd te geven een "morele" haastsituatie: het is dan wel niet noodzakelijk, maar toch wel hoogstgewenst, dat de "klaarmelding" van het vorige transport een rappe reactie ten gevolge heeft. 

     In het geval van trommeltransport wordt de autonoom uit te voeren handeling bepaald door:

(a)

beginadres in kernen

(b)

beginadres op trommel (plus specificatie welke trommel, als nl. hoogstens 1 trommel tegelijk transporteert)

(c)

lengte van het transport

(d)

richting van het transport

De terugmelding bestaat uit twee bits:

(e)

of het transport succesvol is geweest - dwz. er geen pariteitsfout is opgetreden

(f)

de terugmelding, dat het transport - gelukt of mislukt, zie (e) - voltooid is.

     Per startopdracht stelt men nu een aantal consecutieve woorden ter beschikking, waarin in een vaste, nu niet ter zake doende, codering ruimte is voor de gegevens (a) t/m (e); het gegeven (f) wordt door verhoging van een daarvoor gereserveerde seinpaal doorgegeven. 

     De controle van de trommeltransporten moet dus kennis dragen van deze seinpaal - en toegevoegde flip-flop - plus van de plaats van de codeinformatie (a) t/m (e). 

     Ter vermijding van de morele haastsituatie stelt men nu een aantal van dergelijke startruimtes ter beschikking op een aantal consecutieve geheugenplaatsen; als er per startopdracht voor de gegevens a t/m e bv. twee woorden nodig zijn en er bv. vier startopdrachten geaccumuleerd kunnen worden, dan kost dit startmagazijn ons dus 8 consecutieve geheugenplaatsen. De trommeltransportorganisatie moet deze startruimtes nu cyclisch afwerken. 

     Er zijn in dit geval twee extra complicaties, de cyclische afwerking en de foutreactie. 

2.4.1. De cyclische afwerking. 

     De startopdrachten staan nu in een cyclisch magazijn van bekende lengte. Dit startmagazijn wordt onder controle van een ronddraaiende vulwijzer gevuld, wat een geheel programmeerbare aangelegenheid is.
Het opnieuw gevuld zijn wordt iedere keer door
"V(startseinpaal trommeltransport)" aangegeven. 

     Het autonome trommeltransport leegt het startmagazijn - werkt de startopdrachten af - onder controle van een cyclisch ronddraaiende "leegwijzer", waarmee de computer niets te maken heeft, behalve dat bij het prille begin deze in phase moet staan: de eerst uitgevoerde startopdracht moet inderdaad de eerstgegevene zijn. Vanaf dat moment draait, rampen voorbehouden, de leegwijzer netjes achter de vulwijzer aan. 

2.4.1.1.  E�n van de oplossingen is om als onderdeel van het proces, dat de machine aanzet, deze leegwijzer te clearen; het "tandepoetsprogramma" kan de vulwijzer clearen en we starten de twee processen automatisch in phase. Idealistisch is deze organisatie in orde, van practisch oogpunt is het geen stijl, omdat je in geval van twijfel de boel nooit meer "zo zeker als een huis" weer in het gareel kunt krijgen, anders dan door de machine af en aan te zetten. 

2.4.1.2.  Aan dit extra bezwaar komt men tegemoet - zij het ten koste van een extra opdracht - als vanuit de computer de leegwijzer gecleard kan worden. Als je deze clearopdracht in het tandepoetsprogramma opneemt, dan kun je ook tussentijds de boel in geval van twijfel door de computer onder controle van programma weer onder bedwang krijgen. Hoewel het een extra opdracht in de code van de computer kost, is deze oplossing vooralsnog niet onaantrekkelijk. 

2.4.1.3. We kunnen afspreken, dat de leegwijzer op een vaste plaats in het geheugen staat, bv onmiddellijk voorafgaand aan het startmagazijn.  Als dit de enige plaats is, waar de vulwijzer onthouden wordt, dan zou dit bij een autonoom transport per woord wel tot erg veel geheugencontacten aanleiding geven. Immers: 1 geheugencontact voor het woord zelf, maar voordat het bijbehorende physische adres bekend is, moet een geheugencontact met de bijbehorende - inmiddels eventueel opgehoogde - startinformatie gemaakt zijn, maar om dit mogelijk te maken, is het nodig, dat eerst nog een geheugencontact gemaakt wordt om de heersende waarde van de leegwijzer te pakken te krijgen. 

(Mijn opmerking: gaat het hier over de leegwijzer, over de vulwijzer of over beide? Johan E. Mebius)

     Dit is wel wat al te gek; men kan het aantal geheugencontacten per woordtransport van drie tot twee terugbrengen door te stellen, dat we weliswaar een vaste geheugenplaats voor de leegwijzer hebben ingevoerd, maar tevens bij de trommelorganisatie een paar flip-flops - in ons geval twee - toevoegen, waarin bij elke startopdrachtacceptering (dwz. de P-operatie door de autonome apparatuur) de opgehoogde leegwijzer uit de vaste geheugenplaats copi�ren. Dit onder het motto, dat tijdens een heel bloktransport de waarde van de leegwijzer constant is. 

     Opmerking: Het totaal van 2 geheugencontacten per woordtransport was gebaseerd op de veronderstelling, dat beginadres op de kernen en lengte samen in een woord ondergebracht zouden zijn. Wij komen hier later aan het einde van 2.4 nog weer even op terug. 

2.4.2. De foutreactie. 

     Het is natuurlijk erg prettig om een aantal startopdrachten "in het voor" te kunnen geven, maar laten we ons wel ervan bewust zijn, dat je over het algemeen op de latere transporten slechts prijs stelt, als de voorafgaande transporten succesvol zijn verlopen. Heel duidelijk is dat bij een mislukking van een transport van trommel naar kernen: als hier bij woordtransport iets mis gaat - pariteitsfout - dan kan je het allicht nog eens proberen. Als we nu twee transportopdrachten accumuleren, waarvan de eerste een stuk trommel leest, waarna de volgende iets anders op diezelfde trommelplaatsen wil schrijven, dan is het kennelijk niet de bedoeling, dat dat tweede transport plaatsvindt als het eerste mislukt is. 

     De vraag is dus, hoe het autonoom transport reageert op een gedetecteerde pariteitsfout, behalve dat in de startgegevens de mislukking wordt geindiceerd (zie punt e, uit 2.4.)

     Pogingen om de autonome organisatie voor verdere actie te behoeden door de actie-flip-flop te clearen, eventueel ook de startseinpaal op nul te zetten, zijn mislukt, omdat de analyse van 2.1. (in EWD51) hierdoor in elkaar stortte. 

     Een gezondere oplossing lijkt het, om de trommelorganisatie met twee toestanden in te voeren, aangegeven door een OK-bit (op een flip-flop uitgevoerd). Zodra een pariteitsfout gedetecteerd is, gaat de organisatie in de toestand non OK over; als non OK, dan vindt geen woordtransport plaats, elk transport wordt onmiddellijk onder foutmelding beeindigd. Dit geldt zowel voor het transport, waarin de pariteitsfout is opgetreden, als voor de volgende transporten, die nog in het startmagazijn staan.
Het startmagazijn wordt dus "symbolisch" afgewerkt, daarmee garanderend, dat het hele seinpalenspel ongehinderd doorloopt. 

     De vraag is, hoe dan de overgang van non OK naar OK bewerkstelligd moet worden. Even hebben we gedacht, dat dit kon op grond van leegheid van het startmagazijn. Het feit, dat het transportmechanisme, om die leegheid te ontdekken, niet voldoende heeft aan de P-operatie als enig contact met de startseinpaal, had ons achterdochtig moeten maken. De onbetrouwbaarheid van een automatische overgang naar de OK-toetand realiseert men zich, wanneer een nieuwe startopdracht aan een bijna leeg magazijn wordt toegevoegd. Als de P-operatie vlak voor de V-operatie plaatsvindt, kan de seinpaal in kwestie net even = 0 worden, terwijl dat niet het geval is, als de P-operatie juist even na de V-operatie plaats zou vinden: plotseling zou de sequens "1 -> 0 -> 1" een ander effect hebben dan de sequens "1 -> 2 -> 1". En dit was niet de bedoeling: een dergelijke impliciete beeindiging van de non OK toestand maakt een veilige hantering onmogelijk. 

     Er zijn zo op het oog twee voor de hand liggende mogelijkheden, om de machine expliciet de OK-toestand te laten herstellen. 

2.4.2.1.  Dit is de uitbreiding van de situatie in 2.4.1.2. beschreven: dezelfde opdracht, die de leegwijzer cleart herstelle tevens de OK toestand. Men kan deze twee dingen immers koppelen, omdat de OK-toestand hersteld moet worden op een ogenblik dat het startmagazijn toch leeg is; met vullen kan men dan ook wel weer aan het begin beginnen. 

2.4.2.2.  De andere mogelijkheid is een uitbreiding van de situatie, zoals deze in 2.4.1.3. beschreven is. Men kan in het startmagazijn behalve transportopdrachten in beide richtingen ook nog "herstel OK-toestand" opdrachten toelaten. In het geval dat een foutmelding wordt ontdekt, voegt de computer de opdracht "herstel OK-toestand" aan het magazijn toe en herhaalt de mislukte opdrachten. De eerste oplossing voegt een opdracht aan de code van de centrale computer toe, de tweede voegt een opdracht toe aan het arsenaal, dat de autonome organisatie uit het startmagazijn accepteert. Behalve uit "uitbreidingsoverwegingen" heb ik voor de laatste oplossing tevens een uitgesproken voorkeur omdat de centrale computer hier zijn maatregelen al kan treffen zonder dat de eis van leeg startmagazijn op de proppen komt of de extra-specificatie, hoe de autonome transportorganisatie reageert op de nulzettingen als er nog iets loopt. Op deze wijze immers garanderen we dat de autonome organisatie de haar sturende informatie netjes sequentieël krijgt toegediend. 

     De functionering van het autonoom trommel transport kunnen we in de veronderstelling, dat de laatste oplossing is gekozen, voor de welwillende lezer als volgt documenteren. 

Legenda:

de grootheid "CyclischeTellerstand" bevindt zich op een vaste plaats in het geheugen;

de diverse gegevens in het startmagazijn worden beschouwd als evenzovele vectoren ter lengte vier;

de eerste vector is boolean array OKHerstel [0:3];

als de waarde van  een element van deze vector true is, dan is het een herstel-OK-toestand-opdracht en doen de overeenkomstige waarden uit de andere arrays er niet toe; voorts hebben we:

integer array BeginadresTrommel, BeginadresKernen, Lengte [0:3];
boolean array RichtingTransport, Succesmelding [0:3];

De boolean "PariteitInOrde" is globaal t.o.v. de ongedeclareerde procedure "VolgendWoordtransport" evenals de anonyme grootheden, die spoorselectie, transportrichting en trommelsynchronisatie regelen. De hieronder gedeclareerde grootheden staan op flip-flops. 

begin boolean OK, integer teller;

start:
 P (Startseinpaal Trommeltransport);
 teller :=
 CyclischeTellerstand := mod (4, CyclischeTellerstand + 1);
 if OKHerstel[teller] then OK := true else
 begin
  if OK then
  begin 
   SteltransportRichtingInOp (RichtingTransport[teller]);
   StelSpoorSelectieInOp (BeginadresTrommel[teller]:1024);
   WachtOpTrommelstand (mod (1024, BeginadresTrommel[teller]));
   VolgendWoord:
   if Lengte[teller] != 0 then
   begin
    VolgendWoordtransport (BeginadresKernen[teller]);
    Lengte[teller] := Lengte[teller] - 1;
    OK := PariteitInOrde;
    if OK then goto VolgendWoord
   end
  end;
  Succesmelding[teller] := OK  
 end;
 V (Ingreepsignaal Trommeltransport);
 goto start
end

(NB: != betekent "ongelijk aan" - JEM)

     Later hoop ik bij wijze van voorbeeld de structuur te laten zien van het programma, dat het bovenbeschreven stuk gereedschap bespeelt. 

Opm.  Bij de startopdracht voor de trommel moeten we van te voren ruimte vinden voor:

Lengte: 12 bits;
BeginadresKernen: 18 bits;
BeginAdresTRommel: 19 bits;
(trommel): 2 bits;
OKHerstel: 1 bit.

Voor de succesmelding heb je geen nieuwe positie nodig en zou je de OKHerstel-bit kunnen gebruiken. Wij komen zo op een totaal van 52 bits, dat schitterend in twee woorden is onder te brengen. Een complicatie is echter, dat de twee eerste artikelen (Lengte en BeginadresKernen - JEM) samen 30 bits vergen. De 3 bits, die je tekort komt, zou je in het tweede woord onder kunnen brengen, bij het accepteren extern op 3 flip-flops overnemen, zodat het aantal geheugencontacten per woord niet nodeloos oploopt. (Een X8-woord bestaat uit 27 bits - JEM)

3. De coordinator.

3.1. Over de administratie van een bevolking.

     In de coordinator moet de administratie plaatsvinden van bv. welke input- en outputapparaten aan welke programma's zijn toegekend, welke programma's zijn opgehouden tengevolge van welke seinpalen, etc., etc..
     Als het aantal programma's bv. maximaal 10 zou zijn, als de verzameling seinpalen een vaste beperkte collectie zou zijn, dan zouden we met het in het volgende gestelde probleem niet te maken hebben. Ik wil, vooral in het begin van mijn exploraties mij niet een zo drastische beperking opleggen en zoek dus naar een organisatie, waarin het aantal programma's, het aantal seinpalen dat meedoet, in de tijd willekeurig kan varieren, maar zo, dat al deze entiteiten gedurende hun bestaan hun identiteit niet verliezen.

     Een recht-door-zee-methode is om alle entiteiten van een bepaalde klasse naar volgorde van introductie doorlopend te nummeren. Deze methode is practisch onbruikbaar omdat

(a) na verloop van tijd deze nummers willekeurig hoog gaan worden;

(b) op de vraag, hoe men nadere gegevens over entiteit nr zoveel van een bepaalde klasse kan krijgen, slechts een zoeksysteem antwoord kan geven.

     De oplossing, die mij het het ogenblik het meeste aantrekt is geinspireerd op het hotelwezen: zodra je in het hotel komt, krijg je een vrije kamer toegewezen en voor de duur van je bezoek is je kamernummer je identificatie.

     Extra faciliteiten zijn, dat als mijn hotel vol is, ik er een verdieping op kan bouwen en, als de bovenste verdieping leeg is, ik deze desnoods weer kan afbreken.

     De consecutief genummerde hotelkamers worden in het geheugen op consecutieve plaatsen (of vaste formaties daarvan) afgebeeld: afbraak van de bovenste �tage betekent dus, dat geheugen vrijgemaakt wordt voor andere doeleinden. Het zou dus zin kunnen hebben.

     De taktiek is nu, dat elke nieuwe gast de laagstgenummerde vrije kamer krijgt. Programmatechnisch is dit eenvoudig: we onthouden de omvang van het hotel, van elke kamer of hij bezet is of niet, en tenslotte het rangnummer van de laagst bezette kamer. Komt er een nieuwe gast bij, dan krijgt hij meteen zijn kamer en zoeken we naar de volgende vrije kamer; verlaat een gast het hotel, dan wordt zijn kamer vrijgegeven en tevens wordt dit kamernummer even vergeleken met het heersende laagste vrije kamernummer, dat zo nodig vervangen wordt. Het zoekwerk is hierdoor heel eenvoudig, het is zelfs de vraag of we het abundante gegeven "laagste vrije kamernummer" eigenlijk wel nodig hebben. (Als er veel gezocht zou moeten worden, zou ik de bezet-bits in woorden onderbrengen en gebruikmaken van de normeeropdracht om de eerste vrije te vinden; vanwege het "zoveel bits per woord" trekt deze oplossing me minder.)

     Ik weet, dat de taktiek "nieuwe gast krijgt laagste vrije kamer" het tijdsgemiddelde van de effectieve hotelomvang niet minimaliseert: als op een ogenblik, dat het hotel heel vol is, zich een blijvertje aanmeldt, dan kan het gatental nog zo drastisch zakken, voordat het blijvertje op de bovenste �tage zijn biezen gepakt heeft, kan ik niet gaan afbreken. Ik dacht desalniettemin, dat deze taktiek ten koste van weinig me al een heleboel zou helpen, zeker voldoende, omdat de hotelkamers, die ik voor ogen heb, niet zo vreselijk omvangrijk zullen zijn.

     De hotelanalogie gaat verder: menig hotel zal een aantal stamgasten herbergen - de hardware seinpalen, de standaard communicatieprogramma's e.d.; het is duidelijk, dat de stamgasten de laagstgenummerde kamers zullen krijgen, van meet af aan tot in de eeuwigheid.

     Ik neem aan, dat het aantal hotels, dat direct door de coordinator beheerd wordt, beperkt, bekend en constant is. Naast de twee genoemde administratieve gegevens zullen we per hotel ook nog de plaats - dwz. het adres van de nulde kamer - moeten onthouden. Ook dit denk ik me op een vaste plaats geborgen.

3.2. De wachtlijsten voor abstracte machines.

     Een woord vooraf ter waarschuwing. Ik moet een gebouw optrekken, waarvan mij de contouren beginnen te dagen. Ik heb een idee van het soort fundament, waarop dit gebouw zal rusten: wat het fundament precies zal moeten dragen, zal ik pas weten, wanneer de bovenbouw klaar is. Bij het ontwerp van de bovenbouw moet ik me echter steeds afvragen, of hiervoor nog wel een fundament te bouwen is. M.a.w. niemand verwachte in dit stadium een waterdicht betoog, waarin nu iets geintroduceerd wordt met een haarscherpe verwijzing naar de noodzaak, die 100 pagina's verder uiteengezet zal worden: die 100ste pagina is nl. nog niet geschreven!

     De volgorde, waarin ik de diverse "bedrijfsruimten" van dit gebouw in eerste aanleg zal proberen te beschrijven is min of meer toevallig. Waarschijnlijk kies ik steeds dat onderdeel, waavoor de minst duistere taakomschrijving en een mogelijke constructie me op dat moment het helderst voor de ogen staan. Dat de leesbaarheid soms moet lijden onder het feit, dat ik niet alles tegelijkertijd zeggen kan en af en toe mijn gedachten verder uitgewerkt zijn, dan ik op dat moment beschrijven kan, zie ik helaas als onvermijdelijk. Tot zover deze apologie.

     Als een concrete machine - een transputapparaat - in zijn P-operatie blijft hangen, dan hoeft de coordinator daar geen speciale notitie van te nemen: de concrete machine blijft immers op het vinkentouw en zodra de belemmeringen zijn weggenomen, begint de concrete machine autonoom te lopen.

     Met de abstracte machine ligt dat anders: dit zijn programma's, die hun activiteit gestaakt habben, omdat ze toen niet verder konden. Zodra nu de belemmeringen weg zijn, dan moeten ze uit hun diepe sluimer gewekt worden. Het nagaan van de gevolgen - het bijhouden van de veranderde situatie - van een V-operatie op een of meer seinpalen is een taak, die typisch op de weg van de coordinator ligt.

     We beschouwen alle abstracte machines, die op een gegeven moment meedoen, dwz. alle abstracte machines, die op een gegeven moment �f hun activiteit explicietelijk gestaakt hebben - door een P-operatie - �f door interruptie ergens in hun activiteit onderbroken zijn. Deze abstracte machines vormen samen de bevolking van HAM, dwz. "Hotel voor Abstracte Machines", en worden gedurende hun bestaan geidentifceerd door het kamernummer van de hen in HAM toegewezen kamer.

Opmerking: Volgens deze definitie is de coordinator zelf geen abstracte machine en is de coordinator dus niet in HAM opgenomen. Dit geldt, let wel, voor de kern van de coordinator, dwz. het dat gedeelte van de coordinator, dat altijd als centrale administrator in de kernen aanwezig zal zijn. (Hoe het daar komt is zo'n liefelijk "prille-begin-probleem", waarmee we ons voorlopig wijselijk niet zullen bezighouden. Het prille-begin-probleem is nl. geisoleerd.)  Om het tijdsgemiddelde van de kerngeheugenbezetting door de coordinator niet te groot te maken, zullen we stukken van de coordinator normaliter op de trommel hebben en slechts voorgaats halen, als ze een keer in actie moeten komen. Het kon wel eens wezen, dat we dit het elegantst kunnen organiseren door deze uitlopers van de coordinator te beschouwen als abstracte machines, die dan wel tot de stamgasten van HAM zullen behoren.

     E�n van de stamgasten van HAM zal zijn de "Dummy Abstracte Machine" c.n. DAM. De tekst luidt:

"LDAM: P (SDAM); goto LDAM"

     Eén en ander impliceert, dat SDAM een stamgast zal zijn van het seinpalenhotel, waarover later meer.

     De coordinator is nu zo, dat wanneer er geen enkele abstracte machine meer te simuleren valt, omdat ze allemaal door seinpalen geblokkeerd zijn, de operatie

"V (SDAM)"

uitgevoerd wordt; DAM komt daardoor een slag aan bod en schakelt zichzelf door de operatie "P (SDAM)" voorlopig weer uit. Een dergelijke dummy-machine is logisch niet noodzakelijk, het maakt de hele bespiegelingen waarschijnlijk een stukje eenvoudiger. We hoeven dan niet in onze beschrijving er rekening mee te houden, dat de coordinator mogelijk geen abstracte machine vindt om de computer aan te delegeren. In het geval, dat de coordinator bv. altijd uitgevoerd wordt door dove X8 kunnen we in DAM de machine horend maken, wat wel eens prettig zou kunnen zijn.

     Opmerking: Het is niet strict noodzakelijk, dat de operatie V (SDAM) slechts uitgevoerd wordt, als er werkelijk niets meer te doen is. Als het zo zou uitkomen, dat we van DAM een machine met minimale prioriteit maken, dan zou het best kunnen wezen, dat DAM bv. eens per paar seconden eens een slagje maakt. Zoiets zou kunnen voorkomen, als je aan abstracte machines twee prioriteiten zou kunnen toekennen, een statische prioriteit en een effectieve prioriteit, waarbij de effectieve prioriteit, aanvankelijk van de statische afgeleid, langzaam groeit, als de abstracte machine steeds maar niet aan bod komt. Dit om het gevaar van permanente verwaarlozing te bezweren. Als het eleganter uitkomt, om DAM hierin rustig mee te laten hobbelen, dan is daar dus helemaal niets tegen.

     Over het feit, dat er wel enkele bezwaren aan kleven om de kamers van HAM een vaste omvang te geven, stappen we daar voorlopig even over heen.
(Als we, zoals ik het me op het ogenblik beslist voorstel, de kamers van HAM een vaste omvang zullen geven, dan is de vraag, die we voorlopig onbeantwoord laten of we de kamers zo groot moeten kiezen "dat ze altijd wel voldoende zullen zijn" - een riskante beslissing! - of dat we een organisatie moeten maken, waarin een gast zijn exces aan bagage in volgkamers of een centraal depot moet achterlaten. Wij signaleren het probleem nu slechts.)

     De gasten in HAM vallen uiteen in twee gescheiden categorie�n: geblokkeerde machines en onderbroken machines. Tijdens non-activiteit van de coordinator is er ��n machine, die in geen van beide categorie�n valt, nl. de abstracte machine, die op dat ogenblik in actie is.

     Indien de besturing ten gevolge van een interruptie in de coordinator terechtkomt, komt de abstracte machine, die in actie was, in de groep der onderbroken machines.

     Indien de besturing ten gevolge van een P-operatie naar de coordinator verwezen wordt, dan geschiedt dit onder opgave van ��n of meer seinpalen. Als ��n van deze seinpalen non-positief is, dan gaat de machine, die in actie was, over naar de groep van de geblokkeerde, als alle opgegeven seinpalen positief zijn, worden zij alle met 1 verminderd en wordt de abstracte machine, die in actie was, opgenomen in de klasse der onderbroken machines.

     De onderbroken machines zijn dus de machines, waaruit de coordinator kiezen kan; de geblokkeerde machines zijn die, waarvan de coordinator geen notitie hoeft te nemen, zolang de bijbehorende seinpaal niet positief geworden is. Dit geschiedt door middel van de V-operatie en als de V-operatie uitgevoerd wordt, moet de coordinator dus in het geweer komen.

     Als dit een V-operatie op een hardware seinpaal is, uitgevoerd door een autonoom apparaat, dan geschiedt dit met een ingreep als neveneffect; als de V-operatie, uiteraard door programma, op een geprogrammeerde seinpaal uitgeoverd wordt, dan doet dit programma zulks niet met een additie van uitopdracht maar door een (sub)routinesprong naar de coordinator. De zich in de V-operatie onderbrekende machine wordt in HAM in de klasse de onderbroken opgenomen, logisch zijn er immers geen bezwaren om deze machine na voltooiing de V-operatie weer gewoon door te laten werken.

     Om de onderverdeling in klassen aan te geven, gaan we kettingen rijgen: elke kamer van HAM bevat ruimte voor een ander kamernummer. De abstracte machines, die onderbroken zijn, zijn in ��n of andere volgorde gerangschikt.
Extern noteren we het nummer van de eerste onderbroken abstracte machine; in elke kamer noteren we het kamernummer van de volgende onderbroken machine en in de kamer van de laatste van de rij noteren we een als zodanig herkenbare marker.

(Als blijkt, dat we vaak een nieuweling van het gezelschap aan het einde van de rij moeten toevoegen en de rij een appreciabele lengte kan krijgen, is het raadzaam om extern behalve het nummer van de eerste ook het nummer van de laatste van de ketting te noteren. Als we vaak "achter in de ketting" moeten opereren, kan je de ketting in twee richtingen doorloopbaar maken, door in elke kamer ook het nummer van de voorganger te noteren. Toevoegen en wegnemen wordt daardoor omslachtiger; ik dacht niet, dat deze "dubbele schakeling" nodig was. Het extern bijhouden van het nummer van de laatste is wat anders, want dat heeft nevenvoordelen: het maakt de marker overbodig.)

     Praemisse van deze techniek is, dat we stiekem toch een maximale omvang van HAM invoeren, nl. via het aantal bits, dat we in elke kamer voor het nummer van de volgkamer ter beschikking stellen; omdat dit aantal echter slechts logarithmisch oploopt kan je zonder ongehoorde verspilling een majorant aanhouden, die altijd safe is.

     Voordat we nu de kettingen, waarin de geblokkeerde machines zijn opgenomen, nader gaan bespreken, is het goed even te overwegen, waarom we het idee der geblokkeerde machines eigenlijk hebben ingevoerd. We zouden zonder kunnen. Als een machine de P-operatie uitvoert, maar deze kan wegens non-positieve seinpaal niet beeindeigd worden, dan zou je deze abstracte machine in de lijst van onderbroken machines kunnen opnemen, mits als "staat van vordering" een verwijzing naar het begin van de P-operatie wordt opgenomen. Komt deze abstracte machine ooit weer aan bod, dan zal hij wel opnieuw met frisse moed de P-operatie proberen.
Dit heeft twee nadelen. Ten eerste is het niet ondenkbaar, dat de machine dan een aanwijsbaar deel van zijn tijd zoet brengt met het laten mislukken van P-operaties, ten tweede moet de bestrijding van de permanente verwaarlozing dan waterdicht zijn, omdat anders de computer al zijn tijd zou kunnen besteden aan mislukkende P-operaties, terwijl een zinvol proces geen doorgang zou vinden. Het invoeren van de klasse der geblokkeerde machines kunnen we dus zien als middel �n om de efficiency op te voeren door dingen, die kennelijk tot mislukken gedoemd zijn, niet eens te proberen, �n als middel om straks bij de strategie de handen vrij te hebben.

     Laten wij nu de geblokkeerde abstracte machines bekijken, voorlopig onder de vereenvoudigende veronderstelling, dat elke P-operatie in een geblokkeerde machine slechts 1 seinpaal als argument meekrijgt.

     Als de actieve machine nu een P-operatie tegenkomt, wordt de besturing naar de coordinator verwezen; als de seinpaal positief is, wordt de P-operatie voltooid en wordt de machine opgenomen in de klasse der onderbroken machines, anders is hij mogelijk ��n van de vele machines, die wachten moet, totdat de seinpaal in kwestie positief wordt.

     Om nu, als de V-operatie wordt uitgevoerd op een seinpaal, te ontdekken, welke abstracte machines daardoor mogelijk naar de klasse der onderbroken machines kunnen worden overgevoerd, moet het niet nodig zijn om alle kamers van HAM af te zoeken om te kijken of er misschien ook een geblokkeerde machine juist op deze seinpaal stond te wachten. Dit zoekproces kunnen we weer met een ketting ondervangen.

     Alle seinpalen zij ondergebracht in het Hotel voor Seinpalen HS en worden door hun kamernummer in dit hotel geidentificeerd. In elke HS-kamer wordt, behalve de waarde van de seinpaal, genoteerd, of er inmiddels abstracte machines op het positief worden van deze seinpaal staan te wachten; zo ja, dan zijn deze abstracte machines in een ketting aan elkaar verbonden en de HS-kamer bevat (in elk geval) het HAM-kamernummer van de eerste van de reeks.

     Wordt nu op een bepaalde seinpaal de V-operatie uitgevoerd, dan zijn de consequenties, die daaraan verbonden moeten worden, duidelijk. Als de seinpaal al positief was, dan hoeven we er enkel 1 bij te tellen; was hij aanvankelijk = 0, dan dan moeten we kijken, of er inmiddels abstracte machines op stonden te wachten, zo ja, da kan ��n van deze machines uit deze ketting losgemaakt worden en in de ketting der onderbroken machines opgenomen worden. De strategische kwestie komt hier om de hoek kijken in het geval er meer dan 1 abstracte machine op de seinpaal in kwestie stond te wachten; in dat geval moet immers een keuze gemaakt worden.

     Gecompliceerder wordt het, wanneer we bedenken, dat er ook programma's zullen zijn, die via P-operaties met meer dan 1 seinpaal de controle aan de coordinator overgeven, en 1 of meer van de opgegeven seinpalen is op dat moment non-positief. Een mogelijke oplossing is de volgende, in de veronderstelling, dat de HAM-kamer van deze machine groot genoeg is, om de HS-nummers van de bij de P-operatie meegegeven seinpalen te bevatten.

     De abstracte machine in kwestie wordt opgenomen in de ketting van de eerste de beste seinpaal, die non-positief gevonden wordt. Wordt deze seinpaal later door een V-operatie positief en wordt dit programma uitgezocht als als mogelijke candidaat voor deblokkade, dan wordt eerst het rijtje seinpalen, dat in zijn HAM-kamer staat opgegeven, getest. Alleen als die alle positief zijn, kan de P-operatie voltooid worden, anders is het resultaat, dat de machine in een andere seinpaalketting opgenomen wordt. De ketting, die hangt aan de seinpaal, waarop de V-operatie was uitgevoerd, is daarmee 1 korter geworden; als hij daarmee niet leeg is geworden, wordt er opnieuw een schakel uit gekozen. Etc. etc. totdat de ketting leeg of de seinpaal weer = 0 is.

     Het komt er dus op neer, dat men de candidaat voor deblokkade opnieuw zijn P-operatie uit laat voeren, de P-operatie, waarvan nu inmiddels de seinpalen in zijn HAM-kamer gespecificeerd staan. (Dat 1 van de tests daarbij overbodig is, omdat van minstens 1 seinpaal bekend is, dat hij positief is, laten we voor wat het is; deze test onderdrukken zal meer tijd vergen dan hem even uitvoeren.)

     We zien hier dus twee keren, twee situaties, waarin de seinpalen van een P-operatie onderzocht moeten worden. Ik zou ze willen noemen: "de aangeboden P-operatie" en "de gesuggereerde P-operatie", gesuggereerd nl. door het positief worden van een eerst blokkerende seinpaal. Omdat het verleidelijk is, hun overeenkomst uit te buiten, is het goed even op het verschil te wijzen: als de coordinator met de aangeboden P-operatie klaar is, kan hij overgaan tot de orde van de dag, als de coordinator klaar is met een gesuggereerde P-operatie, dan moet de coordinator (in elk geval als de P-operatie tot een nieuwe blokkade aanleiding heeft gegeven) terug naar de suggererende seinpaal!

     Organisatorisch is er nog een open kwestie, nl. of een HAM-kamer voor een abstracte machine inderdaad dit lijstje HS-nummers kan herbergen. Ook het Hotel voor Seinpalen heeft een maximum omvang, die tot uiting komt in het aantal bits, dat we voor een HS-kamernummer ter beschikking stellen. Aangezien P-operaties willekeurig veel seinpalen mee kunnen krijgen, kan ik vantevoren nooit garanderen, dat een HAM-kamer groot genoeg is. De beste oplossing onderscheidt waarschijnlijk twee soorten P-operaties, die met niet meer dan, zeg, drie seinpalen - dit is de overgrote meerderheid - en de P-operatie met meer seinpalen. Als de eerste nu maar zo vlot mogelijk verwerkt wordt en de tweede soort ook kan, dan hebben we het ene gedaan en het andere niet gelaten.

     Een mogelijke oplossing voor de P-operatie met willekeurig veel seinpalen is de volgende: in de HAM-kamer neemt men niet alleen het terugkeeradres op voor het geval van succesvol voltooide P-operatie, maar ook het terugkeeradres, dat verwijst naar het begin van de P-operatie. De aangeboden P-operatie werkt de seinpalen af, zonder deze in de HAM-kamer op te slaan; de gesuggereerde P-operatie kan men nu simuleren door de abstracte machine vlak voor zijn P-operatie weer te laten beginnen. De coordinator krijgt dan een P-operatie aangeboden, waarvan nog bekend moet zijn, dat dit een aangeboden P-operatie voorstelt. Ik suggereer deze oplossing met schroom om twee redenen:

(a)

proberen de P-operatie te voltooien gaat op deze manier wel vrij wat tijd kosten; de overweging, dat P-operaties met zoveel seinpalen wel niet zo vaak zullen voorkomen wordt een beetje tenietgedaan door de overweging, dat juist bij een P-operatie met veel seinpalen de kans op mislukking groot is.

(b)

dit loopt logisch lekker, als het programma waarin de P-operatie voorkwam, nog op de kernen aanwezig was; zo niet, dan kon dit spelletje, speciaal vanwege de speciale toestand van de coordinator, die immers onthouden moet, dat het hier eigenlijk om een gesimuleerde gesuggereerde P-operatie gaat, wel eens naar worden.

     Een alternatieve oplossing is om een abstracte machine meer HAM-kamers ter beschikking te geven; de eerste keer, dat een abstracte machine met een P-operatie met zo'n lange wachtlijst komt aanzetten, zal je de extra moeite moeten doen, om ��n of meer extra HAM-kamers als volgkamers te reserveren. Ik geloof niet, dat het verstandig is om na deze veeleisende P-operatie die "volgkamers" weer vrij te geven: je kunt er beter van uitgaanm dat deze abstracte machine nu een keer zo veeleisende P-operaties aanbiedt en dat we dus de reservering in HAM maar permanent zo moeten laten, totdat de abstracte machine volledig wordt afgevoerd.

     Wat betreft de strategie voor het overvoeren van geblokkeerd naar onderbroken denk ik, dat je vrij goed zit, wanneer je bij blokkade van een aangeboden P-operatie de abstracte machine aan het begin van de ketting van de blokkerende seinpaal onderbrengt en vervolgens bij de V-operatie de aan de seinpaal hangende abstracte machine in volgorde van begin naar eind probeert de deblokkeren. Dit is de goedkoopste versie van "wie het eerst komt, die het eerst maalt." Dit sluit permanente verwaarlozing van een machine, die is blijven hangen in een P-operatie met meer dan 1 seinpaal niet uit, nl. als door andere abstracte machines om deze seinpalen gevochten wordt. Kunnen we hier zeggen "Het zij zo" en concluderen, dat deze machine dus incompatibel is met de rest?

transcribed by Johan E. Mebius
revised Thu, 29 Mar 2007

EWD 57

MULTIPROGAMMERING EN DE X8

DIRECTE TOEGANG TOT DELEN EN SECTIES  -  DIRECT ACCESS TO INSTALMENTS AND SECTIONS

DEEL 1: EWD51

  0  
  1  
 1.1 
 1.2 
 1.3 
  2  
 2.1 
 2.2 
 2.3 

DEEL 2: EWD54

 2.4 
  3  
 3.1 
 3.2 

DEEL 3: EWD57

 3.3 
  4  
 4.0 
 4.1 
 4.2 
 4.3 
 4.4 

DUTCH-ENGLISH DICTIONARY OF PRINCIPAL KEYWORDS

Seinpaal
Semaphore

Verhogen (V)
To raise, To increase

Prolagen (P),
a neologism coming from 
To try and lower,

Probeer te verlagen
To try and decrease

Ingreep
Interrupt, Interruption

Kernen
Core storage,
Main storage

Trommelgeheugen
Drum storage

Multiprogrammering en de X8, aflevering 3.
(Vervolg van EWD51 en EWD54)
Juni 1963

X8 Nr. 19.

3.3.  De functie van de luisterbits. (7 juni 1963)

    Een ingreep (zie 2.3., EWD51 - 7) vindt slechts plaats als
(a) de machine horend is
(b) het collatieresultaat van ingreepwoord(en) en (overeenkomstige) luisterwoord(en) ≠ 0 is.

    Door een luisterbit = 0 te maken, kan men dus bereiken, dat de bijbehorende seinpaal, als de laatst allang positief is en de bijbehorende ingreepflipflop allang = 1 gezet is, tot nader order toch geen ingreep teweegbrengt.

    Men is kennelijk niet geinteresseerd in het positief worden van een seinpaal, als er niets op staat te wachten. Speciaal bij een hardware seinpaal, waarvan het positief zijn in principe een ingreep teweegbrengt, is het begrotelijk, als deze ingreep plaats vindt en de coordinator niets anders doen kan den gedesinteresseerd van dit feit nota nemen, gedesinteresseerd, omdat aan het hele mogelijkheidspatroon niets verandert. Een ingreep kost nl. wel tijd (en we zullen aanhoudend alert moeten blijven om deze tijd niet te veel te laten toenemen).

    Het idee is nu, om de coordinator ervoor te laten zorgen, dat de luisterbit van een hardware seinpaal aangeeft, of er op deze seinpaal iets staat te wachten of niet: als de wachtketen, die aan de hardware seinpaal hangt (zie 3.2., EWD54 - 8 e.v.)., leeg is, zal de bijbehorende luisterbit = 0 zijn, anders = 1. Het is de taak van de tandenpoetserij om initieel hiervoor te zorgen, het is de taak van de coordinator om dit steeds bij te houden.

    Het gebruik van de luisterbit is hiermee duidelijk. Hoe effectief het is, kan ik op geen stukken na bekijken. Algemeen geldt, dat het effectiever zal zijn
(a) als abstracte machines zo mogelijk liever aan non-hardware seinpalen gehangen worden.
(b) als de cumulatie van ingrepen hoger kan zijn. Dit laatste houdt verband met de omvang van het startmagazijn.

    We moeten hier in elk geval naar kijken en wel om twee redenen: ten eerste geeft dit "letten op" waarschijnlijk nauwelijks aanleiding tot kostenverhoging -in hardware, tijd of aantal opdrachten van de coordinator-; ten tweede moeten we ons bewust zijn, dat het uitsparen van onnodige ingrepen hier zou werken, als de computer niet op de transputapparaten zou hoeven te wachten, dwz. als de hele fabriek "processor limited" zou zijn, dwz. juist de omstandigheid, dat het alle zin heeft, om zuinig met computertijd om te springen!

    Een laatste opmerking is, dat de tijdsspendering per ingreep een betrekkelijk vast bedrag is: dit gaat procentueel des te zwaarder tellen, naarmate je randapparatuur frequenter V-operaties uitvoert. (We moeten niet vervallen in de fout, die ik bij de X1 gemaakt heb, waar het ingreepprogramma voor de bandlezer afgestamd was op de 150 char./sec van de Ferranti-bandlezer -onzaliger nagedachtenis!- met het droeve resultaat, dat het de EL1000 vanwege zijn nu niet meer negligeabele reactietijd niet meer bij kon sloffen!)

4. Automatische transporten tussen langzaam en snel geheugen.

4.0. Inleiding.

    Een ander niet onbelangrijk probleem, nl. dat van de toevoeging of afvoering van abstracte machines laat ik voorlopig met opzet liggen, en wel om de volgende redenen. Binnen afzienbare tijd hoop ik de documentatie onder ogen te krijgen van hoe andere systemenm waarin dit probleem in een zekere mate van algemeenheid is opgelost. Daarin is ongetwijfeld een oplossing gevonden voor de toekenning van randapparatuur aan programma's; behalve concrete objecten zullen wij ook abstracte objecten -nieuw in te voeren seinpalen, bv.- moeten toekennen. Door de grotere flexibiliteit, waar we op mikken, zal het voor ons wat minder eenvoudig liggen, maar het zou onverstanding zijn om te schromen, van andermans ervaring te profiteren. De tweede reden is, dat de administratieve plichten bij toevoeging van nieuwe abstracte machines wel eens medebepaald kon worden door de structuur van deze machines. Deze laatste kon wel eens drastisch beinvloed worden door de manier, waarop we de automatische transporten tussen langzaam en snel geheugen denken te regelen. Dit laatste is dus fundamenteler -en ook moeilijker; vandaar dat ik dat nu eerst te lijf wil. Ter inleiding een historisch overzicht van drie relevante stappen.

4.1. De ARMAC.

Ik herinner me nog heel goed, hoe we wild enthousiast waren, toen we het ontwerp van de ARMAC klaar hadden. In zijn laatste dagen, met de X1 aan de andere kant van de gang, hebben we wel eens medelijdend de schouders over het oude beestje opgehaald. In retrospectie was dit enthousiasme uit 1955 toch niet zo ongerechtvaardigd!

    In 't kort kwam de organisatie van de ARMAC, die in wezen een trommelmachine was, op het volgende neer. De trommel was ingedeeld in sporen van 32 woorden per spoor. Opdrachtselectie direct van de trommel was echter onmogelijk: de machine was uitgerust met een buffer op kernen met de capaciteit van 1 spoor en opdrachtselectie bestond uit
(1) verificatie, dat het goede spoor in de buffer gecopieerd stond
(2) selectie van de overeenkomstige plaats in de buffer.

Als aan de eerste voorwaarde niet voldaan was, werd het rekenproces zonder pardon 1 trommelomwenteling opgehouden, waarin de buffer met het nieuwe spoor gevuld werd. Om dat alles mogelijk te maken, waren 7 additionele flipflops ingevoerd (de trommel bevatte 128 sporen, de adreslengte was 7 + 5 = 12 bits) waarin het nummer van het trommelspoor onthouden werd, dat in de buffer gecopieerd stond. Bij elke opdrachtselectie werd getest op gelijkheid van deze 7 bits en de 7 meest significante bits van de opdrachtteller.

    Als additionele feature werd bij elke getalselectie ditzelfde 7-tal vergeleken met de 7 meest significante adresbits in het opdrachtregister: in geval van gelijkheid werd bij lezen niet gewacht, tot de aangewezen trommelplaats onder de koppen doordraaide, maar werd meteen uit de overeenkomstige plaats uit de buffer geselecteerd; bij schrijven werd dan wel op de trommel geschreven, maar tevens werd de kopie in de buffer bijgehouden.

    Deze additionele hardware heeft zijn geld meer dan opgebracht. Let wel, dat de comparatie met de 7 bits, die aangaven, welk spoor in de buffer stond, in elke gewone opdracht twee keer werd uitgevoerd: eerst in de opdrachtcyclus, daarna in de getalcyclus. In een conventionele Von Neumann-machine kon je ook moeilijk anders.

    Op de keper beschouwd waren het merendeel van deze comparaties overbodig: logisch was het toelaatbaar -en dat was toen in zekere zin geavanceerd- om de ARMAC als boven beschreven non-track-bewust te bedrijven. In de praktijk liet je dit wel uit je hoofd: je besteedde dagen om net zo lang aan de subroutine te fiegelen, totdat je hem in 32 woorden geperst had! En alle hoofdprogramma's hadden op den duur ook alle constanten in het spoor, waar ze gebruikt werden; je moest wel.

    Gaan we er nu van uit, dat de machine track-bewust geprogrammeerd wordt, dan komen we tot de verrassende ontdekking, dat alle comparaties met de 7 bits weggepraat kunnen worden en daarmee de 7 flipflops zelf.
    Het enige dat je nodig hebt zijn speciale sprong- lees- en schrijfopdrachten van en naar plaats zoveel van de buffer. De gewone sprongopdrachten kan je dan altijd hernieuwde buffervulling laten impliceren. De enige vraag is dan nog, hoe je van het ene spoor naar het andere overloopt. Je had kunnen detecteren op overloop naar de 7de bit van de opdrachtteller bij dezelfde ophoging; een alternatieve oplossing is om expliciet aan het einde van een spoor naar het begin van het volgende spoor te springen -iets dat we in de praktijk haast altijd deden, omdat je toch over een paar constanten heen moest springen.

    Op deze manier bekeken is de automatische 7-bits comparatie dus eigenlijk, hoewel mooi, volslagen overbodig: de programmeur kon weten hoe de uitslag zou zijn (en hij deed er goed aan dit te weten).

4.2. ATLAS.

   Een volledig beeld van de ATLAS heb ik niet; toen ik het wilde weten, kon ik de documentatie niet te pakken krijgen. Wat mij ervan bijgebleven is, is dat elk programma zijn eigen sporen op de trommel via een of andere techniek van relatieve adressering kan blijven nummeren van 0, 1, 2, 3, ...; tijdens executie zijn daar physische sporen aan toegevoegd. Hoe precies, weet ik niet; het is -althans nu- voor ons ook niet belangrijk.

    Belangrijk is, dat de ATLAS in mijn geheugen beklijfd is als een ARMAC met een aantal buffers. (Ik geloof 32 [,] of 64 als je rijk was.) Voor de programmeur van ieder individueel programma is het niet toegankelijk, welke sporen zich op elk moment in de buffers bevinden. Hij kan vrijelijk als in een echte Von Neumann-machine naar elk woord in zijn programma (opdrachten + werkroumtes) refereren. Hardware detecteert of het geselecteerde spoor in een van de buffers staat; zoja, dan wordt het overeenkomstige woord van die buffer genomen, zo nee, dan wordt een van de buffers vrijgemaakt en wordt daarin het gevraagde spoor gecopieerd, waarna deze berekening door kan gaan. Dit alles in hardware uitgevoerd.

    Dit project is in meer dan 1 opzicht angstig.
In de eerste plaats moeten de comparaties met het ene gevraagde en de 32 (of 64) aanwezige sporen simultaan uitgevoerd worden en de hiervoor benodigde hardware is niet kinderachtig. Het moet allemaal rap gebeuren, want anders campareer je het grootste deel van de tijd.
In de tweede plaats -hoewel dit geloof ik niet inhaerent aan het systeem is- is de strategie volgens welke een buffer vrijgemaakt wordt, ook in de hardware vastgelegd.
Bij de ARMAC hadden we dit strategieprobleem niet: er was maar 1 buffer en een keuze van 1 uit 1 geeft weinig vrijheid.

4.3. GIER ALGOL.

    De GIER is een machine met een kerngeheugen van zeg 100 woorden en een 12 keer zo grote trommel met sporen van ongeveer 40 woorden (Precies weet ik het niet, het is in elk geval een raar getal.)

    De implementatie van ALGOL op deze machine is voor wat de kerngeheugentoewijzing voor tussenresultaten [betreft] geent op de X1-implementatie, voor opdrachten op de ATLAS, met dit verschil, dat het objectprogramma (uiteindelijk) wel trackbewust geformuleerd wordt.

    Karakteristieke eigenschappen van de GIER zijn in dit verband dat het kerngeheugen echt wel klein is, dat de machine snel is en tijdens tracktransporten zelf wel door kan werken. De machine heeft geen interrupt features, multiprogrammering komt niet ter sprake.

    De oplossing van Peter Naur, J�rn Jensen c.s. is in wezen als volgt.

Een zo klein mogelijk hoekje van het kerngeheugen is gereserveerd voor het "run time system", dwz. de administratie (programma + gegevens) welke programmasporen in het kerngeheugen staan en waar. Er is alles aan gedaan om dit gedeelte zo compact mogelijk te houden, iets dat je aan begenadigd codeur als Jensen gerust kunt overlaten.

    De rest van het kerngeheugen is nu beschikbaar voor variabelen en programma. De programmeur heeft de plicht om te zorgen, dat het aantal variabelen de 500 tot 700 niet overschrijdt. Als hij meer variabelen bespelen wil, kan hij dit, mits hij expliciet -via uit de bibliotheek beschikbare standaardprocedures- variabelen expliciet van en naar de trommel transporteert. De variabelen in het kerngeheugen worden gestapeld, de rest is -buiten controle van de programmeur maar onder controle van het run time system- ter beschikking voor copieen van programmasporen. Gedurende die periodes, dat het aantal variabelen klein is, is er meer ruimte in het kerngeheugen voor programma en wordt dus minder tijd aan tracktransporten verspeeld. (Een gedeelte van die tijd maakt hij ten nutte door een gecompliceerde administratie bij te werken.)

    De werkwijze in het GIER ALGOL system lost voor ons niet alles op: het houdt geen rekening met multiprogrammering en legt de transportlast voor variabelen nog op de schouders van de programmeurs.

    Voorts moeten we een vrij wezenlijk verschil niet uit het oog verliezen: bij de GIER moest men ervan uitgaan, dat als regel het kerngeheugen te klein zou zijn om opdrachten en variabelen van een programma alle te bevatten; bij de X8 mogen we er dunkt me van uitgaan, dat het kerngeheugen in de regel daarvoor wel groot genoeg zal zijn.

4.4. Paginaindeling.

    Het idee is dus om de informatie op de trommel in "pagina's" in te delen en paginaasgewijs al of niet in het kerngeheugen te laten zitten. Wil dit aanleiding geven tot een redelijk vlotte afwerking, dan moet aan minstens drie voorwaarden voldaan zijn.

(a) Zolang de benodigde informatie wel een plaats in het kerngeheugen heeft, moet er zo min mogelijk tijd veloren gaan door verificatie hiervan.

(b) De informatie moet volgens een dynamisch zinvol criterium over de pagina's verdeeld zijn.

(c) De strategie volgens welke "oude pagina's" uit het kerngeheugen verwijderd worden, moet door een of andere (dynamische) bespiegeling waarschijnlijk gemaakt kunnen worden.

4.4.1. De verificatie. (ad 4.4 sub a).

    Bij de ARMAC geschiedde de verificatie door weinig, bij de ATLAS door veel hardware, die simultaan met het rekenproces in actie is. Dit in tegenstelling tot GIER ALGOL, waar gebruikt is, dat veel van deze verificaties weggepraat kunnen worden. Het meest vor de hand liggende feit om te gebruiken is wel, dat als een bepaalde opdracht zich in het kerngeheugen bevindt, dat dan de hele bijbehorende pagina zich in het kerngeheugen bevindt.

    Het streven om het werkende programma zo min mogelijk te vertragen, zolang de benodigde informatie op de kernen staat is echter meer dan uitbuiten van evidenties om het aantal verificaties te drukken: we willen er tevens voor zorgen, dat die verificaties, die nog wel uitgevoerd worden, zo min mogelijktijd vergen. Dit is een strategisch uitgangspunt, slechts te rechtvaardigen door de veronderstelling dat een kerngeheugen van 32 K zo groot is, dat het voor vele problemen -dan wel voor lange tijd- toereikend zal zijn. Een kerngeheugen van 32 K lijkt mij zo groot, dat het zinvol is om te eisen, dat alle programma's die daaraan genoeg hebben, zo min mogelijk gehinderd worden door hun permissie die grens te overschrijden. (Hier scheiden wegen zich heel duidelijk van die van GIER ALGOL, dat in een kerngeheugen van 1000 40-bitswoorden gespeeld moet worden.)

    In ons geval betekent dit, dat we, zodra de kerngeheugentoewijzing verandert, bereid moeten zijn om de consequenties hiervan uitgebreid na te gaan en op allerlei plaatsen passende notities te maken: we moeten de dynamische verificaties zoveel mogelijk prepareren.

    Een enkel voorbeeld moge dit toelichten. Stel, dat we een minimumadministratie bijhouden, bestaande uit een lijstje van welke pagina's zich waar in het kerngeheugen bevinden. De vraag of een willekeurige pagina zich in het kerngeheugen bevindt, zou dan wel eens een tamelijk tijdrovende affaire kunnen zijn. Naarmate de opdrachtpagina's kleiner zijn, zal het dynamisch vaker voorkomen, dat een sprong naar de volgende -of daaropvolgende- pagina uitgevoerd moet worden. De hieruit voortvloeiende verificatieplicht kan je drastisch vereenvoudingen door bij elke pagina in kerngeheugen te vermelden of, en zo ja waar, zich de volgende pagina in het kerngeheugen bevindt. Aan de coordinator is dan natuurlijk wel de zoete plicht om bij de wijzigingen deze notities steeds bij te werken.

    Het idee van "de volgende opdracht" kan gebruikt worden om vele verificaties overbodig te maken, het idee van "de volgende pagina" om een aantal verificaties, die nog wel uitgevoerd moeten worden, te versnellen. Het versnellen van verificaties door passende preparatie zullen wij, als ik me niet vergis, nog wel vaker tegenkomen; er is nl. een tweede reden, waarom de techniek veelbelovend is. Als een verificatie een negatief resultaat oplevert, moet er getransporteerd worden: het proces in kwestie kan dus niet verder. Door multiprogrammering bestaat er wel de mogelijkheid, dat er iets anders kan gaan lopen, maar [niet] de zekerheid, dat dat andere niet de Dummy Abstract Machine (zie 3.2., EWD54-7) wordt. Een zinvoller zoethoudertje voor de computer is altijd beter; de coordinator is dan de meest voor de hand liggende candidaat.

4.4.2. Dynamisch zinvolle indeling. (12 juni 1963)

    De drie beschreven voorbeelden werken met pagina's van uniforme lengte; bij de X8, waar de lengte van trommeltransporten binnen zeer ruime grenzen vrij kiesbaar is, zijn we dus niet aan vaste paginalengte gebonden. Het is dus redelijk, om zich af te vragen, of we de lengte van elke individuele pagina zich kunnen laten voegen naar de structuur van de informatie, die hij herbergt. Voordat ik nu de mogelijkheden van uniforme versus non-uniforme paginalengtes wil vergelijken, eerst een opmerking. Als we uniforme paginalengte kiezen, dan is het duidelijk, dat we voor deze uniforme paginalengte een keuze moeten doen -hoe is een andere zaak. De opmerking, die ik maken wilde is, dat we in geval van non-uniforme paginalengte ook een dergelijke quantitatieve keuze moeten doen. Doen we dat niet en kiezen we onze pagina's zo, dat alles dat bij elkaar hoort op 1 enkele pagina komt, dan wordt natuurlijk de uitkomst, dat we het hele programma op een enkele voldoend lange pagina onder gaan brengen. Dat was nu niet de bedoeling. De enige manier, waarop we de non-uniforme pagina-indeling kunnen aanbrengen, lijkt de volgende. Men neme een zekere ideale paginalengte in het oog. Is het programma daarvoor te lang, dan verdeelt men het programma op de meest natuurlijke manier in stukken; zijn die stukken nog te lang, dan kijkt men naar de interne structuur van deze stukken etc. etc. totdat de hele boel in passende mootjes is opgehakt.

    In het geval van uniforme paginalengte ga je, zolang je niet slim probeert te wezen, anders te werk. Het allergrofste is, dat je de tekst van het programma gewoon in vaste stukken van om de zoveel opdrachten ophakt. Een voor de hand liggende verfijning is, om de constanten, die in een pagina gebruikt worden over de pagina op te zamelen en achteraan in dezelfde pagina op te nemen. (Bij dit groeperen moet je even voorzichtig zijn: als je nog ruimte voor een enkele hebt en die opdracht heeft net een nieuwe constante nodig, dan lukt het niet meer!) Tot zover is GIER ALGOL gegaan en verder niet; probeer je veel verder te gaan, dan krijg je steeds meer overwegingen, die bij de non-uniforme paginaindeling van meet af aan een rol moeten spelen.

    En dit soort overwegingen is bedenkelijk, omdat op louter lexicographische gronden niet alle gegevens ter beschikking zijn, die uitmaken, of iets dynamisch zinvol is of niet. Het angstige is, dat het gevolg van vermeende slimheid zelfs averechts kan werken. Een enkel voorbeeld moge dit toelichten: stel dat we in een programma eerst een cyclus A hebben, gevolgd door een cyclus B met een binnencyclus C. Nu beschouwen we twee mogelijke indelingen: cyclus A zit schrijlings over een paginagrens en cyclus B kan nog in zijn geheel in de tweede pagina; het andere arrangement is, dat we de programmatekst wat doorschuiven, zodat cyclus A in zijn geheel aan het begin van een pagina komt te liggen en nu cyclus B schrijlings over een paginagrens ligt, maat zo, dat de binnencyclus C nog in dezelfde pagina als A past. Op grond van het bekende regeltje "optimalisering is vooral van belang bij binnenste cycli" lijkt het tweede beter, want zowel A als C zitten nu niet meer schrijlings. Maar als A vele malen minder doorlopen zal worden dan B, dan is de eerste oplossing dynamisch toch echt te preferen! Een en ander ter illustratie van het feit, dat we met minimaliseringen  van pagina-overgangen erg voorzichtig moeten zijn. De ervaring heeft bovendien geleerd, dat dergelijke groepeerderijen, die al gauw op uitgebreide analyses van de samenhang, de "cross-references" in de aangeboden tekst neerkomen, vertaaltijden makkelijk tot een veelvoud doen exploderen. Het dubieuze effect en mijn voorliefde voor "load and go" maken, dat ik me niet erg aangetrokken kan voelen tot dergelijke optimaliseringen. Het ontaardt gauw in een poging tot raffinement op het verkeerde ogenblik.

    Wat kan je wel doen? Wel, het onderbrengen van constantes in de pagina, waarin ze gebruikt worden, is een duidelijk voorbeeld. Het kost haast niets en het succes is verzekerd!

    Immers: als we de opeenvolgende opdrachten samen in een pagina onderbrengen, dan wete we, dat we niet zo gek zitten, omdat na een opdracht interesse in de volgende opdracht een heel waarschijnlijk gebeuren is. Als we nu in onze tekst " ...* 2.5" tegenkomen, dan is de uit te voeren handeling "met 2.5 vermenigvuldigen" en als we dat in onze machinecode in twee losse stukken splitsen, dan is deze splitsing iets artificieels. Constanten in dezelfde pagina onderbrengen is dus niet: de aangeboden tekst "handig groeperen", maar "niet nodeloos ophakken". De vertaler heeft niet de informatie vernietigd, dat het hier om een constante operatie ging. En wat we in elk geval kunnen doen is proberen om het effect van de informatievernietiging door de vertaler te beperken, te mitigeren.

    De opmerking, dat je verificatieplichten kunt verkorten door bij elke pagina in kerngeheugen te noteren (zie 4.4.1.) waar je de volgende kunt vinden, is op hetzelfde soort overwegingen geent. Je zult dit eerst raadplegen van de volgende nl. vooral doen bij die sprongopdrachten, die niet in de tekst voorkomen, maar die de vertaler er bij gemaakt heeft. En dat zijn nu juist bijna allemaal voorwaartse sprongen; denk aan het overlopen naar de volgende pagina of de vertaling van "if..then..else..". Er is geen enkele reden om de if-clause aanleiding te laten geven tot hetzelfde stuk opjectprogramma, dat je gekregen zou hebben als de sourcetekst het met expliciete sprongen -die "overal heen" kunnen zijn- geformuleerd had.

    Ik hoop hier meer voorbeelden van te kunnen vinden.

    Ik ga er nu maar van uit, dat we "opdrachten + constanten" samen zullen indelen in pagina's van vaste lengte. Blijft natuurlijk de vraag welke lengte.

    Als je aanneemt, dat uiteindelijk het kerngeheugen in het merendeel van de gevallen groot genoeg is, dan is er een prae voor lange pagina's. Immers, het aantal malen, dat verificatie uitgevoerd moet worden is dan minder, omdat je vaker in dezelfde pagina blijft en verificatie dus achterwege kan blijven. Bovendien: hoe minder pagina's er in het spel zijn, hoe goedkoper de verificatie. Zodra je ook ernstig rekening moet houden met hetgeval, dat je kerngeheugen te klein blijkt, dan moet je trommeltransporten vermijden en een van de manieren om dat te doen is zo zuinig mogelijk met je kerngeheugen omspringen. Je verspilt natuurlijk als je maar in een stukje van een pagina geinteresseerd bent, de ruimte, die de rest van de pagina onherroepelijk inneemt. Ik denk dat op het ogenblik -12 juni 1963- over pagina's van 256 opdrachten. (Mijn idee over de ideale paginalengte is tot 256 gegroeid; als het zo doorgaat, zou ik nog wel eens bij 512 terecht kunnen komen.)

    De volgende overwegingen zijn voor mij wel verhelderend geweest om in te zien, welke factoren in het spel waren. Als het kerngeheugen voor het totale programma te klein is, dan kunnen we slechts lange tijd trommeltransporten uitsparen, als de besturing in een gedeelte van de programmatekst rondcyclet. Als prototype van de situatie, waarin winst is te boeken, bekijken we dus een cyclus. Dynamisch beschouwd bestaat een cyclus uit een opeenvolging van referenties naar een aantal door het programma verspreid liggende stukjes consecutief programma (de uitgeschreven cyclus, daarin gebruikte subroutines, formele parameters etc.); de vraag, die we kunnen stellen is "Als al deze stukjes M opdrachten lang zijn, wat is dan de verwachtingswaarde van de geheugenbezetting bij een paginalengte N?". Je zoudt N zo willen kiezen, dat die verwachtingswaarde minimaal is. Dat is hij natuurlijk als we N = 1 kiezen, maar dat is kennelijk niet de bedoeling: sterker, we gaan ervan uit, dan N << M onpractisch is, omdat het begrip "pagina" dan onvoldoende is om zo'n stuk van M opdrachten bij elkaar te laten horen. De kans dat het stuk van M opdrachten binnen 1 pagina komt te liggen is nu p1 = (N - M)/N, de kans, dat het stuk schrijlings over een paginagrens komt is p2 = M/N. De verwachtingswaarde van de geheugenbezetting is nu N*p1 + 2*N*p2 = N + M. Onder de bijvoorwaarde M < N vind je dus dat de ideale paginalengte N = M zou moeten zijn en een cyclus stouw je gemiddeld in twee keer zo veel geheugen als je eigenlijk nodig zou hebben. (De kans, dat je twee stukken M in dezelfde pagina zou aantreffen is verwaarloosd.)

    Op deze manier bezien is de paginalengte van circa 40 woorden in GIER ALGOL heel goed verdedigbaar: M = 40 lijkt redelijk afgestemd op allerlei standaard subroutines, de stukjes tekst, die actuele parameters vastleggen etc. Het is ook duidelijk, dat wij een grotere paginalengte moeten invoeren.

4.4.3. Voorstel tot versnelling van de verificatie. (19 juni 1963)

    Het volgende handelt alleen over de pagina's van uniforme lengte, die ik denk te gebruiken voor het bergen van opdrachten + constanten (dwz. het statische gedeelte van de procesbeschrijving). Om spraakverwarring te voorkomen spreek ik van kernpagina's en trommelpagina's; een kernpagina is een stuk kerngeheugen, bedoeld om een copie van een trommelpagina te herbergen.

    Ik ga in hoofdzaak uit van een paginalengte van 256 woorden -de consequenties der onderscheiden technieken zal ik af en toe trloops ook voor pagins's van 512 woorden vermelden-, een kerngeheugen van 32 K en 1 trommel van 512 K.

    Het kerngeheugen bergt dan maximaal 128 pagina's, de trommel maximal 2048. Ik neem aan, dat de coordinator er hoge prijs op stelt om per kernpagina enige historie bij te houden, welke trommelpagina er in gecopieerd staat, wanneer er voor het laatst naar gerefereerd is etc. Laten wen aannemen, dat voor deze administratie een woord per kernpagina genoeg is. We hebben dan 128 woorden "kernpaginatabel".
    Deze tabel mag dan ideaal zijn om bij een gegeven kernpagina vast te stellen, welke trommelpagina er in gecopieerd staat, hoewel voldoende is deze administratie nauwelijks adequaat om de omgekeerde vraag rap te beantwoorden "Staat trommelpagina [nummer] zo en zo soms ergens op de kernen gecopieerd en zo ja, waar?".

    Als we gewoon het lijstje afgaan om te kijken of hij er bij is, dan kost dit bv. 4 geheugencycli per test; aangenomen, dat de helft van het geheugen met uniforma pagina's gevuld is, dan moeten we minimaal 1, maximaal 64 tests aanleggen en komen we op een gemiddelde van 130 geheugencycli per verificatie. (Als het kerngeheugen wat te klein is en we vaak nul op het rekest zullen krijgen, ligt dit gemiddelde hoger, omdat je om afwezigheid te kunne constateren, de hele boel doormoet.) Dit zou, als we er niets aan doen wel eens 25 procent van de rekentijd kunnen gaan vergen. (Dit is geschat op een verificatie om de 40 opdrachten van gemiddeld 10 geheugencontacten of 50 van gemiddeld 8.) In elk geval te veel. Ik wil dit nu op twee manieren bestrijden:
    (1) onderzoeken hoe door extra geheugenruimte en eventueel extra werkzaamheden bij verandering der kerngeheugentoewijzing deze algemene test versneld kan worden
    (2) onderzoeken hoe we, zolang de kerngeheugentoewijzing niet verandert het aantal van deze algemene verificaties kunne drukken.

    Analoog aan de kernpaginatabel kunnen we een trommelpaginatabel invoeren.
    Die zou dan 2048 woorden beslaan en in elk woord zouden we kunnen noteren of en zo ja, waar de trommelpagina in de kernengecopieerd staat. Dit maakt de omgekeerde vraag inderdaad rap beantwoordbaar, maar tegen niet verwaarloosbare kosten. Bij wijziging in de kerngeheugentoewijzing moet de coordinator behalve de kernpaginatabel ook de trommelpaginatabel bijwerken, deze werkzaamheden zijn verwaarloosbaar, de geheugenbezetting van 2048 woorden maximaal is echter iets, waartegen ik wel een beetje hik. Bedenkend, dat je slechts vraagt naar een 7-bits antwoord, kan je met drie in een woord de omvang van deze tabel tot 683 maximaal drukken, maar dit wordt "trading speed for space".(Bij pagina's van 512 woorden heb je er maximaal 1024 op de trommel en maximaal 64 inhet kerngeheugen: 1024 6-bits antwoorden kunnen op 256 woorden worden afgebeeld. De versnelling door de trommelpaginatabel is nu minder indrukwekkend, omdat scannen van de paginatabel dan ook gemiddeld twee keer zo snel is afgelopen. Hier zien we overigens mooi, hoe grotere pagina's de administratie drukken.)

    Een alternatief om de comprimatie -van 11 tot 7 of van 10 tot 6 bits- te verrichten is om in te voeren een lijstje van de in het kerngeheugen gecopieerde trommelpagina's, naar opklimmend paginanummer gerangschikt. Dit vergt bij verwijdering en toevoeging enige extra administratie -wat geschuif- maar de vraag van het "waar" kan nu met een logarithmische zoekerij, die in gemiddeld 6 (of 5) slagen beeindigd is. De tijdsduur, die voor de logarithmische zoekerij nodig is is iets groter -volgens voorlopige probeersels- dan die nodig voor het raadplegen van de gecomprimeerde trommelpaginatabel (30 tot 40 geheugencontacten) kortom: op de 400 nog te veel om te licht over te denken.

    Je kunt ook de kernpagina's aan een ketting rijgen, aftastbaar in de volgorde van laatste referentie. Het programma, dat zo'n ketting afwandelt is een snoesje, 6 geheugencontacten per slag, als ik me niet heb vergist. Zolang je in een paar pagina's je rondjes draait, gaat de verificatie leuk en kan deze methode met de andere concurreren, maar als je er meer dan vijf, zes schakels af moet tasten, wordt het tijdrovend en moet je rekening gaan houden met maximale zoektijden van bove de milliseconde (zeg 400 geheugencontacten), nl. voor een zo [lang] vergeten pagina, dat hij al bijna op de nominatie staat om overschreven te worden. Het effect zou zijn, dat bij een plotselinge wisseling de machine "wat op zijn kop moet krabben" zich afvragende waar dat en dat ook al weer stond. In verband met multiprogrammering lijkt me dit niet aantrekkelijk. Een technisch nadeel (dat door scannen van de kernpaginatabel gedeeld wordt) is bovendien het volgende: als een trommelpagina niet op de kernen aanwezig is, ontdek je dat pas, nadat je de hele ketting, resp. tabel hebt afgewerkt en je trommeltransport kan pas daarna gestart worden. Liever een snellere detectie, dat het mis zit en administratief gehannes, nadat het transport vast in gang gezet is. Als generale administratie is het ketting rijgen dus niet bruikbaar; hoogstens kunnen we voor de vier jongste pagina's bv. in een klein cyclisch magazijntje bijhouden om kleine cycli wat te helpen, als dit nodig mocht zijn. Ik hoop van niet.

    Vooralsnog zie ik het meeste heil in de naar opklimmend trommelpaginanummer gesorteerde aanwezigheidslijst, en wel voornamelijk omdat deze lijst evenredig lang is met de kernpaginatabel, zodat ik de twee door elkaar kan vlechten. Ik moet de alternatieven gewoon uitwerken. Hoe zwaar we ruimte tegen tijd laten wegen, hangt er mede van af, hoe frequent we proberen moeten om via deze administratie bij een gegeven trommelpaginanummer een kernpaginanummer te vinden. Vooralsnog vergt dit naar schatting 10 procent van de rekentijd, ook als alles in het kerngeheugen zit. En dat vind ik nog wat veel.

    Nu de tweede mogelijkheid: de opmerking is nl. dat het niet nodig is om de vraag "waar staat trommelpagina nummer zoveel" zo rap te kunnen beantwoorden, als we een mechanisme kunnen bedenken, waardoor het aantal malen, datdeze vraag gesteld  wordt, maar genoeg gedrukt wordt.

    Voor sprongen naar de volgende pagina is de oplossing gevonden. Het feitenmateriaal, dat hiervoor door de centrale administratie bijgehouden moet worden is onafhankelijk van de omvang van het programma en onafhankelijk van de intensiteit van interpaginareferenties en tenslotte altijd up to date.

    Om verdere verificaties te onderdrukken heb ik allerlei dingen geprobeerd; de grote moeilijkheid was, dat je op grond van aanwezigheid dat gegeven wel overal rond kunt strooien, maar dat het heel moeilijk wordt om na te gaan, wat je dan allemaal herroepen moet, mocht zo'n pagina verdwijnen. Wat wij echter moeten exploiteren is het volgende: we moeten zorgen, dat de vraag "welke trommelpagina staat in die en die kernpagina?" rap beantwoordbaar is. Dat kan en uit het volgende zal blijken, dat het de moeite loont om daar alles en alles aan te doen

    Laten we als specifiek voorbeeld eens beschouwen het meegeven van de link aan een procedure (het meegeven van het beginadres van een impliciete subroutine als actuele parameter is van hetzelfde laken een pak). Het is duidelijk, dat we dit terugkeeradres invariant, dwz. in termen van trommelpaginanummer moeten meegeven, zeg om de gedachten te bepalen een adres in trommelpagina 287. Het is echter onverstandig om bij de Return de centrale administratie zonder meer te confronteren met de vraag "waar staat trommelpagina 287?". We kunnen er allicht op gokken, dat die nog op dezelfde kernpagina staat. Wat we dus moeten doen is als terugkeeradres twee dingen meegeven: een invariant trommeladres en een kernadres, het laatste als suggestie! De localisatie van een trommelpagina kunnen we beschouwen als een tijdrovend sommetje, waarvan we het antwoord heel makkelijk kunnen controleren en waarvoor we een schatting hebben, die in 95 procent van de gevallen raak zal zijn, nl. als de oude pagina nog op zijn plaats staat. Als dat niet meer het geval is, dan is er in de tussentijd zoveel gebeurd, dat de verificatietest er nog wel bij kan.

transcribed by Johan E. Mebius
revised Thu, 29 Mar 2007

10 juli 1963                                      EWD62

X8 nr. 21.

Notitie over de aansluiting en de programmering van de teleprinter.

1. Hardware

1.1. Hardware voor de teleprinter (dwz. outputorgaan).

De hardware bestaat uit:
een 2-waardige startseinpaal, genaamd "Acflop teleprinter",
een 2-waardige ingreepseinpaal, genaamd "Inflop teleprinter",
een vaste geheugenplaats, die fungeert als buffer met capaciteit van 1 karakter;
het vullen van deze vaste geheugenplaats zal ik in de tekst representeren door

"teleprinter :=....." .

Voor de bediening van het printwerk bestaat dus slechts het minimum: we kunnen geen startopdrachten accumuleren en per startopdracht kunnen we slechts 1 karakter aanbieden. De opmerking is, dat een teleprinter een zo langzaam medium is, dat alles, wat er meer ingebouwd wordt, moeilijk te verdedigen is.

     Het aanbieden van een karakter aan de teleprinter geschiedt door de sequens:

"P(Inflop teleprinter);
teleprinter:= karakter;
V(Acflop teleprinter)" .

     De P-operatie is wel een aanroep van de Coordinator, de V-operatie kan zonder meer in het programma staan (Nl. Acflop teleprinter:= 1").

1.2. Hardware voor het toetsenbord (dwz. inputorgaan).

     Hiervoor zijn twee voorstellen ter sprake geweest; het doel van deze notitie is onder andere om er achter te komen of het ene voorstel preferabel is boven het andere.

1.2.1. Toetsenbord met expliciete "Acflop".

     De hardware bestaat uit:
een 2-waardige startseinpaal, genaamd "Acflop toetsenbord",
een 2-waardige ingreepseinpaal, genaamd "Inflop toetsenbord",
een vaste geheugenplaats, die fungeert als buffer met capaciteit van 1 karakter;
het uitlezen van deze geheugenplaats zal ik in het volgende representeren door:

".......:= toetsenbord".

     Hier wordt het toetsenbord dus beschouwd als een invoermedium zonder de mogelijkheid van accumulatie van startopdrachten en per startopdracht slechts 1 karakter.

     Drukt men op de toets van het toetsenbord, dan stuurt de toetsapparatuur een startpuls, vijf informatiepulsen en een stoppuls naar de "statisizer". De bedoeling van boven gegeven arrangement is, om de statisizer slechts via het toetsenbord te vullen, als op het moment van de startpuls "Acflop toetsenbord = 1" is, terwijl deze vulling zorgt, dat "Acflop toetsenbord := 0" uitgevoerd is, voordat de volgende startpuls zou kunnen komen. Het autonoom transport probeert de inhoud van de statisizer naar de vaste geheugenplaats te transporteren, zodra dit gelukt is, wordt dit door "Inflop toetsenbord := 1" naar de computer gesignaleerd.

     Het ruwe schema, dat een karakter van het toetsenbord accepteert bestaat uit

"P(Inflop toetsenbord);
karakter := toetsenbord;
V(Acflop toetsenbord)" .

     In het kader van het tandenpoetsen moet de machine dus een keer "V(Acflop toetsenbord)" uitgevoerd hebben om voor deze invoer ontvankelijk te kunnen zijn.

1.2.2. Toetsenbord zonder expliciete "Acflop".

     Bij het vullen van de statisizer kan men "Acflop toetsenbord:= 0" uitvoeren bij de afsluitende stoppuls; omdat het autonoom transport practisch instantaan zal plaatsvinden, wordt practisch tegelijkertijd "Inflop toetsenbord:= 1" uitgevoerd.

     Omgekeerd: de luistervergunning van de "Inflop toetsenbord" zal slechts = 1 zijn, als er een toetsenbordprogramma daadwerkelijk in zijn operatie

"P(Inflop toetsenbord)"

is blijven hangen.

     Als de ingreep effect heeft en dit programma weer in de coordinator in de categorie van de (gedeblokkeerde) onderbroken programma's wordt opgenomen -dwz. als de coordinator beslist, dat dit programma zijn P-operatie voltooid heeft- dan wordt "Inflop toetsenbord:= 0" uitgevoerd (en tevens "luisterbit toetsenbord:= 0", wanneer de wachtketen aan de Inflop toetsenbord hiermee leeg is geworden).

     Aannemend, dat dit nu gedeblokkeerde toetsenbordprgramma rap aan de beurt komt -en daar is alles voor te zeggen om er in de coordinator via een prioriteitsregel voor te zorgen, dat dit inderdaad het geval zal zijn- dan zal het tweetal:

"karakter:= toetsenbord;
V(Acflop toetsenbord)"

snel daarna uitgevoerd worden.

     De opmerking nu is, dat hieruit volgt, dat deze Acflop en Inflop "bijna altijd" elkaars inverse zullen zijn en dat men zich daarom kan afvragen, of de Acflop toetsenbord -en daarmee de operatie "V(Acflop toetsenbord)"- niet helemaal vervallen kan. We moeten dan wel opnieuw afspreken wat er gebeurt als men in een te hoog tempo op de toetsen drukt.

     In het voorstel 1.2.1. had het te snel drukken van de volgende toets geen effect. Nu is het voorstel, om het te snel indrukken van de volgende toets het vorige karakter te laten invalideren. Bv. als volgt.

     Het indrukken van een toets heeft altijd ten gevolge, dat een karakter naar de statisizer gezonden wordt. Als dit echter gebeurt op een ogenblik, dat het vorige autonoom transport nog niet heeft plaatsgevonden (kans nihil) of als het autonoom transport plaatsvindt, terwijl "Inflop toetsenbord = 1" is, dan wordt op de geheugenplaats c.n. "toetsenbord" een non-valide karakter aangeboden (bv. numeriek groter dan 31). Hier kan het toetsenbordprogramma dan op testen.

2. Overwegingen bij de vergelijking.

     Bij de vergelijking van deze twee oplossingen laat ik de financiele consequentie van een en ander buiten beschouwing: ik ben niet competent om deze te beoordelen en bovendien kon het wel eens niet zo verschrikkelijk veel uitmaken.

     Voorts dienen we te bedenken:

a)
dat de kans op "te snel de volgende toets indrukken" naar wij van ganserharte hopen, klein zal zijn;

b)
dat het geen ramp is, als de boodschap in eerste aanleg verkeerd is doorgekomen, daar de operateur toch eerst zal afwachten of de "body" van de boodschap correct is uitgetypt, voordat hij de OK-melding geeft.

     Anderzijds dienen we te bedenken:

c)
dat de kans op non-validiteit, omdat het autonoom transport nog niet heeft plaatsgevonden (1.2.2.) heel klein is, maar dat het haastig is op te eisen, dat de reactie op de ingreep onder alle omstandigheden "rap" zal zijn. (We hebben nog nergens essentiele haastsituaties en ik zou me graag de vrijheid voorbehouden, om op gezette tijden -zeg eens in de vijf minuten- de machine een seconde doof te maken voor pak weg herindeling van de informatie op de trommel.) Als dan de bedienende operateur met een kans van 1 op 300 "in de war" zou raken, zou dat toch wel hinderlijk zijn.

d)
dat het gewenst is, dat in de coordinator de behandeling van het toetsenbordprogramma zich in zo weinig mogelijk van die van de andere programma's onderscheidt.

e)
dat het gewenst is, dat de operateur, in twijfel of hij een toets heeft ingedrukt, zo gauw en zo zeker mogelijk weet, waar hij aan toe is.

     Ik ga er van uit, dat opnamen van via het toetsenbord ingevoerde karakters en het uitprinten van deze karakters twee karaktersgewijze synchrone processen zullen zijn.

3. Een conventie voor teleprinterreservering.

     Als de wachtketting van een hardware seinpaal leeg is -als er geen enkel programma op deze seinpaal wacht- dan zet de coordinator de bijbehorende luisterbit = 0. Deze wordt slechts = 1, als wel een programma op het positief worden van de seinpaal staat te wachten. Dit impliceert, dat ik me ingrepen kan besparen, door zo mogelijk er naar te streven, dat P-operaties op hardware seinpalen zo laat mogelijk gepasseerd worden; is de ingreep op dat ogenblik al binnen, dan kunnen we dat meteen verifieren.

     Hieruit volgt als algemene strategie, dat we de passering van een hardware seinpaal in de programma's zo ver mogelijk naar achteren schuiven. Wat aan conventies impliceert, zullen we zo dadelijk zien. (N.B. Ik weet, dat teleprinter-ingrepen zo weinig frequent voorkomen, dat het uitsparen van ingrepen op efficiency-overwegingen hier een zwak argument is; ik wil echter de hele behandeling van de in-en uitvoer-troep zo uniform mogelijk houden, anders verdrinken we in de chaos.)

     Het is duidelijk, dat verschillende programma's van de teleprinter gebruik kunnen willen maken; het is kennelijk niet de bedoeling, dat karakters van verschillende bronnen kriskras door elkaar getypt worden: voor het uitprinten van een samenhangende tekst moet een programma de teleprinter dus voor zich reserveren. We voeren hiertoen in de geprogrammeerde seinpaal "teleprinter vrij"; dit is een 2-waardige seinpaal.

Het synchroon met de teleprinter aanbieden van een stuk samenhangende tekst kan nu door twee soorten programma gebeuren -met weglating van alle hier niet irrelevante tellingen-:

type A:
"
L:
P(teleprinter vrij);
P(Inflop teleprinter);
teleprinter:= volgend karakter;
V(Acflop teleprinter);
if B then goto L;
V(teleprinter vrij)"                      of

type B:
"
L:
P(teleprinter vrij);
teleprinter:= volgend karakter;
V(Acflop teleprinter);
P(Inflop teleprinter);
if B then goto L;
V(teleprinter vrij)" .

     In het eerste geval wordt de teleprinter vrijgegeven na de laatste tikopdracht, in het tweede geval pas na de terugmelding, dat het volgende karakter alweer getikt kan worden. Het is duidelijk, dat wij slechts een organisatie kunnen opbouwen, mits we hier een duidelijke keuze doen; mijn voorkeur gaat op grond van de eerder gegeven overwegingen uit naar type A. (Deze voorkeur is niet uiterst dwingend; dit is een reden te meer om deze conventie in alle klaarheid en met alle nadruk te formuleren!)

4. Uittikken synchroon met het toetsenbord.

     In het volgende veronderstel ik de operatie "P(teleprinter vrij)" uitgevoerd -waarover later meer- zodat niet, terwijl ik aan het "intikken" ben, een machineprogramma me de teleprinter onder de vingers weg kan kapen.

4.1. Met expliciete Acflop voor het toetsenbord.

4.1.1. De meest rigoureuze sluis, die ik me voor kan stellen bestaat uit de volgende cyclus:

"L:
P(Inflop teleprinter);
V(Acflop toetsenbord);
P(Inflop toetsenbord);
karakter:= toetsenbord;
teleprinter:= karakter;
V(Acflop teleprinter);
if B then goto L".

     Hier vraagt de machine pas om een volgend karakter van het toetsenbord, als de terugmelding van het typen van het vorige karakter binnen is. Hier weet de operateur drommels goed, waar hij aan toe is, als hij midden in het tikken van een boodschap -doordat iemand binnenkomt of door doofheid van de machine- gestoord wordt. Als de getikte letters van de boodschap alle nog correct zijn, maar hij weet niet precies meer wat hij heeft aangeslagen, dan zijn er drie mogelijkheden. (Ik neem, evenals bij de volgende toetsenbordprogrammaatjes aan, dat zij in doofheid uitgevoerd zullen worden!)

a)
het programma is (in de coordinator) in de eerste P-operatie blijven hangen, hoewel de bijbehorende ingreep al binnen is (de printer staat immers stil);

b)
het programma is in de tweede P-operatie blijven hangen, omdat de ingreep er nog niet is -de operateur moet de volgende toets aanslaan;

c)
het programma is in de tweede P-operatie (in de coordinator) blijven hangen: het voglende karakter is via de statisizer al tot de machine doorgedrongen.

     In alle drie de gevallen kan de operateur het volgende karakter aanslaan; in geval a) heeft het geen effect, in geval b) heeft het het gewenste effect en in geval c) heeft het geen effect (niet het ongewenste). Alleen in het geval c) zit er een klein, klein lekje, nl. als de operatie "P(Inflop teleprinter)" voltooid kan worden voordat het karakter goed en wel op het papier staat. Het karakter kan dan twee keer getikt worden.

4.1.2. Een iets minder rigoureuze sluis is:

"L:
P(Inflop toetsenbord, Inflop teleprinter);
karakter:= toetsenbord; teleprinter:= karakter;
V(Acflop teleprinter, Acflop toetsenbord);
if B then goto L".

     Hier kan de machine alleen in de P-operatie blijven hangen; als de teleprinter stil staat, is dus "Inflop teleprinter" geen belemmering. Of (a) Inflop toetsenbord is de belemmering of (b) er is geen belemmering, maar de coordinator gunt de machine niet. Als nu weer de tekst voorzover uitgetikt correct is, dan kan de operateur maar een ding doen: het volgende karakter aanslaan en wachten.

     In geval (a) is dit normaal het volgende karakter, in geval (b) was dit karakter al binnen en wordt zijn tweede aanslag genegeerd. Voordeel van dit arrangement is, dat 1 keer volgend karakter aanslaan beslist voldoende is. Ook dit sluisje heeft (in geval b) een lekje: vlak voordat hij de toets hernieuwd aanslaat, beeindigt de machine de P-operatie en maakt zij via de V-operatie de statisizer opnieuw ontvankelijk en de letter verschijnt dus twee maal op papier. Het lekje is iets groter, omdat het niet te verkleinen is door de ingreep van het toetsenbord te vertragen. De kans, dat doorgaan van het toetsenbordprogramma en indrukken van de volgende toets niet voldoende coincideren, lijkt me zo klein, dat we dit lekje wel kunnen accepteren. Een voordeel van dit arrangement is, dat in geval van twijfel nog 1 keer de volgende toets indrukken in elk geval op den duur soulaas moet brengen.

     Nadeel van dit arrangement is, dat "te snel inslaan" hoegenaamd niet tot de machine doordringt en dat snel inslaan van "a b c" dus "a c" op het papier zou kunnen verschijnen. Ik weeg dit bezwaar niet zo heel erg en wel op grond van de volgende overweging: als "a c" op het papier verschenen is, dan is dat naar voor de operateur, want hij moet het correctieritueel uitvoeren. Als hem dit een paar keer is overkomen, zal hij er verder wel voor oppassen, dat dit hem niet te vaak overkomt: en de gedragslijn, die hij daartoe moet volgen, is duidelijk!

4.2. Zonder expliciete Acflop voor het toetsenbord.

     We beschouwen nu de analoge versie van het programma uit 4.1.2.:

 "L1:
P(Inflop toetsenbord, Inflop teleprinter);

  L2:
karakter:= toetsenbord;
if 31 < karakter then
             begin P(Inflop toetsenbord); goto L2 end;
teleprinter:= karakter;
V(Acflop teleprinter);
if B then goto L1".

     Wat betreft het te snel aanslaan van de operateur is dit beter. Nemen we weer het te snel aanslaan van "a b c" in die zin, dat b aangeslagen wordt, voordat a correct is verwerkt. In 4.1.2. was de fout van de operateur, dat hij "c" aansloeg, voordat "b" getikt was; in dit geval moet hij, om het nu spaak te laten lopen "c" al aanslaan, voordat de "a" getikt is: de "a" wordt nl. door de te snel gekomen "b" bedorven tot een karakter dat groter dan 31 is.

     Laten we nu onderzoeken, hoe precies de operateur weet, waar hij aan toe is, als hij aarzelt wat hij heeft aangeslagen of wat door de machine geweigerd is. Het interessante geval is natuurlijk weer, dat de operateur zich even bedenkt en ziet, dat datgene, wat op papier staat, nog correct is. Het enige, wat hij kan doen is na enige bedenktijd vol goede moed het volgende karakter aanslaan, dat op papier verschijnen moet.

     Stond het programma op "Inflop toetsenbord" te wachten, dan was deze actie goed. Nu het geval, dat de volgende karakter al aanwezig was.

     Was "Inflop toetsenbord = 1", maar was de machine te lui met haar reactie hierop, dan vernietigt de nieuwe aanslag het al aanwezige volgkarakter en moet dus mettertijd nogmaals op de toets gedrukt worden.

     Was inmiddels "Inflop toetsenbord:= 0" voltooid, maar had de coordinator het toetsenbordprogramma nog niet verder laten lopen, dan zal de operateur merken, dat het volgende karakter twee keer getikt wordt.

     De kans hierop is te verkleinen, door de coordinator zo te construeren, dat, wanneer de coordinateur de operatie P(Inflop toetsenbord) voltooit, dwz. "Inflop toetsenbord:= 0" uitvoert, het nu toegestane toetsenbordprogramma inderdaad zo snel mogelijk voortgezet wordt. Dit is de prijs, die we betalen voor het dubbele gebruik van "Inflop toetsenbord' en ik vind het niet mooi.

5. Een mengvorm.

     Salvo errore et omissione combineert het volgende voorstel de deugden van beide systemen.

     Elke keer, dat een toets wordt ingedrukt, wordt een karakter naar de staticiser gezonden; als op het moment van de startpuls de staticiser nog vol mocht zijn, dan neemt de staticiser een non-valide karakter op. (Kans nihil, dit is het zelfde loffelijke perfectionisme als in 1.2.2.)

     De inhoud van de staticiser wordt nu in principe naar het geheugen doorgezonden per autonoom woordtransport, afhankelijk echter van de waarde van Acflop toetsenbord en Inflop toetsenbord op dat ogenblik. (De actie van Acflop toetsenbord is dus van het vullen van de staticiser verschoven naar het autonoom transport.)

     We onderscheiden nu drie gevallen (het vierde kan zich niet voordoen).

a)
Acflop toetsenbord = 1 en Inflop toetsenbord = 0.
Het karakter wordt zoals het zich in de staticiser bevindt, naar het geheugen doorgezonden; Acflop toetsenbord:= 0; Inflop toetsenbord:= 1);
(Dit als ondeelbare handeling. Dit is het normale geval van karaktertransport.)

b)
Acflop toetsenbord = 0 en Inflop toetsenbord = 1.
Het karakter wordt in "non-valide vorm" in het geheugen neergezet.
(Dit is het geval, dat de tweede toets ingedrukt wordt, terwijl de machine nog niet gereageerd heeft op de ingreep van de vorige. We kunnen dan het vorige karakter nog met "non-valide" overschrijven.)

c)
Acflop toetsenbord = 0 en Inflop toetsenbord = 0.
Het autonoom transport wordt onderdrukt en het karakter raakt "onder tafel".
(Op de ingreep is gereageerd en het is dus te laat, om het vorige karakter nog te herroepen; anderzijds is het tweede karakter wel te vroeg, omdat de machine er nog niet om gevraagd heeft.)

De vierde mogelijkheid komt niet voor, omdat de machine slechts Acflop = 1 zal zetten, als de Inflop = 0 is.

     De structuur van het programma is nu als volgt:

"L1: 
 L2: 

P(Inflop toetsenbord, Inflop teleprinter);
karakter:= toetsenbord;
if 31 < karakter then begin V(Acflop toetsenbord); P(Inflop toetsenbord);
                                         goto L2 end;
teleprinter:= karakter;
V(Acflop teleprinter, Acflop toetsenbord);
if B then goto L1".

     Wie nu te snel achter elkaar "a b" aanslaat, zal merken, dat er of niets (heel snel) of "a" (iets minder te snel) getypt wordt. In beide gevallen moet hij het eerste ontbrekende karakter aanslaan.

     Als nu de operateur aarzelt over wat er gebeurd is, maar de boodschap is, voorzover hij op het papier verschenen is, nog correct, dan kan de operateur na enige bedenktijd alleen maar vol goede moed het ontbrekende karakter (nogmaals?) aanslaan.

     De teleprinter staat stil en "Inflop teleprinter" kan dus geen belemmering zijn. We moeten nu drie gevallen onderscheiden.

a)
Als Inflop toetsenbord de belemmering in de P-operatie is, dan wacht het programma op het volgende karakter en het aanslaan ervan is dus correct.

b)
Als Inflop toetsenbord = 1 is, maar de machine is wegens doofheid wat lui met de reactie op deze ingreep, dan maakt de extra aanslag het aanwezige karakter non-valide en is er dus ook niets kapot. (Na verloop van tijd raakt het programma dus in toestand a), dat het karakter nogmaals aangeslagen moet worden.)

c)
Als "Inflop toetsenbord:= 0" door de coordinator voltooid is, maar het toetsenbordprogramma is nog niet aan bod gekomen, dan is het volgende karakter inmiddels onherroepbaar tot het geheugen doorgedrongen. De extra aanslag -de herhaling- deert nu niet, want deze aanslag raakt onder tafel.

     Het enige lekje, dat er nu nog in zit is hetzelfde als in het programma 4.1.2. Als de oeprateur een inmiddels ingevoerd (en geaccepteerd) maar nog niet uitgetikt karakter uit ongeduld nog eens aanslaat, precies op het ogenblik, dat de machine de V-operatie uitgevoerd heeft, dan wordt het karakter twee keer ingevoerd. Dit is echter het risico, dat ik geneigd ben om te accepteren.

     Aan de problemen van teleprinter-reservering en conventies voor herroepen van ingetikte boodschappen, dan wel OK-melding wilde ik een andere notitie wijden.

PS. Voor de misspelling van "staticiser" in het begin van deze notitie des schrijvers verontschuldigingen.

transcribed by Frank Steggink
revised Sat, 19 Jun 2004

EWD065

Over Jansen.

20 September 1963 X8 No. 25.

1. De noodzaak van luisterbits.

Een en ander zal gedemonstreerd worden aan een bandlezer.

1.1. Communicatie tussen Jansen en de X8, vanuit de X8 bezien.

Voor een bepaalde bandlezer neem ik de volgende conventies aan (zie X8, nr 22). Jansen is zich bewust van 6 elementen in de X8, die daar speciaal aan deze bandlezer zijn toegekend:
Adres f₀ voor de leegwijzer van het startmagazijn: M[f₀] = f₁ of f₁ + 2
Adres f₁, dwz. het beginadres van het startmagazijn; ik neem de volgende structuur van het startmagazijn aan: M[M[f₀]] = heersende startinformatie
M[M[f₀ + 1] = heersend klassewoord
Adres f₂ voor startopdrachtenteller: M[f₂] = 0, 1 of 2. Hiermee is geassocieerd de boolean Acflop F2: F2=(M[f₂] positief)
Adres f₃ voor ingrepenteller: M[f₃] = 0, 1 of 2. Hiermee is geassocieerd de inflop F3: F3 = (M[f₄] positief)

De qualificaties "acflop" en "Inflop" als boven gegeven zijn "X8-centrisch"; in "Jansen-centrische" terminologie zouden de twee qualificaties net andersom zijn.

Startinformatie bevat door de lengte 9 bits en voor het adres 18 bits. Er is voorshands aangenomen, dat een speciale configuratie fungeert als een opdracht "herstel OK-toestand". Deze veronderstelling is niet essentieel.

1.2. Communicatie tussen Jansen en bandlezer, vanuit Jansen bezien.

Ik neem aan, dat er voor de sybchronisatie[sic] tussen Jansen en de bandlezer twee flip-flops in het spel zijn, IF en VB.

IF is "jansencentrisch" een ingreep-flipflop;
8V is "jansencentrisch" een actieflipflop.

Jansen zal "V8 := true" slechts uitvoeren op momenten, dat IF = false; Jansen signaleert darmee, dat de bandlezer zijn volgende verrichting kan uitvoeren. Dit impliceert V8 := false en na voltooing de terugmelding IF := true.

De naam V8 is een afkorting van "Vul 8" omdat karaktertransport zal plaats vinden via een register, dat in een of ander pampflet een keer 8(and) genoemd is. Dit register is vulbaar door de bandlezer en uitleesbar door Jansen.

Als er nu geen OKF en STF waren, dan was het allemaal niet zo ingewikkeld: dan doet Jansen in wezen de cyclus: "P(IF); lees 8 en zend door; V(V8)"

Om nu OKF en STF in de beschouwing te betrekken (zoals ze in X8 nr 22 geinttroduceerd[sic] zijn) moet ik, dacht ik straks nog wat nadere veronderstellingen maken.
Ik citeer:

"Het drukken op de groene knop heeft tot gevolg: STF := RK ∨ E8; Zolang E₀ = true wordt, desnoods bij herhaling: if ¬ STF then begin OKF := false; STF := true end uitgevoerd.
Herstel-OK betekent OKF := true; if STF then wacht.

STF

en OKF zijn in deze beschrijving op enige houdende elementen. Met de rode knop (STF := true) zijn hiermee alle manieren gegeven, waarop deze twee flip-flops beinvloed kunnen worden. Ik meen voor Jansen een werkend schema te hebben, zonder dat STF tot Jansen hoeft door te dringen.

Ik veronderstel, dat Jansen wel op elk gewenst moment OKF kan uitlezen, maar niet zelf OKF kan zetten. Dit is nl. niet nodig en misschien zelfs ongewenst.

Er zijn twee verschillende verrichtingen, die Jansen van de bandlezer kan vragen en ook inderdaad aan de bandlezer moet overlaten, omdat ze willekeurig lang kunnen duren:

a) een volgend karakter, dwz. well iets niews in 8 en bandtransport

b) herstel OK-toestand en "if STF then wacht", niet iets nieuws in 8 en geen bandtransport.

Ik neem aan, dat er zich in de bandlezer een boolean HOK (Herstel OK) bevindt, die via de plug door Jansen = true gezet kan worden als de OK toestand hersteld moet worden.

Als de bandlezer de passeeroperatie op V8 uitvoert, raadpleegt hij HOK: normaal is HOK = false: dan wordt het volgende karakter in 8 afgeleverd en dit wordt door V(IF) afgerond; also daarentegen HOK = true, dan doet de bandlezer het herstel van de OK-toestand: OKF := true; L: if STF then goto L; HOK := false; V(IF) HOK vertoont enige analogie met 8 inzoverre zetten en raadplegen in de tijd strict gescheiden zijn.

Opm 1. Als Jansen successvol de passeeroperatie op IF gedaan heeft, moet Jansen kunnen detecteren of er nu een nieuw karakter in 8 is gekomen of niet, dwz. of de vorige verrichting van de bandlezer herstel-OK was of niet. Jansen kan dit ontdekken door analyse van de vorige (Heersende zo je wilt) startopdracht. Ordelijker, lijker, sneller en waarscijnlijk[sic] iets duurder is het wanneer op de bandlezerplug uitleesbaar is, of er een nieuw karakter in 8 zit, maw. of IF := true al dan niet uitgevoerd is op grond van een voltooide herstel-ok-opdracht.

Opm.2. Ook na voltooing van de herstel OK-opdracht moet Jansen de OKF uitlezen: er kan immers opnieuw storing zijn ontstaan.

Opm.3. Er is aangenomen, dat Jansen 1 maal per karakter cyclus kijkt, of de OKF nog wel true is; vlak na deze constatering kan Jansen dan nog om de volgende heptade vragen; het is de bedoeling, dat hij die dan nog krijgt, maw. dat er in de bandlezer geen blokkade zit, die dat verhindert. Jansen neemt dan verder de verantwoordelijkheid op zich, om niet om meer karakters te vragen, voordat de OK-toestand hersteld is.

1.3. De programmering voor Jansen.

Ik neem aan, dat de inviduele acties van Jansen zo kort duren, dat we hen in doofheid kunnen verrichten: als besloten is, dat een karakter van de bandlezer getransporteerd gaat worden, dan maakt Jansen die handeling eerts[sic] af, voordat hij gaat kijken of er ook iets anders te doen is.

Ik neem voorts, op financiele en organisatorische gronden aan, dat Jansen wel beschikt over een opdrachtenteller, maar niet over een levend geheugen, waarin een link kan worden opgeborgen. Interruptie in de ware zin des woords treden dus niet op. Omdat ik zo verder zo min mogelijk levend geheugen in Jansen wil veronderstellen, wordt de programmering voor Jansen een heel gebonden kunst.

Jansen kan tijdens een actie natuurlijk altijd het levend geheugen van de X8 raadplegen (zie 1.2. opm. 1). Ik stel echter, dat frequente raadpleging van het X8-geheugen in het scanproces, wat Jansen nu gaat doen, ongewenst is. Zolang Jansen wacht op werk, moet het geheugen van de X8 ongemoeid blijven.

He doel van deze notitie is, om er achter te komen, hoeveel "levend geheugen" bv. op flip-flops Jansen moet hebben, opdat uitmaken, wat de volgende actie zal zijn, een interne aangelegenheid van Jansen zal zijn. Mijn verwachting is, dat de programering voor de bandlezer als voorbeeld, de noodzaak voor luisterbits zal illustreren.

Ik ga nu, voorlopig met veronachtzaming van OKF ruwweg twee programmatjes voor Jansen maken. Bedenk hierbij, dat M[f₂] en M[f₃] -zie 1.1.- X8-centrisch Acflop en Inflop zijn, dat IF en V8 Jansencentrisch Inflop en Acflop zijn.

De twee programma's zijn: a) "L:P(M[f₂]); comment wacht op Acflop van de X8;
V(V8); comment start bandlezer;
L1:P(IF); lees 8, berg en tel; if telling ≠ 0 then
beginV(V8); goto L1 end;
M[f₀] := 2 × f₁ + 2 - M[f₀]; comment opsteppen van leegwijzer;
V(M[f₃]); comment maak ingreep voor de X8; goto L"

en
b)"L: P(M[f₂]);
L1:P(IF); lees 8, berg en tel; V(V8); if telling ≠ 0 then goto L1; M[f₀]:= 2 × f₁ + 2 - M[f₀]; goto L"

Programma a) veronderstelt, dat de "nuchtere toestand" van de bandlezer is met lege 8; programma b) veronderstelt dan het 8-register vol. Hier zit weer zo'n willekeur als en EWD62 gesignaleerd is. Zonder veel overtuiging kies ik voor programma a): ik kom hier straks nog op terug.

Nu wil ik echter tot uiting laten komen, dat Jansen geen echte ingreep heeft. Dit komt in de programmatjes daarin tot uiting, dat ik ze niet als cycli, maar als gestrekte stukjes schrijven kan, ingeleid door een P-operatie en afgesloten door een "klaar", dwz. de sprong naar de distributeur, de scannerij, met vergeting van het feit, dat we op de plaats "klaar" een proces weer onderbroken hebben. In het inwendige van zo'n stukje mag dan geen P-operatie meer voorkomen.

Versie a) valt dan uiteen in twee losse stukken, waarvan de gewenste afwisseling door een luisterbit LV geregeld kan worden: "P(M[f₂], LV); V(V8); klaar" en
"P(IF); lees B, berg en tel; if telling ≠ 0 then
V(V8)else
beginM[f₀]:= 2 × f₁ + 2 - M[f₀]; V(M[f₃], LV) end;
klaar"

De laatste V-operatie maakt een ingreep voor de X8 en signaleert via LV, dat wat Jansen betreft, de volgende startopdracht geaccepteerd kan worden.

Ik kan me dit voorstellen, mits op de plug van de bandlezer voor IF en V8 drie "draadjes" zitten, een uitlesesdraadje voor IF, een false-zet-draadje voor IF en een true-zetdraadje voor V8.

In deze conceptie mogen de laatste twee draadjes niet samenvallen. Doen ze dat wel, dan moeten we een programma maken in stijl b) en dat kost ons dan in Jansen een tweede luistervergunning, nl. om de terugmelding van bandlezer naar Jansen "er is weer een volgend karakter" in geval van nog niet ontstane interesse tijdelijk te kunnen negeren. Nl.: P(M[f₂], LV₁); V(LV₂); klaar" en
"P(IF, LV₂); lees B, berg en tel; V(VB); if telling ≠ 0 then V(LV₂) else
begin M[f₀] := 2 × f₁ + 2 - M[f₀]; V(M[f₃, LV₁) end; klaar"

Vergelijking van deze twee programmatjes illustreert aardig, hoe we de flip-flop, die we bij de bandlezer kunnen uitsparen, er bij Jansen weer bijkrijgen.

We veronderstellen op het ogenblik dus een machanisme, dat de uitkomsten van logische producten scant en op gront van het = 1 zijn naar een bepaald programmatje springt. Ik neem aan, dat daar de P-operatie voltooid wordt. In het laatste programma kan ik daar IF:= 0 uitvoeren (idnentiek aan V(VB)). In plaats van meteen ook LV₂ := 0 (pardon, ik bedoel LV₂ := false) uit te voeren, kan je de luisterbit laten staan en hem pas afzetten, als de telling op blijkt.

Nu het programma in versie a) met inbegrip van de OK-flipflop. Ik veronderstel dat er nu op de plug een uitleesdraadje voor OKF zit en een true-zetdraadje voor HOK. Om schrijfwerk (dwz. programmeruimte) te besparen, lopen de twee stukjes na enige tijd samen.

"P(M[f₂], LV);
if herstel OK-toestand in startmagazijn then begin HOK:= true; V(V8); klaar end
else
L: begin meldt OKF in klassewoord;
M[f₀]:= 2 × f₁ + 2 - M[f₀]; V(M[f₃], LV); klaar end"

en
"P(IF); if herstel OK-toestand then goto L;
lees 8, berg en tel;
if ¬ OKF ∨ telling = 0 then goto L;
V(V8); klaar".

Wij merken hierbij op:

dat 1.2. opm.1. slaat op de test "if herstel OK-toestand" in de eerste regel van het tweede programma

dat een analoog programma in versie b) ook vast wel te maken is

dat het symbolisch afwerken in het geval van een groot startmagazijn niet Jansen gedurende lange tijd blokkeert

dat we "HOK := true" op zichzelf al als start van de bandlezer kunnen beschouwen.

dat we een IF₁ en IF₂ hadden kunnen invoeren, waarbij IF₁:= true een niew karakter aankondigt en IF₂:= true een voltooide herstelling van de OK-toestand, wat ik echter niet gedaan heb, om het aantal bits, dat gescand moet worden in de toestand "klaar" niet nodeloos te laten oplopen. Ik laat voorlopig nog in het midden, hoe deze scan plaatsvindt: als deze scan als cyclus uitgeprogrammeerd wordt, dan hangt de tijd die verstrijken kan tussen het true worden van een flip-flop (of logisch product) en het ogenblik, dat Jansen dit ontdekt, ook als Jansen niets anders te doen heeft, van de grootte van deze cyclus af.

In het geval van uitgeprogrammeerd scannen kunnen we "klaar" nog op minstens twee manieren programmeren: of als een sprong naar een vast punt, waar we de boolean condities op een vaste volgorde gaan onderzoeken, en als we niets vinden, dat gedaan kan worden, springen we weer naar het begin van deze lijst terug. Of: we onderzoeken de boolean voorwaarden cyclisch, maar als we een programmatje uitgevoerd hebben springen we midden in de scanketen, vlak onder de plaats, waar we hem verlaten hebben. Mengvormen zijn ook nog mogelijk, maar dan lijkt het me al ras heel moeilijk, om iets over maximale wachttijden etc. te weten te komen.

Ik heb wel idee, hoe ik hier enige gegevens over zou kunnen krijgen, of ik er binnenkort aan toe kom, is een tweede. Totzover lijkt me de moraal, dat het verwijderen van de plicht om link's te kunnen bergen tegen de prijs van extra luisterbits me een voordelig handeltje lijkt.

transcribed by David J. Brantley
latest revision Sat, 29 May 2004

EWD68

Some Comments on the Aims of MIRFAC.

Dear Editor,

Recently H.J. Gawlik [1] has published an article on project MIRFAC: A Compiler Base on Standard Mathematical Notation and Plain English. Its author is aware of earlier projects along analogous lines (MADCAP and COLASL [2]). When I heard of these earlier projects I was filled with some amazement for what they aimed to seemed to me hardly a sensible thing to do. I did not raise my voice then, convinced and trusting that people would discover this for themselves in a very short time. Now, two and a half years later I am faced with the fact that the movement has not died its natural death as I had supposed it would do. This discovery has cause me some disappointment and I can only regret my earlier silence on the subject.

The justification for the project MIRFAC seems the opinion that what is right for communication from man to man should also be right for communication from man to machine. (This is the only interpretation which allows me to attach a meaning to Gawlik's statement "that a compiler should aim not merely to simplify programming, but to abolish it.") But this opinion should not pass unchallenged!

If we instruct an "intelligent" person to do something for us, we can permit ourselves all kind of sloppiness, inaccuracies, incompleteness, contradictions etc., appealing to his understanding and common sense: he is not expected to perform literally the nonsense he is ordered to do, he is expected to do what we intended to order him. And a human servant is therefore useful by virtue of his "disobedience". This may be of some convenience for the master who dislikes to express himself clearly; the price paid is the non-negligible risk that the servant performs, on his own account, something completely unintended.

If, however, we instruct a machine to do something we should be aware of the fact that for the first time in the history of Mankind we have a servant to our disposal who really does what he has been told to do. In man-computer communication there is not only a need to be unusually precise and unambiguous, there is, at last, also a point in being so, if at least we wish to obtain the full benefits of the powerful obedient mechanical servant. Efforts aimed to conceal this new need for preciseness -for the supposed benefit of the user- will in fact be harmful: for at the same time they will conceal the equally new possibilities of automatic computing, of having intricate processes under complete control.

I go on quoting Mr. Gawlik: "... MIRFAC has been developed to satisfy the basic criterion that its problem statements should be intelligible to non-programmers, with the double aim that the user should not be required to learn any language that he does not already know and that the problem statement can be checked for correctness by somebody who understands the problem but who may know nothing of programming."

I do not see the point of Mr. Gawlik's "basic criterion". Elsewhere (see [3]) I have warned against the "...tendency to design programming languages so that they are easily readable for a semi-professional, semi-interested reader. (Symptoms of this tendency are languages the vocabulary of which includes a wild variety of English words to be used in a nearly normal sense, and some translators that even allow a steadily expanding list of synonyms and misspellings for these words. Particularly, languages designed under commercial pressure have suffered seriously from this tendency.) It looks so attractive: "Everybody can understand it immediately." But giving a plausible semantic interpretation to a text which one assumes to be correct and meaningful, is one thing; writing down such a text[.....]expressing exactly what one wishes to say, may be quite a different matter!" On comparable grounds, John McCarthy calls "COBOL .. a step up a blind alley on account of its orientation towards English which is not well suited to the formal description of procedures" [4].

Furthermore, to set Mr. Gawlik's double aim is fooling oneself. Standard mathematical notation has been designed to describe relations and now we have to define processes. Plain English has grown out of a need of interhuman communication, to be vague and ambiguous, to tell jokes and to sing nursery rhymes, but is obviously unfit to express what has to be expressed now. One can borrow mathematical notations, one can borrow English words, but completely new semantics must be attached to them and despite its superficial similarity one creates a new language. And I think the similarity more misleading than clarifying.

This fear is confirmed by Mr. Gawlik's second aim, viz. "that the problem statement can be checked for correctness by somebody who understands the problem but who may know nothing of programming." Of course he can check it, but the crucial point is whether he will find the errors! And of course he will not find them: for in human communication one is constantly trained to try to understand the others intentions and not to notice the nonsense. The corrector who understands the problem but knows nothing of programming, will be misled by the familiarity of the characters and the words and he will, in all probability, be satisfied if he recognizes the problem.

I am all in favor of clear and convenient Algorithmic Languages, but, please, let them honestly be so: to disguise them in clothes which have been tailored to other purposes can only increase the confusion.

E.W. Dijkstra
Department of Mathematics
Technological University
Postbox 513
EINDHOVEN
The Netherlands

References:

Gawlik, H.J. MIRFAC: A Compiler Based on Standard Mathematical Notation and Plain English. Comm. ACM 6, 9 (Sep.1963).

Wells, Mark B. MADCAP: A Scientific Compiler is a Displayed Formula Textbook Language. Comm. ACM 4, 1 (Jan. 1961).

Dijkstra E.W. On the Design of Machine Independent Programming Languages. In Goodman, R. (Editor): Annual Review in Automatic Programming, Vol. III Pergamon Press, 1961.

McCarthy, John. A Basis for a Mathematical Theory of Computation, Preliminary Report. Western Joist Computer Conference, 1961.

transcribed by Ken Dyck
last revision Wed, 13 Oct 2004

  EWD 69

4 november 1963

Over stapeladministratie

1. Binnenblokken, procedureblokken en blokhoogte.

     Het begrip blok is louter lexicographisch. Het hele programma is per definitie een blok, binnen in een blok kunnen een of meer andere blokken gedefinieerd worden. Behalve de ALGOL-blokken voeren wij nog in:
a) een procedure-declaratie is per definitie een blok
b) een for-statement is per definitie een blok.

     Wij onderscheiden nu twee soorten blokken:
a) procedureblokken
b) alle overige blokken; deze noemen wij "binnenblokken".

Opm. Wij laten voorlopig even buiten beschouwing of we de procedure body als binnenblok van het procedureblok beschouwen.

     De aldus ingevoerde blokken hebben de eigenschap, dat elk blok met uitzondering van het programma-blok in een ander blok gedefinieerd is. We voeren nu in het begrip "blokhoogte", dwz. het programma-blok krijgt blokhoogte 0. Elk ander blok krijgt een blokhoogte 1 hoger dan die van het lexicographisch onmiddellijk omvattende blok.

2. Binnentophoogte en display.

     Aan elk procedureblok kennen we toe een zg. "binnentophoogte". Ook de binnentophoogte is een zuiver lexicographisch begrip: de binnentophoogte is 1 meer dan de maximum blokhoogte in het inwendige van het procedureblok zonder dat het in een daarin inwendig procedureblok zit. (Andere definitie: het is 1 meer dan de maximum inwendig voorkomende blokhoogte na verwijdering van alle erin voorkomende proceduredeclaraties.)

     Binnenblokken hebben de eigenschap, dat men ze slechts vanuit het onmiddellijk omvattende blok kan binnengaan, dit in tegenstelling tot procedureblokken.

     Bij binnenkomst van een procedureblok, en alleen dan, zullen we een nieuwe display invoeren. De lengte van deze display kiezen we gelijk aan de binnentophoogte, dwz. groot genoeg om te garanderen, dat we erin de ruimte hebben om (zie onder) de binnenblokken van deze procedure te kunnen behandelen.

     De opmerking is nl. dat de techniek van de MC1-vertaler voor ingaan en uitgaan van een binnenblok echt wel efficient is. De MC1-vertaler werkt met een vaste display. Bij binnenkomst hoef je alleen een nieuw element in de display in te vullen en de stapelwijzer op te hogen, bij verlating hoef je alleen de stapelwijzer af te lagen (en displayelement te negeren, maar dat kost niet zo'n moeite.)

     Hebben we echter, als in de MC1-vertaler een enkele display, dan hebben we om de haverklap de plicht tot de operatie UDD (Up Date Display). De bewering is, dat slechts een nieuwe display invoeren bij binnenkomst van het procedureblok voldoende is om alle UDD-operaties kwijt te zijn - dwz. te kunnen condenseren tot wisseling van L.

3. De werkruimtewijzer WW.

     Tussen statements keert de stapelwijzer SW in een blok steeds terug tot hetzelfde rustpunt; we noemen dit de werkruimtewijzer WW: hij wijst naar de eerste stapelplaats voor de anonyme tussenresultaten.

     Normaliter hoeft men zich over de WW-waarde van een blok niet te bekommeren. Tijdens de uitvoering van een statement wordt immers de SW evenveel opgehoogd als afgelaagd en de SW keert automatisch tot zijn rustpunt terug. We hebben echter ook de zg. "plotselinge blokverlating": in een blok kan een "goto L" staan, waarbij "L" een globale label is. Als we hierin terugkeren in een blok, dat we via een type procedure, dwz. midden in een statement, tijdelijk verlaten hebben, dan hebben we in het bestemmingsblok als regel nog een paar anonyme tussenresultaten te vergeten, maw: SW moet teruggezet worden op de waarde van WW, die bij de activering van het bestemmingsblok behoort.

     Onze gedachten bepalen we even tot binnenblokken. Als we zitten in een binnenblok B van hoogte n, dan zijn we daarin gekomen via het nauwst lexicographisch omvattende procedureblok op hoogte m ( m < n ). Bij de binnenkomst in dat procedureblok A hebben we in de stapel een nieuwe display ingevoerd, waarvan de onderste m elementen uit een andere display gecopieerd zijn (zie onder), waar het m + 1ste element uit de SW is afgeleid en waarvan de overige elementen beantwoorden aan de binnenblokken van A. Het idee is, om tijdens de uitvoering van binnenblok B de locale grootheden van dit blok te localiseren ten opzichte van element n van deze display en element n + 1 gelijk te laten zijn aan de bijbehorende waarde van WW. Gaan we een binnenblok van B in, dan fungeert element n + 1 onveranderd als referentiepunt voor de locale grootheden van dit blok en element n + 2 bergt dan de (binnen-)WW. Dit is de reden, waarom de binnentophoogte 1 hoger gekozen is dan de maximum voorkomende binnenblokhoogte.

4. Ingaan en uitgaan van binnenblokken.

     Bij het ingaan van een binnenblok op hoogte n en bij het uitgaan moeten we de waarde van n weten: bij het binnengaan om te weten waar (nl. op plaats n + 1 van de display) we de nieuwe WW invullen, bij het verlaten omdat we dan de SW terug moeten zetten, dwz. gelijk moeten maken aan element n van de heersende display.

     In de programmatekst is de heersende blokhoogte, wat een lexicographisch bepaalde grootheid is, desgewenst statisch bekend en we kunnen de mechanismen "binnenblok in" en "binnenblok uit" creeren, zodat ze van het programma een parameter meekrijgen, dwz. "binnenblok in van hoogte n" en "binnenblok uit van hoogte n".

     Een alternatieve oplossing is, om "ergens" —waarover dadelijk meer— het systeem de heersende blokhoogte bij te laten houden: "Binnenblok in" en "Binnenblok uit" krijgen dan geen parameter van het programma mee, maar raadplegen en wijzigen zelf de "ergens" te vinden heersende blokhoogte. Dit laatste is een techniek, die mij iets meer aanspreekt, hoewel ik er op het moment slechts vage argumenten ten gunste van weet te bedenken. Het is het algemene argument, dat je in je programma niet hoeft te vermelden, wat het verwerkende systeem uit de structuur kan afleiden. (Op precies dezelfde manier als we de waarde van de stapelwijzer niet expliciet aangeven, maar door de stapelende opdrachten laten meesjouwen.) De tekst van het programma wordt door deze technieken korter. een nevenvoordeel is, dat de inhoud van de stapel, door de heersende blokhoogte daarin onder te brengen, sprekender wordt. (Dit is voorlopig ook nog vaag: het zou wel eens gewenst kunnen zijn, dat we in de stapel een zodanige administratie bijhouden, dat de stapelinhoud op elk gewenst moment "extern interpretabel" is. Ik denk aan stapelverschuivingen door de coordinator en post mortem dumps.)

     Als we de heersende blokhoogte willen onthouden, dan rijst de vraag: waar?

In de MC1-vertaler deden we dit op een vaste plaats: daar was de heersende blokhoogte een in enkelvoud aanwezige, plaatsgebonden staturvariabele. Dit zou voor ons onpractisch zijn in verband met multiprogrammering, omdat we dan bij wisseling van programma de heersende blokhoogte zouden moeten redden. Als we de heersende blokhoogte als globale variabele van een programma invoeren, dwz. onder in de stapel van dat programma, dan hebben we de multiprogrammeringsmoeilijkheid ondervangen, maar zijn we wat betreft de uni-programmering nog net in de toestand die we bij de MC1-vertaler hebben: redden en herstellen bij procedure aanroepen en returns. Mijn voorlopige suggestie is, om de heersende blokhoogte op te bergen bij de heersende display, dwz. als ML[–1]. Deze suggestie is voorlopig, omdat ik nog moet nakijken, of we door de nog niet in het beeld betrokken parametersituatie niet in moeilijkheden komen.

     De heersende blokhoogte kan dan bij ingaan en uitgaan van binnenblokken bijgehouden worden; bij binnenkomst in een procedure, waar we een nieuw display introduceren, moet de blokhoogte van de procedure bekend zijn (nl. om te weten, hoeveel plaatsen in de nieuwe display gecopieerd moeten worden); bij die gelegenheid kan ook de initialisering van het nieuwe heersende bloknummer verzorgd worden.

     Ik eindig deze korte notitie met het signaleren van de volgende mogelijke complicaties:

1) bij blokverlating moeten we, als er in dit blok "grote arrays" geintroduceerd waren, de door deze arrays bezette trommelpagina's weer vrijgegeven worden.

2) bij "plotseling blokverlating" kunnen een heleboel blokken uit de stapel verdwijnen; wederom geldt, dat aflagen van SW niet voldoende is, omdat er ook grote arrays hierdoor afgevoerd kunnen moeten worden.

3) in de parameter-situatie zitten we nu heel anders: we werken dan onder controle van een heersende L, maar het daarbij geborgen blokhoogte-gegeven ML[–1] heeft op dat ogenblik geen betekenis. Dit zou zich kunnen wreken, als we er over denken, wat we moeten doen, als de stapel verschoven moet worden.

E.W.Dijkstra

transcribed by Sam Samshuijzen
revised Fri, 6 May 2005

  EWD 70

Over stapeladministratie. II

0. Inleiding.

     Ik had aanvankelijk gehoopt, dat we een min of meer volledig overzicht zouden krijgen over de in aanmerking komende mogelijkheden en dat we tevens de criteria zouden krijgen met behulp waarvan we tussen deze mogelijkheden zouden kunnen kiezen. Dit vlot echter niet zo erg, mijn geduld raakt wat op en ik wil wel eens een voorstel zien, dat in elk geval werkt en niet te gek is. Ik hoop dus nu de verdieping van ons inzicht op een andere manier te bereiken, nl. door critische beschouwing van een concreet voorstel. De rest van deze notitie is aan zulk een voorstel gewijd.

     Mijn eerste zorg zijn drie fundamentele problemen, te weten:
a) abrupte blokverschuiving
b) stapelverschuiving
c) paginavrijgave voor zg. grote arrays.

     Daarbij komt dan nog een practisch probleem aan de orde, nl. optimalisering van de red - en herstelprocedure in het geval van de zg. "simpele impliciete subroutine".

     Over de stapelverschuiving het volgende: behalve de lijstjes van de referentiepunten (de displays) hoeven we in de stapel geen absolute adressen op te nemen, die verwijzen naar punten in de stapel; deze laatste kunnen we altijd opbergen relatief t.o.v. het begin van de stapelbodem. (Of we het altijd zullen doen is een tweede: aangenomen dat stapelverschuivingen dingen zijn, die tot de zeldzaamheden behoren, krijgen we wellicht een sneller systeem, als we waar mogelijk met physische adressen werken.)

     Uit het bovenstaande volgt, dat het belangrijk is, dat in de stapel de referentielijstjes gevonden kunnen worden; het is hier, dat we onderscheid maken tussen een procedure (dwz. nieuw lijstje) en ingewikkelde impliciete subroutine (dwz. terugvallen op een oud lijstje). De simpele impliciete subroutine kunnen we hier dacht ik buiten beschouwing laten, omdat deze immers in doofheid uitgevoerd wordt.

     Ik ga nu stapelbeelden voorstellen om toe te voegen bij activering van een procedure, resp. ingewikkelde parameter.

1. Aanroep van een procedure.

     Het is de bedoeling dat het volgende mechanisme gebruikt wordt zowel voor de formele als voor de nonformele procedure, zowel voor de type procedure als de non-type procedure. Het is de bedoeling dit mechanisme blindelings te volgen in het geval van de type procedure call als zelfstandig statement. (De type procedure zal zijn waarde in het F-register afleveren; bij terugkeer zal SW wijzen naar de stapeltop in de zin van Voorhoeve, dwz. naar de eerste vrije plaats in kerngeheugen. Negeren van dit resultaat is dan al heel eenvoudig!)

     Ik veronderstel, dat we voor de formele plaatsen aan twee woorden genoeg hebben en dat ook de invariante representatie van het terugkeeradres aan twee woorden genoeg heeft. (Deze veronderstellingen zijn waarschijnlijk niet juist, maar dat is in dit verband niet essentieel.) Op de volgende pagina is het voorgesteld stapelbeeld gegeven.

     Opm.1 Het "centerpunt" wordt dus door een statusvariabele "d" vastgehouden, die in het kader van deze introductie de waarde d = d[i] krijgt; de waarde aan call-kant - hier aangeduid

M[d – 3 – 2 * nf] M[d – 3 – 2 * nf] | ┑ │ formele plaatsen van de 1ste parameter ┙
| ⋮ ⋮
M[d – 5] M[d – 4] | ┑ │ formele plaatsen van nf-de parameter ┙
M[d – 3] M[d – 2] | ┑ │ invariant terugkeeradres ┙
M[d – 1] | = nf
M[d] | = d[i – 1]
M[d + 1] | = L[i] (=d + 3)
M[d + 2] | = bn[i]
M[d + 3] | = 0-de referentiepunt ⋮ ⋮

met d[i – 1] - wordt hier gered. De index i onderscheidt in deze beschrijving de vigerende activeringen van procedures en ingewikkelde parameters. NB. De index i speelt alleen een rol in deze beschrijving, in het werkende systeem wordt deze niet bijgehouden, we voeren dus geen dynamische diepteteller in. Met "bn[i]" is gemeend de heersende blokhoogte als geintroduceerd in EWD69; L[i] is de alvast in de stapel neergezette heersende waarde van L.

Opm.2 Het stapelen van "nf" is strikt genomen overbodig, maar ik wou het toch maar doen:

a)  
het maakt een dynamische controle op de juistheid van het aantal meegegeven parameters mogelijk

b)  
het maakt het - desgewenst - mogelijk om (in de bibliotheek) procedures op te nemen met een variabel aantal parameters.

c)  
het terugkeermechanisme hoeft van de procedure niet meer het gegeven mee te krijgen, hoeveel formele plaatsen vergeten kunnen worden.

2. Aanroep van een gecompliceerde parameter.

     Dit genereert aan de top van de stapel

M[d – 3] M[d – 2] | ┑ │ invariant terugkeeradres ┙
M[d – 1] | = negatieve value-address indicatie
M[d] | = d[i – 1]
M[d + 1] | = L[i] (= L[j] met j < i)

     Dit stapelbeeld beantwoordt aan de aanroep van de impliciete subroutine. De impliciete subroutine is eenvoudiger dan de volslagen procedure in zoverre er geen parameters aan worden meegegeven; hij is ingewikkelder omdat (nl. als de actuele parameter een geindiceerde variabele is) zijn aanroep ook als "left-hand side" van de assignment statement voor kan komen.

     Voor deze laatste complicatie zijn ettelijke oplossingen. Het boven gegeven stapelbeeld beantwoordt aan de techniek, waarin het objectprogramma van de body zijn behoefte kenbaar maakt met behulp van "Take formal address" of "Take formal value". Welke van deze twee aanroepen gegeven wordt, moet dan in de stapel opgeslagen worden.

     Een alternatief is, dat het objectprogramma slechts zegt "Go formal" en dat de impliciete subroutine behalve zijn primitieve resultaat er bij aflevert de indicatie "address" resp. "value". Het objectprogramma kan dan aan de call kant van de impliciete subroutine inlassen
a) als linkerkant "if value alarm"
b) als rechterkant "if address, take value"

     Een derde mogelijkheid is, om altijd "value" en "address" af te leveren en aan call kant het gewenste te selecteren. Hierbij doe je echter altijd te veel. (Dit is bovendien naar als de waarde nog ongedefinieerd is; ik zou niet graag door een parity fout gestraft worden.)

     De bovengenoemde beelden zijn gesuggereerd in de veronderstelling dat het teken van M[d – 1] steeds descriptief zou zijn voor de situatie procedure resp. impliciete subroutine. (Dit impliceert, dat een procedure zonder parameters van de call kant nf = +0 mee moet krijgen; het onderscheid tussen "value" resp. "address" kan dan door –0 en –1 gemaakt worden.)

     In beide gevallen zouden we zonder de indicatie in M[d – 1] kunnen; het onderscheid tussen de twee stapelbeelden kunnen we ook maken door de testen of er een nieuwe referentielijst is ingewoerd, dwz. of M[d + 1] = d + 3 is of niet.

3. Simpele impliciete subroutine.

     In dit geval hoeft alleen het terugkeeradres in de stapel opgenomen te worden. Het onderscheid tussen value en address bestaat niet, het is nl. altijd value. (De enkele variabele identifier als actuele parameter geeft nl. geen aanleiding tot een impliciete subroutine; het moet een echte expressie zijm. Hier is het feit, dat de indicering in de actuele parameter de impliciete subroutine per definitie ingewikkeld maakt een meevaller!)

4. Stapelverschuiving.

     Tijdens de simpele impliciete subroutine kan geen interruptie optreden en kan dus ook geen behoefte aan verschuiving optreden. In alle andere gevallen geeft de heersende waarde van de statusvariabele "d" ons de clou, hoe we verder moeten gaan. De referentielijsten kunnen we feilloos vinden en dus kunnen we de verschuiving bijwerken. De gestapelde L-waarden en de geketende d-waarden kunnen we eveneens feilloos vinden en ook hier kunnen we ons de luxe van physische adressen veroorloven. Dankzij de conventie van de gestapelde nf kunnen we ook alle formele plaatsen eenduidig vinden. Als we hier een goede layout voor kiezen, kunnen we ook hier misschien ons de luxe van physische adressen veroorloven. (Het is questieus of ons dat geen verdere ellende oplevert. We moeten niet de vergissing van de B5000 maken!)

5. Paginavrijgave.

     Zoals d inhaakt op de jongste schakel van de dynamische ketting, zo kunnen we een statusgrootheid e invoeren (eveneens per programma), die inhaakt op de jongste storage function van een groot array; storage functions van grote arrays ketenen we op de gebruikelijke manier.

     In geval van blokverlating onderzoekt men, of hierdoor SW onder de heersende waarde van e gezakt is: zo ja, dan zakt men de ketting af, daarbij alle gepasseerde storage functions scannend voor vrij te geven pagina's. Hiermee gaat men door totdat e onder SW gezakt is.

transcribed by Sam Samshuijzen
revised Fri, 6 May 2005

  EWD 71

Over pagina-administratie

Het idee is, om in elk programma voor elke in dit programma voorkomende trommelpagina eem zg. TPV (= trommelpagina variabele) in te voeren. De TPV's komen in de stapel van het bijbehorende programma. Ik zie minstens twee klassen:

a) opdrachten-pagina's
b) array-pagina's

De TPV's voor de opdrachten-pagina's van een programma zijn locale variabelen van het buitenste blok; zij worden geïnitialiseerd door de vertaler/inlezer.

De TPV's van grote array's worden, hoger in de stapel, geïnitialiseerd door de array-declaratie en afgevoerd door de blok-verlating.

De bedoeling van de TPV's is, om snel antwoord te kunnen krijgen op de vraag "Kaatje ben je boven?". Wij zouden dit kunnen bewerkstelligen door in de kernen een volledige —gestrekte— inhoudsopgave van de trommel(s) bij te houden, maar met duizend pagina's per trommel kost dit ons, als we niet in een onbarmhartig geschuif willen vervallen, per trommel minstens 3% van de kernen per trommel, ook al gebruik je deze trommelruimte niet.

Nu we de TPV's onderbrengen bij de locale variabelen van de programma's hebben we bereikt, dat er in de kernen niet meer TPV's onthouden hoeven te worden, dan trommelpagina's, waarin mogelijk interesse kan bestaan.

Een gevolg hiervan is dat de interne formulering van het objectprogramma er vrij ongevoelig voor is, welke trommelpagina's nu eigenlijk door dit programma bezet worden: dit staat nl. niet meer door het hele programma verspreid, maar (éénmalig) in de TPV's. Voor de huishouding op de trommel neem ik aan, dat dit voordelen biedt; het betekent wel, dat de wijze, waarop bibliotheekprocedures naar elkaar moeten kunnen refereren me met enige zorg vervult (met "later zorg", om precies te wezen).

Naast de, in de programma's ondergebrachte, TPV's hebben wij ook nog de "inhoudsopgave van de kernen". Deze bevat een element per kernpagina, de omvang van de kernpaginatabel kunnen we meteen instellen op maximaal gebruik van de kernen. (Gebruiken we een stuk van die inhoudsopgave niet, dan betekent dit nl. dat we een stuk van het kerngeheugen niet nodig blijken te hebben, maar dan hadden we het kennelijk breed en konden we het ook breed laten hangen.) De relatieve prijs van deze tabel is de omvang van een element/omvang van een kernpagina. Dit is weer een argument voor niet te kleine pagina's. Elementen van deze inhoudsopgave noem ik KIE (Kernen Inhoudsopgave Elementen).

We gaan nu onderzoeken, wat alzo in een TPV en een KIE onthouden moet worden. De tendens zal zijn, om de omvang van een TPV klein te houden —hiervan kunnen we er immers zoveel hebben. In een TPV moeten we in de eerste plaats onthouden, of zich een copie in de kernen bevindt. Ik stel voor:

TPV ≥ +0 betekent: pagina in kernen aanwezig

TPV ≤ –0 betekent: pagina niet in kernen aanwezig.

In het geval TPV ≥ +0 moeten we dus aangeven, waar deze pagina zich dan wel bevindt. We kunnen opgeven: het beginadres in de kernen of het adres van de overeenkomstige KIE (deze zijn uit elkaar af te leiden). Ik denk dat het KIE-adres het handigste is, de KIE hebben we nl. waarschijnlijk tòch nodig. (Ik laat nog in het midden, of we in de KIE wellicht het kernenadres van de pagina opnemen; dit is dan abundant, maar kon ons wel eens op een welkome wijze geschuif besparen. Zodra we dit doen, zijn we bovendien van tweemachten af als opgelegde lengte van een KIE.)

In het geval TPV ≤ –0 moeten we nog onderscheid maken tussen "trommelpagina gereserveerd" en "nog geen trommelpagina gereserveerd". Dit laatste kunnen we nl. tegenkomen bij een TPV, die hoort bij een groot array. In het eerste geval kunnen we de TPV het beginadres op de trommel laten bevatten, het tweede geval kunnen we b.v. karakteriseren door TPV = –0.

Referentie naar een trommelpagina met TPV ≤ –0 loopt nu verschillend. In beide gevallen moet er een kernpagina gekozen worden. Als TPV ≠ –0, dan is er een —nu een wel-omschreven— transportplicht van trommel naar kernen; als TPV = –0, dan moeten we uit de "vrije trommelpaginalijst" een nieuwe trommelpagina aanvragen, van deze "bezetting" nota nemen en niet feitelijk transporteren. (Deze transport is overbodig en misschien zelfs schadelijk: waarom zou je b.v. nodeloos eisen, dat bij lang niet gebruikte trommelpagina's de pariteit zou deugen?)
Opm. De toekenning van trommelpagina kan ook uitgesteld worden, totdat werkelijk gedumpt moet worden.

Nu gaan wij over tot de KIE. Als wij voor een TPV slechts één woord ter beschikking stellen, dan betekent dit, dat we in de TPV geen ruimte meer hebben om het trommeladres op te bergen, zodra de pagina zich op de kernen bevindt. M.a.w.: dan hebben we de plicht om in de bijbehorende KIE het trommeladres bij te houden.

Wat we in een KIE allemaal gaan bijhouden, weet ik nog niet zo precies; de KIE's zullen nl. ook uitgebreid door de coordinator bespeeld worden. Ik zie zo met het blote oog drie toestanden voor een kernpagina, toegekend, wisselend en vogelvrij.

Een kernpagina wordt vogelvrij, zodra er in de inhoud geen interesse meer is. Het treedt op bij blokverlating, als dit blok grote arrays bevat. Bij deze blokverlating moeten de TPV's, die hierdoor boven de stapeltop komen, gescand worden. Vinden we een TPV = –0, dan hoeven we niets te doen, vinden we een TPV < 0, dan moeten we de in de TPV vermelde trommelpagina aan de lijst van vrijen toevoegen; vinden we een TPV > 0, dan is dat een KIE-adres. De in deze KIE vermelde trommelpagina worde aan de lijst van vrijen toegevoegd en in de bijbehorende KIE moeten we nu "vogelvrij" noteren. Voor de opdrachtenpagina's treedt dit op bij definitieve beÎindiging van het programma.

Het proces "wisselend" moeten wij waarschijnlijk separaat in de KIE aangeven: zodra een kernpagina een nieuwe rol heeft toebedeeld gekregen en deze toekenning impliceert trommel-transporten, dan mag de coordinator niet aan deze kernpagina komen: de coordinator mag aan deze kernpagina pas een andere rol toekennen als het transport voltooid is. (Hetzelfde respect moet de coordinator hebben voor pagina's, die als bufferruimte voor autonome transporten van en naar de communicatie-apparatuur fungeren.)

Wat zich in de KIE van een toegekende kernpagina moet bevinden, is wat beter te overzien.
Ten eerste moet in de KIE onthouden worden het bijbehorende beginadres op de trommel— we hebben immers aangenomen, dat er in de TPV van een aanwezige pagina daarvoor geen ruimte meer zou zijn. Ten tweede moet de KIE een verwijzing naar de TPV bevatten zoals de TPV een verwijzing naar de KIE bevat. (We zijn immers bezig met een soort dubbele boekhouding.)

Als de coordinator een vrije kernpagina zoekt (of moet maken), dan neem ik aan, dat hij het kerngeheugen in zijn totaliteit beschouwt d.w.z. inspectie pleegt in de KIE-tabel (zie ook onder, bij de "look back" informatie). Als de coordinator dan gekozen heeft, welke kernpagina nu van rol zal veranderen, dan moet bij de er aanvankelijk bijbehorende TPV de verwijzing naar deze KIE weggehaald worden. Op grond van de afspraak in de vorige alinea doet de coordinator dit, door aldaar, behalve TPV negatief te maken, ook het trommeladres weer in te vullen. (Dit suggereert, om als KIE-onderdeel, dat in de vorige alinea genoemd is, zonder meer te kiezen: de TPV-waarde bij afwezigheid.)

Het is even de vraag, hoe we deze verwijzing naar TPV denken te doen. Een mogelijkheid is "physisch adres". Dit geeft ons dan wel de plicht om bij stapel-verschuiving de KIE-lijst af te lopen, om te kijken welke adressen daardoor bijgewerkt moeten worden. Een andere mogelijkheid is, om in de KIE de TPV te localiseren ten opzichte van de stapelbodem. Tegen dit laatste lijkt me geen bezwaar. (Wijziging van KIE's komt toch alleen maar voor bij pagina-wisseling.) Wel betekent dit, dat we in de KIE moeten vermelden, bij welk programma de KIE hoort.

(We stappen hier even buiten de gezichtskring van elk individueel programma. Ik neem aan, dat de coordinator alle onder behandeling zijnde programma's kent onder een nummer, dat aan dit programma blijft voorbehouden, totdat het de machine uitgaat. Ik stel tevens dat hij —ook om andere redenen— bij een nummer de stapelbodem zal kunnen vinden.)

Verder zullen we in een KIE, die beantwoordt aan een toegekende kernpagina, moeten noteren, dat deze kernpagina niet tot een stapel behoort. (Stapelpagina's zijn onze vierde groep: ze moeten ook met respect behandeld worden, omdat ze in principe op de kernen blijven staan en slechts met zorg verschoven kunnen worden.)

Verder zullen we in een KIE moeten noteren, of de inhoud van de kernpagina soms identiek is met die van de overeenkomstige trommelpagina. Dit geldt nl. voor alle opdrachten-pagina's; het kan tevens gelden voor getallen-pagina's. (Een betrekkelijk lang constant array hoeft nooit teruggeschreven te worden.) Dit compliceert de assignment aan het element van een groot array. Dat wordt, vrees ik, toch niet zo'n triviale handeling en het zetten van een bit "beschreven" kan er, denk ik, nog wel bij.

Tenslotte is KIE de aangewezen plaats om "look back" informatie in op te slaan, d.w.z. notitie bij te houden van getoonde interesse. Mochten we ooit er toe overgaan een begrip als "starheid" te introduceren dan is ook hiervoor de KIE de aangewezen plaats. Bij gebrek aan beter stel ik me voorlopig maar voor dat we een Naur-achtig interesse-getal in de KIE zullen noteren. (Deze vorm van "look back" volgt de geschiedenis van kernpagina's; zodra een pagina teruggaat naar de trommel verliezen we hem geheel uit het oog. We zouden getempteerd kunnen zijn, om dan in de TPV nog een of ander interesse-getal bij te houden. Experimenten hebben aangetoond —voorzover experimenten dit kunnen aantonen— dat dit niet profijtelijk is: de strategie wordt dan nl. beïnvloed door een gebeuren dat te lang geleden is om nog actueel te zijn.)

transcribed by Sam Samshuijzen
revised Thu, 3 Mar 2005

  EWD 72

Over trommelpaginatransporten.

1. Om het niet te moeilijk te maken beperken we ons voorlopig tot array-pagina's.

1.1. De noodzaak tot transport wordt door het behoeftige programma zelf gedetecteerd en wel in doofheid. Als het nl. niet in doofheid gebeuren zou, zou, na de constatering, dat de pagina er wel is, deze nog onder je vingers weggeratst kunnen worden.

1.2. Als transport noodzakelijk blijkt, dan gaan we naar de coordinator, dwz. het programma komt op de wachtlijst. We keren pas in het programma terug, als de paginatransport voltooid is; we keren dan in doofheid in het programma terug en de aangevraagde arraypagina is geheiligd.

1.2.1. De pagina is geheiligd met de volgende bedoeling: als het transport voltooid is, kan dit programma weer verder; het is niet gezegd, dat het ook onmiddellijk weer verder gaat. In die tussentijd mag de pagina niet verdwijnen!

1.2.2. Het terugkeren in doofheid is niet strikt noodzakelijk, wanneer het programma maar eerst het array-element selecteert en daarna pas de pagina ontheiligt. Keren we terug in doofheid —wat we voor niks krijgen— dan zijn we vrij in de volgorde van elementselectie en ontheiliging. Het programma heeft de plicht de arraypagina te ontheiligen, het element te selecteren (volgorde vrij) en weer horend te worden. Ook dit krijgen we cadeau via de herstellende terugsprong. Een nevenvoordeel is, dat wanneer dit programma verder gaat in nog even doofheid, de ontheiliging gegarandeerd binnen afzienbare tijd na voortzetting plaatsvindt.

1.3. Ik neem aan, dat in geval van noodzakelijk arraypaginatransport de heersende programmapagina ook geheiligd wordt. Dit vergemakkelijkt de terugkeerprocedure aanmerkelijk. Als we dit doen, moet naar ik aanneem ook de programmapagina in doofheid ontheiligd worden (zie 1.1., 1.9.2. e.v.).

1.4. Onbewezen is, dat door de heiligingsprocedure de boel niet kan vast lopen. Dit bewijs kunnen we pas proberen te leveren, als we een volledig overzicht hebben over de aanvraagprocedure bij afwezige (array)pagina.

1.6. Ik beperk me voorlopig tot dat stuk van de coordinator, dat permanent op de kernen aanwezig zal zijn, op een verrekt vaste plaats. De coordinator zal een aantal zg "coordinatorroutines" omvatten; als regel zullen deze met een doofmakende subroutinesprong worden aangeroepen. Het aanroepen van een coordinatorsubroutine op zich zelf betekent niet noodzakelijkerwijze "verlating van het heersende ALGOL-programma". Als regel kan het zo zijn, dat de coordinatorroutine vaststelt, of het heersende programma ongehinderd door kan werken of niet. Zo ja, dan gaat het ALGOL-programma weldra ongehinderd verder — de machine wordt horend bij de herstellende terugsprong uit de coordinatorroutine. De andere mogelijkheid is, dat de coordinatorroutine beslist, dat dit (ALGOL-)programma niet ongehinderd door kan gaan. In dat geval wordt het programma verlaten, dwz. het is niet langer "het heersende programma", het wordt als non-actief op de wachtlijst van de coordinator geplaatst en de coordinator kiest een ander programma en maakt dit heersend.

Ik zoek hier misschien wat spijkers op laag water; wat ik ook probeer is het vinden van een terminologie. In de text van het ALGOL-programma fungeert menig aanroep van een coordinatorroutine als een "mogelijke verlating". Binnenin de coordinatorroutine is de al of niet verlating van het programma een bewuste zaak en kunnen we voor de verlating in doofheid, en na de terugkomst, doelbewuste maatregelen treffen (heiligen en ontheiligen b.v.)

1.7. Coordinatorroutines mogen "over hun break point heen" geen vaste geheugenplaatsen met variabele informatie bezetten: ze kunnen immers parallel geactiveerd worden. Functioneel blijven de betroffen acties dus tot het aanroepende programma behoren. Uit ruimtelijke overwegingen —ook al omdat ze geacht worden zich permanent op de kernen te bevinden— staan ze ook in het geval van multiprogrammering slechts in enkelvoud op de kernen.

1.8. Een gevolg van de graad van bewustheid van een mogelijke onderbreking is de volgende: een gewone interruptie impliceert, dat bij stapelschuiven het B-register aangepast moet worden en dat we heel voorzichtig moeten zijn met absolute verwijzingen naar stapelplaatsen. In een coordinatorroutine kunnen we veel vrijer zijn: na terugkeer onder het break point kunnen we immers testen of de stapel verschoven is en zo ja, wat adressen aanpassen! (dit moet om practische redenen liever niet de spuigaten uitlopen!)

1.9. Voorbeelden van coordinatorroutines zijn de P-operatie, de V-operatie en de indiceeroperaties (schrijvend en lezend). Als het een kleine array blijkt te zijn loopt het helemaal met een sisser af!

1.9.1. Opm. De vorige zin sterkt mij, door de moeilijke scheidbaarheid van "runtime system" en coordinator in de overtuiging, dat we over multiprogrammering in machinecode voorlopig niet hoeven te denken.

1.9.2. In hoeverre de aanroep van een coordinatorroutine in het geval van break point "heiliging" van de aanroepende pagina impliceert zal er van geval to geval van afhangen. Iemand zou kunnen stellen, dat in elk programma de heersende pagina altijd heilig is, maar ik voel daar niet zoveel voor, als het betekent, dat elk programma, ongeacht hoelang het op non-actief staat, altijd minstens 1 pagina blijft bezetten. Je kunt b.v. kijken, of je ermee volstaan kunt heiliging alleen te introduceren in die gevallen, waarvan je er op aan kunt, dat de inhibitie op korte termijn opgeheven zal zijn. Het wordt nogmaals duidelijk, dat we de "deugdelijkheid" van het concept heiligheid pas kunnen bekijken, als een concreet voorstel op tafel ligt. De rol van Advocatus Diaboli lijkt me in dezen uiterst belangrijk! Het zou me niet verbazen, als ons idee over heiligheid in de loop van deze onderzoekingen drastisch zouden veranderen.

1.10. De coordinator-wachtlijst bevat alle programma's in de machine, onderverdeeld naar twee categorieen, de geblokkeerden en de uitvoerbaren.

Geblokkeerde programma's zijn programma's, die niet verder kunnen, doordat ze op een seinpaal staan te wachten, op de voltooiing van een voor hun voortzetting noodzakelijk gebeurtenis.

Uitvoerbare programma's zijn programma's, die wel verder kunnen, ware het niet, dat de X8 maar 1 van hen verder kan helpen. (Ik neem aan, dat het programma, dat door de X8 uitgevoerd wordt, onder de uitvoerbare gerangschikt blijft; de term "wachtlijst" is dan wat merkwaardig, maar laten we daar maar in berusten. Als de besturing echt in de coordinator zit, dan is de term in orde.)

Het effect van de P-operatie kan zijn, dat een programma van uitvoerbaar nu geblokkeerd wordt, het effect van de V-operatie kan zijn, dat een (ander) programma uit de groep der geblokkeerden naar de uitvoerbaren wordt overgeheveld. Een programma, dat in actie door een interruptie onderbroken wordt, blijft gerangschikt onder de uitvoerbare !

We kunnen het ook zo zien: als in een programma een P-operatie geinitieerd wordt, dan was op dat moment het programma in actie, dus uitvoerbaar. Nu zijn er twee gevallen. Of de heersende waarden van de betroffen seinpalen vormen geen beletsel, of zij doen dit wel. In het eerste geval worden zij afgelaagd, de P-operatie is daarmee voltooid en het programma blijft uitvoerbaar. (Of het ook in actie blijft is een heel ander chapiter!) In het tweede geval wordt het programma uit de groep der uitvoerbaren gehaald. De groep der geblokkeerden bevat dus alleen alle programma's, die in een geinitialiseerde, maar niet voltooide P-operatie zijn blijven hangen.

1.11. Ten aanzien van de uitvoerbare programma's kunnen we twee wegen inslaan inzake heiliging. We beschouwen een programma, dat in actie was, door een interruptie is onderbroken en tengevolge daarvan op het uitvoerbare gedeelte van de wachtlijst is gekomen.

1.11.1. In de ene techniek staan we toe, dat de programma-pagina, waarmee we op het moment van interruptie mee bezig waren tijdens het wachten verdwijnt. Dit impliceert: a) dat we in de wachtlijst bij de status quo gegevens het terugkeeradres invariant moeten opbergen. b) dat als de coordinator er toe besluit, dat deze uitvoerbare er nu aan toe is, om voortgezet te worden, er getest moet worden, of de programmapagina, waar we vandaan kwamen en waarheen we weer terugwillen, nog op dezelfde plaats in de kernen zit, maw. de voortzetting moet gespeeld worden als een goto-statement naar een andere, dwz. mogelijk niet aanwezige pagina. c) dat dan in het geval van afwezigheid door de nu aangevraagde trommeltransport het programma weer op de lijst van de geblokkeerde programma's voorkomt.

Als nu na voltooid transport dit programma weer bij de uitvoerbare terecht komt, maar niet direct aan bod komt en dus de pagina voor feitelijk gebruik alweer verdwenen kan zijn, dan is dit niet alleen triest, maar ook gevaarlijk: dit zou nl. betekenen, dat we de mogelijkheid van "effectloze" trommeltransporten geintroduceerd hebben. Zijn we er dan nog zeker van, dat we niet het "Na U" effect geintroduceerd hebben? Dit zou te ondervangen zijn door de kernpagina op het moment van beslissing, dat het transport zal plaatsvinden te heiligen en de ontheiliging pas plaats te laten vinden door de feitelijke voortzetting van dit programma.

1.11.2. In de andere techniek gaan we er van uit, dat het terugkeeradres van een door interruptie onderbroken programma als physisch kernadres opgeborgen wordt, maar dat tijdens uitvoerbaar wachten de pagina in kwestie altijd heilig zal zijn. De andere manier, waarop een programma bij de uitvoerbaren kan komen is via de geblokkeerden. Als blokkade altijd vanuit een coordinatorroutine plaats vindt, dan mogen we ook met een physisch adres volstaan. De coordinatorroutine is immers permanent op de kernen; de coordinatorroutine krijgt dan de plicht om er in geval van gebruikt break point voor te zorgen, dat hij zijn schepen niet achter zich verbrandt. (Door hetzij het terugkeeradres invariant te bergen, dan wel over het break point heen de aanroepende pagina te heiligen.)

Deze techniek kan in eerste instantie op twee wijzen gespeeld worden. We kunnen de heersende pagina altijd heiligen, dit vereist maatregelen bij elke sprong van de ene pagina naar de andere. Een coordinatorroutine heeft dan mogelijk de plicht om bij gebruikt break point —als het te lang kan duren— de heiliging op te heffen en na terugkeer testend terug te springen.

De andere manier is, dat we bij goto statements naar andere pagina's helemaal niets doen, maar in het geval van een interruptie de verlaten pagina heiligen en bij voortzetting ontheiligen. In dit geval moeten we in een coordinatorroutine mogelijk —als de break gegarandeerd kort duurt— deze pagina heiligen voor de duur van de break.

1.11.3. Door de bibliotheek te behandelen zoals Voorhoeve gesuggereerd heeft, kunnen we niet volstaan met in de KIE een heiligbit op te nemen. Immers: vanuit een bibliotheekpagina wordt een coordinatorroutine aangeroepen en de bibliotheekpagina wordt heilig achtergelaten. In de tussentijd komt een ander programma aan bod, dat eveneens deze bibliotheekpagina via een dergelijke coordinatorroutine verlaat. Een van de beide programma's wordt het eerste weer voortgezet: dir programma mag dan de bibliotheekpagina niet ontheiligen! Toen ik dit addertje vanonder het gras had losgewoeld, was ik wel een beetje tevreden met mezelf!

De tweede is duidelijk: de Kie heeft inplaats van een heiligbit een heiligtelling. Telling = 0 betekent profaan, telling positief betekent heilig. Heiligen betekent telling met 1 verhogen, ontheiligen betekent telling met 1 verlagen. Het welbekende "Heilig, heilig, driemaal heilig" begint een bijzonder relief te krijgen.

Opm. Moeten we per programma een "ontheiligingsplicht" bijhouden voor het geval het programma voortijdig beeindigd wordt? Ik denk van wel.

18 December 1963
E. W. Dijkstra

transcribed by Sam Samshuijzen
revised Sun, 13 Feb 2005

EWD74 - 1

Over seinpalen

Wij beschouwen een aantal onderling "zwak gekoppelde", in zichzelf sequentiële processen. Onder de "zwakke koppeling" versta ik, dat ze op bepaalde punten rekening met elkaar kunnen moeten houden. Als bv. een aantal processen af en toe wel eens van een of andere faciliteit gebruik wil maken, die maar een proces tegelijk kan bedienen, dan betekent dit, dat de processen wel eens even op elkaar kunnen moeten wachten. Als het ene proces informatie verwerkt, dat door een ander proces geleverd moet worden, dan is het ook duidelijk, dat het eerste op het laatste kan moeten wachten. M.a.w. de processen moeten ten opzichte van elkaar in zekere mate gesynchroniseerd kunnen worden.

Om de processen in de gelegenheid te stellen onderling informatie uit te wisselen over elkaars staat van vordering, is er een gemeenschappelijk geheugen ingevoerd. De elementen van dit geheugen zijn non-negatieve integers, die we seinpalen noemen.

In de individuele processen zijn de voor de onderlinge synchronisatie belangrijke punten gemarkeerd, doordat daar is aangegeven, dat bij passering van zo'n punt op bepaalde seinpalen een bepaalde operatie moet worden uitgevoerd. De individuele processen hebben hier de keuze uit twee operaties, de zg. V-operatie en de zg. P-operatie, welke wij hieronder zullen beschrijven.

In het volgende nemen wij aan, dat S1, S2, S3 etc. namen zijn van toegankelijke seinpalen (niet alle seinpalen hoeven in elk proces toegankelijk te zijn!); de V- en de P-operatie zullen wij schrijven als procedure statement.

De V-operatie ("verhoog" ).

De V-operatie heeft betrekking op minstens 1 seinpaal, dus bv. "V(S1)" of "V(S1, S2, S3)". Als een van de individuele processen de V-operatie uitvoert, dan is het effect, dat alle er ditmaal bij opgegeven seinpalen in één ondeelbare handeling met 1 worden verhoogd.

Opm. 1 De toevoeging "in één ondeelbare handeling" bedoelt het volgende uit te drukken. Stel, dat de waarde van de seinpaal S1 = 3 is en dat dan bv. twee van de (simultaan werkende!) processen "tegelijkertijd" de operatie V(S1) willen uitvoeren. Tengevolge van de ondeelbaarheid van de handeling mogen we ons dan voorstellen dat deze twee V-operaties op dezelfde seinpaal in een overigens niet ter zake doende volgorde in successie uitgevoerd worden, zodat na afloop S1 = 5 is en niet een van de ophogingen bv. onder tafel is geraakt.

Opm. 2 De V-operatie met meer dan 1 argument is logisch niet noodzakelijk, maar wel elegant. In de statement "V(S1, S2)" wordt een simultane verhoging van beide seinpalen gevraagd; vervangen we dit in een van de individuele processen door "V(S1);V(S2)", dan vragen we heel expliciet om ophoging in een bepaalde volgorde. Het zou wel eens wat minder leuk kunnen zijn om daartoe gedwongen te zijn, als men liever "neutraal" een aantal seinpalen simultaan wil ophogen.

Opm. 3 Als de V-operatie met meer dan 1 argument wel wordt opgenomen, dan zullen wij ons voorlopig beperken tot het geval, dat de erbij opgegeven seinpalen verschillend zijn.

De P-operatie ("Prolaag").

In een individueel proces markeert de P-operatie de tentatieve passering van dit punt. De P-operatie heeft betrekking op 1 of meer seinpalen, dus bv. "P(S1)" of "P(S1, S2, S3)". Als de P-operatie in een van de individuele processen geëntameerd is,

EWD74 - 2

dan is daarmee een operatie begonnen, die slechts beeindigd kan worden op een moment, dat alle erbij opgegeven seinpalen positief zijn. Beëindiging van een P-operatie impliceert, dat alle erbij opgegeven seinpalen met 1 verlaagd worden en ook deze beëindiging geldt als één ondeelbare handeling. Ook voor de P-operatie beperken we ons tot het geval, dat de erbij opgegeven seinpalen onderling verschillend zijn.

Opm. 1 De P-operatie met meer dan 1 argument is logisch wel noodzakelijk.

Opm. 2 Vele seinpalen nemen slechts de waarden 0 en 1 aan. In dat geval fungeert de V-operatie als "baanvak vrijgeven"; de P-operatie, de tentatieve passering, kan slechts voltooid worden, als de betrokken seinpaal (of seinpalen) op veilig staat en passering impliceert dan een op onveilig zetten.

Enige voorbeeldjes voor het gebruik van seinpalen.

Voorbeeld 1.     Als wij een klasje machines (alias processen) Xi hebben (dwz. X0, X1, X2, etc...) en in elk proces komt een kritische sectie voor, kritisch in die zin, dat geen twee kritische secties tegelijkertijd onder behandeling mogen zijn, dan kunnen we dit bereiken met een seinpaal, zeg SX, die in dit simpele geval slechts tweewaardig zal zijn;

SX = 0 zal betekenen: een van de machines Xi is aan zijn kritische sectie bezig
SX = 1 zal betekenen: geen van de machines Xi is aan zijn kritische sectie bezig.

De omschrijving van alle processen is nu gelijkluidend:

"LXi: P(SX); TXi; V(SX); rest proces Xi; goto LXi"

Als we alle processen Xi op hun gelabelde punt (dwz. "aan het begin van de regel") zouden starten met de beginwaarde SX = 2, dan zouden we verwezenlijkt hebben, dat ongeacht de omvang van het klasje processen Xi en nooit meer dan twee simultaan aan hun kritische sectie bezig zouden zijn. Dit is kennelijk een generalisatie van de probleemstelling van wederzijdse uitsluiting. (Het is precies de situatie van bv, n tape decks aan twee kanalen.)

Wij vestigen er de aandacht op, dat de formulering van de individuele processen Xi onafhankelijk is van de omvang van het klasje Xi, iets wat met het ook op de dynamische variatie van deze omvang wel hoogst gewenst is. Ook de maximaal toegestane simultaniteit voor de kritische secties dringt niet tot de formulering van de individuele processen door.

Voorbeeld 2. Nu beschouwen we een groepje machines Xi en een groepje machines Yj, elk met hun kritische sectie TXi resp. TYj. Uitvoering van een critische sectie dient uitvoering van alle andere kritische secties uit te sluiten, maar tevens eisen we, dat de uitvoering van een TX-sectie en een TY-sectie alternerende gebeurtenissen zijn.

We kunnen dit bereiken met twee tweewaardige seinpalen, zeg SX en SY.

SX = 1 betekent, dat nu eerst een TX-sectie aan de beurt is.
SY = 1 betekent, dat nu eerst een TY-sectie aan de beurt is.

De programma's voor de machines luiden:

"LXi: P(SX); TXi; V(SY); proces Xi; goto LXi" en
"LYj: P(SY); TYj; V(SX); proces Yj; goto LYj" .

Als de processen alle "aan het begin van de regel" gestart worden moet SX = 1 en SY = 0 zijn of andersom.

EWD74 - 3

Voorbeeld 3. Tenslotte beschouwen we een klasje machines Xi, die informatie eenheden willen lozen in een cyclische buffer met een capaciteit van N informatie eenheden; voorts een klasje machines Yj, die informatie eenheden uit deze buffer willen verwerken.

Omdat vullen van de buffer administratieve maatregelen met "vulwijzer" impliceert - en voor legen mutatis mutandis hetzelfde geldt - eisen we bovendien, dat vullen slechts door 1 machine Xi tegelijkertijd kan geschieden en evenzo, dat legen slechts door 1 machine Yj tegelijkertijd kan geschieden.

We voeren hiervoor in vier seinpalen:

SX1 = aantal vrije plaatsen in de buffer (aanvankelijk = N)
SX = 0 als een van de machines Xi aan het vullen is, anders = 1
SY1 = aantal gevulde plaatsen in de buffer (aanvankelijk = 0)
SY2 = 0 als een van de machines Yj aan het legen is (anders = 1)

Er zal gelden N - 1 < SX1 + SY1 < N.

De machines zijn nu:

"LXi: P(SX1,SX2); vul volgende plaats van de buffer; V(SY1,SX2);.....; goto LXi"
"LYj: P(SY1,SY2); leeg volgende plaats van de buffer; V(SX1,SY2);.....; goto LYj"

Hardware voorzieningen.

Onze cyclische processen gaan we nu in twee groepen onderverdelen. Die van de ene groep heten " de concrete machines", die van de andere groep heten " de abstracte machines".

De "concrete machines" zijn de transput-apparaten. Dit zijn alle (cyclische) processen, die met een eigen tijdsbewustzijn gedurende een zekere periode autonoom hun werk doen. Onder "autonoom" verstaan wij in dit verband onafhankelijk van de besturing van de centrale computer. Behalve transporten van en naar de buitenwereld (paper tape, printer, ponskaarten etc.) valt hieronder ook transporteren tussen kerngeheugen enerzijds en trommel of magneetband anderzijds. Het zijn die processen, die, mits eenmaal door de X8 in gang gezet, simultaan met de werkende centrale computer plaats vinden.  

De "abstracte machines" zijn de onderling asynchrone programma's. Aangezien de centrale computer de facto steeds maar met 1 programma bezig is, kunnen wij stellen, dat van de abstracte machine er op elk moment hoogstens eentje werkt. (Het is mogelijk, dat geen van deze programma's werkt: de centrale computer "zit dan in de coördinator". De coördinator wordt niet als een van de abstracte machines beschouwd.)

Zolang seinpalen louter door abstracte machines geselecteerd worden, zijn hiervoor geen speciale hardware voorzieningen nodig (behalve doofheid): elke geheugenplaats kan als geprogrammeerde seinpaal fungeren.

Een seinpaal, die louter door de concrete machines geselecteerd wordt (ik laat even in het midden, of die er zullen zijn, het is heel goed denkbaar) is een aangelegenheid, die zich geheel buiten de X8 afspeelt en hoeft ons op het ogenblik dus ook niet te interesseren.

Een seinpaal, die zowel door een concrete als door een abstracte machine geselecteerd moet kunnen worden, vraagt echter onze speciale aandacht. Het is duidelijk dat hiervoor wel speciale hardware voorzieningen en rigoureuze conventies nodig zijn.

In principe is elke "hardware seinpaal" een (per installatie) vaste geheugen-

EWD74 - 4

plaats; door het transput-apparaat kan daar 1 van worden afgetrokken (externe P-operatie) of 1 bij opgeteld worden (externe V-operatie).

Als de centrale computer deze seinpalen moet ophogen of aflagen, dan moet dit gebeuren met behulp van de additieve uitopdracht. In dit geval is nl. interferentie tussen beide additieve operaties (nl. een intern en een externe) niet mogelijk.

Een complicatie is, dat aan elke hardware seinpaal een flip-flip geassocieerd is, die aangeeft of de bijbehorende seinpaal positief is. (Voor de noodzaak van deze flip-flop, zie later)

We kunnen nu twee soorten hardware seinpaal onderscheiden (als regel heeft elk transput apparaat er van beide soorten eentje):

1) Een startopdrachtentelling. In dit geval verricht de centrale computer de V-operatie, en het transputmechanisme verricht de P-operatie. De geassocieerde flip-flop heet in zo'n geval een acflop.

2) Een ingrepentelling. In dit geval verricht de centrale computer de P-operatie en het transput-apparaat de V-operatie. De geassocieerde flip-flop heet in zo'n geval een inflop.

In elke installatie zijn de concrete machines genummerd. Uit het nummer is dan af te leiden welke geheugenplaatsen voor startopdrachten- en ingrepentelling gereserveerd zijn; de bijbehorende Acflop en Inflop zijn onder opgaven van het apparaatnummer bereikbaar.

Wij laten nu zien, hoe de centrale computer bij wijziging van een hardware seinpaal de bijbehorende flip-flop zo nodig kan aanpassen. (Aanpassing van zo'n flip-flop ten gevolge van wijziging door de transput-apparatuur is niet de zorg van de centrale computer, maar van de bouwers.

De V-operatie door de centrale computer.

Zij t de integer, die in het kerngeheugen de seinpaal representeert; de geassocieerde flip-flop noemen we Acflop. Het transput-apparaat zal een volgende startopdracht accepteren, als die er is en het er aan toe is. Het verricht in de voltooiing van de P-operatie op deze seinpaal de handeling, die beschreven kan worden door

"if Acflop then begin t := t - 1; if t < 0 then Acflop := false".

Deze P-operatie, die beschouwd moet worden als onderdeel van het consumeren van de volgende startopdracht, heeft dus als mogelijk gevolg, dat het opnemen van volgende startopdrachten tot nader order niet meer zal plaats vinden; dit nl. als tengevolge van uitputting van de voorraad Acflop op false gezet is.

Additionele spelregels zijn:
a) dat deze handeling vanuit de computer bezien moet worden als ondeelbare handeling - dit schept zijn voordelen - maar dan anderzijds de computer niet over demogelijkheid zal beschikken om deze handeling over een aantal opdrachten te verbieden - en dit schept zijn problemen.
b) dat bij beïnvloeding van t en Acflop door de computer het pertinent verboden is, als hoe kort ook ten onrechte Acflop true zou zijn. Op dat moment zou nl. het transput-apparaat meteen ten onrechte kunnen gaan werken.

Als de centrale computer - ter melding dat de volgende startinformatie is klaar gezet - op deze seinpaal de V-operatie moet uitvoeren, geschiedde dit door het volgende stukje programma:

EWD74 - 5

"t:= t + 1;
 if non Acflop then
    begin if 0 < t
             then Acflop := true end"

De rechtvaardiging van dit stukje programma is als volg. Na de ophoging wordt Acflop getest; als Acflop true was, dan was dus de telling t positief en kan deze door de ophoging alleen maar positiever geworden zijn en eventueel aanpassen van Acflop ligt dus tot nader order op de weg van de transputmachine. Maar als we de Acflop false aantreffen, dan kan de transputmachine de P-operatie niet meer uitvoeren, zodat van die kant t en Acflop ongemoeid gelaten worden en de centrale computer rustig de test kan uitvoeren.

De P-operatie door de centrale computer.

Weer zullen we de seinpaal aanduiden met t; de bijbehorende flip-flop noemen we nu Inflop. Inflop geve aan, of t positief is. De V-operatie, die door de transputmachine uitgevoerd wordt, kan beschreven worden door:

"t := t + 1; if 0 < t then Inflop := true";

van de centrale computer bezien is dit een ondeelbare, niet tegen te houden handeling.

De voltooiing van de P-operatie zal de centrale computer alleen uitvoeren als Inflop true is; bij gratie van doofheid - waarbij de waarde van Inflop geen effect heeft, zie later - kan de computer zich permitteren om Inflop tijdelijk false te zetten.

De voltooiing van de P-operatie door de computer bestaat nu uit het volgende stukje programma:

" t := t - 1;
  Inflop := false;
  if 0 < t then
              Inflop := true"

Essentieel is hierbij aangenomen:
a) dat het geen kwaad kan, als Inflop ten onrechte een tijdje false is
b) dat als transput-machine en computer "tegelijkertijd" proberen om de assignment "Inflop := true" uit te voeren, dat dan na afloop zeker Inflop true zal zijn.

De rechtvaardiging van dit stukje programma is nu als volgt. Elke V-operatie voor de assignment "Inflop := false"  uit bovenstaand programmaatje doet niet te zake, omdat daarna in elk geval Inflop false gezet wordt. Als tijdens de assignment "inflop := false" de telling t positief is, dan zal de computer uiteindelijk de statement "inflop := true" uitvoeren. Door tussengeschoven operaties V kan de telling t alleen maar nog groter worden en dus wordt Inflop correct achter gelaten. Als tijdens de assignment "Inflop := false" de telling t daarentegen non-positief is, moeten we twee gevallen onderscheiden. In het geval, dat de telling t niet door tussengeschoven V-operaties positief wordt, dan zullen zowel de transput-machine als de computer de Inflop verder ongemoeid laten en Inflop blijft dus terecht =false achter. Als door ondergeschoven V-operaties daarentegen de telling positief wordt, dan zal in elk geval door de transput machine op het moment van omslag de assignment "Inflop := true" uitgevoerd worden ( en mogelijk ten overvloede ook nog een keer door de computer, nl. als ten tijde van de test de telling t al positief is ). In dit laatste geval wordt Inflop dus gegarandeerd correct op true achtergelaten.

EWD74 - 6

Opm. De uitleesbaarheid van de Acflops en de tweezijdigheid van de zetbaarheid van de Inflops zijn in de X8 geintroduceerd speciaal om deze programmaatjes mogelijk te maken. Deze hardware is in zekere zin de extra prijs die we betalen moeten voor de ononderdrukbaarheid van de autonome operaties op de seinpalen.

De hardware voor de ingreep.

In het volgende zullen we Inflop true ook door = 1, en false door = 0  representeren.

Zoals gezegd zijn de Inflops genummerd. In een installatie met minder dan 27 Inflops zijn deze gezamenlijk als bits van het zg. (1ste) Inflopwoord uitleesbaar met behulp van een speciale communicatieopdracht. (Komen er meer Inflops, dan wordt een 2de Inflopwoord geintroduceerd. Etc etc. Ik verwacht dat er per Inflopwoord hoogstens 26 bits gebruikt zullen worden en dat het tekenbit van een inflopwoord altijd = 0 is met het oog op normering.)

Opm. Welke positie de verschillende Inflops in het Inflopwoord innemen is mij niet bekend: hier kon nog wel eens een beslissing over genomen moeten worden.

Bij elke Inflop hoort een luisterbit; ook dit is een flip-flop, die door de X8 individueel in beide richtingen zetbaar is. Ook de luisterbits zijn via een (of zo nodig meer) zg. "luisterwoord" uitleesbaar. Een luisterbit neemt in het luisterwoord dezelfde positie in als de overeenkomstige Inflop in het Inflopwoord.

Tenslotte is er een flip-flop, die aangeeft of de X8 "doof" dan wel "horend" is. Een ingreep vindt plaats als
a) het collatieresultaat van Inflopwoord(en) en luisterwoord(en) niet enkel nullen bevat
b) en tevens de machine horend is.

Opm. De doofmakende opdrachten van de X8 werken "instantaan"; het is dus niet mogelijk, dat na de opdracht "maak doof" nog net een interruptie plaats vindt (zoals dit bij de X1 het geval was).

Pro memorie: Dit moet gecontroleerd worden voor de herstellende sprong, die de overgang horend → door kan bewerkstelligen; nagevraagd moet worden of ook de horend makende opdrachten instantaan werken.

De ingreep bestaat daaruit dat:
a) er een speciale subroutinesprong wordt uitgevoerd (met een voor dit doel gereserveerde labda)
b) in de uitvoering van deze subroutinesprong de normale ophoging van de opdrachtteller onderdrukt wordt en de machine onmiddellijk doof gemaakt wordt.

De ingreepsprong verwijst de besturing naar de "ingreeproutine"; deze begint met registerinhouden e.d. te redden om te zorgen dat het nu onderbroken programma later voortgezet kan worden alsof er niets gebeurd is. Vervolgens zal het de Inflops moeten analyseren om te ontdekken welk extern apparaat zo nodig iets te melden had en wat, etc.

De coördinator.

Een belangrijk onderdeel van de coördinator is de ingreeproutine. Ik verwacht dat de ingreeproutine zozeer met de coördinator verweven zal zijn, dat een gescheiden behandeling nauwelijks mogelijk is.

EWD74 - 7

De coördinator wachtlijst bevat alle programma in de machine, onderverdeeld in twee categorieën, de geblokkeerden en de uitvoerbaren.

Geblokkeerde programmaas zijn programmaas die niet verder kunnen, doordat ze op een seinpaal staan te wachten, op de voltooiing van een voor hun voortzetting noodzakelijke gebeurtenis.

Uitvoerbare programmaas zijn programmaas die wel verder kunnen ware het niet dat de X8 maar 1 van hen verder kan helpen. (Ik neem aan dat het programma dat door de X8 uitgevoerd wordt onder de uitvoerbare gerangschikt blijft: de term "wachtlijst" is dan wat merkwaardig, maar laten we er maar in berusten. Als de besturing echt in de coördinator zit, dan is de term in orde.)

Het effect van de P-operatie kan zijn, dat een programma van uitvoerbaar nu geblokkeerd wordt, het effect van een V-operatie kan zijn, dat een (ander) programma uit de groep der geblokkeerde naar de uitvoerbare wordt overgeheveld. Een programma, dat in actie door een interruptie onderbroken wordt, blijft gerangschikt onder de uitvoerbare!

We kunnen het ook zo zien: als in een programma een P-operatie geïnitieerd wordt, dan was op dat moment het programma in actie, dus uitvoerbaar. Nu zijn er twee gevallen. Of de heersende waarden van de betroffen seinpalen vormen geen beletsel, of zij doen dit wel. In het eerste geval worden zij afgelaagd, de P-operatie is daarmee voltooid en het programma blijft uitvoerbaar. (of het ook in actie blijft is een heel ander chapiter!) In het tweede geval wordt het programma uit de groep der uitvoerbaren gehaald. De groep der geblokkeerde bevat dus alleen alle programmaas die in een geïnitieerde maar niet voltooide P-operatie zijn blijven hangen.

De P-operaties van de abstracte machines worden dus beslist niet als een permanent observeren van de betrokken seinpalen gespeeld, in tegendeel: de abstracte machines, die geblokkeerd zijn, sluimeren. Nu de abstracte machines, eenmaal geblokkeerd zijnde, niet meer gevoelig zijn voor het positief zijn van seinpalen, moet de coördinator gevoelig zijn voor het positief worden van seinpalen. Maw, aks 1 of meer seinpalen positief worden, heeft de coördinator de plicht om vast te stellen, of er nu geblokkeerde uit hun blokkade geholpen kunnen worden en zo ja, dan dient de coördinator dit te doen. (Bij de V-operatie met meer dan 1 argument kunnen er dus twee abstracte machines naar de uitvoerbare overgeheveld moeten worden) Hier ligt een vrij stringente plicht voor de coördinator: er moet immers vermeden worden, dat een abstracte machine geblokkeerd is door een geprogrammeerde seinpaal, die inmiddels "onopgemerkt" positief is geworden. De abstracte machine kijkt niet meer, de seinpaal seint niet meer en de boel zit vast!

Het is om bovenstaande redenen, dat wij voor de V-operatie, die tot nog toe als ophoging beschreven is, beslist niet zullen volstaan met een simpele additieve uitopdracht. De geprogrammeerde V-operatie wordt een aanroep van een coördinatorroutine: deze zal de meegegeven seinpalen verhogen en tevens kijken, wat de aan deze verhoging te verbinden consequenties zijn!

Hier zien we inmiddels de verweving van de ingreeproutine en de coördinator. De ingreeproutine sec doet niet veel meer, dan vaststellen op welke (hardware)  seinpaal de V-operatie is uitgevoerd en ook dit zal in de regel tot gevolg hebben, dat een abstracte machine gedeblokkeerd wordt.

De geblokkeerde programmaas bevinden zich in de coördinatorwachtlijst onder opgave van de seinpalen, die bij de voltooiing de P-operatie afgelaagd moeten worden.

EWD74 - 8

Ik stel mij voor, dat de onderverdeling van de wachtlijst geschieden zal niet door verplaatsing maar door kettingrijgen. Ik neem aan dat elke abstracte machine bij creatie een nummer toegekend krijgt - het laagste vrije nummer - en dit nummer gedurende zijn bestaan zal blijven behouden. Ik neem voorts aan, dat onder dit nummer in de wachtlijst direct geselecteerd kan worden.

Ik wilde alle uitvoerbare machines met een ketting aan elkaar rijgen, verder wilde ik bij elke non-positieve seinpaal de beginschakel van een mogelijk niet lege blokkade ketting maken.

Als nu een van de abstracte machines de P-operatie wil uitvoeren, dan worden de meegegeven seinpalen onderzocht. Als een van de seinpalen non-positief bevonden wordt, dan worden de andere seinpalen helemaal niet meer bekeken, want deze abstracte machine wordt meteen aan de blokkadeketting van deze seinpaal gehangen. De opmerking is nl dat voordat deze seinpaal positief is, de P-operatie in elk geval niet voor voltooiing in aanmerking komt.

Als nu een V-operatie op een seinpaal wordt uitgevoerd, dan kan de coördinator nu op vrij snelle wijze de mogelijke consequenties hiervan nagaan. Was de blokkade ketting leeg, dan stond er niets op deze V-operatie te wachten en geen van de geblokkeerde machines komt dus voor deblokkade in aanmerking. Als de blokkadeketting van deze seinpaal niet leeg is, dan onderzoekt men een abstracte machine in de ketting: als de overige seinpalen geen beletsel vormen, dan kan een P-operatie voltooid worden en gaat deze abstracte machine over naar de uitvoerbare. Als een andere seinpaal wel een beletsel vormt, dan gaat de abstracte machine over naar de blokkade ketting van die laatste seinpaal. Repetatur, totdat of de seinpaal weer nul is (succesvolle deblokkade) of de ketting leeg is (of beide). Het is vanzelfsprekend dat door het dusdanig afwerken van de V-operatie het uitgesloten is dat een positieve seinpaal met non-lege blokkadeketting zou overblijven.

Salvo errore et omissione zou de coördinator naar aanleiding van een V-operatie dankzij deze kettingen nu vrij snel moeten kunnen vaststellen of hieraan verdere consequenties verbonden zijn en zo ja, welke.

In dit schema passen de luisterbits voortreffelijk: men maakt de luisterbit van een hardware seinpaal = 1 als zijn blokkadeketting gevuld is, anders = 0. Immers: als de blokkadeketting leeg is, dan staat er in eerste instantie niets op deze seinpaal te wachten. Wat zullen we dan een ingreep introduceren, als deze seinpaal positief wordt? Zo komen de luisterbits naar voren als middel om onnodige ingrepen te onderdrukken. Of dit veel zoden aan de dijk zet, valt nog ernstig te bezien, het zou best eens zo kunnen zijn, dat er haast altijd op een ingreep gewacht wordt.

Transcription by Patrick Tingen.

Last revised on 6 November, 2019

EWD75

Over standaardroutines.

Voor een machine met een trommel is het, naar men zich hopenliji denken kan, een belangrijk criterium, waarnaar men standaardroutines kan onderverdelen, of zij permanent op een vaste plaats in de kernen aanwezig geacht kunnen worden of niet.

Onder de permanent aanwezigen vallen in elk geval de zg. coordinatorroutines, zoals de aanroepen van de P- en V-operaties. In de ALGOL-machine zullen ook de systeemroutines hierbij horen, in het bijzonder die stukken programma, diete maken hebben met de aan- of afwezigheid van informatie in de kernen. (Je kunt uit de aard der zaak informatie "facultatief" op de kernen hebben: als het programma, dat deze aanwezigheid onderzoekt, ook zelf afwezig kan zijn, dan krijg je kennelijk rare dingen.) Het is duidelijk, dat wij de totale omvang van deze routines vanwege hun permanente aanwezigheid scherp in het oog moeten houden.

Het ALGOL-systeem zal de beschikking krijgen over een uitbreidbare bibliotheek, nl. van standaardprocedures; ik neem aan, dat deze bibliotheek zich permanent op de trommel zal bevinden. Bij de incorporering en de interne formulering treedt direct een moeilijkheid op.

Men kan de bibliotheek op de trommel beschouwen als "moedercopie" en bij vertaling van een bibliotheek gebruikend ALGOL-programma de gebruikte bibliotheekprocedures in het objectprogramma opnemen. Deze opname wordt geen blindelingse copiering; nomenclatuur (identificatie van geheugenbezettingen, andere bibliotheekprocedures) moet dan vertaald worden. De copie bevat immers ook de informatie hoe hij -en andere bibliotheekprogramma's- in het ALGOL-programma zijn ingepast. Op deze wijze is de bibliotheek louter een vertalerkwestie, waar het run time system nauwelijks iets mee te maken heeft: in het objectprogramma hoeft niet meer te zien te zijn, dat sommige procedures niet expliciet gedeclareerd zijn geweest.

Dit is evenwel niet de weg, die wij in wilden slaan. Ten eerste waren we- terecht of niet- een beetje bang voor de complicatie van de vertaler; ten tweede betekent dit, dat als twee ALGOL-programma's dezelfde standaardprocedure gebruiken, dat deze procedure dan inmiddels drie maal in het geheugen staat en mogelijk tweemaal op de kernen. En de vraag is, waarom zouden we dat doen?

We mikken dus nu op een oplossing, die de bibliotheekroutines gebruikt zoals ze op de trommel staan. Wat we winnen is een simplificate van de vertaler en de winst, dat we zuiniger met het geheugen omspringen. Mogelijk winnen we ook, dat de tekst van de bibliotheekprocedures, die nu immers niet meer door de vertaler vermalen worden, met wat grotere vrijheden opgesteld kan worden.

De prijs, die we betalen, is vooralsnog onbekend. Ik zie op het ogenblik twee betalingen.

Doordat verschillende programma's dezelfde kernpagina nu parallel kunnen willen gebruiken, wordt het concept van een "heilige kernpagina" gecompliceerder. We kunnen niet meer met een enkel bit volstaan, maar hebben een teller nodig, die bij heiliging met 1 verhoogd moet worden en bij profanatie met 1 verlaagd moet worden. Alleen als de teller = 0 is, is de pagina vogelvrij.

De tweede prijs is een kerngeheugenbezetting door een "bibliotheeksinhoudsopgave", die bijhoudt, waar de bibliotheekpagina's zich bevinden. De lengte van deze tabel is evenredig met de omvang van de bibliotheek, of de bibliotheek nu gebruikt wordt of niet. Dit is strict genomen natuurlijk tegen de regels, maar omdat deze tabel waarschijnlijk maar 1 woord zal beslaan per trommelpagina van waarscijnlijk 512 woorden, dabhten we, dat we ons dit konden permitteren. ALGOL-programma's identificeren bibliotheekprocedures -en bibliotheekprocedures identificeren zichzelf en zichzelf en elkaar-invariant in termen van deze tabel.

Als dit normale procedures zijn, dan krijgen ze bij activering hun geheugenruimte toegewezen in de stapel van het activerende programma. Dit is mogelijk en geeft geen aanleiding tot extra complicaties, bij gratie van het feit, dat de activiteit van een dergelijke bibliotheekprocedure synchroon verloopt met het aanroepende programma. Van de aanroep van een bibliotheekprocedure hoeft, voorzover ik zie, de coordinator geen bijzondere notitie te nemen.

Het bovenstaande is slechts ter inleiding, ter verhoging van de contrastwerking met wat volgt. Wij zullen nl. de individuele ALGOL-programma's ook de beschikking moeten kunnen geven over geprogrammeerde standaardhandelingen, die asynchroon met het ALGOL-programma moeten kunnen werken. Ik voorzie nu, dat het een drommels verschil zal maken, of een dergelijk asynchroon proces willekeurig veelvoudig parallel geactiveerd moet kunnen worden of niet. Als wij ons ervan konden overtuigen, dat dit niet het geval zal zijn, dan zou ik van ernstige zorgen bevrij zijn.

Straks zal ik, ter illustratie, als intellectuele exercitie en mogelijk voor later gebruik een voorbeeld proberen uit te werken, dat niet parallel geactiveerd hoeft te worden. Eerst wil ik proberen aan te duiden, waar ik de moeilijkheden verwacht, als aan deze voorwaarde niet voldaan is.

Als wij even aannemen, dat elk werkend ALGOL-programma het samenspel impliceert tussen dit programma en een aan dit ALGOL-programma toegevoegd simultaan werkend proces, een soort prive-secretaresse, dan betekent de introductie van een ALGOL-programma de creatie van twee abstracte machines, te weten het ALGOL-programma en de prive-secretaresse. Ik laat nu even in het midden of de programmatekst van de prive-secretaresses in veelvoud of in enkelvoud aanwezig zal zijn. In het ene geval moet ik een multipliceringsmechanisme maken, in het andere geval een extra activeringsmechanisme. Wat mij zorgen baart is, dat er tussen ALGOL-programma en prive-secretaresse informatieverkeer zal moeten plaatsvinden, dat er seinpalen zullen moeten zijn, die voor beiden toegankelijk zullen moeten zijn. De introductie van een ALGOL-programma betekent dan ook niet "alleen maar" de creatie van twee nieuwe abstracte machines, het betekent de creatie van twee op bijzondere wijze op elkaar afgestemde abstracte machines. Ik kan bijvoorbeeld niet overzien, of we ons zullen kunnen permitteren, om deze seinpalen gedurendehun leven op vaste geheugenplaatsen onder te brengen. Zo nee, dan bekruipt mij plotseling de angst, dat "verschuiven" van die informatie een hel wordt, omdat meer dan 1 abstracte machine daar weet van moet hebben. Kortom, "wat en waar" is de common ground waar de twee elkaar kunnen ontmoeten?

Opm. Voor de bibliotheekpracedures hebben we de "common ground" geschapen door de tijdens run time permanent aanwezige "bibliotheekinhoudsopgave"; tijdens vertalen komt een soort complement van deze tabel ter sprake, nl. als "prevulling van de naamlijst": aan de standaardnamen zijn daar dan verwijzingen toegevoegd naar de bibliotheekinhoudsopgave. Wijziging van de bibliotheek impliceert in het algemeen een herindeling van het totale bibliotheekgeheugen en is geen triviale opgave. Wij zijn er essentieel van uitgegaan, dat hergroepering van de bibliotheek zal gebeuren tijdens executie, of tussen vertaald zijn en uitvoering, van een of meer ALGOL-programma's. Ziehier een nieuw voordeel van load and go!

Deze zorgen zijn allemaal aanmerkelijk minder, wanneer we een asynchrone "manus voor allen" slechts in enkelvoud willen kunnen bespelen. Stel, dat een ALGOL-programma mogelijkerwijze, maar niet noodzakelijkerwijze, deze manus wil kunnen gebruiken. (Ik ga straks een en ander illustreren aan de printer; een programma mag printen, maar hoeft dat natuurlijk niet!). Van deze manus maak je dan, eens en vooral, een stamgast van je hotel voor abstracte machines. Als hij klein is, zet je hem op vaste plaatsen op de kernen, anders laat je hem als ieder ander programma via de paginaadministratie meedraaien. In elk geval kan je je veroorloven om hem permanent een klein beetje levend geheugen permanent ter beschikking te stellen voor het informatieverkeer.

(De opmerking is, dat als geen van de lopende ALGOL-programma's van de printer gebruik wil maken, er dus waarschijnlijk niet zoveel te doen is en dat je je deze kleine vaste bezetting dus wel kunt permitteren. En er hoeft er maar eentje te willen printen en je hebt het er al uit.) Op dit moment is er een ondubbelzinnige, invariante terminologie, waarin de onderscheiden ALGOL-programma's de manus kunnen toespreken.

Omdat het woord "pagina" al gebruikt is voor de onderverdeling van kern - en trommelgeheugen, noem ik een pagina, zoals die door de printer bedrukt kan worden, een formulier, dwz. het stuk van perforatie tot perforatie.

Ik beschouw een de printer als een snel uitvoerorgaan, zo snel, dat
a) ALGOL-programma's hun resultaten zo ongeveer synchroon met de productie op papier kunnen krijgen, en sterker
b) de printer zelfs meer dan 1 programma bedienen kan.

Het idee is, om de printer steeds formuliersgewijze aan een bepaald programma te gunnen. Dit impliceert, dat bovenaan elk formulier ongevraagd geprint wordt een identificatie van het producerende programma, een volgnummer en verder wat nodig geacht wordt, datum etc.. De "expeditie" moet nu de formulieren maar afscheuren en sorteren.

Dit impliceert, dat een ALGOL-programma pas de printer maag aanvragen, wanneer het de gegevens voor een volledig formulier klaar heeft, Immers: zou een ALGOL-programma de eerste helft van een formulier kunnen bedrukken, voordat de resultaten voor de tweede helft geproduceerd zijn, dan zou dit programma de printer heel lang kunnen blokkeren, omdat de productie van de volgende resultaten wel eens heel lang op zich zou kunnen laten wachten. Elk ALGOL-programma, dat van de printer gebruik maakt, heeft dus een prive-buffer met de capaciteit van een formulier. Ald we aannemen, dat op een formulier 64 regels geprint worden, dan komen we met 32 woorden per regel op een buffer van 2048 woorden, dwz. met een paginagrootte van 512 woorden dus 4 pagina's.

Naast de privebuffer heeft elk ALGOL-programma als globale grootheden de administratieve gegevens over de staat van vulling van de buffer, formuliernummer, etc. Elk ALGOL-programma begint met deze gegevens passend te initialiseren als standaard onderdeel van START.

Een ALGOL-programma, dat wil printen bouwt nu, helemaal locaal, een volledig formulierbeeld op. Hierbij maakt het, neem ik aan, gebruik van in enkelvoud aanwezige, conversie en opmaakroutines. Het is hier onbelangrijk of deze permanent op de kernen staan, dan wel als bibliotheekprocedures van de trommel gehaald kunnen moeten worden. Belangrijk is, dat deze operaties synchroon met het werkende programma plaatsvinden. Ik neem aan, dat deze "conversie en opmaakroutine" detecteert, wanneer aan een nieuw formulier begonnen wordt en op grond daarvan de formulierkop invult en tevens detecteert, wanneer een formulier vol is.

Zodra een formulier vol is, moet het programma met de buitenwereld gaan communiceren, dwz. met de formulierprinter. Deze formulierprinter is de bovengenoemde, geprogrammeerde "manus voor allen".

De synchronisatie met de formulierprinter loopt over twee seinpalen; dit zijn twee vaste geheugenplaatsen, waarvan ALGOL-programma en formulierprinter beide kennis moeten dragen. Verder is er de "toonbank", waarover het formulierbeeld wordt aangeboden. Als we de informatie lijfelijk zouden transporteren, zou dit een stuk van 2048 plaatsen zijn.

Als we een formulierbuffer beschouwen als een groot array van vier pagina's, dan hoeft aanbod helemaal niet het lijfelijke transport van 2048 woorden te impliceren. Immers: die vier pagina's zijn bereikbaar via vier descriptoren, de zg. TPV's (Trommel Pagina Variabelen). Als we deze vier TPV's transporteren, bereiken we daarmee, dat de vier gevulde pagina's, die eerst tot het producerende ALGOL-programma behoorden, nu zijn overgeheveld naar de formulierprinter.

De organisatie van de grote arrays zal de feitelijke reservering van Pagina's niet doen bij de declaratie van het array -dan worden alleen de TPV's geintroduceerd en geinitialiseerd- maar pas bij werkelijk gebruik van het eerste element van de pagina. Na beeindiging van interesse -zoals bij blokverlating- worden detrommel-pagina's weer aan de vrije hoop toegevoegd.

Een en ander heeft tot gevolg, dat wij zonder absurde onkosten de individuele ALGOL-programma's en de formulierprinter grotere buffers zouden kunnen geven; als wij dat niet doen, zullen wij dus iets van een motivering meeten geven.

Een reden om de individuele programme's buffers van meer dan 1 forniulier te geven zou de wens kunnen zijn om een programma in staat te stellen de printer voor meer dan 1 formulier aan zich te binden; wie vier formulieren achter elkaar, dwz. ongestoord door overige programma's geprint wil hebben, mag de printer pas aan zich binden, als die vier formulierbeelden geheel geprepareerd zijn. Hiermee maakt men kunstmatig, dat de aanbiedende programma's in 'bursts' van meer formulieren aanbieden en het ligt dan ook voor de hand dat de buffer van de formulierprinter groter gekozen wordt, viz. groot genoeg om in enen op te kunnen vangen, wat een programma in enen aan zou willen bieden. We zijn echter niet van plan om een programma meer dan 1 formulier tegelijkertijd aan te laten bieden, en dus krijgen de individuele programma's een prive-buffer van 1 formulier.

Aldus besloten rijst de vraag, hoe groot we de buffer van de formulierprinter zullen kiezen. Minstens 1 formulier, nl. het formulier, dat gedrukt wordt. Naar 1 formulier is een bertje weinig: dit betekent immers, dat na voltooiing van dit formulier de buffer gegarandeerd leeg is en dat voor de coordinator een morele haast-situatie zou ontstaan als je de printer tussen de formulieren niet wilt laten stokken. Die morele haastsituatie kan aanmerkelijk verlicht worden door de formu1ierprinter met een toonbank van twee formulieren te laten werken: die worden dan wiggel-waggel bedreven.

Met de beslissing, dat de formulierprinter over meer dan een 1-formuliersbuffer zal beschikken, is een wezenlijke uitbreiding gedaan: dit betekent, dat aanbod oo de toonbank onder controle van een vulwijzer zal moeten geschieden (waar we anders niet over hoefden te praten) en dat meer dan 1 programma tegelijkertijd een formulier zou kunnen willen aanbieden en dat we zorgen moeten dat er dan geen ongewenste interferentie op treedt. Breiden we nu de omvang van de formulierprinterbuffer non uit, dan verandert er aan de structuur van de programma's niets meer, alleen geheugenindeling en de waarde van een naar constantes. De vraag is, of we de formulierprinter een grotere buffer willen geven, Ik geloof van niet.

De overweging is de volgende: als de formulierprinter een grote eigen buffer heeft, die ongeveer leeg is en als nu alle programma's ongeveer tegelijkertijd een formulier aanbieden, dan wordt deze buffer grotendeels gevuld en ligt daarmee voor lang vast, welke programma's door de printer in successie geholpen zullen worden. Dit volgens de regel "wie lang geleden het eerste kwam, zal later het eerste malen". Heeft de formulierprinter maar een kleine buffer, dan is deze ongeveer onmiddellijk vol en de overige programma's staan op een seinpaal te wachten. Zodra er dan weer ruimte in de buffer van de formulierprinter komt, dan mag de coordinator beslissen wie een pagina mag aanbieden. Door deze grotere vrijheid van de coordinator zal het bij kleinere buffer makkelijker zijn om prioriteit te geven aan bepaalde programma's.

We hebben nog een ander ding overwogen, maar we menen tot de conclusie gekomen te zijn, dat je dat beslist niet doen moet; de coordinator heeft dan namelijk nog minder te vertellen. Je kunt als volgt redeneren: ieder programma heeft zelf (van de programmeur) enig idee van de omvang van zijn informatieexplosies, die naar de printer moeten. Laat het daarom een locale buffer introduceren ter grote van een dergelijke "burst" -afgerond op hele formulieren uit de aard der zaak. Nu kan je het aanbieden van een pagina ook anders spelen: inplaats van transport van de informatie -of van een descriptor, wat in dit verband op hetzelfde neer komt- kan je ook de in een ALGOL programma gevormde formulierinhoud via een kettingrijgerij aanhaken aan de ketting van hef "nog te printen spul". Dit heeft de organisatorische complicatie, dat na voltooiing van deze printhandeling dit heugelijk feit niet neutraal betekent "de printer is weer vrij", maar dat dit doorgemeld moet worden naar het programma, in welks locale buffer hierdoor weer een formulierplaats vrijgekomen is. Veel erger is echter, dat wanneer een aantal programma's samen in de machine zit, die met zijn allen outputbound zijn door de printer, zij geholpen worden naar evenredigheid van hun eigen bufferomvang: het aanvragen van een grote locale buffer is dan een manier om je latere mogelijke compagnons in de machine een hak te zetten. Met deze conclusie zijn we erg blij, want om organisatorische rederen hadden we er nl. al niet zo'n zin in.

Het volgende, dat besloten moet worden is in welke vorm de printer tussen de formulieren achtergelaten wordt. De X8 heeft geen mogelijkheid om te testen, wanneer de perforatie voorbijkomt. Ik neem aan, dat tussen formulieren de printer achter gelaten wordt met het papier in de positie gereed voor de bedrukking van de eerste regel. De formulierprinter mag van deze toestand uitgaan maar moet na gebruik van de printer dus ook zorgvuldig deze toestand achterlaten! En dit geldt nu niet alleen van de formulierprinter, maar het geldt voor elk programma, dat "tussendoor" van de snelle regeldrukker gebruik wil maken.

Op dezelfde manier moeten we beslissen wat we zullen doen met de IFT (+ Inflop) en AFT (+ Acflop) van de printer. Wij hebben ons hierbij door de controlemogelijkheid laten leiden. (Terwijl ik dit verslag tik, merk ik, dat we ook anders te werk hadden kunnen gaan; ik beschrijf nu eerst, wat we gedaan hebben). We zijn er van uitgegaan, dat de formulierprinter gebruik zou maken van de terugmeldingen, die met het ophogen van IFT gemeld worden; we hebben gesteld, dat het printen van een formulier, voor zover het de formulierprinter aangaat, beschouwd moet worden als een onscheidbaar geheel, dat in zijn geheel fout of in zijn geheel goed gaat. Mogelijke reactie op een fout moet dus kunnen zijn; het hele formulier opnieuw proberen te printen. Verder hebben we aangenomen, dat er tussen opeenvolgende formulieren geen vorm van "overlap" zou zijn: de formulierprinter begint pas aan de regels van het volgende formulier, als het vorige formulier geheel geprint en gecontroleerd is. Dit impliceert dus, dat tussen de formulieren het startmagazijn van de snelle regeldrukker even helemaal leeg is.

Op grond hiervan hebben we gesteld, dat de nuchtere toestand van de regeldrukker zijn zou AFT = IFT = 0; AFT is duidelijk, er hangen geen startopdrachten meer; het idee van IFT = 0 kan uitgelegd worden als "er is niets meer te melden".

Nadat dit besloten is, moet worden afgesproken, in wat voor staat de formulierprinter de bijbehorende geheugenplaatsen, leegwijzer en startmagazijn zal aantreffen. Het leek ons verstandig om daaromtrent geen enkele veronderstelling te maken. Dit betekent, dat bij de aanvang van een formulier de formulierprinter begint met een leegwijzer in te vullen (op iets, wat er waarschijnlijk nog staat van het vorige formulier, maar dat doet er niet toe). We nemen zelfs aan, dat de gegevens in het startmagazijn er niet meer zullen staan, hoewel die, zie onder, bedoeld zijn om tijdens het formulierprinten niet te veranderen.

Tenslotte moeten we beslissen, waar het regelbeeld zal staan, dat door de regeldrukker geprint zal worden. Dit kost ons 32 woorden per regel en we moeten totaal 4 regels kunnen opbergen. We hebben besloten hier 128 woorden vast voor te reserveren en dus op het allerlaatst de informatie wel lijfelijk te transporteren. De overwegingen, die hier toe geleid hebben, waren de volgende. Als een pagina met regels nog op de kernen staat, staat hij "ergens", dwz. op een vrij willekeurige kernpagina; als de pagina met regels inmiddels op de trommel gedumpt is en we hem voor gaats halen met het standaard mechanisme -en dat willen we natuurlijk- dan komt hij ergens. Maar informatie, die door de printer asynchroon uit het geheugen geslurpt wordt, moet staan op een uiters heilige plaats. Zouden wij de pagina, zoals hij in het kerngeheugen staat of komt, heiligen, dan zou dat impliceren, dat we eventueel midden in het kerngeheugen voor vrij lange tijd een geheiligde pagina zouden hebben. De beperkingen, die daaruit voortvloeien, trokken ons niet aan. Vondaar deze beslissing.

Nu geven we de voorlopige versie van de programma's; zij zijn geschreven met inbegrip van de controle, de detectie, als het goed is gegaan. Het leek ons nu wat vroeg om te gaan uitmelken, wat we moeten doen, als deze controle ALARM geeft.

Relevant grootheden zijn:

integer FPN; | aantal formulieren in FP-buffer (Formulierprinter buffer); dit is een constante, waarschijnlijk dus gelijk 2
integer FPLW, | FPVW; dit zijn leegwijzer, resp. vulwijzer van de FP-buffer deze moeten door het tandenpoetsen aan elkaar gelijk gemaakt worden (door het tandenpoetsen van de formulierprinter); zij worden modulo FPN in het bedrijf opgehoogd.

Om der wille van de beschrijving voer ik in een nieuw type array, een zg TPV array elementen waarvan fungeren als identifier van een array van 512 integers; ik zal deze elementen met dubbele indicering aanduiden.

Globaal voor formulierprinter en elk ALGOL programma hebben we de toonbank, alias de formulierprinterbuffer
TPV array FPB[0:4*FPN-1]; deze factor 4 komt omdat we per formulier vier pagina's nodig hebben. Een ALGOL-programma bouwt zijn formulier op in het locaal formulier
TPV array LF[0:3];

Voor de reductie modulo iets gebruiken we de integer procedure REM.

Synchronisatie tussen een ALGOL-programma en de formulierprinter wordt gespeeld via twee globale seinpalen:
integer FPL,FPV; deze betekenen het aantal lege, resp. volle formulieren in FPB. Aanvankelijk (dwz, bij tandenpoetsen van de formulierprinter wordt FPL:= FPN; FPV:= 0 uitgevoerd).

Aanbod van een formulier aan de formulierprinter geschiedt door het volgende stukje programma (hier hebben we nog een willekeurige locale integer, zeg i nodig):

begin X8 doof; P(FPL);
      for i:= 0,1,2,3 do
         begin FPB[4*FPVW + i]:= LF[i];
               LF[i]:= maagdelijk
         end;
      FPVW:= REM(FPVW + 1, FPN);
      V(FPV); X8 horend
end

Commentaar: de X8 wordt hier doof gemaakt om te zorgen dat dit aanbod onder controle van een unieke vulwijzer plaats vindt; noninterferentie van de ophoging van FPVW is hiermee ook verzekerd. Dit had "zuiniger" onder controle van een speciale uitslutingsseinpaal gekund, zuiniger in de zin, dat we dan minder tijdsrestricties opleggen. Dit accevietje duurt echter gegarabdeerd zo kort, dat even doof minder werk is. Het feit, dat ook de P- en V-operatie in diifheid uitgevierd worden, is logisch niet essentieel.

Met "maagdelijk" is bedoeld de constante waarde van een TPV, waarvoor nog geen pagina gereserveerd is. In dit geval wordt het dus een TPV, waarvoor geen pagina meer gereserveerd is.

De formulierprinter als hieronder geprogrammeerd neemt van de printer alleen maar aan, dat IFT en AFT beide = 0 zijn. Het startmagazijn en de leegwijzer van de printer moeten dus passend geprepareerd worden. Ik gebruik hier de integer procedure address ter beschrijving van "het adres van".

Naast de genoemde globule grootheden heeft de formulierprinter toegang tot de integer "leegwijzer", de grootheid, onder controle waarvan de printer asynchroon de startopdracht aanhaald. Verder is er een globale seinpaal "PV", te weten printer vrij; deze seinpaal stelt ons in staat desgewenst de printer tussendoor ook even op een andere manier te gebruiken.

De tekst van de formulierprinter wordt ongeveer als volgt:

formulierprinter:
begin integer leegwijzer  i, j, vulwijzer;
   integer array startmagazijn [0:7], regelmagazijn [0:127];
   P(FPV, PV);
   leegwijzer:= address(startmagazijn[7]);
   for i:= 0,1,2,3 do startmagazijn[2*i]:= address(regelmagazijn[32*1]) cons;
   i:= vulwijzer:= 0;
nieuwe regel:
   if 3 < i then begin P(IFT printer);
   if startmagazijn[2*vulwijzer + 1] ≠ correct then goto ALARM end;
   if i < 63  then
   begin  for j:= 0 step 1 until 31 do
      regelmagazijn[32* vulwijzer + j]:=
         FPN[4*FPLW + entier((i+0.5V)/16)][32*REM(i,16) + j];
      V(AFT printer) ;
      vulwijzer:= REM(vulwijzer + 1, 4)
   end;
   if i < 68 then goto nieuwe regel;
   for i:= 0,1,2,3 do vrijgave pagina(FPB[4*FPLW + i]);
   FPLW:= REM(FPLW + 1, FPN);
   V(FPL, PV);  goto formulierprinter
end

Opm. het begint met initialiseringen, als het startmagazijn en het regelmagazijn vast gekozen worden, dan zijn dit altijd dezelfde constanten, die her in evuld moeten worden. Er is geen bezwaar tegen, dat dit van formulier tot formulier zou weizigen. De test "3 < i" is om de eerste vier keer de controls te onderdrukken, de test "i < 63" om alleen maar feitelijk aan te bieden, als er nog iets aan te bieden valt. De procedure "vrijgave pagina" krijgt een tpv als argument mee; het resultaat is dat de trommelpagina, die via deze TPV toegankelijk was, nu definitief van de voorraad vrijen wordt toegevoegd. Zou je zoiets als dit vereeten, dat zou de trommel dichtgroeien met oude paginabeelden.

De conventie dat de formulierprinter de printer met IFT = 0 aantreft. wat we in verband met de controle gedaan hebben. lijkt me bij nader inzien questieus. Nu dwing je min of meer elk ander gebruik nodeloos in dit keurslijf. Beter lijkt het me om als neutrale toestand AFT = 0 en IFT = 4 (de omvang van het startmagazijn) te kiezen; dit is niet in tegenspraak, dat de formulierprinter pas na volledige controle overgaat op het volgende formulier. De formulierprinter kan aan het einde, na de controle 4 maal V(IFT printer) doen! Wel ongebruikelijk, maar moeten we er niet aaan wennen?

transcribed by Carl Ludwigson
revised Tue, 2 Oct 2007

  EWD 77

Het controlerende communicatieapparaat

Het volgende is een studie over het bespelen van een controlerend communicatieapparaat dat bediend wordt via een beperkt startmagazijn. Ala dit startmagazijn bv. 4 startopdrachten kan bevatten, dan hebben X8 en communicatieapparaat toegang tot
"array startopdracht,slotwoord [0:3]"; in de praktijk zullen deze twee array's in het geheugen dooreen gevlochten staan, maar dat doet nu niet ter zake.

Het autonoom transport leest de startopdracht en vult het slotwoord ; omdat het lezen-gehoorzamen- van de startopdracht als primair ervaren wordt, noemen wij de wijzer, onder controle waarvan dit gebeurt, de "integer leegwijzer".

Twee seinpalen, AFT en IFT regelen de synchronisatie: AFT is het aantal startopdrachten in voorraad, IFT het aantal "terugmeldingen", waarvan de X8 nog geen nota genomen heeft.

In dit geval kan de handeling van het autonoom transport in eerste aanleg beschreven worden door zoiets als:

"L: P(AFT);
    leegwijzer:= REM(leegwijzer +1,4);
    gehoorzaam(startopdracht[leegwijzer]);
    meld terug in (slotwoord[leegwijzer]);
    V(IFT);
    goto L"

Met "zoiets als" wordt bedoeld

a)  
dat het hier irrelevant is, of leegwijzer voor of na gebruik wordt opgehoogd; in deze beschrijving hebben we "voor" gekozen.

b)
- dat hier over de non-OK-toestand nog niet gesproken is; we beperken ons voorlopig tot het geval, dat het allemaal goed is gegaan.

In het volgende wil ik de consequenties nagaan van het feit, dat, voorzover de X8 betreft, de "V(IFT)" een dubbele betekenis kan hebben. Dit immers meldt een gebeuren, dat in twee richtingen betekenis heeft. Enerzijds is het gericht op het verleden, en wordt hier dus gemeld, hoe iets dat vroeger gestart is, is afgelopen, anderzijds heeft het betekenis gericht op de toekomst, omdat er nu, desgewenst, weer plaats in het startmagazijn vrijkomt. Tengevolge hiervan kan het zijn, dat er nu twee processen voortgang kunnen vinden, nl. het proces, voor welks voortzetting de voltooiing der autonome handeling essentieel is en het proces, dat graag van het apparaat gebruik zou willen maken.

We voeren hiertoe een derde, geprogrammeerde seinpaal in nl. SRT = startruimtetelling. SRT geeft aan het aantal startopdrachten, waarvoor in het startmagazijn ruimte is.

Het startmagazijn wordt nu bespeeld door twee onderling asynchrone processen, viz. Starter en Controleur. De zojuist ingevoerde seinpaal dient voor de onderlinge synchronisatie van deze twee ; deze twee processen hebben, zoals wij straks zullen zien, nog wel meer verknopingen.

De Controleur raadpleegt het slotwoord onder controle van een "integer controlewijzer" in ruwste vorm:

"Controleur: P(IFT);
   controlewijzer:= REM(controlewijzer + 1,4):
   if slotwoord[controlewijzer] ≠ correct then actie fout else actie goed;
   V(SRT); goto Controleur"

Over "actie goed" en "actie fout" straks meer.

De Starter neemt met het startmagazijn contact op onder controle van een vulwijzer, altijd via de sequens:

".....; P(SRT);
         vulwijzer:= REM (vulwijzer + 1,4);
         startopdracht[vulwijzer]:= volgende startopdracht;
         V(AFT); ....."

Ook over "volgende startopdracht" straks meer ; deze moet er nl. zijn.

De geprogrammeerde seinpaal SRT is ingevoerd om controle op de voltooide operatie en aanbieden van de volgende, waarvan nu immers ruimte in het startmagazijn is, in de tijd te kunnen splitsen.

Nu moeten wij in de organisatie verdisconteren:

a)  
dat het gegeven van een startmagazijn van 4 startopdrachten een physisch gegeven is, maar dat deze omvang niets met de logische eenheden te maken heeft, "logische eenheden" ten aanzien van controle (en overdoen) of van interesse in voltooiing.

b)  
dat activiteiten van Starter en Controleur op elkaar afgestemd dienen te worden: de ene zal dingen in gang zetten, de ander zal van de voltooiing kennis nemen. De laatste dient dan te weten van de voltooiing waarvan hij kennis neemt, waar dit goed voor was en welke consequenties hieraan verbonden dienen te worden.

Wij kunnen deze beide dingen bereiken, door een (eventueel groter) magazijn in te voeren, waartoe zowel Starter als Controleur toegang hebben. De elementen van dit magazijn —laten we het even actiemagazijn noemen— bevatten:

a)
ten bate van de Starter startopdrachten

b)
ten bate van de Controleur nadere specificaties van de handelingen "actie goed" resp."actie fout" na voltooiing van de in dit element gegeven startopdracht.

Beide processen zullen dit actiemagazijn aftasten via een cyclisch werkende leegwijzer. Voeren wij de twee gebruikelijke seinpalen voor dit actiemagazijn in, via "actiemagazijn vol" en "actiemagazijn leeg" , dan wordt in dit algemene schema de Starter

"Starter: P(SRT, actiemagazijn vol);
    starterleegwijzer:= REM(starterleegwijzer + 1,N);
    vulwijzer:= REM(vulwijzer + 1,4);
    startopdracht[vulwijzer]:= actiemagazijn[starterleegwijzer];
    V(AFT); goto Starter"

opm. 
Met "actiemagazijn[ ]" wordt hier het startopdrachtgedeelte van een element bedoeld ; N = omvang van achtiemagazijn.

De Controleur begint met

"Controleur: P(IFT);
    controleurleegwijzer:= REM(controleurleegwijzer + 1,N);
    controlewijzer:= etc...."

"actie goed" wordt nu iets, dat het controleurgedeelte van "actiemagazijn [controleurleegwijzer]" verwerkt.
Hieronder kan vallen:

a)  
een aantal malen V(actiemagazijn leeg)

b)
de V-operatie op een in het actiemagazijn opgegeven seinpaal.

Het gecontroleerd transport kan nl. een reeks afsluiten ; hierdoor komt een aantal plaatsen in het actiemagazijn vrij ; verder kan bij een bepaald programma hierop hebben staan wachten.

Een programma, dat een serie elementen van het actiemagazijn wil opgeven, moet de mogelijkheid hebben, deze serie "ongespatieerd" door ander aanbod te kunnen opgeven. Dit kan met een binaire seinpaal AV (aanbod vrij):

"P(AV);
L: P(actiemagazijn leeg);
   vulwijzer:= REM(vulwijzer + 1,N);
   actiemagazijn[vulwijzer]:= volgend element;
   V(actiemagazijn vol);
   if B then goto L;
   V(AV)"

Opm. De elementen bevatten, hoeveel plaatsen in het actiemagazijn vrijgegeven zullen worden na controle. Het is wel vaak niet meer dan N niet vrijgevende elementen in successie aan te bieden. De veilige manier om dit te garanderen is om bij laatst aangeboden element alle elementen, die tussen P(AV) en V(AV) zijn aangeboden, vrij te doen geven. Als je niet oppast, zou het actiemagazijn "combinatorisch" dicht kunnen groeien!

Als het aantal elementen van het actiemagazijn, dat "per keer" gevuld wordt een redelijke bovengrens heeft, dan lenen deze programma's zich tot een vereenvoudiging, die nog wel illustratief is. Je kunt dan zeggen: kom, wees niet kinderachtig, stel in het actiemagazijn ruimte ter beschikking in wat grotere porties ; we noemen deze porties nu "transportschema's": een transportschema neemt de rol van een "aantal bij elkaar behorende elementen uit het actiemagazijn" over.

Het actiemagazijn wordt nu vervangen door een "transportschemabuffer" ; de seinpalen "actiemagazijn leeg, resp. -vol" vervallen en worden vervangen door "transportschemabuffer leeg, resp. vol" .

Het laatste programma wordt nu:

"P(AV, transportschemabuffer leeg);
  vulwijzer:= REM(vulwijzer +1,N1);
  transportschema[vulwijzer]:= .....;
  V(AV,transportschemabuffer vol)"

De Controleur bevat dan als onderdeel van "actie goed" de operatie "V(transportschemabuffer leeg)", de Starter krijgt de volgende constructie:

Starter: P(transportschemabuffer vol);
   starterleegwijzer:= REM(starterleegwijzer +1,N1) ;
L: P(SRT);
   vulwijzer:= REM(vulwijzer +1,4);
   startopdracht[vulwijzer]:= .....;
   V(AFT): if transportschema nog niet leeg then goto L;
   goto Starter"

Hiermee zijn enige "hoogfrequente" seinpalen geruild tegen evenveel "laagfrequente": ten koste van wat bufferruimte hebben wat werk uitgespaard. Het aantal onderling asynchrone processen is niet geslonken!

De trommel

Voor de trommel hadden we een iets afwijkend schema bedacht, dat tot op heden —12 februari 1964— nog niet verworpen is. Hierbij komt nl. nog de complicatie, dat een programma zelf geen "transportschema" opstelt; het kan slechts zijn behoefte uiten. Welke transport of transporten dit impliceert, hangt af van de momentane geheugenbezetting. M.a.w.: de "vertaling" van behoefte naar transportschema is een handeling, en het moment, waarop deze handeling plaats zal vinden moet gekozen worden. Wij hebben ons op het standpunt gesteld dat het gewenst is, deze handeling zo laat mogelijk te laten plaats vinden: het verlaten van behoefte in transportschema kan dan nl. van de meest recente gegevens uitgaan. Dit wordt "tegengewerkt" door het streven, de trommeltransport, als dit de bottleneck wordt, zo min mogelijk ledigheid te gunnen. D.w.z. de bufferingsmogelijkheden zijn hier niet bedoeld om grote asynchroniteit op te kunnen vangen, integendeel: tussen het uiten van behoefte en bevrediging daarvan zal het programma in kwestie als regel helemaal niet door kunnen werken! We hebben dus meer te maken met wat inmiddels een "morele haastsituatie" is gedoopt: buffering van startopdrachten is slechts een middel, om de morele haastsituatie te mitigeren.

Op deze gronden kwamen we tot de volgende constructie. We hebben een transportschemabuffer, dat cyclisch wordt afgewerkt. Over het aantal transportschema's, dat in deze buffer kan, zullen we het later hebben.

Elk programma communiceert met de trommeltransport via een zg. "behoeftetoonbank"; hier is gedacht aan een toonbank met de capaciteit van 1 behoefte.

Het aanbod van een behoefte vindt plaats via

".....P(behoeftetoonbank leeg);
      aanbod behoefte;
      V(behoeftetoonbank vol);
      P(zekere seinpaal)....."

Over de "zekere seinpaal" zullen we het straks nog wat uitgebreider hebben.

Het vertalen van behoefte vindt plaats gesynchroniseerd ten opzichte van het vullen van het physisch startmagazijn van de trommel, nl:

VERZORGER: P(toonbank vol, transportschemabuffer leeg);
           vertaal behoefte in transportschema;
        L: P(SRT);
           zet volgende startopdracht trommel;
           V(AFT);
           if heersend transportschema nog niet leeg then goto L;
           goto VERZORGER..."

De controleur bevat als onderdeel van "actie goed" na controle van een heel transportschema

"V(transportschemabuffer leeg, zekere seinpaal)".

Voor de "zekere seinpaal" kan men kiezen:

a)  
elk programma zijn eigen seinpaal ; deze moet dan (als onderdeel van de behoefte) in het transportschema worden opgenomen.

b)
anderzijds weet men, dat van deze seinpalen er maar een paar tegelijkertijd actueel kunnen zijn (ik geloof 1 meer dan er transportschema's in de transportschemabuffer kunnen). Men kan dit N-tal cyclisch afwerken bij het toonbank vullen en bij het vrijgeven door de controleur. Dit is een klein detail, dat niet belangrijk is.

Uit de tekst van de VERZORGER blijkt, dat als elk transportschema minstens 1 transport vergt, het zinloos is, om meer dan vijf transportschema's te kunnen bufferen. Twee is een absoluut minimum: als je maar 1 transportschema hebt, is bij overgang van het ene transportschema naar het volgende de trommeltransport beslist even ledig. Gezien de tijd van transporten (tientallen millisecunden) dachten we niet, dat een transportschemabuffer van meer dan twee erg verdedigbaar is.

transcribed by Sam Samshuijzen
revised Mon, 10 Jan 2005

EWD082     X-8 nr. 38.

Een ponsbandorganisatie van de X8.

Motto: "Wie het kleine niet eert,
            is het grote niet waard."

Inleiding.

In dit rapport zal het hoofdaccent vallen op het lezen van ponsband. Waarom het ponsen minder grote vragen op hoeft te werpen, zal in de loop hiervan duidelijk worden.

De bandleesopdracht van de X8 is volledig code-onafhankelijk, elke configuratie van al of niet gaatjes dringt tot de machine door en in zekere zin "is er geen probleem", nl. in de zin, dat we de verwerking van deze banden kunne programmeren zoals we willen. Omgekeerd geeft dit ons wel de plicht om uit de baaierd van mogelijkheden dan te kiezen, wat we willen. Een groot gedeelte van dit rapport houdt zich met deze keuze (en de motiviering daarvan) bezig.

Het leidende principie is, dat het voor de gebruiker zo gemakkelijk mogelijk gemaakt moet worden. Dit betekent onder andere dat wanneer een gebruiker opeenvolgende getallen van een ponsband wil lezen, dat hij dan een intern passende identificatie van numerieke waarden in zijn proces wil opnemen, zonder dat hij zich bewust hoeft te zijn van de conventies, volgens welke deze getallen op de band staan. Deze situatie is geheel analoog aan zijn instelling tegenover variabelen van type integer of real: voor hem karakteriseren deze waarden, hoe is zijn zorg niet; de interne representatie hoeft niet eens uniek te zijn. Bij een dergelijke wijze van bandlezen dienen allerlei "irrelevantia", voordat de numerieke waarde tot het programma doordringt, dus onder tafel geraakt te zijn.

De complicatie hierbij is echter, dat wij niet a priori decreteren kunne, wat voor de programmeur irrelevant is. Ponsbanden immers leiden een zelfstandig bestaan buiten de machine, zij kunnen komen van automatische meetapparatuur, zij kunnen voor ponsbandgestuurde machinerie gemaakt moeten worden. Waar wij dus op aansturen is een organisatie, die enerzijds het gemak dient, maar die anderzijds desgewenst de programmeur de volledige controle geeft, die hij nodig heeft om ponsband als "general purpose medium" te kunnen gebruiken.

Een volgende complicatie is het gemengde gebruik, dat men maken wil van het physische "einde band". "Einde band" is door de X8 detecteerbaar, de consequenties, die hieraan verbonden dienen te worden, kunnen van geval tot geval echter aanzienlijk verschillen.

Er zijn programma's, waarin einde band een essentieel onderdeel van de inkomende informatie stroom is, bv. een programma, dat een willekeurige band reproduceert. (Het is in dit licht jammer, dat de ponser niet beschikt over een door de X8 bestuurbaar afsnijertje!)

In andere organisaties wil men liever aan einde band geen betekenis toekennen. Als een programma vraagt om een heel lange band, die vb. uit twee stukken is opgebouwd, dan is het natuurlijk prettig, dat de EL 1000 zorgvuldig gemaakte plakjes slikt, maar het zou jammer zijn, als dit de operateur ook inderdaad tot plakken zou verplichten. Als de operateur om een of andere reden prefereert om zo'n band in twee stukken in te leggen, zou dit moeten mogen zonder dat daarbij een extra last plicht tot plakken wil geven, evenmin wil men de operateur de plicht tot knippen -dwz. het verbod tot plakken- opleggen, althans in het merendeel der gevallen, waarin hierdoor geen onduidelijkheden kunnen ontstaan. (Het is duidelijk, dat men achteraan een band, waarop "einde band" een essentieel onderdeel van de informatie is, niet straffeloos een andere band mag aanplakken.)

Het idee van de standaardband en "de open bek".

We gaan er vanuit, dat het merendeel der ALGOL-programma's zo is, dat, zo zij om getallenmateriaal vragen,

zij niet hoeven te reageren op "einde band"

dit materiaal van te voren bijgeleverd kan worden.

Het (operationeel) normale geval zij, dat deze band met getallenmateriaal dan achter de programmatext aangeplakt wordt (c.q. meteen erachteraan geponst is). Wij noemen een dergelijke band met te verwerken materiaal "de eigen band" van dit programma.

Hier geeft het begin van de band -nl. de programmatext- aan hoe de rest -nl. het getallenmateriaal- verwerkt moet worden. Wij willen dit idee een stap uitbreiden en spreken af, dat vooraan de text een herkenbare standaardkreet, zeg algol voorkomt. Dit is een metakarakter, dat behelst, dat de eropvolgende ponsingen als de etxt[sic] van een ALGOL-programma geinterpreteerd moeten worden. Deze interpretatie (vertaling, gevolgd door executie) is een standaardverwerking; het metakarakter algol is op de band geintroduceerd, omdat ik wel ruimte zie voor uitbreidingen van het aantal standaardverwerkingen. Al deze standaadverwerkingen zullen via een bijbehorend metakarakter geactiveerd kunnen worden.

Een band, die zichzelf aan een dergelijke standaardverwerking doet onderwerpen noemen we een standaardband. Het doel, waarnaar wij streven is om het overgrote deel der operateurshandelingen te gieten in het keurslijf "verwerking van een standaardband."

Hiertoe voeren wij in het concept van de "bandlezer met de open bek". De bedoeling is, dat de operateur voor de verwerking van een standaardband niet meer hoeft te doen dan zo'n standaardband inleggen in een bandlezer en op de groene knop drukken. De toestand, waarin een bandlezer aldus op standaardwijze op een standaardband reageert noemen we "met open bek".

Het is de bedoeling, dat alle banden, eenmaal ingelegd, in principe op volle snelheid -dwz. ongeacht het tempo van feitelijke verwerking- ingelezen worden. Als de lezer sneller loopt dan de feitelijke verwerking, dan kan de rest op de trommel gedumpt worden. Zodra "einde band" gesignaleerd is, wordt de lezer vrijgegeven en blijft deze achter met de bek open.

N.B. We eisen niet, dat "einde band" gesignaleerd is, voordat de feitelijke verwerking begint. Als het dringen in het geheugen is, dan moet de coordinator kunnen kiezen en "lezerbezetting" boven "geheugenbezetting" kunnen prefereren.

Hieraan zitten al enige haken en ogen, omdat bandlezers niet uitsluitend voor de standaardverwerking van standaardbanden gebruikt zullen worden. (Er bestaat ook non-standardverwerking van wat er overigens bedriegelijk als standaardband uitziet!)

De prijs, die we voor de gemakkelijke verwerking van standaardbanden moeten betalen bestaat uit enige extra hocus-pocus voor het non-standaardlezen. Men moet nl. een veilig sluisje maken voor het geval, dat de operateur te goeder trouw een standaardband inlegt in een lezer, juist op hetzelfde moment, dat de X8 beslist, deze lezer voor een ander doel te gaan gebruiken.

In ruimte aanleg kan een eenbandlezer zich in drie toestanden bevinden:
toestand 0: vrij
toestand 1: voor non-standaardwerk aangevraagd
toestand 2: bezet

In toestand 0 hangt er een tamelijk symbolische startopdracht voor 1 enkele heptade, die alleen maar gegeven is om het inleggen van een nieuwe band en het indrukken van de groene knop tot de X8 te laten doordringen. (Ik neem aan, dat de heptade zelf wellicht genegeerd zal worden.)

In toestand 1 heeft de X8 besloten, dat de bandlezer voor non-standaardwerk gebruikt gaat worden; hiervan is via de verreschrijver melding gedaan. De bandlezer zal niet verder lopen, voordat de operateur op deze melding geantwoord heeft, dat er geen verkeerde band in de bandlezer ligt.

In toestand 2 is de bandlezer definitief ingeschakeld voor een welomlijnde (al of niet standaard) taak.

Vindt nu een ingreep plaats van een bandlezer, die zich in toestand 0 bevindt, dan wordt deze band als standaardband verder gelezen. In doofheid vindt, als reactie op de symbolische heptade, de overgang naar toestand 2 plaats (en er wordt genoteerd, dat we nu standaardbandlezen). De volgende ingrepen vinden per definitie plaats in toestand 2.

Vindt een (eerste) ingreep plaats in toestand 1, dan wordt er tot nader order gen band meer gelezen. De operateur heeft dan nl. een standaardband ingelegd in de periode, dat de X8 de lezer al voor een ander doel besteed heeft, maar de operateur nog niet geantwoord heeft, van deze beslissing kennisgenomen te hebben. De operateur merkt dit o.a. doordat van de band, waarvan hij verwacht, dat hij naarbinnen zal schieten, maar 1 heptade gelezen wordt.

Het operateursantwoord -behelzend, dat er geen ongevraagde band in de lezer ligt, bewerkstelligt de overgang van toestand 1 naar toestand 2, een volledige specificatie van wat er dan wel moet gebeuren en tenslotte het vullen van het startmagazijn van de lezer in kwestie. Ligt de band al in, dan gaat hij lopen; de operateur mag het antwoord ook vast geven, als de lezer leeg is, waarna de band gaat lopen, zodra hij is ingelegd.

Het concept van de bandvariabele.

Als een band "synchroon met het physisch leesproces" verwerkt wordt, zoals bij ARMAC en X1, dan fungeert de ligging van de band in de lezer als geheugenelement. Tegen de tijd, dat we het bandbeeld in het geheugen hebben opgeslagen, moeten we dit "heptadewijzertje", dat het sequentieel aftasten van het bandbeeld bestiert, in het geheugen opnemen. Dit heptadewijzer is een belangrijke constituent van de zg. bandvariabele.

Voorts bevat een bandvariabele het gegeven, of het physisch leesproces al beeindigd is of niet. Zo nee, dan bevat hij een verwijzing naar de physische lezer, de lezeradministratie bevat op zijn beurt een verwijzing naar de bandvariabele. De koppeling "bandvariabele - lezer", die bestaan blijft, totdat de X8 voor deze lezer het signaal "einde band" gevonden heeft, wordt dus wederzijds geboekt. Zodra het signaal "einde band" tot de X8 doordringt, wordt deze koppeling verbroken. De bandvariabele heeft er dan geen weet meer van, via welke lezer deze band is binnengekomen, de lezer zelf gaat over in toestand 0 met de startopdracht voor de enkele heptade in het startmagazijn. (Dankzij het symbolisch afwerken van eventuele startopdrachten in het magazijn, zodra einde band gesignaleerd is, is het mogelijk om te zorgen, dat dit de enige startopdracht in het magazijn is.)

Een bandvariabele maakt altijd deel uit van een programma (uitgezonderd misschien bij de allereerste analyse van het metakarakter voorop een standaardband). Tijdens vertaling is de bandvariabele een grootheid van de vertaler, aan het einde van de vertaling fungeert de dan heersende waarade van de bandvariabele als initialisering van de eigen-bandvariabele van het vertaalde programma. Dit overhevelen van bandvariabele van vertaler naar vertaald programma dient met enige zorg te geschieden: omdat de bandlezer het leesproces nog niet voltooid hoeft te hebben, bergt een bandvariabele dus een mogelijke synchronisatiebeperking in zich. Het is deze synchronisatiebeperking, die ook van vertaler naar vertaald programma overgegeven moet worden.

Gestroomlijnd lezen en de rol van metakarakters.

Wanneer wij meer dan 1 programma simultaan in de machine hebben zitten, dan hebben wij zoals bekend er voor te zorgen, dat het ene programma niet zo fout kan zijn, dat daardoor het andere programma verstoord wordt. Deze garantie impliceert beperkingen ten aanzien van de structuur der individuele programma's. Ik heb me steeds op het standpunt gesteld, dat elke gebruiker, die deze beperkingen niet accepteren kan omdat hij in machinecode programeren wil, de machine dan maar in uniprogrammering bedrijven moet.

Een analoge situatie komen we tegen, wanneer we twee programma's, die verder niets met elkaar te maken hebben, achter elkaar op eenzelfde band willen invoeren. Het verwerkende systeem heeft dan de plicht om vast te stellen, waar de text van het tweede programma begint. De opsteller van het eerste programma mag dan niet de mogelijkheid hebben een zodanige fout te maken, dat het correct vaststellen van de plaats van deze caesuur niet meer een betrouwbare operatie is. Om veilig twee programma's achterelkaar[sic] op dezelfde band in te kunnen voeren, moet het eerste programma zekere spelregels in acht nemen, geheel analoog aan de boven gesignaleerde situatie. Uit de aard der zaak zullen wij ernaar streven, deze restricties zo min mogelijk knallend te maken.

Om het leven niet nodeloos te compliceren, veronderstel ik in het volgende dat een programma slechts op twee wijzen contact met de eigen band kan opnemen:

lees volgende ponsing

lees volgend getal.

In geval a) heeft de programmeur toegang tot ieder bit van de ingevoerde band en hij kan hierop naar eigen goeddunken reageren. Een programma, dat de ponsingen als zodanig van de eigen band leest is als het programma in machinecode; het is niet toegestaan om achter de eigen band van dit programma de text van een onafhankelijk volgend programma te plakken. (Wie rot zou willen doen, schrijft dan een ALGOL-programma, waarvan het enige effect is, dat het volgende ALGOL-programma op de hand wordt overgesslagen!)

Een programma, dat zich in zijn contact met de eigen band echter beperkt tot "lees volgend getal" kan door het systeem onder de duim gehouden worden. Ik beschouw hier "lees volgend getal" als een nieuw primitivum en niet als een subroutine opgebouwd met "lees volgende ponsing" in die zin, dat gebruik van "lees volgende getal" a fortiori gebruik van "lees volgende ponsing" zou impliceren. Hieraan verbinden wij twee consequenties.

Wij beschouwen "lees volgend getal" als een niet nader gespecificeerd proces, dat bij elke activering een volgende getalwaarde van de band distilleert (of alarm geeft). In het verwerkende programma is bv. niet te achterhalen, hoe deze getallen op de band gegeven zijn. Ze mogen via een flexowriter in decimalen geponst zijn, ze mogen wat mij betreft ook (door een vroeger ALGOL-programma) binair geponst zijn. Over het aantal mogelijkheden wil ik me nu niet uitlaten. In elk geval, bevat deze band, wat we vroeger controlecombinaties, wat we nu misschien "syntactische structuur" noemen.

De tweede consequentie is, dat we deze syntatische structuur zo kunnen maken, dat ook de omvang van de informatiehoeveelheid ondubbelzinnig -en wel buiten de invloedsfeer van de programmeur- vastgesteld kan worden. Een programma, dat zich in zijn contact met de eigen band beperkt tot die vormen, waarin deze eindvaststelling aldus geschieden kan, leest zijn eigen band "gestroomlijnd".

Als de eigen band voor gestroomlijnd lezen bestemd is en op de flexowriter gemaakt is, dan bestaat deze syntatische structuur naast de interne structuur van de getallen uit conventies ter getalscheiding, waarschijnlijk door middel van welgedefinieerde separatoren. Ik stel me voor een dergelijke band te doen afsluiten door een soort "superseparator", zeg het metakarakter enddata. Het gestroomlijnd lezen moet dan een zwaar controlerend proces zijn, dat o.a. onder geen beding het metakarakter enddata ongemerkt zou mogen laten voorbijgaan. Als het detectieproces voor het einde van de eigen band aldus tegen fouten van de programmeur is afgeschermd, mag de eigen band door een nieuwe, onafhankelijke band geolgd[sic] worden.

Een en ander suggereert, om de vertaler statisch de programma's in drie categorieen in te laten delen

programma's, waarin geen eigen band gelezen wordt

programma's, waarin de eigen band slechts gestroomlijnd gelezen wordt

programma's, waarin de eigen band (slechts) ongestroomlijnd gelezen wordt.

Alleen programma's uit de categorieen I en II staan een achteraangeplakt volgend programma toe (dwz. naar wij hopen bijna allemaal).

Opm.1. Het vaststellen in welke categorie een programma valt, dient statisch te geschieden. Immers, als we het dynamisch afwachten, of en zo ja, hoe een programma contact met de eigen band opneemt, dan zouden we bedrogen uitkomen, zodra een programma uit categorie III ten onrechte zijn activiteit beeindigt, nog voordat contact met de eigen band is opgenomen.

Opm.2. Naar aanleiding van de haakjes om "slechts" in de omschrijving van III. Misschien haal ik deze weg, en sta ik niet toe, dat een band deels gestroomlijnd, deels ongestroomlijnd gelezen wordt. Dit gemengd lezen hinkt nl. erg op twee gedachten. Ik voorzie, dat pogingen om onder alle omstandigheden de semantiek bij overgang te definieren aanleiding geven tot een rommeltje, dat geen gebruiker het vertrouwen geeft geen vergissingen gemaakt te hebben. Liever breidt ik de mogelijheden van gestroomlijnd lezen wat uit.

Buffering.

Wanneer een band gelezen wordt, waarvan de feitelijke verwerkingssnelheid aanmerkelijk lager ligt dan die van het leesproces, dan zal, als er nog voldoende ruimte op de trommel is, de bandlezer moeten kunnen doorlopen en moet het bandbeeld in het geheugen opgebouwd worden.

Als we -even wat royaal rekend- zeggen, dat we octaden lezen, waarvan we er 3 in een woord kunnen pakken, dan bergen we dus 1500 octaden in een pagina van 512 woorden. Een volledige rol -300 meter a 400 ponsingen per meter- bevat 120.000 ponsingen en vult dus 80 pagina's, 8 procent van de trommel. Dit is alleszins acceptabel en we mogen verwachten, dat de lezer dus inderdaad haast altijd full-speed zal doorlopen. Door de snelheid van de schone schuifopdracht kan dit pakken dunkt me ook heel snel; van het idee om banden ongepakt op de trommel op te slaan, schrik ik nog wel een beetje. (Als de prijs van het pakken tegenvalt, kunnen we altijd nog overwegen, om als een band teveel ruimte in dreigt te nemen, pas dan er toe over te gaan om de rest te pakken.)

Hoe een en ander georganiseerd gaat worden is nog niet zo duidelijk. We hebben enige exploratie gepleegd van het volgende arrangement. Op grond van de overweging, dat een voorrekend leesproces impliceren gaat, dat het verwerkende programma het vervolg van het bandbeeld via de trommel gaat aanhalen, dachten we, dat het een eenvoudigere organisatie zouden krijgen, als we afspraken, dat het informatietransport van pakkingsprogramma naar verwerkende programma altijd via de trommel zou lopen. De verwachte simplificatie viel niet mee, integendeel; het zat not niet eens helemaal rond en toen was het al ber[sic] ingewikkeld.

We sullen nu proberen om een arrangement uit te werken, waarbij assemblage- en verwerkingsproces communiceren via een soort cyclische buffer, waarin de elementen "paginadescriptoren" zijn en zullen kijken, of we dit kunnen spelen, onafhankelijk ervan of de pagina's zelf zich nog op de kernen bevinden. De bedoeling is, dat indien bandbeeldpagina's naar en van de trommel getransporteerd worden, ze zich in niets onderscheiden van andere pagina's, die een de autonome trommeltransport onderworpen zijn. Misschien mode, omdat we dit nog niet hebben uitgewerkt, verwachten we hier veel van.

Ook bij output via ponsband willen we bufferen en we stellen ons voor, dat er normaliter pas een ponser voor een band gereserveerd wordt, als het volledige bandbeeld in het geheugen is opgebouwd. Hiermee hopen we drie dingen te bereiken.

Ten eerste zal hierdoor een programma een bandponser zo kort mogelijk aansluitend bezetten. Ten tweede is nu de lengte van de band bekend, voordat het ponsproces begint. Als de coordinator ingelicht wordt, wanneer er een nieuwe rol in een van de ponsers is ingelegd (en wanneer de operateur wat bescheiden met run out omgaat) dan kan de coordinator bijhouden, hoeveel papier er nog op de rol behoortte[sic] zitten. Er kan dus voor gezord worden, dat niet halverwege de band het papier plotseling op is. Ten derde kan men dit bandbeeld twee maal opbouwen, nl. eerst om te ponsen, en later om te controleren. Dit controleproces willen wij beschouwen als een van de standaardhandelingen, die geactiveerd kan worden, door een band met een passend metakarakter in een open bek te leggen. Dit extra metakarakter zal het ponsproces er ongevraagd vooraan toevoegen, als het zijn werk gedaan heeft, kan de operateur het afscheuren. Het succesvol beeindigen van het controleproces kan de geheugenruimte van het bandbeeld vrijgeven.

transcribed by David J. Brantley
latest revision Sat, 29 May 2004

  EWD 84

15 mei 1964

Over paginaadministratie.

0. Enige terminologie.

Om spraakverwarring te voorkomen, voeren we in de begrippen "pagina" en "bladzijde". Een bladzijde is een hoeveelheid informatie van 512 woorden, een pagina is een stuk van een van de geheugens, bestemd om, indien gebruikt, een bladzijde te herbergen. Een pagina beslaat dus 512 woorden. De bladzijde is dus de informatiehoeveelheid, die in een pagina "past".

In de programma's zijn het de bladzijden, die een duidelijke identiteit hebben. De text van het objectprogramma wordt in bladzijden onderverdeeld, bladzijden, wier bestaan begint in de loop van het compilatieproces en eindigt na voltooiing van het programma. Grote arrays zullen hun elementen eveneens in bladzijden ingedeeld krijgen, in principe beginnen deze bladzijden hun bestaan bij de uitvoering van de arraydeclaratie, ze eindigen hun bestaan bij de definitieve verlating van het blok in kwestie.

De stapel wordt enigzins anders behandeld; deze zal wel steeds bestaan uit een aantal bladzijden, maar om de elementen van deze bladzijden te adresseren zal een ander mechanisme geschapen worden dan het mechanisme, nodig om een element te selecteren uit een algemene bladzijde (programmatext of groot array). De elementen in de stapel zullen nl. tijdens hun levensduur slechts op een vaste plaats in de kernen kunnen staan, zodat we deze elementen gedurende hun bestaan kunnen karakteriseren door hun physisch kernenadres.

Elke bladzijde (althans de non-stapelbladzijden) ontleent zijn identiteit aan een hem toegevoegde grootheid, een zg. BZV (BladZijde Variabele). Doorgaans zijn de BZV's gesitueerd in de stapel van het programma, waarin deze bladzijden voorkomen. (Dit geldt ten duidelijkste voor de bladzijden, die de programmatext uitmaken; de bijbehorende BZV's kunnen we beschouwen als globale variabelen van dit programma. Dit geldt ook voor de BZV's voor array-bladzijden; deze zijn lokale grootheden van het blok, waarin het array gedeclareerd is.) Er komen in het samenspel ook andere bladzijden voor, bv. de bladzijden, die de bibliotheek van standaardprocedures, die permanent op de trommel aanwezig geacht wordt; deze kunnen kennelijk niet exclusief in de stapel van 1 programma ondergebracht worden. Immers, de bibliotheek is een gedeelte van het universum, waarin de verschillende programma's samen in ingebed worden, de bibliotheek overtreft, omvat, in levensduur ook de individuele programma's. Dit vindt zijn neerslag daarin, dat er naast wat de programma's prive nodig hebben, op een vaste plaats in het kerngeheugen een rijtje BZV's ondergebracht zal worden, de "bibliotheek BZV's", waartoe ieder individueel programma, bij gratie van het feit, dat ze permanent op een vaste plaats te vinden zullen zijn, via directe adressering toegang toe heeft. Een soortgelijk arrangement zal gemaakt worden om het mogelijk te maken bladzijden van het ene proces over te hevelen naar een ander proces; ik heb hier het oog op input-output-buffers.

Pagina's hebben we uit de aard der zaak in twee soorten, nl. "kernpagina's" en "Trommelpagina's". In beide media beslaan ze 512 opeenvolgende geheugenwoorden. De BZV's heten "variabelen" omdat ze onder andere vastleggen, in welke pagina(s) de bladzijde in kwestie te vinden is. Wij zullen straks uitgebreid en in detail beschrijven, welke informatie in de BZV's vastgelegd wordt en hoe. Bij die afspraak hebben twee dingen als leidraad gediend: het meest voorkomende geval moet zo snel mogelijk herkend kunnen worden (een tijdsoverweging dus) en de BZV moet zo min mogelijk ruimte in beslag nemen (een overweging van geheugenruimte dus). Dit laatste is belangrijk, omdat de BZV's —zoals wij later zullen zien— permanent in het kerngeheugen zullen staan en aan elke voorkomende bladzijde een BZV is toegevoegd.

Ook de pagina's worden door additionele "variabelen" nader beschreven. Voor de trommelpagina's - wat er heel veel zijn - is dit slechts een enkel bit, dat aangeeft of deze trommelpagina vrij, dan wel bezet is. Voor de kernpagina is deze statusinformatie aanmerkelijk omvangrijker, maar daar deert dit minder, omdat het maximale aantal kernpagina's zoveel kleiner is. De informatie, die de status van een kernpagina beschrijft heet een KIE (Kern Inhoud Element). Een KIE beslaat tot op heden vier woorden. (We merken en passant op, dat dit bijna een procent is van de geheugenruimte, die door de kernpagina zelf wordt ingenomen; bij veel kleinere kernpagina's zou de voor de KIE's benodigde geheugenruimte zich gaan wreken.) Wat een KIE precies allemaal aangeeft en hoe, zullen we eveneens in detail bespreken.

1. Classificatie van kernpagina's.

In het volgende zal een classificatie gegeven worden van de hoofdtoestanden, die we bij een kernpagina onderscheiden. Deze classificatie geeft aan (steeds), welke rol deze kernpagina op dit moment speelt. In de individuele programma's is deze rol vrij duidelijk, we moeten ons echter realiseren, dat een kernpagina ook betrokken kan zijn in een trommeltransportopdracht, of om de bladzijde, die hij herbergde op de trommel te dumpen, of om de inhoud van een trommelpagina over te nemen. Deze actie's worden niet zozeer door de individuele programma's als door de coordinator ondernomen. De tijdsduur van deze transporten is geenszins verwaarloosbaar en we moeten de status van een kernpagina "in een transport betrokken" dus expliciet invoeren. Hoeveel onderscheidingen we hierin willen aanbrengen, welke facetten tijdens zo'n transport van belang zijn, hangt van de coordinator af. Dat de hieronder te beschrijven indeling van kernpagina's zinvol is, is dus eigenlijk niet aan te tonen zonder ook in detail dat stuk van de coordinator te beschrijven, dat hier relevant is. We zullen dit toch proberen, dit rapport moge dan dienen als "underlying information" voor de beschrijving van de betrokken coordinator-mechanismen. (Zoals beschreven zijn in de blokschema's van het document "bladzorg" d.d. 1–3 mei 1964.)

Ik ben mij bewust, dat de onder te geven indeling niet dwingend is; zij is de neerslag van weloverwogen (zo men pejoratief wil zijn "willekeurige") beslissingen. Het beste, waarnaar ik dus naar streven kan is waarschijnlijk maken, dat de genomen beslissingen de weg banen tot een hanteerbare organisatie!

Ter introductie tot het soort moeilijkheden moge de volgende "PTT-gelijkenis" dienen. De PTT heeft op zich genomen, om brieven te bezorgen, bezorgt deze niet instantaan maar weet drommels goed, dat deze brieven een eindige reistijd hebben. Als alle geadresseerden het eeuwige leven hadden en nooit verhuisden, had de PTT geen probleem. Gegeven is echter het feit, dat geadresseerden slechts per adres slechts een eindige verblijfstijd doorbrengen. Het probleem van briefbezorging zou heel andere vormen aannemen, asl de gemiddelde verblijfstijd op eenzelfde adres eens klein was ten opzichte van de gemiddelde reistijd van een brief! (Soms vraag ik me af, of de PTT zich wel bewust is, hoezeer ze in dezen door het oog van de naald gekropen zijn.)

Soortgelijke moeilijkheden hebben wij, doordat trommeltransporten niet instantaan plaats vinden, ook. Tijdens de periode, dat een bladzijde tussen langzaam en snel geheugen getransporteerd wordt, kunnen er allerlei dingen mee gebeuren. De bladzijde kan ophouden te bestaan. Het kan ook gebeuren, dat terwijl we bezig zijn om deze bladzijde op de trommel te dumpen, er hernieuwd interesse in ontstaat. Maw. een trommeltransport wordt ondernomen op grond van een of andere beslissing (dat een bladzijde naar het schijnt niet erg interessant is bv.) maar tijdens de uitvoering van een dergelijk transport kunnen zich omstandigheden voordoen, waardoor men deze beslissing eigenlijk wil herroepen, resp. aan het transport een andere betekenis wil geven. De eerste beslissing, die wij daarom genomen hebben is, dat wij voor de roltoekenning van een kernpagina, die in een transport betrokken gaat worden, geen beslissing zullen nemen, die verder in de toekomst reikt dan de voltooiing van dit transport.

Het komt er op neer, dat we niet het volgende arrangement gevolgd hebben. Als een van de programma's een levendige belangstelling in een bladzijde, zeg bladzijde A, toont, die op dat moment zich niet in de kernen bevindt, dan zoekt men uit, welke bladzijde, die zich wel op de kernen bevindt, het oninteressantst lijkt. Dit zij bladzijde B. Men verwijdert nu bladzijde B uit de kernen (als hij niet ook nog op de trommel staat, impliceert dit een dumpend transport naar de trommel) en geeft vervolgens een transportopdracht om bladzijde A op de vrijgemaakte kernpagina over te nemen. Dit arrangement dwingt ons dus om ten aanzien van de kernpagina in kwestie twee transporten in de toekomst te kijken en dit hebben wij niet gekozen.

In plaats daarvan maken wij het systeem zo, dat er in principe wel een vrije kernpagina is. Ontstaat er nu behoefte aan bladzijde A, dan wordt een transportopdracht naar deze vrije kernpagina gegeven; vervolgens wordt geanalyseerd of door deze bezetting het aantal vrije kernpagina's angstig laag geworden is, zo ja, dan wordt gekeken welke het oninteressantst is en deze wordt verwijderd uit de kernen; dit laatste heeft dus mogelijk een dumpend transport ten gevolge.

De redenen, dat wij de tweede methode gekozen hebben, zijn de volgende. Nogmaals, wij zijn ons bewust, dat ze niet dwingend zijn. In het eerste geval moet je eerst de minst interessante kiezen, zodoende ruimte maken voor wat je nodig hebt. Dit lijkt in twee opzichten ongunstig. Het keuzeproces, welke het minst interessant is, kon wel eens een beetje tijdrovend zijn en bovendien komt er (mogelijk) eerst het ruimtemakend transport voordat het transport van trommel naar kernen plaats kan vinden. Het programma, dat bladzijde A nodig had, wordt daardoor gegarandeerd vrij lang opgehouden. Dat is allemaal goed in multiprogrammering, als je veel andere programma's hebt, maar dat is natuurlijk niet iets om op te bouwen. In het gekozen arrangement kan het transport voor bladzijde A meteen gegeven worden, zodat het programma, dat bladzijde A nodig heeft, zo gauw mogelijk weer door kan gaan. Het is nu de vraag, of de machine nog een ander nuttig programma op de pennen heeft en dit is dus het geknipte moment om de "minstinteressante" er uit te kiezen en maar vast ruimte te maken.

Een ander gevolg is zuiver organisatorisch: in het startmagazijn voor de trommel zal op elk moment voor een bepaalde kernpagina hoogstens 1 startopdracht staan, in het transport is elke kernpagina hoogstens met 1 bladzijde betrokken. Dit betekent, dat we de informatie over wat op komst is, wat weggetransporteerd wordt etc. per kernpagina kunnen bijhouden. dwz. dat we de omvang van een KIE klein kunnen houden. Hoewel we alternatieven niet tot het eind toe hebben uitgewerkt (we hebben pogingen ondernomen, maar raakten, mogelijk door gebrek aan ervaring, vast), hebben we het gevoel, dat het hier voor te stellen systeem onder andere zijn eenvoud ontleend aan het feit, dat een kernpagina in de tijd, dat hij vrijgemaakt zit te worden, niet al vast een andere bestemming gekregen heeft.

Nu gaan we de classificatie van de kernpagina's geven. Een kernpagina kan zich in eerste instantie in twee elkaar uitsluitende toestanden bevinden. nl. wisselend en niet-wisselend. Een kernpagina is wisselend, wanneer voor deze kernpagina een trommeltransportopdracht gegeven is, van de voltooiing waarvan door de X8 nog geen kennis is genomen; anders is de kernpagina niet-wisselend.

Zolang een kernpagina wisselend is. zal geen X8-programma zijn kernen aanraken, noch voor deze kernpagina vast andere startopdrachten geven. Het aanbod van een startopdracht impliceert dus (ongeacht richting van het transport) altijd de overgang van niet-wisselend naar wisselend; de kennisname van de voltooiing van het transport impliceert dankzij deze zelfde conventie dus altijd de inverse overgang.

(Wij zijn ons er van bewust, dat de regel, dat geen programma de kernen van een wisselende pagina zal selecteren, nodeloos stringent is. Als dit transport een transport van trommel naar kernen is, zou deze selectie onder bijkans alle omstandigheden zinloos zijn; in het inverse geval valt er nog over te denken: als we uit de kernpagina willen lezen, dan kan dit nog, willen we er in schrijven, dan heeft dit alleen maar ten gevolge, dat de copie, die op de trommel komt, tijdens dat proces al obsoleet aan het worden is. Logisch zou dit wel kunnen, we hebben het echter niet toegestaan.

De eerste reden is, dat hierdoor bij inspectie van de toestand van een kernpagina de transportrichting plotseling interessant zou worden, terwijl, zoals we zullen zien, die verder nauwelijks een rol speelt. (Na afloop van een transport, tijdens de uitvoering waarvan we niet geinterfereerd hebben met de kernpagina, kunnen we altijd de kernpagina beschouwen als een copie van de trommelpagina, ongeacht in welke richting het transport heeft plaatsgevonden.) De tweede reden is een kwestie van voorzichtigheid: stel, dat het transport een pariteitsfout detecteert! Om er dan nog uit te komen, als het programma de inhoud van de kernpagina, zoals die bedoeld was, inmiddels heeft mogen veranderen, lijkt een nodeloze verzwaring van deze toch al hachelijke opgave. (Wisselende kernpagina's blijven dus op alle manieren onaangeroerd.)

Wisselende kernpagina's worden onderscheiden in PRAEVRIJE en PRAECOPIEEN.

Een wisselende kernpagina is PRAEVRIJ, wanneer er —met inachtname van de momentane kennis van de getoonde interesse— na afloop van het transport geen interesse zal zijn in de inhoud van de kernen. Dit is dus ten duidelijkste het geval, wanneer de bladzijde, die in het transport betrokken is, tijdens dit transport zal ophouden te bestaan. Ook als een origineel gedumpt wordt om een vrije kernpagina te maken (zie onder), dan zullen we deze kernpagina als PRAEVRIJ beschouwen.

Een wisselende kernpagina is een PRAECOPIE, zodra is vastgesteld, dat er na voltooiing van het transport interesse in de kerneninhoud geacht wordt te ontstaan. Dit is ten duidelijkste het geval bij het aanhalen van een trommelpagina, die een bladzijde bevat, waarmee een van de programma's verder moet werken.

Een niet-wisselende kernpagina is in eerste aanleg een VRIJE, een COPIE of een ORIGINEEL.

Een niet-wisselende kernpagina is een VRIJE, wanneer zijn KIE niet met een BZV geassocieerd is: de inhoud van deze kernen is volledig "afgeschreven", behalve dat we wel correcte pariteit zullen eisen. (Maar dit is alleen een verplichting voor het tandenpoetsen.)

Een kernpagina is een COPIE of een ORIGINEEL, wanneer hij een bladzijde bevat; zijn KIE is dan geassocieerd met de BZV van deze bladzijde. Het verschil tussen een COPIE en een ORIGINEEL is, dat in het geval van de COPIE tevens een trommelpagina geassocieerd is, waar deze zelfde bladzijde te vinden is. Een origineel bestaat slechts enkel op de kernen. Kernpagina's, die programmatext bevatten zullen dus meestal COPIEEN zijn (nodig is dit niet: ze kunnen door de compiler in het kerngeheugen opgebouwd zijn en als er altijd voldoende ruimte in het kerngeheugen is, dan zijn ze nooit gedumpt en dus origineel gebleven.

Er zijn tussen deze vijf toestanden (hoofdtoestanden, we zullen ze later nog wat differentieren) 10 overgangen mogelijk.

1) VRIJE → PRAECOPIE. Dit vindt plaats, als een vrije kernpagina gekozen is om een bladzijde over te nemen, die alleen op dat moment op de trommel staat. Dit is een heel gewone overgang.

2) PRAECOPIE → COPIE. Dit vindt plaats als onderdeel van de kennisname van de voltooiing van een trommeltransport, waarna mogelijk interesse in de getransporteerde bladzijde ontstaat. Dit is de normale overgang, volgens welke de toestand PRAECOPIE verlaten wordt. Wij vestigen er nogmaals de aandacht op, dat deze overgang plaats kan vinden na afloop van een schrijfopdracht naar de trommel (zie overgang 10.)

3) COPIE → ORIGINEEL. Deze overgang vindt plaats, zodra een programma schrijft op een bladzijde, die in een kernpagina geborgen werd, die als COPIE te boek stond; een neveneffect hiervan is, dat de trommelpagina, die in de KIE van de kernpagina vermeld stond, wordt vrijgegeven. Tevens wordt de verwijzing naar deze trommelpagina, ter voorkoming van verwarring, verwijderd. Dit is een normale overgang voor bladzijden van een groot array, met programmabladzijden zal dit niet gebeuren.

4) ORIGINEEL → PRAEVRIJE. Deze overgang vindt plaats, als de keuze van de coordinator om ruimte te scheppen, gevallen is op een "oninteressant" ORIGINEEL. Er wordt, omdat in de kernen een ORIGINEEL staat, voor deze bladzijde een vrije trommelpagina gekozen en er wordt een (dumpende) startopdracht gegeven. Deze overgang (evenals overgang 1) vindt dus altijd plaats op het moment, dat een nieuwe startopdracht aan de trommel aangeboden wordt. Ook deze overgang moet normaal geacht worden.

5) PRAEVRIJE → VRIJE, Deze overgang vindt plaats als onderdeel van de kennisname van de voltooiing van een trommeltransport. Als de KIE van deze kernpagina nog aan een BZV gekoppeld was (en als aan het einde van het transport de bladzijde nog bestond, dan zal dit het geval zijn) dan wordt op dit moment de koppeling losgemaakt. Op dit moment is deze kerninhoud niet meer via deze BZV te bereiken.

6) COPIE → VRIJE. Deze overgang vindt plaats als de keuze van de coordinator om ruimte te scheppen gevallen is op een "oninteressante" COPIE; de overgang vindt tevens plaats, als een bladzijde ophoudt te bestaan (bv. een bladzijde van een groot array bij verlating van het blok), die als COPIE in de kernen aanwezig is, een geval, waarin tevens een trommelpagina wordt vrijgegeven.

7) ORIGINEEL → VRIJE. Deze overgang vindt plaats als een bladzijde, die als origineel in de kernen aanwezig is, ophoudt te bestaan, bv. een arraybladzijde bij blokverlating. Dit zal ook gebeuren bij inkrimping van een programmastapel, omdat, zoals we later zullen zien, de stapelbladzijden altijd als origineel in de kernen zullen staan.

8) VRIJE → ORIGINEEL. Deze overgang vindt plaats bij stapelgroei en eveneens bij eerste referentie naar een van de elementen van een nieuw geintroduceerde arraybladzijde. Bij de arraydeclaratie wordt voor een groot array nog geen bladzijde geintroduceerd, alleen maar een stel "potentiele" bladzijden, dwz. een stel BZV's, die geinitialiseerd worden met de speciale indicatie "nuchter". Pas bij de eerste referentie naar een dergelijke bladzijde wordt er aan deze BZV een feitelijke (dwz. niet-lage) bladzijde toegevoegd. Deze introductie vindt uit de aard der zaak plaats in de kernen en geeft dus aanleiding tot een ORIGINEEL.

9) PRAECOPIE → PRAEVRIJE. Deze overgang zal, zo hij voorkomt, exceptioneel zijn. Het betekent, dat we, van de veronderstelling, dat een bladzijde interessant was, afstappen en beslissen, dat we deze bladzijde toch maar niet in de kernen willen hebben. Dit zou zich voor kunnen doen, doordat het programma, dat deze bladzijde heeft aangevraagd, in die tussentijd ten gevolge van een foutmelding beeindigd wordt. Het meest waarschijnlijke geval, dat dit optreedt, is ten gevolge van de hint (zie onder); hier kan een programma van te voren vast aankondigen, dat het hoogstwaarschijnlijk straks interesse gaat tonen in een zekere bladzijde. Nodig is die interesse niet, de hint kan een arraybladzijde betreffen, die tijdens transport ophoudt te bestaan.

10) PRAEVRIJE → PRAECOPIE. Deze overgang is weer veel waarschijnlijker dan de vorige. Hij treedt op, wanneer interesse getoond wordt in een bladzijde, die op dat moment net in een transport betrokken was, waaraan op dat moment de bedoeling gehecht was, dat het een VRIJE kernpagina zou opleveren; in alle waarschijnlijkheid was dit dus een dumpend transport voor een arraybladzijde.

2. Onderverdeling van de hoofdclassificaties voor kernpagina's.

De VRIJE kernpagina's zijn het gemekkeijkste, omdat daarover het minste te vertellen valt. De belangrijkste eis is, dat we, op het moment, dat we een vrije kernpagina nodig hebben en er inderdaad eentje is, zo snel mogelijk ontdekken, welke kernpagina we daarvoor kunnen nemen. Voor dit doel zijn de VRIJEN in een ketting geregen, het schakelelement waarvan in de KIE van de kernpagina is opgenomen. Men kan voor dit doel volstaan met een enkelvoudige ketting, omdat je de VRIJEN —ze zijn je allemaal even lief— gebruiken kunt volgens het principe van een stapel. Een nieuwe vrije schakel je voor aan de ketting erbij, als je een vrije nodig hebt, neem je de eerste van de ketting. Het is de plicht van de tandenpoetserij om aan het begin alle kernpagina's, die dan vrij zijn, in deze ketting op te nemen.

Voor de wisselende kernpagina's moeten we onderscheiden, of het transport betrekking heeft op een nog bestaande bladzijde of niet. Bij de PRAECOPIEEN is dit in elk geval zo, voor de PRAEVRIJEN hoeft de bladzijde echter niet meer te bestaan, In geval van wisselende kernpagina ten bate van een bestaande bladzijde zal tijdens het transport de koppeling van BZV en KIE bestaan. Wie vraaagt naar een bladzijde, die in wisseling betrokken is, wordt via de BZV van die bladzijde (deze BZV is uniek voor die bladzijde en de enige manier om contact met die bladzijde op te nemen) naar de KIE verwezen worden, daar echter zal genoteerd staan, dat de kernpagina wisselend is. Tot deze "vroegtijdige" koppeling worden we gedwongen door het bestaan van de bibliotheek: het is immers heel goed mogelijk, dat een programma niet verder kan, vanwege de afwezigheid van een bibliotheekbladzijde; in de wachttijd van dit programma kan heel wel een ander programma, dat wel door kan gaan, ontdekken, dat het deze zelfde bibliotheekbladzijde nodig heeft. Zijn het de PRAEVRIJEN, waarbij we het onderscheid moeten aangeven of de bladzijde nog bestaat, bij de PRAECOPIEEN kunnen we reeds betekenis toekennen aan de zg. heiligheidsteller. (Zie onder.)

De COPIEEN en de ORIGINELEN worden onderverdeeld in "profanen" en "heiligen". Een heilige kernpagina is een kernpagina, waaraan de coordinator niet op eigen gezag een andere rol mag toebedelen. Het is nl. wel mogelijk, de programma's zo te schrijven, dat een bladzijde niet noodzakelijkerwijs ergens in de kernen is, het is echter niet toegestaan, dat een bladzijde, waarvan de aanwezigheid door een programma geconstateerd is, op elk willekeurig microscopisch moment verdwijnt. Allicht niet: als een programma een element van een groot array wil selecteren en heeft vastgesteld, op welk kernadres dit element zich bevindt, dan mag tussen deze vaststelling en de feitelijke selectie dit element niet uit de kernen verdwijnen. Wel, heel vaak zal dit gegarandeerd worden, door het stuk van verificatie van de aanwezigheid en de feitelijk selectie in doofheid te doen uitvoeren. Als X8 aan zo'n stukje begonnen is, dan wordt dat dus eerst afgemaakt, voordat mogelijk de coordinator over de rol van deze kernpagina anders beslist. (In multiprogrammering moet je zoals bekend voorzichtig zijn met doofheid: in de individuele programma's zal de X8 heel vaak eventjes doof zijn.)

Het mechanisme van de tijdelijke doofheid is echter niet machtig genoeg: de efficiency van de individuele programma's wordt aanzienlijk verhoogd, indien zij de mogelijkheid hebben om ten aanzien van een beperkt aantal pagina's over een beperkt verloop van tijd er op te mogen rekenen, dat deze bladzijden niet onder hun vingers worden weggegrist. Aan elk programma is de plicht, zo geconstrueerd te zijn, dat het op geen moment te veel kernpagina's simultaan heiligt, want anders zouden ze het kerngeheugen blokkeren. (Hiermee hebben we bij de behandeling van de stapel een beetje de hand gelicht, zie later.)

Heiliging van een kernpagina is iets, dat geschiedt op instignatie van een van de individuele programma's; dit programma laadt daarmee de plicht op zich om deze heiliging mettertijd weer ongedaan te maken, deze pagina weer te "profaneren". In het bijzonder zal een programma, dat een niet in de kernen aanwezige bladzijde voor zijn voortzetting nodig heeft, vragen om deze bladzijde in een geheiligde kernpagina. Met deze heiliging is gekoppeld, dat dit programma straks via een P-operatie op deze bladzijde kan gaan staan wachten. Hiermee voorkomen we de volgende situatie: een programma heeft een bladzijde, die enkel op de trommel staat, beslist nodig, er wordt een trommeltransport voor dit programma gestart en het programma komt op de wachtlijst der geblokkeerde programma's. Na voltooiing van dit transport wordt het wachtende programma overgeheveld naar de uitvoerbaren, maar het komt niet direct aan bod. Als we nu de pagina in kwestie niet geheiligd hadden, dan zou de mogelijkheid bestaan, dat dit programma, tegen de tijd, dat het wel aan bod komt, tot de ontdekking moet komen, dat de bladzijde, waarop het had staan wachten, inmiddels weer verdwenen is. Dit nu hebben we met behulp van de heiligheid uitgesloten: deze bladzijde blijft onaantastbaar in het kerngeheugen staan, totdat het programma, dat om deze bladzijde gevraagd heeft, de inhoud van deze bladzijde inderdaad heeft kunnen selecteren.

De bibliotheek schept hier een kleine complicatie. Uit het voorafgaande zou men kunnen concluderen, dat het voldoende is, om elke kernpagina een heiligheidsbit te geven, maar terwijl het ene programma staat te wachten op de aankomst van een bibliotheekbladzijde, kan een ander programma doorgaan en ook op deze bladzijde komen te wachten. En niet alleen in deze toestand. We zullen in elk programma de bladzijde, waaruit op dat moment de opdrachten gehoorzaamd worden, heiligen, dwz. heiligen bij binnenkomst en profaneren bij verlating. Twee verschillende programma's kunnen dus beide dezelfde bladzijde willen heiligen. Om die reden bevat de KIE niet een heiligheidsbit, maar een heiligheidsteller; heiliging betekent verhoging met 1, profanatie betekent aflaging met 1 en een kernpagina geldt als profaan, wanneer zijn heiligheidsteller = 0 is. (Naast de individuele programma's zullen wij in het "Hotel voor abstracte machines" ook stamgasten hebben ter verzorging van input-output bv.; dankzij de heiligheidsteller is het nu ook mogelijk, meer dan 1 kleine stamgast in dezelfde programmapagina te definieren, c.q. een stamgast parallel te activeren.)

Het heilig aanvragen van een bladzijde legt een onontkoombare verplichting op aan de coordinator (nl. om vroeg of laat met die bladzijde voor de draad te komen), het programma, op welks instignatie dit gebeurd is, heeft hiermee de verplichting op zich genomen, om vroeg of laat deze pagina weer te profaneren. Dit is het ene mechanisme, dit lijkt ons absoluut noodzakelijk. Daarnaast willen we in dit stadium niet de mogelijkheid uitsluiten, dat een (waarschijnlijk handgemaakt) programma de coordinator een zg. "hint" geeft, behelsend "Straks ben ik waarschijnlijk in die en die bladzijde geinteresseerd". Dit is het soort opmerkingen, dat de coordinator als niet opportuun naast zich neer kan leggen; het programma, dat de hint gegeven heeft, zal voor de feitelijk selectie toch de aanwezigheidstest weer uitvoeren. Als de coordinator de hint krijgt en de bladzijde is aanwezig, dan kan hij het interessegetal van deze kernpagina verhogen. daarmee de kans verkleinend, dat deze bladzijde er in de naaste toekomst uitgekeild wordt; als de bladzijde er niet is, dan mag een trommeltransport gegeven worden (als er een geschikte vrije is, als er ruimte in het startmagazijn is etc.) Deze verwerking van de hint gaat niet met heiliging gepaard. Hier zien we dus, dat ook bij de PRAECOPIEEN de heiligheidsteller van deze kernpagina zal moeten gegeven worden, als de PRAECOPIE in COPIE overgaat. In de volgende sectie zullen we zien, dat dit gegeven op de keeper beschouwd, overbodig zal zijn.

3. Terugmelding van aankomst van bladzijden.

Als een programma vraagt om een heilige kernpagina, dan betekent dit vanuit de kant van het programma, dat het via de voltooiing van een P-operatie van de aanwezigheid van deze bladzijde in kennis gesteld wil worden, het betekent voor het systeem, dat de aankomst van deze bladzijde in een kernpagina door de ophoging van een seinpaal bezegeld moet worden. De eersste vraag is, waar we deze seinpaal onderbrengen. Een eerste suggestie is, om deze seinpaal onder te brengen bij de startopdracht; we zouden dan vier van deze trommelseinpalen hebben, voor elke mogelijke startopdracht in het magazijn eentje. Bij aanbod van een nieuwe startopdracht zouden we deze seinpaal = 0 moeten zetten, in de heiligheidsteller van de PRAECOPIE houden we bij, hoeveel programma's echt op deze bladzijde staan te wachten en als reactie op de ingreep voeren we de V-operatie op deze seinpaal uit met de dan heersende waarde van de heiligheidsteller als increment. Een programma, dat op een bladzijde moet wachten, doet dit, omdat de bladzijde al wisselend is of omdat er een startopdracht voor die bladzijde gegeven moet worden, in beide gevallen is bekend, welke van de vier startopdrachten voor het transport zorgt en het programma weet op dat moment, op welke seinpaal het straks moet gaan wachten. Dit arrangement is echter uiterst link. Dit werkt nl. goed, wanneer het aanvragende programma al op deze seinpaal staat te wachten, tegen de tijd, dat de bladzijde arriveert; in dat geval bewerkstelligt de V-operatie nl. dat het programma van de lijst der geblokkeerden naar die van de uitvoerbaren wordt overgeheveld. Dit gaat echter scheef, wanneer op het moment van aankomst van de bladzijde het programma nog niet zover is, nog niet aan de P-operatie toe is. Tegen de tijd, dat dat nl. het geval is, kan diezelfde plaats in het startmagazijn (en daarmee diezelfde seinpaal) allang voor een ander transport gebruikt zijn.

Een weg uit deze moeilijkheden is, om de seinpaal niet onder te brengen bij de startopdracht maar bij de KIE van de kernpagina in kwestie. Dit is dan wel safe, maar heeft het nadeel, dat dit wel de nodige geheugenplaatsen zal gaan kosten. Een geprogrammeerde seinpaal kost nl. drie geheugenplaatsen en dit zou dus ongeveer een verdubbeling van de pakweg vijftig KIE's betekenen; dit is des te triester, omdat er normaliter niet meer dan vier van deze seinpalen gebruikt worden.

Wij hebben besloten kool en geit te sparen en de seinpalen, die deze blokkade beheersen, bij de individuele programma's onder te brengen (er op gokkend, dat we aanmerkelijk minder programma's in actie zullen hebben dan kernpagina's). Ieder programma heeft dus zijn eigen seinpaal. Het aanvragen van een heilige kernpagina betekent nu (het = 0 zetten van de eigen seinpaal, als daar het tandenpoetsen niet al voor gezorgd heeft) en het melden aan de trommelorganisatie, via welke seinpaal dit keer de voltooiing van het transport teruggeseind moet worden. Bij de kennisname van de voltooiing van het transport moet nu de "trommelingreepreactor" niet een vaste seinpaal met mogelijk meer dan 1 ophogen, maar een lijstje van seinpalen (mogelijk leeg, mogelijk langer dan 1) moeten allemaal met 1 opgehoogd worden. Daartoe bevatten de eigen seinpalen een schakelelement en bij de startopdracht bevindt zich de beginschakel. En nu zien we, dat de heiligheidsteller bij de PRAECOPIE eigenlijk overbodig is; deze is nl. gelijk aan de lengte van de seinpalenketting, die hangt aan de betrokken startopdracht.

Een wezenlijke veronderstelling, die aan dit laatste arrangement ten grondslag ligt, is, dat per programma de aanvraag van een heilige pagina en de P-operatie op de eigen seinpaal in de tijd elkaar afwisselen: Als je immers eerst de ene bladzijde heilig aanvraagt en dan de ander, en vervolgens 1 P-operatie doet, dan weet je niet meer, welke bladzijde nu gearriveerd is. Dit staat ons tevens toe, de eigen seinpaal slechts in 1 enkele ketting opneembaar te kunnen maken. Mocht, wat ik niet veronderstel, dit "ongenest" gebruik van de eigen seinpaal tot ongewenste restricties leiden, dan kunnen we altijd nog over gaan tot een seinpaal per kernpagina.

4. Coderingen.

Om der wille van de volledigheid zal ik nu beschrijven, welke afspraken wij gemaakt hebben over de wijze, waarop de BZV's en de KIE's de informatie, die ze moeten herbergen, vasthouden. Dit is helemaal niet spannend, de genomen beslissingen zijn soms volslagen willekeurig en als ze dat niet zijn, zijn ze ingegeven door het reinste opportunisme.

4.1. De structuur van de BZV.

Een BZV beslaat 1 woord (met zorg niet meer, omdat we er voor elke bestaande bladzijde eentje in het kerngeheugen moeten invoeren). Een BZV kent vier toestanden.

1) BZVi = -0

Dit zal betekenen "De bladzijde in kwestie is nuchter".

2) BZVi = | d[26] = 1
| d[25] = 0
| d[24] . . . d[0] = beginadres trommelpagina, links aangevuld met nullen

Dit zal betekenen, dat de bladzijde in kwestie niet nuchter is, te vinden is op de aangegeven plaats op de trommel en nergens anders; de bladzijde is tevens niet in een transport betrokken.

3) BZVi =:BKPk (dwz. Basis Kern Pagina nr. k), links aangevuld met nullen.

Dit zal betekenen, dat de bladzijde niet nuchter is, niet in een transport betrokken is, wel op de kernen aanwezig is en wel als

BKPk[0] t/m BKPk[511]

Opm.1.:BKPk zal een 512-voud zijn.
Opm.2. Het basisadres van de bijbehorende KIEk wordt gevonden door

:KIEk =:BPKk / 128 + KPC

(KPC = KIEtabel Positionerings Constante); een KIE beslaat dus vier woorden. Opm.3. Toestand 3 zal gekarakteriseerd zijn door BZVi groter dan 0.

4) BZVi =:BPKk, links aangevuld met nullen)

Dit zal betekenen, dat de bladzijde in een transport betrokken is met betrekking tot kernpagina k.

Opm. Deze toestand onderscheidt zich van 1) doordat BZVi ≠ 0 is en van 2) doordat
        d[25] = 1 is.

Het gevolg van deze conventie's is, dat de vaste aanwezigheid van een bladzijde volledig uit de BZV volgt, zonder raadpleging van de KIE; bij het schrijven op zo'n bladzijde moet wel de KIE geraadpleegd worden om te kijken, of dit schrijven wellicht de overgang van COPIE tot ORIGINEEL ten gevolge heeft. Wij kunnen overwegen, om dit bij toestand 3 in bit d[25] weer te geven; ik voel hier op het ogenblik eigenlijk weinig voor, selectie van een arrayelement is anyhow een aanzienlijk proces en raadplegen van de KIE is nu ook weer niet onoverkomelijk (het testen van zo'n hoger bit kost ook wel wat).

4.2. De structuur van de KIE.

KIEk[0] = | indien gekoppeld aan een BZV, dan | = :BZVi, links aangevuld met nullen
| anders  | = - 0

KIEk[1] = indien trommelverwijzing van toepassing (impliceert onvrij)

     d[26] = 1.
     d[25] = 0
     d[24] . . . d[0] = beginadres trommelpagina, links aangevuld met nullen
anders (dwz. trommelverwijzing niet van toepassing)

 indien onvrij, dan = -0

anders (dwz. indien VRIJ)
     indien laatste pagina uit vrije ketting, dan = +0
     anders =:KIEj (≠ 0), verwijzend naar de KIE van de volgende pagina uit de vrije ketting

KIEk[2] = | als COPIE of ORIGINEEL, dan HHTk (< 128)                  (= 0, 1, 2, 3, . . . .) HHT betekent "Heiligheidsteller".
| als PRAECOPIE, dan 128 + HHTk + 1024 * startopdrachtnummer
| als PRAEVRIJ, dan 256 + 1024 * startopdrachtnummer
| als VRIJ, dan 512.

KIEk[3] = strategische informatie (ook wel interessegetal genoemd).

4.3. Opmerkingen.

Tijdens transport van een bestaande pagina zijn KIEk en BZVi dus aan elkaar gekoppeld, ook als de kernpagina PRAEVRIJ is. Tijdens transport van een niet meer bestaande bladzijde is de kernpagina uit de aard der zaak PRAEVRIJ, KIEk[0] = -0 en ook KIEk[1] = -0. Het vermoorden van een bladzijde, die in een transport betrokken is, heeft nl. toch onmiddellijke vrijgave van de trommelpagina ten gevolge. Dit kan, omdat de trommelorganisatie de transportopdrachten verwerkt in de volgorde van aanbod, elke latere bestemming van deze trommelpagina wordt dus pas effectief, als de eerste transporteerderij volledig afgelopen is.

Wij hebben de kernpagina's niet geinterspatieerd met de bijbehorende KIE's, hoewel dit ons de schuifopdracht voor de herleiding van KIEk tot BKPk of omgekeerd zou besparen. De redenen waren:

mocht ooit een systeem van memory protection zijn intrede doen, dan is het waarschijnlijk, dat een techniek, die kernpagina's op hoge tweemachten laat beginnen, meer aansluit bij wat gebruikelijk wordt

het zou voor testdoeleinden (misschien bedrijven wij aanvankelijk nog wel inspectie) wel eens makkelijk kunnen zijn

de herleiding van physisch adres tot kernpagina en regelnummer in deze pagina wordt aanmerkelijk vergemakkelijkt.

Van het feit, dat de schone schuifopdrachten in een enkel register snel zullen zijn, zullen wij dus dankbaar gebruik maken.

transcribed by Sam Samshuijzen
revised Tue, 18 Jul 2006

EWD86

20 mei 1964

Bezettingsadministratie der trommelpagina's.

Aan elke trommelpagina kennen we twee constanten toe, nl. a en s: dit zijn één-éénduidige functies. De constante a "nummert" de trommelpagina's in volgorde van opklimmend beginadres, de constante s "nummert" de trommelpagina's in de sequens, waarin de beginwoorden van de pagina's de koppen passeren.

Voorlopig stellen we ons op het standpunt, dat de hele trommel voor pagina's ter beschikking staat. (Dit zal niet het geval zijn, maar zulks kunnen we opvangen door een aantal trommelpagina's permanent bezet te verklaren, waarna we ze rustig voor andere doeleinden kunnen gebruiken.)

Als functie van a is het beginadres gegeven door

                               beginadres(a) = 513 * a ;

tussen opeenvolgende trommelpagina's zit dus een ongebruikt woord. Verder geldt

                               0 ≤ a ≤ 1021,

voor a = 1022 en a = 1023 is geen ruimte meer op de trommel. De laatste drie woorden op de trommel worden eveneens niet gebruikt.

Nu merken we op, dat 513 * 513 = 1 mod(1024); alle adressen = mod(1024) zijn tegelijkertijd accessibel. Hieruit volgt, dat verhoging van s met 1 neer komt op verhoging van a met 513, gereduceerd mod(1024).

Voegen we aan de pagina met a = 0 code s = 0 toe, dan vinden (we)

                               a(s) = rem(513 * s, 1024).

Omgekeerd vinden we, dat verhoging van a met 1 de s met 513 verhoogt (modulo 1024)
dus geldt

                               s(a) = rem(513 * a, 1024).

Ook s voldoet primair aan de ongelijkheid 0 ≤ s ≤ 1023; we moeten ons even afvragen welke s-waarden niet voorkomen; dit zijn

          s(1022) = 1022           en

          s(1023) = 511   .

Deze nonexistente bladzijden laten we vrolijk meehobbelen, we zullen ze (zijnde nondisponibel) als permanent bezet noteren.

Voorts is s als functie van het beginadres ten duidelijkste gegeven door

                               s(beginadres) = rem(beginadres, 1024);

alle tot dusverre bekeken functies zijn dus door schoon schuiven over 9 plaatsen, een enkele additie en een collatie met 1023 onmiddellijk uit te rekenen.

Aan deze pagina's gaan we bits toekennen uit een boolean array TBB[0:39, 0:25]; (de afkorting TBB komt van Trommel Bezettings Bits). De bits van dit array gaan we afbeelden op de bits d[25] t/m d[0] van de woorden ven het woordarray TBW[0:39], 40 woorden, in het geheugen te bergen op 40 consecutieve geheugenplaatsen in volgorde van oplopend subscript. Van deze 40 woorden is het tekenbit d[26] permanent gelijk aan 1.

Voor de bits van TBB geldt. dat

a) TBB[i,j] afgebeeld wordt op bit d(25 - j) uit woord TBW[i]

b) TBB[i,j] toegevoegd is aan de trommelpagina met s = 26 * i + j

c) TBB[i,j] = 1 betekent, dat de pagina bezet is
                 = 0 betekent, dat de pagina vrij is.

De bits TBB[19,17] (dwz. s = 511), TBB[39,8] (dwz. s: 1022) en TBB[39, 10], TBB[39, 11]...TBB[39, 25] (dwz. s = 1024, 1025, ..., 1039) zijn wegens nonexistentie permanent = 1, evenals de TBB's, die beantwoorden aan stukken van de trommel, die voor andere doeleinden bestemd zijn.

(In het volgende is de constante B25 = 2↑25 = 33554432.)

We zullen de TBB's op drie manieren gebruiken.

a) Om een bezette trommelpagina met s = 26 * i + j vrij te geven.

In een register plaatsen we B25 * 2↑(-j) en met een subtractieve uitopdracht voeren we uit

               TBW[i]:= TBW[i] - B25 * 2↑(-j).

b) Om een vrije trommelpagina met s = 26 * i + j te bezetten; dit gaat analoog met een additieve uitopdracht:

                      TBW[i]:= TBW[i] + B25 * 2↑(-j).

De weg van beginadres naar s gaat met een simpele collatie, om uit s de i en de j te isoleren, kost ons wel een deling. De tekencijfers van de woorden TBW zijn met zorg =1 gekozen, opdat de preferentie voor de min nul ons geen parten speelt. Als wij deze vrijgave en bezetting additief spelen, den moeten we er wel zeker van zijn, dat de pagina van te voren als bezet, resp. vrij genoteerd stond: anders zou overloop de boel immers hopeloos bederven!

c) Om een geschikte vrije trommelpagina te zoeken. Als we nl. dumpen, dan zijn we vrij in de keuze van de trommelpagina. Als zich in het startmagazijn van de trommeltransporten nog een startopdracht bevindt, dan kunnen we onderzoeken, bij welke waarde waarde van s deze is afgelopen. Vermeerderen we (gereduceerd modulo 1024) deze s met de "safety marge", die Electrologica ons op moet geven, opdat de volgende startopdracht nog zonder verlies van een omwenteling gehaald wordt, dan hebben we de ideale s, ware het niet, dat we nog moeten onderzoeken, of de bijbehorende trommelpagina wel vrij is. (Als er in het startmagazijn van de trommel nog maar 1 startopdracht staat, kunnen we in verband met de minimum tijdsduur van het nu volgende onderzoekprogramma uit voorzichtigheid s nog wel met één of andere constante verhogen, extra wel te verstaan. Als het startmagzijn leeg is, is elke s even goed, want dan hebben we stand van de trommel volledig uit het oog verloren.) Het array TBB gaan we nu gebruiken om de eerste vrije trommelpagina (met "s ≥ s ideaal", alles modulo 1024) te zoeken. Daartoe splitsen we s ideaal in

                       s ideaal = 26 * i + j

en voeren met deze waarden van i en j als beginwaarden het volgende programma uit.

A:= TBW[i];
schuif A schoon over j plaatsen naar links;
if A ≠ 0 then
      begin normeer A (het aantal slagen komt in B);
                 j:= j + B
      end
                        else
      begin i0:= i;
volgend woord: modhoog(i, 40);
                     A:= TBW[i];
                     if A = 0 then begin if i = 10 then goto trommel vol else goto volgend woord
                                           end;
                      normeer A (het aantal slagen komt in B);
                      j := B
      end

De gekozen pagina is nu gegeven door de eindwaarden van i en j (door s = 26 * i + j), waarmee het gestelde doel bereikt is.

transcribed by Gerrit Jan Veltink
revised Sun, 28 Mar 2010

EWD89

8 juni 1864

Over formal locations

(Résumé van de besprekingen van de werkgroep, gehouden op 8 juni 1964)

Het volgende is een résumé, dat ik uit mijn blote hoofd opstel; in hoeverre het waarheidsgetrouw is, kan ik dus niet garanderen.

We hebben bij de kop gevat het geval, dat de formele parameter gespecificeerd is als real of integer. We zullen dit noemen "arithmetic": we hebben nl. besloten de vertaler tussen deze twee specificaties geen onderscheid te laten maken en altijd het type van de actuele parameter — mits natuurlijk real of integer — te laten prevaleren.

De prijs die we bereid zijn te betalen, bestaat zo op het oog uit vrij omvangrijke formal locations en een analyse van de meegegeven actuele parameters bij binnenkomst in de procedure.

Over de omvang van de formal locations: wij komen zo op het eerste gezicht op vier woorden per parameter.

Over de test: wij stellen ons voor, dat de meegegeven actuele parameters getest worden, d.w.z. aan een controle onderworpen worden, die op grond van de specificaties aan gelegd kan worden (wij stellen specificaties verplicht). Tot nog toe hebben wij ons geen zorgen gemaakt over de snelheid, waarmee deze test aangelegd kan worden ("Is het dit, of dat, of dat etc." Als je eerst vraagt naar het meest voorkomende type actuele parameter, dan is het waarschijnlijk nog niet eens zo tijdrovend.)

Wij nemen ons voor om deze acceptabiliteitstest zover door te voeren, dat daarna de tests, die nog dynamisch uitgevoerd moeten worden, een soort van sinecure zijn.

Omdat de type-overgangen speciale complicaties met zich meebrengen, gaan we het daar eerst over hebben.

We stellen ons voor, dat de arithmetiek altijd in het drijvend register F wordt uitgevoerd. (Uitgezonderd misschien n := n + 1 of zoiets doms.)

Om een integer als operand, als primary, in een expressie te betrekken, is dankzij de speciale representatie van drijvende getallen in de X8 geen probleem. Moeilijker is de assignment aan een integer variabele. Dit kan op twee manieren moeiljkheden opleveren: het getal kan niet geheel zijn, het getal kan (na evenetuele afronding!) te groot zijn.

Als F geïntegreerd moet worden, lassen we in het programma in:

| U, A = M[57], Z kop F = 0?
| N, SUBCD(INTEGREER)

waarin de subroutine "INTEGREER" — hiervoor moeten we een kortere naam bedenken — luidt (begint met)

INTEGREER: |       F + AFR                    | AFR = 3 * 2 ↑ 38
|       F - AFR |
| U, A = M[57], Z |
| Y, GOTOR(MC[-1]) → | en terug
| ________________________ | capaciteitsoverschrijding

Opm.
De constante AFR is zo gekozen, dat mits F van te voren niet te groot is (abs. < 2 ↑ 38) de som F + AFR met de binaire komma naaar rechts geechelonneerd staat. En passant verzorgt dan het fatsoen van de rekencursist van de EL-X8 de correcte afronding. Vervolgens wordt AFT er weer afgetrokken. Nu is F in elk geval geheel. F kan nog te groot zijn (veel te groot zelfs); vandaar dat de kop van F weer aan een nultest onderworpen wordt.

Een en ander kost ons in het hoofdprogramma twee opdrachten per integer assignment aan plaatsruimte.

Aan tijd

| in het normale geval (geen afronding nodig): 2 geh. cont
| als transferfunctie nodig (wel afronding): 12 geh. cont. + exces tijd voor drijvende optelling

Ik verwacht, dat afronding zo weinig voorkomt, dat ik er weinig voor voel om — als standaardpraktijk tenminate — ten koste van vier extra opdrachten in het objectprogramma de afronding vier geheugencontacten te versnellen.

| U, A = M[57], 4
| Y, JUMP (4)          →
|      F + AFR
|      F - AFR
| U, A = M[57], Z
| N, GOTO              →           capaciteitsoverschrijding
→ |      --------------

Tot zover het probleem van afronding en range analyse. (In geval van capaciteitsoverschrijding zullen we de plaats waar ook nog wel een beetje moeten aangeven. Daar mogen we later dan over denken)

We keren nu terug tot de formal locations.

Het type van de actuele parameter deert ons, zoals bekend, weinig, wanneer de formele in de expressie-situatie uitgewerkt moet worden. Als hij aan de linkerkant van de assignment voorkomt, treedt er nog meer ellende op, zodra we een multiple assignment hebben. Immers:

als een formele linkerkant in zijn eentje voorkomt, heeft een integer actuele tot gevolg, dat er afgerond kan moeten worden;

als een formele linkerkant, samen met een real linkerkant voorkomt, moet een integer actuele tot gevolg hebben, dat er een foutindicatie gegeven wordt, omdat in een multiple assignment de linkerkanten van hetzelfde type moeten zijn;

als in een multiple assignment alle linkerkanten formeel zijn — dankzij de binnenprocedure kunnen dit formelen van verschillende hoogte zijn! — moet de foutindicatie bij verschillende types gegeven worden, en afronding moet bij (homogeen) integer actuelen ingelost worden.

We hebben dus besloten om de multiple formal assignment voorlopig te laten voor wat hij is, d.w.z. het normale geval niet door het bestaan van de multiple formal assignment te laten vertragen. (We hebben voor de multiple formal assignment wel een oplossing, maar die is dan maar een beetje tijdrovend.)

Vast staat, dat we de assignment aan de nonformele scalar exceptioneel zullen behandelen. Als de vertaler in een scan van links naar recht de assignment statement leest, worden de nonformele scalaire linkerkanten opgezouten en op homogeneiteit van type onderzocht (tezamen met de nonformele subscripted linkerkanten, die van hetzelfde type moeten zijn, maar wel meteen aanleiding tot "programma" geven.)

Als de vertaler het programma gegenereerd heeft, dat de expressie uitrekent in het F-register, test hij, of het verzamelde type van de linkerkant van type integer is, zo ja, dan wordt de integratie ingelast. Vervolgens genereert de vertaler voor elke opgezouten nonformele linkerkant een Mp[q] := F of een Mp[q] := G, afhankelijk van het gevonden type. Tenslotte komen de subscripted left hand sides aan bod. (waarover later vast nog een hele hoop meer). Tot zover was er niets formeel.

Nu gaan we bekijken geval van de single formal assignment.

Hier staat de taal als actuele parameter toe:

1e een real scalar
2e een integer scalar
3e een subscripted real
4e een subscripted integer
5e een formal.

De laatste mogelijkheid confronteert ons echter met niets nieuws, want het meegeven van een reeds formele parameter als actuele is niet meer dan copieren van de formal locations; de laatste mogelijkheid geeft dus geen nieuwe vrijheidsgraad aan de formal locations.

De eerste opmerking is, dat we bij een formele linkerkant eerst deze linkerkant moeten analyseren en zelfe moeten uitwerken, in het geval het een subscripted variable is. De uitwerking van de expressie kan immers als neveneffect hebben, dat de subscript evaluation na afloop andere waarden op zou leveren. (Denk maar aan "R[read] := read".)

Om die reden zullen we de formele linkerkant eerst moeten "uitwerken", d.w.z. indentiteit van de variabele moeten vaststellen. (In geval van meer formele en/of subscripted linkerkanten werken we deze af in volgorde van links naar rechts.

Het uitwerken van een formele linkerkant zal aanleiding geven tot een stapelvulling, onder controle waarvan de waarde van de expressie, wanneer deze eenmal in het F-register gevormd is, zal worden weggenschreven. En het is van deze kant, dat we het systeem opbouwen: eerst stellen we vast, wat een plezierige stapelvulling is, opdat dit wegschrijven vlot en snel zal gaan. Hierna stellen we vast, wat geschikte vullingen van formal locations zijn, om bij de uitwerking van de formele linkerkant deze gewenste stapelvulling tot stand te brengen. De stapelvulling ten gevolge van uitwerking van een formele linkerkant noemen we een "linkerkantwaarde".

Op het moment, dat de wegschrijving moet plaatsvinden, staat de waarde in F en de linkerkantwaarde is het top-element van de stapel.

We zullen voor de verschillende gevallen vershillende gestructueerde linkerkantwaarden moeten introduceren. Deze verschillende structuren zijn echter gekoppeld door de eis, dat de feitelijke assignments moeten geschichten op grond van precies dezelfde indicatie in het (aan de body ontleende) objectprogramma. We kiezen deze indicatie zo, dat

a) | de in beslag genomen ruimte in het objectprogramma niet te groot is
b) | het meest voorkomende geval — actuele een real in de stapel zo vlot mogelijk verwerkt wordt.

Één opdracht in het objectprogramma is kennelijk wel het minimum en we gaan exploreren, wat de gevolgen zijn, als we hiervoor kiezen

"DO(MC[-1])"

d.w.z. een execute op de top van de stapel met impliciete aflaging van het B-register.

We gaan nu na, wat in de verschillende gevallen de aangemeten linkerkantwaarde moet zijn.

1. | Een real op een vast physisch adres "a". Dit doet zich voor als de real een scalar in de stapel is, of een element van een klein array. Bladzijden van grote arrays zullen immers in het algemeen niet op heilige pagina's staan.

1.1.
a < 32768

In dit geval bestaat de linkerkantwaarde uit een enkel woord (bij de weergave van stapels is de stapelbodem boven!):

B - 1: M[a] := F
B : ---------

Tijsduur 4 geheugencontacten.

1.2.
a ≥ 32768
Dit geval, dat zich alleen voordoet als men beschikt over een geheugen, dat groter is dan 32K behandelen we volledigheidshalve wel. We kunnen dan niet volstaan met een linkerkantwaarde van een enkel woord. Dan moet dus b.v. B met meer dan 1 worden afgelaagd, dit kan door het topwoord van de linkerkantwaarde een subroutinesprong te laten zijn. Een mogelijke structuur van de linkerkantwaarde is:

B - 2:             + a
B - 1: SUBCD(:q1)
B      : ----------

Waarbij adres :q1 de entry van het systeem is en wel

q1:
S = MC[-2]
MS[0] = F
GOTOR(MC[0]) ⇒
S := a, B := B - 1
berg
B := B - 1 en terug.

Opm.
Wij vestigen er de aandacht op, dat hier wel een stukje gemeen programmeren wordt weggeven. De DO-operatie laagt eerst B af; de uiteindelijke opdracht blijkt een stapelende subroutinesprong te zijn, die zichzelf met de link overschrijft en B weer met 1 ophoogt. De subroutine bestaat uit drie opdrachten, waarin twee stapelverwijzingen de twee nodige B-aflagingen impliciet bewerkstelligen.

Tijdsduur: 10 geheugencontacten.

2. | Een integer op adres a Ook bij integers kan het geval a < 32768 apart behandeld worden; het verschil is echter gemarkeerd.

2.1.
a < 32768
De structuur van de linkerkantwaarde kan zijn

B - 2 : M[a] = G
B - 1 : SUBCD(:q2)
B       : ----------

Met q2:
U, S = M[57], Z

Y, DO(MC[-2])
Y, GOTOR(MC[)])
     F + AFR
     F - AFR
U, S = M[57], Z
Y, DO(MC[-2])
Y, GOTOR(MC[0])
--------------

→ zonder meer acceptabel

→ na afronding acceptabel
    capaciteitsoverschrijding

Tijdsduur minimaal 9 geheugencontacten.

2.2.
a ≥ 32768
De structuur van de linkerkantwaarde kan zijn:

B - 2 : + a
B - 1 : SUBCD(:q3)
B       : ----------

met q3:
     S = MC[-2]
U, S = M[57], Z
Y, MS[0] = G
Y, GOTOR(MC[0]) → zonder meet acceptabel
      .
      .
      .
      . etc.
      .
      .

Tijdsduur minimaal 10 geheugencontacten.

3.
Een real op een bladzijde
De linkerkantwaarde beslaat weer twee woorden

B - 2 :  pakking van physisch adres van de BZV en regelnummer
B - 1 :  SUBCD(:q4)
B       :  ----------

De wijze, waarop de subroutine, die op :q4 begint toegang heeft tot de gepakte gegevens is na de vorige routines nu wel duidelijk. Wij merken op, dat wanneer het uit tijdsoverwegingen voldoende gunstiger uitkomt, we hier een linkerkant ook wel drie woorden kunnen laten beslaan, door nl. het physisch adres van de BZV en het regelnummer gescheiden, ieder in een eigen woord op te bergen.

4.
Een integer op een bladzijde

B - 2 : pakking van physisch adres van de BZV en regelnummer
B - 1 : SUBCD(:q5)
B       : ----------

De routine, die bij q5 begint, begint (zie 2) af te ronden, en verloopt verder analoog aan die van q4. Ook hier kunnen desgewenst de hier gepakte gegevens in twee aparte woorden geborgen.

Uitwerking van formele variabelen

Wij moeten nu, voor elk type van actuele parameter gaan vaststellen, welke structuur de formal locations zullen vertonen. De formal locations bepalen de actuele parameter, die in het algemeen op twee wijzen kan moeten worden uitgewerkt, nl. als linkerkant en als rechterkant. In het laatste geval stellen we als eis, dat de waarde in het F-register verschijnt, in het eerste geval, dat de linkerkantwaarde, als boven beschreven, aan de stapel wordt toegevoegd.

We gaan uit van vier formal locations, in volgorde van opklimmend geheugenadres beschreven als f[0], f[1], f[2], en f[3]. We spreken af, dat uitwerking als rechterkant in het objectprogramma van de body gecodeerd zal worden als

DOS (f[0])

en uitwerking als linkerkant als

DOS (f[1])

Opm. 1. | De formal locations zullen, als grootheden in de stapel, via de dynamische adressering geadresseerd worden.
Opm. 2. | Het meegeven van een formele parameter als actuele willen we effectueren, door "ongezien" copieren van de formal locations. We moeten er dus voor zorgen, dat de structuur van de formal locations zodanig is, dat ze tegen verplaatsing (nl. copiering elders) bestand zijn.

We volgen nu dezelfde indeling.

1. Een real op een vast physisch adres a

1.1.
a < 32768

f[0] : F = M[a]
f[1] : SUBCD(:q6)
f[2] : M[a] = F
f[3] : voor alsnog ongebruikt.

Opm.
f[3] hebbe wel de goede pariteit in verband met copiering van de formal locations.

De subroutine, die op q6 begint, is even wat gecompliceerd, omdat de link boven op de stapel komt en het juist deze plaats is, die gevuld moet worden. Dit impliceert "redden van de link".

De systeemroutine luidt

q6 :      

G = MS[1]

S = M[B-1]
red link

M[B-1] = G

GOTOR(M[60])      ⇒
terug via S-register.

Tijdsduur voor linkerkantuitwerking: 10 geheugencontacten.

De rechterkantuitwerking spreekt voor zichzelf en duurt 4 geheugencontacten.

1.2.
a ≥ 32768

Volledigheidshalve geven we de formal locations voor een vast gesitueerde real boven de 32 K:
f[0] SUBCD(:q7)
f[1] SUBCD(:q8)
f[2] + a
f[3] SUBCD(:q3)
Hier geeft q8 de systeemroutine aan:

q8 :      

F = MS[1]

S = MC[-1]

MC[0] = F

GOTOR(M[60])

een routine, die grote overeenkomst vertoont met q6; de netto verhoging van B met 1 wordt door - 1 + 2 bewerkstelligd. De tijdsduur voor linkerkantuitwerking is nu 12 geheugencontacten.

De systeemroutine q7 luidt

q7 :      

S = MS[2]

F = MS[0]

GOTOR(MC[-1])

en vergt 10 geheugencontacten.

2. Een integer op een vast physisch adres a

2.1.
a < 32768

f[0] G = M[a]
f[1] SUBCD(:q8)
f[2] M[a] = G
f[3] SUBCD(:q2)

Hierbij wordt dezelfde systeemroutine gebruikt (nl. q8) als in geval 1.2. Uitwerking van een linkerkant kost 12 geheugencontacten, uitwerking van een rechterkant 3

2.2.
a ≥ 32768
Volledigheidshalve geven we dit geval weer
f[0] SUBCD(:q9)
f[1] SUBCD(:q8)
f[2] + a
f[3] SUBCD(:q3)

waarbij q9 (analoog aan q7) luidt

q9 :   

S = MS[2]
G = MS[0]
GOTOR(MC[-1])

Uitwerking van een rechterkant duurt dan 9 geheugencontacten, die van een linkerkant als gebrukelijk 12.

3. Een real op een bladzijde

De actuele parameter is dan een subscripted element. We nemen dat deze gegeven is door een impliciete IS, die (zo ongeveer) het element localiseert in termen van physisch adres van de BZV en regelnummer. Aanwezigheidsanalyse van de bladzijde wordt door de impliciete subroutine nog niet gepleegd.

De impliciete subroutine wordt in de formal locations gekarakteriseerd door een "invariant beginadres". We laten in het midden of hierin de BZV van de pagina gegeven is door zijn physische adres, dan wel door zijn adressering als locale van het buitenste blok (eigen bladzijde) of de bibliotheeklijst. Physisch adres is waarschijnlijk het snelste.

De inhoud van de formal locations is dan

f[0]      SUBCD(q10 of q11)
f[1]      SUBCD(q12 of q13)
f[2]       invariant beginadres implicitie subroutine
f[3]      context D.

Routines q10 en q12 zijn bedoeld voor het geval, dat de IS simpel is, wat o.a. impliceert, dat de pagina van de body niet geprofaneerd hoeft te worden en er in de stapel per definitie voldoende anonieme ruimte zal zijn. In dit geval kan de machinelink als terugadres gehandhaafd worden en hoeft alleen de heersende D aan de terugkeergegevens toegevoegd te worden. Anders (q11 en q13) moet de link in invariant terugkeeradres terugvertaald worden en de pagina van de body geprofaneerd worden.

Onder controle van S hebben deze routines toegang tot de IS en de context D, die ingevuld moet worden om de IS correct te kunnen uitvoeren. Verder moet de bladzijde waar de IS begint heilig aangevraagd worden. (Als hij al heilig aanwezig is, betekent dit al, dat HHT = 2 wordt!)

Na afloop van de IS keert de besturing terug in de systeemroutine. Afhankelijk van linker of rechterkant wordt of alleen de pakking van BZV-adres en regelnummer — door de IS afgeleverd — op de top van de stapel gezet en dit afgedekt met de constante "SUBCD(:q4)" of wordt selectie gepleegd — inclusief aanwezigheidscontrole — en de gevraagde real in F gezet.

4.
Een integer op een bladzijde

De inhoud van de formal locations is dan

f[0]      SUBCD(q14 of q15)
f[1]      SUBCD(q16 of q17)
f[2]      invariant beginadres impliciete subroutine
f[3]      context D.

Deze routines verschillen slechts van de vorige vier, doordat bij linkerkantuitwerking de pakking met "SUBCD(:q5)" wordt afgedekt en bij rechterkantuitwerking alleen het geselecteerde woord in G geplaaatst wordt.

Opm. 1
Zodra we ook "kleine arrays" in de stapel willen toestaan, dan zullen (kunnen) de laatste acht subroutines na terugkeer uit IS inspecteren, of het aangewezen element een van een klein array is. In dat geval is de linkerkantwaarde als van type 1 of 2, de rechterkantwaarde is dan triviaal.

Opm. 2
Deze acht subroutines lijken verdacht veel op elkaar en het ligt dus voor de hand om ze van gemeenschappelijke routines gebruik te laten maken. Men lette erop, dat alle status informatie dan op de stapel moet komen, omdat ze genest en parallel gearchiveerd kunnen worden — d.w.z. door verschillende programma's door elkaar gebruikt kunnen worden.

Hiermede zijn alle actuele parameters, corresponderend met een specificatie arithmetic behandeld voorzover zij een bestaanbare linkerkantwaarde hebben. De overige zijn de constante, de expressie en de arithmetic procedure SS (Self Supporting, d.w.z. een procedure identifier behorend bij een procedure zonder parameter).

Bij binnenkomst in de procedure zullen de formal locations op aanwaaardbaarheid getest moeten worden; hier wordt niet getest, of een arithmetic actual ook inderdaad een linkerkantwaarde heeft. Daarom zullen wij deze formal locations (met name f[1]) zo vullen, dat als de body probeert, hun linkerkantwaarde uit te werken, dit alsnog tot protest aanleiding geeft.

5.
De real constante

f[0]
f[1]
F = MS[2] 
Alarmsprong

f[2]    ⎱
f[3]    ⎰
 waarde van de constante

Tijdsduur rechterkantuitwerking: 4 geheugencontacten.

6.
De integer constante

(Dit is misschien een beetje te veel eer!)

f[0]
f[1]
f[2]
f[3]
G = MS[3]
Alarmsprong
invariant beginadres impliciete subroutine
waarde integer constante

Tijdsduur rechterkantuitwerking: 3 geheugencontacten.

7.
De arithmetische expressie

f[0]
f[1]
f[2]
f[3]
SUBCD(q18 of q19)
Alarmsprong
invariant beginadres impliciete subroutine
context D.

Het onderscheid tussen de systeemroutines q18 of q19 is weer of de impliciete subroutine simpel is of niet.

8.
De enkele type procedure identifier, die als expressie op mag treden

De inhoud van de formal location wordt, zodra we goed en wel ons in de body befinden

f[0]
f[1]
f[2]
f[3]
SUBCD(:q20)
Alarmsprong
invariant beginadres van de procedure
context D

De moeilijkheid hier is, dat de procedure ook expliciet als procedure aangeroepen kan worden. Nu stellen wij one voor om bij de call de formal locations van de parameters te vullen, vervolgens dit aantal mee te geven en dan naar de (nog "ongeziene") procedure te springen, die begint te testen of het aantal meegegeven parameters correct is. De body van de procedure zonder parameters begint dus te testen of hij inderdaad geen parameters heeft meegekregen.

De functie van de systeemroutine q20 is om het stukje calling sequence behelzends "nulparameters" dynamisch in te lassen, voordat volgens alle regels van de kunst de procedure geactiveerd wordt.

De formal location vulling met SUBCD(:q20) kan echter slechts op twee manieren to stand komen

1e Door een arithmetic formal parameter — waarbij de actuele een procedure identifier was — als actuele parameter door te geven. Doorgeven is immers copieren van de formal locations.

2e Door een arithmetic procedure identifier als actuele parameter mee te geven, waar de formele als arithmetic gespecificeerd blijkt te zijn. Het meegeven van een procedure identifier als actuele parameter geschiedt door te vertaler:

1e   | zonder bewustzijn van het aantal parameters, dat deze procedure vergt
2e   | zonder bewustzijn of de overeenkomstige formele als procedure of als arithmetic gespecificeerd is.

Als de formele als procedure gespecificeerd is, dan inspecteert de body de formal locations om te kijken of er een procedure van het goede type is meegegeven. Bij gebruik van deze als procedure gespecificeerde parameter zal de callside het feitelijk aantal parameters (kan = 0 zijn) expliciet aangeven.

Als de formele parameter als arithmetic gespecificeerd is, dan wordt als overeenkomstige actuele een procedure identifier van het goede type geaccepteerd, maar de formal locations worden gewijzigd door de invulling van "SUBCD(:q20)" in f[0]. Dit proces vindt plaats ongeacht het aantal parameters, dat de meegegeven procedure graag zou willen hebben. Bij dynamisch gebruik wordt dit in de procedure getest; q20 zorgt nl. voor expliciete meegave van "nulparameters". (Ook dan hoeft de Alarmsprong pas in de formal location ingevuld te worden: bij een procedure, die als zodanig gespecificeerd is, is een alarmsprong immers een open deur!)

transcribed by Carl Ludwigson
revised Thu, 4 Nov 2010

  EWD 91

Samenvatting van oordeel over het "Voorstel tot aanschaffing van een digitale informatieverwerkende machine voor de afdeling der elektrotechniek".

De motivering stelt wel de behoefte aan beschikking over digitale apparatuur, maar laat na aan te tonen, dat deze behoefte niet door de reeds door de THE bestelde machine bevredigd zal kunnen worden en dat dus de aanschaf van een extra machine gerechtvaardigd is.

De motivering noemt wel een aantal toepassingsgebieden, waar een digitale machine bij ingeschakeld zou kunnen worden, maar geeft geen helder beeld van de daaruit voortvloeiende eisen, aan deze machine te stellen. In plaats daarvan bevat het voorstel een lijst van acht deugden van de voorgestelde machine, een IBM 360. Bij nadere inspectie vragen ten minste zes van deze acht wel om enige relativering.

De voorgestelde machine is conventioneel. Door een nodeloze explicietheid van de opdrachtcode deelt zij met haar voorgangers in onverminderde mate de onaangename eigenschap van "onprogrammeerbaarheid", zoals ook blijkt uit de mate, waarin vertaaltijden voor in alogorithmische talen geschreven programma's ten gevolge van optimalisatiepogingen gegroeid zijn. In uniprogrammering zijn deze optimalisatiepogingen al gebrekkig, in multiprogrammering, waar tijdens vertaling van een individueel programma de omstandigheden, waaronder dit programma later zal werken, zoveel minder bekend zijn, zijn ze nog heillozer.

Dit, en de beperkte middelen, waarmee de onderlinge synchronisatie tussen geprogrammeerde en zich buiten de centrale rekeneenheid afspelende processen geregeld moet worden, versterken mijn indruk, dat de ontwerpers zich onvoldoende bewust zijn geweest van de consequenties, die de veranderde werkomstandigheden met zich meebrengen. Zijn geschiktheid voor multiprogrammering en procescontrole - twee nauw verbonden doelstellingen - acht ik dan ook niet overtuigend : hij zal er met pijn en moeite, en mits men met niet te veel al tevreden is, wel voor gebruikt kunnen worden.

De in het voorstel geschatte personeelsformatie van slechts vier man komt mij hierom optimistich voor. Bij deze schatting gaat de afdeling er van uit "dat een toenemend aantal medewerkers zelf zal kunnen programmeren". Wanneer dit gaat impliceren -en daar ben ik bang voor- dat een toenemend aantal medewerkers hun tijd zal moeten besteden aan de toch irrelevante problemen, die rijzen, wanneer men een stuk gereedschap wil inzetten voor taken, waarvoor het eigenlijk niet het adequate stuk gereedschap genoemd kan worden, dan wil ik hierbij opmerken, dat ik uit educatieve overwegingen hier ernstige bezwaren tegen zou koesteren.

Tenslotte: de eigenschappen van de arithmetiek met drijvende komma tarten, zoals dat heet, elke beschrijving. Ik heb nochtans deze uitdaging niet onbeantwoord kunnen laten.

15 juni 1964                                                        E.W.Dijkstra

Aan de hooggeleerde heer
prof. dr.ir.A.A.Th.M.van Trier
voorzitter-beheerder van de
afdeling der electrotechniek

Zeer geachte Collega,

aan Uw namens de afdeling der electrotechniek tot mij gerichte verzoek mijn oordeel te geven over het "Voorstel tot aanschaffing van een digitale informatie-verwerkende machine voor de afdeling der electrotechniek" voldoe ik volgaarne.

Mijn commentaar spruit voornamelijk voort uit een confrontatie van de in dit voorstel gegeven motivering met de gedane keuze. Wanneer ik tot de conclusie kom, dat de gegeven motivering weinig overtuigend is - een conclusie, waartoe het College van Curatoren dan dus ook zou kunnen komen -, dan verzoek ik U, ter voorkoming van misverstand, U er wel van bewust te zijn, dat dit niet hoeft te impliceren, dat ik tegen een effectuering van de voorgestelde aanschaffingen gekant zou zijn.

Het voorstel begint met een beroep op het inrichtingsplan van 18 juni 1963 van de groep Telecommunicatie-B, waarin gesteld wordt, dat "de afdeling der electrotechniek .... op een nader te bepalen tijdstip de beschikking (zal) moeten hebben over een digitale rekenmachine, die geschikt is voor besturingsfuncties.".

Na dit citaat vervolgt het voorstel met "Thans is de meningsvorming binnen de afdeling der electrotechniek zover gevorderd, dat U een concreet voorstel kan worden gedaan tot aanschaffing van.....etc.etc.", waarbij stilzwijgend ervan is uitgegaan, dat de behoefte, die met "de beschikking hebben over" is aangeduid, het beste door een nieuw aan te schaffen apparaat kan worden bevredigd. Zo rijst onmiddelijk de in het voorstel onaangeroerde vraag, in hoeverre de behoeften van de afdeling der electrotechniek mettertijd bevredigd zou kunnen worden onder gebruikmaking van de reeds door de THE bestelde digitale apparatuur. Van de daaropvolgende uitspraak uit het voorstel : "daarnaast hebben ook andere groepen van de afdeling er belang bij, dat over digitale apparatuur kan worden beschikt" zou ik dan ook willen opmerken, dat hij zonder nadere specificatie niet als argument kan dienen en daarom in deze vorm mij als misplaatst voorkomt.

In de volgende passage, lopend van "Bij het ontwerp van electrotechnische systemen...." (pagina 1, regel 14 van onderen) tot en met "...niet meer adequaat worden uitgevoerd." (pagina 2, regel 19 van boven) hoor ikeen lofzang op de general purpose rekenautomaat, die mij uit de aard der zaak als muziek in de oren klinkt. Maar ook deze uitspraak treft mij meer als een bevestiging van de toekomstverwachtingen, die vorig jaar geleid hebben tot de bestelling van een grote rekenautomaat, dan als een deugdelijke motivering voor de aanschaf van nog een nieuwe machine !

Het voorstel vervolgt echter met : "De afdeling meent - en zij wordt in deze mening gesteund door anderen en ervaringen van elders - dat van de aanwezigheid van een digitale machine van bescheiden omvang een zeer stimulerende invloed zal uitgaan op wetenschappelijk onderzoek en ontwikkelingswerk." Deze alinea, die de stap van "beschikken over" tot "aanschaf" zou moeten rechtvaardigen, is om diverse redenen nogal zwak. "De afdeling meent"..... en dan komt er niet, wat je zou verwachten, nl. een bondige aanduiding op grond waarvan de afdeling deze mening koestert, maar... een anonieme verwijzing naar anderen en ervaringen van elders, alsof de afdeling in de gefundeerdheid van haar eigen mening onvoldoende vertrouwen heeft. (Waarom immers anders dit beroep op anderen ?). Er is nog een reden, waarom dit beroep op elders beter weg had kunnen blijven. Het gaat immers uit van de veronderstelling, dat de situatie zoals die zich in het verleden elders heeft voorgedaan, voldoende overeenkomst met de toekomstige situatie aan de THE zal vertonen, een prognose, waarvan ik vurig hoop, dat zij onjuist zal blijken ! (Uit het verzoek van de onderafdeling der wiskunde, gedaan in de "Letter to the Manufacturers" om de offerten zo mogelijk niet tot de toen reeds gangbare marktartikelen te beperken, bleek wel, dat zij met die gangbare marktartikelen niet onverdeeld ingenomen was, met name omdat zij zich voorstelde een gevarieerdere en zo nodig promptere service te leveren, dan daarmee mogelijk was gebleken. Dit streven van de onderafdeling der wiskunde heeft nog niets in kracht ingeboet en het is dan ook wat moeilijk om in Uw beroep op ervaringen van elders een blijk, zo niet van wantrouwen, dan toch wel van twijfel ten aanzien van dit streven te proeven.)

Tot zover de eerste twee regels van deze alinea ; ook de er in uitgesproken mening werpt een aanzienlijk vraagteken op. Uit het voorkomen van de nadere bepaling "van bescheiden omvang" valt wel te concluderen, dat de afdeling der electrotechniek de mate, waarin de aanwezigheid van een digitale machine wetenschappelijk onderzoek stimuleert, afhankelijk stelt van de omvang van deze machine, maar de lezer blijft geheel in het ongewisse over de aard van deze afhankelijkheid. Is de afdeling reeds geholpen met een machine van bescheiden omvang, maar zou zij met een grotere machine beter gebaat zijn, of is in haar toepassingen de bescheidenheid van de omvang der installatie juist een essentiele deugd ? Beide mogelijkheden zijn denkbaar,

Ook de volgende alinea vraagt om ophelderingen. Ten gunste van de IBM 360 wordt gezegd "dat dit systeem het resultaat is van een zeer geavanceerde ontwikkeling, zowel op technologisch gebied als op het gebied van de beginselen van informatieverwerking, die erin zijn toegepast." De beoordeling van de technologische merites - waarvan ik volgaarne aanneem, dat zij zeer groot zijn - valt buiten mijn competentie ; wanneer "de beginselen van informatieverwerking, die erin zijn toegepast" geacht kunnen worden terug te vinden te zijn in de manier, waarop de machine zich aan de programmeur voordoet, dan vraag ik mij in de eerste plaats af, welke deze beginselen dan wel zijn, en in de tweede plaats, waaraan zij dan wel het epitheton ornans "resultaat van een zeer geavanceerde ontwikkeling" - voorwaar geen zwakke term ! - aan mogen ontlenen. Bij de bestudering van "IBM System/360 Principles of Operation, form A22-6821-0" kreeg ik nl. niet de indruk van een moderne machine, integendeel. De voorstelling van zaken, dat het hier gaat om het resultaat van een zeer geavanceerde ontwikkeling acht ik, voorzover het de niet-technologische aspecten betreft, dan ook volledig misplaatst : zij treft mij meer als het product - en daarmee onderdeel - van een mythevorming, dat het hier om een achtste wereldwonder zou gaan, dan als een weloverwogen oordeel, getoetst aan de critische maatstaven een Nederlandse instelling van hoger onderwijs waardig.

Ten aanzien van de in het voorstel genoemde voordelen het volgende.

ad 1) "grote snelheid waarmee de logische handelingen worden uitgevoerd".

Aangezien deze snelheid, als ik het goed begrepen heb, van model tot model sterk verschilt, is dit argument meer van toepassing, naarmate Uw afdeling de aanschaf van een snellere versie voorstelt. Welke versie Uw afdeling op het oog heeft staat in het voorstel merkwaardigerwijs niet vermeld. Uit de prijsopgave meen ik te mogen opmaken, dat U het oog heeft laten vallen op een van de langzaamste versies, wat ik ervaar als een verzwakking van dit argument. Onafhankelijk daarvan zij opgemerkt, dat de snelheid voor alle versies voor een niet onbelangrijk gedeelte te niet gedaan wordt door onbeholpenheid van de opdrachtcode. Het feit, dat het merendeel der opdrachten de zg. Condition Code onherroepelijk wel of niet zet, terwijl alleen de sprongopdrachten op de zetting vann deze condition code kunnen reageren, eist in dit opzicht een zware tol.

ad 2) "de mogelijkheid meerdere programma's gelijktijdig uit te voeren".

Terzijde zij ten eerste opgemerkt, dat het woord "gelijktijdig" de werkelijke gang van zaken te gunstig voorstelt, aangezien de Centrale Processing Unit op elk moment maar met 1 (en indien door communicatie geblokkeerd, met geen enkel) programma actief bezig is.

Om tot de kern van dit punt te komen : het is sinds jaar en dag bekend, dat de mogelijkheid tot interruptie een nodige voorwaarde is om een soepel werkend systeem voor multiprogrammering te realiseren, het is, eveneens sinds jaar en dag, bekend, dat de mogelijkheid tot interruptie opzichzelf een onvoldoende voorwaarde is om de potentiele vruchten van multiprogrammering metterdaad te plukken. Het genoemde IBM-document is hier, dacht ik, wel wat misleidend ; ik citeer "By storing the current PSW (=Program Status Word) during an interruption the state of the CPU can be preserved...." (pg.15, rechterkolom, 5de regel van onder) en "If, at the conclusion of the interruption routine, there is an instruction to make the old PSW the current PSW the system is restored to the state prior to the interruption and the interrupted routine continues." (pg.16, linkerkolom, 5de regel van onder). Helaas is overschakelen van het ene programma naar het andere een aanmerkelijk omvangrijkere taak, aangezien de CPU is uitgerust met 16 enkelwoords- en 4 dubbelwoordsregisters, zodat 96 bytes gered moeten worden, voordat het andere programma kan doorgaan. (Ik ga er op dit moment aan voorbij, dat ook in uniprogrammering de aanwezigheid van een dergelijk groot aantal onderling gelijkwaardige speciale registers niet een onvermengde zegen is : zodra men probeert ze te gebruiken, blijkt het een tweesnijdend zwaard te zijn.) Voorts is het, om de vruchten van multiprogrammering te kunnen plukken, wel wenselijk, dat programma's herplaatsbaar zijn, en wel herplaatsbaar in een wat sterkere zin, dan waarin door deze machine voorzien wordt. Bij punt 7 kom ik hier op terug.

ad 3) "ruime en flexibele communicatiemogelijkheden".

Het is in dit verband speciaal het multiplexor channel, dat fascinerende mogelijkheden schijnt te bieden. Hoe bruikbaar het is, hangt echter af van nadere specificaties, die ik in het geciteerde IBM-document niet heb kunnen vinden. Mondeling is mij meegedeeld - of dit juist is, zou geverifieerd kunnen worden - dat in geval van congestie over het multiplexor channel bij niet stopbare inputapparaten informatie verloren gaat. En congestie is (zie de zg. burst mode) geen exceptie. De eerste vraag is of de CPU kan controleren, dat zulk informatie verlies niet is opgetreden. De tweede vraag is : wanneer er wel stopbare inputapparaten aan het multiplexor channel gekoppeld zijn, kan dan de terugkoppeling tussen channel en apparaat gerealiseerd worden, die in het geval van congestie in het kanaal het apparaat stopt ? Indien niet beide vragen bevestigend beantwoord worden, lijkt mij de bruikbaarheid van het multiplexor channel ernstig geschaad.

Voorts heeft het mij bij het multiplexor channel bevreemd, dat de interrupties van dit kanaal, hoewel er een groot aantal onderling asynchrone apparaten via dit kanaal kan worden aangesloten, tesamen slechts met ÈÈn enkel zg. "mask bit" tegengehouden, dan wel toegelaten worden. De mask bits zijn immers een mogelijkheid om selectief op interrupties te reageren, men zou ze bv. willen gebruiken om tijdens de behandeling van interrupties van gemiddelde prioriteit de CPU wel af te schermen tegen interrupties van lagere, maar niet tegen interrupties van hogere prioriteit. Als nu aan het multiplexor channel maar 1 apparaat zit, waarvan met de interruptie met hoge prioriteit wil honoreren, terwijl de overige interrupties via het multiplexor channel niet de minste haast hebben, dan zie ik hier een conflictsituatie ontstaan.

Bij de selector channels, die voor zover het informatietransport betreft, sequentieel bedreven worden, doet zich deze moeilijkheid niet voor. Hier is echter de vraag of de "command chaining" het soulaas brengt, dat ermee beoogd wordt. Twee vragen zijn bij mij gerezen, waarop ik in de mij ter beschikking staande documentatie het antwoord niet heb kunnen vinden. Indien aan een selector channel een ketting commands is gegeven en het kanaal is met de uitvoering van deze ketting begonnen, kan dan deze ketting nog met nieuwe schakels uitgebreid worden, maw. kunnen de commands continue toegevoerd worden ? Als dit niet het geval is - en daar ben ik een beetje bang voor - zou ik ernstig teleurgesteld zijn. De tweede vraag, die rijst, betreft de PCI-flag (Program Controlled Interruption), die in een CCW (Channel Command Word) mag voorkomen. Indien in een keten van commands meer dan 1 CCW de PCI-flag bevat, is het dus mogelijk, dat de tweede "interrupt condition" ontstaat, voordat de eerste gehonoreerd is. Het geciteerde document (pag 100, rechterkolom, regel 18 van boven) vervolgt : "The PCI-conditions are not stacked ; that is, if another CCW is fetched with a PCI-flag before the interruption due to the PCI-flag of the previous CCW has occurred, only one interruption takes place." Mijn vraag is, of de CPU kan achterhalen, dat deze ene interruptie voor twee (of meer) telt ; zo nee, dan lijkt me de faciliteit zo goed als onbruikbaar.

ad 4) "directe toegang tot het kerngeheugen, capaciteit van het kerngeheugen, mogelijkheid van bescherming van delen van het kerngeheugen".

In hoeverre "directe toegang tot het kerngeheugen" na punt 3 nog iets nieuws toevoegt, ontgaat mij. Hoe men "capaciteit van het kerngeheugen" als facet kan noemen, ontgaat mij eveneens : elk kerngeheugenheeft een zekere capaciteit ! De voorgestelde aanschaf omvat een kerngeheugen van "16000 tekens" (hiermee is bedoeld "16384 bytes" ?). Betekent de speciale vermelding "capaciteit van het kerngeheugen" dat de onderafdeling der electrotechniek haar keuze op de IBM 360 heeft laten vallen omdat deze leverbaar was met een geheugen van deze, door haar ideaal geachte omvang ? Of is hier eigen-omvang" bedoeld en houdt de afdeling reeds thans ernstig met de mogelijkheid rekening, dat de voorgestelde aanschaf in een later stadium als "stepping stone" (of in goed Nederlands : "als hefboom") tot een grotere installatie zal fungeren. In het voorstel zou wat grotere klaarheid in dit opzicht dunkt me wel gewenst zijn ; ik stel me zo voor, dat ook het College van Curatoren wel zal willen weten, of deze aanschaf beschouwd moet worden als hoofdzakelijk een eenmalige investering, dan wel of het met de fiattering van deze aanschaf zich voor latere jaren de (misschien kostbare) plicht tot uitbouw van de installatie op de hals heeft gehaald.

Ten aanzien van de genoemde "mogelijkheid van bescherming van delen ven het kerngeheugen" (mogelijkheid tot bescherming van informatie in delen van het kerngeheugen geeft het iets duidelijker weer) wil ik graag beginnen met de opmerking, dat ik de wijze, waarop dit in de IBM 360 met behulp van de zg. "Protection Key" gerealiseerd is, de leukste manier vindt, die ik ooit gezien heb. Het feit, dat deze methode met drastische uitbreiding van het kerngeheugen verenigbaar is weegt ongetwijfeld zwaarder dan de er uit voortvloeiende beperking, dat het aantal ten opzichte van elkaar beschermde processen aan een bovengrens van 15 gebonden is. Mijn appreciatie voor de wijze van verwezenlijking neemt niet weg, dat ik van de bruikbaarheid maar weinig overtuigd ben. Ten eerste gaat de geheugenbescherming in eenheden van 2048 bytes, met een slechts acht maal zo groot geheugen een tamelijk grove "korrel". Ten tweede - en dit is een aspect, waardoor de machine me als ouderwets treft - beoogt de geheugenbescherming om de ene programmmeur te beschermen tegen de fouten van een ander. Het is veel belangrijker dat de programmeur beschermd wordt tegen de fouten van zichzelf ; met de controle, dat hij anderen gehinderd heeft, is hij zelf heel weinig gebaat, zolang hij nog onbedoeld zijn programma kan hebben overschreven, in zijn getallenmateriaal kan springen etc. Indien van elke geheugenselectie vaststaat, dat hij heeft plaatsgevonden binnen de (deel)informatie-eenheid in kwestie, impliceert dit a fortiori, dat de programmeur anderen niet gehinderd heeft en de ingebouwde geheugenbescherming, die zich beperkt to uitsluiting van interferentie tussen programma's, komt niet eens meer aan bod. Het feit, dat de "Protection Feature" facultatief is, is voor mij, gezien de repercussies van zijn aanwezigheid (nl. niet meer homogeen geheugen) een groot raadsel.

ad 5) "Schijven-geheugen van grote capaciteit".

Behalve de opmerking, dat de combinatie van capaciteit, nog gehaalde accesstijden en prijs mij treft als een indrukwekkende prestatie, geen commentaar.

ad 6) "automatische correctie van tijdelijk machinefouten".

Dit suggereert mij, dat de machine incidentele fouten automatisch corrigeert, en wel allemaal, feilloos en onder alle omstandigheden. Als dit waar zou zijn, ben ik benieuwd te vernemen, hoe dit in zijn werk gaat. Ik kan het me nl. bv. moeilijk voorstellen welke correctieprocedure zonder speciale voorzorgen in de programma's in staat is de juiste waarde van een willekeurige byte te reconstrueren, wanneer deze abusievelijk onjuiste pariteit zou blijken te bezitten. Bij een lezing over de IBM 360 kreeg ik veel meer de indruk, dat hier in de eerste plaats sprake was van een diagnostisch hulpmiddel bij de localisatie van fouten en dat slechts in bijzondere omstandigheden correctie mogelijk is. Voorts spreekt de mij ter beschikking staande documentatie wel over pariteitsbits, maar bv. nergens over een zichzelf controlerende arithmetiek. Als inderdaad feilloze correctie van alle enkelvoudig optredende tijdelijke machinefouten niet onder alle omstandigheden gegarandeerd kan worden, moet ik U verzoeken de mogelijkheden van de zg. "machine check" iets genuanceerder te omschrijven.

ad 7) "mogelijkheid van programma herplaatsing".

Het betreft hier de weinig interessante mogelijkheid de definitieve plaats van een programma pas te beslissen op het moment, dat het programma in het geheugen wordt opgenomen, zonder dat deze beslissing bijwerking van de adressen in de (binaire) programmatext vergt. Dit is alleen van interesse, wanneer men de binaire text, los van hun uitvoering, een zelfstandig bestaan laat leiden, dwz. wanneer men van "Load and Go" geen standaardpraktijk kan maken. Als dit zo is - en bij geruchte heb ik vernomen, dat in de begeleidende software het concept van geprecompileerde programma(gedeelte)s nog steeds is gehandhaafd - is dit een veeg teken ten aanzien van de (automatische) programmeerbaarheid van de machine (wat, gezien het grote aantal expliciet benoemde registers, minder een verrassing dan wel een bevestiging van een reeds gekoesterd bang vermoeden is).

Veel erger is, dat datgene, dat met "mogelijkheid van programma herplaatsing" wel gesuggereerd wordt en in multiprogrammering absoluut noodzakelijk is, wil men het kerngeheugen enigermate efficient gebruiken, in de IBM 360 in het algemeen niet mogelijk is : is eenmaal de plaats, die een programma en zijn onderdelen in het kerngeheugen zullen innemen, gekozen, dan is tijdens de uitvoering van dit programma deze keuze niet meer herroepbaar. Door dit ernstig gebrek aan flexibiliteit - dat o.a. impliceert, dat bij elk programma van te voren een majorant opgegeven moet worden van de maximale geheugenbehoefte, zoals die in de loop van de uitvoering misschien maar even optreedt - krijgt men de hele rompslomp van "job scheduling" (en waarschijnlijk ook van segmentering) weer opgedrongen en gaat een belangrijk deel van de potentiele charmes van multiprogrammering verloren. De IBM 360 presenteert zich in dit opzicht als een uiterst conventionele machine met alle nadelen van dien.

ad 8) "relatief lage prijs".

Als - dankzij de revolutionaire fabricagetechnieken - de prijs in verhouding tot "het informatieverwerkend vermogen" vergeleken bij vroeger inderdaad significant gedaald is, dan geeft dit ernstig te denken. Tot voor kort beschreef de afdeling der electrotechniek haar behoeften in termen van een (conventioneel) geconstrueerde machine van circa f500 000,--. Nu doet zij plotseling het voorstel tot aanschaffing van een machine, die meer dan anderhalf maal zo duur is, en bovendien relatief goedkoop zou zijn. Over deze plotselinge, zeg, verdubbeling van de behoefte aan beschikking over digitale apparatuur rept het voorstel met geen woord, hoewel dit voor een ieder, die enigszins met de voorgeschiedenis op de hoogte is, toch wel een vreemde zaak moet zijn.

Ten aanzien van de in sectie 3 van het voorstel opgesomde toepassingsgebieden zou ik het volgende willen opmerken. Over de aard en omvang van de hieruit voortvloeiende machinebelasting is - althans voor een buitenstaander als ik - moeilijk een beeld te vormen ; het wordt daardoor weinig duidelijk, dat de machine, die de THE reeds in bestelling heeft, niet als het hiervoor aangewezen stuk gereedschap beschouwd moet worden. De indruk van de toepasbaarheid van deze laatste machine wordt nl. door de "lofzang" alleen nog maar versterkt.

Tenslotte : een in dit voorstel slechts terloops genoemde faciliteit, nl. de drijvende komma faciliteit, vraagt wel om enig commentaar.

1. Door de krapte aan bits in de enkelwoords drijvende arithmetiek is deze nauwelijks interessant : er is een compromis uit de bus gekomen, waarin zowel het bereik, als de relatieve preciesie nog kleiner zijn dan bv. in de IBM 1620.

2. Zodra men op dubbele lengte overgaat komen alle bits van het tweede woord aan de mantisse ten goede, maaar het te kleine exponentbereik blijft onverminderd als bezwaar kleven.

3. De representatie van de drijvende getallen is zo gekozen, dat de uitwerking van de transferfuncties van en naar vaste komma representatie (vooral in de ene richting) nodeloos ingewikkeld zijn.

4. Een en ander wordt nog versterkt, doordat de communicatie tussen de registers met drijvende en die met vaste komma slechts via het geheugen mogelijk is.

5. Met het oog op de byte-scandering hebben de ontwerpers zich laten verleiden, om de exponent op basis 16 te betrekken. Hierdoor fluctueert de relatieve prciesie, waarmee getallen gerepresenteerd kunnen worden, een factor 16. Een van de grootste voordelen van de drijvende binaire komma (waar deze fluctuatie slechts een factor 2 is) is hiermee verloren gegaan. Het numerieke ongerief van de drijvende decimale komma is in de IBM 360 dus nog een keer versterkt !

6. De opdrachtcode bevat opdrachten, die hun drijvende resultaat niet "nanormeren". Indien deze ingevoerd zijn in de gedachte, dat hiermee een preciesiecontrole kan worden uitgevoerd, dan berust dit op een vergissing (zie bv. Wilkinson). Indien zij ingevoerd zijn met snelheidswinst als oogmerk (de niet na-normerende opdrachten kunnen nl. sneller uitgevoerd worden), dan hebben de ontwerpers zich hier "pound foolish and penny wise" betoond. De non-unieke getalvoorstelling zal elders nl. een aanzienlijke prijs vergen : in de drijvende arithmetiek, die nu ook ongenormeerde getallen als operand moet accepteren - deze prijs kan klein zijn - maar zeker, doordat de kans op prgrammafouten hierdoor aanzienlijk gestegen is.

7. De arithmische bewerkingen op drijvende getallen leveren niet een fatsoenlijk afgerond resultaat, maar een domweg afgekapt. 8. Doordat negatieve getallen in het zg. tweecomplementensysteem gerepresenteerd worden, leidt dit afkappen voor positieve getallen tot verkleining, voor negatieve getalen tot vergroting van de absolute waarde. Elementaire relaties als

- (a * b) = (-a) * b

zijn in deze onreine arithmetiek dus niet meer gewaarborgd. Over de commutatieviteit van de vermenigvuldiging en de optelling zwijgt de documentatie......

Kortom, de drijvende arithmetiek van de IBM 360 is een sprekend voorbeeld van het soort wanproduct, dat een ongebreideld opportunisme pleegt voort te brengen.

Dit, waarde collega, was mijn commentaar op het voorstel. De tijd heeft mij ontbroken om kort te zijn ; voor de lengte van dit commentaar bied ik mijn verontschuldigingen aan.

Met collegiale groeten,

Uw

E.W.Dijkstra

transcribed by Sam Samshuijzen
revised Sun, 19 Dec 2004

EWD96-0

August 21, 1964

Embedding complex arithmetic

The following is an effort to please ALGOL users, more than to please language designers. It is an answer to the undeniable fact that those, who should like to work extensively with complex numbers will find it hard to use ALGOL 60, and for two reasons: it is hard to express the computing process, and after having done so, it becomes equally hard for the computer.

Those who are crying for the inclusion of complex arithmetic will therefore be helped greatly by any reasonable effort in this direction, even if it has some deficiencies and lack of elegance. Those who do not care, being happy with real numbers, should not protest on account of the deficiencies as long as their non-complex programs are processed as efficiently as before.
This, therefore will be my guiding principle: to introduce complex numbers and complex arithmetic in such a way that, whenever a price in efficiency has to be paid, this price will be paid in the program using the complex numbers. (This with usual machines and implementation techniques in mind.)

Complex variables

With the character "complex", followed by an identifierlist, we can declare a number of complex variables at the beginning of a block. A complex variable will be represented by its real and imaginary part, both as reals, i.e. not e.q. in argument and modulus. (This is of arithmetic importance, because now the "resolving power" in the complex plane has been coupled in a rigid way to that one on the real axis.)

Remark. The complex variable will be declared with the single character "complex" and not by means of "complex real". The reason is that I do not intend to cater for "complex integer".

Complex arrays

They will be declared by "complex array" and will consist of an array of complex variables, just as "real array" introduces one or more arrays of real variable.

Complex procedures

They will be declared by "complex procedure" analogous to the way in which real procedures are declared by "real procedure". When used as a function designator, they represent a complex primary. The library will contain at least one complex procedure, for which I propose the reservation of the identifier "com"

complex procedure com (u,v); value u,v; real u,v;

Its value will be the complex number with the values of u and v as its real and imaginary parts respectively.

EWD96-1

Complex formal parameters

The specification "complex", "complex array", "complex procedure" are added. The library will contain at least two complex procedures for which I propose to reserve the identifiers "re" and "im".

real procedure re(z); value z; complex z;

real procedure im(z); value z; complex z;

When used as a function designator they have the value of the real and imaginary part, respectively, of the value of the actual parameter. Due to the representation we can state for any complex variable z

z = com(re(z), im(z)).

A formal parameter specified "complex", may occur in the value list. If a formal parameter specified "complex array" is also allowed in the value list. I can hardly blame implementers if they do not cater for it. (We should bear in mind that the intention of this proposal is to provide something what is asked for.

The more difficult decisions to take are concerned with

What transfer functions to invoke automatically

The semantics of expression evaluation (control of types of intermediate results)

Whether the special character i should be introduced and if so, how.

My intention is to see to it that the complexity of all intermediate results is known. The restriction, that all complex expressions should be homogeneously of type complex is too strong, therefore I suggest automatic invoking of the transfer of arithmetic (i.e. integer or real) to complex

If "op" is one of the five binary operations "+", "-", "*", "/" or "else",

if c is an expression of type complex,

if ar is an expression of type arithmetic,

then the result will be of type complex, and "c op ar" will be interpreted as "c op com(ar,0)" and "ar op c" as "com(ar,0) op c", assuming the five operations defined for complex arguments. If c is a complex variable, the assignment statement "c:= ar" will be interpreted as "c:= com(ar,0)"

The net effect of this rule will be that all non-complex sub-expressions will be evaluated in terms of integer and real arithmetic. A program, not using complex arithmetic at all will proceed at full speed, as desired.

The definition of the powering operator will be extended to include the case with complex base and integer exponent. The result will then be of type complex.

The unary + and - signs in front of a complex primary will have their usual meaning.

EWD96-2

I am inclined to restrict the automatic invoking of the transfer function to the cases stated above. For one thing, I feel that automatic invoking of the transfer function from complex to real
should never take place.

if "arv" stands for a real or integer variable

if "c" stands for a complex expression

the assignment
"arv:= c" will not be allowed and the translator can already give an error message.
In that case the program should write

"arv:= re(c)" or "arv:= mod(c)", just as he wishes.

The next question to decide is whether we admit an arithmetic actual parameter if the formal one is specified as complex. I think we should, although there are some dangers lurking!

We consider two procedures

procedure p1(z); complex z; begin ..... (z) ..... end; and

procedure p2(z); complex z; begin ....; z:= ..... end;

the difference being, that inside p1 only interest is shown in the right hand value of the formal parameter, whereas in p2 an assignment is made to it(as well).

If we do not provide for automaticly invoking the transfer function, the call "p1(com(z,0))" would be OK, the call "p2(com(z,0))" would have to be rejected at some stage or another. The implementation of this rejection runs shortly as follows.

At call side the actual parameter is specified in its so-called formal locations. Of these formal locations, one is reserved for the evaluation of the right hand value and one for the left hand
value, a specification which is given in the form of an instruction, which at run time will be the argument of an execute operation. At call side the actual parameter "com(z,0)" is recognized as one
without a left hand value. As a result the calling sequence will insert an alarmjump at the word reserved for the left hand value.

If we decide, that the transfer function from arithmetic to complex should be involved automatically, then we can just write p1(x) and p2(x).
In the case "p1(x)" the system must provide for automatic transfer from arithmetic to complex, in the case p2(x) the system should give an alarm. The requirement is, that we can devise a mechanism, catering for this, without slowing down the work of the non-complex user. A second requirement is that the calling sequence will be independent of the procedure called.

We can achieve this by two stage definition of the formal locations. On account of the specification "formal" the procedure starts to inspect the formal locations. If the actual happens to be an arithmetic variable it can change the formal location by replacing the word, reserved for the left hand value by an alarm jump. In this way the price is paid by the complex user.

EWD96-3

Finally I have come to the conclusion that in a system like this there is no room for i, or any other way of representing complex constants. Instead of "u+iv" the user is kindly requested to write com(u,v). If he wishes to do so, he can declare "complex i"; and assigne "i:= com(0,1)" after which he can write "u+i*v".

My dislike for i is that I do not know how to regard it. Is it a unary operator, of which it has not been decided whether it works to the left or to the right? ("u+iv" and "u+vi"). Or is it a constant, not unlike true and false? If so, we should require the user to write "u+i⋅v" or "u+v⋅i". But then the use of the multiplication sign (and the plus sign, for that matter) is a sheer mistification, and there is only a point in this. If the translator recognizes these particular circumstances and is able to introduce a further type, call it "imaginary", at least for anonymous results. Then the question may be raised "i ⋅i", this will equal -1; the real result -1 or the complex one?

All this mess is introduced at the moment one tries to include i. Therefore I propose not to do it, hoping that every user, crying for complex numbers, will be glad with the facilities provided, instead of suffering from an absent i.

Transcription by Ken Dyck.

Last revised on Wed, 30 Jul 2003.

01xx

101: Description of the object program

102: Description of the object program, II

105: Description of the object program (a sequel to EWD102)

108: Een algorithme ter voorkoming van de dodelijke omarming

111: Error checking

112: Ruwe schets vertaalproces

113: Segment control

116: De bankiersalgorithme en verfijningen daarvan

117: Programming considered as a human activity

118: Communicatiebuffering voor de EL-X8 - T.H.E.

123: Cooperating sequential processes

126: The multiprogramming system for the EL X8 THE

130: A sequel to EWD126

131: Verslag van bezoek aan de Arbeitstagung fuer Automatentheorie te Hanover.

132: An Experiment with the “record class” as suggested by C.A.R.Hoare

137: Heel kort verslag bezoek aan het symposium over Multi Access Computers, 2–4 november 1965 in het NPL

139: Appreciatie van ponskaarten

140: Documentatie over de communicatie apparatuur aan de EL X8

145: Globale beschrijving van de drijvende arithmetiek van de EL X8

147: Proposal for the input and the notation of the system

149: Documentatie over de communicatieapparatuur aan de EL X8 (vervanging van EWD140)

150: Tentamenopgave “Cooperating Sequential Processes”

155: Context dependent names

157: Over de sequentiele interpretatie van een ponsband

158: Tentamenopgave “Cooperating Sequential Processes” (april 1966)

161: Sequentiele interpretatie van ponsband

163: Eerste verkenning over de dood van programa’s

164: Keuze tussen symcharf en symchart

167: Aan de leden van de onderafdelingsvergadering

184: Ir.Medema, Ir.Hendriks, weledelgestrenge heren!

188: Over een academische opleiding tot “Computer Scientist”

190: Tentamen “Co-operating Sequential Processes”

191: Aan de Commissie Wetenschapsbeleid ter zake van Automatiseringswiskunde aan de THE

194: Het einde van een ambacht

196: The structure of the “THE”-multiprogramming system

198: An effort towards structuring of programmed processes

EWD101 - 0

Description of the object program

The main points seem to be:

1. Memory lay out

2. Simple variable addressing

3. Block entry and exit

4. Formal variable addressing

5. Procedure calls and actual parameters

6. Subscription

7. Labels and switches (goto-statement)

8. Conditional expressions and statements

9. For-statement

10. Library

11. Assignment

12. Error checking

13. Input-output buffering.

Memory Layout

Apart from a fixed portion of core memory, the remainder will be used in portions of 512 words, called a core page.

Memory on drum will be divided into drum pages of 512 words. The starting address is given by

1025 * drum page number (mod 2¹⁹)

The information in a program is subdivided into segments also of 512 words. (A segment is an information unit, a page is a memory unit)

In the case of a big array, a segment which has been declared, but up till now is still unused, is regarded as existing, but empty. It occupies no page.

The information of a non-empty segment may be at any moment

1) in the process of transportation

2) exclusively on core

3) exclusively on drum

4) on both.

Remark: while a segment is in the process of transportation it may cease to exist. As far as the running system is concerned the core page remains occupied until notice has been taken of the completion of the transport process.

We distinguish (mainly)

stock segments

program segments

array segments.

EWD101 - 1

Remark | 1. | Each program has a unique stack.
| 2. | Program segments are in principle of two kinds, Library segments and private segments ("private" will mean: pertaining to an individual program).
| 3. | Array segment may turn out to be different from buffer segments for input and output. Time will show.

To each segment belongs a so-called SV (Segment Variable); it is via the SV that a segment will be addressed.

Addressing Program Segments

In core memory will be a table of SV's pertaining to the library segments. This will contain as many SV's as the library has segments.

The SV table for the library will be situated at a fixed place in store; the SV's will be addressed --mirabile dictu-- by their physical address.

The private program SV's of a program will be put at the bottom of its stack. This bottom page will be chosen, fixed, at the beginning of the translation process. As a result, the private program SV's can be addressed by their physical address.

Points in program or library are thus characterized by 9 bits line number + 18 (or maybe 15, undecided yet) bits SV-address.

Addressing Array Segments

As array will be local to a program, the SV's corresponding to its segments will be put in the stack at a block height corresponding to the declaration. they are never addressed directly by the object program.

Addressing buffer segments

Undecided yet.

Remark about stack segments

A stack segment will always be in core, and on a so-called "holy core page". Therefore, the system can safely convert to physical addresses when referring to elements within the stack.

Stack segment overflow

Logically consecutive stack segments need not be on consecutive core pages. The object program has the duty to reserve, at block entry, "so and so many more" stack places. Whether they can be put on the same segment or whether the transition to a next page is needed is not reflected in the object program.

  EWD101 - 2

Simple variable addressing

Reading --i.e. executing-- a text implies that D points to a proper display.

Quantities declared in the outermost block will be addressed by MO[q]-addresses, simple variables in blocks with block height 1 by M1[q] addresses, etc.

However: when executing a piece of text of block height n, D[n] should be contained in the A-register, so that for local simple variables the addressing can also be done by means of MA[q]. For the system this implies, that after return from a primitive to program text, care must be taken to ensure that A will indeed contain the local reference point. (At each stage D[n-1] = n, so this is one of the ways to achieve this.)

Simple reals will occupy two words in the stock, simple booleans and integers will occupy a single word. Simple complex variables will contain four consecutive words in the stack.

The local variables of a block will be addressed by Mn[q] (or MA[q], see above) with q = 0, 1, 2, 3 ... m with m £ 255. The rule that we start with q = 0 is essential; whether the maximum value of m will be allowed to be 255 is a translator question: it may decide to introduce a fictitious extra block at an earlier point.

Block entry

The main task of block entry is

    a) extension of the terminology (=Display)

    b) stack reservation.

The block entry apart from arrays will be performed in the following steps.

First a stack reservation has to be made for the explicitly addressed stack quantities (one word per simple boolean, and simple integer, two words per simple real, four words per simple complex and one word per array). To these have to be added some standard ones describing the linking of stack storage; see below.

The stack reservation is made by two instructions:

    S:= number of words consecutively needed

    SEO

Between these two orders, segment transition will not be allowed. SEO is the name of a subroutine jump to a System Routine. it will be an instruction of the type SUBCD.

The task of SEO is to increase the current block number, (to be found in D[-1]), to find the new stack space asked for, either in the same or in another stack page, to provide the linking necessary, to set the WP, the AP and to fill in a new item in the Display.

When no array is declared, the object program will proceed by asking for an anonymous reservation, i.e. the amount of storage space needed for the anonymous intermediate results. The algorithm describing how to derive this number will be given in detail.

EWD101 - 3

In the object program the anonymous reservation will be described by

    S:= number of words consecutively needed

    SE1

Also SE1 is a SUBCD instruction; between these two orders no segment transition will be allowed.

The task of SE1 is to check whether WP can remain as it stands, or whether it must be set to the beginning of a new stack page.

In the case of one or more array declarations the proceedings are slightly different.

After SEO, which effected the block entry proper the array declarations are treated ãarray segmentä after ãarray segmentä (see 5.2.1).

The treatment of an array segment consists of

1) | asking stack space for the values of the bounds in order from lef to right and their anonymous evaluation. (In this respect the creation of storage mapping functions, the processing of an "array segment" can be regarded as a 2n-ary operation).
2) | evaluating the bound values and stacking them as integers, one word for each, on top of the stack (i.e. at the bottom of the place reserved). These values will remain there during the execution of the block.
3) | creation of the storage function. This operation needs as parameters

3.1) | the type of the array (boolean, integer, real, or complex)
3.2) | the bound values
3.3) | the dimension
3.4) | the array words concerned.

The type of the array will be specified by different entries.

The bound values of the array can be found at the top of the stack.

The dimension can be deduced from the difference between AP and WP.

The array words will be specified by the object program, as follows:

S:= number of array identifiers in the segment.

A:= physical address of the first array word concerned.

These two instructions will be followed by one of the following four:

SE2   create integer arrays   \

SE3   create real arrays      |     of type SUBCD.

SE4   create boolean arrays   |

SE5   create complex arrays   /

The return value of A is the local reference point, of B the present AP, of S and F immaterial.

The three instructions thus generated may not be separated by a segment transition.

The first array segment is now treated. The object program will repeat this for any further array segments; after the last one, SE1 will be used to reserve stack space for the anonymous expression evaluation. This is needed, because SE2, SE3, SE4 and SE5 will imply a (statically unknown) increase of AP.

EWD101 - 4

The procedures declared within a block will not result in extra operations in the object program, to be performed at block entry. The processing of switch declarations is undecided yet.

Block exit

The normal block exit (ãpassing through an endä) will be reflected in the object program y a single instruction of type SUBCD

SE6: Block exit.

Formal variable addressing

The top of the stack is used as transmission mechanism to transmit the actual parameters to the procedure called.

At call side the object program stacks the current actual parameters on top of the stack in some prescribed order (either from left to right or right to left; this is fully a translator question and need not be decided now). Each actual parameter specification takes four consecutive words in the anonymous top. As soon as the procedure has been duly entered, they become "nonymous" and can be addressed as the so-called "formal locations".

The top formal locations are addressable by something like Mn[-4] up to and including MN[-1], the next formal locations by Mn[-8] up to Mn[-5] etc. with suitable n, m viz. one higher than the block height of the local variables of the block in which the procedure has been declared.

Note. If the number of local variable exceeds the limit, so that one or more additional block parenthesis pair has to be introduced by the translator, then the procedures and switches declared within this block must be treated as declared within the innermost block.

The processing of the specifications and the value list will be described as part of the procedure entry. In this section we shall restrict ourselves to formals outside the value list.

Here the translator will not distinguish between the specifications integer and real; to indicate this we shall use the term "arithmetic".

The processing of arithmetic formals

The formal locations Mn[-4*m-alpha+0] ... Mn[-4*m-alpha+3] be denoted as f[0] ... f[3]. (alpha leaving space for return information.)

Essentially, these formal locations will be processed in three different ways:

      a) as actual parameter

      b) as right hand value

      c) as left hand value

Actual parameter

The structure of the object program transmitting a formal variable as an actual one will be described as part of the calling sequence. The contents of the formal locations have to be copied on top of the stack.

EWD101 - 5

Right hand value

The object program will contain the instruction

DOS(f[0])

The first formal location must be filled with such an instruction that after return to the body

F | contains the value required
A | and B are unchanged.(A will contain the local reference point and B will contain the stack pointer).

The return value of S, however, is immaterial.

Left hand value

This has to be evaluated when assignment has to be performed to a formal variable of type arithmetic. On account of possible side effects the proceedings will be as follows:

   First a left hand value will be evaluated on top of the stack, then the expression will be evaluated in the F-register, and finally this value will be assigned according to the data on top of the stack. A left hand value is a generalization of the concept ãaddressä.

The evaluation of the left hand value is commanded by the object program by

DOS(F[1])

Upon return in the body the return values of S and F are immaterial.Ê A again contains the local reference point, as it did before, and B is increased according to the size of the left hand value, seeing to it that again it points to the first free place.

The left hand value must be such that, when the value to be assigned has been placed in the F-register and the left hand value is indeed the top element, assignment can be effected with

DO(MC[-1])

After this operation the return value of A is still the local reference point, the contents of S are immaterial, B is decreased in accordance with the size of the left hand value processed and F is unaltered if assignment to a real has taken place. If, however, assignment to an actual integer has taken place, then F will contain the rounded value.

Checking of equal types in multiple assignment

In a multiple assignment, all left hand sides must be of the same type. If no formal left hand side is in the list, the checking will be done at translation time. If one or more of the left hand values are formal the check for type consistency will be performed at run time as part of the assignment statement.

As soon as all left hand sides have been evaluated on top of the stack they will be inspected all ö including the left hand sides of non formal arrays -; to do this, three system entries are introduced:

SE7: check consistent left hand type
SE8: check integer left hand type
SE9: check real left hand type.

EWD101 - 6

They are of the form of SUBCD instruction; they are preceded by

S:= number of left hand values to be inspected.

SE7 has to be used in a multiple assignment, all elements of which are formal. In the case of one or more non-formal left hand sides the translator can have checked the consistency of the non-formal ones, and use SE8 or SE9, just as the case may be.

The two orders, just generated may not be separated by a program segment transition.

Upon return from SE7, SE8 and SE9 ö if the check was satisfactory ö A must contain the local reference point, B must have its previous value, the return values of S and F are immaterial. (The assumption here is, that checking will be done after evaluation of the left hand values) but before that one of the right hand value.)

Remark 1. The number of left hand values is given explicitly; the alternative - derival from WP - would disable us to carry out this check at the so-called "intermediate assignment".

Remark 2. The possibility to perform this consistency check at procedure entry has been rejected on three grounds:

1) | it would impose a scanning burden on the translator, (not serious)
2) | it would require the formal locations to distinguish between integer and real (what is otherwise unnecessary)
3) | multiple assignment is unimportant anyhow, still more so with formal left hand sides.

Other types of formal parameters will be dealt with later.

Complex Arithmetic

This will be described now, now for two reasons: it is not obvious, and we have hardly paid attention to it. Also it has a bearing on the actual formal correspondence, when a actual of type arithmetic may be supplied for a complex formal.

A complex number will occupy in store four consecutive words, two for the real part and two for the imaginary part.

In accordance with our attitude towards complex numbers, we shall implement them as straight forward as possible, only trying to gain, where the gain can easily be won.

The straight forward method puts all results on top of the stack, four words for each operand and we only operate on top of the stack.

The first thing we decide is that, in the case of a simple left hand operand and a complicated expression at the right hand side, we shall do an interchange whenever linguistically possible. (This analysis will be done for arithmetic variables anyhow. So this cannot produce great additional difficulties.)

Up till now the reason to do so is saving of stack space. The next question is under what circumstances we intend to save time as well.

The only operations worth bothering about are the fetch, the assignment, the addition, the negation and the multiplication.

EWD101 - 7

The basic remark is that as long as addition, negation, assignment and fetch are concerned, we can perform our operations first on the real parts and then on the imaginary parts. All primaries being simple

"a:= b + c"

becomes then

F:= real part b; F:= F + real part c; real part a:= F;

F:= imÊÊ part b; F:= F + imÊÊ part c; imÊÊ part a:= F;

This is even OK if a coincides with b or c or both. It becomes more difficult if we have a product, because then there is no non-interference anymore between real and imaginary parts.

If I am not mistaken the following algorithm holds. If a complex product has to be formed, investigate if any direct additions can be performed on it. this defines which anonymous locations will accept the result (if any). Make a list of destinations (including an anonymous one in the case of further processing). Check, whether the first factor occurs among the destinations; if so, save the real part. Check, whether the second factor occurs among the destinations, if so, save its real part. Finally produce the code for the real part computation and store, secondly create the code for the imaginary part, being sure to use the saved real parts. It should be able to cope with

a:= b:= a * b !

If a non-complex primary is used as argument for a multiplication or addition, we can exploit this. This will not be too hard. This being settled we can resume the System Entries for the complex arithmetic.

SE10  complex division.

This will be a SUBCD instruction. The two top elements of the stack must be complex values, the lower one is replaced by the quotient of the lower one divided by the higher one.

Return value of B is 4 lower than the entry value, A must be unchanged, the return value of S and F is immaterial.

SE11  complex power.

The top element of the stack must contain the complex base, F must contain the exponent value. SE11 starts to check, whether this value is indeed integer and replaces the base by the power. Return value of A and B unchanged, of S and F immaterial.

Complex assignment

This only occurs in the case of separately evaluated complex left hand values, derived from formal or subscripted (complex!) left hand sides. The top of the stack will contain a complex value, underneath will be a left hand value. For every assignment the object program will contain

DOS(MB[-5]).

EWD101 - 8

This will perform the assignment, remove the left hand value, shift the complex value down and decrease B accordingly. Upon return, A must contain the local reference pointer, the values of S and F are immaterial. After the last assignment the object program contains

B:= B - 4

in order to get rid of the complex value.

(The last transportation is unnecessary, but I think I prefer it that way.)

Procedure entry and exit

Type procedures will leave their result on top of the stack.

We shall first treat the non-formal case.

The calling sequence for a procedure of type integer, real, complex respectively starts with "B+1", "B+2", "B+4" respectively.

This has also to be done in the case that the type procedure is called as statement; the way in which the decrease of B (in order to reject the unwanted result) will be effected will be described later.

On top of the place left open the calling sequence will put the formal locations, if any. On top of these, the calling sequence will put the return information.

The stack picture at procedure call will be

M[B-10]

:f[0]
\

:f[1]
 | formal locations of last actual

:f[2]
 | parameter, if present

:f[3]
/

M[B-6]
:4*times umber of actual parameters +6
:invariant return address
:return D
:return specifier

M[B-2] | :invariant starting address of the procedure
M[B-1] | :context D
B → | . . . . .    places reserved for the standard locals. ..... .....

The present value of B will be local reference point of the fictitious block of the procedure, see below.

We have the following return specifiers

SE12  | Normal return from explicit procedure. This will result in a AP-value equal to A ö MA[-6], when A is the local reference point of the fictitious block.
| This will be the return specifier in all non-formal calls, except when explicit type procedures are called in the statement situation.

EWD101 - 9

SE13
Reject integer result.
This will result in a AP-value equal to
   A - (MA[-6]+1).
This will be the return specifier when an explicit integer procedure has been called in the statement situation.

SE14 | Reject real result. This will produce AP = A ö (MA[-6]+2); it will be used, when an explicit real procedure is used in the statement situation.
SE15 | Reject complex result. This will produce AP = A ö (MA[-6]+4); it will be used when an explicit complex procedure is used in the statement situation.

The formal calls are classified according to the information available at translation time of the body.

If a formal procedure is specified non type it may only be called in statement situation. All types of procedures are admissable as actual one. The calling sequence will start with B:= B + 4 and SE15 will be used as return specifier.

If a procedure is specified as arithmetic, the only actuals acceptable on account of this specification are those of type integer and real.

If it is called in the statement situation, its calling sequence will start with "B+2" (to give room for a result) and the return specifier will be SE14.

If it is called in the expression situation, its calling sequence will start with:

          F:= 0

        MC[0]:= F;

the return specifier used will be:

SE16 Make real result.

   This will produce the return value of AP equal to A - MA[-6]; but before that, it will check, whether d15 of the lower result word equals d26 of the higher one; if not, -O will be filled in the lower result word. (To cater for the case that the arithmetic actual was integer and has produced a negative result).

If a procedure is specified as complex, the only actuals acceptable are those of types integer, real and complex.

If it is called in the statement situation, its calling sequence starts with "B+4" and the return specifier will be SE15.

If it is called in the expression situation, the calling sequence will start with:

          F:= 0       \   filling in an imaginary part = zero

        MC[0]:= F;    /

        MC[0]:= F;        prepare place for real part

and the return specifier used will be SE16.

EWD101 - 10

Remark. Complex numbers will be represented, for this reason by imaginary part followed by the real part. We shall do this consistently. (In contradiction to a previously stated convention.)

A complication arises because a single procedure identifier may be a complete expression, it may be given as actual parameter where the corresponding formal one has been specified arithmetic.

When a formal parameter has been specified arithmetic, the procedure will accept an arithmetic procedure identifier as actual. It will change, however, the formal locations in such a way that DOS(f[0]) will produce a right hand value in F and DOS(f[1]) will produce an alarm (no left hand value).

This checking will change f[0] in such a way that

a) | two words on the stack are left open for the result, as the arithmetic procedure might be of type integer,+0 will be filled in (at least in the lower word).
b) | the proper calling sequence for a procedure without parameters will be generated. This implies the construction of an invariant return address!
c) | as return specifier it will place

SE17: Real value in F.

This one is a combination of SE16 and SE14.

It starts by making a decent real result of the contents of the locations left free. After that it will reject them, but it will return with the value in the F-register.

The fictitious block

As described above the calling sequence prepares in its anonymous space place for the result (if any), the formal locations (if any) and the return information. This information becomes the "nonymous" information of the fictitious block. On top of the return information sufficient room must be available for the standard locals (WP, SV-chain, etc.). the AP-value at the moment of entry will act as the local reference point of the fictitious block.

The text of the procedure body starts with the fictitious block entry consisting of three orders (not separated by program segment transition):

      A:= block height of the fictitious block

      S:= maximum block height inner block

      SE18  Create Display.

SE18 is a SUBCD instruction. Upon return the values of S and F are immaterial. A contains the local reference pointer, B will contain the stack pointer. At this moment the value of the stack pointer will be equal to that of the WP of the fictitious block; this value will also be stored at MA[0], being one of the standard locals.

EWD101 - 11

The task of SE18 is roughly the following.

It has to find place for a new display on top of the stack, the size of this display being desirable from S. If the amount of space in the current stack page is insufficient a new stack page has to be initiated.

The number of places needed consecutively will be 3 more than the entry value of S, for the Display to be created will have the following formal:

      D[-3] :     PCD =  Parameter Depth Counter

      D[-2] :     FBH =  Fictitious Block Height

      D[-1] :     CBH =  Current Block Height

  D → D[0]  :     global reference point

      D[1]Ê :     reference point block height 1

           ↓etc.

      D[Sentry]

  B → .........

(The number of places needed consecutively will be a little more than Sentry + 3, because we must still be able to give some SUBCD-instructions).

SE18, Create Display will set the new PDC equal to 0, FBH and CBH equal to Aentry, it will fill the places D[0]...D[CBH-1] with the corresponding elements of the context display, D[CBH] with the local reference point of the fictitious block.

After this preparation the fictitious block has been duly entered: in extending the stack the fictitious block behaves as any other block.

The next three orders check the number of parameters supplied.

Unseparated the text will continue with

           S:= MA[-6]

      U, S - "(4*number of formal parameters + 6)", Z

      N, SE19

where SE19 is an alarm exit for "wrong number of parameters".

After this check the procedure will investigate the actual parameters.

Actual parameter investigation is done by two unseparated instructions per parameter, viz.

      S:= f[0]    (with absolute MA-addressing)

followed by one of the following system entries (all SUBCD-orders):

SE20 | Check formal arithmetic
SE21 | Check formal boolean
SE22 | Check formal arithmetic array
SE23 | Check formal boolean array
SE24 | Check formal procedure
SE25 | Check formal arithmetic procedure
SE26 | Check formal boolean procedure
SE27 | Check formal label

EWD101 - 12

SE28 | Check formal switch
SE29 | Check formal string
SE30 | Check formal complex
SE31 | Check formal complex array
SE32 | Check formal complex procedure

After return - when the check is satisfactory - S and F have immaterial values. A and B must contain the usual information.

If the value list contains scalars, the fictitious text will continue with

      S:= 16 (or something else, this is a translator question)

      SE1

in order to reserve anonymous space for formal scalar evaluation (case of simple implicit subroutine).

For each scalar in the value list it will contain the code sequence asking for the right hand value followed by an assignment, overwriting the formal locations (this can both be done with MA-addressing).

If arrays by value are to be processed they must be processed now. (see later) this may cause a WP-increase, but there is nothing wrong with that.

The whole picture of a procedure-text that will be

Create Display (SE18)

Check Number of Parameters (SE19)

Check Formal Parameters (SE20-SE32)

Process Value List (SE1)

Block Entry (SE0)

    :

    :

Block exit (SE6)

DO(MA[-3])

The block exit SE6 annihilates the block entry SE0; if the procedure body does not contain any local variables, which need space reservation in the stack, this bracket pair may be omitted.

The fictitious block entry Create Display (SE18) is annihilated by the last instruction: an execute of the return specifier supplied at the call.

The Parameter Depth Counter PDC

The following applies to the non-simple implicit subroutine NSIS. When counting the maximum inner block height, the NSIS counts for an increase equal to 1.

When in implicit subroutine is called, this is done under control of a so-called context D. Before entering the NSIS proper the PDC of the context D is increased by one; upon return from the NSIS it is again decreased by 1. As an NSIS might contain a call of another procedure supplying again a NSIS as actual parameter, PDC might get larger than 1.

EWD101 - 13

The Non Simple Implicit Subroutine NSIS

The NSIS is treated as a special kind of procedure with a "parameter block" of a height 1 higher than the calling sequence.

The fact that an actual parameter is a NSIS is given in the formal locations. Its block introduction, however, needs no parameters from the text od NSIS. (The implicit subroutine has no local variables.) Before entering the NSIS, therefore, its context D is already the current one, the PDC and the CBH associated with it have been increased, a local reference point has been introduced and a WP has been set.

The NSIS starts by asking for anonymous space in the usual manner (with SE1).

At the end it will contain the return from the implicit subroutine, which will find its return information under control of the local reference pointer. As part of the return operation PDC and CBH, will be decreased by 1. Further details later.

EWD101 - 14

List of system entries introduced

SE0         Block Entry

SE1         Anonymous Reservation

SE2         Create integer arrays

SE3         Create real arrays

SE4         Create boolean arrays

SE5         Create complex arrays

SE6         Block Exit

SE7         Check consistent left hand type

SE8         Check integer left hand type

SE9         Check real left hand type

SE10        Complex division

SE11        Complex power

SE12        Specify normal return

SE13        Specify return, rejected integer

SE14        Specify return, rejected real

SE15        Specify return, rejected complex

SE16        Specify return, integer to real extension

SE17        Specify return, result in F

SE18        Create Display

SE19        Alarm exit wrong number of parameters

SE20        Check formal arithmetic

SE21        Check formal boolean

SE22        Check formal arithmetic array

SE23        Check formal boolean array

SE24        Check formal procedure

SE25        Check formal arithmetic procedure

SE26        Check formal boolean procedure

SE27        Check formal label

SE28        Check formal switch

SE29        Check formal string

SE30        Check formal complex

SE31        Check formal complex array

SE32        Check formal complex procedure.

     EWD102-0

9 september 1964

     Description of the object program, II

(A sequel to EWD101).

     Program segment transition

For the moment I restrict my attention to implicit jumps to other program segments.

In contrast to previous thoughts I have the idea, that it would be nice if such a transition could be coded in such a way that no register contents will be destroyed. (This means that many of the previous remarks about "not separated by program segment transition" can be omitted in many cases.)  At present I take the view that the program segment transition will be fully preserving. (Including Interruption Permits, Conditions etc., for at present I do not know how we shall code the boolean expressions.)

In the object code program segment transition will be coded by two consecutive words, stored on the segment to be left, viz.

          SE 33    Program Segment Transition

          invariant target address

The second word contains 18 bits for the physical address of the segment SV and 9 bits for the line number within the segment.

          SE 33    will be a SUBCD instruction.

An immediate consequence is that we are not allowed to let B point to a place of interest whenever a program segment transition occurs. The contents of this place will be overwritten by the machine link. (The translator must be jolly well aware of this rule, e.g. when translating complex expressions!)

The phenomenon of program segment transition has nothing to do with the stack, with Display-modifications or what not. Secondly it cannot be nested per program. My suggestion therefore is that it shall use the bottom of the current stack. Each program will have some global variables for this and may be other purposes. the idea of the "standard locals" suggests that one of the "standard globals". Decision is left to the system makers.

SE33 is an inconditional SUBCD instruction; making it a conditional instruction would lead to disaster as the next word (invariant target address) does not allow its interpretation as a machine instruction.

The conditional forward jump resulting from the if-clause will be coded as a conditional forward JUMP instruction to a point in the same program segment. It will point either to the direct continuation which is a SE33. The inconditional jumps derived from the if then else construction will also be coded primarily as a (inconditional) JUMP instruction, leading either to the continuation of the program or to a transition gate. the fact that in the latter case we have wasted one word of program space will be accepted as the price for ease of translation.

EWD102-1

The transition gate will also be generated in the case of segment exhaustion.

Designational expressions

We shall now describe in its full pomposity and clumsiness the general mechanism for evaluation and use of designational expressions. Whether this mechanism will be used for goto statements with explicit labels in the same block is, at this of the description, immaterial.

On account of the fact that a formal parameter specified as label may occur in the value list, we must separate the evaluation of a designational expression on the one hand and its use in a goto statement on the other.

On account of the fact that a goto statement with an undefined switch element as its final operand is to be performed as a dummy state, the possible range of label values will be extended with a special one, called "skip".

The value of a designational expression is called a label value.

The constituents of a label value unequal to skip are

     1. the invariant target address

     2. the local reference point of the target level.

The local reference point LRP of the target level will give access to:

     LRP[0]    WP of target level

     LRP[1]    SV-link of target level

     LRP[2]    D value of target level

     LRP[3]    CBH of target level

Remark: | To have CBH also among the standard locals is nice but unnecessary, for two reasons.

The CBH of target level could be one of the constituents of the label value.
Furthermore, the LRP occurs once in the display identifier by D (viz. LRP = D[CBH]) so we could find CBH by scanning of the display.
Even D is not strictly necessary because the three counters attached to each display enable us to break down the stack level by level until the LRP specified is the current one.
Specifying D as one of the standard locals, however, permits us to make a short cut.  The same holds for the way in which the SV-chain and the stack page chain has been built up.

Remark. Having direct access to the target D and the target CBH allows the short cut in the goto statement. The goto should consist of the following actions, as far as stack control is concerned.

From the situation about to be left, the system must isolate

     a) old SV-link := M[old LRP + 1]

     b) old AP.

The first one will control array segment cancelling, the second will control stack page cancelling.

EWD102-2

Then

          D := M[new LRP+2] to set new D

      D[-1] := M[new LRP+3] to set CHB

      D[-3] := 0        (i.e. new PDC).

         AP := M[new LRP+0] because at inter statement situation AP = WP.

Now the array segment cancelling will be controlled by old SV-link and new SV-link = M[new LRP+1] and stack page cancelling will be controlled by old AP and AP.  It can be proved that all associated counters of the Displays which are retained in the stack will have the correct value.

Further more program segment transition has to be effected on account of the machine link and the invariant target address. This is the usual manner, as in SE 33. (In the case of a wild jump I do not expect to distinguish between a jump within the same program segment and one leading to another.) the above was a premative discussion of the goto.

Per program we shall have two consecutive words in the bottom of the stack. This global variable has the name Òuniversal labelÓ. All evaluation of designational expression has to deliver the invariant target address and the target LRP in these two locations: they will be implemented as assignments to the universal label. The evaluation of switch element will also act as an assignment to the universal label.

The general implementation of the goto will be implemented by a single word in the object program

     SE 34     General goto

it will transfer control and regulate stack collapse on account of the target specification in universal label.

When the object program has been generated, the invariant target address will look like a constant to be stored on the same program segment.

A goto to a wild, but yet explicit label, will be coded as

          S := invariant target address

      UL[0] := S

          S := D[target BH]

      UL[1] := S

          SE 34              General goto

(This needs one additional word in a program segment for the invariant target address.)

Supplying an explicit label as actual parameter consists of

1. | placing a two word constant on top of the stack (the first will be a system entry of the type SUBCD the second one may be needed to indicate the fact that the parameter is a constant label value).
2. | followed by

EWD102-3

          S := invariant target address

      MC[0] := S

          S := D[target BH]

      MC[0] := S

     f[0] will be filled with such a system entry, that

      DOS(f[0])

          will perform

      UL[0] := f[2]

      UL[1] := f[3].

If a formal label occurs in the value list it will give rise to the following piece of program

      DOS(f[0])

   f[0, 1] := constant described above

   f[2, 3] := UL[0, 1]

and the label will remain to be treated as a formal label.

Conditional designational expressions present no special difficulty.

A separate description, however, is required for the switch, i.e. the switch designator and the switch declaration.

To the switch declaration corresponds a label procedure; the full procedure mechanism will be invoked. As far as embedding in the stack is concerned it will be treated as a non-type procedure, as it will not leave its value in the stack but in the Universal Label. Analogously, it will be treated in the stack as a procedure without parameters, its subscript value being rendered to it in the global variable ÒSwitch SubscriptÓ. there is no objection to using the Universal Label for this purpose.

The switch designator will be coded as follows

          F := subscript value

         UL := F

| calling sequence of the switch as non-type procedure without parameters

After return UL will contain the label value.

Remark: The switch can be formal or explicit, just as in the case of the statement procedure. Initial B:= B + 4 can be omitted and SE 12 will be used as return specifier.

The description of the switch body

The switch body is translated as a non-type procedure without parameters and no normal inner blocks within the fictitious block. (On account of type procedure calls with NSIS-parameter, the fictitious block may contain inner parameter blocks.)

The body will start with Create display (SE18); the parameter needed

EWD102-4

for the maximum inner block height implies a scan over the complete switch declaration.

Analysis of number and type of formal parameters will be omitted.

Next the body will ask for anonymous space in order to be able to evaluate subscript expressions; it will do so with SE1, the parameter needed will imply a scan over the complete switch declaration.

Then the contents of the Universal Label will be placed in the F-register. it will be inspected for integrity (and rounded to nearest integer).

Unless segment transition disallows, you code

          S:= -G

          S + 1 , P

     N ,JUMP (2) →

          SE 35        UL := skip

          DO(MA[-3]) ⇒

     →   ......

System entry SE 35 will make UL = skip. (A system entry is the easiest way to fill in this constant.

Then the text continues with

          S + number of elements dealt with on this page, P

     N , JUMP(......) →

If not all elements can be treated on this page, the last jump will point to a transition gate to the next.
If the complete switch can be dealt with within this page it will point to

     →  SE 35

          DO(MA[-3])

in order to create a skip for index values above the maximum.

The jump itself is followed by

          S + constant

(specifying the place of the primary element of the distributor) followed by

          JUMP(S)

The end of the page will contain the distributor, a sequence of JUMP-instructions with fixed negative argument; each of these will point to a piece of program derived from the corresponding switch element. The structure of such an element will be:

          Evaluate Designational Expression (in UL)

          DO (MA[-3]) ⇒

If it was impossible to accommodate the complete switch in the segment in question, the transition gates to the next segment fall into distinct classes:

one transition for the elements not dealt with by the distributor of the current segment;
one or more transition gates for the continuation of the evaluation of the last element accommodated within the current distributor.

EWD102-5

The next segment will start with the continuation of this last element; after that it will see to the remaining switch elements. Etc.

Cumulative list of system entries introduced in EWD 102

     SE 33         Program segment transition

     SE 34         General goto

     SE 35         Assign ÒskipÓ

Transcribed by Guy Haworth.

Revised Sun, 31 Aug 2003.

EWD 105

Description of the object program (a sequel to EWD102)

Obsolete are EWD101, page 5, top half of page 6, last paragraph of page 7 and first paragraph page 8. (Complex assignment.) From page 14, the lines SE7, SE8 and SE9 should be deleted.

Exhaustive list of the formal locations

Formal locations occupy four consecutive words in the stack, designated by f[0], f[1], f[2] and f[3] (in order of increasing address). The word f[1] will contain the so-called parameter code, a characteristic bit pattern, specifying the nature of the actual parameter. Layout of the parameter code will be decided later.

1. 

A real constant

f[0]

F = MS[2]

f[1]

parameter code

f[2]

 constant value in

f[3]

 floating point representation.

2. 
An integer constant
f[0]     G = MS[3]
f[1]     parameter code
f[2]     unused
f[3]     integer value.

3. 
A real in the stack (< 32K)
f[0]     F = M[a]
f[1]     parameter code
f[2]     M[a] = F
f[3]     unused.

4. 
An integer in the stack (< 32K)
f[0]     G = M[a]
f[1]     parameter code
f[2]     M[a] = G
f[3]     unused.

5. 
Pro forma: A real in the stack above 32K
f[0]     SE36   High stack real
f[1]     parameter code
f[2]         a
f[3]     unused.

6. 
Pro forma: An integer in the stack above 32K
f[0]     SE37   High stack integer
f[1]     parameter code
f[2]         a
f[3]     unused.

7. 
An integer array
f[0]     array word
f[1]     parameter code
f[2]     SE38   Left subscripted integer
f[3]     SE39   Right subscripted integer.

8. 
A real array
f[0]     array word
f[1]     parameter code
f[2]     SE40   Left subscripted real
f[3]     SE42   Right subscripted real.

9. 
A complete array
f[0]     array word
f[1]     parameter code
f[2]     SE42   Left subscripted complex
f[3]     SE43   Right subscripted complex.

10. 
A procedure or switch
f[0]     unused
f[1]     parameter code
f[2]     invariant starting address
f[3]     context D.

Layout 10 will be used when the actual parameter is a procedure identifier. The parameter code distinguishes between non-type, integer, real, complex, boolean or switch (= label procedure).

11. 
An arithmetic procedure as expression
f[0]     SE44   Arithmetic procedure as expression
f[1]     parameter code
f[2]     invariant starting address
f[3]     context D.

The above formal location contents are never generated directly; it is created by SE20 (Check formal arithmetic) and SE30 (Check formal complex) when the actual parameter is a procedure of arithmetic type. The parameter code will distinguish between arithmetic and complex.

12. 
A complex procedure as expression
f[0]     SE45   Complex procedure as expression
f[1]     parameter code
f[2]     invariant starting address
f[3]     context D.

13. 
Non simple implicit subroutine
f[0]     SE46   Non simple implicit subroutine
f[1]     parameter code
f[2]     invariant starting address
f[3]     context D.

These formal locations are derived from actual parameters which are

a) 
a subscripted variable (integer, real boolean or complex)

b) 
a arithmetic, complex or boolean expression, more trivial than a single identifier or constant

c) 
a designational expression, more complicated than a simple label.

The parameter code will distinguish between these cases.

14. 
Simple implicit subroutine
f[0]     SE47
f[1]     parameter code
f[2]     invariant starting address
f[3]     context D.

Parameter code as above.

15. 
Label
f[0]     SE48   Actual label value
f[1]     parameter code
f[2]     invariant target address
f[3]     target LRP.

16. 
A complex in the stack
f[0]     SE55   Stack complex
f[1]     parameter code
f[2]         a
f[3]     unused.

17. 
A complex array in arithmetic specification
When formal locations of type 9 are met by the system entry SE22 “Check formal arithmetic array” the right hand value is destroyed giving:
        f[0]     array word
        f[1]     parameter code
        f[2]     SE42   Left subscripted complex
        f[3]     SE56   Alarm arithmetic value of complex array.

Possible structures of left had values

(In pictures stack upside down.)

Left hand value for an integer

   on address a < 32K:

M[B-1]:

M[a] = G

B →:

........

   on address a ≥ 32K:

M[B-2]:

    a

M[B-1]:

SE49

B → 
 ........

   on array segment:

    invariant address

M[B-1]:

SE50

B → 
 ........

Remark. Number of words occupied by invariant address still undecided.
    SE49     Assign to high stacked integer
    SE50     Assign to integer on segment.

Left hand value for a real

   on address a < 32K:

M[B-1]:

M[a] = F

B →:

........

   on address a ≥ 32K:

M[B-2]:

    a

M[B-1]:

SE51

B → 
 ........

   on array segment:

    invariant address

M[B-1]:

SE52

B → 
 ........

    SE51     Assign to high stacked real
    SE52     Assign to real on segment.

Left hand value for a complex

     on address a:

M[B-2]:

  a

M[B-1]:

SE53

B →

......

   on array segment:
    invariant address

M[B-1]:

SE54

B → 
 .......

    SE53     Assign to high stacked complex
    SE54     Assign to complex on segment.

Creation of the left hand values described

Indexing a non formal array
After the indexing routine has been called the object code continues with
    SE 38     Left subscripted integer       or
    SE 40     Left subscripted real           or
    SE 42     Left subscripted complex,
depending on the type declaration of the array (which is known to the translator).

Depending on the outcome of the indexing process, SE38 creates one of the three left hand values for an integer. The indexing process delivers location information only (i.e. physical or invariant address), but not the type of the array: this is known to the translator and brought to effect by calling the appropriate system entry. For the moment we assume that the indexing process leaves its outcome in some of the registers.

Indexing a formal array
After the indexing routine has been called, the object code continues with
              DO(f[2])
referring again to the formal location of the array offered.

Processing of the left hand values described

The processing of a left hand value may only be given in the object program when the right hand value offered is of the correct type.

The assignment itself will be commended by the instruction
              DO(MC[-1])
and the stack will be shortened in accordance with the extent of the left hand value processed.

In the case of an integer assignment the integer value must be stored in G, the assignment itself will leave this value unchanged.

In the case of a real assignment the real value must be stored in F, where it must remain unchanged.

In the case of a complex assignment the real part of the complex value will stand in the F-register, the imaginary part in two universal locations of the program. The assignment will leave this complex value unchanged.

Creation of the right hand values due to subscripting

In the case of a right hand value required from an arithmetic array the call of the indexing routine will be followed by SE39 or SE41, Right subscripted integer or real, respectively.
It will deliver the value in the F-register.

When subscripting a complex array, the indexing call will be followed by
              B + 2
            SE 43

The two places left blank will be filled by the imaginary part. The real part will be handed over in the F-register.

The creation of a right hand value of a formal array

If the specification of the array is arithmetic,
              DC(f[3])
referring to the formal locations, will put the value required in F.

If the specification of the array is complex, the indexing sequence will be followed by
              F = 0
            MC[0] = F
            DO(f[3])

The zero placed on top of the stack will be overwritten by the imaginary part of the value delivered, when the actual array is indeed a complex one. The real part will be delivered in F.

The universal locations FLV and FRV

Per program two universal locations FLV and FRV (Formal Left/Right hand Value) play a role in the information transmission from actual parameters, when the formal parameter has been specified arithmetic or complex.

These locations have standard values in order to speed up the transmission in the case of simple arithmetic actuals. The standard values are:
      FRV :   “U, S = 0”
or any faster skip instruction available, and
      FLV :   SE57   “Standard value for FLV”.

The body of SE57 will be

G  | = MS[+2]      | take instruction to be stacked
S  | = M[B-1] | save link
M[B-1]  | = G | stack left hand value
GOTOR(S) ⇒  | return.

To get the left hand value of a formal parameter specified arithmetic or complex, the body will eventually invoke
            DOS(f[0])
            DO  (FLV).

To get the right hand value of a formal parameter specified arithmetic the body will contain
            DOS(f[0])
            DO  (FRV),
which pair will put the value required in the F-register.

The Universal location FCV

Per program there is a third universal location, called FCV (Formal Complex Value).

To get the right hand value of a parameter specified to be complex, the body will contain

F =  | 0
MC[0] =  | F     
      DOS(f[0])
      DO(FCV)

After return the imaginary part of the value will be on top of the stack, the real part in the F-register.

Also FCV has a standard value, viz.
            FCV :   DO(FRV).

All actual parameters of type arithmetic leave FCV unchanged. When the actual value is asked for by the above mechanism, it will ensure that the complex value will be properly delivered.

Advanced use of the FRV, FLV and FCV

As long as actual parameters specify arithmetic quantities, FCV will keep its standard value, FCV will first be left out of discussion.

Implicit subroutines may end by changing FRV and FLV; if so, they will be filled by system entries which, upon execution return FRV and FLV to their standard values.

The implicit subroutine, describing a subscripted variable

First we shall discuss the case of the non-formal array. After the call of the indexing routine, the result of this proves may be stored in the registers.

The idea is, that the choice of a left or right hand value will be postponed until return to the body has been completed. It will do so by filling in FLV and FRV in the appropriate way. At the same time, we can choose some other universal locations, the Universal Address UA to transmit the outcome of the indexing.

If the array has been declared integer, the implicit subroutine will fill

FLV with SE58 “Formal Left Subscripted Integer” and
FRV with SE59 “Formal Right Subscripted Integer”

These system entries start by resetting FLV and FRV to their standard values, by picking up from the UA locations the quantities, as delivered by the indexing process and from then onwards they merge with SE38 and SE39 respectively.

If the array has been declared real, the implicit subroutine will fill

FLV with SE60 “Formal Left Subscripted Real” and
FRV with SE61 “Formal Right Subscripted Real”

which, after the same introduction merge with SE40 and SE41 respectively.

If the array has been declared complex, the implicit subroutine will fill
      FLV with SE62 “Formal Left Subscripted Complex”
      FRV with SE64 “Alarm complex value in arithmetic”
      FCV with SE63 “Formal Right Subscripted Complex”
SE62 and SE63 will reset all three to their standard values, will pick up the UA-contents and will merge with SE42 and SE43 respectively.

If the array is formal, from the three transmission mechanism one has to be chosen on account of the type of the actual array, as can be derived from its parameter code.

The above can be condensed as follows.
After indexing a declared integer, real or complex array, there follows one of the following system entries.
      SE65 “Transmit subscripted integer”
      SE66 “Transmit subscripted real”
      SE67 “Transmit subscripted complex”.

They will save the outcome of the indexing process in the UA-locations and will FLV, FRV (and the last also FCV) in the appropriate way.

After indexing a formal array, S can be saved in a UA-location, the instruction
            S = f[1].
puts the parameter code of the array in the S-register and the following system entry
      SE68 “Transmit subscripted formal”
will effectively select one of the previous three on account of the bit pattern in the S-register.

We code SE55 “stack complex”.

SE55:         | FLV:= |  “SE 55.1” |  |  |
| FRV:= |  “SE64” |  |  |       transports via F(G)
| FCV:= |  “SE 55.1” |  |  |
| S = |  MS[+2] |  |  | take address a in S
| GOTOR |  (MC[-1])   ⇒
SE55.1: | FLV:= |  “SE 57” |  |  |       reset to standard       values via F(and G).
| FRV:= |  “U, S = 0” |  |
| FCV:= |  “DO(FRV)” |  |
| F = |  MS[0] |  |  |       transportation im. part
| M[B-3] = |  F |  |
| F = |  MS[2] |  |  | real part
| GOTOR |  (MC[-1])   ⇒
SE55.2: | FLV:= |  “SE 57” |  |  |       reset to standard       values via F(G)
| FRV:= |  “U, S = 0” |  |
| FCV:= |  “DO(FRV)” |  |
| G = |  M[B-1] |  |  | save link
| M[B-1] = |  S |  |  | store address a
| S = |  “SE53”
| MC[0] = |  S |  |  | complete left hand value
| GOTOR |  (G)         ⇒

Cumulative list of system entries in EWD105

SE 36         | High stack real
SE 37 | High stack integer
SE 38 | Left subscripted integer
SE 39 | Right subscripted integer
SE 40 | Left subscripted real
SE 41 | Right subscripted real
SE 42 | Left subscripted complex
SE 43 | Right subscripted complex
SE 44 | Arithmetic procedure as expression
SE 45 | Complex procedure as expression
SE 46 | Non simple implicit subroutine
SE 47 | Simple implicit subroutine
SE 48 | Actual label value
SE 49 | Assign to high stacked integer
SE 50 | Assign to integer on segment
SE 51 | Assign to high stacked real
SE 52 | Assign to real on segment
SE 53 | Assign to stacked complex
SE 54 | Assign to complex on segment
SE 55 | Stack complex
SE 56 | Alarm “arithmetic value of complex array”
SE 57 | Standard Value for FLV
SE 58 | Formal left subscripted integer
SE 59 | Formal right subscripted integer
SE 60 | Formal left subscripted real
SE 61 | Formal right subscripted real
SE 62 | Formal left subscripted complex
SE 63 | Formal right subscripted complex
SE 64 | Alarm “complex value in arithmetic”
SE 65 | Transmit subscripted integer
SE 66 | Transmit subscripted real
SE 67 | Transmit subscripted complex
SE 68 | Transmit subscripted formal.

transcribed by Corrado Cantelmi
revised 14-Mar-2012

EWD108 - 1

Een algorithme ter voorkoming van de dodelijke omarming.

     Een bankier is op de volgende -menslievende- voorwaarden bereid om aan klanten -in hele guldens- geld te lenen.
1) De klant moet kunnen garanderen, dat als hij over het gevraagde geld de beschikking krijgt, het project, waarvoor de lening wordt aangegaan, binnen eindige tijd voltooid zal worden, waarna de klant al het geleende geld aan de bankier zal teruggeven.
2) De klant moet van te voren een bovengrens opgeven van wat hij ooit tegelijkertijd ten bate van dit project in leen zal moeten kunnen hebben.
3) Als de klant -met eerbiediging van 2)- om een aanvullende lening komt vragen, mag hij niet klagen, wanneer hij van de bankier te horen krijgt "Op het moment kan ik U het gevraagde bedrag niet ter beschikking stellen, maar ik garandeer U, dat dit binnen eindige tijd wel het geval zal zijn."
4) Het is toegestaan -zulks wordt zelfs aangemoedigd!- dat de klant, wanneer hij tijdens de transactie ziet, dat de initiele (zie 2.) resp laatst genoemde bovengrens niet meer gehaald zal worden, de bankier van de verlaging van de bovengrens in kennis stelt.

     De vragen zijn: (als de bankier met een kapitaal van A gulden werkt)
a) onder welke voorwaarden kan hij een zich aanbiedende klant aannemen?
b) wat is de algorithme om tot wel, resp. niet uitbetaling te beslissen, zo, dat de bankier enerzijds nimmer een uitbetaling zal uitstellen, die hij veilig had kunnen doen, anderzijds nooit een betaling doet, wanneer hij niet meer onder alle omstandigheden garanderen kan, dat hij zijn toekomstige verplichtingen zal kunnen nakomen.

     Het antwoord op de eerste vraag is, dat de bankier elke klant kan accepteren, welks (initiele) bovengrens zijn totale kapitaal A niet overschrijdt.

     Om te beslissen, of hij bij aanvraag tot betaling kan overgaan, overziet hij de situatie, die zou ontstaan, wanneer hij tot betaling zou overgan. Is deze situatie "veilig", dan betaalt hij uit, is deze niet veilig, dan weigert hij de betaling. Om de algorithme te beschrijven, die vaststelt of een situatie veilig is, voeren we de volgende termen in.

     Voor elke klant houdt de bankier twee bedragen bij:
1) lening (aanvankelijk = 0)
2) claim (aanvankelijk = initiele bovengrens)

Op elk moment geldt voor elke klant "lening + claim = bovengrens".

Het aanvangskapitaal A verminderd met de som der leningen noemen we de "kasvoorraad".

Om een situatie te onderzoeken, rangschikt de bankier zijn klanten in volgorde van niet afnemende claim, dus claim[i] < claim[i + 1]. Vervolgens voert hij uit:

"vrij bedrag:= kasvoorraad; i:= 1;

L:  if claim[i] < vrij bedrag then

        begin vrij bedrag:= vrij bedrag + lening[i];

              if vrij bedrag < A then begin i:= i + 1; goto L end

                                 else veilig:= true

        end

                              else

        veilig:= false"

De bankier controleert dus of hij "door verstandig te wachten al zijn geld weer terugziet."

Transcribed by Frank Steggink
Revised Tue, 6 Jan 2004.

EWD 111

8 december 1964

Error checking

Voornamelijk is vandaag aandacht geschonken aan de wijze van terugmelding.

     De vertaler nummert de niet-lege regels van de programmatext. Als bijproduct geeft hij via de output van een aantal labels het regelnummer van de regel, waarin ze voorkomen. Procedure declarations zijn ook mooi.
Opm. 1 De vertaler zal hier identifiers in 1 alphabet uitprinten.
Opm. 2. De output kan aangeven of het een label dan wel een procedure identifier is;
      kan zelfs iets van de blokstructuur proberen aan te geven. Als de text zo slechts,
     dat we een lower bound voor label aanzien, dan zal deze print wel wat cryptisch worden !

     Probleem: in de dynamische plaatsbepaling ontmoeten we ook MCP's. In het minimale geval zeggen we, dat elke bibliotheekprocedure op 1 regel staat. Een alternatief is, om elke MCP moedwillig in een aantal regels onder te verdelen; netjes is om bij de terugmelding ook de naam van de MCP te vermelden. (Dit kon er wel eens toe leiden, dat we elke MCP een naam geven.)

Statische checking.

     De vertaling zal bestaan uit een aantal passes (eigenlijk hoop ik van niet te veel). We zullen proberen om bij de detectie van een fout althans de pass, waarin deze fout gedetecteerd wordt, af te maken met de bedoeling meer fouten van hetzelfde allooi te vinden. (Of dat altijd kan, is heel erg de vraag: is niet de executie "de laatste pass"?)

     Wat betreft error checking zie ik maar 2 passes noodzakelijk optreden:
1) analyse van delimiter structure en opbouw van de naamlijst
2) type checking etc. dwz. alles, waarvoor je de declaratie gezien moet hebben.

Opm. 3 Als ik in de pass, waarin de regelnummers uitgedeeld worden ook al check, zullen die foutmeldingen er wel doorheen komen; dit hindert niet.
Opm. 4 Een voordeel van Cor's regelnummering is, dat deze uniek is, ook in die gevallen, waarin de systactische structuur macroscopisch niet klopt.!

     Ik stel me voor, dat de vertaler in een left to right pass, waarin de regelscheidingen in de source text nog herkenbaar zijn, het uiteindelijke programma definitief over de segmenten verdeelt. Op dat moment kan de vertaler dus een lijst maken van invariante beginadressen (programma adressen), in de volgorde van opklimmend regelnummer.
(Ik neem aan, dat voor de opeenvolgende programma segmenten opeenvolgende SV's gebruikt kunnen worden, zodat we die niet hoeven te ketenen.) Bij de dynamische plaatsmelding kan deze lijst geraadpleegd worden.

Statische errormelding zal bestaan uit:
1) korte beschrijving van de gemaakte fout. (Omdat we een trommel en een high speed printer hebben, moeten we hiermee niet te karig zijn, dus niet "fout 7")
2) regelnummer.

Dynamische errormelding zal bestaan uit:
1) korte beschrijving van de soort fout (zie boven)
2) plaats.

     Ruwweg komt deze opgave op het volgende neer:
je geeft een regelnummer (afgeleid uit een invariant adres). Via inspectie van de stapel vindt je de aard van het niveau (te weten binnenblok, parameter of fictitious block). Deze aard meldt je; als het een binnenblok is, ga je de dynamische ketting af, totdat je een fictitious block vindt (of de buitenkant). Dan heb je in de stapel een returnadres en vervolgens ga je dat analyseren. Aangezien parameters geen binnenblokken hebben zijn
er dus drie mogelijkheden:
1) parametersituatie
2) block (dwz. buitenste of binnenblok van een procedure)
3) fictitious block.

Opm. Als we het fictitious block gevonden hebben, staat in de stapel het invariante starting address van de procedure, die we wilden verlaten. Een lijstje is voldoende om de procedure identifier er bij te verschaffen.

Post mortem.

     Als we ons op het standpunt stellen, dat een uniforme post mortem reactie (bv. altijd alles) irreeel is, dan laat zich dit als volgt sturen. Vooraan de band (programheading) is een entry, die de aard van de post mortem dump aangeeft. De hier mogelijke notities worden met 1 uitgebreid, die betekent "als een dynamische fout optreedt, vraag dan via toetsenbord". Dit geeft alle mogelijke flexibiliteit zonder last als je er geen behoefte aan hebt. (Je kunt dit uitbreiden met bv. "De lege post mortem notitie in de heading betekent niets".)

     Verder hebben we te dumpen anoniemen, scalairen en arrays.
ad1) de anoniemen zijn wat moeilijk, omdat we de interpretatie niet in de stapel vinden. De dumper kan integers uitprinten en zo mogelijk (tekenconsistentie) ten overvloede paren ook als drijvend getal. De interpretatie van deze rommel is in elk geval voorbehouden aan specialisten (men denke bv. aan de verwisseling van primaries !)

ad2) de scalairen hebben twee moeilijkheden
   2a) bij de scalairen van een expliciet programma moet je, als je enig fatsoen hebt, de indentifiers —zij het dan gereduceerd tot een alphabet— er bij fokken. Taakje voor de vertaler en de trommel!
   2b) bij de handgecodeerde MCP's heb je niet een twee drie een naamlijst. Het alternatief dat we voor de anonymen bedacht hebben, kon hier wel eens aangewezen zijn (format kan hier nl. wisselen.)

ad3) arrays kunnen zo groot zijn. Wat we met arrays in MCP's moeten doen is nog minder duidelijk, maar op dit ogenblik willen we daar niet te veel over denken.

Statische checks zullen omvatten: delimiter structure, identifier matching, correct gebruik (subscripts etc) en type checking. Identifier matching omvat een duidige correspondentie vaststellen tussen gebruik en declaratie, vangen van meervoudige declaratie in een blok, multipele formals, complete specificatie, controle van de value list et.

Dynamische checks omvatten: actual formal correspondence (inclusief tellen aantal parameters) array declaratie (lower bound niet groter dan de upper bound) subscript values within bounds, formal array's test op aantal subscripts, formal left hand side consistency by multiple assignment, complex ~real barrier, sqrt, ln, to the power
integer division, input output control, integer overflow

     Wat we niet checken is: delen door 0, feitelijke assignment in type procedure, undefined variable (grote voorkeur, althans in het begin, voor de uniforme reactie) niet eindigende recursie (maar die wordt via de stack control gevangen) en de blinde loop

transcribed by Sam Samshuijzen
revised Sun, 16 Jan 2005

EWD112 - 0

Ruwe schets vertaalproce

     We zullen proberen om de vertaler in twee left to right scans in elkaar te draaien. In de eerste scan gebeurt onder meer het volgende.

     De heptaden van de invoerstroom worden tot basic characters geassembleerd en in deze vorm wordt de text van het ALGOL programma ten bate van de tweede scan opgeborgen. In deze representatie komen enige non-ALGOL characters voor, zoals "Nieuwe Regel" en "illigitiem", bv. een rare onderlijning. We zullen nl. proberen om bij check alarm de pass in questie af te maken; het is niet gezegd, dat dat kan: immers, als je de executie van een programma beschouwt als "de laatste pass", wat het toch eigenlijk is, dan hebben we inmiddels al besloten, dat we in geval van alarm zullen stoppen.

     Behalve, dat de text in basic characters voor later gebruik wordt opgebouwd, wordt hij in de eerste scan aan een aantal analyses onderworpen. Ten eerste zullen we de delimiter structure zorgvuldig checken; in deze phase zullen we nooit gebruik maken van "de bijbehorende declaratie" omdat die in principe nog ongezien kan wezen.

     Verder is de belangrijkste taak van de eerste scan om de volledige naamlijst op te bouwen. Wij stellen ons voor, dat dit gaat via een stapel, die als transition mechanism gebruikt wordt: hierin worden alle gedeclareerde namen plus de uit deze declaratie volgende en voor de tweede pass relevante gegevens opgenomen. Zodra een blok einde gedetecteerd is, wordt de top van deze naamstapel naar de definitieve naamlijst overgeheveld. Wel moeten we door enige ketening zorgen, dat de boomstructuur van deze naamlijst correct tot uiting gebracht wordt. In deze definitieve naamlijst fokken we dus de namen bloksgewijs in volgorde van blokeinde. Hiermee hebben we bereikt, dat voor dit naamsorteerproces elke naam precies een keer verhuisd wordt. Dit is mooi.

     Neventaak van de eerste scan is om de niet lege regels van de aangeboden text te nummeren en om via de output op herkenbare plaatsen het toegekende regelnummer uit te printen. (Bv. in regels, waarin labels voorkomen en regels, waarin procedures gedeclareerd worden. De output mag zich hier bedienen van een enkel alphabet.) In deze output mag zelfs wel iets van de blokstructuur tot uiting komen; als in de eerste scan al fouten ontdekt worden, komen deze foutmeldingen door dit lijstje heen, maar dit achten we geen bezwaar (we = Cor en ik).

     In de tweede scan wordt het complete ALGOL-programma definitief gemaakt en op segementen ingedeeld. Dit lijkt een beetje moeilijk, maar moet wel meevallen, want we hebben drie machtige kanonnen tot onze beschikking. Ten eerste hebben we de volledige naamlijst met alle declaratiegegevens, die we maar wensen (daar had de eerste pass dan maar voor moeten zorgen). Ten tweede is dit essentieel een vertaler, die het objectprogramma in het geheugen opbouwt, ten derde hebben we de volledige text van het objectprogramma ook al in het geheugen staan en kunnen we de vertaler tamelijk straffeloos een stukje in de toekomst laten kijken.

     Een en ander impliceert wel, dat de routine "read next character" een soortement van juweeltje dient te worden. Ten eerste kent hij twee toestanden: in de eerste fase moet hij het volgende basic character uit de heptaden opbouwen en dumpen, in de tweede fase moet hij "the next character" uit de gedumpte informatiestroom halen. Ter verhoging van de feestvreugde zal hij wel twee pointers moeten hebben, een testpointer en een gehadpointer.

     Dit lijkt in deze staat van "ruwheid" een redelijk overzicht van de taken.

8 december 1964

Transcribed by Frank Steggink
Revised Tue, 6 Jan 2004.

  EWD 113

9 December 1964

Segment Control

(this report replaces EWD84)

Layout of core store and drum store.

     In order to avoid confusion we introduce some new terminology. With the term "segment" we indicate an information unit of 512 words. With the term "page" we indicate a memory unit of 512 consecutive words. Core store and drum store are subdivided into pages, a segment may be stored in a core page, in a drum page or even in both (as we shall see below).

     If the complete drum were available for subdivision into drum pages the number of drum pages accomodated would equal 1023. Drum pages are identified by either drum page number (0 &lt; drum page number &lt; 1022) or by their drum page starting address. The relation between these two quantities is given by (following a suggestion from A.N. Habermann):

     drum page starting address = (1025 * drum page number) (mod 2 ^ 19)
and
     drum page number = drum page starting address (mod 1024).

From this it follows that the first words of drum pages pass the heads in order of (cyclically) increasing drum page number.

     Within core store there will be a Drum Page Table "DPT", which contains one bit per drum page, indicating whether the corresponding drum page is occupied or not. The bits in DPT are arranged in such a way that a simple algorithm (using normalizing orders) can discover the first unoccupied drum page with a number (cyclically) following upon a given value; this algorithm will be used to reduce waiting times for segment transfers from core to drum, whenever this is possible. (In DPT the bits corresponding to non-available drum pages will be turned permanently in the position "occupied": non-availability might result from different sources: parts of the drum may be reserved for standard system routines or a drum page may be defect!)

     The available part of core store will be subdivided into core pages of 512 words. A Core Page Base "CPB" (i.e. its starting address) will be an integral multiple of 512.

     The contents of the core pages are kept track of in the core table with one Core Table Entry "CTE" for each core page. Each CTE will occupy four consecutive words in the core table: the whole of the core table will be permanently in core store in fixed locations. Denoting the base address of a CTE with :CTE the relation between :CTE and CPB is given by

     :CTE = CPB / 128 + core table positionings constant.

     The meaning of the constituent parts of a CTE will be described at a later stage (see below).

     Up till now we have described the identity of pages; now we must describe the identity of segments. With each segment we associate a so-called Segment-Variable. An SV is a one word variable which, during the life time of the associated segment, will be stored permanently on the same core location. During the life time of the segment, the segment can therefore be identified by the physical core address of the SV (denoted below by ":SV").

     A segment variable is a variable because its value will give a clue where the segment associated with it can be found. The meaning of the different SV-values will also be described at a later stage.

States of a core page.

     The mutually exclusive primary states of a core page are
a) Free
b) the Victim
c) Designated
d) occupied.

     When a core page is free, its contents are of no interest, no drum transfers from or towards this page are pending and the page is immediately available for any other purpose. The number of Free core pages may be zero.

     At every moment exactly one core page is designated as "the Victim". Whenever a program wants access to a segment which happens to be on the drum only, a drum to core instruction will be given with the Victim as the destination; at this moment a new Victim will be selected.

     Remark 1. At the moment that the Victim is used as destination for a drum to core transport instruction, its contents may still be of vital importance, viz. for the completion of a pending drum transfer given to dump a segment from core to drum. The difference between the Victim and a Free page is that a Free core page is instantaneously available for any other purpose, whereas the cores of the Victim will become available in due time, i.e. certainly after completion of the pending drum transports.

     Remark 2. Essential use is made of the fact that the drum transports are performed in order in which they are given. If a machine were equipped with two independent drums, say drum A and drum B, and simultaneous transfer possibilities (and two independent chains of transport instructions for the two drums) then analogous techniques seem possible, provided one introduces two victims, Victim A and Victim B. This situation has also been investigated, it did not seem to present additional difficulties. In this report the multidrum situation will not be pursued any further.

     A core page is Designated when it has been decided which segment it is going to contain, while the availability of the segment in this core page will only come into effect after the completion of one or more pending drum transports. As soon as these are completed the page becomes Occupied.

     A core page is Occupied when it contains a segment when the information of this segment is instantaneously available and when the page is not involved in a pending drum transport. Occupied core pages fall into two classes: those that contain an Original, or that contains a Copy. In the first case the segment in question is regarded as being stored in the core page only; if this core page is needed for other purposes, this means that a suitable non-occupied drum page has to be selected, that a core to drum transport has to be given and that care must be taken that this core page will not be used effectively before the completion of this dumping transport. If the core page, however, contains a Copy, this means, that the segment in question is stored on a drum page as well. In that case no dumping transport order has to be given in order to free the core page for other purposes.

     Before describing the possible transitions between these four states of a core page, we must mention the "empty segment". Segments can be introduced, i.e. SV's are introduced; at the moment of introduction, however, they are made to point to "an empty segment". Actual reservation of 512 words of storage is postponed till the moment that the segment is actually used for the first time. (This allows us to "overdeclare" arrays without any appreciable loss.)

State transitions of a core page.

Between the four states six directed transitions are possible; these transitions are instantaneous in the sense that they will be accomplished by an uninterrupted sequence of X8 instructions.

1. Free → Occupied.

     When one of the programs desires access to an empty segment at a moment that the number of free core pages is greater than zero, then one of the Free core pages is supplied to store the segment. This is the only case where a program request for a new segment is granted immediately, bypassing the Segment Controller (see below). With "a new segment" is meant here: a segment not present in core store.

2. Occupied → Free.

     Whenever a program decides that one of its segments ceases to exist (e.g. segments of local arrays at block exit or at stack collapse) and the segment in question occupies a core page, then this core page will become Free.

3. Free → the Victim.

     When the old Victim is used and a new Victim must be chosen, one of the Free core pages (if present) may be selected.

4. Occupied → the Victim.

     When the old Victim is used and a new Victim must be chosen, one of the Occupied pages may be selected. If the Occupied page selected was an Original, this choice implies a dumping transport from core to drum.

5. The Victim → Designated.

     When a new segment request cannot be granted instantaneously, and there is not already a transport order pending that will bring the segment required into core store, then the Victim will act as destination for the new segment. When this new segment has to come from the drum (i.e. was non-empty) then this implies a drum to core transport order.

6. Designated → Occupied.

     The previous five transitions take place under direct control of the program that needs or kills a segment. The sixth transition takes place under control of a special purpose abstract machine, the so-called "Segment Controller". In all cases that a segment request cannot be granted instantaneously, this is due to the fact that one or more pending drum transfers must first be completed. It is the task of the so-called "Segment Contraller" - the progress of which is synchronised with respect to the interrupt signals of the drum transfers - to keep track of these (and other) completions. The main tasks of the controller are
a) to effect the transition Designated → Occupied
b) to notify the program waiting for this completion
c) to do the above at the proper moment.
Its structure will be described in more detail at a later stage.

15 December 1964

The possible values of an SV.

     An SV, SVi say, can be in one of four different states; the first two are applicable when no core page is associated with the segment, the last two when there is a core page associated with the segment.

     No core page association arises in two cases, either because the segment is empty, or because the segment can be found on the drum only.

1. Segment empty.
        SVi = - 0

2. Segment on drum.
        SVi = { d[26]= 1
              { d[25]= 0
              { d[24]....d[0]= DPB, to the left supplied with zeroes.

Legenda. In this description the bits of SV are numbered in the usual manner with d[0].......d[26] in order from right to left, from least to most significant; d[26] is thus the sign bit. With DPB (Drum Page Base) is meant the drum page starting address. (At present it will extend over the 19 bits d[18]...d[0]; this coding leaves room for 63 additional drums!)

     When a segment is associated with a core page we distinguish between two different cases: either the core page is Designated because the segment has not arrived yet in the core page, or its presence is indeed well established in the core page, which is then Occupied. This difference will be indicated in the SVi; the coupling to a core page nr. k will be made by storing in the SVi the :CTEk, i.e. the base address of the corresponding core table entry.

3. Segment in core.
        SVi =:CTEk, to the left supplied with zeroes.

     This will indicate that the segment is to be found in the Occupied core page nr. k.

4. Segment coming.
        SVi = - (:CTEk, to the left supplied with zeroes)

     This will indicate that the segment in question is due to become available in core page nr. k, but that its arrival has not been confirmed yet by the Segment Controller.

     State 4 can be distinguished from state 1 because SV≠0, and from state 2 because d[25] = 1. The above rules imply that the definite presence of a segment in core (state 3) can be established by inspection of (the sign bit of) SVi only.

     Remark. When an Original is chosen as the new Victim the coupling between the SV and the core page is disconnected instantaneously and the SV returns to state 2 "Segment on drum" although in actual fact quite some time (at least one, but maybe many more drum transfers) may elapse before the segment has really arrived in the drum page chosen. The drum transfer start organisation and the segment controller together see to it that
a) the segment will not be read efficively frrom the drum page before it has effectively arrived there
b) the core page will be left untouched until the dumping transfer has been completed.

The possible values of a CTE.

When a core page is Designated or Occupied the four words of its CTE are:

CTE[0] = SVi

CTE[1] = DPB if the (coming) segment is a Copy
       = - 0 if the (coming) segment is an Original

CTE[2] = CPB (= 128 * (:CTE - core table positionings constant))
       This value is a constant in time; it has been introduced to
       speed up the address arithmetic.

CTE[3] = d[26] = 0,
d[25] = 1 when Designated
= 0 when Occupied
d[24]...d[20] = holyness counter (see below)
d[19]....d[0] = interest number (≠ 0)

     When a core page is Free the values are:

CTE[0] = chain element

CTE[1] = - 0

CTE[2] = CPB

CTE[3] = d[26] = 0, d[25] = ......d[0] = 1

     The Free core pages are chained: each CTE[0] contains the :CTE of the next Free core page, if present.

     The CTE corresponding to the Victim has the same layout as that one of a Free core page, but for the fact that CTE[0] is meaningless and unused.

The Segment Controller.

     As we shall see below a seventh core page state transition will be introduced, viz. the transition Occupied → Occupied (but by different segments) following a suggestion made by P.A. Voorhoeve during a discussion of the first half of this report. Also in this transition a segment request will be granted bypassing the Segment Controller.

     The program actions we are going to describe now are the request for an empty segment and the request for a non empty segment.

The request for an empty segment.

     If there are Free core pages a Free core page is selected. (The Free core pages will be chained by their CTE[0] contents and they will be used in stack fashion.) The Victim remains unaltered and the request is granted bypassing the Segment Controller.

     If no Free core pages are present the ruling Victim could be used; this would go via the Segment Controller and as a result the segment would only be handed over to the requesting program "in due time" (see below). Furthermore the use of the ruling Victim always implies the selection of a new Victim. Therefore, in the case of empty segment request without Free core pages the new Victim selection is carried out first. If the choice for the new Victim happens to fall on a core page containing a copy, then this new Victim will be handed over to the requesting program instantaneously; the Segment Controller is bypassed and the (old) Victim retains its position. If the new Victim choice happened to fall upon an original, however, the effort to bypass the Segment Controller has not succeeded. In that case the old Victim will be handed back in due time to the requesting program; for further details, see below.

The request for a non-empty segment.

     If the SV indicates that the segment is non empty, not present in core and not coming, then a drum to core instruction must be given, for which the Victim is chosen as the destination page. then a new Victim must be selected. If there are free core pages, one of them may be chosen; otherwise one of the Occupied core pages with a holyness counter value = 0 (see below) must be selected. This may be a Copy, in which case "uncoupling" of the SV and the CTE is the only action necessary; it may be an Original, in which case a next, but now core to drum, transport instruction must be given. In order to see to it that under no circumstances pages are used effectively before pending transports for such a page are completed each program gives in situations like the above a message to the so-called Segment Controller. The Segment Controller processes these messages in the order in which they have been given to it, but does so in synchronisation with the drum interrupts. Giving a new message to the segment controller is an undividable action; when the message has been given completely the requesting program stops on a semaphore, which will be increased by the Segment Controller when the presence of the segment asked for can be guaranteed by the latter.

     A message to the Segment Controller consists of two halfs, the first half is concerned with the segment asked for, the second half is concerned with the possible drum transfers given to make a new Victim.

     The first half of a message to the Segment Controller contains:
a) an identification of the program semaphore which has to be increased by 1 by the Segment Controller upon completion of the processing of this first half message.
b) a bit indication whether a drum to core transport was part of this first half message
c) if so, the complete specification of the drum transfer in question (taken up in the chain of drum transfers); if not, whether the request was for an empty core page with standard neutral contents. In all cases it will contain the CPB (or the:CTE) of the core page involved.

     The second half of a message contains
a) a bit indicating whether a core to drum transfer was part of this second half message; if not the second half is regarded further as empty
b) if so the complete specification of the drum transfer in question (taken up in the chain of drum transfers).

     The independent programs put their message to the Segment Controller in a cyclic Segment Control Buffer. Upon completion of the message specification (by such an independent program) it signals the presence of a next message to the Segment Controller by means of a V-operation on SCS (Segment Control Semaphore) which is initialized at the value zero (i.e. "no messages").

     Neglecting the tentative recovery measures by the segment controller in the case of error detection in the drum transfers, the basic structure of the Segment Controller is as follows:

"LL: P(SCS);
     if first half under consideration contains drum transport then
                  P(Interrupt Semaphore Drum);
     clerical processing of the first half;
     V(program semaphore specified in the first half under consideration);
     if second half under consideration contains drum transport then
                  P(Interrupt Semaphore Drum);
     cyclic increase of Segment Control Buffer Read Pointer; goto LL"

(we have assumed that offering of messages to the Segment Controller will take place under supervision of a counterpart: the Segment Control Buffer Write Pointer, also to be increased cyclicly.)

     The holyness counter.

     In each program certain privileged segments may occur, which during a certain period of time should be permanently stored in the same core page. Such a period is initiated by "asking for a holy segment", such a period is closed by the inverse operation, viz. "profanation of a segment".

     In the ALGOL organisation examples of holy segments are the stack segments and the program segment under execution.

     We should like to make some remarks.

     The holyness concept is also used whenever a program asks for a segment for, maybe, a single reference, say an array page. When the reference is desired, presence in core of the segment is investigated. If it is present, the reference is made instantaneously. (Between the establishing of the presence and the actual reference, the segment is of course not allowed to disappear from the core; this is, however, taken care of by disabling the interrupt temporarily and the state of holyness remains unchanged in this situation.) When the segment is not in core, the program asks for it, but "holy". When it is allowed to continue, it performs the reference and profanates the segment. Upon arrival of the segment, the Segment Controller signals to the requesting program that it can proceed; by the holyness we have guaranteed that, when the program actually proceeds, the segment asked for is indeed still there!

     The next remark is, that holyness cannot be indicated by a single bit, but by positiveness of a counter. For instance, more different programs may wish access in a holy way to the same segment (say a library segment). In that case the page should continue to contain the segment until all of them have profanated this segment. For that reason we have introduced the holyness counter; profanation means subtraction of 1 from this counter, asking for a holy page means setting the holyness counter to 1 if a new core page must be selected for it, it implies an increase by 1 of the holyness counter, if already a core page was coupled to the segment asked for.

     The concept "multiply holy" is not confined to library pages (remark made by F.J.Hendriks): in the ALGOL system the implementation of simple parameter subroutines has made it desirable to allow each ALGOL program to declare two program segments holy; if these segments happen to coincide its holyness counter will be equal to 2.

     This and the limited number of bits, set aside for the value of the holyness counter in CTE[3] puts an upper limit to the number of concurrently running programs. If they were all general ALGOL programs, this upper limit would be 15 (Remark made by C. Ligtmans). In practice this limit will be higher and is therefore assumed never to be a nuisance.

     The process of Victim selection will be such that never a core page will be chosen with a holyness counter positive. The packing of the holyness bits and the interest number in one single word is made to facilitate the page choice for the new Victim.

     The size of the SEGMENT CONTROL BUFFER.

     In the description of the segment request we have assumed that the Segment Control Buffer was sufficiently large to accept the new message. It is absolutely mandatory ("unbedingt Notwendig"!) that this condition is satisfied! Earlier efforts have been made, where such a buffer could be full, but this gives rise to nearly prohibitive strategical and clerical complications; for during the period of time that the requesting program waits for room in the buffer, the situation in core may have changed! It can be proved that with N concurrently running programs a Segment Control Buffer with a capacity of N + 1 messages is always sufficient.

transcribed by Sam Samshuijzen
revised Mon, 6 Jun 2005

EWD116 - 0

De bankiersalgorithme en verfijningen daarvan

0. Inleiding

In dit rapport wordt de interferentie besproken tussen simultane programma's, zoals deze voortvloeit uit het gemeenschappelijk gebruik van randapparatuur. Aan de restricties, die voortvloeien uit het feit, dat deze verschillende programma's in eenzelfde (eindig) geheugen moeten worden geherbergd, wordt (voorlopig?) geen aandacht geschonken. Onze primaire zorg ten aanzien van deze interferentie is de beheersing ervan, d.w.z. de vermijding van een dodelijke omarming. Onze eerste beschouwing is van toepassing, als het slechts gaat om een enkel soort communicatieapparaat.

1. De bankier met homogene klanten en één valuta

Een bankier (lees "installatie") beschikt over een eindig kapitaal in guldens (lees "bandlezers"). Hij is bereid geld aan klanten (lees "programma's") te lenen op de volgende voorwaarden:

de klant verricht de leningen voor een in de tijd gemeten eindige transactie;

de klant moet van tevoren de maximale omvang van de voor de transactie benodigde lening opgeven;

de klant hoeft niet meteen dit totale bedrag op te nemen en tot het einde toe vast te houden; integendeel, het wordt aangemoedigd, als hij pas om meer geld komt vragen, als hij het nodig heeft en als hij zo gauw mogelijk weer komt afbetalen;

de klant mag niet mopperen, wanneer hij om uitbreiding van zijn lening om meer geld komt en te horen krijgt: "Weliswaar overschrijdt U met deze aanvraag Uw opgegeven maximum niet, maar op dit moment kan ik U het gevraagde niet lenen. Ik zal U bericht sturen, wanneer ik U wel de door U gevraagde lening kan verstrekken";

de garantie, dat dit moment mettertijd zal aanbreken ontleent de klant aan de wijsheid van de bankier en het feit, dat zijn medeklanten aan dezelfde eis gebonden zijn, nl., dat ze, zodra ze over het gevraagde bedrag de beschikking gekregen hebben, met bekwame spoed hun zaken voortzetten, d.w.z. dus in een eindige tijd om meer komen vragen, dan wel terugbetalen, dan wel hun transactie beëindigen;

beëindiging van een transactie, van de bankier-klant contract impliceert dat het geleende bedrag geheel is terugbetaald. Rente wordt niet berekend.

De primaire vragen zijn

onder welke voorwaarden kan de bankier met een zich aanmeldende klant een contract aangaan?

onder welke voorwaarden kan de bankier bij aanvraag van (meer) geld tot uitbetaling overgaan zonder het gevaar te lopen, dat hij wegens dodelijke omarming niet zijn verplichtingen kan nakomen?

Ter verklaring van het verschijnsel van dodelijke omarming het volgende voorbeeld: Een bankier met een kapitaal van 8 gulden heeft twee klanten A en B, die beiden 6 gulden als hun maximale behoefte hebben opgegeven. Als A en B beiden twee gulden hebben opgegeven is er nog geen vuiltje aan de lucht. Wil nu bv. eerst A zijn lening tot 3 uitbreiden, dan mag dat. Komt dan echter B om zijn derde gulden, dan moet uitbetaling aangehouden worden, hoewel er nog 3 gulden in kas is. Zou immers aan B zijn derde gulden uitbetaald worden, dan zou er nog maar 2 gulden in kas overblijven. Als nu A voor zijn voortzetting nog 3 gulden vraagt (waar hij "mettertijd" recht op kan laten gelden) dan kan dit niet gegeven worden en A moet wachten; als echter ook B met zijn zaken in een stadium gekomen is, dat

EWD116 - 1

hij de resterende 3 gulden nodig heeft, voordat hij over terugbetaling kan gaan denken, dan zit de hele troep zo vast als een huis. Dit verschijnsel wordt "de dodelijke omarming" genoemd en het is deze calamiteit, die de bankier in zijn wijsheid dient te voorkomen. Deze alinea ter explicatie.

Vraag a. is gemakkelijk beantwoord: de bankier kan met elke zich aanbiedende klant het contract ondertekenen als de door de klant genoemde behoefte het totale kapitaal van de bankier niet overtreft.

Om vraag b. te beantwoorden voeren wij enige termen in:

De bankier beschikt over een vast "kapitaal". Elke klant biedt zich aan onder opgave van zijn maximale "behoefte".
Er geldt voor elke klant

               "behoefte ≤ kapitaal".

De momentane toestand van een klant is gegeven door zijn "lening"; aanvankelijk is "lening ≡ 0", voor elke klant zal steeds gelden

               "lening ≤ behoefte".

Afhankelijk van deze twee grootheden voeren wij per klant in de "claim", gegeven door

               "claim = behoefte - lening".

De claim is dus het bedrag, dat de klant mogelijk voor de completering van zijn transacties er nog bij wil kunnen eisen.
Tenslotte voeren wij in de zg. "kasvoorraad" gegeven door

               "kasvoorraad = kapitaal - som van de leningen".

Uiteraard geldt "0 ≤ kasvoorraad".

Om te kijken of de bankier bij aanvraag om meer tot uitbetaling kan overgaan, onderzoekt hij de toestand die ontstaan zou zijn als hij tot uitbetaling zou overgaan. Is deze toestand "veilig", dan gaat hij tot uitbetaling over; is deze toestand "onveilig", dan wordt de uitbetaling aangehouden en komt de klant op de wachtlijst. Rest ons te beschrijven, hoe hij de veiligheid van een situatie onderzoekt.

In wezen onderzoekt hij, of hij al zijn klanten nog kan bedienen en hij dus "mettertijd" zijn hele kapitaal kan vrijmaken. Hij voert daartoe in de groep van "bedienbare klanten" (aanvankelijk leeg) en de groep van "te dienen klanten" (aanvankelijk alle klanten omvattend). Voorts voert hij in de hulpgrootheid "vrij te maken bedrag", die aanvankelijk gelijk gemaakt wordt aan de kasvoorraad. Nu begint de algorithme:

Zolang de groep der "te dienen klanten" nog niet leeg is, wordt er hieronder gezocht naar een klant, wiens momentane claim de momentane waarde van het vrij te maken bedrag niet overschrijdt. Wordt zo'n te bedienen klant gevonden, dan wordt hij overgeheveld naar de groep "bedienbare klanten", waarbij tegelijkertijd het "vrij te maken bedrag" met zijn momentane lening vermeerderd wordt, waarna het proces herhaald zal worden. Dit proces kan op twee manieren eindigen:

Doordat op deze wijze de groep "te dienen klanten" leeg wordt, in dit geval is de situatie "veilig";

Doordat, voordat de groep "te bedienen klanten" leeg is, zich hierin geen klant bevindt met een claim, die de inmiddels bereikte waarde van het vrij te maken bedrag niet overschrijdt; in dit geval is de situatie "onveilig".

EWD116 - 2

Opm. Veiligheid kan reeds geconstateerd worden, zodra "vrij te maken bedrag = kapitaal" is; de resterende te bedienen klanten zijn dan a fertion bedienbaar.

Het is duidelijk, dat de bankier, door de situatie steeds veilig te houden, de dodelijke omarming steeds kan vermijden. Men kan ook laten zien, dat zodra de bankier zich tot een onveilige situatie verleiden laat, het behoefte patroon zich zo kan ontwikkelen, dat de dodelijke omarming niet meer is af te wenden.

2. Uitbreiding tot verscheidene in-converteerbare valuta

Het bovenbeschrevene is van toepassing wanneer de onderlinge interferentie tussen programma's zich beperkt tot "vechten om een soort apparaat", zeg "bandlezers", waarbij de ene bandlezer ons iedere keer even lief is als de andere. In de praktijk werden we geconfronteerd met het feit, dat de programma's bandlezers, bandponsers, kaartlezers en wat niet willen bespelen. Deze zijn inconverteerbaar in de zin, dat het bitter weinig helpt, als je voor een programma, dat eigenlijk een bandlezer nodig heeft, probeert te troosten met de mededeling "Pech, maar ik heb nog wel een ponser voor je".

In termen van de bankier komt dit er op neer dat kapitaal, lening, behoefte, claim en kasvoorraad nu niet enkel in guldens, maar in meer dimensies (franken, ponden en kronen) uitgedrukt worden. De passage in de algorithme "een klant wiens momentane clai de momentane waarde van het vrij te maken bedrag niet overschrijdt" dient vervangen te worden door "een klant, van wie geen claim de momentane waarde van de corresponderende kasvoorraad overschrijdt". Verder is de hele algorithme, inclusief het idee van het kasgeld onveranderd bruikbaar.

Transcribed by Frank Steggink
Revised Wed, 7 Jan 2004.

EWD 117

Programming Considered as a Human Activity.

by

Edsger W. Dijkstra

1. Introduction.

By way of introduction I should like to start this talk with a story and a quotation.

The story is about the physicist Ludwig Boltzmann, who was willing to reach his goals by lengthy computations. Once somebody complained about the ugliness of his methods, upon which complaint Boltzmann defended his way of working by stating that "elegance was the concern of tailors and shoemakers", implying that he refused to be troubled by it.

In contrast I should like to quote another famous nineteenth century scientist, George Boole. In the middle of his book "An Investigation of the Laws of Thought" in a chapter titled "Of the Conditions of a Perfect Method." he writes: "I do not here speak of that perfection only which consists in power, but of that also which is founded in the conception of what is fit and beautiful. It is probable that a careful analysis of this question would conduct us to some such conclusion as the following, viz., that a perfect method should not only be an efficient one, as respects the accomplishment of the objects for which it is designed, but should in all its parts and processes manifest a certain unity and harmony". A difference in attitude one can hardly fail to notice.

Our unconscious association of elegance with luxury may be one of the origins of the not unusual tacit assumption that it costs to be elegant. To show that it also pays to be elegant is one of my prime purposes. It will give us a clearer understanding of the true nature of the quality of programs and the way in which they are expressed, viz. the programming language. From this insight we shall try to derive some clues as to which programming language features are most desirable. Finally we hope to convince you that the different aims are less conflicting with one another than they might thought to be at first sight.

2. On the Quality of the results.

Even under the assumption of flawlessly working machines we should ask ourselves the questions: "When an automatic computer produces results, why do we trust them, if we do so?" and after that; "What measures can we take to increase our confidence that the results produced are indeed the results intended?"

How urgent the first question is might be illustrated by a simple, be it somewhat simplified example. Suppose that a mathematician interested in number theory has at his disposal a machine with a program to factorize numbers. This process may end in one of two ways: either it gives a factorization of the number given or it answers that the number given is prime. Suppose now that our mathematician wishes to subject to this process a, say, 20 decimal number, while he has strong reasons to suppose that it is a prime number. If the machine confirms this expectation, he will be happy; if it finds a factorization, the mathematician may be disappointed because his intuition has fooled him again, but, when doubtful, he can take a desk machine and can multiply the factors produced in order to check whether the product reproduces the original number. The situation is drastically changed, however, if he expects the number given to be non-prime: if the machine now produces factors he finds his expectations confirmed and moreover he can check the result by multiplying. If, however, the machine comes back with the answer that the number given is, contrary to his expectations and warmest wishes, alas a prime number, why on earth should he believe this?

Our example shows that even in completely discrete problems the computation of a result is not a well-defined job, well-defined in the sense that one can say: "I have done it." without paying attention the convincing power of the result, viz. to its "quality".

The programmer's situation is closely analogous to that of the pure mathematician, who develops a theory and proves results. For a long time pure mathematicians have thought —and some of them still think— that a theorem can be proved completely, that the question whether a supposed proof for a theorem is sufficient or not, admits an absolute answer "yes" or "no". But this is an illusion, for as soon as one thinks that one has proved something, one has still the duty to prove that the first proof was flawless, and so on, ad infinitum! One can never guarantee that a proof is correct, the best one can say, is: "I have not discovered any mistakes". We sometimes flatter ourselves with the idea of giving watertight proofs, but in fact we do nothing but make the correctness of our conclusions plausible. So extremely plausible, that the analogy may serve as a great source of inspiration.

In spite of all its deficiencies, mathematical reasoning presents an outstanding model of how to grasp extremely complicated structures with a brain of limited capacity. And it seems worthwhile to investigate to what extent these proven methods can be transplanted to the art of computer usage. In the design of programming languages one can let oneself be guided primarily by considering "what the machine can do". Considering, however, that the programming language is the bridge between the user and the machine —that it can, in fact, be regarded as his tool— it seems just as important to take into consideration "what Man can think". It is in this vein that we shall continue our investigations.

3. On the structure of convincing programs.

The technique of mastering complexity is known since ancient times: "Divide et impera" ("Divide and rule"). The analogy between proof construction and program construction is, again, striking. In both cases the available starting points are given (axioms and existing theory versus primitives and available library programs), in both cases the goal is given (the theorem to be proven versus the desired performance), in both cases the complexity is tackled by division into parts (lemmas versus subprograms and procedures).

I assume the programmer's genius matched to the difficulty of his problem and assume that he has arrived at a suitable subdivision of the task. He then proceeds in the usual manner in the following stages:

he makes the complete specifications of the individual parts

he satisfies himself that the total problem is solved provided he had at his disposal program parts meeting the various specifications

he constructs the individual parts, satisfying the specifications, but independent of one another and the further context in which they will be used.

Obviously, the construction of such an individual part may again be a task of such complexity, that inside this part job, a further subdivision is required.

Some people might think the dissection technique just sketched a rather indirect and tortuous way of reaching ones goals. My own feelings are perhaps best described by saying that I am perfectly aware that there is no Royal Road to Mathematics, in other words, that I have only a very small head and must live with it. I, therefore, see the dissection technique as one of the rather basic patterns of human understanding and think it worthwhile to try to create circumstances in which it can be most fruitfully applied.

The assumption that the programmer had made a suitable subdivision finds its reflection in the possibility to perform the first two stages: the specification of the parts and the verification that they together do the job. Here elegance, accuracy, clarity and a thorough understanding of the problem at hand are prerequisite. But the whole dissection techniques relies on something less outspoken, viz. on what I should like to call "The principle of non-interference". In stage II it is assumed that the correct working of the whole can be established by taking, of the parts, into account their exterior specification only, and not the particulars of their interior construction. In stage III the principle of non-interference pops up again: here it is assumed that the individual parts can be conceived and constructed independently from one another.

This is perhaps the moment to mention that, provided I interpret the signs of current attitudes towards the problems of language definition correctly, in some more formalistic approaches the soundness of the dissection technique is made subject to doubt. Their promoters argue as follows: whenever you give of a mechanism such a two stage definition, first what it should do, viz. its specifications, and secondly how it works, you have, at best, said twice the same thing, but in all probability you have contradicted yourself. And statistically speaking, I am sorry to say, this last remark is a strong point. The only clean way towards language definition, they argue, is by just defining the mechanisms, because what they then will do will follow from this. My question: "How does this follow?" is wisely left unanswered and I am afraid that their neglection of the subtle, but sometimes formidable difference between the concepts "defined" and "known" will make their efforts an intellectual exercise leading into another blind alley.

After this excursion we return to programming itself. Everybody familiar with ALGOL 60 will agree that its procedure concept satisfies to a fair degree our requirements of non-interference, both in its static properties (e.g. in the freedom in the choice of local identifiers) as in its dynamic properties (e.g. the possibility to call a procedure, directly or indirectly, from within itself).

Another striking example of increase of clarity through non-interference, guaranteed by structure, is presented by all programming languages in which algebraic expressions are allowed. Evaluation of such expressions with a sequential machine having an arithmetic unit of limited complexity will imply the use of temporary store for the intermediate results. Their anonymity in the source language guarantees the impossibility that one of them will inadvertently be destroyed before it is used, as would have been possible if the computational process were described in a von Neumann type machine code.

4. A comparison of some alternatives.

A broad comparison between a von Neumann type machine code —well known for its lack of clarity— and different types of algorithmic languages may be not out of order.

In all cases the execution of a program consists of a repeated confrontation of two information streams, the one (say "the program") constant in time, the other (say "the data") varying. For many years it has been thought one of the essential virtues of the von Neumann type code that a program could modify its own instructions. In the mean time we have discovered that exactly this facility is to a great extent responsible for the lack of clarity in machine code programs. Simultaneously its indispensability has been questioned: all algebraic compilers I know produce an object program that remains constant during its entire execution phase.

This observation brings us to consider the status of the variable information. Let us first confine our attention to programming languages without assignment statements and without goto statements. Provided that the spectrum of admissible function values is sufficiently broad and the concept of the conditional expression is among the available primitives, one can write the output of every program as the value of a big (recursive) function. For a sequential machine this can be translated into a constant object program, in which at run time a stack is used to keep track of the current hierarchy of calls and the values of the actual parameters supplied at these calls.

Despite its elegance a serious objection can be made against such a programming language. Here the information in the stack can be viewed as objects with nested life times and with a constant value during their entire life time. Nowhere (except in the implicit increase of the order counter which embodies the progress of time) the value of an already existing named object is replaced by another value. As a result the only way to store a newly formed result is by putting it on top of the stack; we have no way of expressing that an earlier value becomes now obsolete and the latter's life time will be prolonged, although void of interest. Summing up: it is elegant but inadequate. A second objection —which is probably a direct consequence of the first one— is that such programs become after a certain, quickly attained degree of nesting, terribly hard to read.

The usual remedy is the combined introduction of the goto statement and the assignment statement. The goto statement enables us with a backward jump to repeat a piece of program, while the assignment statement can create the necessary difference in status between the successive repetitions.

But I have reasons to ask, whether the goto statement as a remedy is not worse than the defect it aimed to cure. For instance, two programming department managers from different countries and different backgrounds —the one mainly scientific, the other mainly commercial— have communicated to me, independently of each other and on their own initiative, their observation that the quality of their programmers was inversely proportional the density of goto statements in their programs. This has been an incentive to try to do away with the goto statement.

The idea is, that what we know as "transfer of control", i.e. replacement of the order counter value, is an operation usually implied as part of more powerful notations: I mention the transition to the next statement, the procedure call and return, the conditional clauses and the for statement; and it is the question whether the programmer is not rather led astray by giving him separate control over it.

I have done various programming experiments and compared the ALGOL text with the text I got in modified versions of ALGOL 60 in which the goto statement was abolished and the for statement —being pompous and over-elaborate— being replaced by a primitive repetition clause. The latter versions were more difficult to make: we are so familiar with the jump order that it requires some effort to forget it! In all cases tried, however, the program without goto statements turned out to be shorter and more lucid.

The origin in the increase in clarity is quite understandable. As is well known there exists no algorithm to decide whether a given program ends or not. In other words: each programmer who wants to produce a flawless program must at least convince himself by inspection that his program will indeed terminate. In a program, in which unrestricted use of the goto statement has been made this analysis may be very hard on account of the great variety of ways in which the program may fail to stop. After the abolishment of the goto statement there are only two ways in which a program may fail to stop: either by infinite recursion —i.e. through the procedure mechanism— or by the repetition clause. This simplifies the inspection greatly.

The notion of repetition, so fundamental in programming, has a further consequence. It is not unusual that inside a sequence of statements to be repeated one or more subexpressions occur, which do not change their value during the repetition. If such a sequence is to be repeated many times, it would be a regrettable waste of time if the machine had to recompute these same values over and over again. One way out of this is to delegate to the now optimizing translator the discovery of such constant subexpressions in order that it can take the computation of their values outside the loop. Without an optimizing translator the obvious solution is to invite the programmer to be somewhat more explicit and he can do so by introducing as many additional variables as there are constant subexpressions within the repetition and by assigning the values to them before entering the repetition. I should like to stress that both ways of writing the program are equally misleading. In the first case the translator is faced with the unnecessary puzzle to discover the constancy, in the second case we have introduced a variable, the only function of which is to denote a constant value. This last observation shows the way out of the difficulty: besides variables the programmer would be served by "local constants", i.e. identifiable quantities with a finite lifetime, during which they will have a constant value, that has been defined at the moment of introduction of the quantity. Such quantities are not new: the formal parameters of procedures already display this property. The above is a plea to recognize that the concept of the "local constant" has its own right of existence. If I am well informed, this has already been recognized in CPL, the programming language designed in a joint effort around the Mathematical Laboratory of the University of Cambridge, England.

5. The double gain of clarity.

I have discussed at length that the convincing power of the results is greatly dependent on the clarity of the program, on the degree in which it reflects the structure of the process to be performed. For those who feel themselves mostly concerned with efficiency as measured in the cruder units of storage and machine time, I should like to point out that increase of efficiency always comes down to exploitation of structure and for them I should like to stress that all structural properties mentioned can be used to increase the efficiency of an implementation. I shall review them briefly.

The lifetime relation satisfied by the local quantities of procedures allows us to allocate them in a stack, thus making very efficient use of available store; the anonymity of the intermediate results enables us to minimize storage references dynamically with the aid of an automatically controlled set of push down accumulators; the constancy of program text under execution is of great help in machines with different storage levels and reduces the complexity of advanced control considerably; the repetition clause eases the dynamic detection of endless looping and finally, the local constant is a successful candidate for a write-slow-read-fast store, when available.

Let me conclude. When I became acquainted with the notion of algorithmic languages I never challenged the then prevailing opinion that the problems of language design and implementation were mostly a question of compromises: every new convenience for the user had to be paid for by the implementation, either in the form of increased trouble during translation, or during execution or during both. Well, we are most certainly not living in Heaven and I am not going to deny the possibility of a conflict between convenience and efficiency, but I do now protest when this conflict is presented as a complete summing up of the situation. I am of the opinion that is worthwhile to investigate to what extent the needs of Man and Machine go hand in hand and to see what techniques we can devise for the benefit of all of us. I trust that this investigation will bear fruits and if this talk made some of you share this fervent hope, it has achieved its aim.

Prof. Dr. Edsger W. Dijkstra
Department of Mathematics
Technological University
P.O.Box 513
EINDHOVEN
The Netherlands

transcribed by Nolan Egly
revised Thu, 8 Jul 2010

EWD118 - 0

3 Februari 1965

Communicatiebuffering voor de EL-X8 - T.H.E.

Algemeen

De mogelijkheid communicatie-informatie te bufferen is een faciliteit van de installatie als geheel: de bufferruimte wordt dan ook niet bij speciale programma's ondergebracht, maar "universaliter", zoals de tabel van de SV's van de bibliotheek.

Dit doet ons leed, want het impliceert een permanente kerngeheugenbezetting voor de SV-lijst van de buffersegmenten. Toch moet het maar; wij denken aan, zeg 256 SV's (d.w.z. maximaal &Mac185; trommel vol gebufferde transput informatie).

Naast de 256 SV's zullen wij extra ruimte ter beschikking stellen om hierin kettingen van segmenten te rijgen.

Analyse van de Segment Controller heeft aangetoond, dat het niet ondoenlijk is om SV's te verhuizen; dit maakt het mogelijk, dat een producent een segment als privé segment vult, en als het vol is de informatie naar de bufferruimte overhevelt, zonder de informatie "vleselijk" te transporteren. Er hoeft slechts een SV verhuisd te worden

Invoer via bandlezers

De invoer via bandlezers behandelen we apart, omdat we deze tamelijk afwijkend bedienen.

De PM's nemen niet rechtstreeks contact met de bandlezers op, maar doen dit via een informatiestroom, waarvan de opbouw ver op de consumptie vóór mag zijn. Men kan denken dat de bandlezer zo snel is, dat dit nauwelijks de moeite waard is; wij moeten dit echter wel doen, omdat de buffering de enige manier is om de bandlezer zo gauw mogelijk vrij te maken.

Elke PM krijgt slechts de beschikking over een enkele papierband-informatiestroom; het feit dat er (wellicht) meer bandlezers aan de installatie zitten komt niet de individuele programma's, maar het samenspel ten goede.

Om deze impliciete invoerstroom hoeft een programma niet te vragen: hij was er kennelijk al, toen het programma ingevoerd ging worden.

Wij zagen twee wegen: òf de bandlezers in de bankiersalgorithme betrekken en van de programmeur verlangen, dat hij de interesse "afmeldt" wanneer hij zijn laatste gegeven heeft ingelezen òf het er maar op wagen, d.w.z. niet de programmeur laten verklaren dat hij niet meer lezen wil, en, omgekeerd, de bandlezers buiten het bankiersalgorithme te houden. Wij hebben - tegen alle regels in! - tot het laatste besloten. Om het ruimtebeslag in de buffer te mitigeren hebben we wel besloten, om in de informatiestroom van de lezers het bandbeeld gepakt te bergen. (Een pakking van 2000 karakters per segment geeft bij volle band van 300 meter à 400 kar. per meter 60 segmenten. Dat is natuurlijk niet mals, maar het zij zo.)

Wij hebben dit onder anderen gekozen, omdat wij niet veel vertrouwen hebben in de zo moeilijk afdwingbare plicht tot afmelden. (Wij doen ons best onze programmeurs niet te hoog aan te slaan!)

EWD118 - 1

Reservering van een bandlezer voor de opbouw van een bepaalde informatiestroom valt onherroepelijk af bij de detectie van "einde band".

Deze informatiestromen zijn objecten, die elk behoren bij een bepaalde PM. We kunnen ons het "handvat" onderin de stapel van de PM voorstellen. (Geheugenprotectie schept wel problemen, want de producent moet bij het handvat kunnen, maar de producent is tenslotte een stamgast, die moet weten wat hij doet.)

Over de gedetailleerde layout van het handvat doen we nu geen voorstel. Wij merken op, dat er onderscheid gemaakt moet worden tussen "informatiestroom nuchter" - d.w.z. niet eens in opbouw - en "informatiestroom leeg", d.w.z. het komt wel, maar er zit geen enkel segment in de bufferruimte. Het handvat bevat de seinpaal, via welke de producent toevoeging van één nieuw segment aan de consument doormeldt. Het handvat bevat tevens een identificatie van de producent - om vrij te kunnen maken in geval van desaster, b.v.

Plotter, printer & ponser

Wij nemen aan, dat een plotter, die aan een bepaald plaatje begonnen is, dit plaatje moet kunnen afmaken, voordat hij aan een ander plaatje begint. Voorts stellen wij, dat een plotterprent potentieel zo uitgebreid kan zijn, dat wachten met output, het programma "einde plaatje" heeft gemeld, prohibitief zou kunnen zijn. Hieruit volgt, dat met 1 physische plotter, geen PM via twee "abstracte" kanalen, twee - willekeurig uitgebreide - plaatjes kan gaan tekenen. Wij voorkomen dit door geen PM het uitdrukkingsvermogen te geven om aan meer dan een plaatje bezig te zijn. Bij voorkeur zal de plotter (zie onder) slechts aan plaatjes beginnen, waarvan de specificatie volledig voltooid is.

Ook voor bandponsers geldt, dat we bij voorkeur slechts een ponser aan het ponsen van een bandje zullen laten beginnen, als het bandbeeld geheel is opgebouwd. Als dit nl. zo is, kan de machine controleren, of er nog genoeg papier op de rol is. Moet een ponser aan een onaf bandbeeld beginnen, dan zal hij vragen om een nieuwe band in de ponser.

Tenslotte: de highspeed printer verwerkt van de programma's de informatie "formuliersgewijs". Als echter twee programma's met dezelfde snelheid formulieren aanbieden is het voor de receptie hoogst onaangenaam, als de formulieren om de ander komen. Ook hier hebben we dus zoiets, dat de formulier printer - zo mogelijk - affe teksten produceren.

Ondanks de verschillen zullen wij proberen, deze drie apparaten zo gelijk mogelijk te bespreken.

Het volgende beeld werd in eerste instantie voor de plotter(s) ontwikkeld. Wij zullen straks bekijken, in hoeverre het ook voor de andere gereedschap van toepassing is. Wij praten dus eerst even over de plotter(s).

Kwantitatief spelen twee aantallen een grote rol: het aantal physische apparaten en het aantal "documenten in opbouw". (Een "document" is voor een plotter een plaatje, voor een bandponser een noodzakelijkerwijze onverknipte band.)

EWD118 - 2

Wij stellen ons voor, dat een physisch apparaat niet aan het volgende document begint, voordat het vorige is voltooid. (Bij de plotter is dat niet strikt noodzakelijk!) Wij gaan er verder van uit, dat een document zo omvangrijk kan zijn, dat het onredelijk is om a priori te eisen, dat het in zijn totaliteit gebufferd moet kunnen worden, voordat aan de feitelijke uitvoer begonnen wordt. (Dit is voor de ponser weer wat restrictief, omdat de lengte van een physische band wel aan een bovengrens gebonden is.)

Voor een bepaald soort physisch apparaat voeren wij in "de uitvoerders" - in evenveelvoud als er physische apparaten zijn - en "de prae-uitvoerders". Elke prae-uitvoerder is de mogelijkheid om een eventueel "onbegrensd" document te gaan opbouwen. Prae-uitvoerders zijn geprogrammeerde instituten, hun aantal kan in overigens identieke installaties verschillen.

De programmeur kent het verschil tussen de prae-uitvoerder en de uitvoerder niet. Als hij als zijn behoefte opgeeft b.v. "1 plotter", dan wordt deze behoefte ten bate van de bankier vertaald in "1 praeplotter + 1 plotter". Als hij aangeeft, dat hij een document wil gaan opbouwen, dan wordt dit vertaald in de poging een prae-uitvoerder te lenen. Nu krijgt de PM een prae-uitvoerder toegewezen: hij kan nu het document opbouwen - mogelijk hierin geremd door een P-operatie op vrijkomende bufferruimte en tenslotte wordt van hem verwacht, dat hij het document "voltooid" meldt. Op dit moment komt de prae-uitvoerder vrij en kan een andere - of dezelfde - PM aan documentopbouw beginnen.

Als er n prae-uitvoerders en m echte uitvoerders zijn, spelen achter de schermen n + m overigens equivalente informatiestromen een rol: hiervan zijn op elk moment een ten hoogste n-tal "de prae-uitvoerders". (Deze som komt voort uit het volgende: elke physische uitvoerder kan bezig zijn met de consumptie van een inmiddels af document; daarnaast zijn n documenten in opbouw.)

Als een PM een document voltooid meldt, dan moeten wij twee getallen onderscheiden: of een feitelijke uitvoerder was reeds aan de consumptie van deze stroom begonnen of niet. Zo nee, dan wordt het voltooide, onbegonnen beeld aan de z.g. "documentenketting" gehangen. Naast genoemde informatiestromen die hoogstens één document in opbouw, in afbraak of beide bevatten, is er nl. nog een ketting van voltooide documenten. In deze ketting worden klare documenten opgenomen in volgorde van voltooiïng; in deze zelfde volgorde zal later aan hun feitelijke uitvoer begonnen worden. (N.b.: bij meer uitvoerders betekent dit niet, dat ze de een na de ander in volgorde uitgevoerd hoeven te worden!) Verder wordt een prae-uitvoerder vrijgegeven.

Als bij voltooiïng van het documentbeeld wel reeds een physische uitvoerder aan de feitelijke consumptie begonnen was, wordt de documentenketting met rust gelaten, maar wordt aan de bankier beëindiging van lening gemeld van niet alleen een prae-uitvoerder, amar ook van een uitvoerder. (Zie onder.)

Een vrij ledige uitvoerder handelt als volgt:
Als de documentenketting niet leeg is, zoekt hij uit de m + n informatiestromen een ongebruikte (die is er!) en initieert deze stroom met het kopdocument uit de ketting. Vervolgens gaat hij uit deze stroom consumeren.

EWD118 - 3

Als de documentenketting leeg is, kan hij, wanneer er wel documenten in opbouw zijn, proberen, of hij al vast aan de uitvoer van een onaf document beginnen kan. Het beginnen aan een onaf document betekent echter dat het opbouwende programma vanaf dat moment geacht wordt behalve een prae-uitvoerder ook een uitvoerder geleend te hebben. De uitvoerder mag zich dus slechts onder controle van de bankier aan een onaf document beginnen.

Als een uitvoerder zichzelf uit de documentenketting initieert, is dit een aflopende taak: de uitvoerder kan zich op daggeldbasis ter beschikking stellen en omarmingsrestricties worden hierdoor aanmerkelijk milder.

Het idee van de prae-uitvoerders is dus om zo mogelijk op daggeldbasis van de physische uitvoerders gebruik te maken; dit is des te interessanter naarmate de beschikbare bufferruimte groot is ten opzichte van voorkomende document omvangen.

Een en ander werpt wel strategische problemen op, speciaal: hoeveel prae-uitvoerders kiezen we en wanneer beslissen we, dat een uitvoerder begint aan de uitvoer van een onaf document. (De mogelijkehid zulks te doen wordt door de bankier afgeperkt: als het mogelijk is, hoeft de uitvoerder het echt nog niet te doen.)

Een enkel voorbeeld moge de strategische problemen nader illustreren. Stel, dat we in een installatie van een bepaald type 1 uitvoerder hebben, maar meer prae-uitvoerders en stel, dat de installatie geladen is met een programma, dat een niet ontiegelijk omvangrijk document heel traag vult (een z.g. "druppelaar"). Zolang de omvang van de gebufferde informatiestroom nog geen onbehoorlijke proporties heeft aangenomen, is het zaak, de uitvoerder nog niet aan de uitvoer te laten beginnen: dit kan de physische uitvoerder nl. nodeloos lang bezig houden. En inderdaad: terwijl de druppelaar moeizaam zijn document opbouwt, komt een extra programma, een "vluggertje", die eventjes een snel produceerbaar document wil uitvoeren; van de kant van de machine is dit een ideale "mix'. Het tweede programma gaat document produceren: als nu dit tweede document - b.v. omvangrijk - niet eerst in zijn geheel gebufferd kan worden, moet het physisch apparaat wegens gebrek aan bufferruimte op een gegeven moment aan een van beide documenten beginnen. Hoe besturen we, dat hij dan aan het document van het vluggertje begint?

Er zijn twee oplossingen: als een uitvoerder aan een onaf physisch document moet beginnen - wegens uitputting van de bufferruimte - laat hem dan in geval van keuze de langste informatiestroom kiezen: dit helpt het meeste. In boven beschreven situatie moet je dus hopen dat op het moment dat tot uitvoer besloten wordt, de producenten van het vluggertje de productie van de druppelaar inmiddels heeft ingehaald. (Je moet dus met het vluggertje wel "op tijd" komen: dat moet toch, want als de druppelaar definitief aan de uitvoerder gekoppeld is, dan heb je het gehad en komt het vluggertje toch al niet meer aan bod. Deze inhaaloverweging stelt de grens van "op tijd zijn" alleen wat scherper.)

Er is een andere techniek, nl. die der vrijheidsklassen. Hierin kent men aan elk programma een vrijheidsnummer toe: de bankier hanteert nu als nevenvoorwaarde, dat een programma met hoger vrijheidsnummer voor zijn voortzetting niet op de voortzetting van - d.w.z. vrijgave door - een programma uit een lagere vrijheidsklasse afhankelijk mag zijn. Door

EWD118 - 4

de druppelaar dan een lager vrijheidsnummer te geven dan het vluggertje forceert men dat
a) het vluggertje alleen geaccepteerd wrodt als de uitvoerder nog niet aan het document van de druppelaar begonnen is,
b) daarna de feitelijke uitvoer van het document van het vluggertje de voorrang krijgt.

Of de invoering van het vrijheidsgetal geen nadere complicaties met zich meebrengt - afgezien ervan, dat men het moet definiëren - moet een nadere analyse nu uitmaken.

Zonder invoering van het vrijheidsgetal kan men altijd (logisch) straffeloos een vrije uitvoerder aan minstens een van de onaffe documenten laten beginnen. Immers: dit geldt als een lening van de uitvoerder. Voordat deze koppeling tot stand gekomen is, was de toestand veilig, d.w.z. de bankier zag al zijn programma's op den duur eindigen, d.w.z. kon dit programma in een zekere volgorde verifiëren: het eerste prae-ponsende programma, waarvan hij de doorgang garanderen kan, mag dus ook de feitelijke uitvoerder op dit moment willen lenen. Houdt ook na introducite van het vrijheidsgetal deze redenering stand?

In dat geval onderzoekt de bankier eerst of de programma's uit de hoogste vrijheidsklasse door kunnen gaan. Hieronder kunnen er zijn, die wel prae-uitvoerder en uitvoerder geclaimd, maar nog niet geleend hebben. Vervolgens worden de programma's uit de daaronder liggende klasse onderzocht: hier kan het eerste prae-uitvoerende programma ontmoet worden, dat evenwel de uitvoerder zelf niet lenen mag, omdat dan een programma uit hogere vrijheidsklasse in de knoei zou kunnen komen.

Moraal is: zonder vrijheidsklasse kan altijd de uitvoerder aan minstens 1 niet leeg onaf document beginnen. Met vrijheidsklasse - en vrije prae-uitvoerders - is het mogelijk de uitvoerder voor een nog lege prae-uitvorder te reserveren!

Het voorgaande dekt vrij aardig de bandponser en de plotter: de highspeed printer is een ander chapiter.

Om te beginnen: het lijkt irreëel om voor de printer het aantal prae-uitvoerders lager te kiezen dan het aantal PM's ("een programma, dat niet print is nauwelijks een programma").
Als wij ons op het standpunt stellen, dat de printer snel is, dat de programmeur snel zijn gegevens naar buiten wil hebben, dan zou men zeggen: beschouw een formulier van de printer als "document", zodra dit klaar is, neem het dan in de ketting op. Anderzijds is dit onacceptabel: het scheur- en sorteerwerk, dat hierdoor voor de expeditie zou ontstaan is gewoon te erg. En dan ga je dus zeggen: beschouw aan elke prae-uitvoerder "N" formulieren als document. Maar hoe groot kies je "N"?

Het is duidelijk, dat beëindiging van het programma de prae-uitvoerder vrijgeeft en het staartje formulieren als document naar de ketting kan overhevelen. Dan is er ten duidelijkste werk voor de printer. Als de documentenketting leeg is, begint de printer (beginnen de printers) pas actief te worden als de totale omvang van de gebufferde informatie daartoe aanleiding geeft. Het ligt voor de hand, om dan uit een informatiestroom, die begint met het oudste document of de informatiestroom, die het grootste aantal formulieren bevat? Mijn neiging is om de tijdsfactor te verwaarlozen - er komen geen programmeurs in de machinekamer - en de langste informatiestroom te pakken.

Transcribed by Frank Steggink
Revised Tue, 6 Jan 2004.

EWD 123

Cooperating sequential processes

Table of Contents.

Preface.

0. Introduction

1. On the Nature of Sequential Processes.

2. Loosely Connected Processes.

2.1 . A Simple Example.

2.2. The Generalized Mutual Exclusion Problem.

2.3. A Linguistic Interlude.

3. The Mutual Exclusion Problem Revisited.

3.1. The Need for a More Realistic Solution.

3.2. The Synchronizing Primitives.

3.3. The Synchronizing Primitives Applied to the Mutual Exclusion Problem.

4. The General Semaphore.

4.1. Typical Uses of the General Semaphore.

4.2. The Superfluity of the General Semaphore.

4.3. The Bounded Buffer.

5. Cooperation via Status Variables.

5.1. An Example of a Priority Rule.

5.2. An Example of Conversations

5.2.1. Improvements of the Previous Program.

5.2.2. Proving the Correctness.

6. The Problem of the Deadly Embrace.

6.1. The Banker's Algorithm.

6.2. The Banker's Algorithm Applied

7. Concluding Remarks.

Preface

The main purpose of this preface is to explain the specification "Preliminary Version", appearing on the title page of these lecture notes. They have been prepared under considerable tine pressure, circumstances under which I was unable to have my use of the English language corrected by a native, circumstances under which I was unable first to try out different methods of presentation. As they stand, I hope that they will serve their two primary purposes: to give my students a guide as to what I am telling and to give my Friends and Relations an idea of what I am doing.

The future fate of this manuscript, that may prove to be a monograph in statu nascendi, will greatly depend on their reactions to it. I am greatly indebted, in advance, to any reader who is so kind as to take the trouble to give his comments, either in the form of suggestions how the presentation or the material itself could be improved, or in the form of an appreciation. From the latter comments I will try to get an idea whether it is worth-while to pursue this effort any further and to prepare a publication fit for and agreeable to a wider public.

Already at this stage I should like to express my gratitude to many: to my collaborators C.Bron (in particular for his scrutinous screening of the typed version), to A.N.Habermann, F.J.A.Hendriks, C.Ligtmans and P.A. Voorhoeve for many stimulating and clarifying discussions on the subject itself, to the Department of Mathematics of the Technological University, Eindhoven, for the opportunity to spend my time on the problems dealt with and to lecture on their solutions and also —trivial as it may seem, this is nevertheless vital:— for putting at my private disposal a type writer with a character set in complete accordance with my personal wishes.

E.W.Dijkstra

Department of Mathematics
Technological University
P.O. Box 513
EINDHOVEN
The Netherlands

0. Introduction.

These lectures are intended for all those that expect that in their future activities they will become seriously involved in the problems that arise in either the design or the more advanced applications of digital information processing equipment; they are further intended for all those that are just interested.

The applications I have in mind are those in which the activity of a computer must include the proper reacting to a possibly great variety of messages that can be sent to it at unpredictable moments, a situation which occurs in process control, traffic control, stock control, banking applica- tions, automization of information flow in large organizations, centralized computer service and, finally, all information systems in which a number of computers are coupled to each other.

The desire to apply computers in the ways sketched above has often a strong economic motivation, but in these lectures the not unimportant ques- tion of efficiency will not be stressed too much. We shall occupy ourselves much more with the logical problems which arise, for example, when speed ratios are unknown, communication possibilities restricted etc. We intend to do so in order to create a clearer insight into tie origin of the difficulties we shall meet and into the nature of our solutions. To decide whether under given circumstances the application of our techniques is economically attractive or not falls outside the scope of these lectures.

I regret that I cannot offer a fully worked out theory, complete with Greek letter formulae, so to speak. The only thing I can do under the present circumstances is to offer a variety of problems, together with solutions. And in discussing these, we can only hope to bring as much system into it as we possibly can, to find which concepts are relevant, as we go along. May everyone that follows me along this road enjoy the fascination of these intriguing problems as much as I do!

1. On the Nature of Sequential Processes.

Our problem field proper is the cooperation between two or more sequential processes. Before we can enter this field, however, we have to know quite clearly what we call "a sequential process". To this preliminary question the present section is devoted.

I should like to start my elucidation with the comparison of two machines to do the same example job, the one a non-sequential machine, the other a sequential one.

Let us assume that of each of four quantities, named "a[1]", "a[2]", "a[3]" and "a[4]" respectively, the value is given. Our machine has to process these values in such a way that, as its reaction, it "tells" us, which of the four quantities has the largest value. E.g. in the case:

a[1] = 7, a[2] = 12, a[3] = 2, a[4] = 9

the answer to be produced is "a[2]" (or only "2". giving the index value pointing to the maximum element).

Note that the desired answer would become incompletely defined if the set of values were —in order— "7, 12, 2, 12". for then there is no unique largest element and the answer "a[2]" would have been as good (or as bad) as "a[4]". This is remedied by the further assumption, that of the four values given, no two are equal.

Remark 1. If the required answer would have been the maximum value occuring among the given ones, then the last restriction would have been superfluous, for then the answer corresponding to the value set "7, 12, 2, 12" would have been "12".

Remark 2. Our restriction "Of the four values no two are equal" is still somewhat loosely formulated, far what do we mean by "equal"? In the processes to be constructed pairs of values will be compared with one another and what is really meant is, that every two values will be sufficiently different, so that the comparator will unambiguously decide, which of the two is the largest one. In other words, the difference between any two must be large compared with "the resolving power" of our comparators.

We shall first construct our non-sequential machine. When we assume our given values to be represented by currents, we can imagine a comparator consisting of a two-way switch, the position of which is schematically controlled by the currents in the coils of electromagnets as in Fig.1 and Fig.2.

Fig. 1. x < y | Fig. 2. y < x

When current y is larger than current x, the left electromagnet pulls harder than the right one and the switch switches to the left (Fig.l) and the input A is connected to output B; if current x is the larger one, we shall get the situation (Fig.2) where the input A is connected to output C.

In our diagrams we shall omit the coils and shall represent such a comparator by a small box

only representing at the top side the input and at the bottom side the two outputs. The currents to be led through the coils are identified in the question written inside the box and the convention is, that the input will be connected to the right hand side output when the answer to the question is "Yes", to the left hand side output when the answer is "No".

Fig. 3.

Now we can construct our machine as indicated in Fig.3. At the output side we have drawn four indicator lamps, one of which will light up to indicate the answer.

In Fig.4 we indicate the position of the switches when the value set "7, 12, 2, 9" is applied to it. In the boxes the positions of the switches are indicated, wires not connected to the input are drawn blotted.

Fig.4.

We draw the reader's attention to the fact that now only the positions of the three switches that connect output 2 to the input, matter; the reader is invited to convince himself that the position of the other three switches is indeed immaterial.

It is also good to give a moment attention to see what happens in time when our machine of Fig.3 is fed with four "value currents". Obviously it cannot be expected to give the correct answer before the four value currents are going through the coils. But one cannot even expect it to indicate the correct answer as soon as the currents are applied, for the switches must get into their correct position and this may take some time. In other words: as soon as the currents are applied (simultaneously or the one after the other) we must wait a period of time —characteristic for the machine— and after that the correct answer will be shown at the output side. What happens in this waiting time is immaterial, provided that it is long enough for all the switches to find their final position. They may start switching simultaneously, the exact order in which they attain their final position is immaterial and, therefore, we shall not pay any attention to it any more.

From the logical point of view the switching time can be regarded as a marker on the time axis: before it the input data have to be supplied, after it the answer is available.

In the use of our machine the progress of time is only reflected in the obvious "before - after" relation, which tells us, that we cannot expect an answer before the question has been properly put. This sequence relation is so obvious (and fundamental) that it cannot be regarded as a characteristic property of our machine. And our machine is therefore called a "non-sequential machine" to distinguish it from the kind of equipment —or processes that can be performed by it— to be described now.

Up till now we have interpreted the diagram of Fig.3 as the (schematic) picture of a machine to be built in space. But we can interpret this same diagram in a very different manner if we place ourselves in the mind of the electron entering at the top input and wondering where to go. First it finds itself faced with the question whether "a[l] < a[2]" holds. Having found the answer to this question, it can proceed. Depending on the previous answer it will enter one of the two boxes "a[1] < a[3]" or "a[2] < a[3]", i.e. it will only know what to investigate next, after the first question has been answered. Having found the answer to the question selected from the second line, it will know which question to ask from the third line and having found this last answer it will now know which bulb should start to glow. Instead of regarding the diagram of Fig.3 as that of a machine, the parts of which are spread out in space, we have regarded it as rules of behaviour, to be followed in time.

With respect to our earlier interpretation two differences are highly significant. In the first interpretation all six comparators started working simultaneously, although finally only three switch positions matter. In the second interpretation only three comparisons are actually evaluated —the wondering electron asks itself three questions— but the price of this gain is that they have to be performed the one after the other, as the outcome of the previous one decides what to ask next. In the second interpretation three questions have to be asked in sequence, the one after the other. The existence of such an order relation is the distinctive feature of the second interpretation which in contrast to the first one is therefore called "a sequential process". We should like to make two remarks.

Remark 3. In actual fact, the three comparisons will each take a finite amount of time (switching time", "decision time" or, to use the jargon, "execution time") and as a result the total time taken will at least be equal to the sum of these three execution times. We stress once more, that for many investigations these executions can be regarded as ordered markers on a scaleless time axis and that it is only the relative ordering that matters from this (logical) point of view.

Remark 4. As a small side line we note that the two interpretations (call them "simultaneous comparisons" and "sequential comparisons") are only extremes. There is a way of, again, only performing three comparisons, in which two of them can be done independently from one another, i.e. simultaneously; the third one, however, can only be done, after the other two have been completed. It can be represented with the aid of a box in which two questions are put and which, as a result, has four possible exits, as in Fig.5.

Fig.5.

The total time taken will be at least the sum of the comparison execution times. The process is of the first kind in the sense that the first two comparisons can be performed simultaneously, it is of sequential nature as the third comparison can only be selected from the second line when the first two have both been completed.

We return to our purely sequential interpretation. Knowing that the diagram is meant for purely sequential interpretation we can take advantage of this circumstance make the description of the "rules of behaviour" more compact. The idea is, that the two questions on the second line —only one of which will be actually asked— are highly similar: the questions on the same line only differ in the subscript value of the left operand of the comparison. And we may ask ourselves: "Can we map the questions on the same line of Fig.3 on a single question ?"

This can be done, but it implies that the part that varies along a line —i.e. the subscript value in the left operand— must be regarded as a parameter, the task of which is to determine which of the questions mapped on each other is meant, when its turn to be executed has come. Obviously the value of this parameter must be defined by the past history of the process.

Such parameters, in which past history can be condensed for future use are called variables. To indicate that a new value has to be assigned to it we use the so-called assignment operator ":=" (read: "becomes"), a kind of directed equality sign which defines the value of the left hand side in terns of the value of the right hand side.

We hope that the previous paragraph is sufficient for the reader to recognize also in the diagram of Fig.6 a set of "rules of behaviour". Our variable is called i; if the reader wonders, why the first question, which is invariably "a[l] < a[2] ?" is not written that way, he is kindly requested to have some patience.

Fig.6

When we have followed the rules of Fig.6 as intended from top till bottom, the final value of i will identify the maximum value, viz. a[i].

The transition from the scheme of Fig.3 to the one of Fig.6 is a drastic change, for the last "rules of behaviour" can only be interpreted sequentially. And this is due to the introduction of the variable i: having only a[1], a[2], a[3] and a[4] available as values to be compared, the question "a[i] < a[2] ?" is meaningless, unless it is known for which value of i this comparison has to be made.

Remark 5. It is somewhat unhappy that the jargon of the trade calls the thing denoted by i a variable, because in normal mathematics, the concept of a variable is a completely timeless concept. Time has nothing to do with the x in the relation

sin(2 * x) = 2 * sin(x) * cos(x) ;

if such a variable ever denotes a value, it denotes "any value".

Each time, however, that a variable in a sequential process is used —such as i in "a[i]"— it denotes a very specific value, viz. the last value assigned to it, and nothing else! As long as no new value is assigned to a variable, it denotes a constant value!

I am, however, only too hesitant to coin new terms: firstly it would make this monograph unintendedly pretentious, secondly I feel that the (fashionable!) coining of new terms often adds as much to the confusion in one way as it removes in the other. I shall therefore stick to the term "variable".

Remark 6. One may well ask, what we are actually doing, when we introduce a variable without specifying, for instance, a domain for it, i.e. a set of values which is guaranteed to comprise all its future actual values. We shall not pursue this any further here.

Now we are going to subject our scheme to a next transformation. In Fig.3 we have "wrapped up" the lines, now we are going to wrap up the scheme of Fig.6 in the other direction, an operation to wich we are invited by the repetitive nature of it and which can be performed at the price of a next variable, "j" say.

Fig.7

The change is a dramatic one, for the fact that the original problem was to identify the maximum value among four given values is no longer reflected in the "topology" of the rules of behaviour: in Fig.7 we only find the number "4" mentioned once. By introducing another variable, say n, and replacing the "4" in Fig.7 by n we have suddenly the rules of behaviour to identify the maximum occurring among the n elements a[1], a[2], .......,a[n] and this practically only for the price that before application, the variable n must be put to its proper value.

I called the change a dramatic one, for now we have not only given rules of behaviour which must be interpreted sequentially —this was already the case with Fig.6— but we have devised a single mechanism for identifying the maximum value among any number of given elements, whereas our original non-sequential machine could only be built for a previously well-defined number of elements. We have mapped our comparisons in time instead of in space, and if we wish to compare the two methods, it is as if the sequential machine "extends itself" in terms of Fig.3 as the need arises. It is our last transition which displays the sequential processes in their full glory.

The technical term for what we have called "rules of behaviour" is an algorithm or a program. (It is not customary to call it "a sequential program" although this name would be fully correct.) Equipment able to follow such rules, "to execute such a program" is called "a general purpose sequential computer" or "computer" for short; what happens during such a program execution is called "a sequential process".

There is a commonly accepted technique of writing algorithms without the need of such pictures as we have used, viz. ALGOL 60 ("ALGOL" being short for Algorithmic Language). For a detailed discussion of ALGOL 60 I must refer the reader to the existing literature. We shall use it in future, whenever convenient for our purposes.

For the sake of illustration we shall describe the algorithm of Fig.7 (but for n instead of "4") by a sequence of ALGOL statements:

      i:= 1; j:= 1;
back: if j ≠ n then
        begin j:= j + 1;
              if a[i] < a[j] then i:= j;
              goto back
        end .

The first two statements: "i:=l; j:= 1" are —I hope— self-explanatory. Then comes "back:", a so-called label, used to identify this place in the program. Then comes "if j ≠ n then", a so-called conditional clause. If the condition expressed by it is satisfied, the following statement will be performed, otherwise it will be skipped. (Another example of it can be found two lines lower.) When the extent of the program which may have to be skipped presents itself primarily as a sequence of more than one statement, then one puts the so-called statement brackets "begin" and "end" around this sequence, thereby making it into a single statement as far as its surroundings are concerned. (This is entirely analogous to the effect of parentheses in algebraic formulae, such as "a * (b + c)" where the parenthesis pair indicates that the whole expression contained within it is to be taken as factor.) The last statement "goto back" means that the process should be continued at the point thus labeled; it does exactly the same thing for us as the upward leading line of Fig.7.

2. Loosely Connected Processes.

The subject matter of this monograph is the cooperation between loosely connected sequential processes and this section will be devoted to a thorough discussion of a simple, but representative problem, in order to give the reader some feeling for the problems in this area.

In the previous section we have described the nature of a single sequential process, performing its sequence of actions autonomously, i.e. independent of its surroundings as soon as it has been started.

When two or more of such processes have to cooperate with each other, they must be connected, i.e. they must be able to communicate with each other in order to exchange information. As we shall see below, the properties of these means of intercommunication play a vital role.

Furthermore, we have stipulated that the processes should be connected loosely; by this we mean that apart from the (rare) moments of explicit intercommunication, the individual processes themselves are to be regarded as completely independent of each other. In particular we disallow any assumption about the relative speeds of the different processes. (Such an assumption —say"processes geared to the same clock"— could be regarded as implicit intercommunication.) This independence of speed ratios is in strict accordance with our appreciation of the single sequential process: its only essential feature is, that its elementary steps are performed in sequence. If we prefer to observe the performance with a chronometer in our hand, we may do so, but the process itself remains remarkably unaffected by this observation.

I warn the reader that my consistent refusal to make any assumptions about the speed ratios will at first sight appear as a mean trick to make things more difficult than they already are. I feel, however, fully justified in my refusal. Firstly, we may have to cope with situations in which, indeed, very little is known about the speeds. For instance, part of the system may be a manually operated input station, another part of the system might be such, that it can be stopped externally for any period of time, thus reducing its speed temporarily to zero. Secondly —and this is much more important— when we think that we can rely upon certain speed ratios, we shall discover that we have been "pound foolish and penny wise". True that certain mechanisms can be made simpler under the assumption of speed ratio restrictions. The verification, however, that such an assumption is always justified, is in general extremely tricky and the task to make, in a reliable manner, a well behaved structure out of many interlinked components is seriously aggravated when such "analogue interferences" have to be taken into account as well. (For one thing: it will make the proper working a rather unstable equilibrium, sensitive to any change in the different speeds, as may easily arise by replacement of a component by another —say, replacement of a line printer by a faster model— or reprogramming of a certain portion.)

2.1. A Simple Example.

After these introductory remarks I shall discuss the first problem.

We consider two sequential processes, "process 1" and "process 2", which for our purposes can be regarded as cyclic. In each cycle a so-called "critical section" occurs, critical in the sense that the processes have to be constructed in such a way, that at any moment at most one of the two is engaged in its critical section. In order to effectuate this mutual exclusion the two processes have access to a number of common variables. We postulate, that inspecting the present value of such a common variable and assigning a new value to such a common variable are to be regarded as indivisible, non-interfering actions. I.e. when the two processes assign a new value to the same common variable "simultaneously", then the assignments are to be regarded as done the one after the other, the final value of the variable will be one of the two values assigned, but never a "mixture" of the two. Similarly, when one process inspects the value of a common variable "simultaneously" with the assignment to it by the other one, then the first process will find either the old or the new value, but never a mixture.

For our purposes ALGOL 60 as it stands is not suited, as ALGOL 60 has been designed to describe one single sequential process. We therefore propose the following extension to enable us to describe parallellism of execution. When a sequence of statements —separated by semicolons as usual in ALGOL 60— is surrounded by the special statement bracket pair "parbegin" and "parend", this is to be interpreted as parallel execution of the constituent statements. The whole construction —let us call it "a parallel compound"— can be regarded as a statement. Initiation of a parallel compound implies simultaneous initiation of all its constituent statements, its execution is completed after the completion of the execution of all its constituent statements. E.g.:

begin S1; parbegin S2; S3; S4; parend; S5 end

(in which S1, S2, S3. S4 and S5 are used to indicate statements) means that after the completion of S1, the statements S2. S3 and S4 will be executed in parallel, and only when they are all finished, then the execution of statement 55 will be initiated.

With the above conventions we can describe our first solution:

begin integer turn; turn:= 1;
      parbegin
      process 1: begin Ll: if turn = 2 then goto Ll;
                           critical section 1;
                           turn:= 2;
                           remainder of cycle 1; goto L1
                 end;
      process 2: begin L2: if turn = 1 then goto L2;
                           critical section 2;
                           turn:= 1;
                           remainder of cycle 2; goto L2
                  end
      parend
end .

(Note for the inexperienced ALGOL 60 reader. After "begin" in the first line we find the so-called declaration "integer turn", thereby sticking to the rule of ALGOL 60 that program text is not allowed to refer to variables without having introduced them with the aid of a declaration. As this declaration occurs after the "begin" of the outermost statement bracket pair it means that for the whole duration of the program a variable has been introduced that will only take on integer values and to which the program text can refer by means of the name "turn".)

The two processes communicate with each other via the common integer "turn", the value of which indicates which of the two processes is the first to perform (or rather: to finish) its critical section. From the program it is clear that after the first assignment, the only possible values of the variable "turn" are 1 and 2. The condition for process 2 to enter its critical section is that it finds at some moment "turn ≠ 1", i.e. "turn = 2". But the only way in which the variable "turn" can get this value is by the assignment "turn:= 2" in process 1. As process 1 performs this assignment only at the completion of its critical section, process 2 can only initiate its critical section after the completion of critical section 1. And critical section 1 could indeed be initiated, because the initial condition "turn = 1" implied "turn ≠ 2", so that the potential wait cycle, labeled L1, was initially inactive. After the assignment "turn:= 2" the roles of the two processes are interchanged. (N.B. It is assumed that the only references to the variable "turn" are the ones explicitly shown in the program.)

Our solution, though correct, is, however, unnecessarily restrictive: after the completion of critical section 1, the value of the variable "turn" becomes "2", and it must be =1 again, before the next entrance into critical section 1. As a result the only admissible succession of critical sections is the strictly alternating one "1,2,1,2,1,2,1,.....", in other words, the two processes are synchronized. In order to stress explicitly that this is not the kind of solution we wanted, we impose the further condition "If one of the processes is stopped well outside its critical section, this is not allowed to lead to potential blocking of the other process.". This makes our previous solution unacceptable and we have to look for another.

Our second effort works with two integers "c1" and "c2", where c = 0 / 1 respectively will indicate that the corresponding process in inside / outside its critical section respectively. We may try the following construction:

begin integer c1, c2;
      c1:= 1; c2:= 1;
      parbegin
      process1: begin L1: if c2 = 0 then goto L1;
                          c1: = 0;
                          critical section 1;
                          c1:= 1;
                          remainder of cycle 1; goto L1
                end;
      process2: begin L2: if c1 = 0 then goto L2;
                          c2: = 0;
                          critical section 2;
                          c2:= 1;
                          remainder of cycle 2; goto L2
                end
      parend
end .

The first assignments set both c's = 1, in accordance with the fact that the processes are started outside their critical sections. During the entire execution of critical section 1 the relation "c1 = 0" holds and the first line of process 2 is effectively a wait "Wait as long as process 1 is in its critical section.". The trial solution gives indeed some protection against simultaneity of critical section execution, but is, alas, too simple, because it is wrong. Let first process 1 find that c2 = 1; let process 2 inspect c1 immediately afterwards, then it will (still) find c1 = 1. Both processes, having found that the other is not in its critical section, will conclude that they can enter their own section safely!

We have been too optimistic, we must play a safer game. Let us invert, at the beginning of the parallel processes, the inspection of the "c" of the other and the setting of the own "c". We then get the construction:

begin integer c1, c2;
      c1:= 1; c2:= 1;
      parbegin
      process 1: begin A1: c1:= 0;
                       L1: if c2 = 0 then goto Ll;
                           critical section 1;
                           c1:= 1;
                           remainder of cycle 1; goto A1
                 end;
      process 2: begin A2: c2:= 0;
                       L2: if c1 = 0 then goto L2;
                           critical section 2;
                           c2:= 1;
                           remainder of cycle 2; goto A2
                  end
      parend
end .

It is worth while to verify that this solution is at least completely safe. Let us focus our attention on the moment that process 1 finds c2 = 1 and therefore decides to enter its critical section. At this moment we can conclude
     1) that the relation "c1 = 0" already holds and will continue to hold until process 1 has completed the execution of its critical section,
     2) that, as "c2 = 1" holds, process 2 is well outside its critical section, which it cannot enter as long as "c1 = 0" holds, i.e. as long as process 1 is still engaged in its critical section.
Thus the mutual exclusion is indeed guaranteed.

But this solution, alas, must also be rejected: in its safety measures it has been too drastic, for it contains the danger of definite mutual blocking. When after the assignment "c1:= 0" but yet before the inspection of c2 (both by process 1) process 2 performs the assignment "c2:= 0" then both processes have arrived at label L1 or L2 respectively and both relations "c1 = 0" and "c2 = 0" hold, with the result that both processes will wait upon each other until eternity. Therefore also this solution must be rejected.

It was OK to set one's own "c" before inspecting the "c" of the other, but it was wrong to stick to one's own c-setting and just to wait. This is (somewhat) remedied in the following construction:

begin integer c1, c2;
      c1:= 1; c2:= 1;
      parbegin
      process 1: begin L1: c1:= 0;
                           if c2 = 0 then
                               begin c1:= 1; goto L1 end;
                           critical section 1;
                           c1:= 1;
                           remainder of cycle 1; goto L1
                 end;
      process 2: begin L2: c2:= 0;
                           if c1 = 0 then
                               begin c2:= 1; goto L2 end;
                           critical section 2;
                           c2:= 1;
                           remainder of cycle 2; goto L2
                 end
      parend
end .

This construction is as safe as the previous one and, when the assignments "c1:= 0" and "c2:= 0" are performed "simultaneously" it will not necessarily lead to mutual blocking ad infinitum, because both processes will reset their own "c" back to 1 before restarting the entry rites, thereby enabling the other process to catch the opportunity. But our principles force us to reject also this solution, for the refusal to make any assumptions about the speed ratio implies that we have to cater for all speeds, and the last solution admits the speeds to be so carefully adjusted that the processes inspect the other's "c" only in those periods of time that its value is = 0. To make clear that we reject such solutions that only work with some luck, we state our next requirement: "If the two processes are about to enter their critical sections, it must be impossible to devise for them such finite speeds, that the decision which one of the two is the first to enter its critical section is postponed until eternity.".

In passing we note, that the solution just rejected is quite acceptable everyday life. E.g., when two people are talking over the telephone and they are suddenly disconnected, as a rule both try to reestablish the connection. They both dial and if they get the signal "Number Engaged", they put down the receiver and, if not already called, they try "some" seconds later. Of course, this may coincide with the next effort of the other party, but as a rule the connection is reestablished succesfully after very few trials. In our mechanical circumstances, however, we cannot accept this pattern of behaviour: our parties might very well be identical!

Quite a collection of trial solutions have been shown to be incorrect and at some moment people that had played with the problem started to doubt whether it could be solved at all. To the Dutch mathematician Th.J.Dekker the credit is due for the first correct solution. It is, in fact, a mixture of our previous efforts: it uses the "safe sluice" of our last constructions, together with the integer "turn" of the first one, but only to resolve the indeterminateness when neither of the two immediately succeeds. The initial value of "turn" could have been 2 as well.

begin integer c1, c2 turn;
      c1:= 1; c2:= 1; turn = 1;
      parbegin
      process 1: begin A1: c1:= 0;
                       L1: if c2 = 0 then
                               begin if turn = 1 then goto L1;
                                     c1:= 1;
                                 B1: if turn = 2 then goto B1;
                                     goto A1
                               end;
                           critical section 1;
                           turn:= 2; c1:= 1;
                           remainder of cycle 1; goto A1
                 end;
      process 2: begin A2: c2:= 0;
                       L2: if c1 = 0 then
                              begin if turn = 2 then goto L2;
                                    c2:= 1;
                                B2: if turn = 1 then goto B2;
                                    goto A2
                              end;
                           critical section 2;
                           turn:= 1; c2:= 1;
                           remainder of cycle 2; goto A2
                 end
      parend
end .

We shall now prove the correctness of this solution. Our first observation is that each process only operates on its own "c". As a result process 1 inspects "c2" only while "c1 = 0", it will only enter its critical section provided it finds "c2 = 1"; for process 2 the analogous observation can be made.

In short, we recognize the safe sluice of our last constructions and the solution is safe in the sense that the two processes can never be in their critical sections simultaneously. The second part of the proof has to show that in case of doubt the decision which of the two will be the first to enter cannot be postponed until eternity. Now we should pay some attention to the integer "turn": we note that assignment to this variable only occurs at the end —or, if you wish: as part— of critical sections and therefore we can regard the variable "turn" as a constant during this decision process. Suppose that "turn = 1". Then process 1 can only cycle via Ll, that is with "c1 = 0" and only as long as it finds "c2 = 0". But if "turn = 1" then process 2 can only cycle via B2, but this state implies "c2 = 1", so that process 1 cannot and is bound to enter its critical section. For "turn = 2" the mirrored reasoning applies. As third and final part of the proof we observe that stopping, say, process 1 in "remainder of cycle 1" will not restrict process 2: the relation "c1 = 1" will then hold and process 2 can enter its critical section gaily, quite independent of the current value of "turn". And this completes the proof of the correctness of Dekker's solution. Those readers that fail to appreciate its ingenuity are kindly asked to realize, that for them I have prepared the ground by means of a carefully selected set of rejected constructions.

2.2. The Generalized Mutual Exclusion Problem.

The problem of section 2.1 has a natural generalization: given N cyclic processes, each with a critical section, can we construct them in such a way, that at any moment at most one of them is engaged in its critical section? We assume the same means of intercommunication available, i.e. a set of commonly accessible variables. Furthermore our so1ution has to satisfy the same requirements, that stopping one process well outside its critical section may in no way restrict the freedom of the others, and that if more than one process is about to enter its critical section, it must be impossible to devise for them such finite speeds, that the decision which one of them is the first one to enter its critical section, can be postponed until eternity.

In order to be able to describe the solution in ALGOL 6O, we need the concept of the array. In section 2.1 we had to introduce a "c" for each of the two processes and we did so by declaring

integer array c1, c2  .

Instead of enumerating the quantities, we can declare —under the assumption that "N" has a well defined positive value—

integer array c[1 : N]

which means, that at one stroke we have introduced N integers, accessible under the names

c[subscript],

where "subscript" might take the values 1, 2, ....... N.

The next new ALGOL 60 feature we shall use is the so-called "for clause", which we shall use in the following form:

for j:= 1 step 1 until N do statement S ,

and which enables us to express repetition of "statement S" quite conveniently. In principle, the for clause implies that "statement S" will be executed N times, with "j" in succession = 1, = 2, ......, = N. (We have added "in principle", for via a goto statement as constituent part of statement S and leading out of it, the repetition can be ended earlier.)

Finally we need the logical operator that in this monograph is denoted by "and". We have met the conditional clause in the form:

if condition then statement .

We shall now meet:

if condition 1 and condition 2 then statement S .

meaning that statement S will only be executed if "condition 1" and "condition 2" are both satisfied. (Once more we should like to stress that this monograph is not an ALGOL 60 programming manual: the above —loose!— explanations of ALGOL 6O have only been introduced to make this monograph as self-contained is possible.)

With the notational aids just sketched we can describe our solution for fixed N as follows.

The overall structure is:

begin integer array b, c[O : N];
       integer turn;
      for turn:= 0 step 1 until N do
            begin b[turn]:= 1 end;
      turn:= 0;
      parbegin
      process 1: begin.....................end;
      process 2: begin.....................end;
         .
         .
         .
         .
         .
         .
         .
      process N: begin.....................end
      parend
end .

The first declaration introduces two arrays with N + 1 elements each, the next declaration introduces a single integer "turn". In the following for clause this variable "turn" is used to take on the successive values 1, 2, 3,......, N, so that the two arrays are initialized with all elements = 1. Then "turn" is set = 0 (i.e. none of the processes, numbered from 1 onwards, is privileged). After this the N processes are started simultaneously.

The N processes are all similar. The structure of the i-th process is as follows (1 ≤ i ≤ N) :

process i: begin integer i;
              Ai: b[i]:= 0;
             Li: if turn ≠ i then
                 begin c[i]:= 1;
                       if b[turn] = 1 then turn:= i;
                       goto Li
                 end;
                 c[i]:= 0;
                 for j:= 1 step 1 until N do
                    begin if j ≠ i and c[j] = 0 then goto Li end;
                 critical section i
                 turn:= 0; c[i]:= 1; b[i]:= 1;
                 remainder of cycle i; goto Ai
           end .

Remark. The description of the N individual processes starts with declaration "integer j". According to the rules of ALGOL 60 this means that each process introduces its own, private integer "j" (a so-called "local quantity").

We leave the proof to the reader. It has to show again:
1) that at any moment at most one of the processes is engaged in its critical section
2) that the decision which of the processes is the first to enter its critical section cannot be postponed until eternity
3) that stopping a process in its "remainder of cycle" has no effect upon the others.

Of these parts, the second one is the most difficult one. (Hint: as soon as one of the processes has performed the assignment "turn:= i", no new processes can decide to assign their number to turn before a critical section has been completed. Mind that two processes can decide "simultaneously" to assign their i-value to turn!)

(Remark, that can be skipped at first reading.) The program just described inspects the value of "b[turn]" where both the array "b" and the integer "turn" are in common store. We have stated that inspecting a single variable is an indivisible action and inspecting "b[turn]" can therefore only mean: inspect the value of "turn", and if this happens to be = 5, well, then inspect "b[5]". Or, in more explicit ALGOL:

process i:= begin integer j, k;
                      .
                      .
                      .
                      .
                  k:= turn; if b[k] = 1 then........ ,

implying that by the time that "b[k]" is inspected, "turn" may slready have a value different from the current one of "k".
Without the stated limitations in communicating with the common store, a possible interpretation of "the value of b[turn]" would have been "the value of the element of the array b as indicated by the current value of turn". In so-called uniprogramming —i.e. a single seouential process operating on quantities local to it— the two interpretations are equivalent. In multiprogramming, where other active processes may access and change the same common information, the two interpretations make a great difference: In particular for the reader with extensive experience in uniprogramming this remark has been inserted as an indication of the subtleties of the games we are playing.

2.3. A Linguistic Interlude.

(This section may be skipped at first reading.)

In section 2.2. we described the cooperation of N processes; in the overall structure we used a vertical sequence of dots between the brackets "parbegin" and "parend". This is nothing but a loose formalism, suggesting to the human reader how to compose in our notation a set of N cooperating sequential processes, under the condition that the value of N has been fixed beforehand. It is a suggestion for the construction of 3, 4 or 5071 cooperating processes, it does not give a formal description of N such cooperating processes in which N occurs as a parameter, i.e. it is not a description, valid for amy value of N.

It is the purpose of this section to show that the concept of the so-called "recursive procedure" of ALGOL 60 caters for this. This concept will be sketched briefly.

We have seen, how after "begin" declarations could occur in order to introduce and to name either single varibles (by enumeration of their names) or whole ordered sets af variables (viz. in the array declaration}. With the so-called "procedure declaration" we can define and name a certain action; such an action may then be invoked by using its name as a statement, thereby supplying the parameters, to which the action should be applied.

As an illustration we consider the following ALGOL 6O program:

begin integer a, b;
      procedure square(u, v); integer u, v;
           begin u:= v * v end;
   L: square(a, 3); square(b, a); square(a, b)
end .

In the first line the integer named "a" and "b" are declared. The next line declares the procedure named "square", operating on two parameters, which are specified to be single integers (and not, say, complete arrays). This line is called "the procedure heading". The immediately following statement —the so-called "procedure body"— describes by definition the action named: in the third line —in which the bracket pair "begin....end" is superfluous— it is told that the action of "square" is to assign to the first parameter the square of the value of the second one. Then, labeled "L", comes the first statement. Before its execution the values of both "a" and "b" are undefined, after its execution "a = 9". After the execution of the next statement, the value of "b" is therefore = 81, after the execution of the last statement, the value of "a" is =6561, the value of "b" is still = 81.

In the previous example the procedure mechanism was essentially introduced as a means for abreviation, a means for avoiding to have to write down the "body" three times, although we could have done so quite easily:

begin integer a, b;
    L: a:= 3 * 3; b:= a * a; a:= b * b
end .

When the body is much more complicated than in this example, a program along the latter lines tends indeed to be much more lengthy.

This technique of "substituting for the call the appropriate version of the body" is, however, no longer possible as soon as the procedure is a so-called recursive one, i.e. may call itself. It is then, that the procedure really enlarges the expressive power of the programming language.

A simple example might illustrate the recursive procedure. The greatest common divisor of two given natural numbers is
1) if they have the same value equal to this value
2) if they have different values equal to the greatest common divisor of the smallest of the two and their difference.

In other words, if the greatest common divisor is not trivial (first case) the problem is replaced by finding the greatest common divisor of two smaller numbers.

(1n the following program the insertion "value v, w;" can be skipped by the reader as being irrelevant for our present purposes; it indicates that for the parameters listed the body is only interested in the numerical value of the actual parameter, as supplied by the call.)

begin integer a;
      procedure GCD(u, v, w); value v, w; integer u, v, w;
      begin if v = w then u:= v
                     else
                begin if v < w then GCD(u, v, w - v)
                               else GCD(U, v -w, w)
                end;
      GCD(a, 12, 53)
end .

(In this example the more elaborate form of the conditional statement is used, viz.:

if condition then statement 1 else statement 2   ,

meaning that if "condition" is satisfied,"statement 1" will be executed and "statement 2" will be skipped, and that if "condition" is not satisfied, "statement 1" will be skipped and "statement 2" will be executed.)

The reader is invited to follow the pattern of calls of GCD and to see, how the variable "a" becomes = 3; he is also invited to convince himself of the fact that the (dynamic) pattern of calls depends on the parameters supplied and that the substitution technique —replace call by body— as applied in the previous example would lead to difficulties here.

We shall now write a program to perform a matrix * vector multiplication in which
1) the order of the M scalar * scalar products to be summed is indeed prescribed (the rows of the matrix will be scanned from left to right)
2) the N rows of the matrix can be processed in parallel.

(Where we do not wish to impose the restriction of purely integer values, we have used to declarator "real" instead of the declarator "integer"; furthermore we have introduced an array with two subscripts in a, we hope, obvious manner.)

It is assumed that, upon entry of this block of program, the integers "M" and "N" have positive values.

begin real array matrix[1 : N, 1 : M];
      real array vector[l : M];
      real array product[l : N];
      procedure rowmult(k); value k; integer k;
          begin if k > O then
                parbegin
                   begin real s; integer j;
                         s:= 0;
                         for j:= 1 step 1 until M do
                             s:= s + matrix[k, j] * vector[j];
                         product[k]:= s
                   end;
                   rowmult(k -1)
                parend
          end;
      .
      .
      .
      .
      .
      rowmult(N);
      .
      .
end

3. The Mutual Exclusion Problem Revisited.

We return to the problem of mutual exclusion in time of critical sections, as introduced in section 2.1 and generalized in section 2.2. This section deals with a more efficient technique for solving this problem; only after having done so, we have adequate means for the description of examples, with which I hope to convince the reader of the rather fundamental importance of the mutual exclusion problem. In other words, I must appeal to the patience of the wondering reader (suffering, as I am, from the sequential nature of human communication!)

3.1. The Need for a More Realistic Solution.

The solution given in section 2.2 is interesting in as far as it shows that the restricted means of communication provided are, from a theoretical point of view, sufficient to solve the problem. From other points of view, which are just as dear to my heart, it is hopelessly inadequate.

To start with, it gives rise to a rather cumbersome description of the individual processes, in which it is all but transparent that the overall behaviour is in accordance with the conceptually so simple requirement of the mutual exclusion. In other words, in some way or another this solution is a tremendous mystification. Let us try to isolate in our minds in which respect this solution represents indeed a mystification, for this investigation could give the clue to improvement.

Let us take the period of time during which one of the processes is in its critical section. We all know, that during that period, no other processes can enter their critical section and that, if they want to do so, they have to wait until the current critical section execution has been completed. For the remainder of that period hardly any activity is required from them: they have to wait anyhow, and as far as we are concerned "they could go to sleep".

Our solution does not reflect this at all: we keep the processes busy setting and inspecting common variables all the time, as if no price has to be paid for this activity. But if our implementation —i.e. the ways in which or the means by which these processes are carried out— is such, that "sleeping" is a less expensive activity than this busy way of waiting, then we are fully justified (now also from an economic point of view) to call our solution misleading.

In present day computers, there are at least two ways in which this active way of waiting can be very expensive. Let me sketch them briefly. These computers have two distinct parts, usually called "the processor" and "the store". The processor is the active part, in which the arithmetic and logical operations are performed, it is "active and small"; in the store, which is "passive and large" resides at any moment the information, which is not processed at that very moment but only kept there for future reference. In the total computational process information is transported from store to processor as soon as it has to play an active role, the information in store can be changed by transportation in the inverse direction.

Such a computer is a very flexible tool for the implementation of sequential processes. Even a computer with only one single processor can be used to implement a number of concurrent sequential processes. From a macroscopic point of view it will seem, as though all these processes are carried out simultaneously, a more closer inspection will reveal, however, that at any "microscopic" moment the processor helps along only one single program, and the overall picture only results, because at well chosen moments the processor will switch over from one process to another. In such an implementation the different processes share the same processor and activity of one of the processes (i.e. a non-zero speed) will imply a zero speed for the others and it is then undesirable, that precious processor time is consumed by processes, which cannot go on anyhow.

Apart from processor sharing, the store sharing could make the unnecessary activity of a waiting process undesirable. Let us assume that inspection of or assignment to a "common variable" implies the access to an information unit —a so-called "word"— in a ferrite core store. Access to a word in a core store takes a finite time and for technical reasons only one word can be accessed at a time. When more than one active process may wish access to words of the same core store, the usual arrangement is that in the case of immanent coincidence, the storage access requests from the different active processes are granted according to a built in priority rule: the lower priority process is automatically held up. (The literature refers to this situation when it describes "a communication channel stealing a memory cycle from the processor.) The result is that frequent inspection of common variables may slow down the process, the local quantities of which are stored in the same core store.

3.2. The Synchronizing Primitives.

The origin of the complications, which lead to such intricate solutions as the one described in section 2.2 is the fact that the indivisible accesses to common variables are always "one-way information traffic": an individual process can either assign a new value or inspect a current value. Such an inspection itself, however, leaves no trace for the other processes and the consequence is that, when a process want to react to the current value of a common variable, its value may be changed by the other processes between the moment of its inspection and the following effectuation of the reaction to it. In other words: the previous set of communication facilities must be regarded as inadequate for the problem at hand and we should lock for better adapted alternatives.

Such an alternative is given by introducing
a) among the common variables special purpose integers, which we shall call "semaphores".
b) among the repertoire of actions, from which the individual processes have to be constructed, two new primitives, which we call the "P-operation" and the "V-operation" respectively. The latter operations always operate upon a semaphore and represent the only way in which the concurrent processes may access the semaphores.

The semaphores are essentially non-negative integers; when only used to solve the mutual exclusion problem, the range of their values will even be restricted to "0" and "1". It is the merit of the Dutch physicist and computer designer Drs.C.S.Scholten to have demonstrated a considerable field of applicability for semaphores that can also take on larger values. When there is a need for distinction, we shall talk about "binary semaphores" and "general semaphores" respectively. The definition of the P- and V-operation that I shall give now, is insensitive to this distinction.

Definition. The V-operation is an operation with one argument, which must be the identification of a semaphore. (If "S1" and "S2" denote semaphores, we can write "V(S1)" and "V(S2)".) Its function is to increase the value of its argument semaphore by 1; this increase is to be regarded as an indivisible operation.

Note, that this last sentence makes "V(S1)" inequivalent to "S1 := S1 + 1".
For suppose, that two processes A and B both contain the statement "V(S1)" and that both should like to perform this statement at a moment when, say, "S1 = 6". Excluding interference with S1 from other processes, A and B will perform their V-operations in an unspecified order —at least: outside our control— and after the completion of the second V-operation the final value of S1 will be = 8. If S1 had not been a semaphore but just an ordinary common integer, and if processes A and B had contained the statement "S1:= S1 + 1" instead of the V-operation on S1, then the following could happen. Process A evaluates "S1 + 1" and computes "7"; before effecting, however, the assignment of this new value, process B has reached the same stage and also evaluates "S1 + 1", computing "7". Thereafter both processes assign the value "7" to S1 and one of the desired increases has been lost. The requirement of the "indivisible operation" is meant to exclude this occurrence, when the V-operation is used.

Definition. The P-operation is an operation with one argument, which must be the identification of a semaphore. (If "S1" and "S2" denote semaphores, we can write "P(S1)" and "P(S2)".) Its function is to decrease the value of its argument semaphore by 1 as soon as the resulting value would be non-negative. The completion of the P-operation —i.e. the decision that this is the appropriate moment to effectuate the decrease and the subsequent decrease itself— is to be regarded as an indivisible operation.

It is the P-operation, which represents the potential delay, viz. when a process initiates a P-operation on a semaphore, that at that moment is = 0, in that case this P-operation cannot be completed until another process has performed a V-operation on the same semaphore and has given it the value "1". At that moment, more than one process may have initiated a P-operation on that very same semaphore. The clause that completion of a P-operation is an indivisible action means that when the semaphore has got the value "1", only one of the initiated P-operations on it is allowed to be completed. Which one, again, is left unspecified, i,e, at least outside our control.

At the present stage of our discussions we shall take the implementability of the P-and V-operations for granted.

3.3. The Synchronizing Primitives Applied to the Mutual Exclusion Problem.

The solution of the N processes, each with a critical section, the executions of which must exclude one another in time (see section 2.2) is now trivial. It can be done with the aid of a single binary semaphore, say "free". The value of "free" equals the number of processes allowed to enter their critical section now, or:

"free = 1" means: none of the processes is engaged in its critical section
"free = 0" means: one of the processes is engaged in its critical section.
The overall structure of the solution becomes:

begin integer free; free:= 1;
    parbegin
    process 1: begin...............end;
    process 2: begin...............end;
      .
      .
      .
      .
    process N: begin...............end;
    parend
end

with the i-th process of the form:

process i: begin
             Li: P(free); critical section i; V(free);
                 remainder of cycle i; goto Li
           end

4. The General Semaphore.

4.1. Typical Uses of the General Semaphore.

We consider two processes, which are called the "producer" and the "consumer" respectively. The producer is a cyclic process and each time it goes through its cycle it produces a certain portion of information, that has to be processed by the consumer. The consumer is also a cyclic process and each time it goes through its cycle, it can process the next portion of information, as has been produced by the producer. A simple example is given by a computing process, producing as "portions of information" punched cards images to be punched out by a card punch, which plays the role of the consumer.

The producer-consumer relation implies a one-way communication channel between the two processes, along which the portions of information can be transmitted. We assume the two processes to be connected for this purpose via a buffer with unbounded capacity, i.e. the portions produced need not to be consumed immediately, but they may queue in the buffer. The fact that no upper bound has been given for the capacity of the buffer makes this example slightly unrealistic, but this should not trouble us too much now.

(The origin of the name "buffer" becomes understandable as soon as we investigate the consequences of its absence, viz. when the producer can only offer its next portion after the previous portion has been actually consumed. In the computer - card punch example, we may assume that the card punch can punch cards at a constant speed, say 4 cards per second. Let us assume, that this output speed is well matched with the production speed, i.e. that the computer can perform the card image production process with the same average speed. If the connection between computing process and card punch is unbuffered, then the couple will only work continuously at full speed when the card production process produces a card every quarter of a second. If, however, the nature of the computing process is such, that after one or two seconds vigorous computing it produces 4 to 8 card images in a single burst, then unbuffered connection will result in a period of time, in which the punch will stand idle (for lack of information), followed by a period in which the computing process has to stand idle, because it cannot get rid of the next card image before the preceding one has been actually punched. Such irregularities in production speed, however, can be smoothed out by a buffer of sufficient size and that is, why such a queuing device is called "a buffer".)

In this section we shall not deal with the various techniques of implementing a buffer. It must be able to contain successive portions of information, it must therefore be a suitable storage medium, accessible to both processes. Furthermore, it must not only contain the portions themselves, it must also represent their linear ordering. (In the literature two well-known techniques are described by "cyclic buffering" and "chaining" respectively.) When the producer has prepared its next portion to be added to the buffer, we shall indicate this action simply by "add portion to buffer", without going into further details; similarly, the consumer will "take portion from buffer", where it is understood that it will be the oldest portion, still in the buffer. (Another name of a buffer is a "first-In-first-Out-Memory.)

Omitting in the outermost block any declarations for the buffer, we can now construct the two processes with the aid of a single general semaphore, called "number of queuing portions".

begin integer number of queuing portions;
      number of queuing portions:= 0;
      parbegin
      producer: begin
              again 1: produce the next portion;
                       add portion to buffer;
                       V(number of queuing portions);
                       goto again1
                end;
      consumer: begin
              again 2: P(number of queuing portions);
                       take portion from buffer;
                       process portion taken;
                       goto again 2
                end
      parend
end

The first line of the producer represents the coding of the process which forms the next portion of information; it can be conceived —it has a meaning— quite independent of the buffer for which this portion is intended; when it has been executed the next portion has been succesfully completed, the completion of its construction can no longer be dependent on other (unmentioned) conditions. The second line of coding represents the actions, which define the finished portions as the next one in the buffer; after its execution the new portion has been added completely to the buffer, apart from the fact that the consumer does not know it yet. The V-operation finally confirms its presence, i.e. signals it to the consumer. Note, that it is absolutely essential, that the V-operation is preceded by the complete addition of the portion. About the structure of the consumer analogous remarks can be made.

Particularly in the case of buffer implementation by means of chaining it is not unusual that the operations "add portion to buffer" and "take portion from buffer" —operating as they are on the same clerical status information of the buffer— could interfere with each other in a most undesirable fashion, unless we see to it, that they exclude each other in time. This can be catered for by a binary semaphore, called "buffer manipulation", the values of which mean:

= 0 : either adding to or taking from the buffer is taking place
= 1 : neither adding to nor taking from the buffer is taking place.

The program is as follows:

begin integer number of queuing portions, buffer manipulation;
      number of queuing portions:= 0;
      buffer manipulation:= 1;
      parbegin
      producer: begin
              again 1: produce next portion;
                       P(buffer manipulation) ;
                       add portion to buffer;
                       V(buffer manipulation);
                       V(number of queuing portions);
                       goto again 1
               end;
      consumer: begin
              again 2: P(number of queuing portions);
                       P(buffer manipulation);
                       take portion from buffer;
                       V(buffer manipulation);
                       process portion taken;
                       goto again 2
               end
      parend
end

The reader is requested to convince himself that
a) the order of the two V-operations in the producer is immaterial
b) the order of the two P-operations in the consumer is essential.

Remark. The presence of the binary semaphore "buffer manipulation" has another consequence. We have given the program for one producer and one consumer, but now the extension to more producers and/or more consumers is straightforward: the same semaphore sees to it that two or more additions of new portions will never get mixed up and the same applies to two or more takings of a portion by different consumers. The reader is requested to verify that the order of the two V-operations in the producer is still immaterial.

4.2. The Superfluity of the General Semaphore.

In this section we shall show the superfluity of the general semaphore and we shall do so by rewriting the last program of the previous section, using binary semaphores only. (Intentionally I have written "we shall show" and not "we shall prove the superfluity". We do not have at our disposal the mathematical apparatus that would be needed to give such a proof and I do not feel inclined to develop such mathematical apparatus now. Nevertheless I hope that my show will be convincing!) We shall first give a solution and postpone the discussion till afterwards.

begin integer numqueupor, buffer manipulation, consumer delay;
      numqueupor:= 0; buffer manipulation:= 1; consumer delay:= 0;
      parbegin
      producer: begin
              again 1: produce next portion;
                       P(buffer manipulation);
                       add portion to buffer:
                       numqueupor:= numqueupor + 1;
                       if numqueupor = 1 then V(consumer delay);
                       V(buffer manipulation);
                       goto again 1
               end;
      consumer: begin  integer oldnumqueupor;
                wait:  P(consumer delay);
                go on: P(buffer manipulation);
                       take portion from buffer;
                       numqueupor:= numqueupor -1;
                       oldnumqueupor:= numquepor;
                       V(buffer manipulation) ;
                       process portion taken;
                       if oldnumqueupor = 0 then goto wait else goto go on
                end
      parend
end .

Relevant in the dynamic behaviour of this program are the periods of time during which the buffer is empty. (As long as the buffer is not empty, the consumer can go on happily at its maximum speed.) Such a period can only be initiated by the consumer (by taking the last portion present from the buffer), it can only be terminated by the producer (by adding a portion to an empty buffer). These two events can be detected unambiguously, thanks to the binary semaphore "buffer manipulation", that guarantees the mutual exclusion necessary for this detection. Each such period is accompanied by a P- and a V-operation on the new binary semaphore "consumer delay". Finally we draw attention to the local variable "oldnumqueupor" of the consumer: its value is set during the taking of the portion and fixes, whether it was the last portion then present. (The more expert ALGOL readers will be aware that we only need to store a single bit of information, viz. whether the decrease of numqueupor resulted in a value = 0; we could have used a local variable of type Boolean for this purpose.) When the consumer decides to go to "wait" i.e. finds "oldnumqueupor = 0", at that moment "numqueupor" itself could already be greater than zero again!

In the previous program the relevant occurrence was the period with empty buffer. One can remark that emptiness is, in itself, rather irrelevant: it only matters, when the consumer should like to take a next portion, which is still absent. We shall program this version as well. In its dynamic behaviour we may expect less P- and V-operations on "consumer delay", viz. not when the buffer has been empty for a short while, but is filled again in time to make delay of the consumer unnecessary. Again we shall first give the program and then its discussion.

begin integer numqueupor, buffer manipulation, consumer delay;
      numqueupor:= 0; buffer manipulation:= 1; consumer delay:= 0;
      parbegin
      producer: begin
              again 1: produce next portion;
                       P(buffer manipulation);
                       add portion to buffer;
                       numqueupor:= numqueupor + 1;
                       if numqueupor = 0 then
                          begin V(buffer manipulation);
                                V( consumer delay) end
                                  else
                          V(buffer manipulation);
                       goto again 1
                end;
      consumer: begin
              again 2: P(buffer manipulation);
                       numqueupor:= numnqueupor -1;
                       if numqueupor = -1 then
                          begin V(buffer manipulation);
                                P(consumer delay);
                                P(buffer manipulation) end;
                       take portion from buffer;
                       V(buffer manipulation);
                       process portion taken;
                       goto again 2
                end
      parend
end

Again, the semaphore "buffer manipulation" caters for the mutual exclusion of critical sections. The last six lines of the producer could have been formulated as follows:

if numqueupor = 0 then V(consumer delay);
V(buffer manipulation); goto again 1

In not doing so I have followed a personal taste, viz. to avoid P- and V-operations within critical sections; a personal taste to which the reader should not pay too much attention.

The range of possible values of "numqueupor" has been extended with the value "-1", meaning (outside critical section execution) "the buffer is not only empty, but its emptyness has already been detected by the consumer, which has decided to wait". This fact can be detected by the producer when, after the addition of one, "numqueupor = 0" holds.

Note how, in the case of "numqueupor = -1" the critical section of the consumer is dynamically broken into two parts: this is most essential, for otherwise the producer would never get the opportunity to add the portion that is already so much wanted by the consumer.

(The program just described is known as "The Sleeping Barber". There is a barbershop with a separate waiting room. The waiting room has an entry and next to it an exit to the room with the barber's chair, entry and exit sharing the same sliding door which always closes one of them; furthermore the entry is so small that only one customer can enter it at a time, thus fixing their order of entry. The mutual exclusions are thus guaranteed.

When the barber has finished a haircut, he opens the door to the waiting room and inspects it. If the waiting room is not empty, he invites the next customer, otherwise he goes to sleep in one of the chairs in the waiting room. The complementary behaviour of the customers is as follows: when they find zero or more customers in the waiting roam, they just wait their turn, when they find, however, the Sleeping Barber —"numqueupor = -1"— they wake him up.)

The two programs given present a strong hint to the conclusion that the general semaphore is, indeed, superfluous. Nevertheless we shaal not try to abolish the general semaphore: the one-sided synchronisation restriction expressible by it is a very common one and comparison of the solutions with and without general semaphore shows convincingly that it should be regarded as an adequate tool.

4.3. The Bounded Buffer.

I shall give a last simple example to illustrate the use of the general semaphore. In section 4.1 we have studied a producer and a consumer coupled via a buffer with unbounded capacity. This is a typically one-sided restriction: the producer can be arbitrarily far ahead of the consumer, on the other hand the consumer can never be ahead of the producer. The relation becomes symmetric, if the two are coupled via a buffer of finite size, say N portions. We give the program without any further discussion; we ask the reader to convince himself of the complete symmetry. ("The consumer produces and the producer consumes empty positions in the buffer".) The value N, as the buffer, is supposed to be defined in the surrounding universe into which the following program should be embedded.

begin integer number of queuing portions, number of empty positions,
      buffer manipulation;
      number of queuing portions:= 0;
      number of empty positions:= N;
      buffer manipulation:= 1;
      parbegin
      producer: begin
              again 1: produce next portion;
                       P(number of empty positions);
                       P(buffer manipulation);
                       add portion to buffer;
                       V(buffer manipulation);
                       V(mumber of queuing portions); goto again 1 end;
      consumer: begin
              again 2: P(number of queuing portions);
                       P(buffer manipulation);
                       take portion from buffer;
                       V(buffer manipulation) ;
                       V(number of empty positions);
                       process portion taken; goto again 2 end
      parend
end

5. Cooperation via Status Variables.

   EWD 126

14 - 6 - 1965

The Multiprogramming System for the EL X8 THE.

     In the following I shall describe our proposed multiprogramming system. While starting to do so I am aware that I shall be content with a system satisfying our needs as we see them; I am also aware of the fact that the presence of the drum and the way in which we intend to effectuate the so-called "Segment Control" have had a major influence on our approach. For a detailed description of Segment Control we refer to EWD113.

     Sequential processes, embedded in the machine.

     Sequential processes, to be performed by the central computer under program control have been called "abstract Machines". They fall into two groups, the programmable machines, called for short the PM's and the constant machines (originally "de stamgasten"), called the CM's for short.

     Each PM represents the possibility to execute a user's program; the number of PM's will be fixed, say 4.

     Each CM describes a process to be performed synchronized with the interrupt signals sent by one of the pieces of peripheral equipment. We shall have a CM
1) for each tape reader
2) for each tape punch
3) for the line printer
4) for the plotter
5) for the drum (the so-called "Segment Controller")
6) for the console teleprinter
     (we regard the console teleprinter as a single piece of equipment: when the keyboard is used the printer is used by the X8 in complete synchronisme, and therefore the teleprinter gives rise to only one CM.)

     The 12 abstract machines, thus embedded in the installation have to cooperate with each other. Originally we thought that one needed a 13th program, say "a coordinator" to regulate this cooperation. This now strikes me as organizing a society out of 12 unwilling individuals by appointing a policeman. Our present solution is more aptly described by making 12 mutually well-behaved individuals. There is still some coordinator left (viz. the instructions performed between transition from one abstract machine to another) but this is so meagre, that I doubt, whether any attention will be paid to it in this report at all.

     Information streams.

     The different abstract machines can communicate with each other in the sense that one can describe its "status" and that another can inspect it. This section, however, deals with bulk information transport between an input CM and a PM or between a PM and an output CM. In other words with the transportation of information which must be regarded as subject matter of the user's program. The following discussion does not apply to the drum, nor to the teleprinter. Not to the drum, because the activities of the segment controller take place behind the scenes, segment control is in fact, integrated with the addressing facilities available to each abstract machine; not to the teleprinter because here we shall only allow for very limited buffering and it is exactly the task of the information streams to cater for that.

     Each PM has the same fixed set of information streams to its private disposal: the PM's are identical and there is no question of "stream sharing" between the different PM's. This set wil comprise two tape reader streams, two tape punch streams, one plotter stream and one line printer stream. The local terminology with which each PM can identify its various information streams is the same for each PM.

     When an input CM is engaged in the production of an information stream, it must know which information stream it is building up. We may think of a local variable "current information stream" which can take 8 possible values (8 tape reader information streams being present in the installation).

     Similarly a tape punch CM must know, when engaged, which of the 8 tape punch information streams it is consuming, the plotter CM and the line printer CM must know which of the four information streams, destined for them, they are processing.

     An information stream consists of
1) a fixed size "handle"
2) a number of chained segments (may be zero)

     The handle describes the state of the information stream, whether a CM is engaged with it, how many segments there are in the chain, if so, links to the first and last segment in the chain etc.

     Producing and consuming the contents of an information stream are strictly sequential operations, an information stream is really a first-in-first-out memory. As a result the output of two programs, via the same (local) output information stream will appear the one after the other when the programs have been processed by the same PM. (A program may leave the PM as soon as it has finished its task, that is chaining its last output to the appropriate stream. The PM becomes immediately available to the next program, although its output information streams may still contain many segments!)

     Chaining and unchaining of transput information.

     Information is chained onto and unchained from an information stream in fixed size portions, the size being characteristic for the nature of the stream concerned. For the line printer it will be the picture of a form (from fold to fold) for the other streams it will be a segment.

     During production such a portion will be treated as an array local to the producer, at "chaining onto the stream" its SV (or SVA) will be transported. Also during consumption such a portion will be treated as a local array of the consumer; before actual consumption can start, it must be "unchained from the information stream", an action which again requires the transportation of SV-values. The advantages of this are
1) no seperate addressing mechanism has to be provided in order to address the individual words of such portions
2) chaining and unchaining do not involve any operation on the bulk information itself, but on the SV's only. (Our latest version of Segment Control enables us to move SV-values under all circumstances; in this case however (alas?) it can be shown that the operation of chaining and unchaining will in time always be disjunct with Segment Control activity concerning this segment!)

     There is, however, a small difference between chaining and unchaining by a CM or by a PM. Whether a CM is active or not, there will always be set aside a segment (or, say, 4 segments if it is the line printer CM) to store its current portion. This implies a permanent reservation "to keep the transput going" of about 9 segments. For the PM's however, these portions are undistinguishable from any other local array; when used, they count among the total number of non-empty segments occupied.

     The concept "document" and equipment sharing.

     A document is the amount of information in a single stream (to be) processed by a CM continuously. i.e. without the CM in the mean time switching over to serve another information stream.

     For the tape reader, a document is a single physical tape. The document size is given by the input itself and need not concern the programmer.

     For the plotter a document is a single "picture". As each PM is only equipped with one plotter output information stream, a user's program has only the facility of specifying one picture at the time. We shall not exploit the possibility that the plotter may leave an unfinished picture, turn to the next picture and finish the earlier one later. It is the duty of the programmer to indicate dynamically begin and end of plotter documents.

     For the punch a document is a piece of tape to be punched without "end of paper" interruptions. Also for the paper tape punch the programmer must indicate dynamically begin and end of punch documents. As far as plotters and punches will be treated on the same footing we shall refer to them as "plunches".

     For the line printer a document is a whole number of consecutive forms. The programmer has no control over this number, the line printer prints forms from the different information streams "as it sees fit".

     With regard to the deadly embrace, we propose the following, mixed attitude.

     From the line printer no difficulties can arise, as the line printer can —in case of emergency— always restrict itself to documents of single forms.

     For the tape readers, we assume, that the facilities for input buffering are such, that when a tape reader is wanted, we can always wait, until a tape reader is free again.

     For the plunches we propose to apply the banker's algorithm. The moment of the starting of the loan, is not when the program specifies "begin of document" but when it is decided, that the plunch will start with the output of an incomplete document. The initial program description must specify, which plunch streams it is going to use.

     The punch CM's keep track of the amount of paper, used from the present reel. When they start a finished document, they know beforehand, whether the amount of paper tape still on the reel is sufficient or not, if not, they will ask the operator to insert a fresh reel. If they have to start with an incomplete document, they will always ask for a fresh reel.

     The activity of a CM has two distinct stages, "document selection" and "document processing". In document selection it has to decide what to do next, in document processing it has to decide at what speed.

     The easiest part is document processing by an output CM: "as fast as possible". Document selection is a more refined process. The plunches will try not to initiate the processing of an unfinished document, but may be forced to do so, when total output buffering starts to overgrow a certain limit. If an output CM has the choice between various finished documents, the one from the same information stream as the last document processed has a certain preference, but monopolization by a single, very productive PM will be avoided.

     In the case of input CM's, both document selection and document processing are complicated. The document selection is difficult on account of the feature of the open mouth, tape reader request by a PM for the reading of a non-standard tape, a request, which may be refused by the operator, and "urgent request for a reader" by the operator. Document processing is also non-trivial, because the simple rule "as fast as possible" is not applicable. The idea is, that tape processing might occur under two different circumstances: either interest has been shown in this tape reader or not. In the latter case it will regulate its speed so as to keep the information stream reasonably filled (target goal: one segment in the chain). If, however, another user is waiting for it to become free, then it will read as fast as possible.

     The logic for tape reader document selection has been worked out to great detail; for the purpose of illustration we list the console messages, associated with it. (The numbering of the messages should not confuse the reader, they have grown historically)

M1. Machine opening.
     It requests the operator to insert a tape (identified in the message) in a tape reader (also identified in the message). Console remains reserved for operator answer.

M2. Operator answer to M1.
     Tape requested has been inserted. Console becomes available, conversation closed.

M3. Operator answer to M1.
     Tape unavailable now. Console becomes available again, as well as the tape specified. Conversation remains open, requiring operator reopening M4.

M4. Operator reopening.
     Requested, refused tape available now. This message must identify the PM. The console becomes available again, end of conversation. At some later stage, however, the machine will give again a M1 message.

M5. Operator opening.
     Request opportunity to insert standard tape. Console becomes available, conversation remains open, requiring machine reopening M8.

M8. Machine reopening.
     An identified free tape reader is at the disposal of requested standard tape insertion. (The operator has no means of disavowing his earlier request. If he comes now to the conclusion. that he does not want to insert a normal standard tape, he should insert a little piece of blank tape, "the empty standard tape".)

M9. Operator opening.
     Specified tape reader to be put out of circulation. Console becomes available, conversation requires reopening M12.

M12. Machine reopening.
     Disconnection effected. Console becomes available again, conversation requires reopening M13.

M13. Operator reopening.
     Reconnection disconnected tape reader. Console available, conversation closed.

M14. Machine opening.
     Request to remove the tape from an identified reader. Console remains available for operator answer.

M15. Operator answer to M14.
     Requested removal has been done. Conversation closed.

M16. Operator answer to M14.
     Skip until end of tape. Conversation closed.

(Remark: All messages printed by the operator are tested for applicability. If an operator (re)opening is not applicable, the console becomes available after rejection, if it was an immediate answer, the console remains reserved for the acceptable version of the answer.)

     Memory sharing.

     In this section the segments that are permanently present (library etc.) are left out of the discussion. We restrict ourselves to the managing of the remaining part of the drum, say "tot" segments.

     In this space we have to accomodate three kind of segments, their total numbers being indicated by p, i and o;
p = the total number of occupied segments that are part of the PM's
i = the total number of segments in input information streams
o = the total number of segments in output information streams.

     We have decided to impose a maximum bound on "i + o". The presence of the segments in the information stream implies the presence of SV's and linking information. It would upset the total organization rather drastically if we could have to introduce segments the SV's of which were not permanently stored in core. Furthermore the life times of these SV's considered as a whole are rather chaotic. For that reason we have decided to set aside a part of core store (the transput area), in which the stream segment SV's and the linking information can be accomodated. But this results in the upper bound mentioned. We think about 256 segments, i.e. a quarter of the drum.

     Furthermore we wish to set aside, say, a quarter of transput area for output buffering, i.e. 64 segments. It does not seem necessary to make a fixed reservation in transput area for input only: if the shoe begins to pinch it will become available provided that the output is indeed active. We intend to see to it, that output is indeed active, as soon as output buffering exceeds the reservation.

     To get an idea of the importance of sharing, it is restricted to three quarters of transput area, available for either o-, i-, or p-segments. Say 20 percent of available store.

     The vital inequalities to be respected are

p + i + o ≤ tot
i + o ≤ tot – resp (=size transput area)
p + i ≤ tot – reso
i ≤ tot – (resp + reso).

     We have not worked out yet a complete strategy, we have what I should like to call "a pattern of a strategy", i.e. we have a picture of the relevant occurrences in the abstract machines, and with these points their possible actions and influences upon each other. We shall now give a list of these points.

They are primarily:

SH1   p–increase in a PM (first reference to an empty segment)
SH2   p–decrease in a PM (killing of non-empty segments at block exit)
SH3   i → p transition in a PM (unchaining from input stream)
SH4   p → o transition in a PM (chaining onto output stream)
SH5   i–increase in an input CM (chaining onto input stream)
SH6   o–decrease in an output CM (unchaining from output stream)
SH7   document selection in output CM

     In general, at these points the abstract machine investigates the situation and one of three possible reactions may result
1) it may decide, that a disaster has happened (e.g. store explosion, to be avoided)
2) it may decide to do its action
3) it may decide to postpone its action and to wait. In the last case "the situation" tells clearly, that it is waiting. It then delegates to the remaining abstract machines to discover the situation under which it can go on again and to see to it, that this indeed happens. Therefore, these points, in general, include the inspection whether one or more waiting processes can go on again; we call this "V-inspection" (inspection whether a V-operation is appropriate).

     As SH1 and SH2 are the most frequent occurrences, our guiding principle has been to burden them as little as possible. In particular:

SH1 will not be burdened by the V-inspection, whether on account of the now tight store situation, document selection SH7 becomes most desirable. We intend to do so by guaranteeing that as soon as o > reso, there will certainly be active output.

SH2 will not be burdened by V-inspection, whether on account of the now less tight store situation, completion of SH1 or SH5 can be done. This is accomplished by signalling "disaster" when in SH1 or SH5 "p + i" is in danger of exceeding its upper bound.

     We have first to see, how we can guarantee active output as soon as o > reso. The only way in which we are forced to violate this rule is if o > reso without being able to perform document selection, i.e. when the appropriate CM's are not available (tied up with other unfinished documents) or not assignable on account of the bankers algorithm. That is, the banker must avoid unfinished unselected documents with a total size exceeding reso. That is: as soon as this limit is reached, unfinished document selection has to be done, if the banker allows it, otherwise the PM has to be held up, until the banker allows it or the total amount of unselected unfinished documents is decreased otherwise (by selection, say)

     From this it follows, that we have to mention a next relevant occurrence:

SH8   end of pluncher document, in a PM.

     After these preparations we may hope to be in a position to give an outline of the necessary actions at these relevant points.

     At SH1 it is inspected whether the p-increase is permissable. If so, the PM continues its activity, if not the reason is
a) the upper bound of "p + i" → disaster
b) the upper bound of "p + i + o" → wait.
(Case b implies o > reso, this implies output activity and in due time, the o-decrease will be in a position to remove the barrier.)

     At SH2 we only decrease p by the amount of non-empty segments killed.

     At SH3 —which may be preceded by a delay, because the next input portion was not present yet— it is inspected
a) whether now a SH5 should be completed (if there is still a CM active in producing portions for this stream, that one is a succesful candidate)
b) whether now a PM should complete its SH4 (which might be held up by the upper bound for "i + o"). This mechanism makes it possible that space used for input becomes available for output.

     At SH4 distinction is made between "forms and selected documents" on the one hand and "unselected documents" on the other hand. In the first case, the "i + o" bound may represent an obstacle; if so, the PM will wait, otherwise it will chain. When, as a result of chaining, "o > reso" then it will inspect, which output CM's shall complete their SH7. If it is an unselected document, the PM inspects, whether the total number of unselected segments would exceed reso. If not, it will attach, if so, it will call for the banker. Either this results in document selection or not. The PM will either be allowed to chain on or it has to wait.

     At SH5 the input CM will inspect whether it shall chain on its next portion to the stream (i – increase).
It will signal disaster when
a) its stream is empty and
b) chaining on would result in exceeding the upper bound for "i" or ""p + i".
It will wait, when
a) its stream is empty
b) chaining on would result in exceeding the upper bound for "i + o" or "p + i + o".

     When its stream is not empty, it will wait, when the stream is reasonably filled, it will chain on, when it is not reasonably filled. (At this stage we do not propose to give a further description of the criterion "reasonably filled"; it shall be dependent on how far the upper bounds are still away and whether this CM has been selected for the next paper tape, so that there is a point in trying to make it free.)

     At SH6 —i.e. o–decrease by the unchaining from the output stream, an extensive inspection is performed, whether an SH1, an SH4 or an SH5 can now be completed.

     Finally SH8 (end of pluncher document) will inspect, whether this document was already selected; if so, the banker comes in action and SH4-waits may now be finished. Above that, programs will be able to signal "end of output": this has influence on the document selection of the CM concerned, for then there is no point in waiting for more. (It is very nice if the line printer prints as a rule at least 5 consecutive forms from the same program, but this is a little bit difficult if the program produces only three forms.)

Remark: The scheme contains, right from the start, the danger, that a PM, privileged by the banker, fails to get a free tape reader. The description given above does not include the detection of this disaster.

Next remark. The count p of "occupied segments" does not include the stack segments, as they are never dumped on the drum. The reason that we have chosen the number of "dumpable" segments as the relevant unit in which to express the storage demands of a PM is that now we can guarantee that, whenever Segment Control needs a free drum page, there will certainly be one available. And if Segment Control would need to wait for free drum pages, we would be faced with the logical translation of "Who was first, the hen or the egg ?".

transcribed by Sam Samshuijzen
revised Tue, 11 Jan 2005

  EWD 130

A Sequel to EWD126.

I recall from EWD126 the definitions:

p = the total number of segments that are part of the PM's
i = the total number of segments that are part of the input streams
o = the total number of segments that are part of the output streams.

The vital inequalities to be respected are:

1) | i + o + p < tot
2) | i + o < transput area
3) | i + p < tot - reso
4) | i ≤ transput area - reso

To guarantee these inequalities, we introduce the "differences":

fiop | (initially = tot) | say: | 1024 | - something
fio | (initially = transput area) | say: | 256 |
fip | (initially = tot - reso) | say: | 960 | - something
fi | (initially = transput area - reso) | say: | 192 |

The operations that perform changes in i, o and/or p do so by changing the value of the four quantities listed:

SH1 | p-increase: | "dec(fip)" and "dec(fiop)"
SH2 | p-decrease: | "inc(fip)" and "inc(fiop)"
SH3  | i-p transition: | "inc(fio)" and "inc(fi)"
SH4 | p-o transition: | "dec(fio)" and "inc(fip)"
SH5 | i-increase: | "dec(fiop)", "dec(fio)", "dec(fip)" and "dec(fi)"
SH6  | o-decrease: | "inc(fiop)" and "inc(fio)".

Sequencing of the regions of program will be done in such a way, that the four quantities listed never get negative values.

Before going on, we shall first justify the inequalities, then the four quantities.

The first inequality is obvious: it expresses the maximum size of the drum.

The second inequality expresses the existence of transput area: this has been introduced because the SV's of (possible) transput segments will impose a permanent core store occupation.

The third and fourth inequality express that part of transput area (viz reso) is reserved for output exclusively. This is a selfimposed restriction which we exploit in the following way.

If the third or fourth inequality is in danger of being violated (i.e. when fip or fi is in danger of becoming negative) we signal "disaster" (viz. store exhaustion). Disaster detection must be implemented anyway, we shall see below, that this convention pins down the disaster detection to a few well defined points. The counterpart of this disaster detection is, that when at these few points no disaster has been detected, we must be able to guarantee that the processes will be able to continue. Or more precisely, the operations "dec(fi)" and "dec(fip)" occur only at SH1 (in a PM) and at SH5 (in a CM for input). These are the only points in which disaster can be signalled. If this disaster has not been signalled, dec(fiop) and dec(fio) might force a delay (viz. when fiop = 0 or fio = 0). In order that in due time the desired i- or p-increase indeed becomes possible, we must see to it, that the contents of the output streams are constantly such that, if necessary, the state "o < reso" can be reached without relying on further PM-or input CM activity.

It is necessary that we can get o ≤ reso, in order to be able to effect the i- or p-increase that has been requested without disaster signalling, but this condition is insufficient. For it means that upon the total size of the output streams, the upper bound reso may be imposed: if now all reso segments, available for output buffering, are occupied by output for which at this moment no equipment is available, we are still stuck, as we lack the room to keep the "moving streams" going.

We therefore impose upon the so-called "passive output" (for the definition, see below) a lower upper bound, called "maxu", where reso = maxu = maxpor (say =4), the maximum size of a portion of information to be put in transput area at SH4 and taken from it at SH6. Thus we guarantee that, if necessary

a) all but reso segments become available for i and p
b) the remaining reso segments are sufficient to keep the output going.

Remark. The active output may be confined to maxpor segments in transput area. If more than one output CM has to get its food via this narrow buffer, we cannot expect them to run at maximum speed. We leave it at that: we could have remedied this -without altering maxu- by increasing reso, i.e. by being quicker in signalling disaster, but there is nothing to be gained from that.

We make a second use of the boundary maxu: if "maxu < o", there is not only active output possible, but we even guarantee active output. This has the subsidiary advantage, that in SH1 -a frequent occurrence- we have only to test, whether the desired p-increase is possible. If not, and relieve has to come from active output, there is no need to inspect, whether now the moment has come to activate; output is already going and the PM has only to wait. The secone advantage is that SH2 (i.e. p-decrease), also a frequent occurrence, is never an occurrence upon which other processes may be waiting for their relieve.

So much for the inequalities. Now for the equalities.

They have been introduced for two reasons: the minor reason is that they enable us to test for danger situations at a zero value, instead of comparing with some bound. The main reason, however, is the following. Note, that we have carefully avoided to define "fiop = tot - i - o - p" etc., although their initial values and the dec- and inc-operations to which they are subjected in SH1 to SH6 are consistent with these definitions: these definitions would only be correct, if in SH1, say, "dec(fip)" and "dec(fiop)" were performed simultaneously. But this is not the case! In SH1, disaster is signalled if fip = 0, otherwise, dec(fip) is performed. After that, fiop = 0 is tested, if false, dec(fiop) is done immediately, if true, however, the PM has to be delayed, the p-increase has to be postponed. (Without the "predecrease" of fip, we should have to face the situation, that also the completion of a delayed p-increase could generate the disaster condition.)

Now we come to the definition of passive output, i.e. output in the buffer, of which we are not sure whether we can get rid of it (or even: are sure that we cannot get rid of it) without further PM-activity. It is closely connected to the banker's algorithm and only applies to documents for the plunchers.

(Use of the printer is not subjected to the banker's approval; accordingly, printer forms in the buffer never contribute to the passive output. We recall that the PM's offer the printer information in SH4 form wise and that we allow the printer CM to change information stream after each form, if necessary. We call a from inmage in a printer stream "a (printer) portion".)

For the pluncher streams, however, the PM's produce so-called "documents" of a priori unknown length. They attach (in SH4) then information portion wise, here a portion being a segment. The concept of "a document" is a restriction for the plunchers. As soon as a pluncher has selected a document (i.e. irrevocably decided that now the output of a certain document will be initiated), it will not become available for any other purpose until the document in question has been processed completely. If a pluncher selects a finished document, it sets itself to an already well defined task; the document is in its entirety available in the output buffer and the pluncher can go on at full speed.

The situation is drastically changed, however, if a pluncher selects an unfinished document, for then it becomes tied up until the PM will finish the document. The critical situation in which a pluncher has selected an unfinished document may only arise under the banker's approval. We describe it as the pluncher being tied up to the PM, or rather in the banker's terminology "being borrowed by the PM". The PM starts the loan of a pluncher at the moment that the pluncher selects an unfinished document, it ends the loan at SH8 "Finish Pluncher Document" (This is a PM-action). If the document has been finished before it has been selected, there is no loan involved and the banker's algorithm is not applied.

We introduce, for the banker, but also for the definition of passive output

plocash = the number of plotters that are not borrowed
puncash = the number of punches that are not borrowed.

These two quantities tell us "How much the banker has in cash". (Mind that "unborrowed" does not mean "idle": a pluncher engaged in the processing of a finished document is unborrowed, but certainly not idle!)

To the passive output belong

a) all unfinised, unselected pluncher documents
b) all finished unselected plotter documents of plocash = 0 and all finished unselected punch documents of puncash = 0.

Category a) represents the information of which we are not sure, whether we can get rid of it via the output (for this would imply selection of the unfinished document, an action which is subjected to the banker's approval); category b) represents the information of which we are sure that we cannot get rid of it with stopped PM's: the banker has no corresponding equipment in cash, i.e. the corresponding equipment has all been borrowed.

The total size of the passive output may not exceed maxu, growth of the passive output must therefore be carefully watched. We propose to restrict the growth of passive output to increasing the length (in SH4) of a document in category a) and rule out that passive output increases, due to the fact that finished documents, first outside category b) come to fall inside category b), due to "cash" going from 1 to 0.

For the single plotter this just means "never select an unfinished document if there is still a finished plotter document"; for the (more) punches this means "if you are the last unborrowed punch, then never select an unfinished document in the presence of a finished one." (The rule is certainly obeyed, if also punches only select an unfinished document, when no finished ones are available, as we may program them.)

To keep track of passive output we introduce for each pluncher stream:

lufd     | (=length of unfinished, unselected document). This quantity gives the length (in segments) of the document under construction provided it is unselected. Otherwise, lufd = 0.

The contribution to passive output of category a) is therefore SIGMA(lufd), taken over all pluncher streams.

For the contribution to passive output of category b) we introduce for finished pltter documents "plofp" and for finished punch documents "punfp" (...fp : finished passive documents).

Naturally:  | 0 < plocash implies plofp = 0 0 < puncash implies punfp = 0. | and

Passive output will be equal to

                SIGMA(lufd) + plofp + punfp

and as this may not exceed the upper bound maxu we introduce again the difference, the number of segments free for passive output

fpas (initially = max)

a quantity which is not allowed to have a negative value.

In order to describe the modification of the quantities introduced we mention the variable (per pluncher stream)

unfsel   | =1  | means: the unfinished document in this stream has been selected (i.e. the corresponding PM has borrowed the corresponding output CM)
| =0  | otherwise.

In SH4: (p-o transition)

if unfsel = 0 then begin inc(lufd); dec(fpas) end;    dec(fio)

Thus, if the document is unselected (category a) the corresponding changes in passive output control are booked.

In SH7: (document selection) in the case of selection of an unfinished document (under banker' approval!):

dec(...cash); INC(fpas, lufd); lufd:= 0; unfsel:=1

The document selected leaves passive output from category a. No finished documents shall enter passive output in category b) (see previous remark).

In SH8: (Finish Pluncher Document)

if unfsel = 1 then
begin unfsel:= 0; inc(...cash);
      if ...cash = 1 and 0 < ...cash then
      begin INC(fpas,...fp); ...fp:= 0 end
end
            else
begin if ...cash = 0 then INC(...fp,lufd) else INC(fpas,lufd);
      lufd:= 0
end

If a selected document is finished, this ends a loan; if now cash changes from 0 to 1, there may be documents in category b) now leaving passive output. If an unselected document (by definition in category a) is finished, it either goes to category b or it leaves passive output.

This far we have described the clerical variables and shown how we can operate upon them, consistently with their meaning. Now we shall describe the structure of the programs that together see to it, that the five basic quantities that must remain non-negative, indeed remain non-negative. For the present moment we restrict ourselves to the PM's and the output CM's.

Each PM has a private semaphore, called "pmsem" and a private state variable called "pmshr". In their homing position, they have both the value "0". Analogously, each output CM has a private semaphore, called "ocmsem" and a private state variable, called "plovar" for a plotter, "punvar" for a punch and "privar" for a printer. (If we wish to talk about the statevariables for the combined plunchers, we may call them "pluvar"). Also here, the homing position = 0.

Over these we have a universal, binary semaphore, called "SHS", which caters for the mutual exclusion of the inspection and modification of the common clerical variables.

The easiest operation is SH2: p-decrease. If the number of non-empty segments killed equals "killed", the program runs:

SH2: P(SHS); INC(fip, killed); INC(fiop, killed); V(SHS)

(Note: in the present description we shall not investigate, whether in trivial cases the P(SHS) and V(SHS) can be omitted and replaced by disabling and abling the interrupts.)

The next easiest operation is SH1: p-increase. In a PM this always occurs for a single segment. Here fip and fiop have to be decreased both, but this is done in two steps. The program is as follows:

P(SHS);
if fip = 0 then disaster else dec(fip);
if fiop = 0 then
      begin pmshr := 3; V(SHS); P(pmsem) end
            else
      begin dec(fiop); V(SHS) end

after which the PM has got the permission to fill an empty segment.

The PM tries to do dec(fip) and then dec(fiop); if the first one is unsuccessful, disaster is signalled, otherwise it is done. If the second one is also successful, we are immediately ready, otherwise the PM leaves the critical section after having set

pmshr = 3       | "The PM is waiting on account of inability to perform dec(fiop) in SH1"

After having left the critical section it waits.

The complementary action takes place in the critical section of a process that has increased fiop. After having done so it has to inspect, whether any pmshr = 3 is present. If so, it performs for the PM concerned

"dec(fiop); pmshr:= 0; V(pmsem)"

i.e. the decrease, which the PM was unable to do; then it sets pmshr = 0, as the decrease requested has been performed and finally it signals to the waiting PM that it can go on.

Note. if "fiop" is the limiting factor, total output must exceed reso (otherwise, namely, disaster would have been signalled). On the other hand we shall guarantee that there will be active output already, if the total output exceeds maxu. Therefore: 1) the task to resolve "pmshr =3" can be delegated to o-decrease in active output only and 2) the PM has nothing else to do because there will be active output and the o-decrease will occur.

The other operation with possibly two decreases is SH4: p-o-transition in the case of an unselected document for a pluncher. If so, the two decreases will again be a two stage affair. We give the raw outline of the program, the discussion of "desire" (a stream variable), "banker" (a universal procedure) the constant "maxpor" and the PM-variables "bsn" and "request" will be postponed.

SH4: P(SHS); bsn:= "stream identification";
      if unfsel = 0 then
      begin if fpas = 0 then
            begin pmshr:= 1; desire:= 1; banker;
                  V(SHS); P(pmsem); P(SHS) end
                        else
            begin inc(lufd); dec(fpas) end
      end;
      if fio < maxpor then
      begin pmshr:= 2; request:= 1;
            V(SHS); P(pmsem); P(SHS) end
      dec(fio);
      "Now the p-o-transition can be effectuated, followed by:"
      inc(fip).

The quantity desire is a stream variable, its usual value is zero. For a pluncher stream its sole purpose is to influence the procedure "banker" which compares the lengths of various unfinished, unselected documents, but it then takes

"lufd + desire" .

The main point is the distinction between desire = 0 and desire = 1, both with lufd = 0; the difference between a document being empty for lack of interest or for lack of space. In the first case it is not a suitable candidate for selection, in the second case it might be.

The next state, described by the state variable pmshr is

pmshr = 1    The PM is waiting on account of inability to perform dec(fpas) in SH4.

It implies that the blocking stream is a pluncher stream, containing an unselected document. The existence of one or more "pmshr = 1" implies "fpas = 0".

There are two ways, in which the PM can be helped over this barrier

a) After increase of fpas. The processes increasing fpas have the duty to investigate whether now PM's sleeping have to be woken up. Waking up then consists (within a section, critical to SHS)

"pmshr:= 0; dec(fpas); inc(lufd); desire:= 0; V(pmsem)"

(Here the initial choice is the waiting PM; a variable bsn (blocking stream number) tells, in which stream "lufd" and "desire" have to be selected. "bsn" is superfluous: it points to the one and only pluncher stream of this PM with "desire = 1")

b) By selection of the stream in question. For this makes the desired "dec(fpas)" unnecessary. The actions comprise:

(for the selection) "INC(fpas, lufd); lufd:= 0; unfsel:= 1"

and, provided desire = 1 (then pmshr = 1 as well)
for waking up) "pmshr:= 0; desire:= 0; V(pmsem)"

When the first barrier has been passed, the second comes: instead of asking whether the current value of fio allows the decrease wished for this time, we always decide on

fio < maxpor

following a suggestion by C.Ligtmans.

The price paid is that the last maxpor-1 available output segments remain unused, when the printer is unused. The advantage, however, becomes apparent, as soon as we investigate what happens when plunchers decide on "fio < 1" and only the printer on "fiop < maxpor". In that case output limitation might easily lead to stopping of the printer stream. Also, we can now state, that the existence of one or more "pmshr = 2" implies "fio < maxpor"; if fio increases we can select the PM with pmshr = 2, regardless the type of the blocking stream.

We have the meaning

pmshr = 2       | "The PM is waiting on account of the inability to perform DEC(fio, request) for request ≤ maxpor.

If some process decides to wake up a PM with pmshr = 2, it does so by

"pmshr:= 0; DEC(fio, request); request:= 0; V(pmsem)"

It is the function of the procedure "banker" to try to wake up PM's with pmshr = 1. It will always be called from within a critical section, it may be called from a PM, but also from a CM.

Its total action may end in two ways:
either there are no pmshr = 1 any more (fpas may have any value) or there are still pmshr = 1 (and fpas = 0) but it has not been able to remedy the situation.
This last thing can happen in two ways

a) an unfinished document may be unselectable on account of absence of an idle pluncher of the correct type
b) an unfinished document may be unselectable on account of disapproval of the banker's algorithm.

Waking up a PM with pmshr = 1 will imply "pmshr:= 0; V(pmsem)", waking up an idle pluncher (characterized by "pluvar = 1") will imply "pluvar:= 0; V(ocmsem)". Note that waking up may be applied to the abstract machine (either PM or CM) from which the banker happens to be called.

The only tool available for the banker is to make an unfinished document selected; this may have a double effect.
1) The stream is question may be a blocking stream for a PM with pmshr = 1; this makes the requested dec(fpas) no longer necessary and the PM has to be woken up
2) Furthermore fpas may increase on account of which pmshr = 1 can be removed.

Roughly, the procedure "banker" has the following body:

L0: if fpas > 0 then goto finish;
      if non exist(pmshr = 1) then goto finish;
L1: if non exist(pluvar = 1) then goto finish;
L3: if "there exists an unfinished document in an otherwise empty stream with lufd + desire > 0 and a corresponding pluvar = 1, selection of which is allowed by the banker's algorithm" then
select the document:
      begin dec(plucash);
            pluvar:= 0; etc. for pluncher; V(ocmsem);
            INC(fpas, lufd); lufd:= 0; unfsel:= 1;
            if desire = 1 then
            begin comment a blocking stream happens to be selected;
                  pmshr:= 0; desire:= 0; V(pmsem) end;
            use fpas for waking; goto L0
      end
finish:

with the procedure use fpas for waking;
      begin LL: if fpas > 0 and exist(pmshr = 1) then
            begin pmshr:= 0; dec(fpas) inc(lufd); desire:= 0; V(pmsem);
                  goto LL end
      end

In the conditional clause labelled "L3" the banker inspects the streams with "nfd = 0" (nfd = number of finished documents. "nfd = 0" means that the stream contains at most an unfinished document) for which a corresponding pluncher is idle (pluvar = 1) and inspects them in order of decreasing "lufd + desire". The first allowed by the banker's algorithm but still with "lufd + desire > 0" is taken. As a rule the banker will select at most one unfinished document; as it looks for the longest one it will cause the maximum increase of fpas possible. Note, that in SH4 the banker is called after the PM has set pmshr and desire; it may be this very document, that needs to be selected.

Further the banker is called whenever a change in circumstances occurs, that may create the possibility for succesful action.

A more complete version of SH8 (Finish Pluncher Document) is therefore:

SH8:
P(SHS); inc(nfd);
if unfsel = 1 then
begin unfsel:= 0; inc(...cash);
      if ...cash = 1 and ...fp < 0 then
      begin INC(fpas,...fp);...fp:=0; use fpas for waking end;
      banker
end
            else
begin if ...cash = 0 then
      begin INC(...fp,lufd); lufd:= 0 end
                  else
      begin INC(fpas,lufd); lufd:= 0; use fpas for waking;
            if exist(...var = 1) then
            begin ...var:= 0; etc. for pluncher; V(ocmsem) end
      end
end;
V(strsem); V(SHS)

Remark 1. "strsem" is a streamsemaphore that is also increased at ever new portion added to the stream. It is used to synchronize the output CM, when it has selected this stream.

Remark 2. It is felt that the choice of the PM in the case of multiple "pmshr = 1" in "use fpas for waking" is highly irrelevant.

When the pluncher has finished the processing of a document, it will do a final "P(strsem) -as the complement of the V(strsem) in SH8- in order to guarantee that the pluncher will never look for a new job, before the corresponding SH8 is duly completed.

If it then finds a finished document on top of one of its (unselected) streams, it takes it, otherwise it does

"pluvar:= 1; banker; V(SHS); P(ocmsem)"

When this last P-operation has been completed, a new document (finished or not) has been selected.

We shall now give a short description of the high speed printer. It may be used from wise, so we are independent of the banker's algorithm. Nevertheless it is unattractive to have the printer forms from different sources all mixed up: it should like to print a number of successive forms from the same program successively. Therefore: if the different printer streams contain very few forms, the printer will delay selection, if possible, in order to wait, until one of the streams has a reasonable amount available. This delay is no longer necessary, if one of the programs has produced its last form, it is no longer possible, if the total output increases beyond maxu, without other output being active. (Below, we shall use an other criterion to regulate printer activity.)

In each printer stream the final form, produced by a program is marked as such; the number of such final forms is counted (we may use "nfd" for this purpose, now meaning "number of final documents"). It is increased at the chaining on of the final form (by the PM), it is decreased by the printer CM, at processing of the final form.

The printer may be idle in two different ways:

privar = 1     | dependent on past history: the last form printed was not a final document, the stream in question, however, is empty, and the printer prefers to wait -as long as possible- for the next form from the same stream.
privar = 2 | independent of past history: the printer has not printed yet, or the last form printed was a final document (or one program is in danger of monopolizing the printer).

We must prevent one very active PM from monopolizing the printer; we propose to do so, by "forgetting the past history" after, say 20 consecutive forms from the same stream.

Idleness of the printer can always be removed for two different reasons
1) there is a form available that the printer should love to select
2) there is no such attractive form, but the printer should get in action on account of the maxu barrier.

In the case of "privar = 1" the attractive reason is a form in the current stream, in the case of privar = 2, the attractive reason is, in some printer stream, a positive nfd.

The unattractive reason is -under both circumstances- something of the nature of total output exceeding maxu, and no other output active. Let us construct this criterion a little bit more carefully.

For the plunches we have passive output and the active output. We can leave the active output out of consideration, because that will disappear: without further PM activity, the passive output will remain, and the printer activity must be such, that yet the total amount of growth of buffered output will in due time not exceed maxu. As fpas is the amount of growth of passive information, that we can admit, the criterion for activity of the printer is

                       fpas < sump

where "sump" is the sum of the lengths of the printer streams (measured in segments).

The quantity "sump" is increased as part of the SH4 for a printer document and it is decreased as part of the printer form processing by the printer CM.

Similar to "banker", that caters for pluncher document selection, we have a procedure "printer selection"; it will only be called from within section, critical with respect to SH5 and will have no effect, when the printer is not idle. First it looks for attractive reasons to go on printing, then it looks for the unattractive ones.

printer selection:
if privar = 1 then
begin if current printer stream non empty then
      begin privar:= 0; V(prisem) end
            else
      begin if fpas < sump then privar:= 2 end
end;
if privar = 2 then
begin if exist (0 < nfd) then
      begin privar:= 0; select stream with positive nfd etc; V(prisem) end
            else
      begin if fpas < sump then
            begin select stream with printer information etc; V(prisem) end
      end
end

This routine is called
1) after dec(fpas) in SH4 for pluncher documents (as now fpas < sump might hold)
2) in SH4 for printer documents as sump has been increased and now, again, fpas < sump might hold; furthermore the current printer stream may have become non empty.
3) at program exit, where "nfd" is increased
4) by the printer CM itself, after processing of a form:

P(SH5);
if previous form final or number of successive forms of the same program more than, say 20 then privar:=2 else privar:= 1;
printer selection; V(SH5); P(prisem)

After completion of this last P-operation there will be a next form in the now current stream.

SH4 for the printer forms will have the form:

P(SH5);
if fio < maxpor then
      begin pmshr:=2; request:= current form size; V(SH5); P(pmsem); P(SH5) end
            else
      DEC(fio, current form size);
"now the p-o transition can be effectuated, followed by"
INC(fip, current form size);
INC(sump, current form size);
printer selection;
V(SH5)

Remark. In the procedure "use fpas for waking" a "dec(fpas)" may occur, but nevertheless, there is no need to call the "printer selection" there. For this routine "use fpas for waking" has only an effect when "exist(pmshr = 1)", that is, while at some earlier stage, fpas was = 0. The final value of fpas will be = 0 or more: as a result this cannot be responsible for the creation of the situation

"fpas < sump".

Afterthought. The 20 successive forms rule had probably better be overruled if "0 < nfs of current stream"; the program has ended its activity and the danger of monopolization canot persist very long any more.

Remark on the safety of printer activity control.

A PM may be blocked after the succesful performance of "dec(fpas)" but before succesful performance of "dec(fio)"; the decrease of fpas may be ahead of that of fio. In that case the printer is sooner urged to activity, the out-of-phaseness can therefore never give rise to output blocking, due to the printer failing to recognize its duty to go to work. On the other hand, it can never be urged to go to work too soon, i.e. without printer forms actually present in the buffer for sump must be positive. The increase of sump takes place in the same critical section as the chaining on, it can be regarded as "in phase".

Strategy and output limitation

Only in one case -selection of unfinished pluncher documents- we have specified in which order the documents are scanned: in that of decreasing length. But we have more to specify:
1) if a pluncher makes a choice between finished documents, from which stream will it select?
2) if the printer (with privar = 2) finds streams with positive nfd, from which one does it select?
3) if the printer (with privar = 2) has to select a stream on account of "fpas < sump", which one has to be selected?

and, as counter part

4) if in SH6 it is inspected which PM with pmshr = 2 can be woken up, which one is selected?

First we remark, that our targets are twofold: we wish to keep the output equipment as busy as possible and should avoid that in some "active streams" the actual speed is zero, because all available outputarea has been usurped by another stream. This can be remedied by keeping the streams as much as possible, equally long; P.A.Voorhoeve has suggested to achieve this via favouring in the removal of pmshr = 2 (building up of the stream) the shortest one and by selection by the CM's favouring the longest ones. This seems to have attractive properties, if all PM are filled with output producing programs. However: if a PM has processed a program that produced a little bit of output in an empty stream, and no next program produces further output in this stream, the stream length may be so short, that it is never selected for consumption. To remedy this, we could try to introduce a kind of "ageing factor".

We introduce a universal "portion clock" which is increased by a fixed amount "alpha" at each completed SH4; furthermore we note for each stream the value of the portion clock at the latest SH4 completion with respect to this stream; call this stream variable "attachment time". Furthermore, we keep track of the stream length, measured in portions.

If the CM has the freedom to select finished documents or forms, it selects the stream with the maximum value of

             "length in portions - attachment time"

If a production at a stream stops, so that the stream may be very short, the CM's will in due time select this stream: the stream will get empty as desired.

When we have to select which pmshr = 2 has to be removed, we take the stream with minimal

      "length in portions + attachment time"

thus giving some preference to the stream to which the previous completed SH4 was longest ago. The behaviour with, say "alpha = 1/4" seems, up till now, very reasonable.

Speed regulation of the input CM's

At the moment of i-increase, all four quantities fi, fip, fio and fiop have to be decreased. The idea is that
a) the input CM tries to perform "dec(fi)" and "dec(fip)" immediately; if unsuccesful, there will be a distaster signalling.
b) then the desirability of "dec(fio)" and "dec(fiop)" is investigated. If these latter decreases are undesirable, the input CM will be retarded on this criterion.

We must bear in mind, that "disaster" may be unavoidable, because the readers are kept outside the banker's algorithm. We have put two requirements on our strategy
1) in granting "dec(fio)" and "dec(fiop)" the system should be somewhat conservative, in order to avoid tapes running in quite unnecessarily and thus provoking a quite unnecessary "fi" or "fip"-disaster. (Or even: hindering output buffering much more than defendable.)
2) in case of effective disaster, however, the speed regulation of the input CM's must be such, that the fi- and fip-alarm's must get the opportunity to signal it. (If one slows down the speed of the input CM's so that fi- and fip-alarm is too carefully avoided, one has to build in another mechanism to detect, that the complete system has got stuck.) We have chosen the following rules:
1) If not request for a free tape reader is pending, an input CM, wishing to perform "dec(fio)" and "dec(fiop)" will get permission to do so if "2 * current length of information stream < min(fio, fiop)"
2) if at least one request for a free tape reader is pending, an input CM, wishing to decrease fio and fiop will get permission to do so if

            "0 < min(fio, fiop)".

The points at which the need for input CM reactivation must be inspected are
1) at the end of the i-p-transition (where the current length of the information stream has been decreased).
2) at SH6 (o-decrease), where both inc(fio) and inc(fiop) have been performed.
3) at the moment where free tape reader request has been refused.

Remark 1. The first cause of removal will never get an opportunity if the stream is empty. Then, however, it will only stop if fio = 0 or fiop = 0, conditions which, after succesfull dec(fi) and Dec(fip), imply active output.

Remark 2. At SH6 the output CM will first inspect, whether input CM's that require decrease of both fio and fiop- should be reactivated; after that the fiop is used to help PM's waiting at SH1 and the fio is used to help PM's waiting at SH4.

Remark 3. If an input CM builds up a new portion, it might simultaneously request a portion in transput area:

P(SH5);
if fi = 0 or fip = 0 then goto disaster;
dec(fi); dec(fip);
if (if free tape reader requested then 0 else 2 * lenght of current stream) < min(fio,fiop) then
begin dec(fio); dec(fiop); V(icmsem) end
            else
begin icmvar:= "characteristic value" end;
V(SH5);

build up next portion

P(icmsem)

now the i-increase can be effected.

Every process, granting a segment to an input CM must perform (within a section critical to SH5)

"icmvar:= 0; dec(fio); dec(fiop); V(icmsem)" ;

this may take place during the whole period of building up the next portion. (this technique of a pending request, already pending during the activity of the input CM is a noverlt; it is however perfectly sound.)

Remark 4. If a request for a free tape reader is pending, both readers will read at maximum speed. This is somewhat naieve, but we could not convince ourselves that more elaborate constructions were significantly better.

The description of document selection for input CM's, although already designed, will be postponed, being closely related to the structure of the keyboard program.

transcribed by Ike Naar
revised Tue, 15 Aug 2006

EWD 131

Verslag van bezoek aan de Arbeitstagung fuer Automatentheorie te Hanover.

        Het primaire doel van de reis was, om er achter te komen in hoeverre de Duitse automatentheorie (het vak wordt bij mijn weten in Nederland niet bedreven) voor ons relevant lijkt; het nevendoel was om door middel van een zorgvuldig voorbereide voordracht wat reclame voor Nederland te maken. Beide opzetten schijnen geslaagd te zijn. En passant deden we wat "achtergrondinformatie" op over de aard van mensen en werkzaamheden aan de verschillende Duitse centra, achtergrondinformatie, die mij niet onwelkom was.

        Het programma was overladen op een manier, die ik niet voor mogelijk gehouden zou hebben; voordrachten van 's morgens kwart voor negen tot 's avonds half zeven met een anderhalf uur tussen de middag, en beide zittingen slechts onderbroken door een pauze van een kwartier. Er waren naar schatting tachtig deelnemers in een collegezaal met een capaciteit van zeventig; het was opvallend hoe weinig er gespijbeld werd.

        In de voordrachten waren drie hoofdonderwerpen te onderscheiden,
        1) ontwerp van logische schakelingen
        2) gecastreerde Turing machines
        3) linguistisch allerlei.

        De lezingen uit de eerste categorie hadden het voordeel, dat de sprekers zich in elk geval op een duidelijke klasse problemen geworpen hadden, nl. de optimalisering van logische schakelingen, een probleem waarvoor in het algemeen geen hanteerbare algorithme bestaat. In de praktijk lost men deze problemen dus op door "geleide intuitie"; de sprekers beijverden zich om diverse aspecten van de "leidraad" bloot te leggen. Mede, doordat men in verschillende opzichten kan willen optimaliseren (zoals benodigd materiaal en schakeltijd) ontstond er tussen de geinteresseerden af en toe een levendige discussie, die in de oren van een buitenstaander als mij zinvol leek. Dit stuk van de automatentheorie beschouw ik na deze kennismaking als voor mij niet relevant; het is ons probleem niet, ik vond het te onaantrekkelijk om me geroepen te voelen er mijn probleem van te maken en ik kreeg niet de indruk, dat de gepresenteerde technieken in ontwikkeling, zich buiten de oorspronkelijke probleemstelling als het ideale gereedschap zullen ontpoppen.

        De lezingen uit de tweede categorie hadden het nadeel, dat ik noch van te voren, noch na afloop, enig idee had, waar deze onderzoekingen goed voor waren (waar nog bij komt, dat voor sommige verhalen "onderzoekingen" een wat groot woord is). Ik heb niet aan de indruk kunnen ontkomen, dat het werk van Turing te groots is geweest: in de dertiger jaren heeft hij een vak geschapen, dat daarmee af was. Door de Turingmachine allerlei beperkingen wel of niet op te leggen, schept men een horde van wat mij treft als wanstaltige gedrochten, waarop een classificatiecultus tot weelderige bloei is gekomen.

        Het linguistisch allerlei —dat wij niet meer hebben bijgewoond— bestreek —merkwaardig genoeg!— onderzoekingen over het Duits; verder verhalen in het kielzog van Chomsky. Nadat Floyd bewezen heeft, dat de vraag, of een syntaxis dubbelzinnige constructies toestaat, in het algemeen undecidable is, is voor mij deze kous af; buiten deze belangrijke stelling heb ik er verder niets in gevonden, waarvoor ik warm kon lopen. Er is een aantal open deuren ingetrapt, de verdere preoccupatie met bij voorkeur pathologische syntaxes heeft op mij althans voornamelijk de indruk gemaakt van een kwaadaardig gezwel.

        Buiten dit kader vielen vier van de voordrachten op de tweede dag.

        Ik had het voorrecht, die dag als eerste spreker op te mogen treden; de zaal was nog niet benauwd en ik mocht me verheugen op een geboeid gehoor. Ik heb gesproken over "Cooperating Sequential Processes, a form of Non-Deterministic Machines". Het laatste gedeelte van de titel was speciaal met het oog op dit publiek toegevoegd.

        De laatste morgenlezing was van een zekere Frank, hoogleraar aan een Pedagogische Hogeschool te Berlijn. Vervuld van de meest sombere voorgevoelens ben ik daar weggebleven; Habermann heeft hem wel aangehoord en was bijzonder aangenaam getroffen door de realiteitszin van de spreker.

        De middag werd geopend door een zekere Goehring over leerprocessen. Dit was het prototype van de lege voordracht; ik heb op het punt gestaan me in de discussie te mengen, maar te elfder ure drong tot mij door, dat deze Goehring de prijsleerling van collega Haendler, de organisator van het geheel, was. Om de prettige atmosfeer niet te bederven heb ik mijn mond maar gehouden, wat ik nog steeds beschouw als een niet te onderschatten staaltje van zelfbeheersing.

        De laatste voordracht, die wij gehoord hebben, was van Petri. Helaas had hij zich bij de voorbereiding onvoldoende gerealiseerd, hoe weinig je in een uur vertellen kan als je aanpak maar ongewoon genoeg is, zodat hij niet veel verder is gekomen, dan zijn inleiding. De quintessence van zijn betoog was, dat hij automaten en eindige, discrete physische systemen niet als verschillend wilde beschouwen; hierop entte hij een axiomasysteem (waarin in elk geval verdisconteerd waren de constantheid van de lichtsnelheid, de lokale reversibiliteit van physische processen en de onmogelijkheid een willekeurig fijne onderverdeling van een tijdsinterval te verwezenlijken), kennelijk met de bedoeling om de mogelijkheden van physisch realiseerbare automaten af te bakenen. De zorgvuldigheid van zijn presentatie, de omvangrijke kennis, die hier aan ten grondslag lag, en de orginaliteit, maakten dat ik slechts volmondig met hem kon instemmen, toen hij met "Das tut mir leid", reageerde op de opmerking, dat zijn tijd verstreken was.

        Al of niet hernieuwde kennismaking met Petri (Bonn), Felsch (Kiel) en Becvar (Liberec , CSR) verzoenden ons met veel. En, zoals wel al zal zijn doorgeschemerd, viel er wel het een en ander te verzoenen. In het verleden hebben wij kunnen waarnemen, hoe de Tale Kanaans zich ontwikkelde tot een techniek om uren lang te spreken, zonder daarbij iets te zeggen. Jargon en formularium van de verzamelingsleer en de groepentheorie gaan hard dezelfde kant op.........
Het was deprimerend om mee te maken, hoe gedwee dit publiek deze maskerade accepteerde. Wij konden tenminste nog troost putten uit de overweging, dat onkunde de meeste Nederlandse wiskundigen beschermt tegen de verleiding om hun formules met Gothische hoofdletters een nog indrukwekkender aanzien te geven.

E.W.Dijkstra

25 oktober 1965

transcribed by Maria C. Dijkstra-Debets
revised Thu, 10 Mar 2005

EWD 132

An Experiment with the "record class" as suggested by C.A.R.Hoare

The primary purpose of this experiment has been to try out the usefulness of the concept of the "record class" as suggested by C.A.R.Hoare. I have selected the algorithm to find the shortest route from one town to another via a map if only the direct town to town connections of this map are given.

Seven years ago I coded this in machine code and at that time it was one of the toughest programming jobs I had ever done. To say that, compared with this early effort, Hoare's record class allows a tremendous simplification in the formulation of the algorithm is of course a next to empty statement. But I invite anybody who is interested in the adequateness of the "record class" as a tool and has grasped the algorithm, to rewrite this program in ALGOL 60 as it stands. Let him embellish his program as much as he likes in the name of his standard of clarity and elegance (for so did I with mine!) and let him then compare them. I am so much convinced that the comparison will turn out in favour of the program making use of the record classes, that I am beginning to ask myself whether I have selected the one problem to the needs of which to the record classes are really tailored.....

The secondary purpose of this experiment has been to show what beauty can be achieved (and at what price) if one refuses to make use of goto statements. In this example I have used the simple while clause without controlled variables (to make legal ALGOL 60 of it, one could insert "for dummy:= 0" in front of every occurrence of the character "while".) The preceding version of this program contains nine labels and nine goto statements and was accordingly messy.

Now some explication. The linking by the field "fol" serves a dual purpose. It connects all towns in a single chain; from "start" to "last placed" it contains the towns for which the path of minimum length from "start" has been established and it does so in the order of increasing path length (which is also the order in which the towns are attached to this part of the chain in time), from "last placed" to "end" it contains, in irrelevant order, all towns with at least one direct connection to a town in the range from and including "start" up till and including "last placed". For all towns in this chain we keep track of the minimum distance from "start" found thus far and the field "previous" indicates the town, via which this minimal path finally leads to it. For each town, added to the first part of the chain, we make the second part of the chain up to date by inspecting all the roads leading out from it; after that we select from the second part of the chain the town with minimum distance found thus far and this is the next town to be transferred to the first part. As soon as "finish" has been transferred to the first part of the chain, the problem of the minimum path from "start" to "finish" has been solved.

The topology of the map is given as follows. The roads leading from a town are arbitrarily ordered, the source town contains a reference to the first road leading out of it, each road contains a reference to the next road, leading out of the same source town, if such a road is present, otherwise the field of such a road reference will contain "null". (Roads are on this map directed connections, {....} have towns without roads leading out of it, the dead alley.)

The algorithm may end in two ways: either it finds the connection (last placed = finish) or it decides that the map does not provide for a connection from "start" to "finish". This is decided to be the case when the second part of the chain (from and excluding "last placed" up to and including "end") is empty at the moment, that a town from the second part has to be transferred to the first part; it causes this outcome by "last placed" = null".

Now some comments on the structure of the program. The outermost while clause ("while last placed ≠ finish and last placed ≠ null") controls the repetition of the statement in which

1) the second part of the chain is made up to date as result of a newly placed town (i.e. just transferred to the first part of the chain);

2) from the updated second part a new town is selected and transferred to the first part (provided the second part is not empty, for them the algorithm ends with "last placed = null)

The while clause ("while trial ≠ null") controls the repetition of the statement in which the updating consequences of the road "trial", emanating from "last placed" are performed and the next road emanating is made the next trial.

The while clause "while scanned ≠ goal do" investigates whether goal = destination(trial) (i.e. the town, to which "trial" leads) occurs already in the chain; if not, it is quickly added, so that the next time it does belong to the chain and the while clause is terminated. This (and the preliminary distance "+ infinity") is one of of the extra prices to be paid for the absence of goto statements. At first sight it is a trick, but after some consideration it becomes such a neat one, so perfectly sound, that it may develop into a method.

The conditional resetting of the distance is by necessity non-active if "goal" was already in the first part of the chain, on account of "+ infinity" active if "goal" has just been added to the chain.

When the second part of the chain has been updated, the new town must be selected. If the second part of the chain is non-empty, "premin" is made to point to the predecessor of the selected town. This is done in the while clause "while prescanned ≠ end do". Then the selected town is placed at the beginning of the second part (unless it is already there) and finally last placed is moved over one town.

Note. I am aware that the algorithm could be speeded up at the price of more fields in the town records.

record class town;
      begin reference first out(road), fol, previous(town); integer distance end;
record class road;
  begin reference destination(town), next out(road); integer length end;

reference start, finish, scanned, prescanned, last placed, goal, premin, end(town),
          trial(road)

"Now the data must be given. Of the records "town" the field "first out" must be defined (may be = null), the fields of the records "road" must all be defined. "start" and "finish" (both ≠ null) must be given."

end:= last placed:= start; fol(start):= previous(start):= null;
distance(start):= 0;
while last placed ≠ finish and last placed ≠ null do
begin trial:= first out(last placed);
      while trial ≠ null do
      begin goal := destination(trial); scanned:= start;
            while scanned ≠ goal do
            begin if scanned = end then
                  begin fol(end):= goal; end:= goal; fol(goal):= null;
                        distance(goal):= + infinity
                  end;
                  scanned:= fol(scanned)
            end;
            if distance(last placed) + length(trial) < distance(goal) then
            begin distance(goal):= distance(last placed) + length(trial);
                  previous(goal):= last placed
            end;
            trial:= next out(trial)
      end;

      if last placed = end then
               last placed := null
                           else
      begin premin:= last placed; prescanned:= fol(last placed);
            while prescanned ≠ end do
            begin if distance(fol(prescanned)) < distance(fol(premin)) then
                                          premin:= prescanned;
                  prescanned:= fol(prescanned)
            end;
            if premin ≠ last placed then
            begin scanned:= fol(premin);
                  fol(premin):= fol(scanned);
                  fol(scanned):= fol(last placed);
                  fol(last placed):= scanned
            end;
            last placed:= fol(last placed)
      end
end

transcribed by Tristram Brelstaff
revised Sun, 5 Jul 2009

EWD137 - 0

Heel kort verslag bezoek aan het symposium over Multi Access Computers
2 - 4 november 1965 in het NPL.

Het symposium was zeer slecht georganiseerd. Men was er op persoonlijke uitnodiging (ongeveer 75 man), bij de uitnodiging tot deelname was ook een uitnodiging tot bijdrage, gesteld in zodanige termen, dat ze nauwelijks "Nee" konden zeggen, als iemand antwoordde, dat hij wel wat te zeggen had. De hieruit voortvloeiende overlading laat zich raden. Doordat geen enkele spreker was uitgenodigd om in een paar regels zijn onderwerp aan te duiden, waren er lezingen, die helemaal buiten het programma vielen of op de verkeerde plaats in het programma waren gezet. Voorts waren de deelnemers over allerlei hotels verspreid, zodat er weinig terecht kwam van de "ongedwongen contacten", iets, waaraan door de overlading juist zoveel behoefte was.

G. Seegmueller uit München gaf een beschrijving van het "control system" dat zij voor de TR4 ontwikkeld hebben. Een Engelse vertaling van een Duitse publicatie hierover heb ik destijds niet kunnen begrijpen, zijn voordracht hierover was uiterst helder. (Waarschijnlijk door het gepast weglaten van details.) Het zich gestelde doel hadden ze hiermee bereikt -iets, waar hij met gepaste trots geen doekjes omheen wond-; hij liet er ook geen twijfel over bestaan, dat hij er op uitgekeken was. Hij kreeg terecht een hartelijk applaus.

De bijdragen uit The Mathematical Laboratory, Cambridge, waren eigenlijk wat triest. De ideeën, die Wilkes opperde, waren nu juist de dingen, die we allemaal wel eens geprobeerd hebben, maar weer hebben laten schieten, omdat ze bij nader inzien niet duidelijk genoeg waren. Je kunt ze samenvatten als maatregelen, die microscopisch gezien versnellingen mogelijk maken, maar onder voorwaarden, die macroscopisch nare gevolgen hebben. En het werk van de software groep is deprimerend (It is a lousy machine but we make the best of it.), temeer, omdat uit wat ze zouden willen (maar niet kunnen) blijkt, dat ze wel een consistente "philosophy" hebben. Ik vind dit erg jammer, omdat ze een paar heel goede mensen hebben, opgescheept met een historisch wel verklaarbare erfenis.

Er was veel uit Amerika; ze hadden met zorg mensen uit heel verschillende projecten genodigd. Sommige bijdragen konden me gestolen blijven, zoals uitgebreide analyses over "scheduling techniques", maar dan toegepast op machineconfiguraties, waarvan inmiddels iedereen overtuigd was, dat ze hoogst ongeschikt waren om veel consoles tegelijkertijd te bedienen. Dit gaf wel een juist historisch beeld, ze hebben het met deze apparatuur gedaan en het was natuurlijk instructief om te zien, in wat voor bochten deze mensen zich hebben moeten wringen. Er is aan deze m.i. niet meer actuele problemen wel erg veel tijd besteed. Er waren een aantal andere bijdragen uit Amerika, die heel verfrissend waren. Er was het verslag van een man, die bij wijze van research contract had mogen onderzoeken, in hoeverre het informatieverkeer in een groot hospitaal zich laat automatiseren en nu een proefopstelling ($ 800.000,-- aan hardware) in bedrijf had. De boventoon bij de Amerikanen werd gevoerd door mensen van project MAC (MIT) en General Electric, die in overleg met MIT (en BELL, als ik het goed begrepen heb), de apparatuur levert. Dit keer werden de reclameleuzen, (dat multiaccess computing een revolutie betekent etc.) ons bespaard -ik zou haast zeggen: integendeel, met uitzondering van Perlis-; er waren veel leukere dingen te observeren. Software maken is niet meer je behelpen met een van God gegeven machine, men raakt er gelukkig steeds meer van overtuigd, dat de specificaties van de hardware komen moeten van de man, die de software maken moet, of althans dat je samen verstandig over de taakverdeling moet denken. En in dit opzicht heeft multi access computing heel veel wakker geschud.

EWD137 - 1

In dit korte bestek heb ik nauwelijks een volledige indruk kunnen krijgen over de GE machine, waarop ze dit gaan spelen. Ze hadden veel aandacht besteed aan het interruptiesysteem, en mij werd verzekerd door Dennis -en ik heb geen reden om aan hem te twijfelen- dat het consistent was. De adresseringstechniek was duidelijk geënt op mijn dierbare vriend, de B5000. Als General Electric wel kans ziet, hier een zakelijk succes van te maken, zou het leuk zijn, als ze wat naar Burroughs overhevelden, die de spits daar heeft afgebeten. Of het allemaal goed is, wat ze gedaan hebben, weet ik niet, helemaal gerust ben ik er helaas niet op.

Er is voorts een artikel uitgereikt van twee mensen, die niet aanwezig waren, het werd heel kort gepresenteerd door Dennis over de "file organisation" van de nieuwe versie van project MAC. Ik heb nog geen tijd gehad, dit zo grondig te bestuderen, dat ik alle implicaties ervan doorzie, ik ben wel van plan, dit op korte termijn te gaan doen. Mijn eerste reactie was een van groot enthousiasme, omdat ik de indruk kreeg, dat ze precies gemaakt hadden, wat ik sinds een paar maanden probeer te construeren: een sluitend identificatiesysteem voor objecten van gemengde levensduur. Hoe sluitend hun systeem is werd bij nader inzien wat minder overtuigend. Ik zal hun verhaal bestuderen en hoe de uitslag ook zij, ik ben in elk geval erg dankbaar voor deze confrontatie. Is hun oplossing bevredigend, dan ben ik ook klaar met het probleem, is hun oplossing het niet, dan is dat een aansporing om er echt in te duiken. Hun hele systeem is hieromheen gebouwd en ik zie hierin een bevestiging van mijn vermoeden, dat dit probleem heel vitaal is. Als bijproduct zou ik misschien kunnen doorgronden, wat nog geen administrateur over zijn eigen activiteiten heeft begrepen.

Mijn bijdrage werd met groot enthousiasme ontvangen.

E.W. Dijkstra

Transcribed by Frank Steggink
Revised Tue, 6 Jan 2004.

EWD139 - 0

Appreciatie van ponskaarten

In het volgende hoop ik overtuigend te motiveren waarom ik de vraag, of de EL X8 van de THE met ponskaartenapparatuur uitgerust moet worden, met een volmondig "Neen" beantwoord. De uitgesprokenheid van mijn oordeel is alleen dan gerechtvaardigd, wanneer ik in mijn motivering het medium ponskaart in alle fairheid benader. Het volgende is een proeve van mijn fatsoensvermogen in die richting.

Ik observeer, dat de ponskaart groot geworden is in de tijd van vóór de general purpose rekenmachine. Om dit medium zijn beperkt programmeerbare special purpose machines ontstaan, zoals reproducers, sorteermachines, tabulators, collators, controleponsers etc..
Het is mijn overtuiging dat veel van het mogelijke profijt, van dit medium slechts dan geplukt kan worden, als men metterdaad over voldoende van de genoemde, op dit medium afgestemde apparatuur beschikt: het voordeel, dat ponskaarten goed sorteerbaar zijn is zonder sorteermachine moeilijk realiseerbaar. (Dit neemt niet weg, dat de aanwezigheid van een general purpose automaat wel verschil maakt: het feit, dat een snelle sorteermachine aan de X1 kon worden aangesloten, waarbij de X1 de sortering kon besturen, heeft er vaak toe geleid, dat sorteerprocessen, die nu immers op veel complexere criteria konden worden uitgevoerd, na een X1 plaats vonden, dit met drastische beperking van het aantal doorgangen. Door de beperkte stopmogelijkheden van de sorteermachine betekende dit voor de rekenautomaat helaas wel de introductie van een essentiële haastsituatie.)

De stijl, waarin men met ponskaarten werkt is in het verleden natuurlijk sterk door de eigenschappen van de speciale ponskaartmachines beïnvloed. Het is mijn overtuiging, dat deze invloed zal blijven, met name daar, waar de ponskaart nauw verbonden is met leesbaar schrift. (Het is duidelijk, dat er sinds productie door en voor automaten volledig nieuwe gebruiksvormen ontstaan zijn zoals "a pack of binary cards". Dit treft mij nu juist als het niet typische ponskaartengebruik: dat hier een heleboel informatie over losse kaarten verdeeld wordt, lijkt mij meer vervelend dan prettig en ik dacht, dat dit gebruik nooit ontstaan zou zijn, als de ponskaart er niet al was geweest.)

Deze gebruiksstijl manifesteert zich bv. in de gangbare controletechnieken, kort samen te vatten als "tweemaal is scheepsrecht". Ponskaartlezers en ponskaartponsers zijn voorzien van een extra controlestation, wat verder in de

EWD139 - 1

de baan, met de hand vervaardigde kaarten worden na controleponsing gecontroleerd. (De kaarten, die bij de controleponsing zijn vervaardigd plegen van een speciale markering te zijn voorzien: ervaring heeft geleerd, dat ze suspect zijn.) Naast pariteitschecks -tegen incidenteel slecht functioneren van de apparatuur - gebruikt men tegenwoordig waar mogelijk - bv. bij programmateksten! - liever structurele redundantie, waardoor de controle zich ook over het oorspronkelijk manuscript uitstrekt. (Het feilloos ponsen, waar dan ook in, van monotoon getallenmateriaal, van staten, blijft een probleem, waarvoor ik geen smakelijke oplossing ken. De moraal lijkt me, dat dit vermeden dient te worden.

Erger is wat ik zou willen aanduiden met de traditie der parallelle verwerking en de tyrannie der 80 kolommen.

Parallelle verwerking impliceert een a priori kennis over de omvang van een te verwerken hoeveelheid informatie. Door bv. integers te laten optreden als constituenten in een text met een recursief gedefinieerde syntaxis, is aan deze integers geen bovengrens opgelegd. In de ponskaartenwereld is het echter gebruikelijk de omvang van een informatie-eenheid - bv. een integer - door ad-hoc conventies vast te stellen (bv. het veld van de kolommen 7 t/m 12).

Om te beginnen merken wij op, dat het uitsparen der separatoren geen onverdeelde winst is: hier staat nl. tegenover, dat men altijd het maximum aan posities ter beschikking moet stellen. (Denk aan het volgnummer van programmakaarten, wanneer men bij programmawijziging de mogelijkheid wil hebben, kaarten tussen te voegen!) Erger is, dat men door de veldindeling van de kaart met allerlei bovengrenzen genoegen moet nemen; bovengrenzen die enerzijds de mogelijkheid van de sequentiële automaat miskennen (zie mijn college, sorry), anderzijds gauw hinderlijk zijn, omdat ze wegens de beperkte kaartomvang vrij - soms heel - scherp gesteld moeten worden.

Deze bedenkingen wegen bij mij heel zwaar: ik sluit niet uit, dat de scherpste kantjes er door herscholing vanaf te vijlen zijn; ik weet echter ook, dat ik me niet geroepen voel, om dit te ondernemen en bij gebrek aan nadere gegevens verlaat ik mij dus op observatie elders. Deze observatie omvat:

EWD139 - 2

de waarneming, dat in alle "card oriented programming systems" bv. het manual, dat verteld, hoe een of andere "control card" geponst moet worden, altijd de noodzakelijke positie op de kaart expliciet vermeldt;

dat - om der wille van uniforme verwerking in de ponskamer? - alle informatie, die op de kaarten geponst moet worden, positiebewust moet worden opgegeven, ook in die gevallen - programmateksten - waar dit niet de minste informatie draagt. (Zonneveld moet nu zijn programma's opschrijven op papier met voorbedrukte kolommen. Hij beklaagde zich bitter, hij had van zijn leven nog niet zoveel gestuft; en dat alles, omdat de ponskamer geen karakters "achter elkaar" kan ponsen! Ik zie geen reden om te veronderstellen, dat wij deze bezwaren zouden kunnen ondervangen en ril, in bescheidenheid bij voorbaat.) Samenvattend: sinds Alen Turing weten we, dat we ons moeten beperken tot aftelbaar veel mogelijke situaties, maar de ponskaart is een uitnodiging zich tot a priori enumereerbare gevallen te beperken.

Wat betreft de tyrannie hoef ik niet uitgebreid in te gaan op de bochten waarin men uitgenodigd kan worden zich te wringen. ("Als iemand nooit gehuwd geweest is, kan men het veld, normaliter gereserveerd voor kinderaantal (2 decimalen) gebruiken voor nadere polsspecificatie etc.") Ik vermeld slechts, dat deze tyrannie ernstige beperkingen oplegt aan een van de meest effectieve manieren om de leesbaarheid van programma's te verhogen: inspringen ter representatie van de structuur van het programma. (Dit is zo effectief, dat ik de Flexowriter boven de teleprinter verkies, misschien nog wel meer vanwege de mogelijkheid tot tabulatie dan vanwege het tweede alphabet. Het zou mij niet verbazen wanneer wij, zonder spijt van de Flexowriter te hebben, onze gebruikers zouden suggereren zich tot kleine letters te beperken!)

Mijn laatste bezwaar jegens de ponskaart is een van fundamentele onduidelijkheid in de manier, waarop ik geacht word aan de kaart zelf betekenis toe te kennen. Ik geef toe, dat deze overweging een variant lijkt op de vulgaire aanvat. "Als iemand een bak met kaarten laat vallen, etc" (Je kunt je mensen hoop ik leren, daar geen gewoonte van te maken. Bovendien: wie zo stom is om honderd meter paper tape in de knoop te laten raken is ook nog niet jarig!)

EWD139 - 3

Identificatie is, uiteindelijk, altijd een recursief proces. Als wij een willekeurige ponsband tegenkomen, weten we ook niet, wat deze betekent. We kunnen hem door de Flexowriter jagen, en als er dan een programma uitgetikt wordt weten we nog niet of dit soms niet een band met meetgegevens is. Er is maar een oplossing voor dit probleem: voorop elke band - in ponsing of met viltstift - in een metataal, verstaanbaar voor de mensen rond onze installatie, de band identificeren. En wanneer deze band dan via de prullebak en de straatgoot bij de BVD komt, dan blijkt die locaal voldoende, identificatie onvoldoende. Dus moeten we voorop elke band in een meta metataal "THE" zetten, etc. etc..

Een voor locaal gebruik, voldoende identificatie voorop een band fokken is moeilijk, maar, ik hoop, doenlijk. Op elke kaart is dit niet doenlijk. (Op het MC zijn wij genoodzaakt geweest in te stellen, dat iedereen die een onbeschreven band tegen kwam, deze vernietigde. Dit was heel heilzaam. De consequentie is, dat wij uit groepszelfdiscipline onze mensen instrueren elke niet-blanco ponskaart, die ze tegenkwamen, als betekenisloos weg te gooien. Dit is geen goedkoop grapje: het is een op de spits gedreven onlustgevoelen, waarvan ik met hoofd en hart weet, dat het meer dan gerechtvaardigd is.)

Hier wil ik het bij laten. Als mensen mij komen vertellen, dat zij met recht van ponskaarten gebruik gemaakt hebben, dan verandert die mededeling minder aan mijn opinie over ponskaarten, dan over de man.
Ik concludeer dan, dat deze man voldoende inventief of ordelijk geweest is om van een in wezen ongezond middel gezond gebruik te maken. Als pleidooi voor het medium - ik kan niet anders - is zo'n mededeling zonder enig effect.

Transcribed by Frank Steggink
Revised Tue, 6 Jan 2004.

EWD140

Documentatie over communicatie apparatuur aan de EL X8

0. Inleiding

Er is voorzien in een maximum van 48 zg. Apparaten, genummerd van 0 t/m 47.
Ze vallen uiteen in twee groepen:
nr. 0 t/m 31: de echte apparaten
nr. 32 t/m 47: de administratieve apparaten.
De administratieve apparaten verrichten parallel aan de basismachine zekere handelingen (zoals “tandenpoetsen” en “foutafhandeling”); deze apparaten hebben een vast nummer, dat niet installatie-afhankelijk is.
De echte apparaten in een specifieke installatie ontlenen hun nummer aan de plaats in de communicatiebekabeling; deze apparaatnummers zijn dus wel installatie-afhankelijk, kunnen zelfs gewijzigd moeten worden bij heropstelling.

1. Communicatie opdrachten.

Het opdrachtenrepertoire van de X8 heeft de mogelijkheid 1ste, (2de en 3de) zg. IF-woord in A of S te lezen. Tot nu toe is alleen de layout van het 1ste IF-woord beslist:

| d26 = permanent 0 ( is tekenbit)
| d25 = IF app. nr. 39
| d18 = IF app. nr. 32
| d17 = IF app. nr. 0
| d0 = IF app. nr. 17

Bij de laatste 26 toevoegingen betekent d = 1 : IF = true (IF = Ingreep Flip Flop).
Het zetten van IF's door de basismachine geschiedt individueel door opdrachten:

| zet IF true
| zet IF false

waarbij het apparaat wordt aangewezen door het adresgedeelte van de opdracht.
N.B. Deze opdrachten zijn B-modificeerbaar.
Voorts is aan elk apparaat toegevoegd een zg. LVIF (Luister Vergunning op de Ingreep Flip Flop), het opdrachten repertoire bevat de opdrachten:

| zet LVIF true
| zet LVIF false

waarbij weer het apparaat wordt aangewezen door het adresgedeelte van de opdracht. Ook deze opdrachten zijn B-modificeerbaar.
Tenslotte is aan elk apparaat toegevoegd een zg. AF (Actie Flip Flop); deze kan door de basismachine slechts in 1 richting gezet worden, nl.:

| zet AF true

waarbij weer het apparaat wordt aangewezen door het adresgedeelte van de opdracht. Ook deze opdrachten zijn B-modificeerbaar.
Tenslotte kent de basismachine:

| zet IV true (maak horend)
| zet IV false (maak doof)

(IV = Ingreep Vergunning).

2. Betekenis van IF, LVIF, IV en AF

Als een IF true is, betekent dit, dat de basismachine op ten minste 1 terugmelding van het apparaat in kwestie nog niet heeft gereageerd.
Een ingreep vindt plaats mits

IV = true and

Voor tenminste 1 apparaat geldt “LVIF and IF”.

Door het zetten van de LVIF's kan de basismachine reguleren, van welke apparaten het ingreepmechanisme al dan geen nota neemt. Door het zetten van IV kan de basismachine (nl., door “maak doof”) tijdelijk verhinderen door ingrepen onderbroken te worden.
De uitvoering van de ingreep bestaat uit de uitvoering van de opdracht op adres 24 in plaats van de volgende opdracht. Op adres 24 moet een niet stapelende subroutinesprong staan; zijn uitvoering is in twee opzichten bijzonder:

Het ophogen van de opdrachtteller OT wordt onderdrukt (de opdracht is immers niet onder kontrole van OT aangehaald).

De basismachine wordt doof.

De subroutinesprong in 24 verwijst naar het begin van de ingreeproutine, die begint met de status quo van het onderbroken programma te redden, waarna onderzocht wordt, welke IF of IF's voor de ingreep verantwoordelijk waren. Wat de IF is voor de basismachine is de AF voor Charon. Zoals IF = true betekent, dat er voor de basismachine weer wat te doen is, zo betekent AF = true, dat er voor het bijbehorende communicatie apparaat weer wat te doen is, d.w.z. dat er tenminste 1 opdracht voor dit apparaat gegeven is.

3. Vaste toekenning van geheugenplaatsen aan apparaten

De AF meldt voor een apparaat aan Charon de aanwezigheid van tenminste 1 startopdracht, de IF meldt omgekeerd aan de basismachine de aanwezigheid van tenminste 1 terugmelding van dit apparaat. Nadere specificatie (aantal startopdrachten en welke, aantal terugmeldingen en welke, etc.) vindt plaats via het kerngeheugen, dat zowel voor de basismachine als voor Charon toegankelijk is (met prioriteit voor Charon).
Voor deze communicatie zijn voor elk apparaat vier opeenvolgende geheugenplaatsen gereserveerd te beginnen bij:

64 + 4 * apparaatnummer

(Dit loopt dus van 64 t/m 255). In het volgende zullen deze 4 woorden worden aangeduid met AR0, AR1, AR2 en AR 3.
De 9 meest significante bits enerzijds en de 18 minst significante bits anderzijds worden vaak als onafhankelijke bestanddelen beschouwd; het stuk d26 t/m d18 heet dan “ het tellingdeel”, het stuk van d17 t/m d0 heet dan “het adresdeel”.
Vooruitlopend geven wij de algemene functie van de 4 apparaat woorden.

Opm 1. | Deze functies zijn niet bij alle apparaten van toepassing; uitzonderingen zullen per apparaat vermeld worden.
Opm 2. | In dit vooruitlopend overzicht geven wij geven wij slechts een eerste aanduiding van de betekenissen.

AR0 :

Tellingdeel
: werkruimte Charon, in het bijzonder gereserveerd voor OK-status.

Adresdeel
: label van de heersende schakel.

AR1 :

Tellingdeel
: IFT

Adresdeel
: irrelevant, ≠ (wordt uit compalibiliteitsoverwegingen met de X2 door Charon niet gebruikt)

AR2 :

Tellingdeel
: AFT

Adresdeel
: meestal werkruimte voor Charon

AR3 : | Werkruimte voor Charon (vaak gereserveerd voor het zg. “lopende codewoord”).

4. Ketens van startopdrachten

4.1. Layout van de startopdracht

Per apparaat kan men een keten van startopdrachten “aanhangig maken”. Elke startopdracht – omdat hij alleen in een keten voorkomt ook wel “schakel” genoemd – bestaat uit een aantal opeenvolgende geheugenplaatsen. Onder de “label van een schakel” verstaat men het adres van het tweede woord van deze schakel.
De algemene layout van een startopdracht is:

label [–1] : | zg. slotwoord. Vóór de feitelijke uitvoering van deze startopdracht, is de inhoud van dit woord voor Charon irrelevant; na afloop van de uitvoering heeft Charon verslaglegging gedaan over de afloop van de startopdracht.

label [0] :

Tellingdeel
: allemaal nullen

Adresdeel
: label van de volgende schakel

label [1] : | Codewoorden ter beschrijving van
etc. | de startopdracht; de layout hiervan is apparaat afhankelijk.

Een startopdracht wordt dus klaargemaakt in de vorm, die specifiek is voor het apparaat in kwestie. De startopdracht is niet positioneel gebonden aan het gebied van het kerngeheugen, waarop de feitelijke informatietransport betrekking heeft. Omdat voor de labels altijd 18 bits gereserveerd zijn is er geen hardware restrictie aan hun plaats opgelegd.

4. 2. Het aanhaken van een startopdracht

In AFT (0 ≤ AFT ≤ 511) wordt ten behoeve van Charon het aantal schakels van de startketen genoteerd (inclusief de schakel, die door Charon in behandeling is). In de Actie Flip Flop AF wordt aangegeven, of ADT > 0 is.
Nadat de nieuwe schakel volledig is geprepareerd (met op het door zijn label aangewezen adres bv. + 0 wegens het ontbreken van een volgende schakel) moet deze worden aangehaakt.
De aanhaakorganisatie moet in een zg. vulwijzer VW de label van de laatst aangehaakte schakel onthouden. Het aanhalingsprotocol is nu in volgorde:

1. Met M[VW] := label nieuwe schakel wordt de nieuwe schakel aangehaakt. (Als er geen “laatste schakel” (meer) is, moet dit worden onderdrukt); verder wordt VW := label nieuwe schakel.

Met een additieve uitopdracht (versie PLUSA of PLUSS) moet AFT met 1 verhoogd worden, waarbij de nieuwe waarde van AFT tevens in het basismachineregister komt.

Indien deze nieuwe AFT-waarde = 1 is moet de basismachine

3.1 | het adresdeel van AR0 door het nieuwe label vervangen (zonder het tellingdeel te verstoren),
3.2. | vervolgens AF true zetten.

Opm. Tijdens de behandeling van de startopdracht wijst het adresdeel van AR0 naar deze startopdracht. Als afsluiting laagt Charon AFT met 1 af. Is het resultaat hiervan > 0, dan vervangt Charon het adresdeel AR0 := adresdeel M[adresdeel AR0], d.w.z. gaat over op de volgende schakel. Is het resultaat van de AFT aflaging = 0 (afgeleverd in de vorm van negen nullen), dan wordt simultaan AF false gezet en de overgang op de volgende schakel wordt onderdrukt. Dit, plus het feit dat bij niet lege startketen de AFT aflaging op voor de basismachine oncontroleerbare ogenblikken kan plaatsvinden is de achtergrond van voornoemde aanhaakriten, waar streng de hand gehouden moet worden.

4. 3. Het reageren op een terugmelding

In IFT wordt ten behoeve van de basismachine genoteerd het aantal terugmeldingen van Charon, waarop de basismachine nog niet gereageerd heeft. Voltooiing van een terugmelding wordt door Charon afgesloten met de ophoging van IFT met 1 en het true zetten van IF.
De basismachine moet, in het kader van de reactie op een terugmelding, IFT met 1 aflagen en zorgen dat IF – die de betekenis “IFT>0” heeft – passend wordt achtergelaten. Omdat ook hier Charon op voor de basismachine oncontroleerbare ogenblikken de IFT-ophoging kan doen, is de IFT aflaging en de bbh IF aanpassing doen de basismachine aan een streng protocol onderwerpen.
Dit luidt:

Zet IF False

Laag IFT met MINA, MINS ( of PLUSA of PLUSS) met 1 af.

2.1. | Doordat het adresdeel van AF1 ≠ nul is, wordt, als IFT algebraïsch nul wordt, het tellingdeel van AR1 negen nullen.

Als de in het register aangetroffen nieuwe waarde van IFT ≠ 0 is, zet dan IF true.

Ook aan dit protocol moet streng de hand gehouden worden.

5. Het toetsenbord

Het toetsenbord is een in voor apparaat, waarvan het nummer installatie-afhankelijk is.
Het is een afwijkend apparaat in zoverre de operateur dit invoer apparaat bedienen kan, zonder dat de basismachine er een startopdracht voor heeft gegeven.
Wanneer de basismachine bereid is een volgend karakter van het toetsenbord te accepteren dient van

AR1 : | het tellingdeel uit negen nullen te bestaan, het adresdeel ≠ nul te zijn

AF dient true te zijn.

De aanvangswaarde van AR0, AR2 en AR3 is irrelevant.

Indrukken van een toets heeft tot gevolg

if AF then AR0 := karakter else AR3 := karakter;

AF := false;

IFT := IFT + 1 en IF := true;

Het protocol voor de reactie op de ingreep van het toetsenbord is als volgt:

L0 : IF := false;
          IFT := IFT - 1 annex if IFT > 0 then
                  begin AR0 := iets negatiefs: goto L0 end;    
           A := AR0;
           if A > 0 then begin AR0 := iets negatiefs; A moet nu als volgend
                         symbool geaccepteerd worden end;
                AF := true; comment nu kan het toetsenbord weer iets in AR0 zetten;

Onder “accepteren van een symbool” valt onder meer het uitprinten hiervan. Door pas daarna AF = true te zetten, kan men ervoor zorgen, dat de basismachine pas een volgend karakter accepteert, nadat het voorgaande netjes is verwerkt. Het toetsenbord plaatst de X8 voor een essentiële haastsituatie: de X8 moet dit karakter zo snel mogelijk verwerken, maar “AF := true” tot het bitter einde uitstellen.

6. Het teleprinterdrukwerk

De indeling voor AR0, AR1, AR2 en AR3 is normaal. Het tellingdeel van AR0 bevat de OK-status, het adresdeel van AR2 wordt niet gebruikt. Het lopend codewoord in AR3 is gesplitst in tellingdeel en adresdeel (zie onder). De startschakel bestaat uit 3 woorden, de eerste twee zijn normaal, de laatste, label [1], bevat het codewoord.

Een startschakel geeft de mogelijkheid om de woorden uit N opeenvolgende adressen naar het drukwerk van de teleprinter te sturen. Van elk woord bepalen de laagste een actie van het drukwerk (Ik neem aan dat in elk van deze woorden de 21 hoogste bits irrelevant zijn, ik zou ze altijd =0 maken.)

Het codewoord bepaald lengt en ligging van de uit te voeren waardering, en wel

tellingdeel codewoord

= lengte van de rij,
(waarbij tellingdeel = 0 de lengte
=512 voorschrijft; in de lege
startopdracht is dus niet voorzien)

| adresdeel codewoord | = beginadres van de waardering – 1.

Als de startopdacht door Charon geaccepteerd wordt, wordt het codewoord uit de heersende schakel in het lopende codewoord (in AR3 dus) overgenomen.
Per woordverzending naar het drukwerk neemt Charon tweemaal contact met het geheugen op. In het eerste geheugencontact met AR3 wordt het tellingdeel (mod. 512) met 1 verlaagd en wordt het adresdeel ( modulo 2¹⁸) met 1 verhoogd. Is het resulterend tellingdeel = 0, dan is het nu nog volgend woordtransport het laatste van de startopdracht. In het geheugencontact, volgend op dat met AR3 wordt het woord getransporteerd, aangewezen door het zojuist in AR3 weggeschreven adresdeel. Als – door storing – de startopdracht voortijdig wordt afgebroken, bevindt zich in het tellingdeel van AR3 dus het resterende aantal te printen woorden, in het adresdeel het adres van het laatste getransporteerde woord.
De heersende OK-status van het drukwerk wordt onthouden in het tellingdeel van AR0; na afloop van elke startopdracht wordt dit tellingdeel overgenomen in het tellingdeel van het slotwoord (label [–1]) van de schakel in voltooiing. Het adresdeel van het slotwoord is ongedefinieerd.

Bij het drukwerk heeft de OK-indicatie slechts 2 mogelijke waarden:

| 000 000 000      OK
| 111 111 111      niet bedrijfsklaar (d.w.z. bv. niet aangesloten)

De status van het Charon programma voor het drukwerk kent dus twee toestanden, kortweg aangeduid met OK en non OK.
Boven hebben we de normale afwerking van een startopdracht beschreven, als deze in de toestand OK geaccepteerd wordt. Een startopdracht, die in de toestand non OK geaccepteerd wordt, wordt op één uitzondering na, onmiddellijk symbolisch afgewerkt. (Onder terugmelding van de non OK status in het slotwoord). De ene uitzondering is de zg. HOK-opdracht (Herstel OK toestand), die normaal in de startketen kan worden opgenomen en gekarakteriseerd is door een codewoord bestaand uit louter nullen. (Mede tengevolge hiervan kan men niet in 1 startopdracht de inhoud van de woorden op adressen 1 t/m 512 naar het drukwerk sturen: deze zijn nl. als HOK-opdracht geïnterpreteerd worden. De HOK-opdracht moet niet opgegeven worden als het apparaat al in de OK-toestand is.
NB. Toetsenbord en teleprinterdrukwerk houden elk, onafhankelijk van elkaar, op mechanische wijze de heersende shift bij. Bij het drukwerk bepaalt de shift welke van de twee tekens bij een vijfbits drukcommando op papier verschijnt; bij het toetsenbord bepaalt de heersende shift welke helft van het toetsenbord geblokkeerd is.

6.1. Hardware code teleprinter EL X8

(Weggelaten zie origineel.)
Bij zwart lint heeft X als neveneffect het starten van een rood flikkerend attentiesignaal, dat alleen door de operateur kan worden afgezet.

7. Het bandlezer

De betekenis van de centrale administratie AR0 t/m AR3 is normaal, als in 3 beschreven.
De startschakel bestaat uit 3 opeenvolgende woorden:

label [-1] :

slotwoord en wel:

tellingdeel
:
Ok indicatie

adresdeel
:
undefined

label [0] :

tellingdeel
:
allemaal nullen

adresdeel
:
label van de volgende schakel

label [+1] :
enig codewoord en wel

tellingdeel
:

lengte van de rij (waarbij tellingdeel =0
de lengte =512 voorschrijft; in de lege start-
opdracht is dus niet voorzien)

adresdeel
:
beginadres van de woordenrij – 1.

Als de startopdracht door Charon geaccepteerd wordt, wordt het codewoord uit de heersende schakel in AR3 overgenomen. Per gelezen ponsing neemt Charon twee maal contact met het geheugen op. In het eerste geheugencontact met AR3 wordt het tellingdeel (mod. 512) met 1 verlaagd en wordt het adresdeel ( mod. 2¹⁸) met 1 verhoogd. Is het resulterend tellingdeel = 0, dan is het nu nog volgend woordtransport het laatste van de startopdracht. In het geheugencontact, volgend op dat met AR3 wordt de gelezen ponsing, aan de meest significante zijde aangevuld met nullen, ingevuld op de geheugenplaats, die wordt aangewezen door het zojuist in AR3 weggeschreven adresdeel.
Wanneer de startopdracht voortijdig wordt afgebroken, bevindt zich in AR3 in het tellinggedeelte het ontbrekende aantal ponsingen, in het adresdeel het adres van het laatste gevulde woord.
De heersende OK-status van de bandlezer wordt onthouden in het tellingdeel van AR0. Aan het einde van de verwerking van een startopdracht wordt de dan heersende OK-status gecopieerd in het tellingdeel van het slotwoord van de betrokken schakel.
de OK-status kent drie waarden:

| 000 000 000 111 111 111 111 111 110 | OK niet bedrijfsklaar (d.w.z. bv. niet aangesloten einde band

De laatste twee toestanden worden kortweg aangeduid met “non OK”. Als de bandlezer non OK is, worden alle volgende startopdrachten op één uitzondering na onmiddellijk symbolisch afgewerkt, onder terugmelding van de heersende non OK status in het slotwoord. De ene uitzondering is de zg. HOK-opdracht (Herstel OK toestand), die normaal in de starttreden kan worden opgenomen. Mede tengevolge hiervan kan men niet in een startopdracht 512 ponsingen willen doen lezen, het opbergen te beginnen bij adres 1. De HOK-opdracht moet niet opgegeven worden als de bandlezer al OK is.

Opm. 1 De symbolische afwerking verstoord AR3 niet, zodat het gegeven hoeveel er nog gelezen is, voordat “einde band” het leesproces afbrak, niet verloren gaat, voordat de volgende leesopdracht effectief geaccepteerd wordt.
Opm. 2 De bandlezer leest met een snelheid van 1000 ponsingen per seconde; het leesproces belegt het geheugen dus voor ½ procent van de tijd.
Opm. 3 De bandlezer bevat een schakelaar voor verschillende bandbreedten Deze bandbreedte wordt niet geacht bij te dragen tot de informatie, programma-technisch is de heersende bandbreedte niet detecteerbaar.
Opm. 4 De bandlezer leest alle configuraties ongeinterpreteerd, ook “blank tape” en “all holes”.

De band passeert in volgorde:
1. een mechanische detector voor einde band,
2. de rem,
3. het leesstation,
4. de aandrijving.
De uiteinden van de band kunnen daardoor niet gelezen worden.

De bandlezer is uitgerust met een rode en een groene knop. Door op de rode knop te drukken stopt men de bandlezer onmiddellijk en maakt men de detector op einde band non-effectief. Door op de groene knop te drukken keert de bandlezer in zijn normale toestand terug. Het indrukken van de rode en groene knop dringt als zodanig niet tot de basismachine door: als een startopdracht onder behandeling is (of komt) duurt het alleen wat lang, voordat hij wordt afgehandeld.
Wanneer einde band gedetecteerd wordt, springt de bandlezer instantaan in de toestand alsof op de rode knop gedrukt is, het indrukken van de groene knop heeft slechts effect wanneer er een nog voldoende lange band in de bandlezer ligt.
Opm. 5 Der rode knop geeft de operateur de gelegenheid in noodsituaties de bandlezer even te stoppen (knoop of krinkel of wat dan ook) zonder dat dit tot de logica van het verwerkende programma doordringt. Zelfs kan hij, als hij voldoende rap is, een aantal banden achter elkaar als een band aan het verwerkende programma offreren.
Opm. 6 Als een band tot het einde gelezen is moeten er, voordat een volgende band over die bandlezer gelezen kan worden, twee dingen gebeurd zijn:

de basismachine moet een HOK-opdracht gegeven hebben.

de operateur moet het inleggen van de volgende band hebben afgesloten met het drukken op de groene knop.

De volgorde van deze twee acties doet niet ter zake.

8. Het bandponser

De centrale administratie op de plaatsen AR0 t/m AR3, evenals de layout van de startschakel is bij de bandponser als bij het teleprinterdrukwerk, zie 6. (Teleprinter en bandponser worden nl. door precies hetzelfde Charonprogramma bediend.) Nu bepalen van elk woord de laagste 7 bits, wat er geponst wordt. (Ik neem aan, dat de resterende 20 bits irrelevant zijn, ik zou ze altijd =0 maken.)
Ook de bandponser heeft een rode en een groene knop. het indrukken van de rode knop heeft tot gevolg, dat de bandponser instantaan stopt en dat de selectie voor bandeinde tijdelijk ineffectief is. Door het indrukken van de groene knop wordt dit weer ongedaan gemaakt.
Als de detectie voor het bandeinde voor het eerst alarm geeft, is er nog minstens een paar meter band ter beschildering. In tegenstelling tot de bandlezer, die bij bandeinde instantaan stopt, maakt de bandponser de heersende startopdracht rustig af en gaat dan pas over in de toestand “einde band”, waarin de volgende startopdrachten (if any) symbolisch worden afgemaakt totaan de eerste HOK-opdracht.
Deze HOK-opdracht brengt de bandponserij in de afsluittoestand. In de afsluittoestand worden ponsopdrachten weer normaal geaccepteerd, zij het dat aan noodkreten van de einde band detectie geen aandacht wordt geschonken. De afsluittoestand is geïntroduceerd om de programmeur de gelegenheid te geven eindindicaties op de band te ponsen; het is echter zijn verantwoordelijkheid om te zorgen, dat deze eindindicaties niet te lang zijn.
Na de laatste ponsopdracht van de afsluiting geeft de programmeur een tweede HOK-opdracht, die dubbel gevolg heeft. Het Charonprogramma gaat weer in de normale OK-toestand over en de programmeur kan de startopdrachten voor de volgende band aanbieden. Een tweede effect van de tweede HOK-opdracht is dat de bandponser zelf in de toestand raakt, alsof de rode knop ingedrukt is, waarbij drukken op de groene knop slechts effect heeft nadat een nieuwe band is ingelegd.

Opm. Met het aanbieden van de startopdrachten voor de volgende band hoeft het programma dus niet te wachten, totdat de operateur de band gewisseld heeft.
De OK-status geeft vier waarden:

000 000 000
111 111 111
111 111 110
111 111 101
OK
niet bedrijfsklaar
einde band
afsluittoestand

9. Regeldrukker

De centrale administratie (AR9t/m AR3) evenals de driewoords startschakel (label [-1] t/m label [+1]) hebben de normale functie. Het laatste woord van de startschakel is het codewoord, dat op nader te beschrijven wijze aangeeft, wat voor regel gedrukt moet worden.
Ter specificatie van de startopdracht bouwt men in het geheugen op een aantal opeenvolgende adressen het zg. regelbeeld op. Plaats en lengte van het regelbeeld worden gegeven in het codewoord van de startschakel en wel

codewoord: | tellingdeel | : aantal woorden dat het regelbeeld bestaat (1 ≤ dit aantal ≤ 36)
| adresdeel | : beginadres van het regelbeeld – 1.

Charon zendt de woorden van het regelbeeld in volgorde van opklimmend adres naar de regeldrukker. In elk woord zijn vier zes-bits symbolen gepakt

| d26.... d21 | 1ste symbool
| d19.... d14 | 2de symbool
| d12.... d7 | 3de symbool
| d5.... d0 | 4de symbool

De drie scheidingsbits d20, d13 en d6 moeten =0 zijn.
De actie van de regeldrukker laat zich het best beschrijven in termen van zijn reactie op een van als boven gedefinieerde symbolenrij (waarvan de lengte altijd een viervoud is.)
Het allereerste symbool van de rij wordt afwijkend geïnterpreteerd en is de zg. sprong indicatie (zie onder); daarna specificeren de symbolen van de rij wat de regeldrukker op die regel moet drukken, positie per positie in de volgorde van links naar rechts. Het maximale aantal karakters per regel is 143. Als het regelbeeld in het geheugen korter is dan 36 woorden, laat de regeldrukker de ongespecificeerde posities aan het rechtereinde van de regel onbedrukt. De lengte van de symbolenrij die naar de regeldrukker gestuurd wordt is per definitie een viervoud; zonodig moet de programmeur de rij dus aanvullen met 1, 2 of 3 spaties.

De betekenis van de sprong indicatie (opgevat als een getal van 0 t/m 63) is als volgt:

0 | t/m 31 | voer het papier op over het opgegeven aantal regels en druk vervolgens de regel af, zoals door de rest van het regelbeeld is opgegeven.
32 | t/m 39 | regelopvoer gestuurd door een achtgats ponsbandje, druk dan.
40 | t/m 63 | komt niet voor

(In geval van formulieren van een vaste lengte kan men in de regeldrukker een cyclisch geplakt achtgats ponsbandje inleggen, dat met elke regel over een ponsing getransporteerd wordt. Dit bandje geeft 8 kanalen, genummerd van 0 t/m 7; de bandgestuurde regelopvoer vindt plaats, totdat in kanaal nr. “sprong indicatie – 32” een ponsing in het bandje gedetecteerd wordt. Bij koppeling aan een rekenautomaat is dit soort faciliteit overbodig, ik ben niet van plan hem te gebruiken.)

De betekenis van de symbolen uit de rij na de sprong indicatie volgt uit de volgende tabel. De symboolwaarde is opgevat als getal van 0 t/m 63. (wals EL X( van THE.)
(tabel weggelaten, zie origineel document).

Opm. In de afdruk is de nul smaller dan de letter O.

De normale toestand is OK d.w.z.

Tellingdeel AR0 | = 000    000    000
slotwoord | = +0     (d.w.z. allemaal nullen)

De regeldrukker bevat een detector “paper low”; als deze signaleert, blijft de OK-toestand bestaan – regelprint opdrachten worden dus normaal geaccepteerd – maar in de startschakel verschijnt

| slotwoord = +1 (d26 = ··· = d1 = 0, d0 = 1)

Geeft de programmeur nu – d.w.z. terwijl de toestand OK is – een HOK-opdracht – als steeds in de vorm van een codewoord gelijk aan louter nullen – dan gaat op de regeldrukker het lichtje “Change Paper” branden. De regeldrukker raakt daardoor in de toestand, alsof op de rode knop gedrukt is, drukken op de groene knop heeft slechts effect als “paper low” geen alarm geeft, d.w.z. als de operateur zonodig nieuw papier heeft ingedaan.

Als de regeldrukker niet is aangesloten dan wordt:

Tellingdeel AR0 | = 111 111 111 | niet bedrijfsklaar
slotwoord | = 111 111 111 , | gevolgd door een ongedefinieerd adresdeel

Deze toestand geldt als non OK, en de volgende startopdrachten ≠ HOK worden symbolisch afgemaakt.

Drie andere oorzaken kunnen de toestand non OK tevoorschijn roepen. Zij laten achter:

tellingdeel AR0 | = | 111 111 110 en
slotwoord | : | tellingdeel = 111 111 110

adresdeel: d₁₇ = ····· d₄ = 0

d3 = 1
als “Yoke open”

d2 = 1
als papier gescheurd

d1 = 1
als pariteitsfout in transmissie

d0 = 1
als tevens “paper low”

Van de bits d3, d2 en d1 moet er minstens 1 gelijk zijn aan 1. De pariteits-foutsignalering d1 = 1 betreft de symbooltransmissie voor de regeldrukker: elk zesbits symbool wordt nl. voorzien van een pariteitsbit naar de regeldrukker gestuurd. Bij standaardwalsen, waar minder dan 64 verschillende symbolen in de rij zijn toegestaan betekent d1 = 1 “pariteitsfout in transmissie of onbestaanbaar symbool”.

Bij elke niet-lege combinatie wordt tevens in d0 = 1 paper low gemeld. In dat geval herstelt de eerste HOK-opdracht de OK-toestand, maar de indicatie paper low blijft hangen. Ee tweede HOK-opdracht vanuit de machine schakelt dan normaal het lichtje “Change Paper” aan.
Opm. 1 Bij non OK door een van de drie genoemde oorzaken kan het reagerende programma d0 negeren. Blijkt “paper low” te heersen, dan merkt men dat wel bij de eerstvolgende startopdracht.
Opm. 2 De voorstelling van zaken, alsof er aan de regeldrukker slechts een rode en een groene knop zitten, is wat simplistisch: er zitten er meer aan. Het effect is echter wel, dat na de HOK-opdracht na “paper low” de basismachine zonder meer de volgende startopdrachten al kan aanbieden, zij zullen pas verwerkt worden, nadat de operateur volgend de regels van de kunst nieuw papier heeft ingezet.
Opm. 3 Als de regelprintopdracht voortijdig is afgebroken bevat het tellingdeel van AR3 zoals gebruikelijk het aantal resterende (d.w.z. niet getransporteerde) woorden en het adresdeel het adres van het laatst getransporteerde woord. Als de regelprintopdracht normaal is afgewerkt, bevat het tellingdeel 511 en het adresdeel het adres van “het eerste niet getransporteerde woord”.

10. De trommel

In de centrale administratie hebben AR0, AR1 en AR2 de normale betekenis. AR3 is ongebruikt. Een startopdracht is een schakel bestaande uit 5 opeenvolgende woorden.

label [–1] :

tellingdeel
:   copie van OK-status als in tellingdeel van AR0

adresdeel
:   nadere specificatie slotwoord (zie onder)

label [0] :

tellingdeel
:   000 000 000

adresdeel
:   labeladres volgende schakel.

label [1] :

d26 t/m d19
:   irrelevant, mits niet alle = 0.

d18 t/m d0
:   beginadres op trommel

label [2] :

d26
= ··· = d19 = 0

d18
= 0 transportrichting van trommel naar kernen

= 1 transportrichting van kernen naar trommel.

label [3] :

d26 = ··· = d12 = 0

d11 t/m d0 : lengte ( dus < 4096)

In tellingdeel van AR0 betekent:

| 000 000 000 111 111 111 111 111 110 | OK niet bedrijfsklaar iets mis

De laatste twee toestanden geven aanleiding tot symbolisch afwerken totaan de HOK-opdracht (Gekaraktiseerd door label[1] = + 0; label [2] en label [3] doen in de HOK-opdracht niet mee).

In het slotwoord is

d26 t/m d18 | : (tellingdeel) : een copie van tellingdeel van AR3.
d17 = … = d14 | : altijd = 0
d13 = 1 | als te laat geaccepteerd geheugencontact
d12 = 1 | als pariteitsfout.
d11 t/m d0 | eindstand aantallenteller (moet = 0 zijn).

d13 = 1 of d12 = 1 impliceert OK-status: 111 111 110.

Ad d13: | De trommel plaatst het kerngeheugen voor een essentiële haastsituatie. Als deze (door schromelijke overbelasting!) niet gehonoreerd zou kunnen worden, wordt d13 = 1 gezet en het transport onderbroken.
Ad d12: | De trommeltransporten zijn aan de normale pariteitscontrole onderworpen. Als bij een transport van kernen naar trommel een woord met onjuiste pariteit in de kernen staat, zal de transportopdracht alarm geven. Nogmaals proberen is dan gegarandeerd zinloos.

Opm. 1 In “label [1]” moet tenminste 1 van de bits =1 zijn om de opdracht van de HOK-opdracht te kunnen onderscheiden.
Opm. 2 De ophoging van het lopend trommeladres geschiedt modulo 2 ↑ 19 : het trommelgeheugen is dus cyclisch gerangschikt.
Opm. 3 Bij een transport van trommel naar kernen, die er niet zijn, gaat informatie ongedetecteerd verloren; bij een transport uit kernen die er niet zin, slaat de pariteitscontrole alarm. Ook het lopend kernenadres telt rond ( modulo 2 ↑ 18), maar erg interessant is dit niet.
Opm. 4 In d 11 t/m d0 vindt men de eindstand van de teller, d.w.z. het aantal ongetransporteerde woorden. Bij fout geldt het mislukte woord als getransporteerd: als het laatste woord vindt men, dus d11 = … = d0 = 0.

11. De klok

De klok is onveranderljk apparaat nr. 39. Hij werkt onafhankelijk van AF en heeft drie functies.

11.1 | De eigenlijke klok Elke 10 insec wordt AR0 modulo 2 ↑ 27 met 1 verhoogd. De cyclus van dit telproces is van de orde van grootte van twee weken.

11.2
De kodewekker
Elke 10 insec wordt het adresdeel van AR1 modulo 2 ↑ 18 met 1 verminderd. Als hierdoor AR1 totaal = +0 wordt, wordt in het tellingdeel van AR1 :000 000 001 gezet en IF wordt true, m.a.w. de ingreep van de kodewekker kan plaatsvinden. Wie deze ingreep niet wil hebben, kan hem dus definitief onderdrukken door het tellingdeel van AR1 meteen ≠ te maken. De maximale looptijd van de kodewekker is circa 40 minuten.

11.3

De apparaatwekker
Modulo 512 wordt elke 10 insec het tellingdeel van AR2 met 1 verminderd. Als het resultaat in het tellingdeel = 0 wordt en het adresdeel van AR2 = NR ≠ 0 dan wordt:

van het apparaat met apparaatnummer = NR de LVAF op true gezet,

in AR2 wordt AR3 overgenomen.

Men initieert dit proces door eenmalig AR3 en AR2 met hetzelfde te vullen. Men kan een aangewezen apparaat om de zoveel tijd ergens nota van laten nemen, met maximum periode van circa vijf seconden.

transcribed by Martin van der Burgt
revised 2013-06-20

  EWD 145

Globale beschrijving van de drijvende arithmetiek van de EL X8.

Met "globaal" wordt bedoeld, dat deze beschrijving de lezer in staat stelle voor zichzelf uit te maken, wat het antwoord van een zekere operatie is, als hij de operanden kent. Het is niet gezegd, dat deze beschrijving ook de beschrijving is van de manier, waarop de arithmetische circuits van de EL X8 dit antwoord construeren.

Voorstelbare getallen.

De drijvende arithmetiek opereert op getallen van de vorm

m × 2↑e

waarbij m (van mantisse) voldoet aan 0 ≤ abs (m) ≤ 2↑40 − 1
en e (van exponent) voldoet aan 0 ≤ abs (e) ≤ 2↑11 − 1 = 2047.

Opm. 1. Voor e zijn 12 bits ter beschikking, voor m 41; in beide gevallen kan de waarde 0 op twee wijzen worden voorgesteld, nl. +0 en −0.

Opm. 2. Niet alleen e maar ook m neemt dus louter gehele waarden aan.

Afronding.

Optelling, aftrekking, vermenigvuldiging en deling kunnen alle een resultaat afleveren, dat, ongeacht de bovengrens van abs(e) niet exact voorstelbaar is, omdat de afstand van meest en minst significante bit van abs(m) meer dan 39 zou moeten zijn.
(Bij optelling en aftrekking kan dit ontstaan doordat de mantissen onder elkaar geschoven moeten worden, bij de vermenigvuldiging is de afstand van meest en minst significante bit van het execte product in het algemeen 79 of 78, bij de doorgaans niet opgaande deling is deze afstand oneindig).
In al deze gevallen wordt exact afgerond, en in het twijfelgeval van de nul af.
Het twijfelgeval treedt op, wanneer de afstand van meest en minst significante bit van het exacte antwoord 40 is; m.a.w. als de exacte m = 2↑40 + 1 wordt dit tot 2↑40 + 2 afgerond, zodat halvering tot 2↑39 + 1 mogelijk is.
Aldus is de eventueel afgeronde m en exacte e (waarin netjes van alle halveringen is boekgehouden) bepaald. Van deze exacte e nemen we voorshands niet aan, dat hij aan abs(e) ≤ 2047 voldoet.

Opm. 3. Door de conventie, dat het twijfelgeval van de nul af wordt afgerond is gegarandeerd, dat (−a)× b = − (a × b) is.
Vervolgens worden exacte e en (eventueel afgeronde) m aan de normering onderworpen.
De normering probeert de absolute waarde van e zo klein mogelijk te krijgen als zonder cijferverlies mogelijk is. (Elke verhoging van e moet gecompenseerd worden door halvering van m,
wat alleen zonder cijferverlies mogelijk is, als m eerst even is; elke verlaging van e moet gecompenseerd worden door verdubbeling van m, wat zonder "cijferverlies aan kop" alleen mogelijk is als abs(m) < 2↑39).

Opm. 4. Dit proces kan eindigen doordat abs(e) = 0 wordt; in dat geval wordt e = +0 afgeleverd.
Als m = ± 0, kan onbeperkt zonder cijferverlies geschoven worden: in de hardware zit een m = ± 0 detectie, die dit geval kortsluit en onmiddelijk e = + 0 maakt.
Nadat aldus gepoogd is abs(e) zo klein mogelijk te maken, wordt gekeken, of abs(e) klein genoeg is.
Als e ≥ 2048 is, dan wordt als antwoord afgeleverd e = 2047 en m = ± (2↑40 − 1), en wel met het teken van de oorspronkelijk m.
Als e ≤ − 2048 wordt (bij herhaling)
1) e met 1 opgehoogd
2) m afkappend gehalveerd, als abs(m) > 1 is;
als abs(m) = 1 is blijft m ongewijzigd.

Met andere woorden: in geval van overflow wordt het grootste getal met het goede teken afgeleverd, in het geval van underflow wordt door uitschuiven gepoogd de exponent alsnog binnen de perken te brengen. Het minste, wat overblijft is daarbij &plusmn; 2↑(−2047).
Underflow kan dus niet m = 0 genereren.

Opm. 5. Aftrekking van een getal "m × 2↑e" wordt gerealiseerd door "−m × 2↑e" op te tellen.

Opm. 6. Overflow kan optreden bij +, −, × en ∕ .
Underflow kan niet bij + en × optreden.

Opm. 7. Additieve bewerkingen leveren alleen nul op als het antwoord exact = 0 is; dit antwoord is alleen m = +0 wanneer de operanden van de effectieve optelling (zie opm. 5) beide = +0 zijn.

Opm. 8. De vermenigvuldiging levert alleen exact nul als antwoord, wanneer ten minste een factor = 0 is. Het teken van de productnul volgt de normale tekenregel voor producten.

Opm. 9. Voor de deling geldt:
deeltal ≠ 0, deler ≠ 0→ quotiÎnt ≠ 0
deeltal = ± 0, deler is ≠ 0 → quotiÎnt = ± 0 (met in achtname van de normale tekenregels).
De situatie voor deler = ± 0 is momenteel het voorwerp van ernstige discussie.
Verwacht wordt:
deeltal ≠ 0, deler ± 0 → ± (2↑40 −1) × 2↑2047 met in achtname van de normale tekenregel.
deeltal = ± deler = ± 0 → een welgedefinieerd antwoord met in achtname van de tekenregel.

Eindhoven, 6 december 1965.

transcribed by Sam Samshuijzen
revised Wed, 19 Jul 2006

EWD147

Proposal for the Input and the Notation of the System.

0. Introduction

Input of the system will take place in two stages.

From the written documents we shall punch on Flexowriters the tape HACOSYS (Hand Coded System), an assembler will read HACOSYS and punch the tape BICOSYS (Binary Coded System). The tape BICOSYS will load the system into a virgin machine. BICOSYS, which will be handled daily by the operator will be very much shorter than HACOSYS, which is only handled at system modification.

1. The General Structure of BICOSYS.

Paper tape can be read

1) for the sake of initial input into the virgin machine under complete control of Charon

2) under normal program control (with Charon as program controlled slave).

We call the two forms of input primary and secondary input.

Primary input is unchecked; for this reason we shall restrict it to a minimum, i.e.

1) an interrupt jump in M[24] to the starting address of the secondary input program

2) the secondary input program inself. The latter will be stored in a future core page.

The tasks of the secondary input program are the following ones

1) It has to verify its correct presence in core store, say by means of a sum check. It has to clear the remainder of the memory.

2) It has to clean all the necessary teeth in the normal manner but for the real time clock, which has to remain dormant (say by LVCA false )

3) All LVIF's can be set in their future position and IV can be set true

4) Now the secondary input program starts to read paper tape over the golden reader in a most unorthodox manner, viz.

4.1) it will give tape read commands directly to the golden reader

4.2) it will keep the IFT-value negative, it will not rely on the interrupt

       mechanism but will inspect the IFT increases.

5) Secondary reading will consist of two phases, core filling, followed by segment filling.

During core filling all core locations with permanent meaning are filled. They are filled in such a way that at the end of core filling the primary input program looks as a program in PM1. All mechanisms to dump segments are then present, the clock, if necessary, can be started and secondary reading continues to fill the segments. The multirunning system is then working but for the information streams.

6) Finally the golden reader is set in accordance with the initial state of the corresponding CM and PM1 ends its activity as normal programs do.

The information on BICOSYS consists of

a) the text of the secondary input program

b) the information to be read during core filling

c) the information to be read during segment filling.

2. The Structure of HACOSYS.

HACOSYS will consist of two parts

1) the Table, followed by

2) the Contents, the latter subdivided into

2.1) the secondary input program

2.2) the core information

2.3) the segment information

2.1. The Structure of the HACOSYS Table.

The identifiers occuring on the HACOSYS Table identify parameters, the HACOSYS Table specifies their constant type and value according to rules to be explained in this section. The identifiers have the complete HACOSYS Contents as their scope.

They are of three different types

1) constants

1.1) fixed constants

1.2) derived constants

1.3) invariant addresses

2) dynamic addresses

3) static addresses

On the HACOSYS Table they are introduced in the following order

1) the fixed constants

2) the dynamic addresses

3) the static addresses, the invariant addresses and the derived constants in order of increasing CCA (Current Core Address)

The CR (if desired, preceded by comment introduced by quotes) acts as separator.

2.1.1 The Fixed Constants

The fixed constant is given by its identifier, followed by "=", followed by its value; its value —a single word— may be given by a (signed or unsigned) decimal integer or by a (signed or unsigned) octal number (at most 9 octal digits enclosed within apostrophes). Then one or more separators have to follow.

2.1.2. The dynamic Addresses.

Dynamic addresses are defined in terms of the value of CDA (Current Dynamic Address); CDA is initialized by "d p[q]", where "p" (unsigned decimal integer) and "q" (decimal integer) specify a dynamic address in the usual manner. Then one or more separators must follow.

A dynamic address is then given by its identifier, followed by an unsigned decimal number enclosed within parentheses. The value of CDA is then assigned to the parameter identified, whereafter CDA is increased by the amount given within the parentheses. One or more separators follow.

2.1.3. The Static Addresses.

The static addresses can only be given after the first CCA initialization, that specifies the value of CCA (Current Core Address)

The CCA initialization consists of c, followed by an address value, given as unsigned (decimal or octal) number, followed by one or more separators. This value is the next CCA value, CCA must be monotonically non decreasing.

A static address is then given by its identifier, followed by an unsigned decimal number within parentheses, followed by one or more separators. The value of CCA is assigned to the parameter identified, whereafter CCA is increased by the amount given within the parentheses.

2.1.4 The Derived Constants.

After the definiton of a static address, one or more "derived constants" may be given. Each derived constant is given by its identifier, followed by "=", followed by a word, given as decimal or octal number. The value of the derived constant is this word increased by the static address value just assigned to the last static address. (In a —be it clumsy— manner, this facility enables us to introduce "SE1" with the value "SUBCD(:PSE1)" as soon as PSE1 has been defined.)

2.1.5. The Invariant Addresses.

When CCA points to a location that shall contain an SV, then the moment has come to give the invariant addresses, related to that correspoinding segment.

By "s" invariant address definition is announced and the variable CLN (Current Line Number) is set to zero. From then onwards invariant addresses related to this segment can be given by giving their identifier, followed by an unsigned decimal number between parentheses.

The value assigned to the parameter is the invariant address, composed of CCA and CLN (which must be less than 512), whereafter CLN is increased by the amount given within the parentheses. Invariant address definition with respect to this segment is ended by "t", which causes CCA to be increased by 1.

The individual invariant address definitions belonging to the same segment must be separated by one or more separators. Following "s" and preceding "t" no separator is required.

2.2. The Structure of the HACOSYS Contents.

On the HACOSYS Contents we find in order on the tape

1) the primary input

2) the core information

3) the segment information.

2.2.1. The Primary Input.

A piece of primary input is announced by "p", followed by an unsigned (decimal or octal) number or a static address, (i.e. the identifier of a static address) indicating the starting address, followed by an unsigned decimal number between parentheses indicating the number of words that follow, followed by one or more separators. Then the successive words will follow, all separated from one another.

On account of such part of the HACOSYS Contents, a part of BICOSYS will be made, intended for primary input, on successive locations, starting at the address given. This BICOSYS portion will contain at the end a word more, computed in such a way that the total sum of this portion is = 0.

A number of such pieces of primary input may follow. (E.g. one for M[24] and one for the secondary input program).

2.2.2. A Piece of Core Filling.

Such a piece is announced by the identifier of its static starting address, followed by an unsigned decimal integer between parentheses, indicating the number of words that follow. Then the words follow, announcement and words all followed by one or more separators.

Many such pieces may follow.

2.2.3. A Piece of Segment Filling.

Such a piece is as a piece of core filling but for the fact that it is announced by the identifier of an invariant address. Many such pieces may follow.

2.2.4. The End of HACOSYS.

An "e" indicates the end of HACOSYS.

2.2.5. The Words.

We shall now describe how the words on the HACOSYS Contents are written down. They are of two different layouts, called "constants" and "instructions". In the following description an "optional sign" is "+" , "-" or "empty"; an octal number is an apostrophe, followed by at most 9 octal digits, followed by an apostrophe.

2.2.5.1. The Layout of HACOSYS constants.

The following 6 basic forms are admissible

a) an optional sign, followed by an unsigned decimal integer

b) an optional sign, followed by an unsigned octal number

c) an optional sign, followed by the identifier of a fixed constant

d) an optional sign, followed by the identifier of a derived constant

e) an optional sign, followed by the identifier of an invariant address

f) an optional sign, followed by a colon ":", followed by the identifier of a static

   address.

All six may be followed by the optional increment; this consists of (zero or more times) a "[", followed by one of the six constant formats, followed by "]".

Remark 1. The character sequences "][+" and "][-", that may thus arise may be contracted into "+" and "-" respectively.

Remark 2. If the constant starts with a minus sign, this minus sign applies to the complete constant: all increments are added (mod 2 ! 27 -1) and at the end the result is inverted.

2.2.5.2. The Layout of HACOSYS instructions.

The instruction notation is an adaptation of the ELAN conventions.

Instructions with an address of type "STAT" may have this address in the form

a) M

b) the identifier of a static address

followed by the optional increment as described in 2.2.5.1. (The identifier "M" is regarded as static address = 0). The resulting address must fit into the 15 bits available.

Instructions with an address of type "STATB" may have this address in the form

a) M[B]

b) identifier of a static address, followed by "[B]

followed by the optional increment (also after "B", the contraction convention applies). The resulting address must fit into the 15 bits available.

instructions with an address of type "DYN" may have this address in the form

a) MG, MA, MS, MC, MT, MD, Mp

b) the identifier of a dynamic address

followed by the optional increment.

In the above cases the corrections are applied to the future address part of the instruction.

The address operand of type ":DYN" has the form ":" followed by one of the forms dynamic address just described; the address operand ":STAT" has the form of an unsigned constant (see 2.2.5.1). Both followed by the optional increment.

All increments that follow are added to the unsigned operand thus described. The result must be less than 32768 in absolute value, an initial plus or minus sign applies to the result thus obtained, the resulting sign is processed in building up the instruction part.

transcribed by Brian Fitzwater
revised 04-Sep-2011

7 januari 1966 | EWD 149

Documentatie over de communicatie apparatuur aan de EL X8. (Vervanging van EWD140)

0. Inleiding

Er is voorzien in een maximum van 48 zg. Apparaten, genummerd van 0 t/m 47.

Ze vallen uiteen in twee groepen:

| nr.0 t/m 31: | de echte apparaten
| nr.32 t/m 47: | de administratieve apparaten.

De administratieve apparaten verrichten parallel aan de basismachine zekere handelingen (zoals “tandenpoetsen” en “foutafhandeling”); deze apparaten hebben een vast nummer, dat niet installatie-afhankelijk is. De echte apparaten in een specifieke installatie ontlenen hun nummer aan de plaats in de communicatiebekabeling; deze apparaatnummers zijn dus wel installatie-afhankelijk, kunnen zelfs gewijzigd moeten worden bij heropstelling.

1. Communicatie opdrachten.

Met elk apparaat zijn drie flipflops geassocieerd.

AF | ( = actie Flipflop)
IF | ( = Ingreep Flipflop)
LVIF | (= Luistervergunning Ingreep Flipflop).

Zij worden beschouwd als booleans; als hun waarde op bits wordt afgebeeld, dan wordt true door 1 en false door 0 gerepresenteerd, zodat de logische vermenigvuldiging de and-functie oplevert.

1.1. Woordsgewijze uitleesopdrachten.

Het opdrachtenrepertoire van de X8 bevat de mogelijkheid het 1ste (2de of 3de) IF- of LVIF-woord uit te lezen. Tot nu toe is alleen de layout van de 1ste woorden beslist, dwz. de wijze, waarop de bitposities in dit woord aan de apparaten zijn toegevoegd:

d26 | = permanent 0 (dit is het tekenbit)
d25 | = toegevoegd aan apparaat nr. 39
   : |                                                    :
d18 | = toegevoegd aan apparaat nr. 32
d17 | = toegevoegd aan apparaat nr.   0
   : |                                                    :
d0 | = toegevoegd aan apparaat nr. 17

Bij de woordsgewijze uitleesopdrachten specificeerd men

1) welk register in de uitlezing betrokken is; hier heeft men de keus tussen de registers A en S

2) welk type flipflops uitegelezen moeten worden; hier heeft men de keus tussen de IF's en de LVIF's

3) de keus tussen "schoon in" en "logische vermenigvuldiging"; in het geval "schoon in" geldt het flipflopwoord zelf als het resultaat, dat bij non-U in het geselecteerde register verschijnt, in het geval van "logische vermenigvuldiging" geldt het logische product van het flipflopwoord en de oorspronkelijke inhoud van het geselecteerde register als het resultaat dat bij non-U in het geselecteerde register verschijnt

4) 1ste, 2de of 3de flipflopwoord.

De layout van deze opdrachten is als volgt:

d26 t/m d21 | = 110 110 |  | A-register
| = 111 110 |  | S-register
d14 t/m d9 | = 111 101 |  | IF
| = 111 110 |  | LVIF
d8 t/m d6 | = 000 |  | schoon in
| = 001 |  | logische vermenigvuldiging
d5 t/m d0 | = 000 000 |  | 1ste flipflopwoord
| = 000 001 |  | 2de flipflopwoord
| = 000 010 |  | 3de flipflopwoord

Van de adresvarianten is alleen de B-modificatie toegestaan, PZE en UYN werken normaal. NB. De AF's zijn niet uitleesbaar.

1.2. Bitsgewijze zetopdrachten

De flipflops kunnen individueel gezet worden. Hierbij specificeert men

1) of de nieuwe waarde true of false (1 of 0) moet zijn

2) op welk type flipflop de opdracht betrekking heeft; hier heeft men de keuze tussen AF, IF en LVIF

3) het apparaatnummer (dwz. het nummer van het apparaat, waarmee deze flipflop geassocieerd is.)

De layout van deze opdrachten is:

d26 t/m d21 | = 110 110 |  | zet flipflop false (=0)
| = 111 110 |  | zet flipflop true (=1)
d14 t/m d9 | = 111 000 |  | AF
| = 111 001 |  | IF
| = 111 010 |  | LVIF
d8 t/m d6 | = 000 |  |
| = 001 |  | logische vermenigvuldiging
d5 t/m d0 | = 000 000 |  | binaire representatie van het apparaatnummer

Van de adresvarianten is alleen B toegestaan, van de conditievolging alleen Y en N; U, P, Z, E zijn verboden.

De flipflop IV (Ingreep Vergunning, zie onder) kan gezet worden door de opdrachten "maak doof" resp. "maak horend", met de coderingen:

d26 t/m d21 | = 110 110 |  | IV:= false (=0, maak doof)
| = 111 110 |  | IV:= true (=1, maak horend)
d14 t/m d12 | = 110 |  |
d11 t/m d0 | = 000 000 000 000 |  |

Hierbij zijn Y en N de enige toegelaten varianten.

2. Betekenis van IF, LVIF, IV en AF.

De IF van een apparaat fungeert ten opzichte van de basismachine als een soort attentiesignaal; wij zullen later zien onder welke omstandigheden de voltooiing van een zg. startopdracht voor een communicatieapparaat de assignment "IF := true (vanzelfsprekend is hier de met het apparaat geassocieerde IF bedoeld) als neveneffect heeft.

De primaire reactie van de basismachine op zo'n attentiesignaal is de zg. ingreep, die plaats vindt als:

1) IV (dwz. machine horend) and

2) voor ten minste 1 apparaat geldt "LVIF and IF".

Door het zetten van de LVIF's kan de basismachine reguleren, van welke apparaten het ingreepmechanisme al dan geen nota neemt; door het zetten van IV (bv. maak doof) kan de basismachine het optreden van een ingreep generaal verhinderen.

Opm. Wanneer de opdracht (hetzij maak horend, hetzij een herstellende sprong) de overgang van doof naar horend bewerkstelligt, zal onmiddelijk na deze opdracht nog geen ingreep optreden, ook al geldt allang voor een of meer appaarten "LVIF and IF". Na een effectief horend makende opdracht wordt dus gegarandeerd de volgende opdracht nog aansluitend uitgevoerd, voordat de eerste ingreep kan optreden. Daarentegen is elke overgang van horend naar doof ten aanzien van de ingreeponderdrukking onmiddelijk effectief.

De uitvoering van de ingreep bestaat hieruit, dat

1) in plaats van de volgende opdracht de opdracht op adres 24 wordt uitgevoerd als operand van een DO-opdracht (dwz. de ophoging van OT wordt onderdrukt, omdat deze opdracht immers niet onder controle van OT is aangehaald)

2) aan het einde van de ingreep wordt de machine doof gemaakt.

Het normale gebruik is, dat de uiteindelijke ingreepopdracht een normale (dwz. niet stapelende) subroutinesprong is. In de link, die daarbij wordt weggeschreven, wordt dus nog IV = true genoteerd; het adres in deze link wijst naar de opdracht uit het onderbroken programma, die net niet meer aan de beurt kwam.

Opm. De doofmaking als onderdeel van de ingreep vindt plaats aan het einde; zou de uiteindelijke ingreepopdracht (onwaarschijnlijkerwijze) een opdracht blijken te zijn, die de machine horend maakt, dan worden er aan het einde van de ingreep twee tegenstrijdige bevelen gegeven ten aanzien van de zetting van IV; de uiteindelijke waarde van IV moet dan ook als onbepaald beschouwd worden.

In het begin van het ingreepprogramma kan de basismachine —zie 1.1— door inspectie van het logische product van IF— en LVIF-woord onderzoeken, welke IF’s voor deze ingreep verantwoordelijk kunnen zijn geweest.

Wat de IF's zijn voor de basismachine, zijn de AF's voor Charon: wanneer Charon voor een apparaat geen startopdracht (zie onder) onder behandeling heeft, legt Charon "AF = true" uit als de aanwezigheid van tenminste ��n nieuwe startopdracht voor dit apparaat.

3. Vaste toekenning van geheugenplaatsen aan apparaten.

De AF fungeert als attentiesignaal vanuit de basismachine ten behoeve van een apparaat, de IF fungeert als attentiesignaal vanuit Charon ten behoeve van de basismachine. De feitelijke informatieuitwisseling tussen basismachine en Charon vindt plaats via het kerngeheugen, dat zowel voor de basismachine als voor Charon toegankelijk is (met prioriteit voor Charon).

Voor dit doel zijn voor elk apparaat vier opeenvolgende geheugenadressen gereserveerd, te beginnen bij adres

64 + 4 * apparaatnummer.

(Dit loopt dus van adres 64 t/m adres 255.) In het volgende zullen deze vier woorden worden aangeduid met AR0, AR1, AR2 en AR3.

In het volgende zullen van een woord de 9 meest significante bits enerzijds en de 18 minst significante bits anderzijds vaak als onafhankelijke bestanddelen beschouwd worden; het stuk d26 t/m d18 heet dan "het tellingdeel", het stuk van d17 t/m d0 heet dan "het adresdeel". Als wij spreken over de numerieke waarden van deze delen, dan bedoelen we de non-negatieve getallen met deze 9, resp. 18 bits als binaire representatie.

Vooruitlopend geven wij de algemene functie van de vier woorden, zij het, dat we slechts een eerste aanduiding van de betekenis kunnen geven.

Opm. Deze betekenissen zijn niet bij alle apparaten van toepassing; uitzonderingen zullen bij de apparaatsgewijze behandeling vermeld worden.

AR0: |  | tellingdeel | : | werkruimte Charon, in het bijzonder gereserveerd voor de OK-status
|  | adresdeel: |  | label van de heersende schakel
AR1: |  | tellingdeel | : | if IFT < 0 then IFT + 512 else IFT
|  | adresdeel | : | irrelevant, mits ≠ 0 (wordt uit compalibiliteitsoverwegingen met de X2 door Charon niet gebruikt)
AR2: |  | tellingdeel | : | =AFT
|  | adresdeel | : | meestal werkruimte voor Charon
AR3: |  | Werkruimte voor Charon (vaak gereserveerd voor het zg. "lopende codewoord")

4. Ketens van startopdrachten

4.1. Layout van de startopdracht.

Per apparaat kan men een keten van startopdrachten "aanhangig maken". Elke startopdracht �omdat ze geketend kunnen worden ook wel "schakel" genoemd� beslaat een aantal opeenvolgende geheugenplaatsen. Onder de "label van een schakel" verstaat men het adres van het tweede woord van deze schakel.

De algemene layout van een startopdracht begint als volgt:

label[-1]: |  | Slotwoord. V��r de feitelijke uitvoering van deze startopdracht, is de inhoud van dit woord voor Charon irrelevant; na afloop van de uitvoering heeft Charon in dit woord verslaglegging gedaan over de afloop van de startopdracht.
label[ 0]: |  | bij de laatste schakel van een keten voor Charon irrelevant;
|  | bij een schakel, die niet de laatste van de keten is, eist Charon
|  |  | tellingdeel | : allemaal nullen
|  |  | adresdeel | : label van de volgende schakel.
label[ 1]: |  | 1ste van een rij van 1 of meer codewoorden ter beschrijving van de startopdracht; aantal en layout hiervan is apparaat-afhankelijk

De basismachine moet de startopdracht klaarmaken in een vorm, die specifiek is voor het apparaat in kwestie. De startopdracht is niet positioneel gebonden aan het apparaat, noch aan het gebied van het kerngeheugen, waarop de feitelijke informatietransport betrekking zal hebben. Omdat voor de labels altijd 18 bits gereserveerd zijn, is er geen hardware restrictie aan hun plaats opgelegd.

4.2. Het aanbieden van startopdrachten.

Deze sectie behandelt hoe in het algemeen startopdrachten moeten worden aangeboden; de opstelling van de startopdracht zelf —in het bijzonder van de codewoorden— wordt uitgesteld tot de apparaatgewijze gehandeling. Omdat de regels, die bij het aanbod in acht genomen moeten worden, uiteindelijk hun oorsprong vinden in het gedrag van Charon, zullen wij eerst beschrijven hoe Charon overgaat tot het accepteren van een nieuwe startopdracht.

4.2.1. Charongedrag ten aanzien van AF en AFT.

In het volgende zullen wij de activiteiten van Charon kortheidshalve beschrijven alsof Charon niets anders te doen heeft dan het verzorgen van een enkel apparaat: het feit dat Charon meer apparaten kan verzorgen betekent dat de hieronder te beschrijven Charon-reacties niet instantaan hoeven plaats te vinden, nl. niet wanneer Charon net even met iets anders nuttigs bezig is. Met "rust" van Charon wordt hieronder bedoeld "rust ten aanzien van dit apparaat".

Als Charon geen startopdrachten onder behandeling heeft, zal hij rusten, zolang AF false is.

Zodra AF true is, zal Charon dan een startopdracht in behandeing nemen, en wel degene, waarnaar verwezen wordt door het adresdeel van AR0: label van heersende schakel.

Aan het eind van de behandeling van de startopdracht zal Charon als ondeelbare handeling

AFT := AFT - 1 (mod 512); if AFT = 0 then AF := false

uitvoeren. De ondeelbaarheid van de aftrekking wordt gegarandeerd, doordat Charon de terugschrijf-halve-cyclus van het kerngeheugen gebruikt om de nieuwe waarde van AFT in het adresdeel van AR2 terug te schrijven en doordat het kerngeheugen slechts per hele cyclus aan de verschillende processen gegund wordt. Verder wordt als onderdeel van de AFT-behandeling de assignment "AF := false" uitgevoerd, als AFT de waarde = 0 gekregen heeft; anders blijft AF onaangetast.

Als de nieuwe waarde van AFT ≠ 0 was —en AF dus onbeinvoed is gebleven— zal Charon

adresdeel AR0 := M[ adresdeel AR0]

uitvoeren, dwz. de label van de volgende schakel tot "label van heersende schakel" bevorderen.

Daarna (zie IFT-behandeling, later) wordt de behandeling van de startopdracht voltooid, deze voltooing aan de basismachine teruggemeld en tenslotte gaat Charon over in de uitgangstoestand van deze sectie "geen startopdracht onder behandeling". De vorige is nl. voltooid en de volgende is nog niet in behandeling genomen.

4.2.2. Een enkele schakel voor een passief apparaat.

Bij het simpelste gebruik van Charon biedt de basismachine slechts de volgende schakel aan, nadat de basismachine (via IFT en IF, zie later) van de voltooiing van de vorige schakel heeft kennisgenomen en Charon dus (ten aanzien van dit apparaat) in rust is.

In de aangeboden schakel is de inhoud van "label[0]"label van de volgende schakel- omdat er geen volgende schakel is, irrelevant.

De basismachine moet er voor zorgen, dat in het adresdeel van AR0 de label van de aangeboden schakel staat —om Charon in staat te stellen de schakel te vinden—, moet er voor zorgen, dat AFT = 1 —om te zorgen, dat Charon na afloop AFT = 0 maakt en in de rusttestand overgaat— en tenslotte moet de basismachine AF op true zetten, opdat Charon metterdaad aan de startopdracht begint.

Opm. De heersende label in het adresdeel van AR0 wordt hierbij niet verstoord; als alle aan te bieden startopdrachten op dezelfde plaats staan, hoeft het tellingdeel van AR0 van te voren slechts ��n keer ingevuld te worden.

4.2.3. Een keten voor een passief apparaat.

Wil men in plaats van een enkele schakel (zie vorige sectie) een keten van schakels aan een op dat moment passief apparaat aanbieden, dan moet de basismachine er voor zorgen, dat het adresdeel van AR0 de label van de eerste schakel bevat, dat de volgende schakels netjes aan hun voorganger gehaakt zijn, dat AFT gelijk is aan het aantal schakels —om er voor te zorgen, dat Charon de keten netjes afwerkt en dan ophoudt— en tenslotte zet men AF op true opdat Charon metterdaad aan de keten begint.

Opm. In dit geval blijft het adresdeel van AR0, de label van de heersende schakel— niet ongewijzigd.

4.2.4. Het aanhaken van een schakel aan een mogelijk nog actief apparaat.

Wij zullen nu een methode behandelen om een schakel aan te haken aan een keten die mogelijkerwijs nog niet is afgewerkt. Omdat Charon ook op de AFT, de AF en de AR0 zou kunnen opereren, moet dit wel met enige voorzorgen geschieden.

We nemen aan dat een zogenaamde vulwijzer "VW" de label van de laatst aangehaakte schakel bevat. Als de nieuwe label volledig is geprepareerd —label[0] is daarin irrelevant— vervolgt de basismachine

1) met "M[VW] := label nieuwe schakel" wordt de nieuwe schakel aan de keten gehaakt (het ingevulde woord bevat in het tellingdeel louter nullen);

2) met "VW" := label nieuwe schakel" wordt de vulwijzer up to date gemaakt.

3) met een additieve uitopdracht in de versie "PLUS" wordt AFT met 1 opgehoogd, zodat de hierbij gevormde nieuwe waarde van AFT tevens in een register van de basismachine verschijnt en geinspecteerd kan worden. Voor de ophoging gebruikt de basismachine een additieve uitopdracht, omdat zodoende gegarandeerd wordt, dat de ophoging van de basismachine en een mogelijke aflaging door Charon niet met elkaar op oncontroleerbare (in elk geval ongewenste) wijze met elkaar kunnen interfereren.

4) indien de door de PLUS-opdracht in het register van de basismachine opgevangen nieuwe AFT-waarde = 1 is, dan was de oude AFT-waarde dus = 0 en heeft Charon dus besloten uit deze keten geen nieuwe startopdracht meer aan te halen; de handeling onder 1) genoemd heeft geen effect gehad en Charon heeft AF op false gezet. In dit geval vervolgt de basismachine aldus:

4.1.)

in het adresdeel van AR0 wordt de label van de nieuwe schakel ingevuld zonder het tellingdeel van AR0 te verstoren. We zijn in de toestand, dat Charon besloten heeft, de keten met rust te laten, wat betekent, dat Charon het adresdeel van AR0 verder wel met rust zal laten, maar het tellingdeel van AR0 mogelijkerwijs nog niet. Het invullen van de label van de nieuwe schakel in het adresdeel van AR0 zonder het bijbehorende tellingdeel te verstoren kan de basismachine verrichten met een additieve uit-opdracht bij AR0 op te tellen.

4.2.)

AF := true . NB . De assignment "AF := true" mag alleen uitgevoerd worden in dit geval, waarin we dus hebben vastgesteld, dat Charon "AF := false" had uitgevoerd. Wie redeneert "We hebben iets nieuws aangeboden, dus AF mag in elk gevalop true gezet worden." vergist zich, want Charon zou denieuwe startopdracht tegen deze tijd al voltooid kunnen hebben en terecht al AF op false gezet kunnen hebben.

Opm. Het is niet aantrekkelijk om te proberen, de activiteit ten aanzien van een keten tijdelijk stil te leggen, door (wat de basismachine wel kan) AF := false te zetten. Charon's beslissing om op grond van AF = true een nieuwe startopdracht aan te halen laat opzichzelf geen sporen in het kerngeheugen achter. Zo de basismachine er achter kan komen welke startopdracht nog wel aangehaald is en welke gegarandeerd niet meer aangehaald zal worden, dan zal dat niet zonder real-time overwegingen kunnen.

Opm. Handeling 1) dient achterwege te blijven als er nog geen laatst aangehaakte schakel is (aan het begin bv.) of als de geheugenruimte, destijds door de laatst aangehaakte schakel ingenomen, inmiddels een heel andere bestemming heeft gekregen (zie 4.3.1).

4.3. De terugmeldingen van voltooiingen.

Als 0 ≤ tellingdeel AR1 ≤ 255, dan wordt het tellingdeel van AR1 geinterpreteerd als IFT; als 256 ≤ tellingdeel AR1 ≤ 511, dan wordt het tellingdeel van AR1 geinterpreteerd als IFT + 512. Het waardebereik van IFT is dus -256 ≤ IFT ≤ 255. IFT ≥ 0 is gekarakteriseerd door d26=0.

4.3.1. Het gedrag van Charon ten aanzien van IFT en IF.

Charon beeindigt de behandeling van een startopdracht met in een ondeelbare handeling

IFT := iFT + 1 (mod 512); if IFT > 0 then IF := true

uit te voeren.

De ondeelbaarheid van de additie wordt weer gerealiseerd door in de terugschrijf-halvecyclus de opgehoogde waarde van IFT terug te schrijven.

Charon verricht deze handeling, nadat AFT is afgelaagd, de label van de heersende schakel eventueel is opgestapt en slotwoord en OK-status (zie onder) zijn ingevuld. De IFT-ophoging is de signalering, dat Charon de afgewerkte schakel niet meer zal raadplegen; de basismachine mag hierna de door de afgewerkte schakel belegde geheugenplaatsen dus een andere bestemming geven.

4.3.2. IFT-aflaging door de basismachine.

Tegenover de IFT-ophoging door Charon moeten IFT-aflagingen van de basismachine staan. Door deze met behulp van een additieve uitopdracht uit te voeren, verzekert men, dat deze aflagingen niet interfereren met de eventuele ophogingen door Charon. Doordat het adresdeel van AR1 ≠ 0 is, bereikt men, dat IFT = 0 door deze additieve uitopdracht inderdaad correct met een tellingdeel uit louter nullen wordt afgeleverd.

Het gedrag van Charon is er op gericht om "IF" de betekenis te geven "IFT > 0": als IF deze betekenis heeft, blijft hij bij Charon-verhogingen van IFT (aangenomen, dat de capaciteit van IFT niet overschreden wordt) gehandhaafd. Als de basismachine IFT gewijzigd heeft en men stelt er prijs op, dat daarna IF weer "IFT > 0" zal betekenen, dan kan de basismachine als volgt te werk gaan:

" IF := false;
if IFT > 0 then IF := true"

De analyse "IFT > 0" kan worden uitgevoerd door te testen, of van AR1 d26 = 0 en het tellingdeel ≠ 0 is. Nauwkeurige analyse leert, dat er geen bezwaar tegen zou zijn, wanneer voor deze test het tellingdeel van AR1 tweemaal uit het geheugen geselecteerd zou worden, ook al zou Charon onderhand IFT ophogen. (De veronderstelling, dat de basismachine na "IF := false" IFT ongemoeid laat, is essentieel; het protocol, zoals in EWD140 gegeven is fout, wanneer IFT ook negatieve waarden mag aannemen!)

Wanneer men begint met IFT = 0 en als onderdeel van het kennisnemen van een voltooing van een startopdracht IFT met 1 aflaagt, dan heeft IFT de betekenis van het aantal reeds voltooide schakels, waarvan de basismachine nog geen kennis heeft genomen. Door IFT een negatieve voorgift te geven, kan men desgewenst bereiken, dat IF pas true gezet wordt (en de ingreep tengevolge hiervan dus pas optreedt) na voltooing van de zoveelste startopdracht uit de keten. In al deze gevallen mogen we veilig aannemen, dat het beperkte bereik van de AFT en de IFT nimmer een beperking zal zijn.

5. Het toetsenbord.

Het toetsenbord is een invoerapparaat, waarvan het nummer installatie-afhankelijk is.

Het is een ernstig afwijkend apparaat: het verricht zijn activiteit nl. niet op commando van de door de basismachine gegeven startopdrachten, maar doordat de operateur een toets aanslat. Charon maakt bij het toetsenbord geen gebruik van AR2.

Als de operateur een toets aanslaat, verricht Charon:

if AF and LVAF then AR0 := karakter else AR3 := karakter; AF := false;
IFT := IFT + 1 (mod 512); if 0 < IFT then IF := true

(LVAF is een interne boolean van Charon, die in dit geval permanent = true geacht wordt te zijn; zie verder "Het tandenpoetsen.".)

Door aanvankelijk IFT (= tellingdeel AR1) = 0 te maken en (in overeenstemming met de normale betekenis) IF = false te zetten en LVIF = true, bereikt men dat de basismachine via het ingreepmechanisme van het indrukken van een toets op de hoogte wordt gesteld, zodra de basismachine horend is. Door bovendien AF = true te zetten, verzorgt men, dat het eerste karakter in AR0 komt en eventueel volgende karakters (met overschrijving van de vorige) in AR3 terechtkomen.

(Het vullen van AR3 geschiedt, wanneer de basismachine niet tijdig op de ingreep na het vorige karakter gereageerd heeft; in het onwaarschijnlijkegeval, dat Charon nog geen kans heeft gezien, om het vorige karakter in het geheugen te plaatsen, hebben de te snel op elkaar volgende aanslagen het effect, dat Charon als bovenbeschreven ��n karakter in het geheugen plaatst, maar nu een zg. non-valide met een getalwaarde groter dan 31.)

L. Zwanenburg heeft een programma gemaakt, waarin de tijd in alternerende perioden verdeeld wordt;
periode a): verwerking van een enkel of verwerping van een of meer karakters, afgesloten door de indicatie, dat nu de volgende aanslag mag plaatsvinden;
periode b): de tijd, waarin een aanslag mag plaatsvinden, afgesloten door de reactie op de ingreep;
en wel zodanig, dat in de periode a) slechts dan een karakter wordt verwerkt, als in de voorgaande periode a) geen en in de daaropvolgende periode b) precies ��n aanslag heeft plaatsgevonden.

Bij de reactie op de ingree�p van het toetsenbord gaat de machine dan als volgt te werk

L0: IF := false; IFT := IFT - 1; if IFT ≠ 0 then
           begin AR0 := iets negatiefs; goto L0 end;
    A := AR0; if A > 0 then
          begin AR0 := iets negatiefs;
                A is nu het volgende karakter, dat
                                      geaccepteerd wordt end
                    else er zijn karakters verworpen, wat
                         desgewenst kan worden aangegeven;
    AF := true;
    comment nu kan de operateur weer een karakter in
    AR0 krijgen;

6. Het teleprinterdrukwerk.

De indeling voor AR0, AR1, AR2 en AR3 is normaal (zie 3.); het adresdeel van AR2 wordt niet gebruikt. Het lopend codewoord in AR3 is gesplitst in tellingdeel en adresdeel (zie onder).

Een startschakel geeft de mogelijkheid om de woorden uit N opeenvolgende adressen (1 ≤ N ≤ 512) in volgorde naar het drukwerk te sturen. Van elk woord bepalen de laagste zes bits een actie van het drukwerk; de 21 hoogste bits van deze woorden zijn irrelevant.

De startschakel bestaat uit drie woorden; de eerste twee (label [-1] en label[0]) zijn normaal (zie 4.1.), het derde woord (label[1]) bevat het zg. codewoord. Het codewoord bepaalt lengte en ligging van de naar het drukwerk te zenden woordenrij en wel:

tellingdeel codewoord = | lengte van de rij, (waarbij tellingdeel = 0 de rijlengte =512 voorschrijft; zodat dus niet in de lege startopdracht is voorzien)
adresdeel codewoord  = | beginadres van de woordenrij � 1.

Als de startopdacht door Charon geaccepteerd wordt, wordt het codewoord uit de heersende schakel in het lopende codewoord (in AR3 dus) overgenomen. Per woordverzending naar het drukwerk neemt Charon tweemaal contact met het geheugen op. In het eerste geheugencontact met AR3 wordt het tellingdeel (mod. 512) met 1 verlaagd en wordt het adresdeel ( modulo 2 ↑ 18) met 1 verhoogd. Is het resulterend tellingdeel = 0, dan is het nu nog volgende woordtransport naar het drukwerk het laatste van de startopdracht. In het geheugencontact, volgend op dat met AR3 wordt het woord getransporteerd, aangewezen door het zojuist in AR3 weggeschreven adresdeel. De afsluitingsriten van de schakelbehandeling ( zoals AFT-aflaging etc. en IFT-ophoging etc.) vinden in Charon plaats, zodra het laatste woord naar het drukwerk is gezonden. Charon meldt de startopdracht dus als voltooid, terwijl het drukwerk nog 100 msec bezig is met het feitelijk drukken van het laatst aangeboden karakter. Daar de feitelijke woordtransporten naar het drukwerk steeds pas plaatsvinden, nadat Charon van de teleprinter het signaal ontvangen heeft, dat het volgende woord gestuurd mag worden, is een en ander (zoals te verwachten) geen beletsel om meteende volgende startopdracht aan te bieden, noch voor Charon, om deze alvast te accepteren.

Daar de afwerking van de startopdracht afhankelijk is van de terugsignalering van het drukwerk naar Charon, zou een startopdracht nimmer eindigen, als deze terugsignalering achterwege blijft, zoals dat het geval zou zijn, als het drukwerk helemaal niet is aangesloten. Charon initieert om deze reden alleen het transport van een woordrij, nadat hij (naar eer en geweten) geverifieerd heeft, dat het drukwerk volgens de regels van de kunst is aangesloten en naar behoren functioneert.

Een en ander wordt als volgt gerealiseerd. Het Charonprogramma, dat het drukwerk verzorgt, kent twee toestanden, genaamd "OK resp. "NBK" (Niet Bedrijfs Klaar). Vlak voordat dit programma in de toestand van OK een nieuwe startopdracht zal gaan aanhalen, test Charon, of het drukwerk goed is aangesloten; zo ja, dan wordt de startopdracht als boven afgehandeld, zo nee, dan gaat het verzorgingsprogramma prompt over in de toestand NBK, beschouwt deze opdracht als afgehandeld en gaat over tot de afsluitingsriten. Als het verzorgingsprogramma zich in het begin van het aanhalen van de volgende schakel al in de toestand NBK bevindt, dan worden alle startopdrachten zg. symbolisch afgewerkt —dwz. Charon gaat meteen tot de afsluitingsriten over— met uitzondering van de zg. HOK-opdracht (Herstel OK-toestand). De uitvoering van de HOK-opdracht bestaat nl. daaruit, dat het verzorgingsprogramma van het drukwerk in de toestand OK gebracht wordt.

De twee toestanden van het verzorgingsprogramma worden onderscheiden in het tellingdeel van AR0 en wel:

tellingdeel AR0 | = 000 000 000 | betekent OK
| = 111 111 111 | betekent NBK.

De afsluitriten van een startopdracht omvatten tevens het invullen van het zg. slotwoord (in label[-1]); in het tellingdeel van het slotwoord van de schakel in voltooing vult Charon een copie van het tellingdeel van AR0 in; de waarde, die aan het adresdeel van het slotwoord wordt toegekend is ongedefinieerd.

De HOK-opdracht wordt gecodeerd door een codewoord (label[1]), bestaande uit louter nullen. De uitgevoerde HOK-opdracht krijgt in zijn schakel een slotwoord, bestaande uit louter nullen.

Opm 1. Het codewoord = + 0 wordt altijd als een HOK-opdracht en nimmer als transportopdracht uitgelegd. Hierdoor is het niet mogelijk om in ��n startopdracht een woordenrij van 512 woorden te transporteren, te beginnen op adres 1.

Opm 2. De HOK-opdracht mag gegeven worden, terwijl het verzorgingsprogramma zich reeds in de toestand OK bevindt; hij heeft dan geen effect. Het aanhaken van dergelijke "overbodige" HOK-opdrachten aan nog actieve ketens moet in het algemeen niet gestimuleerd worden: in het algemeen (dwz. bij ingewikkeldere apparaten) kan nl. de OK-toestand bij de uitvoering van de nog voorafgaande schakels verlaten worden en de oorspronkelijk overbodige HOK-opdracht zou dan plotseling wel effect krijgen, en waarschijnlijk een ongewenst effect!

Opm 3. Het codewoord van de startschakel, waaraan het verzorgingsprogramma in de OK-toestand zou willen beginnen, maar wat niet doorgaat, omdat het drukwerk zich niet bevredigend aan Charon voordoet, zodat de overgang naar NBK plaatsvindt, wordt niet geraadpleegd. Als dit een HOK-opdracht was, raakt het verzorgingsprogramma dus toch in de NBK-toestand en deze HOK-opdracht krijgt dan niet het slotwoord = +0.

6.1. Controlelichten op het teleprinterdrukwerk.

6.1.1. Rode en groene knop.

De besturing van het teleprinterdrukwerk kent twee toestanden, genaamd "rood" respectievelijk "groen". De heersende toestand wordt aangegeven door het branden van een rood, resp. groen controlelichtje. Verder bevinden zich bij de teleprinter een rode en een groene knop; door een van deze beide in te drukken kan men de teleprinter in de overeenkomstige toestand brengen.

Boven hebben wij de teleprinter beschreven in de groene toestand. In de rode toestand zendt de teleprinter geen synchronisatiesignalen naar Charon. Zodoende kan men door op de rode knop te drukken het teleprinterdrukwerk even stilleggen —bv. om het papier te verschikken— en daarna, door het drukken op de groene knop het teleprinterdrukwerk weer vrijgeven en wel zonder dat deze ingreep tot Charon (en dus evenmin tot de basismachine) is doorgedrongen. (Het drukwerk heeft zich even gedragen als een heel langzaam apparaat, maar "real time" overwegingen spelen geen rol in de logica van het samenspel tussen basismachine en Charon, noch tussen Charon en de randapparatuur.)

Zodra Charon metterdaad wacht op een dergelijke synchronisatiesignalering, die voorlopig achterwege blijft, omdat het apparaat zich in de rode toestand bevindt, wordt de operateur hierop attent gemaakt, doordat het bijbehorende rode lampje gaat flikkeren.

6.1.2. Het papiercontact.

Als in het teleprinterdrukwerk het papier dreigt op te raken, wordt dit mechanisch gedetecteerd. Dit heeft tot gevolg, dat bij einde van het papier
1) een speciaal waarschuwingslichtje op de teleprinter geat branden
2) de besturing van het teleprinterdrukwerk overgaat in de rode toestand.

6.1.3. Het attentiesignaal.

Als het ijzeren kruis is gedrukt en 100 msec later de lintkleur zwart is, dan gaat een wit attentiesignaal flikkeren, dat door de opereteur kan worden uitgezet. Door het ijzeren kruis nooit door een lintkleurverandering te laten volgen, kan men er voor zorgen, dat het flikkerlicht alleen na een zwart ijzeren kruis volgt.

7. De bandlezer.

De betekenis van de centrale administratie AR0 t/m AR3 is normaal (zie 3.); de layout van de startschakel, die drie woorden omvat is als in 4.1 beschreven, de betekenis van het codewoord in label[1] is:

label[1]: | codewoord
| als codewoord bestaat uit louter nullen, dan HOK-opdracht, anders

tellingdeel =  | lengte van de rij (waarbij tellingdeel = 0
| de lengte = 512 voorschrijft)
adresdeel =  | beginadres van de woordenrij - 1

Het Charonprogramma, dat de bandlezer verzorgt kent drie toestanden, genaamd OK, NBK (Niet Bedrijfs Klaar) en EB (Einde Band). De toestand van het verzorgingsprogramma wordt ten bate van Charon in het tellingdeel van AR0 bijgehouden. Ten bate van de basismachine, die na afloop van elke startopdracht moet kunnen vaststellen, hoe deze is uitgevoerd, wordt in het tellingdeel van elk slotwoord de op het moment van de invulling heersende toestand genoteerd. In beide tellingdelen geldt de codering:

000 000 000 |  | OK |
111 111 111 |  | NBK | (Nist Bedrijfs Klaar)
111 111 110 |  | EB | (Einde Band)

De overgang naar de toestand NBK vindt (zie 6.) weer plaats, wanneer het verzorgingsprogramma, vlak voordat het in de toestand OK een startopdracht zou aanhalen, de aanwezigheid van de correct aangesloten bandlezer niet naar tevredenheid kan vaststellen. Van deze startopdracht wordt het codewoord dan niet geraadplaagd en Charon gaat direct over tot de afsluitingsriten (met vermelding van de inmiddels heersende NBK in het slotwoord).

In de toestanden NBK en EB worden startopdrachten symbolisch afgewerkt, dwz. Charon kijkt, of het codewoord de HOK-opdracht is, zoja, dan gaat het verzorgingsprogramma over in de toestand OK (met vermelding van een slotwoord = +0), zo nee, dan wordt de opdracht meteen afgesloten met vermelding van de toestand (NBK of EB) in het slotwoord.

Wanneer de OK-status geldt en de bandlezer lijkt zijn correcte aanwezigheid te bevestigen, dan wordt de nieuwe startopdracht normaal verwerkt. Is hij een (overbodige) HOK-opdracht, dan wordt hij als zodanig uitgevoerd, anders wordt het feitelijk bandlezen geinitieerd. Bij de acceptering van de startopdracht wordt het codewoord uit de heersende schakel in AR3 overgenomen. Per gelezen ponsing neemt Charon tweemaal contact met het geheugen op. In het eerste geheugencontact met AR3 (het zg. lopende codewoord) wordt het tellingdeel (mod 512) met 1 verlaagd en het adresdeel (mod 2¹⁸) met 1 verhoogd. Is het resulterende tellingdeel = 0, dan is het nu volgende woordtransport het laatste van de startopdracht. In het geheugencontact, volgend op dat met AR3 wordt de gelezen ponsing, aan de meest significante zijde aangevuld met nullen, ingevuld op de geheugenplaats, die wordt aangewezen door het zojuist in AR3 weggeschreven adresdeel. Tevens wordt bij het lezen van elke ponsing geinspecteerd of de detectie van het einde van de band alarm geeft, zo ja, dan gaat het verzorgingsprogramma tot de afsluitingsriten van deze startopdracht over, na eerst de toestand EB heersend te hebben gemaakt.

Opm. Er wordt dus altijd tenminste 1 ponsing ten gevolge van de geaccepteerde transportopdracht gelezen. Na elke ponsing wordt eerst gevraagd naar het bandeinde� zo nee, dan wordt pas getest, of de afsluiting tengevolge van tellingdeel = 0 aan de beurt is. Als het slotwoord EB vermeldt, kan de startopdrecht dus wel volledig zijn uitgevoerd! Het symbolisch afwerken verstoort AR3 niet: wanneer de startopdracht op grond van Einde Band is beeindigd� bevindt zich in het tellingdeel van AR3 het ontbrekende aantal pons�ngen, in het adresdeel het adres van het laatst gevulde woord.

De bandlezer leest met een snelheid van 1000 ponsingen per seconde; afgezien van initiering� en afsluitriten belegt het leesproces het geheugen van de machine voor .625 procent van de tijd.

De bandlezer kan ingesteld worden op het lezen van 5-, 7- of 8-gats band. Deze bandbreedte wordt niet geacht bij te dragen tot de informatie, programmatechnische is de heersende bandbreedte niet detecteerbaar. In het geheugen wordt een gat in een ponsing door een 1 en geen gat door een 0 voorgesteld; de individuele posities in een ponsing worden in volgorde op de minst significante bitposit�es van het woord afgebeeld, en wel zo, dat de sporen, toegevoegd aan d2 en d3 aan beide zijden van de 'sprocket holes" liggen. De bandlezer leest alle configuaties onge�nterpreteerd, ook "blank tape" en "all holes�.

NB. In de bandlezer zitten buffers voor twee ponsingen. Dit heeft tot gevolg, dat na bandverw�sselen de eerste twee ponsingen� die tot Charon doordringen, de laatste twee van de vorige band zijn. Na aanzetten van de machine zijn de eerste twee gelezen ponsingen ongedefinieerd.

De band passeert in volgorde
1) een detector voor het einde van de band
2) de rem
3) het leesstation
4) de aandrijving.
De uiteinden van een band kunnen daardoor niet gelezen worden.

De bandlezer is eveneens uitgerust met een rode en een groene knop en bijbehorende controlelichtjes; ook hier flikkert het rode licht als Charon metterdaad wacht op een achterwege blijvend synchronisatiesignaal van de bandlezer ("een hangende startopdracht"). Wanneer Charon op grond van het tot hem doorgedrongen signaal "Einde Band" een startopdracht afbreekt voert hij tevens de bandlezer in kwestie over in de rode toestand, het indrukken van de groene knop heeft slechts effect, wanneer er nog een voldoend lange band in de bandlezer ligt. Het indrukken van de rode en de groene knop dringt als zodanig niet tot de machine door, evenmin als het band verwisselen in een rode bandlezer.

Als er over een bandlezer een band tot en met het einde gelezen is, moeten er, voordat een volgende band over die bandlezer gelezen kan worden, twee dingen gebeurd zijn:
1) de basismachine moet een HOK-opdracht aan deze bandlezer hebben aangeboden
2) de operateur moet een nieuwe band hebben ingelegd en dit met het drukken op de groene knop daarna hebben bekrachtigd.
De volgorde van deze twee gebeurtenissen doet niet ter zake.

8. De bandponser.

De centrale administratie op de plaatsen AR0 t/m AR3, evenals de layout van de startschakel zijn bij de bandponser even normaal als bij het teleprinter drukwerk (zie 6). Teleprinterdrukwerk en bandponser worden nl. door identieke Charon-programma's verzorgd. Nu bepalen de laagste 7 bits van het woord, dat naar de ponser gestuurd wordt, wat er wordt geponst� de overige 20 zijn irrelevant. De toevoeging van de bitposities in het woord aan de sporen op de band is als bij de bandlezer.

Het Charonprogramma� dat de bandponser verzorgt, kent vier toestanden, genaamd OK, NBK (Niet Bedrijfs Klaar)� EB (Einde Band) en ASL (AfSLuit�ng). De toestand van het verzorgingsprogramma wordt ten bate van Charon in het tellingdeel van AR0 bijgehouden. Ten bate van de basismachine� die na afloop van elke startopdracht moet kunnen vaststellen, hoe deze is uitgevoerd, wordt in het tellingdeel van elk slotwoord de op het moment van invulling heersende toestand genoteerd. In beide tellingdelen geldt de codering:

000 000 000 |  | OK
111 111 111 |  | NBK (Niet Bedrijfs Klaar)
111 111 110 |  | EB (Einde Band)
111 111 101 |  | ASL (AfSLuit�ng)

De overgang naar de toestand NOK vindt (zie 6) weer slechts plaats, wanneer het verzorgingsprogramma� vlak voordat het in de toestand OK een startopdracht zou gaan aanhalen, de aanwezigheid van een correct aangesloten bandponser niet naar tevredenheid kan vaststellen. Van deze startopdracht wordt het codewoord niet geraadpleegd en Charon gaat direct over tot de afsluitingsriten (met vermelding van de inmiddels heersende NBK in het slotwoord).

De overgang naar de toestand EB vindt plaats, wanneer het verzorgingsprogramma in de OK�toestand aan een nieuwe startopdracht wil gaan beginnen, de bandponser zijn correcte aanwezigheid lijkt te bevestigen maar de detector op het einde van de band alarm geeft. Van deze startopdracht wordt het codewoord niet geraadpleegd en Charon gaat direct over tot de afsluitingsriten (met vermelding van de inmiddels heersende EB in het slotwoord).

In de toestanden NBK en EB worden startopdrachten symbolisch afgewerkt, dwz. Charon kijkt, of het codewoord de HOK-opdracht is, zo nee, dan wordt de opdracht meteen afgesloten met vermelding van de heersende toestand (NBK of EB) in het slotwoord, zo ja, dan bewerkt de HOK-opdracht bij NBK de overgang naar OK (met slotwoord = + 0) en bij EB de overgang naar ASL (met vermelding van de inmiddels heersende ASL in het slotwoord).

Niet symbolische afwerking treedt op, wanneer het verzorgingsprogramma in de toestand OK of ASL aan een nieuwe startopdracht wil beginnen. De enige verschillen tussen deze twee toestanden zijn

1) | de test van correct aangesloten zijn blijft bij ASL achterwege, de overgang ASL → NBK komt dus niet voor
2) | de test van alarm van de detector van het einde van de band blijft bij ASL achterwege, de overgang ASL → EB komt dus niet voor
3) | bij ASL heeft de HOK�opdracht het neveneffect, dat de bandponser in de rode toestand komt en een lichtje "Band verwisselen" op de bandponser gaat branden. Voor de verwerking van de feitelijke ponsopdracht (in toestand OK of ASL) verwijzen we naar sectie 6, het teleprinterdrukwerk.

Als het einde van de band nadert, krijgt de laatst normaal verwerkte ponsopdracht nog de OK�melding in het slotwoord, van de eerste met de EB-melding is niets meer geponst. Met een HOK�opdracht krijgt de basismachine het Charonprogramma in de afsluitingstoestand� waarin alarm van de einde�band�detect�e genegeerd wordt. De programmeur heeft dan nog de gelegenheid (minstens anderhalve meter band) om een speciale afsluitcombinatie op de band te ponsen (deze mag uit meer dan een startschakel zijn opgebouwd). Een volgende HOK�opdracht brengt het verzorgingsprogramma weer in de OK�toestand, (en wat de basismach�ne betreft kunnen de volgende startopdrachten alweer aangeboden worden), de bandponser is echter nog rood, totdat de operateur een nieuwe rol heeft ingelegd (inclusief het resetten van het EB-contact) en op de groene knop heeft gedrukt.

Opm. In de rode toestand wordt alarm van de einde�band�detector niet aan Charon doorgegeven. Wanneer na de tweede HOK�opdracht de basismachine alweer opdrachten voor de volgende band aanbiedt, kan als de operateur nog geen band verwisseld heeft het einde van de eerste band dus niet voor dat van de tweede aangezien worden. Het drukken op de groene knop heeft geen effect� wanneer het lichtje "Band Verwisselen" nog brandt.

9. De klok.

De klok is onveranderlijk apparaat nr. 39. Hij werkt onafhankelijk van de AF en heeft drie functies.

9.1. De eigenlijke klok.

Elke 10 msec wordt AR0 (mod 2²⁷) met 1 verhoogd. De cyclus van dit telproces is van de orde van grootte van twee weken. Gelijkzetten van de klok: tandenpoetsen (NLVAF and NLVCA), gelijkzetten, poetsen (NLVAF and LVCA)

9.2. De kookwekker.

Elke 10 msec wordt het adresdeel van AR1 (mod 2¹⁸) met 1 verminderd. Als AR1 hierdoor totaal = + 0 wordt � wordt het tellingdeel van AR1 =000 000 001 gezet en IF:= true, maw. de ingreep van de kookwekker kan plaatsvinden. Wie deze ingreep niet wil hebben, kan hem dus definitief onderdrukken door het tellingdeel van AR1 meteen ≠ 0 te maken. De maximale looptijd van de kookwekker is circa 40 minuten.

9.3. De apparaatwekker.

Elke 10 msec wordt het tellingdeel van AR2 met 1 (mod 512) verminderd. Als het resulterende tellingdeel = 0 wordt en het adresdeel van AR2 = NR ≠ 0 is, dan wordt
1) van het apparaat met apparaatnummer = NR de LVAF = true gezet
2) AR3 in AR2 overgenomen.

Men initieert dit proces door eenmalig AR2 en AR3 met hetzelfde te vullen. Men kan met de apparaatwekker een aangewezen apparaat om de zoveel tijd ergens nota van laten nemen, met een maximum periode van circa vijf seconden, een faciliteit, die in sommige on line toepassingen van interesse is. Door in AR2 bv. + 0 in te vullen schakelt men de apparaatwekker uit.

10. Het aanschakelen van de machine.

Als de machine wordt aangezet, dan komt hij in de toestand, die ook te bereiken is door het indrukken van LS (Laatste Schakelaar) op het wegklapbare gedeelte van het bedieningspaneel. Dit heeft de volgende effecten:

Alle randapparatuur komt in de rode toestand.

Charon komt in zijn rusttoestand en doet niets.

De basismachine komt in de zg. statische stop, dwz. doet ook niets en is zelfs voor het ingreepmechanisme niet ontvankelijk.

De regulerende flipflops hebben na afloop de volgende waarden
IV = true (Ingreep Vergunning)
OV = false (Onderzoek Vergunning)
alle AF = false
alle IF = false
alle LVIF = true
alle LVAF = true (Luister Vergunning AF, interne Charon flipflops)
alle LVCA = false (Luister Vergunning Communicatie Aankondiging, eveneens interne flipflops van Charon)

In deze installatietoestand (en alleen in deze installatietoestand) heeft het indrukken van hetzij IP (Initieel Programma) hetzij NB(Normaal Begin) effect. De bespreking van het effect van de toets NB wordt uitgesteld tot de behandeling van het tandenpoetsen.

10.1 Het Prille Begin.

Het indrukken ven de toets IP heeft tot effect. dat de basismachine overgaat in de dynamische stoptoestand, dwz. hij doet nog steeds niets maar is nu wel voor ingrepen ontvankelijk; daar (zie 10) alle IF�s false zijn, treedt het ingreepmechanisme voorlopig niet in werking. In T wordt de waarde 2¹⁸ - 1 gezet.

Verder wordt Charon gestart in een speciaal programma —genaamd het prille begin— dat via een vaste, installatieafhankelijke bandlezer op een heel speciale manier band gaat lezen.
Op deze band komen woorden voor, als volgt gecodeerd in vier opeenvolgende heptades; de leesrichting is van boven naar beneden, de positie van de sprocket holes is door wat extra ruimte weergegeven. Weer stelt een gat een 1 voor.

       1 d26 d25 d24    d23 d22 d21
     d20 d19 d18 d17    d16 d15 d14
     d13 d12 d11 d1O     d9  d8  d7
      d6  d5  d4  d3     d2  d1  d0

Voor en achter aan de band kieze men een behoorlijk stuk blank. Het leesprogramma skipt eventuele extra blanke heptades voor elk woord; het eerste woord, dat van de band gelezen wordt, wordt ge�nterpreteerd als codewoord, zij het dat de opeenvolgende woordtransporten naar het geheugen nu niet betrekking hebben op enkele heptades naar op hele woorden. Zodra deze startopdracht is afgelopen keert het prille begin terug naar de toestand, waarin het eerst volgende van de band gelezen woord weer als codewoord wordt ge�nterpreteerd.

Het IP-lezen wordt door Charon beeindigd� zodra hij een codewoord bestaande uit louter nullen zou vinden, dwz. op het goede moment de configuratie

          1000 000
          0000 000
          0000 000
          0000 000

Het beeindigen heeft voor Charon ten gevolge� dat hij in de normale rusttoestand ("niets te doen") overgaat(tijdens het IP-lezen was zijn toestand nog wel een beetje bijzonder); de betrokken bandlezer stopt en blijft groen met LVAF = true (poetsen is niet noodzakelijk). Tenslotte zet Charon onafhankelijk van IFT van de bijbehorende bandlezer de IF = true. Tenzij SVA (Stop Volgende Adres) in staat, vindt in de basismachine nu onmiddelijk de normale ingreep plaats via M[24]. (Staat SVA wel in, dan blijft de �ngreep hangen met in de opdrachtteller allemaal enen (2↑18 - 1), totdat de machine wordt doorgestart.)

NB. Aangezien het lezen van het prille begin aan geen enkele vorm van pariteitscontrole is onderworpen� verdient het aanbeveling, met het prille begin niet al te veel meer dan nodig in te lezen.

10.2 De tandenpoetser.

De tandenpoetser is voor alle installaties apparaat nr. 38. Men start de tandenpoetser door (na aanbieding van een startopdracht) zijn AF op true te zetten, hij meldt voltooiing van zijn actie door zijn IF op true te zetten. Dit alles gaat buiten AFT en IFT om, die bij de tendenpoetser niet bestaan. (AR1, AR2 en AR3 worden niet gebruikt door het tandenpoetsprogramma).

Startopdrachten voor de tandenpoetser kunnen niet geketend worden, men plaatst ze stuk voor stuk in AR0. De betekenis van de bits van AR0 is dan:

d26 | t/m d20: |  | alle = 0 | LVCA =: false
|  | niet | alle = 0 | LVCA =: true
d19 | t/m d18: | beide permanent = 0
d17 | t/m d11: |  | alle = 0 | LVAF =: false
|  | niet | alle = 0 | LVAF =: true
d10 | t/m d6: | irrelevant
d5 | t/m d0: | nummer van het te poetsenapparaat.

Het poetsen van een apparaat betekent
1) dat de electronische besturing van het apparaat in de �thuisstand" wordt gebracht
2) dat de LVAF en de LVCA voor dit apparaat gezet worden volgens specificatie van de startopdracht.

De LVAF's en LVCA's zijn interne flipflops van Charon en voor elk apparaat is er zo'n paar. De LVAF (Luister Vergunning AF) bestuurt of Charon een actie zal ondernemen op het true zijn van de bijbehorende AF; de LVCA (Luister Vergunnning Communicatie Aankondiging) bestuurt, of Charon een actie zal ondernemen op de aanwezigheid van de bijbehorende zg. Communicatie Aankondiging (een "synchronisatiesignalering" van het aparaat naar Charon).

Voor de klok moet LVCA true zijn en is de LVAF irrelevant, voor het toetsenbord moeten LVCA en LVAF beide true zijn, voor de tandenpoetser moet LVAF true zijn (laat hem dus zo); voor "normale apparaten" (teleprinterdrukwerk, bandponser� bandlezer� regeldrukker� plotter, trommel) moet LVAF true en LVCA false zijn.

NB. Het tandenpoetsen verzorgt geen initiering van de centrale administraties, dit moet dus rechtstreeks door de basismachine gedaan worden

11. De foutbehandeling.

De foutbehandeling is altijd apparaat nr. 37. De betekenis van de centrale administratie is

AR0: | basisadres centrale administratie eerste fout
AR1 | tellingdeel: IFT
| adresdeel : ongelijk nul
AR2 | ongebruikt
AR3: | basisadres centrale administratie volgende fout.

Zodra in een van de Charonprogramma's een pariteitsfout wordt gesignaleerd bij het aanhalen van een woord uit het geheugen, dan wordt
1) het woord met de foute pariteit in het geheugen teruggeschreven, net zoals het daar werd aangetroffen
2) het heersende Charonprogramma, na LVCA:= LVAF:= false (zodat het tot nader order niet meer actief zal worden) onmiddellijk onderbroken
3) onder meegave van het adres van de AR0 behorende bij het onderbroken Charonverzorgingsprogramma wordt de foutbehandel�ng onmiddellijk gestart door het true maken van de LVCA.

Dit basisadres van de centrale administratie wordt door de foutbehandeling verwerkt als een karakter van het toetsenbord door het toetsenbordprogramma:

if AF and LVAF then AR0:= basisadres else AR3 := basisadres; AF := false;
IFT:= IFT + 1 (mod 512); if 0 < IFT then IFT:= true

De reactie op de ingreep ven de foutbehandeling stelt de besismchine voor een essentiele haastsituatie; bij cumulatie van fouten raakt de basismachine het spoor bijster.

Opmerking. Als er bij de tandenpoetser een pariteitsfout optreedt, is men op LS aangewezen om weer greep op de machine te krijgen!
- - - - - - - - - - - - - - - - - - - -- - - - - - - - - - -- - - - -
Toevoeging en 10.2. Na aanzetten of LS kan men, behalve op IP ook drukken op NB Men forceert dan IF T := 2¹⁸ - 1 van de tandenpoetser true en krijgt een ingreep via M[24].

Transcribed by Martin van der Burgt

Revised 16-Aug-2013

  EWD 150

Tentamenopgave "Cooperating Sequential Processes."

De klanten van een kapper zijn genummerd van 1 t/m N; de integer "N" (evenals de later te noemen integer "M") zij gegeven in het universum, waarin dit programma begrepen moet worden.

De structuur van de samenleving is als volgt:

begin integer array klantsem, rangnummer [1 : N];
      integer kappersem, klantnummer, lopend zwart, lopend blond,
              aantal zwarte wachters, aantal blonde wachters;
         ⋮
         ⋮ (1)
         ⋮
      parbegin
      kapper: begin
        wie volgt: 
                    ⋮
                    ⋮    (2)
                    ⋮
                    ⋮
                   P(kappersem);
                   kapper knipt haren van de klant aangewezen door de waarde
                   van de variabele genaamd klantnummer;
                    ⋮
                    ⋮   (3)
                    ⋮
                    ⋮
                  goto wie volgt
           end;
      klant 1: begin ....................end;
                  ⋮
                  ⋮
                  ⋮
      klant i:   begin
      naar de kapper:
                        ⋮   (4)
                        ⋮
                   P(klantsem[i]);
                   leven van alledag en laat de haren groeien;
                   goto naar de kapper
            end;
                       ⋮
                       ⋮
                       ⋮
      klant N: begin....................end
      parend
end

In (1) moeten de verder benodigde seinpalen en variabelen gedeclareerd worden. Vervolgens moeten de nodige initialisaties worden verricht.

In (2) moet de kapper uitmaken, of hij een volgende klant gaat knippen; zo nee, dan kan hij in "P(kappersem)" opgehouden worden. Gedurende het geknipt worden wordt van de klant geen activiteit gevergd.

In (3) moet de kapper het voltooien van het haarknippen aan de klant in kwestie melden, opdat deze het leven van alledag kan voortzetten.

In (4) meldt de klant zich bij de kapper, hij mag "P(klantsem[i])" pas voltooien, nadat de kapper hem geknipt heeft.

De klanten met nummer van 1 t/m M (< N) hebben zwart haar, zij met nummer van M + 1 t/m N hebben blond haar.

De kapper heeft een grote weerzin regen het overschakelen van het knippen van blonde klanten naar het knippen van zwarte klanten. Hij heeft zich daarom de volgende gedragslijn aangemeten:

Zolang hij ingesteld is op blonde klanten, laat hij de zwarte rustig wachten; hij stelt zich in op het knippen van zwarte klanten zodra
1) er geen blonde klanten meer wachten en bovendien
2) er ten minste 3 zwarte klanten wachten.
Zolang hij is ingesteld op zwarte klanten, laat hij de blonde rustig wachten; hij stelt zich pas in op het knippen van blonde klanten zodra
1) er geen zwarte klanten meer wachten en bovendien
2) er ten minste 1 blonde klant wacht.

De tentaminandi wordt verzocht de in het programma ontbrekende stukken (1), (2), (3) en (4) in te vullen; voor sectie (4) moet een blonde en een zwarte versie gemaakt worden.

Klanten van dezelfde haarkleur worden geholpen in volgorde van binnenkomst, het programma beginnen met de kapper ingesteld op blonde klanten.

De variabelen, die reeds in de declaratie aan het begin van het programma zijn opgenomen, zijn daar ingevoerd om het nakijken van de programma's te vergemakkelijken en kunnen verder als hint voor de oplossing beschouwd worden.

De variabelen "rangnummer[i]" zijn bedoeld om aan te geven, of de i-de klant geknipt moet worden; zo nee, dan zij "rangnummer[i] = 0", zo ja, dan zij "rangnummer[i]" gelijk aan het nummer van binnenkomst van klanten met dezelfde haarkleur. Binnenkomende zwartharige respectievelijk blonde klanten worden haarkleursgewijs geteld door de grootheden "lopend zwart" respectievelijk "lopend blond", beide tellingen te beginnen met 1.

De variabelen "aantal zwarte wachters" zij gelijk aan het aantal zwartharige klanten met "rangnummer[i] > 0".

Om uit een haargroep de langst wachtende klant te bepalen, kiest men uit die groep de klant met minimaal positief rangnummer; de tentaminandus hoeft geen extra moeite te doen om dit zoekproces te versnellen, we mogen bij wijze van spreken aannemen, dat dit zoekproces in het niet valt bij het knippen zelf.

transcribed by Sam Samshuijzen
revised Wed, 19 Jul 2006

EWD155 - 0

Context Dependent Names

Q: "Who is there?"
A: "It is me."

Introduction

Under regrettable circumstances I can truthfully make the statement: "My nose is bleeding.". Having only one nose I have identified the bleeding object considerably better than in a statement such as "My finger is bleeding.", the bleeding nose is even uniquely identified if ..... I were the only person or animal existing. This not being the case, the question "Which nose is bleeding?" can be raised and the proper answer would be "Edsger W.Dijkstra's nose is bleeding.". Having a very rare Christian name I can safely assume that my name identifies my person uniquely in the population of this world, and my second statement then identifies the bleeding nose among the human noses of this world. Of course one can then ask "Which world?" etc. Our conclusion must be that identification is a process of a recursive nature, that names will only identify an object, provided it is known in which context this name is to be understood; in actual fact, each identification stops with the proviso "If you understand what I mean.".

In automatic data processing, particularly in the aspect of it that I have called "Information Management" we are faced with the problem how to identify objects, how to name them and how to keep track of the context in which such a name is to be understood.

A potential way out is to decide, once and for all, upon a universe of discourse, a context in which each object is uniquely identified and to performs the processes in terms of those universal identifications. However, if I have to take care of my bleeding nose, it seems a somewhat roundabout way of doing if I first translate this task into "Take care of the nose of Edsger W.Dijkstra.", the human being is thus identified. On the contrary, taking care of my bleeding nose is an action that I can take, unconscious of the presence of other fellow human beings and irrespective of how I am identified among them.

The problem to be solved is whether we can find a suitable technique for identifying objects with names that will have a meaning in the context in which they occur, without making any assumptions about the total size of the universe in which the process in question happens to be embedded, i.e. by keeping the identification problem at that side open ended.

To be more concrete: I may have two independent programs in both of which occur thirty objects, within each program suitably identified by the numbers (used as names) from 0 through 29. If these programs are sound by themselves, they should without any recoding remain so, when the two programs are executed concurrently in a multiprogrammed machine.

For the time being I shall stress the logical structure of such an identification technique, intentionally disregarding many aspects of efficiency. Once the structure stands clear, we may hope to see, where additional equipment can be used at good advantage.

EWD155 - 1

Starting points.

There is no point in trying to conceal the fact that multiprogrammed systems are one of my major concerns.

Years ago the idea was that each individual user had at his private disposal a von Neumann kind of memory, addressed by positive integers, starting at zero up to a certain limit, that often had to be given a priori.

Embedding many such programs within a single machine consisted of allocating contiguous areas of memory space to each of the programs. The transition from address, as mentioned in the program, to the physical location in store consisted of the addition of a so-called "base address", viz. the starting point of the memory area allotted to the program in question.

Let us review this technique. Its kernel implies that by the process - either from the text as stored within the computer or as a computed intermediate result - a non-negative value is supplied to the selection process, which then establishes (by the addition of the appropriate base address) the identity of the object identified.

I feel a strong urge to try to retain the integers as the kernel of our identification technique. When elements of a set are numbered (from zero onwards) we shall call the integer values with such a specific role of identification within the set "an index".

There are two reasons to try to use indices. The first reason is that from the users point of view they have proved to be extremely useful. If a procedure body starts with the declaration

"real x,y,z"

it is for a translator a trivial renaming to generate for them in order the index values "0", "1" and "2", thus creating an object text that produces indices quite naturally. Arrays and stacks are well-known (and essential!) programming devices, in the use of which the index values are part of the subject matter of the process itself. When keeping the role of the index as central as possible, we may in case of doubt derive comfort from the respectable company of von Neumann and Peano.

The second reason is founded upon the possibility of implementation: modern electronic equipment is remarkably efficient in performing additions. In the following I shall refrain from speculations about large associative memories, and therefore the index controlled selection is taken as the kernel of the identification mechanism. The act of the selection under control of a single index shall be called "a primitive selection".

Such a primitive selection, however, can only be performed provided that it is understood with regard to which population of numbered elements the index value supplied should be used, e.g. provided that the base address to be incremented by the index is known. For lack of a better term I shall call the contents of this understanding "the condition of the primitive selection". The condition of a primitive selection sees to it, that the index supplied to it is related to the proper population.

EWD155 - 2

So we assume indices to be here to stay. Let us now return to the multiprogramming technique described earlier, in which each individual user has a single set of consecutive integers at his disposal, the idea being that each individual user can now program as in a classical von Neumann type memory, starting at address zero and of the appropriate size. To my feeling there is something wrong in this approach. For one thing: the duty to embed the information in a reasonably well filled linear store of ten imposes a considerable burden on the shoulders of the individual programmer. And often each programmer has taken this trouble, the system as a whole is faced with the task to find a sufficiently large consecutive area available for such a program!

In other words: within such a system the condition of the primitive selection -see above- may differ from selection to selection; this facility, however, should not be restricted in purpose to distinguish between indices originated in different programs, but we should try to place this facility also in the hands of the individual programmer.

Locally total selections.

Suppose that a programmer operates upon two integers "i" and "j" and a vector, "k" say, itself of integer elements. The use of an integer value as an index indicating by enclosing it within square brackets, we can rename

"L[0]" for "i",
"L[1]" for "j" and
"L[2]" for "k".

(For the time being the capital letter "L" in front of the square opening bracket can be regarded as a noise symbol.)

In the case "L[0]" or "L[1]" it is clear, that the integer variable named "i" or "j" has to be selected; "k", however, identifies a vector and in order to select an element of this vector, we must supply a second index such as in

"L[2][0]" or "L[2][7]".

If the zeroth and seventh element of the array "k" exist as integers variables, we may assume these integer variables suitably identified by the given successions of two index values.

I regard the processing of such a sequence of index values as a sequential process, for the value of the first index determines, whether the second one is applicable. It is then a succession of two primitive selections, the outcome of the first being nothing else than what we have called earlier "the condition of the next primitive selection".

I do not regard the condition of the next primitive selection as belonging to the subject matter of the process, i.e. the information upon which can be operated at programmer's whim: it can only be used..... to control the next selection.

This forces upon us the recognition that the three primary objects, named "i", "j" and "k" are of vastly different nature.

EWD155 - 3

The first two I call "terminal objects": their value, being integers, is part of the subject matter of the process, when they are selected no next index is permissible.

The last one I call "a non-terminal object": its "value" - in whatever domain expressed - is the condition of a next primitive selection. The selection of a non-terminal object requires a next index value to be supplied (and so on), until a terminal object is reached.

Remark 1. This formalism allows a distinction between the terminal object "L[3]" and the set "L[3]" having "L[3][0]" as its only (terminal) member.

I call a total selection the succession of one or more primitive selections, until a terminal object is reached. To be a little bit more explicit, I shall call them "locally total selections", leaving the question open, whether previous primitive selections are to be understood to condition the selection by the leading index.

Remark 2. I have strong reasons for my refusal to regard "the value of a non-terminal object" -i.e. the condition for a next primitive selection - as part of the subject matter of the process, more in particular as data of which arbitrarily many copies can be made at programmers desire. Within a certain context, the non-terminal object is invariantly identified by the index value (sequence) leading to its selection: within this context its value has only a meaning for the next primitive selection. If we ask, how this value is represented, we ask a question that is meaningless in terms of the subject matter of the process itself, but that can - and must! - have a meaning in the immediately surrounding universe in which this process is embedded: it may contain, say, a base address.

In the surrounding universe, it may be desirable to change the way in which the process is embedded: then one makes changes which are irrelevant to the process itself. On the other hand, such changes will result in updating of non-terminal values. On account of this lack of invariance of meaning, I feel obliged to disallow any uncontrolled copying of non-terminal values.

(Obviously: under the assumption of the declaration "real x,y", the assignment

"x := y"

assigns to the variable "x" the current value of "y", i.e. an object, most explicitly independent of the future history of the variable y: It can be implemented thanks to the eternal existence and invariant representability of numbers.)

The context.

To the implicit conditioning of the selection by the leading index we give the name "the context".

By having different contexts we can attain that the same index values may point to distinct objects, a vital facility.

EWD155 - 4

In the nomenclature used in a program or program part, we may rightly require the "resolving power of the nomenclature" to be sufficient to distinguish between the different objects that this (part of the) program could possibly refer to; it is irrealistic to require a resolving power able to distinguish between all objects ever named, now or in the future. Nevertheless we can view this program as embedded in the collection of all programs being written!

In other words: we allow different programmers to use the same identifications for local usage and if such an identifier is used in more than one meaning, this is an accident of combinatorial nature: the fact that their different programs happen to have been written.

The combinatorial nature of the origin of the need for more than one context is most clearly demonstrated by a closer inspection of the mechanism needs for procedure execution.

Taking for granted the availability of some primitive "whistle", we can write a procedure, "twentywhistle", say, that performs the action "whistle" 20 times in succession:

procedure twentywhistle;
begin integer i; i:= 20;
      while 0 < i do begin whistle; i := i - 1 end
end

We can regard the procedure body as the constant value of the object named "twentywhistle" and we may talk about its life time. Within its life time it can be in action and it will be in action as many times as it is called.

With each call, however, the creation of a new variable "i" must take place, an object that will belong to, and the life time of which will extend over, the execution of "twentywhistle" as a result of this call. At the return, the local variable will be destroyed. In other words, it is the call of twentywhistle (and not its definition) that creates the variable as an object. In general we are bound to do so, as we have no guarantee that the intersection of the different periods of execution of "twentywhistle" will be empty. In multiprogramming, where different sequential processes may invoke the same procedure, such an overlay of execution times may occur by accident; in uniprogramming such an overlay is generated by structure each time a procedure invokes itself, a thing that recursive procedures generally do.

It is very tempting to regard procedure call and procedure return as actions of a very special nature, viz. as actions in which a new context is born and annihilated respectively. The declarations at the beginning of the procedure body are the commands controlling what context will be born.

(Note. I have reasons enough to give the procedure concept a central position in my considerations:
1) in 1962 (An attempt to unify the constituent concepts of serial program execution) I have shown that the most natural conception of a variable is a procedure that upon call produces the value assigned to it.
2) in the multirunning system we are constructing at present, the status of a user program is that of an (anonymous) procedure, whose body is defined during "load" and that is called at "go".
The procedure concept thus covers a wide spectrum!)

EWD155 - 5

Context Identification

0. Introduction.

We, i.e. somewhat external observers, can take a snapshot of the full program status somewhere in the middle of its execution, say when the program has called procedure A, which has called procedure B which has called procedure C. We can then observe the existence of four different contexts: the one that was the current one before A was called and that will be restored to this status after A's completion, and those belonging to the activations of A, B and C. (Note: If A happens to call itself, e.g. when C = A, we can still distinguish four different contexts!)

On account of their nicely nested lifetimes they can conveniently be identified with the elements of a stack; thus giving the outer context the index value "0", the one belonging to A the value "1", the one belonging to B the value "2" and the one belonging to C the value "3".

Let us call this "the stack of activations"; upon procedure entry an element is added to it, upon return its top element is unstacked.

Such a stack of activations becomes an object associated with a single sequential process. In a multiprogramming system one could consider a single "activation list" for the union of all activations of all programs running in the system. The objects -i.e. activations- will then no longer have nicely nested life times, but something could be done about that, e.g. giving to each new activation the lowest free index available. I most emphatically propose not to do so: creation of a new context implies then the analysis what index should be used for its identification in the total "activation list", and as a result concurrent context creations would have to exclude each other mutually in time. We could also remark that the introduction of the different stacks (one for each sequential process) is nothing more than the creation of a terminology that exploits nicely the life time relations as far as they are present; essentially this is the same argument.

It may be clarifying to inspect the consequences of the parallel processing as described in "Cooperating Sequential Processes", where the different constituent statements of a so-called "parallel compound" are activated in parallel and should be executed concurrently. Instead of a single element to be stacked as in the case of the procedure call, a number of elements have to be stacked together; associated with these elements is not a context (as in the case of a procedure call) but a new stack of activations, viz. one for each of the constituent parts of the parallel compound. We shall return to this in greater detail below.

Now a number of questions should be raised (and answered in some sense) e.g. "Why do we want to identify contexts by indices" and "Of what nature will the value be to be found in the activation stack?'. To that last question we can give our usual vague answer "It will be the condition of the next primitive selection."

The need to identify them becomes apparent if we pay attention to the parameter mechanism, for instance the ever present implicit parameter: the return information. One of the parameters of a procedure shall be what context to restore to its status of "the current one" upon return!

EWD155 - 6

1. The Stack of Activations.

In a single sequential process our activations have nested lifetimes and we can assume the values specifying the corresponding contexts to be stacked.

To my taste the difference between a stack and a push down store is that in the push down store accessibility is by definition restricted to the top element, whereas in a stack, interior elements may be accessed. That is, we regard a stack as a vector with a moving upper bound

"array stack[0 : MI]"

(where MI stands for "Maximum Index") in which terminology "to stack" can be expressed as

"MI := MI + 1; stack[MI] := "element to be stacked".

Thus we ensure that each stack element is uniquely identified "within the stack and during its lifetime" by the index value giving its distance from the stack bottom.

If an expression to be interpreted under the current context is to be handed over as a parameter to a procedure with the effect that its actual interpretation will take place at a stage where the context relevant to the parameter is no longer the current one - but at that stage may be deep down the stack - then the context can be identified by its index values in the stack of activations: this is invariant identification in contrast to its distance from the then current top of the stack.

Within the program, the actual value of MI is without any meaning! The only operations in which MI plays a role are increase of it, decrease of it and selection under control of it or under control of a copy of an earlier value. It are these operations that have a meaning within the program, the interpretation of the values, identifying contexts, falls outside the scope of the context itself. It is like making with you an appointment for "tomorrow": I request you to increase the current date by 1, it is irrelevant whether you translate this in terms of the Julian or the Chinese calendar; I may process this appointment without calendar, such as children do "after one night sleeping".

During specification of parameter, at entering into or returning from procedures, the process has to operate secundum regulas artis upon the MI, associated with the implicitly understood stack of activations. The copies made from such MI values will only be used (to be copied or) to control the selection of the contexts. Such an MI is not a local variable of the process, it is a variable in whose value the process dutifully reports its behavior.

I regard the MI, i.e. the stack length as part of the condition under control of which an element of this stack can be selected, because it gives the upper bound of the index values that can be processed by the next primitive selection.

EWD155 - 7

2. The Tree of Activations.

Within a sequential process including procedural processing a stack of activations is implicitly understood. We shall now try to visualize the entrance of an n-fold parallel compound.

The n new elements will be added (simultaneously) to the current stack of activations, each for one of the parallel statements; when the execution of the n parallel statements have all been completed, the n elements will be removed together and the stack of activations from which they have been removed will return to its former status of "the current one".

Upon creation each of the n elements will get as value the condition for selection in a new stack, that also will be created (either empty or suitably initialized). The n stacks thus created will act as the current stack of activations for the n different parallel statements. The n different stacks to be implicitly understood during the activity of the parallel compound are thus elements with an identity within the stack from which they blossomed out; the actual index values by which each stack is identified depends on the momentaneous filling of the "mother stack" at the moment that the parallel compound has to be entered.

For the interpretation of the n parallel constituents of the compound - i.e. the sequence of primitive selections to be performed before the appropriate context is identified and the next primitive selection suitably conditioned - one primitive selection more than before blossoming must be done: if before the entrance of the parallel compound a sequence of DC index values was sufficient to identify the current context within the universe, then now DC+1 index values will be needed.

This DC is a variable, gravely analogous to MI ("DC" being short for "Depth Counter"). During the lifetime of a stack of activations a constant DC-value is associated with it; the stacks created upon entry of a parallel compound will all have a DC-value associated with them that is one higher. The actual value of DC depends on the distance from the root of the universe, but inside the processes this value is as meaningless as the distance of the bottom of the stack.

In the previous section we have shown that as long as we have one sequential process, the current MI value will be sufficient to identify this context for further reference. If on top of this context parallel blossoming occurs, we do no longer know, to which stack of activations the fixed MI value refers. This problem is now solved by identifying the current context by a combination of the current values of MI and DC.

Thus we have achieved that contexts can identify themselves in a terminology independent of the size, complexity and total hierarchical structure of the universe in which they are to be understood.

Transcribed by Mikhail Esteves.

Last revised on Wed, 30 Jul 2003.

EWD157

Over de sequenti‘le interpretatie van een ponsband.

HEP

Als fundamentele bouwsteen beschouw ik de integer procedure, die ik HEP noem. Bij het lezen van n-gats band levert hij in eerste instantie een van 21n mogelijke waarden af, nl van en met 0 (voor blank tape) tot en met 21n-1 (voor all holes) en wel steeds de waarde die overeenkomt met de volgende n-ade.

Hoe we aan de band komen is een onderdeel van de initialisering van HEP, waarover ik me liever niet wilde uitlaten. Ik neem dus aan, dat we weten, over welke band we het hebben. Die kunnen we dan n-ade voor n÷ade aftasten: die band kan dan wel opraken!

De vraag rijst direct, hoe HEP moet reageren, als "einde band" gedetecteerd wordt.

Mijn voorstel is om het arsenaal van mogelijke, door HEP af te leveren waarden uit te breiden met een speciale waarde (ik denk aan 511 of -1), die "EINDE BAND" zal betekenen. Het is dan aan het programma om vast te stellen, of het nu genoeg gelezen heeft; zo nee, dat zal HEP opnieuw geinitialiseerd moeten worden (band aanvragen).

Onmiddellijk rijst de vraag, hoe HEP reageert, als nadat "EINDE BAND" als waarde is afgeleverd, HEP weer wordt aangeroepen, voordat de volgende initialisatie heeft plaatsgehad.

Nu kunnen we drie kanten uit.

we kunnen dit interpreteren als letaal deraillement van het programma

we kunnen dit interpreteren als de indicatie, dat er dus blijkbaar meer informatie gevraagd wordt en als onderdeel van HEP impliciet de initieringsriten plegen (om nieuwe band vragen etc.)

we kunnen weer "EINDE BAND" afleveren.

Omdat ik HEP bechouw als mijn meest fundamentele bouwsteen prefereer ik het laatste; het maakt het gebruik van HEP mogelijk zonder na elke aanroep te inspecteren, of "EINDE BAND" soms voorkwam "X:= HEP * HEP" kan nu. Een band wordt nu een halfrechte, oneindig lang in de toekomst, vanaf een zeker moment komen er alleen maar "EINDE BAND"'s op voor.

De routine HEP is van toepassing, als we als band willen verwerken, bv. de output van een registrerend meetapparaat. De rest van deze notitie beschouwt de inhoud van de ponsband als derivaat van een paginabeeld: hier ligt een code aan ten grondslag, bv. telexcode of FLEXOWRITER code.

CHAR

In het volgende zal ik een en ander toelichten aan de hand van Flexowriter code; voor telexcode is een analoge beschouwing te houden, zolang er geen losse carriage returns zonder line feed gegeven worden.

En ik moet me zelfs beperken tot een vrij speciale Flexowriter: een Flexowriter met vaste spatiering, zonder backspace waarbij de tabulatorstoppen op vaste posities staan. (En dit apparaat zullen wij zelfs nog iets moetfin idealiseren: over de minimum afstand, waarin de tabulatie "het nog haalt", bv. 1 niet, twee wel, moetem we een vaste afspraak maken.)

CHAR nu is een routine, die zich interesseert voor het paginabeeld: het is de functie van CHAR om bij het aftasten van een band een verslaglegging te doen, die een÷eenduidig is toegevoegd aan het met de band corresponderende paginabeeld.

Ik stel me bij de definitie van het paginabeeld op het standpunt, dat

meervoudige underlining niet van enkelvoudige underlining is te onderscheiden

UHX meervoudige "stroking" niet van enkelvoudige "stroking" is te onderscheiden

dat de op de wagen ingestelde afstand van de regelopvoer niet tot het paqinabeeld behoort, een extra regel blank wel

dat op het papier de plaats van de linker kantlijn bekend is (wie elke regel begint met een extra spatie fokt een ander paginabeeld)

Ik stel me voor, dat CHAR bij herhaald aanroepen dit verslag zal afleggen, daarbij het paginabeeld regel voor regel verslaand (in volgorde van boven naar beneden) en elke regel op zichzelf van links naar rechts.

Over de wijze van verslaglegging door CHAR zuJlen we enige conventies moeten treffen.

Ik stel me voor, dat CHAR niet elke regel met spaties tot een vaste maximum lengte hoeft aan te vullen, maar in plaats daarvan NLCR wel tot de output van CHAR te laten behoren; CHAR heeft dan wel de plicht om eventuele TABS en 5PATIES aan het einde van de regel te onderdrukken.

Voor de verwerking van de TAB's stel ik voor ze te vertalen in een aequivalent aantal spaties: op deze wijze geeft een reeks CHAR-waarden zonder NLCR een beeld, dat invariant is voor zijn plaats op de reqel. Wel zal CHAR voor het bepalen van deze aequivalentie de wagenpositie moeten bijhouden.

Wat betreft de underlining en de stroking kunnen we verschillende wegen bewandelen.

elke "zichtbare, transporterende ponsing" bestaat in vier versies, al af niet met underlining, al of niet met stroking

een aanroep van CHAR kan wel "underlining" en "stroking" separaat doormelden. In dit geval moet, om der wille van de eenduidigheid een vaste afspraak gemaakt worden over de volgorde, waarin deze door CHAR worden doorgemeld (bv, eerst de underlining, dan de stroke en dan het transporterende karakter).

Omdat CHAR dan toch verder moet kijken dan zijn neus lang is, prefereer ik de eerste mogelijkheid. Deze heeft de voordelen, dat

we van de willekeurige afspraak over de volgorde verlost zijn

nu met elke aanroep van CHAR een positieverplaatsing van de wagen correspondeert.

CHAR heeft de eigenschap, dat mist de code bekend is, elke produceerbare band gelezen kan worden en over elke produceerbare pagina een uniek verslag wordt afgelegd.

Een willekeurige Flexowriterpaqina is niet als willekeurige Telexpagina te interpreteren, noch omgekeerd. Ik stel daarom voor, om de codeonafhankelijke CHAR af te schaffen en zoveel CHAR's in te voeren, als we codes (i.e. apparaten) hebben. Dus CHARF voor de verslaglegging over een Flexowriterpagina en CHART over de verslaglegging over een Telexpagina. (En. Wie naast de beschreven Flexowriter ook een Flexowriter met variabele spatiering etc. wil kunnen bespelen, zal daarvoor een andere CHARF, zeg CHARFV, moeten maken.)

De toevoeging van de integerreeks, die CHARF aan een Flexowriterpagina toekent heeft niets te maken met de integerreeks, die CHART aan een telexpagina toekent, Ik beschouw op dit niveau Flexowriterpagina en Telexpaginas nl. als onvergelijkbare voorwerpen.

Kijk, CHARF mag twee Flexowriters, die alleen daarin verschillen, dat de ene een recbt lettertype en de ander een cursief lettertype heeft, als aenquivalent beschouwen (mits natuurlijk beide lettertypes het zelfde onderscheidende vermogen -zoals verschil tussen de letter O en het cijfer 0 hebben).

CHART mag twee teleprinters met de ALCOR symbolen als aequivalent beschouwen, ook al heeft de ene alphabet van kleine letters en de andere een alpnabet wan hoofdletters .

CHARF en CHART leggen verslag af over het paginabeeld en moeten elke paqina, die op het betrokken apparaat vervvaardigbaar is, uniek verslaan; dit heeft nog niets te maken met ALGOL basic symbols! Er is een aparte beslissing nodig om de Flexowriter "A" resp. "a" op papier te gebruiken als afbeelding van het basic symbol "A" resp. "a". Evenzo zal apart beslist moeten worden, dat het telexcharacter, dat verdacht veel lijkt op een van de gebruikelijke afbeeldingen ven de eerste letter van het alphabet, ge•dentificeerd kan worden met hetzij het ALGOL basic symbol "A", dan wel het ALGOL basic symbol "a". Hoe deze beslissing uitvalt is een kwestie, die helemaal los staat van het feit, of teleprinters meestal met kleine, dan wel meestal met hoofdletters zijn uitgerust!

Ik zou mij kunnen voorstellen, dat het practisch zal blijken om het bereik van CHARF en dat van CHART een lege doorsnede te geven!

HEP is het aangewezen inspectiemiddel, als de programmeur in het bandbeeld ge•nteresseerd is, CHARF en CHART zijn de aangewezen inspectiemiddelen, als dp programmeur in het paginabeeld ge•nteresseerd is. Een programmeur, die, bij wijze van spreken in manuscript een ALGOL÷programma aanbiedt, is niet in het bandbeeld geinteresseerd, noch in de verwerking van het paginabeeld: zijn manuscript heeft in zijn prive-hardware representatie (nl. zijn handschrift en notatieconventies) een reeks basic symbols van ALGOL 60 en hij verwacht van de ponskamer (ik zou hier nog liever willen "typekamer"), dat deze reeks basic symbols op een van de voorhanden zijnde paginabeeldmakers (Flexowriters of teleprinters) wordt afgebeeld in overeenstemming met de specifieke regels, die voor elk van deze apparaten met in acht name van hun beeldend vermogen gekozen zijn. Wie aldus een text heeft aangeboden, mag niet protesteren als waar hij "Boolean" heeft geschreven, hij "boolean" on zijn papier vindt, tenminste niet, wanneer het laatste een van de volgens afspraak toelaatbare representaties is van het basic symbol, dat vermoedelijk bedoeld is. Was het niet zijn bedoeling om een ALGOL programma aan te bieden, maar een op een Flexowriter produceerbare text, dan is een dergelijke vrijheid natuurlijk niet veroorloofd (en waarschijnlijk doet hij er dan beter aan om zelf zijn tekst te Flexowriteren).

Fungeert het paginabeeld slechts als "carrier" voor een reeks ALGOL basic symbols, dan is het aangewezen inspectiemiddel een integer procedure "SYM". Het waardebereik van SYM heeft niets te maken met dat van CHARF en CHART, het onderscheidt waarschijnlijk alle basic symbols van ALGOL 60 (met uitzondering van het overbodige wordtteken?) en waarschijnlijk nog wel wat meer, NLCR bv.

SYM is een integer procedure, die heel nadrukkelijk slechts in enkelvoud staat; dus geen 5YMF of 5YMT.

Het afzondelijke bestaan van CHARF en CHART is gerechtvaardigd omdat wij hiermee paginabeelden kunnen aftasten, vervaardigd op apparaten met heel verschillende (Onvergelijkbare) beeldende vermogens. CHARF en CHART fungeren als optische aftasters; dat de facto de machine via een bandbeeld toegang tot het paginabeeld krijgt, is een omstandigheid, waarvan bij het gebruik van CHARF en CHART geheel geabstraheerd is, evenals van het feit, dat het feitelijke bandbeeld, dat slechts als "carrier" voor het paginabeeld fungeert, door het laatste niet eenduidig bepaald is. Aan deze abstractie ontlenen CHARF en CHART juist hun bruikbaarheid. De toevoeging van paginabeeld aan bandbeeld is bepaald door de eigenschappen van de respectievelijke apparaten.

Bij het gebruik van SYM fungeert, zoals gezegd, het paginabeeld op zijn beurt als carrier voor een reeks ALGOL basic symbols; de toevoeging van deze reeks aan een paginabeeld is nu bepaald door de conventies van de typekamer. Zoals CHARF en CHART abstraheren van het niet eenduidiq bepaalde bandbeeld, Zo abstraheert SYM van het niet eenduidig bepaalde paqinabeeld. Het is deze abstractie, waaraan SYM zijn enorme bruikbaarheid ontleent; het is deze abstractie, die de programmeur ontheft van de plicht het paqinabeeld aanslag voor aanslag, (spatie voor spatie!) te preciseren, het is tevens deze abstractie, die de ponskamer de vrijheid geeft in de keuze van het ponsapparaat en de layout.

Alle genoemde routines hebben hun stilzwijgend veronderstelde "own variables". Voor HEP is dit, waar welke band wordt afgetast, voor CHARF en CHAHT zijn dit de heersende case shift, de wagenpositie etc, voor SYM is dit onder meer de heersende code, dwz. of hij via CHARF, dan wel CHART moet werken. Omdat de afbeeldingsregels voor basic symbols op een pagina apparaatafhankelijk zijn, in deze heersende code de statusvariabele van SYM; dit in dan ook de reden, waarom ik CHAR heb afgeschaft.

Boven gegeven uitweidingen zijn de vrucht van een mislukking. Toen ik HEP, CHARF en CHART qeconcipieerd had, ben ik gaan denken over wat men doen moet, als een programma, na via, zeg, CHARF een stuk band gelezen te hebben, via HEP een stukje doorleest, om daarna desnoods via CHARF weer door te kunnen lezen. Een vraag, die opkomt, zolang men CHARF beschouwt als een speciale manier van bandlezen, een vraag, die zinloos wordt, zodra men CHARF beschouwt als een mechanisme tot paginaaftasting. Zolang men CHARF beschouwt als een speciale manier van bandlezen en dus probeert om aan de alternering van CHARF en HEP een betekenis toe te kennen, duiken er allerlei vieze problemen op, waarvoor ik geen overtuigende oplossing heb kunnen vinden. Ik heb nog geprobeerd om naast HEP een "HEPF" en een "HFPT" in te voeren, die de plicht zouden hebben, voor CHARF, resp CHART de passerende heptade aan te kijken en de relevante updating van de statusinformatie van CHARF resp. CHART te verrichten. Nou, dit is mislukt, speciaal omdat er geen duidelijke manier is om de beide sequenti‘le processen -het aftasten van een band en het aftasten van een uit deze band afgeleid paginabeeld-, hoewel ze macroscopisch gezien wel synchroon lopen (het begin van de band komt overeen met het begin van het paginabeeld, microscopisch door een zinvolle (dwz. hanteerbare) conventie te synchroniseren. Ik kom dan ook tot de conclusie, dat het gemengde gebruik van HEP en CHAR een hinken op twee gedachten is, waarin je met de ene hand probeert terug te nemen, wat je met de andere gegeven hebt (nl. dat het preciese bandbeeld er niet toe doet). Ten aanzien van dit gemengde gebruik zou ik dan ook het standpunt willen innemen: of verbieden (en de implementatie hierop laten testen) of er bij zeggen, dat het undefined is, en dat de gebruiker wilde reacties mag verwachten, onder het motto "What else do you expect?".

transcribed by Jan Berend Dusink
revised Mon, 25 Oct 2010

EWD158

Tentamenopgave "Cooperating Sequential Processes"

april 1966

In elk van vijf cyclische processen (resp. genaamd "A", "B", "C", "D" en "E") komt een critische sectie voor (resp. genaamd "TA", "TB", "TC", "TD" en "TE"). Zij zijn critisch in de zin, det voor hun uitvoeringstijden vijf wederzijdse uitsluitingarelaties gegarandeerd moeten worden:

1) het gelijktijdig in uitvoering zijn van TA en TB is verboden
2) het gelijktijdig in uitvoering zijn van TB en TC is verboden
3) het gelijktijdig in uitvoering zijn van TC en TD is verboden
4) het gelijktijdig in uitvoering zijn van TD en TE is verboden
5) het gelijktijdig in uitvoering zijn van TE en TA is verboden.

De cyclische processen worden buiten hun critische sectie gestart; zolang een proces bij de ingang van zijn critische sectie moet wachten, mag dit voor geen van de overige processen een blijvend beletsel vormen om hun critische sectie binnen te gaan.

De structuur van proces A is als volgt:

A: begin

start: niet critische sectie A;

.

.

.

. (1A)

.

.

TA;

.

.

.

. (2A)

.

.

goto start

end

De structuur van de overige processen is analoog.

De stukken 1A, 2A, 1B, 2B, 1C, 2C, 1D, 2D, 1E en 2E, benevens het omvattende blok moeten worden ingevuld.

De tentaminandi wordt verzocht slechts eenzijdig beschreven papier in te leveren.

transcribed by Carl Ludwigson
revised 12-Nov-2014

EWD161

Sequentiele interpretatie van ponsband.

Dit rapport handelt over de structuur en onderlinge samenhang van vier procedures (of proceduretypen):

integer procedure HEP |  | voor het aftasten van ponsband
integerproceduretype CHAR |  | voor het aftasten va een paginabeeld
integer procedure SYM |  | voor het aftasten van een rij basic                      symbols
real procedure NUM |  | voor het aftasten van een rij numerieke                      waarden.

Van het type CHAR beschouwen we er twee, zeg CHARF en CHART voor het aftasten ven een paginabeeld van flexowriter resp. teleprinter; de uitbreiding naar meer dan twee verschillende CHAR’s ligt voor de hand. We gaan voorbij aan het feit, dat het paginabeeldend vermogen van de teleprinter toevallig bijna geheel vervat is in dat van de flexowriter en beschouwen dus hun respectievelijke paginabeeldende vermogens als volslagen verschillend.

Als een routine van het type CHAR een band van het betrokken apparaat te verwerken krijgt, zal deze bij herhaald aanroepen een waardenreeks afleveren, die uniek verslag aflegt over het bij deze band behorende paginabeeld en wel regel voor regel, elke regel van links naar rechts. Het zijn de routines van het type CHAR� waarin de eigenschappen van de diverse hardware ponser/bladschrijvers hun neerslag vinden. Over deze eigenschappen worden twee veronderstellingen gemaakt

a)         We veronderstellen dat het hardware apparaat beschikt over enige geheugenelementen, waarvan de beginwaarde (het begin van) het paginabeeld mede kunnen bepalen, dat aan een band ontleend wordt. Wij noemen heersende case, wagenpositie etc. Hieraan beantwoordt, dat elke routine van het type CHAR, voordat hij over een paginabeeld een verslag kan gaan afleggen geactualiseerd (ge�nitialiseerd) moet worden, waarbij deze mechanische geheugenelementen een bij de actualisering opgegeven beginwaarde toegedacht krijgen. Na actualisering verslaat CHAR het paginabeeld, dat ontstaat wanneer

| 1) | het apparaat in de toestand gebracht zou worden zoals bij de actualisering van CHAR opgegeven
| 2) | de band ingelegd wordt met de eerste heptade die door CHAR via HEP gelezen gaat worden in het leesstation van het apparaat in kwestie.

b)        we veronderstellen de door de hardware van de ponser/bladschrijver gegeven code zo ingewikkeld, dat in het algemeen geen natuurlijke synchronisatie tussen pagina— en bandbeeld bestaat, maw. dat als het verslag van CHAR tot een bepaald punt op de pagina gevorderd is, het plotseling doorlezen van de band via HEP op een in het algemeen ongedefinieerd moment inhaakt.

Is het gebruik van CHARF en CHART —door de complexiteit van de apparatuur en door niets anders!— aan enige beperkende regels onderworpen, verder beogen we de grootst mogelijke algemeenheid. (Als een implementator voor sommige hieronder te noemen mogelijkheden geen emplooi ziet en ze weglaat, dan is dat zijn zaak: ik betrek ze in het beeld, om dan de weg tot latere toevoeging open te houden.)

De routine SYM kan op drie manieren aan een band een rij basic symbols ontlenen

| 1) | een rij basic symbols gedefinieerd op een flexowriterpaginabeeld; SYM zal dan via CHARF de band aftasten, dit interpretatieproces noemen we “symcharf”.
| 2) | een rij basic symbols gedefinieerd op een teleprinterpaginebeeld; SYM zal dan via CHART de band aftasten, dit interpretaieproces noemen we “symchart”.
| 3) | een rij basic symbols� zonder tussenkomst van een paginabeeld direct op het bandbeeld gedefinieerd; SYM zal dan via HEP de band aftasten, dit interpretatieproces noemen we “symhep”.

In het bijzonder zullen we eisen, dat indien via SYM een reeks basic symbols van een band gelezen wordt, tussentijdse wisselingen tussen de drie interpretatieprocessen zijn toegestaan, zonder dat het SYM aanroepende programma hier enige zorg mee heeft. Dit impliceert
1)      dat in een ALGOL tussen te voegen teksten van standaardprocedures een soort binaire banden zouden kunnen zijn, die SYM via symhep zou kunnen lezen
2)      dat een programma, dat in teleprintercode wordt aangeboden, van een omvattend blok kan worden voorzien door er een stukje flexowritertekst voor- en achteraan te plakken.

Evenzo laten wij voor NUM vier verschillende manieren open, waarin hij aan een band numerieke waarden ontleent
1)       numerieke waarden, gedefinieerd op een rij basic symbols. NUM zal dan via SYM de band aftasten, wij noemen dit interpretatieproces “numsym”. (Bij activiteit van numsym doet het niet ter zake of SYM via symcharf� symchart of symhep werkt.)
2)       numerieke waarden gedefinieerd op een flexowriterpaginabeeld; NUM zal dan via CHARF de band aftasten, wij noemen dit interpretatieproces “numcharf”. (NB. Hierbij kunnen paginabeelden verwerkt worden, die niet als representatie van basic symbols beschouwd kunnen worden, bv. octale getallen met onderstreepte cijfers of zo.)
3)       numerieke waarden gedefinieerd op een teleprinterpagina; NUM zal dan via CHART de band aftasten, wij noemen dit interpretatieproces “numchart”.
4)       numerieke waarden, zonder tussenkomst van basic symbols of paginabeeld� direct gedefinieerd op een bandbeeld; NUM zal dan via HEP de band aftasten, dit interpretatieproces noemen we “numhep”. (Op deze wijze zouden binaire voorstellingen direct van een band gehaald kunnen worden.)

Wederom moet een programma vele malen NUM kunnen aanroepen, ongeacht de wisselingen tussen deze vier wijzen van getalopbouw.

Behalve dat gemengde toegankelijkheid van een van de paginabeelden of het bandbeeld elkaar uitsluiten, proberen we zo liberaal mogelijk te zijn. In het bijzonder:

a)       Alternering tussen SYM en CHARF (CHART resp. HEP) is definieerbaar mits SYM werkt volgens symcharf (symchart resp. symhep).

b)       Alternering tussen NUM on CHARF (CHART resp. HEP) is definieerbaar

| 1) | als NUM werkt volgens numcharf (numchart resp. numhep)
| 2) | als NUM werkt volgens numsym en SYM voldoet aan voorwaarde a).

c)       Alternering tussen NUM en SYM is definieerbaar

| 1) | als NUM werkt volgens numsym (aan de werkwijze van SYM is dan geen beperking opgelegd)
| 2) | als NUM werkt volgens numcharf (numchart resp. numhep) en SYM werkt volgens symcharf (symchart resp; symhep}.

We observeren, dat er drie elkaar uitsluitende basisinterpretaties aan de gang kunnen zijn; welke van de drie vigeert leggen we vast in de waarde van een aan de informatiestroom toegevoegde integer statusvariabele “basint”.

basint = 1 | de informatie is gedefinieerd op een bandbeeld� dat niet uitgelegd wordt als carrier van een paginabeeld (symhep� numhep en algemeen HEP toegestaan, CHARF en CHART niet van toepassing)
basint = 2 | CHARF actueel, dwz. het bandbeeld fungeert alleen als carrier van een flexowriterpagina� alleen CHARF van toepassing (en HEP alleen vanuit CHARF).
basint = 3 | CHART actueel. dwz. het bandbeeld fungeert alleen als carrier van een teleprinterpagina, alleen CHART van toepassing (en HEP alleen vanuit CHART).

De statusinteger basint kent nog een vierde waarde

basint = 0
geen van de drie genoemde interpretaties vigeert; in het bijzonder, als in deze toestand informatie van de band moet komen, die alternatief op teleprinterpagina, flexowriterpagina, dan wel direct op bandbeeld gedefinieerd kan zijn, dan zal de aanhef van het dan te lezen bandstuk duidelijk moeten maken, of basint de waarde 1, 2 of 3 moet krijgen.

De routine HEP.

Nadat deze geinitialiseerd is —dwz. de band is ingelegd— geeft de integer procedure HEP per aanroep de volgende n-ade van de band. Op “EINDE BAND” reageert hi door totaan de volgende initialisering de waarde “–1” af te leveren. De routine HEP berekent bij herhaald aanroepen een functie gedefinieerd op het mathematisch model, dat ik voor een eindige ponsband heb gekozen: een (in de toekomst) oneindige halfrij “heptaden�� die voor een zeker moment niet en na dat moment louter de karakteristieke waarde “–1” bevat en aflevert. Voor dit model pleite
1)       dat de oneindigheid de mathematische hanteerbaarheid van HEP alleen maar ten goede kan komen
2)       dat een mogelijk relevant aspect van de werkelijkheid (nl. einde band) hierin zijn representatie vindt.

(Ik ben me bewust, dat andere mogelijk relevante aspecten van de werkelijkheid onder tafel zijn geraakt. De breedte van het papier zou men kunnen willen gebruiken ter bepaling van de keuze tussen alternatieve codes; de kleur van het papier of het fabrieksnummer van de flexowriter� waarop een band geponst is, zou men bij het optreden van lees— of ponsfouten voor diagnostische doeleinden misschien willen weten!)

Vooralsnog zie ik geen noodzaak om HEP “een voorgift” te kunnen geven. Mocht deze noodzaak optreden, dan moet een verstandige keuze gemaakt worden tussen de bijna aequivalente mogelijkheden, die naar aanleiding van CHAR nog ter sprake zullen komen.

De routines van het type CHAR.

Deze sectie behandelt alleen CHARF� omdat ik met de teleprinter onvoldoende op de hoogte ben en ik mij, vanwege onbekendheid met standaardpraktijken in het telexverkeer� nauwelijks bevoegd acht om hier aanbevelingen te doen.

De routine CHARF die ik op het oog heb heeft betrekking op een MC-flexowriter zonder variabele spatiering� zonder backspace� met vaste instelling van de regel- opvoer en vaste spatiering van de tabulatorstoppen.

Initialisering van CHARF geschiedt onder opgave van twee parameters, de boolean “lower case” en de integer “carriage position”� die bij het begin van de regel op 0 gesteld wordt. Daarna levert CHARF per aanroep het verslag van het paginabeeld en wel per positie op de pagina. (Elke “escaping” aanslag wordt verslagen in viervoud als hij caseonafhankelijk is (dwz. de spatie) en in achtvoud als hij caseafhankelijk is, nl. al of niet onderstreept en al of niet doorgestreept). Bij het waardebereik van CHARF is tevens NLCR —dwz. overgang op een nieuwe regel— begrepen, TAB’s worden vertaald in een aequivalent aantal spaties, spaties en TAB’s aan het einde van de regel worden vanwege hun onzichtbaarheid niet doorgegeven.

We kunnen (zie boven) bv— basic symbols hetzij op een Flexowriterpagina� hetzij op een teleprinterpagina definieren en we hebben geeist van bv. een routine als SYM, dat hij achter de schermen van de ene code op de andere kan overgaan.

Deze overgangen moeten door de band gestuurd worden. Van elke routine van type CHAR stel ik me voor, dat er een karakteristieke (zelfafsluitende) ponsing (of ponscombinatie) is, die behelst, dat hiermee de heersende interpretatie tot nader order is afgelopen. Voor de procedure CHARF stelde ik me voor hiervoor de stopcode in de betekenis “EINDE CODE” te gebruiken.

Omdat ik voor routines, die in termen van CHARF werken zeer zeker wil toestaan dat ze niet zelfafsluitende eenheden van de pagina lezen, zal CHARF wel een voorgift van een enkele waarde kunnen hebben.

Voor de routine CHARF doemt de volgende rol op.

De toestand “CHARF actueel” —dwz. basint = 2— kan slechts bewerkstelligd worden door de aanroep van een initialiseringsnrocedure� waarbij de statusvariabelen van CHARF (te weten “heersende case” en “Waqenpositie”) worden opgegeven. Door de initialiserinqsprocedure wordt de voorgift ingesteld op “leeg”.

Het geven van een voorgift zou op twee manieren kunnen

1) | door het parameterloze commando “herhaal bij eerstvolgende aanroep de laatst afgeleverde waarde eerst nog een keer”
2) | door het parameterhebbende commando “geef bij eerstvolgende aanroep eerst de hierbij opgegeven waarde”.

Omdat de tweede methode wat flexibeler is �en de eerste bovendien slecht gedefinieerd is onmiddellijk na initialisatie� prefereer ik de tweede versie.

Indien aan CHARF een voorgift gegeven wordt op een moment, dat CHARF niet actueel is, heeft deze handeling geen effect.

Indien aan CHARF een voorgift gegeven wordt, terwijl een nog niet teruggegeven voorgift hing, dan overschrijft de laatste voorgift de eerste.

Een neveneffect van CHARF zal moeten zijn� om naar aanleiding van het ontmoeten van de stopcode de toestand “basint = 2” (dwz. CHARF’s actualiteit) te beeindigen, Precieser: evenzo als CHARF onzichtbare spaties aan het einde van de regel niet doorgeeft, zal CHARF ook onzichtbare NLCL’s niet doormelden� wanneer uiteindelijk een stopcode op de band gevonden wordt. Het optreden van de stopcode wordt aan het aanroepend programma doorgegeven, doordat CHARF met de waarde “–1” terugkeert, nu in de betekenis “EINDE CODE”. Indien CHARF wordt aangeroepen tijdens “basint =: 2” en hij keert terug met de waarde “–1”, dan heeft dit “basint:=0” als neveneffect. (Dit geldt ook, als deze –1 uit de voorgift komt; hiermee is dus een manier gegeven om CHARF, als hij actueel mocht zijn� zijn actualiteit te laten beeindigen.) Als CHARF wordt aangeroepen tijdens “basint ≠ 2 � dan keert de besturing eveneens terug met CHARF = –1, doch ditmaal zonder neveneffect.

Bij non-actualiteit van CHARF heeft het geven van een voorgift geen (neven) effect, het aanroepen van CHARF evenmin.

Met deze definitie van het afvallen van de actualiteit heb ik het volgende bereikt: als SYM van de flexowriterpagina een niet afsluitend symbool leest, gevolgd door een basic symbol� dat 1 positie beslaat, gevolgd door een stopcode� dan heeft SYM bij het afleveren van het eerste symhool de volgende positie al gezien. CHARF heeft misschien de stopcode al gezien, maar nog niet doorgegeven� zodat hij zijn actualiteit nog niet heeft beeindigd. Dus kan de laatste positiebeschrijving nog in CHARF worden teruggeduwd.

Als CHARF wegens het doorgeven van in stopcode voor basint de overgang van 2 naar 0 heeft bewerkstelligd, dan is (als de stopcode via de band is gekomen) de synchronisatie met HEP gedefinieerd: hierna levert een aanroep van HEP de eerste heptade, die volgt op de stopcode. (En dit is eigenlijk het enige moment, waarop ik synchronisatie tussen CHAR en daarna HEP expliciet zou willen definieren. Uitgebreidere synchronisatieregels krijgen gauw iets gekunstelds en bovendien: de hemel weet, wat voor dol apparaat we morgen in het systeem moeten opnemen!)

Beinvloeding van basint.

Rechtstreeks HEPpen is niet verenigbaar met de actualiteit van CHARF of CHART� De vraag is, hoe het systeem reageert wanneer men deze (en dergelijke) regels probeert te schenden. In het bijzonder:
1)  actualisering van CHARF terwijl basint ≠ 0 is
2)  actualisering van CHART terwijl hasint ≠ 0 is
3)  rechtstreeks HEPpen terwijl basint = 2 of = 3 is.

Als basint ≠ 0 is, betekent dit heel expliciet: dat we ons tot nader order tot een bepaalde bandinterpretatie verplcith hebben, Je kunt zeggen: dan nog een keertje CHARF of CHART initialiseren is kennelijk misplaatst (en daar de consequentie van een letale programmafout aan verbinden); je kunt ook zeggen: het herdefinieren van de bandinterpretatie is dan kennelijk die “nader order” en het zal wel goed wezen. Uit opportunistische overwegingen neig ik tot het laatste; voor argumenten, dat het de moeite waard is om dit als letale programmafout te behandelen, sta ik open.

Rechtstreeks HEPpen terwijl basint = 2 of = 3 is, is vreemder, omdat we immers ons op het standpunt hebben gesteld, dat bij actualiteit van een CHAR de synchronisatie met HEP in het algemeen ongedefinieerd is. Om dit als letale programmafout te brandmerken, is me echter te gortig. Daarvoor is het primitivum HFP me te fundamenteel. Wel betekent rechtstreeks HEPpen� dat een eventuele CHAR�interpretatie niet meer valide is. Ik stel daarom voor, om HEP als neveneffect te laten hebben

“if basint ≠ 1 then basint := 0” .

(wordt HEP met basint = 2 vanuit CHARF aangeroepen, dan kan CHARF zelf, voor verlating met �basint := 2” dit neveneffect weer ongedaan maken.)

De initialisering van CHARF en CHART zijn de enige manier om basint = 2 of = 3 te krijgen; verder zal de programmeur basint = 0 of basint =1 mogen zetten.

De keuze tussen symhep, symcharf en symchart

De keuze tussen symhep, symcharf en symchart hangt af van de heersende waarde van basint. Maw, wie weet, dat zijn SYM via symcharf zal moeten werken, kan zulks bereiken, door voor de eerste aanroep van SYM de CHARF te initialiseren; evenzo kan hij a priori interpretatie volgens symchart of symhep via basint dicteren. Zodoende is het mogelijk om via SYM flexowriterbanden te lezen, zonder dat deze zich in hun aanhef als zodanig identificeren. Willen we echter de keuze niet a priori opleggen, maar van de band laten afhangen, dan kunnen we dit doen door
1) voor de eerste aanroep van SYM de variabele basint op 0 in te stellen.
2) ponsconventies te eisen, zodat aan het begin van de band te zien is, met welke waarde van basint tot nader order doorgelezen moet worden. SYM kan dan zelf zonodig CHARF of CHART actualiseren. (Ik zou voor de flexowriteraanhef willen voorstellen na skippen van blanks erases (en stopcodes?) eerst een NLCR of een casedefinitie, voor teleprinterbanden na skippen van blanks eerst men CR, een NL of een casedefinitie; de door SYM ingelaste CHARF- of CHART-initialisatie zal voor de onbekende parameter een standaardkeuze doen, bv. begin van de regel, lower case dan wel lettershift.)
Om tot normalisering van deze aanheffen te komen doe ik een beroep op alle belanghebbenden. Ik verwacht dan, dat iedereen zijn ponserij zo zal instrueren, dat de aldaar geponste banden —speciaal ALGOL-programma’s en gegevensbanden— conform die conventie aanheffen, ook al heeft hij dit voor eigen bedrijf niet nodig. Tevens verwacht ik van elke beperkte implementatie van eigen bedrijf (zeg “alleen Flexowriter banden”), dat die flexowriterbanden met genormaliseerde aanhef accepteert.

Initialisering van SYM.

Wat betreft de keuze van interpretatieproces is de status van SYM dus geregeld door basint. We zitten er nog mee, dat ook SYM (juist SYM!) een voorgift van een enkele waarde moet kunnen hebben. Definieren we het geven van een voorgift door overschrijving van een eventueel nog hangende voorgift (als hij CHAR) dan kunnen we SYM in dit opzicht initialiseren door een voorgift te geven en 1 maal SYM aan te roepen.

Initialisering van NUM.

De interpretatiewijze van SYM is volledig door basint bepaald, dit geldt niet voor NUM: immers als basint bv. CHARF als actueel aanwijst, dan hebben we nog de keuze tussen numcharf en numsym via symcharf, NUM heeft dus nog een boolean statusvariabele, die we “numint” noemen en die aangeeft of numsym actueel is. Is numint true, dan bepaalt basint slechts de keuze tussen symcharf, symchart en symhep; is numint false, dan bepaalt basint tevens de keuze tussen numcharf, numchart en numhep. De boolean “numint” zij in beide richtingen zetbaar.

Ik stel voor om de derde denkbare toestand (numint ongedefinieerd) te laten vervallen en in alle twijfelgevallen numint true te zetten. (Aan het begin van een nieuwe band.) Dit is een keuze, die aan de interpretatiewijze numsym een zekere voorkeur geeft.

Immers: laat —onder voortdurende actualiteit van CHARF— NUM een tijdlang via numsym gewerkt hebben en laten we nu op de Flexowriterpagina willen aangeven, dat van nu af aan tot nader order NUM via numcharf moet werken. Het feit, dat numint false moet worden, moet worden gemeld door de band, met wie NUM slechts via SYM contact heeft, Dit kan op verschillende manieren; ik noem
1) door af te spreken, dat het optreden van bepaalde getalscheiders door NUM geinterpreteerd zal worden als “ga over op numint = false”
2) door een extra basic symbol in te voeren met deze betekenis
3) door alles, wat niet als basic symbol interpreteerbaar is als “nonsense” door te melden en diezelfde betekenis te geven.
(Ik ga steeds meer voor de eerste mogelijkheid voelen.)

In alle gevallen kunnen we bereiken, dat een band niet via numsym gelezen gaat worden, door in de aanhef dit aan te geven. Het resultaat is, dat NUM banden leest via numsym� tenzij andere vermeld. Dit lijkt in overeenstemming met wat we wensen.

De verwerking van “EINDE BAND”.

Tot nog toe hebben we alleen erover gesproken, hoe HEP op einde band reageert. Daar hebben we afgesproken, dat het optreden van EINDE BAND mogelijk wel tot de semantische informatie behoort en HEP is niet uitgerust met automatische aanvrage van volgband. Nu moeten we dit voor de volgende niveaus (CHAR� SYM en NUM) beslissen.

Ook op het niveau van CHAR zou ik nog geen automatische volgbandaanvrage willen inbouwen. Sterker: ik vond het hachelijk om de door CHAR veronderstelde codecontinuiteit zich over physisch gescheiden stukken band te laten uitstrekken en stel daarom voor CHARF —wanneer hij via HEP “EINDE BAND” detecteerd— op deze detectie te laten reageren als op de stopcode en “EINDE CODE” te laten doormelden (en dan basint:= 0 uit te voeren). Het CHAR aanroepend programma kan dan via HEP inspecteren of er nog meer band is, zo nee, beslissen of het meer wil zien etc.

De consequentie hiervan is de eis, dat als we met SYM in diverse codes willen kunnen lezen, dan in elk geval op het begin van elke physische band de code-identificerende aanhef staat. Is aan deze voorwaarde voldaan, dan kunnen we een lange band uit een aantal deelstukken assembleren door plakken; wanneer alle deelstukken eindigen met de stopcode� dan kan dit plakproces zelfs zonder er aandacht aan te besteden of bij die plakjes codewisselingen optreden.

Een en ander voel ik als streke aanwijzing om SYM wel met automatische aanvraag van volgband te versieren. (Onder het motto: het hoeft tot het SYMmend programma niet door te dringen, dat die logisch nu zonder meer toegestane plakjes misschien niet de facto zijn uitgevoerd). En ik stel me zelfs voor om op dit niveau aan het physisch einde band geen semantische betekenis meer toe te kennen (en dan ook consequent, dus niet bv. nog een keer doormelden). Dat een programma, dat basic symbols van een band pulkt dan gegarandeerd ongevoelig is voor de gebruikte code en voor het physisch aantal banden lijkt me een groter goed dan het verlies van de mogelijkheid om met SYM een programma te schrijven, dat het aantal basic symbols op een band telt.

Het is aan SYM om nieuwe band aan te vragen, en wel, wanneer tijdens inspectie (basint = 0) blijkt, dat HEP de waarde –1 aflevert. Het aanvragen van een nieuwe band hebben als neveneffect, dat numint = true gezet wordt.

Nog enkele opmerkingen over de synchronisatie.

We nemen aan, dat NUM via numsym de getallen als niet zelfafsluitende eenheden uit de basic symbol stroom pulkt. (B.v. het teken van het volgende getal kan als separator gebruikt worden.) Als alleen NUM gebruikt zou worden kan dit op twee manieren gerealiseerd worden.
1) het teveel gelezen basic symbol wordt in SYM teruggeduwd
2) het teveel gelezen basic symbol wordt in NUM opgeslagen.

Zodra we alternerend NUMmen en SYMmen maakt dit wel verschil. Ik geloof, dat iedereen methode 1) verkiest.

Als echter SYM in termen van CHARG gedefinieerd is, dan zij nu ook een alternering tussen NUM en CHARG gedefinieerd. Men lette er op, dat na NUM het CHARFen het paginabeeld aftast te beginnen achter het teveel gelezen basic symbol!

Wie de band “zonder overslaan” sequentieel wil aftasten zal na NUM eerst een keer SYM moeten doen en dan pas CHARFen. Een open vraag is, of SYM zijn voorgift moet behouden bij rechtstreeks CHARFen� CHARTnn of HEPpen. Ik hem geneigd deze vraag ontkennend te moeten beantwoorden; anders heeft nl na CHARF herhaald SYMmen niets meer te maken met in successie aftasten en dat kon wel eens “a trouble shooter’s nightmare” worden.

Het laatste getal.

Lijkt ons de opgave “tel de basic symhols op deze band” wat gezocht, programma’s die een onbekend aantal getallen moeten verwerken zijn heel bekend. De truc “zet voorop het aantal” kennen we allemaal en we weten allemaal, hoe hinderlijk deze kan zijn.

Ik zou me kunnen voorstellen, dat we naast NUM een boolean procedure NUMMARK introduceren en dit tweetal samen definieren op een willekeurige rij van numerieke waarden en zg� “marks” (waarbij een mark als getalscheider fungeert).

De boolean procedure NUMMARK geeft antwoord op de vraag of er bij doorlezing eerst een “mark” komt, zo ja, dan is daarmee deze mark gepasseerd. In de diverse codes moet dit realiseerbaar zijn, zonder NUM meer statusvariabelen te geven. (Als we HEP niet met de terugduwfaciliteit uitrusten kost dit ons een heptade per getal, maar daarover zou ik niet willen vallen).

transcribed by Martin van der Burgt
revised 20-Nov-2013

  EWD 163

Eerste verkenning over de dood van programma's.

1. De processen, die door de CM's worden uitgevoerd, zijn onsterfelijk. Dit rapportje handelt dus duidelijk over een PM-aangelegenheid.

2. Een PM heeft een onsterfelijk buitenste blok, het PM-blok. Dit wordt nooit verlaten, het is in dit blok, dat de in- en uitvoerstromen thuishoren; evenzo hoort hier thuis de statusinteger "runnumber". De PM bevindt zich in dit blok, wanneer op standaardband gewacht wordt. (Deze toestand, ook in een statusvariabele voor de bandlezerselectie vastgelegd, zou ook in "runnumber = 0" kunnen worden vastgelegd.) Zodra een vermeende standardband wordt gevonden, wordt het runnumber ingevuld; als het een algolprogramma blijkt wordt op grond van de buiten het programma vermelde pluncherbehoefte de acceptabiliteit getest; zo ja, dan gaat de PM een binnenblok in, waarin de globalen voor de vertaler gedeclareerd worden, wordt de vertaler als procedure aangeroepen en als we daaruit terugkomen (en het programma was goed vertaald) dan roepen we het programma aan. Komen we hier helemaal legitiem uit terug, dan doet de standaardtekst van de PM de blokexit van het ingegane blok, we zijn terug op het niveau van het PM-blok. De eigen informatie (segmenten, heiligingen etc.) van het algolprogramma zijn hiermee afgehandeld, de PM hoeft niet meer te doen, dan de in- en uitvoerstromen tot hun nuchtere staat terug te brengen. Als er nog iets in een invoerstroom zit (of zit te komen), dan moet "skip until end of tape" gedaan worden (inclusief "geen interesse meer", zie de tape reader CM), als in een pluncherstroom een unfinished document zit, moet dit worden voltooid en aangehaakt, als in de printerstroom nog een unfinished form zit (hier zit een WC-rol conventie: ik neem aan, dat deze erin zit, zo er ueberhaupt van de printer gebruik gemaakt is) wordt deze als de laatste gemarkeerd en "number of final documents nfd" wordt met 1tje opgehoogd. (Dit even met Coen opnemen.)
      Nadat alle stromen zijn afgemaakt, zet de PM zijn behoeften op 0 (inclusief repercussies voor verdachte plunchers), zet het runnumber op 0 en gaat op standaardband staan wachten.

Dit is, zoals ik me de natuurlijke dood van een programma voorstelde. In verband met schijndood en de gewelddadige dood (zie onder) komt er nog wel wat bij.

3. De operateur heeft de mogelijkheid (waarvoor moge de hemel weten) om een programma schijndood te verklaren. Het moet dan op een zacht pitje zitten wachten, totdat het weer, via de console, wordt gewekt.
      Het schijndood maken is een bevel, gericht tot een programma in een PM; als er geen 1tje in zit (runnumber = 0) dan lijkt het commando me Non Applicable. Ook als het programma, dat er in deze PM zit, al schijndood is. Waarschijnlijk zullen we voor een aanwezig programma ook de boolean "op sterven" hebben; dan moet er ook maar gestorven worden en ik dacht, dat het bevel tot schijndood ook dan NA moest wezen.

De complicatie bij schijndood is, dat het programma dat zachte pitje bij voorkeur wel plaatst op een onschuldig punt. Wij hadden zo gedacht "niet in een rode sectie". Als een programma wit en uitvoerbaar is, dan kan het commando tot schijndood meteen verwezenlijkt worden: men boekt het als wachtend op een voor dit doel in elke PM voorkomende seinpaal. Anders moeten we alleen het verzoek tot schijndood boeken (weer een toestand, waarin het commando "val schijndood" als NA behandeld zou kunnen worden).

Deze blokkering van schijndood moet achterwege blijven, als de PM rood is (hij moet nog doorwerken) en is niet lekker codeerbaar, als de PM al op een andere seinpaal staat te wachten. De uitgestelde schijndoodheid moet effectief worden bij de witmakende V-operatie en de voltooide P-operatie. (Opmerking van Piet: de schijndood hoeft pas effectief te worden als je dreigt de controle aan een wit proces metterdaad te gunnen. Dit geldt ongeacht de reden tot uitstel en zou tot compactere codering aanleiding kunnen geven.)

De wekoperatie is nu makkelijk. Als de schijndood gevraagd, maar nog niet gerealiseerd is, kan worden volstaan de notitie weg te nemen. Als de aanvraag niet hangt, moet de schijndood gerealiseerd zijn (anders NA) en de message interpreter kan op de daartoe strekkende seinpaal een V-operatie uitvoeren. (Let wel, dat het veilig lijkt om voor de schijndood een specifieke seinpaal per PM in te voeren !)

4. De gewelddadige dood komt vanuit een andere AM (hetzij van een CM, die ontdekt, dat een ponser kapot is, hetzij via de message interpreter van de operateur, misschien ook van de PM zelf, die ontdekt, dat hij "onmogelijk verder kan". Ik zie dit nog niet zo direct, zo mogelijk openhouden.)

Het grote probleem van de gewelddadige dood is, dat we dit programma moeten beÎindigen, dwz. er een punt aan moeten draaien, zodat het toch nog well-behaved blijft. Een eerste vereiste is, dat het in elk geval zover doorgaat (zo nodig), dat ook de toestand "schijndood" zou mogen ingaan. Dit geeft ons een nieuw criterium om vast te stellen, waar roodheid begint en waar roodheid moet ophouden: buiten roodheid moet de PM in een hanteerbare toestand achterblijven. Nadat we nu straks hebben laten zien, wat we ons bij dat hanteren voorstellen, moeten we de stukken PM-programma, waarin roodheid voorkomt en die we inmiddels gemaakt hebben, in dit licht nog eens duchtig nakijken.

Er is een communicatieapparaat, dat hier wat roet in het eten doet, en dat is de trommel. Ik wil een programma liever niet vermoorden, als het nog op een seinpaal staat te wachten, in het bijzonder niet, wanneer het aan de segment controller een segment gevraagd heeft. Als we af kunnen spreken, dat sterven niet begint, zolang de PM nog op een seinpaal wacht, dan kunnen we dit als volgt spelen (NB. Het aanvragen van een segment aan de segment controller gaat buiten alle roodheid om: het kan in roodheid, het kan in witheid). Bij de opdracht aan de segment controller kan de PM een boolean "Aanvraag Segment" true zetten.
            De structuur in de PM wordt dan
                                AS := true
                                     aanvrage van segment
                                     V(SCS)
                                AS := false; P(eigen segment seinpaal)

De laatste twee statements staan op een regel, om heel nadrukkelijk af te spreken, dat ze in doofheid na elkaar gebeuren. Nu spreken we af, dat de initialisering van de zelfmoordriten niet plaats kan vinden, als AS. Hiermee bereiken we, dat de aangevraagde pagina's er zijn, voordat ze wellicht vernietigd zijn. (Ik schreef pagina's, ik bedoelde segmenten.)

Zo te zien, kunnen we met 1 variabele "killvar" al een heleboel doen. Tentatief zou ik deze de volgende waarden met de volgende betekenis willen geven (De op pag.0 gesuggereerde codering van X "runnummer = 0" kan dan vervallen.)

killvar = 0  | De PM is leeg
killvar = 1 | De PM is bezig met een programma, dat volslagen levend is
killvar = 2 | Er is aanvrage tot schijndood
killvar = 3 | Het programma is schijndood (hangt op de seinpaal killsem)
killvar = 4 | Er is aanvrage tot zelfmoord
killvar = 5 | Het programma is tot de zelfmoordriten overgegaan.

(Of de boolean AS hier ook in gecodeerd moet worden, bv. door killvar = 8 is voor mij nog een open vraag.)

Ik stel me nu op het standpunt, dat het agens, dat de zelfmoordopdracht geeft, hiervan via de consoleteleprinter melding maakt, maar dat we de PM (of liever: het er in zittende programma) niet de gelegenheid geven, nog een brief aan vrienden en bekenden ten afscheid te schrijven, dus geen rapportering over de status, warin het programma zich bevond, toen tot de zelfmoordriten werd overgegaan. (Hoogstens voeren we nog in

killvar = 6 | Het programma is op eigen initiatief tot de zelfmoordriten overgegaan, in tegenstelling tot killvar = 5. Op de laatste printerform kan dan nog een kreet komen te staan "ik heb mezelf beeindigd", dan wel "ik ben er afgetrapt".)

Ik hoopte, dat de overgang tot de zelfmoordriten geeffectueerd zou kunnen worden door in de status van het onderbroken programma zo te knoeien, dat zo ongeveer met het mechanisme van de General Goto de besturing springt naar het punt in het PM-blok, waar de PM de stromen gaat afmaken. Dit is niet genoeg, want er kunnen vanwege de SIS twee programmasegmenten heilig zijn - en de general goto ontheiligt er maar 1tje, als de moord plaatsvindt wanneer een arraysegment heilig is aangevraagd, dan zitten we daar ook nog mee. (De moord wordt wel uitgesteld, totdat dit segment gearriveerd is). Ik kan me voorstellen, dat een en ander bij het heilig aanvragen van arraysegmenten een extra notitie vergt en dat de overgang tot de zelfmoordriten zo min mogelijk door de coordinator en zoveel mogelijk door de PM zelf gebeurt. Het wegwerken van een stukje SIS (ontheiliging en zo) is nl. een handeling, die bij de dynamische fout onder auspicien van de PM zelf zal gebeuren.

5. De dynamische fout.

Na ampele overwegingen zijn we tot de conclusie gekomen, dat de reactie op een dynamische fout een zuivere PM-aangelegenheid is. Ik stel me zo voor, dat deze alleen tijdens killvar = 1 zal kunnen voorkomen (in rode stukken wil ik helemaal niet zulke griezelige dingen kunnen doen). De PM zal dan de stapel moeten afbreken totaan de eerste Working Space Pointer; als de fout in een SIS optreedt, dan moet hij dit door stapelinspectie ontdekken, als er nog een arraysegment heilig is, dan weet het foutendetecterende mechanisme dat, en kan dat arraysegment ontheiligd worden. Is de stapel teruggebracht tot het eerste niveau, waarop SE1 aangeroepen kan worden, dan zal dat moeten gebeuren om een aanroep van de procedure ALARM te kunnen simuleren. Met de sprong daarnaar toe wordt de laatste programmapagina ontheiligd, ALARM kan onder zich de stapel zoveel inspecteren als hij wil en kan tenslotte springen naar het punt in het PM-blok, waar we na programmabeÎindiging terecht komen.

De microscopie van het mieren aan de status onder in de HAM-kamer en het toespelen naar een tussengeschoven systementry is een spelletje, dat me wel boeit; ik beschik zelf niet over de kennis om direct te zien, hoe dit moet, ik dacht wel, dat het kon en wil er graag over helpen denken.

EWD.

transcribed by Sam Samshuijzen
revised Sun, 14 Jan 2007

EWD164

Keuzemechanisme tussen symcharf en symchart.

In het volgende beperk ik me tot het vaststellen, of een band als flexowriterband, dan wel als Telexband geinterpreteerd gaat worden: ik sta toe, dat dit proces tot een decisie komt, zonder dat alle statusvariabelen van CHARF resp. CHART vanuit de band gedefinieerd zijn. De ontbrekenden zullen volgens conventie geinitialiseerd moeten worden. Evenzo valt de detectie van een loslopende telexwagenterug buiten het bestek van de keuze.

Voor de beschrijving zal ik (voor de duidelijkheid, dan wel als mystificatieoefening) van BNF gebruik maken; de syntactische dubbelzinnigheden zijn dan voor de fijnproevers. Heptaden zal ik aangeven door hun decimaal equivalent tussen aanhalingstekens. Relevante waarden zijn voor de teleprinter: 2(wagenterug), 8(nieuweregel), 27(cijfershift) en 31(lettershift); voor de flexowriter: 11(stopcode), 26(carriagereturn), 122(lowercase) en 124(uppercase).

<vijferase>::= "31" | <vijferase> "31"

<flexonoise>::= "0" | "11" | "127"

<flexoskip>::= <flexoskip> <flexonoise> | <flexonoise>

<flexoleader>::= <empty> | <vijferase> | <vijferase> <flexoskip> | <flexoskip>

<flexCR>::= <flexoleader> "26"

<flexoLO>::= <flexoleader> "122"

<flexoUP>::= <flexoleader> "124"

<telcar>::= "2" | "8"

<telcarLE>::= "31" <telcar> | "31" <telcarLE>

<telCY>::= "27" | "31" <telCY>

<teleleader>::= <empty> | <flexoskip> | <vijferase> "0" | teleleader> "0"

<telxCY>::= <teleleader> <telCY>

<telxCARun>::= <teleleader> <telcar>

<telxCARLE>::= <teleleader> <telcarLE>

Codekeuze en initialisatie vindt plaats bij detectie van

<flexCR> | Flexowriter, wagenstand = 0, case volgend conventie
<flexoLO> | Flexowriter, wagenstand volgens conventie, lowercase
<flexoUP> | Flexowriter, wagenstand volgens conventie, uppercase
<telxCY> | Teleprinter, wagenstand volgens conventie, cijfershift
<telxCARun> | Teleprinter, wagenstand = 0, shift volgens conventie
<telxCARLE> | Teleprinter, wagenstand = 0, lettershift.

transcribed by Carl Ludwigson
revised Mon, 25 Oct 2010

EWD 167

Aan de leden van de onderafdelingsvergadering

Om U de gelegenheid te geven in te grijpen met "Ja maar, zo had ik het niet bedoeld." geef ik de conclusies, die ik gemeend heb te kunnen verbinden aan Uw reacties op mijn filmplan. Twee leden hebben zich van commentaar onthouden, omdat ze geen duidelijke voorstelling hadden van wat mij voor ogen zou kunnen zweven; accentverschuivingen daargelaten reageerden de overige leden eigenlijk unaniem.

Aan de zinvolheid van het doel werd niet getwijfeld, in het bijzonder
1) verantwoorde voorlichting over rekenautomaten aan middelbare scholieren is belangrijk;
2) het lijkt niet uitgesloten, dat men in het beperkte bestek van een film (ik denk aan drie kwartier) iets overdraagt, dat voldoende de moeite waard is.

Het werd niet misplaatst geacht, dat ik een dergelijk project zou aanzwengelen, resp. zou doen uitvoeren. Spontane suggesties om vooral die en die er bij te betrekken, waarschuwingen om er niet teveel tijd in te steken etc., vat ik in eerste instantie samen als een unanieme waarschuwing me niet te ver te begeven buiten het terrein van mijn erkende competentie. Men deelde unaniem mijn overtuiging dat een dergelijk project, hoe dan ook uitgevoerd, heel omvangrijk zal zijn. Ik beschouw Uw positieve reacties dan ook niet als toestemming het project onafwendbaar in gang te zetten, wel als aansporing voor terreinverkenning, opdat ik tegelegenertijd een wat beter gedocumenteerd voorstel ter discussie kan stellen. Omdat de verkenningen, waarop de definitieve beslissing genomen moet worden al vrij kostbaar zullen blijken, moeten we eerst de goedkope verkenningen uitvoeren en op grond van de uitkomst beslissen, of we doorgaan met verkennen. Kortom, we moeten ons voorbereiden op een meertraps- beslissing.

Ik stel me het begint van de verkenningen als volgt voor.

In de eerste fase moeten we een voorstel maken over de inhoud van de film, dwz. de er in te behandelen onderwerpen (voorbeelden) en een schets van hoe we ons hun presentatie voorstellen. Dit lijkt me het urgentste om de volgende redenen:
1) als hieruit blijkt, dat wat we kunnen bedenken, niet voldoende de moeite waard is, kunnen we er meteen mee ophouden;
2) in onze onmiddellijke nabijheid zijn genoeg mensen met interesse, met benul van het vak, van het kinderzieltje en -in iets mindere mate- van het medium, om de hoop te rechtvaardigen, dat er iets verantwoords uitkomt; vooral als we ons in dit stadium de beperking opleggen niet te veel in filmische details te treden, lijkt het gevaar van competentieoverschrijding me niet onacceptabel groot;
3) het lijkt gewenst, dat er een streng draaiboek is, voordat enigszins intensieve samenwerking met heel andere mensen geentameerd wordt: als je anderen echt interesseert voor een nog vaag plan loop je nl. het gevaar, dat er evenveel films als geinteresseerden geconcipieerd worden;
4) genoemde verkenning (inhoud en schets van de vorm) is niet duur en wel leuk.

Vervolgens zou een stukje -zeg van 2 minuten- proeffilm gemaakt moeten worden. In een zo vroeg mogelijk stadium moeten we ons op ons zwakste punt controleren en als alles heel anders uitpakt dan we ons gedroomd hebben, dan is het bij nader inzien dus toch niet zo'n goed idee en moeten we er mee stoppen. Bij gebrek aan nadere gegevens houd ik voor de uiteindelijke versie een richtprijs van f 5000,-/minuut aan; een proefstukje van 2 minuten kan wat minder mooi, anderzijds zit je natuurlijk daar al met aanloopkosten. De beslissing het proefstukje metterdaad te gaan maken vergt dus een weloverwogen oordeel, m.a.w. dit moet in de tweede fase plaatsvinden.

In de eerste fase kunnen we voorzichtig exploreren, hoe dit proefstukje gemaakt zou kunnen worden. Zolang we nog geen stevig draaiboek hebben, moeten we echter voorzichtig zijn met polsen. In de eerste fase kan het eventueel maken van een proefstukje slechts besproken worden met iemand, die bereid is, zich uit het project terug te trekken, nadat hij het proefstukje gemaakt heeft. Is zo iemand niet te vinden, dan wordt het zoeken van een maker van het proefstukje tot het zoeken naar een maker van de film en verschuift dit dus naar de tweede fase.

De regels, die ik mij voor dit overleg met U heb opgelegd, impliceren, dat mijn plannen doelbewust vager worden, naarmate ze verder in de toekomst liggen. Het stadium, dat we aan het einde van de tweede fase van de verkenning bereikt moeten hebben, duid ik dus slechts aan. Het zou het volgende moeten omvatten.

1)   | er zou een proefstukje moeten zijn
2) | er zou een reele kostenbegroting moeten zijn (dit moet dan mogelijk zijn)
3) | er zou een inzicht in de financieringsmogelijkheden moeten zijn
4) | er zou een inzicht in de materiele fabricagemogelijkheden moeten zijn
5) | er zou een overzicht moeten zijn van de bij het project betrokken mensen, inclusief aard en omvang van de door hen te spelen rol; zonder zich aan beroepsdidacten en paedagogen te verkopen, zal nauwlettend moeten worden gecontroleerd, of hun verenigde competentie geen baarlijke lacunes vertoont.
6) | er moet een beeld zijn van hoe de feitelijke fabricage georganiseerd gaat worden.

E.W.Dijkstra

transcribed by Ike Naar
revised Tue, 15 Aug 2006

  EWD 184

Ir.Medema, Ir.Hendriks, weledelgestrenge heren!

de toespraken, die ik tot U beiden zou willen richten hebben een zo omvangrijke doorsnede, dat ik ze, voorzover mogelijk, zou willen combineren.

Om te beginnen wens ik U van ganser harte geluk met de eclatante wijze, waarop U beiden het groeiproces tot wiskundig ingenieur doorstaan en volbracht hebt, een gelukwens, waarin ik graag allen betrekken wil, aan wie Uw welzijn dierbaar is.

Dit groeiproces besloeg twee gedeelten: enerzijds het omvangrijke gedeelte van Uw studie, de eindeloze reeks tentamina, mag ik wel zeggen, en anderzijds de afsluiting in de vorm van het afstudeerwerk.

Wat betreft Uw studie hebt U beiden, elk op Uw eigen manier, een grootse prestatie geleverd, zeker wanneer we in dit oordeel betrekken de steeds ongunstiger wordende omstandigheden, waaronder de studie verricht moest worden.

U, ir.Medema, begon al onder heel ongunstige omstandigheden, nl. een volle dagtaak elders, omstandigheden, zo ongunstig, dat ik me wel eens afvraag of het uberhaupt moreel verantwoord is, iemand onder zulke omstandigheden een studie te laten entameren. Tot overmaat van ramp ontwikkelde U zich in de loop van Uw studie tot een voor Uw werkgever zo kostbare kracht, dat het beroep op Uw medewerking steeds intensiever werd en U ter beloning uit Eindhoven naar Apeldoorn werd overgeplaatst, een niet te onderschatten verzwaring van de taak van de student Medema. Dat U desondanks Uw studie in dit tempo tot een goed einde hebt weten te brengen is een bewonderenswaardig wonder.

Ook bij U, ir.Hendriks, werden de omstandigheden voor Uw studie steeds ongunstiger. Ook U bent, lang voor Uw laatste tentamen, verwikkeld geraakt in dit fascinerende, de mens volledig opeisende vak. In Uw geval is het bijzonder te waarderen, dat U, terwijl er zoveel aanleiding was om U met een Jantje van Leiden van deze laatste tentamina af te maken en U van dit blok aan het been te bevrijden, niet voor deze pressie gezwicht bent en tot het bittere einde Uw hoge standaard hebt gehandhaafd. U hebt zich daarmee een student naar mijn hart betoond en ik waardeer dit bijzonder in U, temeer omdat ik, die in mijn eigen studententijd uiteindelijk wel voor een dergelijke pressie gezwicht ben, daardoor taxeren kan hoeveel liefde U voor de wiskunde hebt leren koesteren.

Totzover Uw studie, nu het afstudeerwerk. Nu dit door U beiden zo riant is volbracht, mag ik wel publiekelijk releveren, dat U beiden destijds met tamelijk bedenkelijke geloofspapieren aan mij gepresenteerd werd.

U, ir.Medema, kenden we van tentamina: wat we U vroegen, dat wist U wel, maar we kregen nooit het prettige gevoel, dat het ook nog overhield. Wij hebben U steeds "the benefit of the doubt" gegeven, op een of andere grond vertrouwend dat U Uw tentamina overtuigender afgelegd zou hebben, als U in de gelegenheid geweest was U intenser in de stof te verdiepen, een vertrouwen, dat U niet beschaamd hebt, integendeel! De ware Medema is ons getoond in Uw afstudeerwerk, waarin U zich als volwassen wiskundige bewogen hebt op het gebied, dat inmiddels Uw vak geworden is.

U, ir.Hendriks, kenden we als meeloper: algemene indruk was die van een luie en ongeintereseerde blaag, van wie, omdat hij mogelijk niet dom was, misschien wel wat gemaakt kon worden als hij stevig werd aangepakt. Door onze toenmalige voorzitter werd ik toen voorzichtig gepolst, of ik soms met hem als student assistent in zee durfde. Ik ben me niet bewust, U "streng aangepakt" te hebben, U hebt U zëlf ontwikkeld tot een creatieve, geengageerde medewerker, wiens werk elke toets met glans doorstaat. Apart vermeldenswaard is Uw afstudeerverslag, dat als kroon op dit werk schittert door helderheid.

Zo is het dus met U beiden gelopen; U bent wiskundig ingenieur geworden en ik neem als afstudeerhoogleraar hiermee afscheid van U in Uw hoedanigheid van mijn eerste twee afstudeerders. Ik doe dit met enige weemoed, er helaas van overtuigd, dat ik niet tot in lengte van mijn dagen gezegend zal zijn met afstudeerders van Uw kaliber. Ik zou mijn gelukwens dan ook willen beeindigen met mijn dank uit te spreken voor de rol, die ik —hetzij als regisseur van het laatste tafereel, dan wel als figurant, ik weet het niet!— heb mogen spelen in een groeiproces, dat U bekroond hebt door U als volwassen wiskundigen te gedragen.

Weledelgestrenge Heren, mijn oprechte dank.

transcribed by Sam Samshuijzen
revised Sun, 14 Jan 2007

EWD188

gaarne commentaar

EW Dijkstra.

Over een academische opleiding tot “Computer Scientist”.

Met “academische opleiding” bedoel ik een opleiding aan Hogeschool of Universiteit. Wanneer ik spreek over “het vak” Computer Science”, dan bedoel ik een geestelijke discipline, vooralsnog in het midden latens, hoe dit in het academisch bestel zou moeten worden ingepast: zelfstandig, als afstudeerrichting c.q. mogelijk hoofdvak voor een doctoraalexamen, met een interfacultaire status etc. (Dit zal mede van lokale omstandigheden afhangen.)

Belangrijke praeliminaire vragen lijken mij

1) wat zou het vak moeten inhouden?

2) hoe omvangrijk is de behoefte aan in dit vak afgestudeerden? en wat is hun plaatsingsmogelijkheid?

3) is de instelling van een dergelijk specialisme tegenover studenten, die nog een heel leven voor de boeg hebben, verantwoord?

4) wat zijn de opleidingsmogelijkheden?

5) liggen er taken voor academisch onderzoek? en tenslotte (dit is geen grapje!)

6) hoe zou dit vak in het Nederlands moeten heten?

Het is duidelijk dat deze vragen niet onafhankelijk van elkaar beantwoord kunnen worden. Uitgaande van de dienende functie van het Hoger Onderwijs, wil ik van de maatschappelijke aspecten uitgaan. En dan observeer ik het volgende.

Aan een computer scientist “pur sang”, die niet bereid is zich bij de uitoefening van zijn vak in specifieke toepassingen te verdiepen is geen schreeuwende behoefte. Men zou een moment kunnen denken, dat men zulke mensen ten bate van de Nederlandse rekenmachineindustrie zou kunnen opleiden, maar

a) de toekomst van de Nederlandse rekenindustrie is niet zeker

b) de praktijk heeft geleerd, dat elke rekenmachinefabrikant zich uitgebreid in de problemen van zijn klanten moet verdiepen, omdat de klant (nog) niet beschikt over de mensen, die de brug van de toepassing in een gegeven situatie kunnen slaan.

Omgekeerd is het duidelijk, dat men geen opleiding tot computer scientist kan componeren, door 100 bijvakjes (nl. voor elk mogelijk toepassingsgebied 1) bij elkaar te vegen. De situatie lijkt erg op die, welke we bij de opleiding tot wiskundig ingenieur al kennen: van de pas afgestudeerde wiskundige ingenieur eisen we niet dat hij van alle markten thuis is, wel dat hij over de nodige basiskennins beschikt om zich snel in een nieuwe markt thuis te gaan voelen, dwz. uit een toepassingsgebied de quintessence, voorzover voor hem relevant, te extraheren.

Bedenkend dat de opmars der rekenautomaten niet anders is dan een symptoom van de voortschrijdende mathematisering van de maatschappij, denk ik me bij gebrek aan gedetailleerdere ideeen gemakshalve een soort onderbouw, zoals we die inmiddels voor de opleiding tot wiskundig ingenieur kennen, zij het met enige accentsverschuiving (zoals wat minder bemoeienis met het continuum, ten gunste van discrete, eindige problemen, praktische logica, stukken van de regeltheorie en de bedrijfskunde; ook wat stochastiek).

Van de computer scientist zal bv. verlangd worden, dat hij intuitief geformuleerde automatiseringsprojecten met kennis van zijn zaken en in nauw contact met de geinteresseerden omsmeedt tot we! gedefinieerde projecten, met een duidelijk onderscheid tussen vereisten en desiderata; hij meet deze structureel kunnen analyseren en liefst in een vroeg stadium een verantwoord inzicht krijgen in de logische en kwantitatieve knelpunten, kwetsbaarheid, expansiemogelijkheid etc. Voor de taxatie van kwantitatieve knelpunten lijkt enige stochastische scholing niet ondienstig; de regeltheorie heb ik genoemd omdat van de computer scientist een heel operationele appreciatie van causale afhankelijkheid gevergd wordt. Bij de genoemde verkenning is een scholing in de logica al een groot goed, bij de gedetailleerde uitwerking van dergelijke projecten is het dunkt me een onmisbaar stuk gereedschap.

Laat ons thans de verhouding tot “randdisciplines” afbakenen, Ik denk aan de constructiekant bijvoorbeeld aan electrotechniek en werktuigbouwkunde, aan de gebruikskant speciaal aan de numerieke wiskunde. Ik kan we een zeer nuttige computer scientist voorstellen, die op al deze drie gebieden een onbeschreven blad is. Het is evenwel ook heel goed mogelijk, dat een computer scientist zijn werkterrein heel dicht bij of zelfs op deze randgebieden legt. Mijn conclusie is dat dergelijke randdisciplines (met het noemen van dit drietal claim ik geen volledigheid) niet essentieel tot de geestelijke bagage van de computer scientist behoren, maar als mogelijk keuzevak op een programma niet zouden misstaan. En hiermee zijn we dan gekomen tot de vraag, wat dan wel specifiek tot het vak computer science zou behoren.

1) Hij (dwz. de computer scientist) dient in hun gebruiksaspecten met hardware en hardware componenten vertrouwd te zijn. Enig orgaan voor snelheid, betrouwbaarheid, prijs, onderhoud, klimatologische voorzorgen kan allemaal geen kwaad. (Tegen de tijd dat de computer scientist specificaties van te bouwen hardware moet geven, is intensievere vertrouwdheid met electrotechniek wel gewensd.)

2) Hij zal met gangbare programmeertalen en hun implementatietechniek vertrouwd moeten zijn

Het onder 1 en 2 genoemde is encyclopaedische kennis van vrij vergankelijke aard. Omvang en actualiteit zullen daarom streng bewaakt moeten worden.

3) Vertrouwdheid met coderingstechnieken, syntaxes op eindige alphabetten, structuren van hanteerbare contextafhankelijkheid van betekenis etc.

Ook minder zakelijke wiskundigen hebben rijkelijk tot dit gebied bijgedragen, zodat er onvergankelijk materiaal te over is. Omvang dient daarom bewaakt te worden, relevantie zij daarbij richtsnoer.

4) Hij zal met inachtname van alle denkbare flexibiliteitseisen complexe systemen moeten kunnen concipieren, construeren en verifieren.

Voor de conceptie dient hij over een scherp ontwikkeld en ik zou willen zeggen “zakelijk” abstractievermogen te beschikken.

Voor de constructie dient hij vertrouwd te zijn met de mogelijkheden deze te automatiseren: dit stelt hogere eisen aan de graad van abstractie bij de conceptie, is anderzijds een belangrijke toetssteen voor “de gezondheid” van een nieuw begrip.

Voor de verificatie zal hij vertrouwd moeten zijn met moderns bewijstechnieken. Een ontwikkeld gevoeld voor de factoren, waarvan de hanteerbaarheid van dergelijke bewijzen critisch kan afhangen, is bij conceptie en constructie een onmisbare leiddraad.

Ik heb alle reden om te verwachten, dat dit in de zeer nabije toekomst tot een logisch samenhangende discipline zal uitklinken, doceerbaar, examineerbaar, bruikbaar en weinig vergankelijk. Te verwachten bijproducten

a) een documentatietechniek die aan strenge eisen voldoet

b) een organisatietechniek, die aan strenge eisen voldoet

c) een begrippenarsenaal waarmee gegeven rekenautomaten op hun logische consistentie kunnen worden beoordeeld

d) een begrippenarsenaal in termen waarvan de eerder genoemde “structurele analyse van autamatiseringsprojecten” relevantelijk kan worden uitgevoerd.

Zonder claim op volledigheid staak ik hier de opsomming van wat dan specifiek wel tot het vak Computer Science zou behoren. Het soort vakman, dat mij voor ogen zweeft is door de genoemde voorbeelden, hoop ik, voldoende getekend.

Om vraag 2 (omvang van behoefte en plaatsingsmogelijkheid) concreet te beantwoorden, ontbreken mij helaas de middelen.

Zijn potentieel werkterrein is enorm: wij kunnen veilig stellen dat “the computer is here to stay” en het zal alleen maar erger worden. Numerieke besturing van gereedschapswerktuigen, reservering, banken, grote en kleine bedrijfsadministraties, informatiebeheer in ruimere zin, ziekenhuizen (zowel voor adminisstratie als bewaking), havenbedrijf, verkeersregeling op de grond, in de lucht en op de rails (overzicht wagenpark!), verweving met experimentele technieken etc.

De behoefte aan hem is evenredig aan dit soort activiteit. Wat nu gevergd wordt gaat het bevattingsvermogen van de gewone programmeur (zelfs de goede), die dateert uit de tijd dat accuratesse en spitsvondigheid voldoende waren om zijn ambacht te bedrijven, ver te hoven. De alom waarneembare incompetentie, die bij omvangrijkere computertoepassingen tentoongespreeid pleegt te worden, is ronduit beangstigend en zou ons moeten leiden tot de conclusie dat het Hoger Onderwijs in dezen al gefaald heeft. Over de behoefte maak ik me dan ook geen zorgen: in elk geval groter dan de uit de aard der zaak beperkte productiemogelijkheid van hooggekwalificeerde academici.

Over de plaatsingsmogelijkheden maak ik me meer zorgen: dat in het computer-gebruik het menselijk bevattingsvermogen de zwakste schakel begint te worden, is nog onvoldoende bekend. Menig bedrijfsleiding leeft in de overtuiging, dat je voor je personeel rond de computer volstaan kunt met mensen van middelbaar niveau of lager die (soms zelfs zonder HBS) een paar cursussen gevolgd hebben, een fictie die door opleidingsinstituten van dubieuze signatuur wordt warmgehouden. (Ook door computerfabrikanten, die drempelvrees van klanten willen overwinnen.) Advertenties spreken in dit opzicht weinig geruststellende boekdelen. Ik ben verder bang voor het soort weerstand, dat je bewust zou kunnen oproepen door Computer Scientist met “rekenweter” te vertalen! De meeste mensen willen niet, dat hen verteld wordt dat zij te licht zijn voor hun taak.

Vraag 3, of het tegenover de studenten verantwoord is, zich “voor de rest van hun leven” in dit specialisme te begeven, durf ik na enige aarzeling bevestigend te beantwoorden. Het werkterrein zal niet zo een twee drie uitgeput zijn, toch meet je je de vraag stellen “Wat doet zo’n man, als hij ouder wordt.” Het zou me niet verbazen, als het dan te moeilijk voor hem wordt; in dit geval moet je hopen, dat de man bv. zoveel organisatorische ervaring heeft opgedaan, dat hij in een minder technische beleidsfunctie kan groeien. Dit is niet irreeel, temeer daar hij door zijn eerdere werk het bedrijf wel eens heel aardig zou kunnen kennen.

Vraag 4 stelt de opleidingsmogelijkheden. Uit het voorafgaande blijkt dat ik me de opleiding alleen kan voorstellen als wiskundige specialisatiemogelijkheid. Gezien het werkterrein van de computer scientist lijkt een hogeschool iets meer voor de hand te liggen dan een universiteit. Bekommerd om de “weltfremdheit” van de universiteit zou je kunnen opteren voor een universiteit, als middel om de universitaire wiskundige een toegang tot de maatschappij te geven. Dat zou heel mooi zijn, als dat kan. Elke wiskundige groep (subfaculteit of onderafdeling) die deze opleiding gastvrijheid zou verlenen, moet wel drommels goed weten, wat hij doet. Het specialisme “computer science” mag niet verwelkomd worden als uitloopmogelijkheid voor de minder begaafde student, waar je eigenlijk niet zo goed raad mee weet, in zo’n milieu is de opleiding een doodgeboren kindje. Men meet met open ogen zich er a priori bij neerleggen, van ganser harte zelfs, dat een aantal van de beste studenten deze kant opgaat. Men versta mij goed, dit is niet een oratio pro domo, een opschroeven van de importantie of intellectuele pretentie van eigen vak, het is de maatschappelijke consequentie, van het feit, dat nu machines gemeen goed worden, die 1 000 000 maal zo snel zijn dan wat een generatie geleden mogelijk was, zodat allerlei behoeften mechanisch bevredigd zouden kunnen worden, als wij maar wisten hoe.

Liggen er taken voor academisch onderzoek? Dat was vraag 5. Op dit punt aarzel ik, althans voor de verdere toekomst. Op het ogenblik is er nog een heleboel werk te doen, de manier waarop we rekenautomaten gebruiken is, hoewel beter dan vroeger, nog steeds vrij rommelig; de structuur van de machines zelf is navenant. Maar het is niet uitgesloten dat binnen tien of twintig jaar dit zoeken en tasten zijn beslag vindt, dat alle rekenmachinetoepassingen onderling evenveel overeenkomst vertonen als alle wiskundige bewijzen en dat iedereen er gelukkig mee is. Het is een jaar of dertig geleden begonnen, in een halve eeuw zouden we er wel eens op uitgekeken kunnen raken. De veelheid der toepassingen zal blijven, maar de gemeenschappelijke kern zou klaar kunnen raken. In Angelsaksische terminologie zou ik niet voor een “Department of Computer Science” durven pleiten, ik zou het onderzoek niet op deze wijze willen institutionaliseren. Ik durf het niet, ik geloof ook niet dat het hoeft zolang het vak zich geborgen weet waar het thuis hoort: onder de mantel van de Koningin der Wetenschappen.

Nu vraag 6: hoe moet het vak heten? Ik ben alergisch voor het woord Computer (uit te spreken: kompuuter). Rekenkunde zou gaan, maar dat is al bezet. Ik kan op het ogenblik niet veel anders bedenken dan “automatiseringswiskunde”, dit heeft het voordeel, dat haar beoefenaren ook een naam hebben “automatiseringswiskundigen”. De constructie is analoog aan “toegepaste wiskunde” maar loopt zelfs iets lekkerder. (Het substantief “toegepast wiskundige” is natuurlijk waanzin!) De term is wel fair. Je kunt ook denken aan informatieleer, maar “informatie” is me wat te passief. Automatentheorie is een heel ander vak, dat kan dus ook niet. Voor electronische rekenautomaat is de term “informaat” gesuggereerd, maar bij mijn weten niet aangeslagen. Wiskundige programmering is geloof ik ook al bezet, ligt in elk geval te dicht bij constructies als dynamische programmering. De term “autonomica” (naar analogie van de dynamica en de physica) heeft het voordeel, dat de term in Engeland geintroduceerd is. (Het NPL kent een “Autonomics Division”). Ingeburgerd is een tweede... Toegepaste logica kan je ook proberen, mechanische wiskunde is een andere mogelijkheid (in Bonn is een instituut voor “Instrumentelle Mathematik”). Voor geen der genoemde namen loop ik vreselijk warm, we houden ons voor suggesties aanbevolen.

transcribed by Bart Vreugdenhil
revised 28-Nov-2011

  EWD 190

Tentamen "Co-operating Sequential Processes."

Aan een grote ronde tafel zijn de plaatsen cyclisch genummerd van 0 t/m 39; de leden van een gezelschap van 40 personen zijn eveneens genummerd van 0 t/m 39, ieder mag alleen op zijn eigen plaats - dwz. de plaats, die zijn eigen nummer heeft - aan tafel aanzitten.

Hun gedragspatroon bestaat uit een niet-eindigende cyclische opeenvolging van:

leven (buitenskamers);
borrelen (binnenskamers, maar niet aan tafel);
eten (binnenskamers, aan tafel);

en alleen voor de heren

sigaren (binnenskamers, niet aan tafel).

Hun gedragingen moeten zo gesynchroniseerd zijn dat

1) nimmer drie cyclische opeenvolgende plaatsen aan tafel tegelijkertijd bezet zijn, en

2) geen dame van tafel opstaat, tenzij er tenminste 1 andere dame in de kamer is.

Voor de dames (die qualitate qua na tafel geen sigaar roken) is het opstaan van tafel en het verlaten van de kamer eenzelfde handeling. Eventuele personen, die met aan tafel gaan moeten wachten (wegens regel 1) op het van tafel opstaan van dame A, die (wegens regel 2) met opstaan moet wachten totdat, zeg, dame B binnenkomt, hebben ten aanzien van het aan tafel gaan voorrang boven dame B.

Er zijn tenminste twee dames in het gezelschap, dat met iedereen buitenskamers levend geinitialiseerd wordt.

De oplossing acht (ik) in het omvattend universum gedeclareerd:

1) | de boolean procedure dame(u); value u; integer u; deze heeft de waarde "true" als persoon nr. u een dame is, de waarde "false" als persoon nr. u een heer is.

2) | de integer procedure mod40(u); value u; integer u; deze heeft de waarde van u, gereduceerd modulo 40.

Gegeven is een oplossing van de volgende structuur.

begin semaphore mutex, damutex; semaphore array persem [0:39];
      boolean array honger [0:39]; integer array eettal [0:39];
      integer damnr, k;
      procedure test(u); value u; integer u;
      begin if honger[u] then
            begin if eettal[mod40(u-1)] < 2 and
                     eettal[u] < 2 and
                     eettal[mod40(u+1)] < 2 then
                  begin eettal[mod40[u-1)] := eettal[mod40(u-1)] + 1;
                        eettal[u] := eettal[u] + 1;
                        eettal[mod40(u+1)] := eettal[mod40(u+1)] + 1;
                        honger[u] := false ; V(persem[u])
                  end
            end
      end

      procedure staop(u); value u; integer u;
      begin eettal[mod40(u-1)] := eettal[mod40(u-1)] - 1;
            eettal[u] := eettal[u] - 1;
            eettal[mod40(u+1)] := eettal[mod40(u+1)] - 1;
            test(mod40(u-2)); test(mod40(u-1));
            test(mod40(u+1)); test(mod40(u+2))
      end
      for k := 0 step 1 until 39 do
      begin honger[k] := false; eettal[k] := 0; persem[k] := 0 end;
      mutex := 1; damutex := 1; damnr := -1; k := 0;

      parbegin
      persoon 0 : begin..... ..... ..... .....end;
              ⋮
      persoon39 : begin..... ..... ..... .....end
      parend
end

waarbij de structuur van persoon h is als volg:

persoon h:
begin Lh: leven;
          if dame(h) then
          begin P(damutex); k := k + 1;
                if damnr ≥ 0 then
                begin P(mutex); staop(damnr); V(mutex);
                      V(persem[damnr]); damnr := -1
                end;
                V(damutex)
          end;
          borrelen;
          P(mutex); honger[h] := true; test(h); V(mutex); P(persem[h]);
          eten;
          if dame(h) then
          begin P(damutex); k := k - 1;
                if k = 0 then
                begin damnr := h; V(damutex); P(persem[h]) end
                         else
                begin P(mutex); staop(h); V(mutex); V(damutex) end
          end
                     else
          begin P(mutex); staop(h); V(mutex);
                sigaarroken
          end;
          goto Lh
end

Opgave. Bewijs, dat de gegeven oplossing aan alle specificaties voldoet.

NB. De tentaminandi wordt verzocht hun papier slechts eenzijdig te beschrijven.

transcribed by Sam Samshuijzen
revised Mon, 15 Jan 2007

EWD191

Aan de Commissie Wetenschapsbeleid ter zake van Automatiseringwiskunde aan de THE.

Het doel van deze note is te verkennend in hoeverre er op het gebied van de automatiseringswiskunde aan taak ligt voor de Onderafdeling, wat deze taak zou omvatten en wat het zou inhouden, als de Onderafdeling deze taak zich nam.

Kort samengevst berust het bestaansrecht cvan de automatiseringswiskunde op:

de constaterings, dat bij conceptie, realisering en gebruik van logische mechanismen het naieve menselijke bevattingsvermogen het nijpendste knelpunt is geworden;

de constatering dat het ambacht, stoeland op spitsvondigheid en accuratesse, ontoereikend als het blijkt, zijn plafond bereikt heeft;

de overtuiging, dat soulaas slechts komen kan en ook komen zal va iets, dat er uit zal zien als een wiskundige discipline (die we in het vervolg met "automatiseringswiskunde" zullen aanduiden);

de (nist in de laatste plaats economische) importantie van de automatiseringswiskunde.

Als wij een opleiding overwegen, dan dient de behoefte aan automatiseringswiskundigen nader gespecificeerd te worden. Wij merken hierbij op:

dat de behoefte aan de hoogstgekwalificeerde het meest apart is, dwz. aan de leider, die een project kan overzien zonder zich in de details te verliezen en nochtans weet, dat zijn project uit "details" zal moeten worden opgebouwd;

dat de behoefte aan automatiseringswiskundigen, die hat hoogs-denkbare niveau niet halen, hoewel minder sprekend, zeker zo omvangrijk is, want elk groot project zal slechts gerealiseerd kunnen worden, mits de leiding in vertrouwen deeltaken delegeren kan aan mensen, die althans begrip voor de discipline hebben.

Hiermee is voldaan aan een voorwaards, die aan elke opleiding moet worder opgelegd. Ik noem dit expliciet, omdat ik persoonlijk (en misschien ik niet alleen!) me vaak betrap op de neiging me in deachten tot de top 10 percent te beperken.

Wat betreft de omveng van de behoefte is het een veilige veronderstelling, dat deze onze productiemogelijkheid zal overtreffen. Dit is gebaseerd op:

de overweging dat (in weerwil van de vorige alinea) het hier toch altijd nog gast om de opleiding van vrij hooggekwalificeerde mensen, iets waartoe uit de aard der zaak de mogelijkheden beperkt zijn;

de overweging, dat hun toekomstig werkterrein, dat (gevarieerde) automatiseringsprojecten omvatten moet, heel aanzienlijk zal zijn. (Het zich beperken tot bv. rekenmachines en standaard software zou een veel te smalle basis zijn: gezien de onzeker toekomst van de Nederlandes rekenmachinesindustrie zou dat bovendien wel eens in "werken voor de brain drain" kunnen uitlopen. Ik vermeld dit expliciet vanwege de eenzijdigheid van mijn eigen industriele contacten.)

In de opstelling van een studieprogramma moeten, dunkt me, drie aspectes betrokken werden:

wat voort soort vaardigheden en kennis verwachten we van de automatiseringswiskundige (dwz. wenselijkheid);

in hoeverre kunnen de hiervoor gewenste docenten (hij ons, dan wel elders) gevonden worden (dwz. mogelijkheid);

wat zijn de organisatorische repercussies (bv. is een uniform candidaatsexamen nog te handhaven?).

In het huidige stadium van deze verkenning moet ik dunkt me in de eerste plaats proberen om tenaanzien van de wenselijkheden zoveel mogelijk duidelijkheid te scheppen.

Als eerste vereiste zou ik voor de automatiseringswiskundige willen noemen; een zakelijk abstractievermogen. Ik noem dit voorop, omdat ik dit (zonder iets of iemand al simplificerend te kort te willen doen) niet als kenmerkend aspect van aanverwante disciplines kan onderbrengen.

De begrippen, die de doorsnee creatieve wiskundige introduceert, zijn doorgaans wel scherp gedefinieerd; hij is er zich echter vaak onvoldoende van bewust, dat een begrip slechts bestaansrechts heeft bij gratis van zijn (logische) hanteerbaarheid, zijn doel is vaak te weinig scherp gesteld dan dat hij zich kan afvragen, hoeveel het begrip hem helpt. Vandeer dat ik het gangbare wiskundige abstractievermogen niet het praedicaat "zakelijk" wil geven. Bovendien lijkt me de wiskundige training meer gericht op het leren hanteren van begrippen, die hun bruikbaarheid bewezen hebben, dan op het introduceren van nieuwe begrippen, op het bewust evalueren van hun hanteerbaarheid en hun effectiviteit.

Schakeltechniek en programmeren worden wel op een zakelijke basis bedreven (zij het dat deze zakelijkheid overwegend slechts een eenzijdig kostenbewustzijn is) maar doorgaans door mensen met een onvoldoend ontwikkeld abstractievevermogen. Zij scheppen op tamelijk intuitieve manier gecompliceerde mechanismen, zonder de begrippen in te voeren, met behulp waarvan zij de totale taak kunnen ontleden en in termen waarvan zij hun mechanismen kunnen rechtvaardigen. Een en ander is historisch maar al te goed verklaarbaar (de "ingenieursmentaliteit" in de benepen zin des woords, het "wij-mensen-van-de-praktijk" speelt hier ook nog mee). Bovendien blijkt, dat zij als regel hat gedrag van hun creaties niet kunnen definieren; zij verwarren constant "hoe het werkt" en "wat het doet".

Organisatieleer is doordrenkt van psychologische en sociologische invloeden en is daarmee onder anders ook geworden tot de kunst om met behulp van vage "begrippen" toch tot een bruikbare conclusie te komen. Er zijn ni die hoek wel paginen tot grotere exactheid, maar die treffen mij als eenzijdig kwantitatief, waarbij het object van deze kwantificering even vaag blijft als voorheen.

Ten tweede moet hij een duidelijke affiniteit hebben voor discrete, eindige problemen en de nodige bewijstechnieken vaardig hanteren. Waar dit in eerste instantie traditioneel wiskundige activiteiten betreft, moet ik aantekenen, dat ik meen te voorstellingsvermogen senzijdig ruimtelijk ontwikkelt: door "een tijd-as te tekenen" wordt de onomkeerbaarheid van de tijd onvoldoende gerpresenteerd. Het voorstellingsvermogen van de automatiseringswiskundige omvatte een tamelijk operationele appreciatie van de casualiteit. (Observering: mijn beelspraken zijn vaak slechts middel om de tijd gezond in mijn denken te betrekken, zij zijn een eigen, nodig stuk denkgereedschap en niet alleen maar een presentatiemiddel.)

Van de automatiseringswiskundige zal bv. verlangd worden, dat hij intu•tief geformuleerde automatiseringsopgaven met kennis van zaken en in nauw contact met de geinteresseerden omsmeedt tot wel-gedefinieerde projecten, met een duidelijk onderscheid tussen versisten en desiderata; hij moet deze projecten structureel kunnen analyseren en liefst in een vroeg stadium een verantwoord inzicht krijgen in de logische an quantitatieve knelpunten, kwetsbaarheid, expansiemogelijkheden etc.

Voor het tijdig isoleren van quantitatieve knelpunten is behalve algemene "gereedschapskennis" een stochastische scholing onontbaarlijk. (Met onstemming van college Benders ken ik aan de stoichastiek een aanmerkelijk centralere rol toe dan aan optimaliseringsmethoden.)

Voor de analyse van kwetsbaarheid en expansiemogelijkheden lijkt me, behalve de in de vorige alinea genoemde "gereedschapskennis" een scholing in de practische logica onmisbaar. Vaak zullen geinteresseerden (die ook niet helderziend zijn) slechts schuchtere prognoses over omvang en richting van expansie kunnen geven; onder die omstandigheden is het vitaal, dat de automatiseringswiskundige bij zijn eerste opzet een overzicht kan geven van latere mogelijkheden en onmogelijkheden. (Vooral voor grotere projecten zal de eis, dat het groeiproces niet al te pijnlijk is, diepe sporen in de eerste opzet dienen achter te laten.

Kortom: de automatiseringswiskundige zal met inachtname van alle denkbare flexibiliteitseisen (vals hiervan zal hij zelf moeten aandragen!) complexe systemen moeten kunnen concipieren, construeren en verifieren. Voor de constructie zal hij vertrouwd moeten zijn met de mogelijkheden het constructieproces zelve te automatiseren, voor de verificatie zal hij vertrouwd moeten zijn met de hiervoor geschikte bewijstechnieken. Een ontwikkeld gevoel voor de factoren, waarvan de hanteerbaarheid van deze bewijzen critisch kan afhangen, is bij conceptie en constructie een onmisbare leiddraad. Ik heb alle reden om te verwechten, dat dit in de zeer nabije toekomst tot een logisch samenhangende discipline zal uitklinken, doceerbaar, examineerbaar, bruikbaar en vrij onvergankelijk.

De "gereedschapskennis" omvat vertrouwdheid met hardware (in zijn gebruiksaspecten), programmeertalen en hun implementatiesmogelijkheden. Het betreft hier encyclopaedische kennis van vrij vergankelijke aard: omvang hiervan moet streng bewaakt worden, actualiteit zij hierbij richtsnoer.

Voorts zal hij vertrouwd moeten zijn met coderingstechnieken, syntaxes op eindige alphabetten, structuren van hanteerbare contextafhankelijkheid van betekenis etc. Ook minder zakelijke wiskundigen hebben rijkelijk tot dit gebied bijgedragen, zodet er onvergankelijk materiaal te over moet zijn. Omvang dient daarom bewaakt te worden en relevantie zij daarbij richtsnoer. (In deze hoek zal er ernstig voor gewaakt moeten worden, dat het programma niet nodeloos opgesierd wordt om het een respectabel uiterlijk te geven; inplaats van excessieve syntaxclassificeringen zou ik liever minder specifiek spul als combinatoriek en algebra zien. Dat is veel veiliger.)

Nog een woord over de "praktische logica". Het is een prozaisch vereiste, dat de automatiseringswiskundige logische formules als de gewoonste zaak van de wereld opschrijft, interpreteert en manipuleert. Een zijspoor naar de computability is niet misplaatst, Turing en Gödel mogen geen hoofdschotel vormen. Ten aanzien van de eeuwige verwarring tussen de aanduiding van een object en het object zelf zou mogelijk de logicus verhelderend kunnen optreden.

Ik heb organisatieleer als aanverwante discipline genoemd: er zijn allerlei verbindingen tussen het werk van de automatiseringswiskundige en wat organisatieleer zou kunnen zijn (maar nauwelijks lijkt te zijn). Zijn product is een organisatie, het mechanisme, waarmee hij het maakt is een organisatie, teslotte is waarin het functionerend ingrijpt een organisatie. Ik heb om die reden een hele ochtend met collega Hulsof gesproken om hem de achtergrond van mijn interesse te schilderen opdet ik een idee zou kunnen krijen in hoeverre de automatiseringswiskunde van de organisatieleer zou kunnen profiteren. Voorshends heb ik de indruk, dat de organisatieleer meer van de automatiseringswiskunde zal kunnen profiteren dan andersom.

                                  27 februari 1967

transcribed by Carl Ludwigson
revised Thu, 4 Nov 2010

  EWD 194

Het einde van een ambacht.

In de wijze waarop met rekenautomaten wordt omgesprongen begint een drastische verandering zich af te tekenen en in verband met de consequenties hiervan lijkt het gewenst deze verandering tijdig te signaleren. Kortweg kan men stellen, dat het programmeren het ambachtelijke stadium ontgroeit tot een wel-gefundeerde, tamelijk wiskundig gerichte discipline.

Een en ander is een direct gevolg van de capaciteitsvergroting van het technische vermogen, zoals wij deze in het laatste decennium aanschouwd hebben. Enerzijds heeft deze vergroting geleid tot een afzwakking van de efficiencyeisen, gemeten naar de wat eenzijdige maatstaven van geheugenruimte en rekentijd, zodat het denken daardoor nu minder verlamd is, anderzijds heeft deze vergroting toepassing gebieden ontsloten, waarbij nu blijkt dat het ongetrainde menselijke bevattingsvermogen verreweg het nijpendste knelpunt is geworden.

Het eerste teken aan de wand was het omhoogschietende budget, dat voor software-projecten ter beschikking gesteld moest worden, een ontwikkeling die aanvankelijk met enig succes door organisatietechniek nog wat is afgeremd. De noodklok is pas goed gaan luiden toen een groot gedeelte van de aldus voor grof geld vervaardigde software na aflevering bleek gewoon niet te deugen.

Dit falen was een intellectuele uitdaging, die mede vanwege de economische belangen niet onbeantwoord kon blijven en dan ook niet onbeantwoord gebleven is. Bewijstechnieken, waarmee de correctheid van zowel sequentiele programma's als ook van multiprogrammeringssystemen kan worden aangetoond, zijn en worden ontwikkeld, bewijstechnieken, die niet zullen nalaten de stijl van programmeren diepgaand te beinvloeden: een nauwkeurig aanvoelen van de factoren, waarvan de hanteerbaarheid van dergelijke bewijzen critisch kan afhangen, zal binnen niet te lange tijd tot de vereiste vaardigheden van de competente programmeur gerekend moeten worden. Bovendien : als men met de opbouw van zijn programma's er rekening mee houdt, dan blijkt de opgave om een serie testgevallen te construeren, waarmee de juistheid van een programma aan de machine uitputtend kan worden vastgesteld, helemaal niet zo onmogelijk als dikwijls nog wordt aangenomen.

Heden is het nog niet ongebruikelijk, dat grote programma's min of meer op de bonnefooi gemaakt worden en dan aan enige willekeurig gekozen testgevallen worden onderworpen om althans de grofste blunders aan het licht te brengen en —zij het vaak ten koste van veel machinetij— te localiseren. En zulke programma's gaan daarna als "geteste programma's" de wereld in! Maar het moment lijkt nabij, waarop een dergelijke manier van werken met recht dilletantisme genoemd mag en ook zal worden.

Van de professionele programmeur van zo niet morgen, dan toch overmorgen, zal aan abstractievermogen —nodig om structuur te onderkennen en beheersen— en aan mathematische bewijsvaardigheid aanmerkelijk meer gevraagd worden van een jongeman, wiens geestelijke bagage niet meer omvat dan een programmeurscursus van een paar maanden met daarna een praktijk van een paar jaar. Hoe snel de verandering in rekenklimaat zich zal inzetten, laat zich moeilijk voorspellen: tegenover de economische pressie werk van een klasse beter (goed nl.) af te leveren staat de remmende invloed van het in vele instituten overvloedig aanwezige kader van middelbaar niveau of lager, waarvan we niet mogen verwachten dat het, zo het zulks al ziet, gaarne erkennen zal dat het vak boven zijn geestelijk plafond is uitgegroeid, dat zijn ambacht heeft opgehouden als zodanig te bestaan.

Prognoses over het aantal rekenmachines lijken me wat klakkeloos vertaald in prognoses over de behoefte aan programmeurs van het thans gangbare niveau. Is het nog langer verantwoord middelmatige jongens met niet meer dan middelbare school naar programmeurscursussen te lokken met de suggestie, dat ze daarna onmisbare specialisten zullen zijn, als we zien aankomen, dat ze door de bank genomen professioneel niet mee zullen kunnen? Het is in dit verband tekenend, dat een Angelsaksische instelling, naar ik onlangs vernam, voor programmeurs met een Bachelor's Degree geen genoegen meer neemt: Master's Degree is een minimum, Ph.D.'s hebben ze liever.

prof.dr.E.W.Dijkstra
Technische Hogeschool Eindhoven

transcribed by Sam Samshuijzen
revised Wed, 17 Jan 2007

  EWD 196

Copyright Notice

The following manuscript

EWD 196: The structure of the 'THE'-multiprogramming system

was published in Commun. ACM 11 (1968), 5: 341-346. It is reproduced here by permission.

The structure of the THE-multiprogramming system

Introduction

Papers "reporting on timely research and development efforts" being explicitly asked for, I shall try to present a progress report on the multiprogramming effort at the Department of Mathematics at the Technological University, Eindhoven, the Netherlands.

Having very limited resources (viz. a group of six people of, on the average, half time availability) and wishing to contribute to the art of system design —including all stages of conception, construction and verification— we are faced with the problem of how to get the necessary experience. To solve this problem we have adopted the following three guiding principles:

1) Select a project as advanced as you can conceive, as ambitious as you can justify, in the hope that routine work can be kept to a minimum; hold out against all pressure to incorporate such system expansions that would only result into a purely quantitative increase of the total amount of work to be done.

2) Select a machine with sound basic characteristics (e.g. an interrupt system to fall in love with is certainly an inspiring feature); from then onwards try to keep specific properties of the configuration for which you are preparing the system out of your considerations as long as possible.

3) Be aware of the fact that experience does by no means automatically lead to wisdom and understanding, in other words: make a conscious effort to learn as much as possible from your precious experiences.

Accordingly, I shall try to go beyond just reporting what we have done and how, and shall try to formulate as well what we have learned.

I should like to end the introduction with two short remarks on working conditions, remarks I make for the sake of completeness. I shall not stress these points further.

The one remark is that production speed is severely degraded if one works with half time people, who have other obligations as well. This is as least a factor of four, probably it is worse. The people themselves lose time and energy in switching over, the group as a whole loses decision speed as discussions, when needed, have often to be postponed until all people concerned are available.

The other remark is that the members of the group —mostly mathematicians— have previously enjoyed as good students a university training of 5 to 8 years and are of Master's or Ph.D. level. A less qualified young man, originally included, found our activities beyond his mental grasp and left the group. I mention this explicitly, because at least in Holland, the intellectual level needed for system design is in general grossly underestimated. I am more than ever convinced that this type of work is just difficult and that every effort to do it with other than the best people is doomed to either failure or moderate success at enormous expenses.

The tool and the goal

The system has been designed for a Dutch machine, the EL X8 (N.V. Electrologica, Rijswijk (ZH)). Characteristics of our configuration are:

1) core memory cycle time 2.5mms., 27 bits; at present 32K

2) drum of 512K words, 1024 words per track, rev. time 40ms.

3) an indirect addressing mechanism very well suited for stack implementation

4) a sound system for commanding peripherals and controlling of interrupts

5) a potentially great number of low capacity channels; ten of them are used (3 paper tape readers at 1000 char/sec; 3 paper tape punches at 150 char/sec; 2 teleprinters, a plotter and a line printer)

6) absence of a number of not unusual awkward features.

The primary goal of the system is to process smoothly a continuous flow of user programs as a service to the University. A multiprogramming system has been chosen with the following objectives in mind:

1) a reduction of turn around time for programs of short duration

2) economic use of peripheral devices

3) automatic control of backing store to be combined with economic use of the central processor

4) the economic feasibility to use the machine for those applications for which only the flexibility of a general purpose computer is needed but (as a rule) not the capacity nor the processing power.

The system is not intended as a multi-access system. There is no common data base via which independent users can communicate with each other; they only share the configuration and a procedure library (that includes a translator for ALGOL 60 extended with complex numbers).

Compared with larger efforts one can state that quantitatively speaking the goals have been set as modest as the equipment and our other resources. Qualitatively speaking, I am afraid, we got more and more immodest as the work progressed.

A progress report

We have made some minor mistakes of the usual type (such as paying too much attention to speeding up what was not the real bottle neck) and two major ones.

Our first major mistake has been that for too long a time we confined our attention to "a perfect installation": by the time we considered how to make the best of it when, say, one of the peripherals broke down, we were faced with nasty problems. Taking care of the "pathology" took more energy than we had expected and part of our troubles were a direct consequence of our earlier ingenuity, i.e. the complexity of the situation into which the system could have manoeuvred itself. Had we paid attention to the pathology at an earlier stage in the design, our management rules would certainly have been less refined.

The second major mistake has been that we have conceived and programmed the major part of the system without giving more than scanty thought to the problem of debugging it. For the fact that this mistake had no consequences —on the contrary! one might argue as an afterthought— I must decline all credit. I feel more like having passed through the eye of the needle.....

As captain of the crew I had had extensive experience (dating back to 1958) in making basic software dealing with real time interrupts and I knew by bitter experience that as a result of the irreproducibility of the interrupt moments, a program error could present itself misleadingly like an occasional machine malfunctioning. As a result I was terribly afraid. Having fears regarding the possibility of debugging we decided to be as careful as possible and —prevention is better than cure!— to try to prevent bugs from entering the construction.

This decision, inspired by fear, is at the bottom of what I regard as the groups' main contribution to the art of system design. We have found it is possible to design a refined multiprogramming system in such a way that its logical soundness can be proved a priori and that its implementation admits exhaustive testing. The only errors that showed up during testing were trivial coding errors (occurring with a density of only one error per 500 instructions), each of them located with 10 minutes (classical) inspection at the machine and each of them correspondingly easy to remedy. At the moment of writing the testing is not yet completed, but the resulting system will be guaranteed to be flawless. When the system has been delivered we shall not live in the perpetual fear that a system derailment may still occur in an unlikely situation such as might result from an unhappy "coincidence" of two or more critical occurrences, for we shall have proved the correctness of the system with a rigour and explicitness that is unusual for the great majority of mathematical proofs.

A survey of the system structure

Storage allocation. In the classical von Neumann machine information is identified by the address of the memory location containing the information. When we started to think about the automatic control of secondary storage we were familiar with a system (viz. GIER ALGOL) in which all information was identified by its drum address (as in the classical von Neumann machine) and in which the function of the core memory was nothing more than to make the information "page wise" accessible.

We have followed another approach an as it turned out, to great advantage. In our terminology we made strict distinction between memory units (we called them "pages" and had "core pages" and "drum pages") and corresponding information units (for lack of a better word we called them "segments") a segment just fitting in a page. For segments we created a completely independent identification mechanism in which the number of possible segment identifiers is much larger than the total number of pages in primary and secondary store. The segment identifier gives fast access to a so-called "segment variable" in core whose value denotes whether the segment is still empty or not and if not empty, in which pages (or pages) it can be found.

As a consequence of this approach: if a segment of information, residing in a core page has to be dumped onto the drum in order to make the core page available for other use, there is no need to return the segment to the same drum page as it originally came from. In fact, this freedom is exploited: among the free drum pages the one with the minimum latency time is selected.

A next consequence is the total absence of a drum allocation problem: there is not the slightest reason why, say, a program should occupy consecutive drum pages. In a multiprogramming environment this is very convenient.

Processor Allocation We have given full recognition of the fact that in a single sequential process (such as performed by a sequential automaton) only the time succession of the various states has a logical meaning, but not the actual speed with which the sequential process is performed. Therefore we have arranged the whole system as a society of sequential processes, progressing with undefined speed ratios. To each user program, accepted by the system, corresponds a sequential process (buffering input stream in synchronism with the execution of the input commands), to each output peripheral corresponds a sequential process (unbuffering output streams in synchronism with the output commands); furthermore we have the "segment controller" associated with the drum and the "message interpreter" associated with the console keyboard.

This enabled us to design the whole system in terms of these abstract "sequential processes". Their harmonious co-operation is regulated by means of explicit mutual synchronization statements. On the one hand, this explicit mutual synchronization is necessary, as we do not make any assumption about speed ratios, on the other hand this mutual synchronization is possible, because "delaying the progress of another process temporarily" can never be harmful to the interior logic of the process delayed. The fundamental consequence of this approach —viz. the explicit mutual synchronization— is that the harmonious co-operation of a set of such sequential processes can be established by discrete reasoning; as a further consequence the whole harmonious society of co-operating sequential processes is independent of the actual number of processors available to carry out these processes, provided the processors available can switch from process to process.

System hierarchy The total system admits a strict hierarchical structure.

On level 0 we find the responsibility for processor allocation to one of the processes whose dynamic progress is logically permissible (i.e. in view of the explicit mutual synchronization). At this level the interrupt of the real time clock is processed, introduced to prevent any process to monopolize processing power. At this level a priority rule is incorporated to achieve quick response of the system where this is needed. Our first abstraction has been achieved, above level 0 the number of processors actually shared is no longer relevant. On the higher levels we find the activity of the different sequential processes, the actual processors having lost their identity, having disappeared from the picture.

At level 1 we have the so-called "segment controller", a sequential process synchronized with respect to the drum interrupt and the sequential processes on higher levels. At level 1 we find the responsibility to cater for the bookkeeping resulting from the automatic backing store, the dynamic relating of segments of information to pages of store. At this level our next abstraction has been achieved: in all higher levels identification of information takes place in terms of segments, the actual storage pages having lost their identity, having disappeared from the picture.

At level 2 we find the "message interpreter", taking care of the allocation of the console keyboard via which conversations between the operator and any of the higher level processes can be carried out. The message interpreter works in close synchronism with the operator: when the operator presses a key a character is sent to the machine, together with an interrupt signal to announce this next keyboard character: the actual printing is done on account of an output command generated by the machine under control of the message interpreter. (As far as the hardware is concerned the console teleprinter is regarded as two independent peripherals: an input keyboard and an output printer.) If one of the processes opens a conversation it identifies itself for the benefit of the operator in the opening sentence of this conversation. If, however, the operator opens a conversation he must identify the process he is addressing, in the opening sentence of the conversation, i.e. this opening sentence must be interpreted before it is known to which of the processes the conversation is addressed! There lies the logical reason to introduce a separate sequential process for the console teleprinter, a reason that is reflected in its name "message interpreter". Above this level it is as if each process had its private conversational console. The fact that they share the same physical console is translated into a resource restriction of the form "only one conversation at a time", a restriction that is satisfied via mutual synchronization. At this level the next abstraction has been implemented: in all higher levels the actual console teleprinter has lost its identity. (If the message interpreter had been on the same level as the segment controller, then the only way to implement it would have been to make a permanent reservation in core for it; as the conversational vocabulary might get large (as soon as our operators wish to be addressed in fancy messages) this would result in too heavy a permanent demand upon core storage. Therefore the vocabulary in which these messages are expressed is stored on segments, i.e. as information units that can reside on the drum as well. Therefore the message interpreter is of a level one higher than the segment controller.)

At level 3 we find the sequential processes associated with buffering buffering of input streams and unbuffering of output streams. At this level the next abstraction is affected, viz. the abstraction of the actual peripherals used, that are allocated at this level to the "logical communication units" in terms of which is worked in the still higher levels. The sequential processes associated with the peripherals are of a level above the message interpreter, because they must be able to converse with the operator (e.g. in the case of detected malfunctioning). The limited number of peripherals again acts as a resource restriction for the processes on higher levels, to be satisfied by mutual synchronization between them.

At level 4 we find the independent user programs, at level 5 the operator (not implemented by us).

The system structure has been described at length in order to make the next section intelligible.

Design experience

The conception stage took a long time. During this period of time the concepts have been born in terms of which we sketched the system in the previous section. Furthermore we learnt the art of reasoning by which we could deduce from our requirements the way in which the processes should influence each other as regards mutual synchronization so that these requirements were met. (The requirements being that no information can be used before it has been produced, that no peripheral can be set to two tasks simultaneously, etc.) Finally we learnt the art of reasoning by which we could prove that the society composed by processes thus mutually synchronized by each other, would indeed in its time behaviour satisfy all requirements.

The construction stage has been rather traditional, perhaps even old-fashioned: plain machine code. Reprogramming on account of a change of specifications has been rare, a circumstance that must have contributed greatly to the feasibility of the "steam method". The fact that the first two stages took more time than planned was somewhat compensated by a delay in the delivery of the machine.

In the verification stage we had, during short shots, the machine completely at our disposal, shots during which we worked with a virgin machine without any software aids for debugging. Starting at level 0 the system has been tested, each time adding (a portion of) the next level only after the previous level has been thoroughly tested. Each test shot itself contained on top of the (partial) system to be tested a number of testing processes with a double function. Firstly they had to force the system into all different relevant states, secondly they had to verify that the system continued to react according to the specification.

I shall not deny that the construction of these testing programmes has been a major intellectual effort: to convince oneself that one has not overlooked "a relevant state" and to convince oneself that the testing programmes generate them all is no simple matter. The encouraging thing is that (as far as we are aware!) it could be done.

This fact was one of the happy consequences of the hierarchical structure: testing level 0 (the real time clock and processor allocation) implied a number of testing sequential processes on top of it, inspecting together that processor time was divided among them according to the rules.

This being established, sequential processes as such had been implemented. Testing the segment controller at level 1 meant that all "relevant states" could be formulated in terms of sequential processes making (in various combinations) demands on core pages, situations that could be provoked by explicitly synchronizing among the testing programs. At that stage the existence of the real time clock —although interrupting all the time— was so immaterial that one of the testers indeed forgot its existence!

By that time we had implemented the correct reaction time upon the (mutually unsynchronized) interrupts from the real time clock and the drum. If we had not introduced the separate levels 0 and 1 and if we had not created a terminology (viz. that of the rather "abstract" sequential processes) in which the existence of the clock interrupt could be discarded, but had tried instead to make in a non-hierarchical construction the central processor directly react upon any weird time succession of these two interrupts, the number of "relevant states" would have exploded to such a height that exhaustive testing would have been an illusion. (Apart from that, drum speed and clock speed being outside our control, it is doubtful whether we could have had the means to generate them all.)

For the sake of completeness I must mention a further happy consequence. As stated before, above level 1 core and drum pages have lost their identity and buffering of input and output streams (at level 3) therefore occurs in terms of segments. While testing at level 2 or 3 the drum channels hardware broke down for quite some time, but testing could proceed by restricting the number of segments so that they could be held in core. If building up the line printer output streams had been implemented as "dumping onto the drum" and the actual printing as "printing from the drum" this advantage would have been denied us.

Conclusions

As far as program verification is concerned I present nothing essentially new. In testing a general purpose object (be it a piece of hardware, a program, a machine or a system) one cannot subject it to all possible cases: for a computer this would imply that one feeds it with all possible programs! Therefore one must test it with a set of relevant test cases. What is relevant or not, cannot be decided as long as one regards the mechanism as a black box, in other words it has to follow from the internal structure of the mechanism to be tested. it seems the designer's responsibility to construct his mechanism in such a way —i.e. so highly structured— that at each stage of the testing procedure the number of relevant test cases is so small that he can try them all and that what is being tested is so perspicuous that it is clear that he has not overlooked a situation. I have presented a survey of our system because I think it a nice example of the form such a structure might take.

In my experience, I am sorry to say, industrial software makers tend to react to it with mixed feelings. On the one hand they are inclined to judge that we have done a kind of model job, on the other hand they express doubts whether the techniques used are applicable outside the sheltered atmosphere of a University Department and express the opinion that we could only do it this way thanks to the modest scope of the whole project. It is not my intention to underestimate the organizing ability needed for a much bigger job with ten or more times as many people, but I should like to venture the opinion that the larger the project, the more essential the structuring! A hierarchy of five logical levels might then very well turn out to be of modest depth, in particular when one designs the system more consciously than we have done with the aim that the software can be smoothly adapted to (perhaps drastic) configuration expansions.

transcribed by Tristram Brelstaff
revised Sat, 24 Jun 2006

EWD198

An Effort Towards Structuring of Programmed Processes.

0. Introduction

It is my impression that one of the most deep-rooted difficulties in programming is to bridge in one's imagination the gap between the (static) program text and its (dynamic) behavior, between the algorithm and the process described by it. This would be considerably easier if processes would present structural properties closely reflected in the structure of the program text.

Methods to structure program texts have been widely explored by syntactical investigations over the last few years. The question remains: what process structures to be represented in the program structure are we looking for? In exploring these I have used two yard sticks: our ability to understand and our ability to implement.

In looking for useful process structures I have started from a multiprogrammed environment. I have done so for two reasons. Firstly we may expect computers of the future to exhibit more and more parallelism and it will be vital that a configuration can be extended with, say, another processor without upsetting the whole software system. Secondly, if we indicate to what extent two assigned tasks can be delegated to two dependently assigned computers, we have also indicated to what extent these processes are logically independent, thus guaranteeing a noninterference from which the clarity of the process can only benefit.

Actions, processes, and states.

It is customary to regard a sequential process as a time succession of actions, each of which has a well defined effect. The total effect of the process is then the cumulative effect of the successive actions. The first subdivision of a process into actions may be a coarse one: then the composing actions themselves may again be regarded as processes, i.e. being thought of as composed of a time succession of subtractions, etc.

Disregarding input and output we can describe the effect of each action as a "change in the current state of the process", the current state at the end of the action --and thereby the effect-- being a unique function of the state at the beginning of the action.

If we use values of variables to record the current state we can regard the variables as coordinate axes in a "state space", with as many dimensions as variables. The current state is then given by a point in state space; furthermore the metaphor of "a subspace" is offered to us when we consider an action that is only concerned with a subset of the variables.

The above picture is reasonably adequate when we are concerned with a sequential process operating in a constant state space. If these conditions, however, are not satisfied the picture is badly in need of refinement.

I mention two reasons it is all right to regard an ALGOL inner block from the point of view of the embracing blocks as "an atom". As a whole its effect is defined by and reflected in values of variables specifying the state of the embracing block (or blocks). But as soon as we regard the innerblock as a process in which the local variables of the block have to be taken into account, we discover that this change in our attitude is accompanied with a temporary extension of state space, viz. with a new dimension for each local variable.

Secondly we assumed the possibility to speak about "the state at the beginning of an action and the state at the end of an action, and this assumes an implied definition of simultaneity, covering all the variables and specifying the moment at which their value should be taken to specify "the current state". This condition is certainly not satisfied as soon as our process has been split up over two or more parallel processes, that may have been delegated to as many mutually unsynchronized computers! In that case the effect of actions is only defined by and describable in a projection of a subspace: the other dimensions have to be ignored.

Before trying to refine the traditional picture I should like to make some remarks about it. Firstly as long as we regard a sequential process as a line of actions, leading from one state to the other, then the current state is only defined in between those actions. During an action the current state is undefined, or better perhaps: the whole concept of "current state" is inapplicable. To regard an action as a process composed of subactions is nothing more than a means to bring a finite number of intermediate states in our picture. In other words there is no point in talking about the current state of an action, the notion of "the current state" applicable only to a process composed of actions, and what is meant by "current" is related to (a finite number of) discrete points of progress, marked as "after the preceding action but before the next".

Secondly in real time these discrete points of progress may be periods of time, viz. when a process is temporarily stopped in between two successive actions. If the notion of "current state of a process" is to be of any use at all, we must be sure that in such a period of time between two actions the current state remains constant in time. In other words, if the current state of a process is recorded by the value of variables we must be sure that no actions of other processes will change these values: the variables used to record the current state of a process must in some sense be "private to the process", each process is related to its own subspace.

Thirdly I have come to the conclusion that the usual concept of a sequential process embodies two different aspects and that there is a point in retaining only one of them. In a sequential process the next action only begins after the preceding one has ended: this however implies that no two actions of the same process can ever overlap in time. The two different aspects mentioned are: explicit sequencing of actions on the one hand and "mutual exclusion in time" on the other. The latter aspect seems the more fundamental one: only if actions exclude each other mutually in time we can attribute a time sequence to them.

We shall admit a sequential process "to get unsequenced" for a finite period of time, i.e. during that period of time it is still composed of actions that exclude each other in time, but the order in which they occur --or stronger even: if they occur at all-- is for the time being no longer an intrinsic property of the process.

We shall give you a clear example of this situation, viz. the solution of the "Problem of the Dining Quintuple".

[Insertion]

We can distinguish in this example six different subspaces: the five local spaces of the persons concerned -- the spaces in which "eating" and "thinking" is described for each of them-- and the global space of the state variables and the semaphores.

The five personal processes are only initiated and the corresponding subspaces are only created at the entry of the parallel compound. The global subspace remains in existence and we have indeed actions taking place with regard to it: the critical section in the person behavior, mutually excluded by the P and V operations on the binary semaphore called "mutex". We regard them as actions of the global process; they only take place however sequenced in the personal processes.

Allowable modifications of the state space.

The actions discussed so far bring about a change of current state: the current state before and after are described with respect to the same state (sub)spaces. The dynamic introduction of new variables --such as at block entry-- yet falls outside the picture. Let us try and let us start with the ordinary inner block of ALGOL 60, with only local scalars.

Many implementers have remarked that if we allocate scalars in a stack, then the local variables of nested inner blocks can be numbered consecutively by the translator, while at runtime this number can be related to the distance from the stack bottom.

That is: the variable belonging to a block and in inner blocks can be identified as indexed elements of a vector, this vector increasing and decreasing in stack fashion. And also: if this block operator on these variables only, only the identity of this vector has to be implicitly understood. Or again: the total execution of an inner block is an action of the process described by the embracing block. The inner block can be regarded as a process, but then operating in an other (be it related) subspace. In the middle of the execution of the inner block, the state of the outer process is an inapplicable notion!

transcribed by Nolan Egly
revised Sun, 30 May 2004

02xx

200: The variable size machine

201: A sequel to EWD200

206: A sequel to EWD201

209: A constructive approach to the problem of program correctness

209A: A constructive approach to the problem of program correctness

214: ACM Symposium in Gatlinburg “Operating System Principles”

215: A case against the GO TO statement

221: [Raw code for computing De Bruijn-sequences]

222: Verslag van het bezoek aan Grenoble en Parijs (6–11 december 1967)

224: HEEL VERTROUWELIJK

227: Stepwise program construction

229: Aan de leden van de Commissie Wetenschapsbeleid

230: To the EDITOR ALGOL 68

231: De Rekenautomaat als Gebruiksvoorwerp

232: Pretentie en doelstelling van het THE multiprogrammeringsproject

235: Contractie en expansie

236: Complexity controlled by hierarchical ordering of function and variability

237: A preliminary investigation into Computer Assisted Programming

238: Computation versus program

239: On trading storage against computation time

240: The moral of EWD237 – EWD239

241: Towards correct programs

243: Bijdrage voor de subcommissie Aanschaffingsbeleid Rekenautomaten

244: Een educatief dilemma

245: On useful structuring

246: Verslag van het bezoek aan de NATO Conference on Software Engineering

247: [“Journal for half-baked Ideas”]

247a: [Beantwoording ener enquete]

251: Requirements of programming tools

252: Mijn laatste verslag van een bijeenkomst van W.G.2.1.

252a: Ontwerp voorwoord [afstudeerrichting Fundamentele Programmering]

253: Tentamen Co-operating Sequential Processes (jan. 1969)

253a: Ontwerp Collegebeschrijving “Inleiding tot de kunst van het programmere

254: Computer Science of enkel Software Engineering?

254a: Hoger orde adressering

255: Over de IBM360

257: Verslag bezoek aan MIT

259: Toekomstverwachting Fundamentele Programmering

260: Plotting a curve with a printer

261: Hoe wiskundig programmeren is

264: On understanding programs

267: Over de toekomst van Computer Science

268: Structured programming

270: Aan de keuzecommissie rekenmachine

272: Verslag van de tweede “Conference on Software Engineering”, georganiseerd door de NATO Science Committee te Rome, 27–31 oktober 1969

273: The programming task considered as an intellectual challenge

275: Structure of an extendable operating system

278: Organisatie van onderzoek en onderwijs van Fundamentele Programmering

279: The programming laboratory project

281: Aan de Commissie Wetenschapsbeleid

282: A tree-structured system

286: Verslag van mijn reis naar California

287: Sans titre (but most definitely a predecessor to EWD316, “A short introduction into the art of programming”)

288: Concern for correctness as a guiding principle for program construction

288a: Recensie voor het tijdschrift “Informatie”

292: Letter to professor C.A.R. Hoare (31 August 1970)

295: Reisverslag van bezoek aan het Seminar on the Teaching of Programming at University Level

298: Informatica als wiskundige discipline

14 June 1967.                                                                             EWD200

The variable size machine

Classical programming is done for a fixed size machine. The fixed size machine consists of a constant number of components - processors, peripherals, storage locations - all with a permanent existence, an undeniable identity. The identity is reflected in the addressing structure, which is unique in both ways: each address points to a unique component, and conversely, each component is identified by a unique address. Later on, I think, I shall call such an address "an identity index".

The classical uniprogrammer has the complete machine at his disposal; he has to decide when components will be used for what purpose, decisions that materialize via the addresses as they occur in and are generated by his program.

In multiprogramming the situation is drastically different. If a number of programs co-reside within the machine, it must be known at any instant of time which part of the machine is at the disposal of which program, in order to avoid a clash of claims (to put it mildly).

For combinatorial reasons it is unacceptable that the programmer decides during program construction which part of the machine will be claimed by his program. (If so, two independently conceived programs could both, say, claim the storage locations from 0 through 1000, thus prohibiting concurrent execution.).

To postpone the decision until the moment of program loading is slightly better, but only slightly. It means that the program text indicates over which areas consecutivity is needed, more general: what amount of freedom is given to the loading program. If addresses - as they are in classical programming - are quantities upon which arithmetic operations are performed, the allocating algorithm will need consecutive areas in core store and the ability to use gaps may be absent.

Slightly better still is the technique, in which the programmer claims a consecutive area of store but will address the locations with indices from 0 onwards, indices to which at run time a base address will be added to transform the index into the machine address. As long as the program only manipulates indices, this technique allows reallocations of store by shifting, an operation that has to be accompanied by adjustment of the appropriate base address.

The above change is significant: the program itself has local terminology in which to identify storage locations, viz, the identity indices, that are among the subject matter of the progress, viz, the abstraction from the actual storage area used is performed so rigidly that indeed reallocation can be done in a safe and clear way. In practice, this solution has a number of disadvantages, due to a lack of refinement.

For one thing: the program is still executed by a fixed size machine, be it that the size is set at the moment of program execution.

For another thing: apart from a private terminology in terms of which a program can identify its private objects, there are common objects, such as library procedures that should be identified as will. The mixture of such terminologies is a problem for which, as far as I know, no satisfactory solution has been found.

Finally, the identification by consecutive index values has two serious disadvantages. On the one hand it forces the program to do it that way, on the other hand, the integers are so "neutral" that the way in which the program asks for its information (by just stating the integer index value) is most unhelpful in the case that the environment has to implement it all with multilevel storage.

What we are looking for is a process structure that defines (and modifies) the size of the machine as the process continues. Furthermore we require that it presents its "needs" - i.e. in the implementation of the variable size machine - in a useful manner. Above aims have a clear technical aspect. Simultaneously we desire a logically satisfactory way in which local and global terminology can be mixed.

If you wish you can regard the variable size machine as a "logical interface" between programs to be executed and implementing systems. At present, hardware extensions of a configuration tend to give rise to severe adaptation problems for the software. It is urgently hoped (and to some extent even expected) that the notion of the variable size machine will contribute to the solution of this vital problem.

Part of the consequences of the notion of the variable size machine is that it redefines not only its size, but also its structure, in the hope that the implementation can make good use of it. (We shall have to give a sharper definition of the notion "structure", but loosely speaking the obvious way in which to increase implementation efficiency can always be regarded as the systematic exploitation of structure rather than the ad hoc exploitation of discovered combinatorial luck.) One of the ways in which I hope to structure can be described as "desequencing" and I plan to apply this both to data and processing.

I intend to apply it to data, i.e. instead of specifying storage as a linear sequence - a vector of consecutive elements - the variable size machine must be able to comprise a number of vectors. There is no question about it, that the programmer will benefit from this - he has a kind of "elastic memory" that solves (for him at least!) a number of allocation problems. Also the implementation should be able to benefit from it, certainly as soon as multiple storage of different levels is considered. (In the multiprogramming system considered we saw that first the programmer has to fit his variables in a linear store and that thereafter the implementation has to find a long, now consecutive storage area! That seems funny!)

A next point of desequencing is, that I intend the variability of the size to apply to the number of processes conceptually going on in parallel. If the program "goes in parallel" - at present we must be content with a loose terminology, I am sorry! - this should be regarded as an invitation to allocate more processors, if available.

In the previously considered example (single vector and implicit base address per program) each variable of a program has an identity index and the identity indices are the quantities that have a semantic function within this program. The actual address associated with it has no meaning within this program, it is an "external" value, "only" a consequence of the embedding (as given by the base addresses) and it has only a meaning with respect to the embedding. This is very satisfactory.

As far as the system is concerned the values of the vector elements are non-interpreted: the only thing the system does with these values is moving them around when the embedding is changed. Also this is very satisfactory.

Remark. Twice I have used the term "satisfactory" without stating explicitly why. I think I shall return to this question in a later letter.

transcribed by Andreas Jonsson
revised Wed, 18 Aug 2004

15 June 1967

EWD 201

 A sequel to EWD200.

In today's letter I shall deal with a subtle question, viz. the problem of identity of elements in a set, a population, of variable size. Mind you, that in the opening paragraph of EWD200, I have spoken of components "with a permanent existence, an undeniable identity", and indeed, if we have a set of 100 elements, numbered (or should I say "identified"=) from 0 through 99, we have no problems.

But suppose that this is a vector that is allowed to shrink and grow in stack fashion and let element nr. 99 be removed from the top of the stack. This suggests, that the remaining elements (with a permanent existence, an undeniable identity!) keep their identity index, i.e. remain identified by their distances from the stack bottom. This is essentially what is meant by "identity", it provides a means in which we can refer (and continue to refer) to the remaining elements.

But if as a next move, a new element is added to the stack, we can raise the question, what the identity index of the element just added will be. There are at least two different attitudes:
a) in the stack elements are identified by their distances from the bottom, therefore the element just added will get as identity index the value 99
b) the element just added is a new object, definitely different from the old top element, that has ceased to exist; because somewhere we might (probably erroneously) still have hanging around a now obsolete reference to the no longer existing old top, it is essential the new top will get a different identity, i.e. an identity index that is still "virgin" with respect to this population (say: 100).
     (There is even a solution in between: if it is possible to scan the indices that might refer to elements in the population, one can upon removal of element nr. 99 scan for this value and replace it, whenever found, by some value meaning "undefined" so that the new top can again get the identity index 99 without the danger of identifying with each other the old and the new top.)

The whole point in this discussion is to make clear that population shrinking or growing are undefined operations, unless we define the algorithm that controls the generation of new identities, of new identity indices when the thing grows. And we have given two examples of such algorithms, case a): the lowest free index value and case b): the lowest virgin index value.

The first conclusion is that if we allow our variable size machine to vary in some aspect of its size, this is only a well defined operation provide we decided upon the pattern according to which identity indices for the elements to be added will be created. This decision is not trivial.

In designing our variable size machine we must make such a choice for the standard patterns according to which it may vary. My proposal is to keep method b) out of the hardware, for I shudder at the thought. In the cases of the stack I prefer method a) for a large variety of reasons.

For one thing: method a) is much easier to implement. Furthermore method a) gives a more practical significance to the identity index, because the elements "under" or "on top of" an identified element have identity indices that can be generated by subtraction and addition. Finally, if we describe stack arithmetic, we can describe in words the binary operation on the top in two different ways, say the sum. We can say "The top two elements are removed from the stack and the sum of the values removed is then put on the top of the stack", a description in which the stack elements seem to be constant during their life time, or we can say "The top element is removed from the stack and the then current top is replaced by the sum of its original value and that of the value removed". Method a) has the advantage that both descriptions of the addition give the same identity to the stack element whose value equals the sum.

The final remark is that method b) ignores the fact that the varying size object is indeed a stack!

In my present stage of thinking I restrict myself mentally to size variations in which the identity indices with respect to a certain size aspect (such as a vector) will have consecutive values. For the sake of completeness I mention two consequences for the program to be carried out by the variable size machine.

The first consequence is that in the case of wilder life times we may have inside the variable size machine unused portions. If the aspect in question is storage and we think the large size is too expensive (this, I am sorry to admit, is a hard question to decide!) then the program should have the decency to do some garbage collection, should move information (physically, I presume) and should reduce the size of its machine.

A next consequence is, that the program inside the variable size machine has the responsibility to see, that obsolete references to no longer existing objects do not lead the process astray. Our decision is, that also this will not belong to the responsibility of the system implementing the variable size machine.

In order not to confuse the issue, we continue to think today about machines of which only one aspect of the size can vary, and in order to explicit, we consider again a vector of storage locations.

The choice of method a) implies then that we can give another interpretation of the variable aspect: we can regard the situation as if the program were working all by itself in a very large (may be "infinite" in one of the appropriate meanings) memory, all the time stating as well lower and upper bound of the area used. It is another picture, maybe it will provide in the long run an easier terminology. Up till now I don't think so.

There is a very hard efficiency problem, that I shall indicate now, without looking for an answer. One may expect that the introduction of a constant size aspect can be done much cheaper than the introduction of a variable size aspect. If so, it might be cheaper (if a certain aspect does not vary too much and an a priori upper bound of the size is known) to introduce immediately a constant size aspect, leaving parts of the machine unused. This question would be solved if we find that a variable size aspect can be implemented so satisfactorily, that it does not pay to introduce the fixed size aspect as a special case.

There is a second efficiency problem. Undoubtedly it will be expensive to have the variable size machine too large for a long period of time; on the other hand the processing of the redefinitions of the size might be expensive. In the case of a stack this can be overcame: there is no need to let the machine size follow all microscopic changes in stack length, one can decide that machine size variations will take place in larger grains. The trouble is the size of this grain and (if the most appropriate grain size is a system characteristic) the variable size machine can be programmed independent of the actual grain size. Reference to an object that is not contained in the machine is clearly nonsense and will be detected; that reference to an object inside the machine can be meaningless (due to "majoration") is a possible. If so, this imposes a responsibility on the particular program, not unlike the previous one.

transcribed by Andreas Jonsson
revised Sat, 16 Oct 2004

25 July 1967

EWD206

A sequel to EWD201.

In today's letter I shall give some hardware considerations, because all the time they are at the back of my mind and it may be confusing if I keep silent about them much longer.

The first observation is that inside a sequential machine an important logical function has to be attached to the notion of simultaneity. This notion is never an exact one (in the mathematical sense) it is always with respect to a certain grain of time. The faster the sequential machine, the smaller its time grain. It is also obvious (at least to my taste, formed by theoretical physics years ago!) that the physical dimensions of such a sequential component must be small compared with the distance travelled by light during such a grain of time, i.e. the fast components must be small. One answer to this has been given by (micro)miniaturization, but I am looking for another answer, viz. the coupling of a number of such fast components.

I presume that each fast component will have its own, private clock, its "local time", and I am looking to an arrangement, where the various components can really work independent of each other, temporarily unsynchronized with respect to each other.

Immediate consequences of this approach are the following two.
Firstly, the individual fast components must have their private memory, coupled with one or more processors: without a private memory they will not be able to work on their own for a considerable number of microseconds.
Secondly, we shall have to arrange the co-operation between these components, and this will minimally imply an information traffic between these components. The actions taking place in this co-operation must correspond to a much coarser grain of time.

In order to visualize this thing a little bit more clearly, I have been thinking about a number of fast components grouped a round a centre. This centre should have a great amount of store and it should have logic. I assume that bulk information traffic from one component to another will always take place via the centre, I have verified that a single centre can be coupled to a number of mutually asynchronized components. It is particularly simple if we conceive the components as being in one of two mutually exclusive states, either working, independently and geared to the clock of the centre, that probably must be able to maintain a number of communications simultaneously, say word wise merged. Information traffic from centre to component is the easiest of the two: the centre will only send it when the component is standby available to receive it and the centre should send it not too fast (or in the case of conflict at the centre side) slower. Information traffic in the other direction requires a signal from the centre to the component, that the centre is ready to accept along that channel the next information unit. If the channel has such a long delay, that its capacity slows down, then I presume a private buffer at the centre end of the channel. All this can be done if necessary, the main thing to take care of is to avoid urgency situations as may arise due to causes of combinatorics, i.e. where a number of channels share the same memory and its access mechanism. (In the above picture the receiving component is faced with an urgency situation, but that is not too bad, for the component has nothing else to do and is "standing by".)

The potential advantage of such a configuration would be, that configuration extension with some more components should not be the cause of a major software revision. A consequence is that the total work load is presented to the machine in such a way, that the possibility of parallellism is given and need not be detected.

Previous experiences seem to indicate that in the mutual synchronization of sequential processes we have two distinct, and in a sense complementary, aspects. On the one hand we have the critical sections, of which we only know, that they exclude each other in time, but where we do not define any priority rules; total time spent in critical sections must be such a small fraction of real time that the queuing strategy can be regarded as irrelevant. With an implementation for critical sections and the notion of the private semaphore for each sequential process, we can implement whatever strategy we want.

This knowledge may give a hint how the system should be divided over hardware and software and what should take place in the centre and what in the components. At least a hint as to what is attractive from a logical point of view.

My present hope is the following.

All processing, also the execution of "systems program" in critical sections will be done by the components. The centre is fairly neutral (although its logic will be programmed it will be a special purpose device) but caters for mutual exclusion automatically. I hope that the mutual exclusions needed can be coupled to the accessibility claim towards a certain amount of information.

It is obviously associated with the state of embedding of a sequential process: if a process operates on its private variables only, as long as it moves in its own state space, then this process together with the variables being the coordinates in this state space, can be delegated for the time being to one of the components (having processor and store). As soon as communication with the outer world implies operating on "common variables", then also these common variables must be sent to the component, and therefore cannot be somewhere else. But these are exactly the critical sections: one of the processes claims and gets privilege to inspect and modify in a universe it shares with others.

In our present multiprogramming system we have at bottom level the task of processor allocation; if we follow an analogous approach we should here the task of "component allocation"; logically speaking one should expect the implementation of the component allocation in the centre. The little experience we have has not yet belied our assumption that the problem of processor allocation is relatively trivial and it is conceivable that a non-sophisticated standard solution, implemented in the centre, will indeed do the job of component allocation.

Warning. Here I must be very careful not to make too hasty an extrapolation. In our present environment processor reallocation does not imply extensive moving around of bulk information. In the case of component allocation this will no longer hold. So maybe the centre will have more refined logic (of a special component, put aside permanently, to do with scheduling job).

transcribed by Andreas Jonsson
revised Sat, 16 Oct 2004

EWD209

A Constructive Approach to the Problem of Program Correctness.

Summary.

As an alternative to methods by which the correctness of given programs can be established a posteriori, this paper proposes to control the process of program generation such as to produce a priori correct programs. An example is treated to show the form that such a control then might take. This example comes from the field of parallel programming; the way in which it is treated is representative for the way in which a whole multiprogramming system has actually been contstructed.

Introduction.

The more ambitious we become in our machine applications, the more vital becomes the problem of program correctness. The growing attention being paid to this problem is therefore a quite natural and sound development. As far as I am aware, however, the problem has been tackled, posed roughly in the following form: "Given an algorithm and given specifications of its desired dynamic behaviour, prove then that the dynamic behaviour of the given algorithm meets the given specifications." After sufficient formalization of the way in which the algorithm and specifications are given, we are faced with a well-posed problem that is apparently not without mathematical appeal.

In this paper I shall tackle the problem from the other side: "Given the specifications of the desired dynamic behaviour, how do we derive from these an algorithm meeting them in its dynamic behaviour?". For certain mathematical minds the latter problem will be less attractive (for one thing: the algorithm to be desired is not uniquely defined by the specifications given); it seems, however, to be of much greater practical value because, as a rule, we have to construct the algorithm as well.

This paper has been written because the approach seems unusual, while we have followed it very consciously and seem to have done so to our great advantage. We also publish it in the hope that it may serve as a partial answer to the many doubts evoked by our claim to have constructed a multiprogramming system of proven flawlessness.

In this paper I shall illustrate the method by deriving an algorithm meeting very simple specifications, the simplicity being chosen in order to avoid an unneccessarily lengthy paper. In doing so I am running the risk of readers not believing in the practicability of the method when applied to large problems. To those I can only make the following remarks. Firstly, that the art of reasoning to be displayed below is faithfully representative of the way in which we have actually designed a multiprogramming system with fairly refined management rules. Secondly, that it is my firm belief that by consequent application of such methods our ability to deal with large problems will rather increase than decrease. Thirdly, that to anyone who doubts the practicability of the method I can only recommend to try to apply it. Finally, that I know only too well that I can force no one to share my beliefs.

The problem.

For the purpose of demonstration I have chosen the following problem. We consider two parallel, cyclic processes, called "producer" and "consumer" respectively. They are coupled to each other via a buffer (in this example of unlimited capacity) for "portions" of information. Once per cycle the producer puts a next portion into the buffer, once per cycle the consumer takes a portion from the buffer. The buffer is allocated in the universe surrounding the two processes; after introduction and initialization of this universe, the two processes are started in parallel, as indicated below by the bracket pair "parbegin" and "parend". It is also indicated that the activity of the producer as well as the activitiy of the consumer can be regarded in this stage as an alternating succession of two actions. We depart in our example from the (hopefully now self-explanatory) structure given below; here the actions invoked are to be considered as available primitives.

begin initialize an empty buffer;
    parbegin
producer: begin local initialization of the producer;
            P1: produce next portion locally;
            P2: put portion into buffer;
                goto P1
          end;
consumer: begin local initialization of the consumer;
            C1: take portion from buffer;
            C2: consume new portion locally;
                goto C1
          end
    parend
end

For the proper co-operation of the two processes as described above we must assume an implicit synchronization, preventing the consumer to try to take a portion from an empty buffer. In the following we shall refuse to make any assumptions about the speed ratio of the two processes and our task is to program the synchronization between the two processes explicitly. (The synchronizing primitives I intend to use for this solution will be described in due time.)

Note. For brevity I omit the proof —although for this simple example not too difficult— that the above problem is well-posed in the sense that a synchronization satisfying the above requirement does not contain the danger of the so-called "deadly embrace", i.e. one or more processes getting irrevocably stuck because they are waiting for each other. I do so because this proof is more concerned with the problem as posed than with the task of programming it and the latter is the true subject of this paper.

Formalization of the required dynamic behaviour.

Our first step is the introduction of suitable variables in terms of which we can give a more formal description of the specification of the required dynamic behaviour. Obviously, the number of portions in the buffer is a vital quantity. Therefore we introduce an integer variable, n say, whose value has to equal the number of portions in the buffer. The rule to be followed this time is particularly simple: first, initialize the value of n together with the initialization of the buffer, so that the relation

n = number of portions in the buffer | (1)

is satisfied to start with. From then onwards, adjust the value of the variable called "n" whenever the number of portions in the buffer is changed, i.e. at putting a portion into it or taking a portion from it. As a result the relation (1) will always be satisfied.

From now onwards the three actions initializing or changing the buffer contents are regarded as actions including the proper operation on the variable called "n". To indicate this, we may write Version 1:

begin integer n;
      initialize an empty buffer including "n := 0";
   parbegin
producer: begin local initialization of the producer;
            P1: produce next portion locally;
            P2: put portion into buffer including "n := n + 1";
                goto P1
          end;
consumer: begin local initialization of the consumer;
          C1: take portion from buffer including "n := n - 1";
          C2: consume new portion locally;
              goto C1
          end
   parend
end

Thus we have achieved that the specification of the dynamic behaviour can be formulated by the requirement that the inequality

n ≥ 0 | (2)

will always be satisfied.

(Remark. It may well be, that already in the transition from the original version to Version 1 we can observe one of the origins of the efficiency of the constructive approach. If we did regard the Version 1 as given and wanted to identify the current value of n with the current number of portions in the buffer, we would have to observe its initialization and its adjustments, but in excess to this we would have to read the whole program in order to verify that no other operations on it can occur.)

Analysis of the formalized requirements.

We now proceed from Version 1 and requirement (2). The latter requirement is satisfied by the universe as initialized, we have only to synchronize the two processes in such a way that it remains satisfied.

From the fact that requirement (2) concerns the value of the variable called "n" only, it follows that the processes can only effectuate violation by acting on this variable, i.e. only via the actions labelled "P2" and "C1" respectively. Closer inspection of the requirement ("n ≥ 0") and the actions show that the action labelled "P2" (including "n := n + 1") is quite harmless, because

n ≥ 0 implies n + 1 ≥ 0,

but that the action labelled "C1" (including "n := n-1") may indeed cause a violation. More precisely, as

n ≥ 1 implies n - 1 ≥ 0,

the action labelled "C1" is harmless when initiated with

n ≥ 1 | (3)

while with n = 0 it would cause violation; under the latter circumstance it has to be postponed.

(Remark. Our last conclusion is, that the only possible harm is trying to make the buffer more empty than empty. Its obviousness here is a direct consequence of the simplicity of this example. The point is, that this conclusion could be reached by inspection of the formalized requirement (2) and the operations on the variables concerned. In the case of a more refined management, the requirements analogous to (2) are no longer a simple inequalilty and their analysis will really tell you the danger points.)

Consequence of the preceding analysis; the unstable situation.

In the previous section we have concluded that the action labelled "C1" is the only danger point. Having here only one consumer, we could have solved the problem logically by inserting just in front of it a wait cycle

C0: if n = 0 then goto C0

but we refused to implement this busy form of waiting, because in a multiprogrammed environment it seems a waste to spend central processor time on a process that has already established that for the time being it cannot go on. Therefore we have implemented means —viz. the synchronizing primitives— by which a process can go to sleep until further notice (a sleeping process being by definition no candidate for processor time), leaving of course to the other processes the obligation to give this "further notice" in due time. This is so closely analogous to usual optimizing techniques that I proceed with this multiprogramming example in full confidence that the uniprogrammer will be able to apply similar considerations to his own tasks.

We see ourselves faced with the decision whether the action labelled "C1" should take place or not. Earlier we have seen that this decision depends on the current value of the variable called "n". Recently we have seen that under certain curcumstances we refuse to regard this as a private decision of the consumer (this would imply the busy form of waiting) but wish to delegate it (via the mechanism of the further notice) to the producer. As long as it was a private decision of the consumer, inserting it at the right plalce in the consumer's text was a sufficient means to ensure that the decision was taken in accordance with the dynamic progress of the consumer. As soon as this decision may be taken by another process —here by the producer— the dynamic progress of the consumer becomes a question of general interest, in particular whether the consumer is ready to perform the action labelled "C1". We introduce a boolean variable, called "hungry" whose value has to indicate explicitly that the consumer's progress has reached the stage that the decision to execute or to postpone the action labelled "C1" is relevant.

To ensure that the variable called "hungry" has this meaning, we must

1)    insert within the consumer's cycle the assignment "hungry := true" just in front of the statement labelled "C1";

2)    include the assignment "hungry := false" as part of the action labelled "C1";

3)    initialize in the universe the variable called "hungry" in accordance with the starting point in the consumer's cycle.

The variable called "hungry" is an explicit coding of the consumer's progress, analogous to the variable called "n", an explicit coding of the number of portions in the buffer. We arrive at Version 2:

begin integer n; Boolean hungry;
      initialize an empty buffer including "n := 0";
      hungry := false;
   parbegin
producer: begin local initialization of the producer;
            P1: produce next portion locally;
            P2: put portion into buffer including "n := n + 1";
                goto P1
          end;
consumer: begin local initialization of consumer;
            C0: hungry := true;
            C1: take portion from buffer including "n := n - 1"
                  and "hungry := false";
            C2: consume new portion locally;
                goto C0
          end
   parend
end

From relation (3) and the meaning of the variable called "hungry" we now deduce that the action labelled "C1" should take place whenever

n ≥ 1 and hungry | (4)

becomes true, the action labelled "C1" itself causing (4) to become false again. In other words: we must see to it that (4) characterizes what we could call "an unstable situation", for as soon as it emerges it should be resolved by the action labelled "C1".

Having no permanently active observer that will give alarm whenever the unstable situation arises, we must allocate the inspection for the unstable situation (and if found its subsequent resolution by action "C1") somewhere in the sequential processes. The necessary and sufficient measure is to attach this inspection as an appendix to each action that may have generated the unstable situation from a stable one, pinning the responsibility to resolve the unstable situation down on the process that has generated it.

Some elementary logic applied to (4) tells us that this transition can only be effected by an action assigning the value true to the variable called "hungry" or by an action increasing the value of the variable called "n" (or by an action doing both, not occurring in this example). In terms of Version 2: the instability may be reached as a result of the action labelled "C0" (on account of "hungry := true") and by the action labelled "P2" (on account of "n := n + 1"). So the action labelled "P2" 𠅊llocated in the producer— might get attached to it as an appendix the action labelled "C1", originally allocated in the consumer!

At this stage of the discussion we must insert an interlude that has nothing to do with this particular problem, nor with the main train of thought of this paper. The interlude is inserted because I expect many a reader to be unfamiliar with the basic problems of programming parallel processes, a field from which our example happens to have been taken.

Interlude on synchronizing primitives.

We need primitives to control that processes may go to sleep or may be woken up. For the purposes of this we introduce

1)    special purpose binary valued variables, called "semaphores". A semaphore may have the values 0 and 1. Semaphores are allocated in the surrounding universe and are initialized before the parallel processes are started.

2)    two special operations, called the P- and V-operation respectively.

The P-operation on a semaphore can only be completed at a moment that the semaphore value equals 1. Its completion implies that the semaphore value is reset to 0. If a process initiates a P-operation on a semaphore with at that moment a value equal to 0, "the process goes to sleep, the P-operation remains pending on this semaphore".

The V-operation on a semaphore is only defined if its initial value equals 0. It will then set the semaphore to 1. If no P-operation is pending on this semaphore the V-operation has no further effect. If one or more P-operations are pending on it, the V-operation will have the further effect that exactly one of the pending P-operations will be completed (thereby resetting the semaphore to the value 0), i.e. the process in which this P-operation occurred is woken up again.

As a result a semaphore value equal to 1 implies that there are at that moment no P-operations pending on it.

The semaphores are used for two entirely distinct purposes; both standard usages will occur in the example.

On the one hand we have the so-called "private semaphores" each belonging to a specific sequential process, that will be the only one to perform a P-operation on it, viz. where the process might need to be delayed until some event has occurred: the semaphore values 0 and 1 at the initiation of the P-operation represent the situation that the event in question has not yet or has already occurred. As a rule the universe initiates private semaphores with the value 0.

On the other hand we have the semaphore(s) used for the implementation of so-called "critical sections", the executions of which have to exclude each other in time. Such critical sections can be implemented by opening them with a P-operation and closing them with a V-operation, all on the same semaphore with initial value 1. At each moment the value of such a semaphore for mutual exclusion equals the number of processes allowed to enter a section critical to it. The purpose of critical sections is to cater for unambiguous modification and interpretation of universal variables (such as "n" and "hungry" in our example).

Alternatively: at a certain level of abstraction we can visualize a single sequential process as a succession of "immediate actions"; the time taken to perform them is logically immaterial, only the states (as given by the values of the variables) observable in between the actions have on that level a logical significance. It is only when we shift to a lower level of abstraction and implement the actions themselves by means of (smaller) sequential sub-processes, that the intermediate states as well as their periods of execution enter the picture. And it is only at this lower level that "mutual exclusion in time" has a significance. In a single sequential process successive actions (now regarded as sub-processes) exclude each other in time automatically, because the next one will only be initiated after the preceding has been completed. In multiprogramming the mutual exclusion at the lower level of abstraction is no longer automatically guaranteed and the fact that on the higher level we regard them as single "immediate actions" requires then explicit recognition. This is exactly what the critical sections cater for.

Resolution of the unstable situation and synchronization of the processes.

Our analysis of the unstable situation ended with the conclusion that the action labelled "C1", originally allocated in the consumer, will be attached as a conditional appendix to the actions labelled "C0" and "P2" respectively, to the ones that might generate the unstable situation.

To pin the responsibility for the resolution of the unstable situation down on the process that has generated it, the latter one must be uniquely defined (which is not the case if the effective assignments "n := 1" as part of P2 and "hungry := true" as part of C0 are allowed to take place simultaneously) and it must have resolved the unstable situation before the other process may have discovered it. In other words, creation of the unstable situation and its subsequent resolution must be regarded as a single "immediate action" in the sense of the last paragraph of the interlude. We shall implement them by critical sections controlled by a semaphore, "mutex" say, that will be initialized with the value 1.

Finally, in Version 2 the sequential nature of the consumer guaranteed that each execution of the action labelled "C2" would be preceded by one execution of the action labelled "C1". This implicit sequencing can be made explicit with the aid of a private semaphore of the consumer, "consem" say (to be initialized with the value 0) by concluding the action labelled "C1" with "V(consem)" and opening the action labelled "C2" with "P(consem)". The sequencing has to be made explicit because the action labelled "C1" may now occur as an activity of the producer.

After these considerations the final version of the program is given. For reasons of clarity and economy (of writing and thinking) the action labelled "C1" has been included in the body of a procedure declared in the universe.

Final Version:

begin integer n; Boolean hungry; semaphore mutex, consem;
      procedure resolve instability if present;
      begin if n >= 1 and hungry then
            begin take portion from buffer; n := n - 1;
                  hungry := false; V(consem)
            end
      end;
      initialize buffer; n := 0;
      hungry := false; mutex := 1; consem := 0;
   parbegin
producer: begin local initialization of producer;
            P1: produce next portion locally;
            P2: P(mutex);
                put portion into buffer; n := n + 1;
                resolve instability if present
                V(mutex);
                goto P1
            end;
consumer: begin local initialization of consumer;
            C0: P(mutex);
                hungry := true; resolve instability if present;
                V(mutex);
            C2: P(consem); consume new portion locally;
                goto C0
          end
   parend
end

The above is as faithful a reproduction as I can give of the kind of reasoning we applied in the construction of a multiprogrammng system, be it that it has been interlaced with explanatory paragraphs, covering the insights we had already gained at an earlier stage just by thinking about the problems involved in the programming of parallel processes. (At that stage, for instance, the semaphores were born.) At the end, when we were all familiar with this type of problem, the reasoning needed to derive the program from specifications much more complicated than the present example, used to be given on a single page or less.

Concluding remarks.

Firstly, one can remark that I have not done much more than to make explicit what the sure and competent programmer has already done for years, be it mostly intuitively and unconsciously. I admit so, but without any shame: making his behaviour conscious and explicit seems a relevant step in the process of transforming the Art of Programming into the Science of Programming. My point is that this reasoning can and should be done explicitly.

Secondly, I should like to stress that by using the verb "to derive" I do not intend to suggest any form of automatism, nor to underestimate the amount of mathematical invention involved in all non-trivial programming. (On the contrary!) But I do suggest the constructive approach sketched in this paper as an accompanying justification of his inventions, as a tool to check during the process of invention that he is not led astray, as a reliable and inspiring guide.

Thirdly, I am fully aware that the style of reasoning I have applied, though possibly appealing to some, might easily appall others. For this difference in taste I blame them as little as they should blame me. I can only hope that they will find a way to follow the constructive approach in a style satisfying to them.

Finally, I should like to point out that the constructive approach to program correctness sheds some new light on the debugging problem. Personally I cannot refrain from feeling that many debugging aids that are en vogue now are invented as a compensation for the shortcomings of a programming technique that will be denounced as obsolete within the near future.

Acknowledgements.

Acknowledgements are due to my closest collaborators C.Bron, A.N.Habermann, F.J.A.Hendriks, C.Ligtmans and P.A.Voorhoeve, for by working in the way they did they convinced me of the practicability of the constructive approach when faced with a large problem.

Acknowledgements are also due —although they may be unaware of the fact— to Peter Naur and my colleague Gerhard W. Veltkamp. To the first one because he convinced me that something should and could be done regarding program correctness, to the second one for his inspiring faith in my efforts, his patience when listening to me and his unrelenting pityless criticism whenever I indulged in disguising sloppy reasoning by means of a verbal show.

Eindhoven, August 1967

transcribed by Saleem Shafi
revised Thu, 13 Nov 2008

EWD 209A

Copyright Notice

The manuscript
        EWD 209A: A Constructive Approach to the Problem of Program Correctness
was published as
       BIT8 (1968): 174–186.
It is reproduced here by permission.

A Constructive Approach to the Problem of Program Correctness.

Summary. As an alternative to methods by which the correctness of given programs can be established a posteriori, this paper proposes to control the process of program generation such as to produce a priori correct programs. An example is treated to show the form that such a control might then take. This example comes from the field of parallel programming; the way in which it is treated is representative of the way in which a whole multiprogramming system has actually been constructed.

1. Introduction.

The more ambitious we become in our machine applications, the more vital becomes the problem of program correctness. The growing attention being paid to this problem is therefore a quite natural and sound development. As far as I am aware (see[1],[2],[3]), however, the problem has been tackled, posed roughly in the following form: “Given an algorithm and given specifications of its desired dynamic behaviour, prove then that the dynamic behaviour of the given algorithm meets the given specifications.” After sufficient formalization of the way in which the algorithm and specifications are given, we are faced with a well-posed problem that is apparently not without mathematical appeal.

In this paper I shall tackle the problem from the other side: “Given the specifications of the desired dynamic behaviour, how do we derive from these an algorithm meeting them in its dynamic behaviour?” For certain mathematical minds the latter problem will be less attractive (for one thing: the algorithm to be derived is not uniquely defined by the specifications given); it seems, however, to be of much greater practical value because, as a rule, we have to construct the algorithm as well.

This paper has been written because the approach seems unusual, while we have followed it very consciously and seem to have done so to our great advantage. We also publish it in the hope that it may serve as a partial answer to the many doubts evoked by our claim to have constructed a multiprogramming system of proven flawlessness.

In this paper I shall illustrate the method by deriving an algorithm meeting very simple specifications, whose simplicity has been chosen in order to avoid an unnecessarily lengthy paper. In doing so I am running the risk of readers not believing in the practicability of the method when applied to large problems. To those I can only make the following remarks. First, that the art of reasoning to be displayed below is faithfully representative of the way in which we have actually designed a multiprogramming system with fairly refined management rules. Second, that it is my firm belief that by consistent application of such methods our ability to deal with large problems will rather increase than decrease. Third, that to anyone who doubts the practicability of the method I can only recommend to try to apply it. Finally, that I know only too well that I can force no one to share my beliefs.

(The chosen problem is a synchronization problem of the type as encountered in multiprogramming. Many of my readers will be unfamiliar with this type of problem and the article may therefore strike them as two articles merged into one: one dealing with multiprogramming and another dealing with the constructive approach. This shortcoming of the paper has been pointed out to me by various unofficial referees of its preliminary version: I agree with their criticism and apologize to my readers. I have, however, stuck to my multiprogramming example, for the general reader’s unfamiliarity gives me a unique opportunity to illustrate the approach by treating a simple example, the solution of which is not immediately obvious to everyone. And this, I feel, illustrates the power of the approach more convincingly than treating a traditional problem.)

2. The problem.

For the purpose of demonstration I have chosen the following problem. We consider two parallel, cyclic processes, called “producer” and “consumer” respectively. They are coupled to each other via a buffer (in this example of unlimited capacity) for “portions” of information. In each of its cycles the producer puts a next portion into the buffer, in each of its cycles the consumer takes a portion from the buffer. The buffer is allocated in the universe surrounding the two processes; after introduction and initiation of this universe, the two processes are started in parallel, as indicated below by the bracket pair “parbegin” and “parend”. It is also indicated that the activity of the producer as well as the activity of the consumer can be regarded at this stage as an alternating succession of two actions. It is understood that the actions labelled P1 (i.e. actual production) and C2 (i.e. actual consumption) are the time-consuming actions (probably synchronized to other processes) of which the possibility of parallel execution is of actual interest, while the actions labelled P2 and C1, in which portions are transmitted into or from the buffer (the only ones in which reference to the common buffer is made) will be very concise actions (some bookkeeping with pointers and links, say), the potential parallelism of which can be discarded if desired. We depart in our example from the (hopefully now self-explanatory) structure given below; here the actions invoked are to be considered as available primitives.

Version 0:

begin initiate an empty buffer;
   parbegin
producer: begin local initiation of the producer;
            P1: produce next portion locally;
            P2: transmit portion into the buffer;
            goto P1
          end;
consumer: begin local initiation of the consumer;
            C1: transmit portion from buffer;
            C2: consume new portion locally;
            goto C1
          end
   parend
end

For the proper co-operation of the two processes as described above we must assume an implicit synchronization, preventing the consumer to try to take a portion from an empty buffer. In the following we shall refuse to make any assumptions about the speed ratio of the two processes and our task is to program the synchronization between the two processes explicitly. (The synchronizing primitives I intend to use for this solution will be described in due time.)

Note. For brevity I omit the proof �although for this simple example not too difficult— that the above problem is well-posed in the sense that a synchronization satisfying the above requirement does not contain the danger of the so-called "deadly embrace", i.e. one or more processes getting irrevocably stuck because they are waiting for each other. I do so because this proof is more concerned with the problem as posed than with the task of programming it and the latter is the true subject of this paper.

3. Formalization of the required dynamic behaviour.

Our first step is the introduction of suitable variables in terms of which we can give a more formal description of the specification of the required dynamic behaviour. As stated, the consumer should behave in such a way that it does not try to take a portion from an empty buffer. The first question is: how do we keep track of its emptyness? As a result of transmitting a portion into the buffer, the buffer becomes non-empty, as a result of transmitting a portion from the buffer the latter only becomes empty if its last and only portion has been taken from it. In other words, we can keep track of its emptyness (i.e. the buffer contains zero portions) provided that we can answer the question whether the (non-empty) buffer contains exactly 1 portion. Repeating the argument we conclude that the number of portions in the buffer is a vital quantity. Therefore we introduce an integer variable, “n” say, whose value has to equal the number of portions in the buffer. The rule to be followed this time is particularly simple: first, initiate the value of “n” together with the initiation of the buffer, so that the relation

| "n = number of portions in the buffer" | (1)

is satisfied to start with. From then onwards, adjust the value of the variable called “n” whenever the number of portions in the buffer is changed, i.e. when transmitting a portion into it or from it. As a result the relation (1) will be always satisfied.

From now onwards the three actions initiating or changing the buffer contents are regarded as actions including the proper operation on the variable called “n”. To indicate this, we may write Version 1:

begin integer n;
       initiate an empty buffer including "n:= 0";
  parbegin
producer: begin local initiation of the producer;
           P1: produce next portion locally;
           P2: transmit portion into the buffer including "n:= n + 1";
               goto P1
          end;
consumer: begin local initiation of the consumer;
           C1: transmit portion from buffer including "n:=n - 1";
           C2: consume new portion locally;
               goto C1                                    
          end
  parend
end

Thus we have achieved that the specification of the dynamic behaviour can be formulated by the requirement that the inequality

| n ≥ 0 | (2)

will always be satisfied.

(Remark. It may well be, that already in the transition from the original Version 0 to Version 1 we can observe one of the origins of the efficiency of the constructive approach. If we had regarded the Version 1 as given but in addition to this wanted to identify the current value of n with the current number of portions in the buffer, we would have to observe its initiation and its adjustments, but in excess to this we would have to read the whole program in order to verify that no other operations on it can occur, while we, however, exploit the given fact that the actions labelled P1 and C2 by definition do not refer to the buffer.)

4. Analysis of the formalized requirements.

We now proceed from Version 1 and requirement (2). The latter requirement is satisfied initially; we have only to synchronize the two processes in such a way that it remains satisfied.

From the fact that requirement (2) concerns the value of the variable called "n" only, it follows that the processes can only cause violation by acting on this variable, i.e. only via the actions labelled "P2" and "C1" respectively. Closer inspection of the requirement ("n ≥ 0") and the actions shows that the action labelled "P2" (including "n:= n + 1") is quite harmless, because

               n ≥ 0 implies   n+1 ≥ 0    ,

but that the action labelled "C1" (including "n:= n - 1") may indeed cause a violation. More precisely, as

               n ≥ 1 implies n-1 ≥ 0  ,

the action labelled "C1" is harmless when initiated when

| n ≥ 1 | (3)

while when n = 0 it would cause violation; under the latter circumstance it has to be postponed.

(Remark. Our last conclusion is, that the only possible harm is trying to make the buffer more empty than empty. Its obviousness here is a direct consequence of the simplicity of this example. The point is, that this conclusion could be reached by inspection of the formalized requirement (2) and the operations on the variables concerned. In the case of a more refined management, the requirements analogous to (2) are no longer a simple inequality and their analysis will really tell you all the danger points.)

5. Consequence of the preceding analysis; the unstable situation.

In the previous section we have concluded that the action labelled "C1" is the only danger point. Having here only one consumer, we could have solved the problem logically by inserting just in front of it a wait cycle

     "C0: if n = O then goto C0" 

but we refused to implement this busy form of waiting, because in a multiprogrammed environment it seems a waste to spend central processor time on a process that has already established that for the time being it cannot go on; furthermore this solution does not admit a straightforward generalization to, say, more consumers.. Therefore we have implemented means —viz. the synchronizing primitives— by which a process can go to sleep until further notice (a sleeping process being by definition no candidate for processor time), leaving of course to the other processes the obligation to give this “further notice” in due time. This is so closely analogous to usual optimizing techniques that I proceed with this multiprogramming example in full confidence that the uniprogrammer will be able to apply similar considerations to his own tasks.

We see ourselves faced with the decision whether the action labelled “C1” should take place or not. Earlier we have seen that this decision depends on the current value of the variable called “n”. Recently we have seen that under certain circumstances we refuse to regard this as a private decision of the consumer (this would imply the busy form of waiting) but wish to delegate it (via the mechanism of the further notice) to the producer. As long as it was a private decision of the consumer, inserting it at the right place in the consumer’s text was a sufficient means to ensure that the decision was taken in accordance with the dynamic progress of the consumer. As soon as this decision might be taken by another process —in this example by the producer— the dynamic progress of the consumer becomes a question of general interest, in particular whether the consumer is ready for the next action labelled C1. We introduce a boolean variable, called “hungry” whose value has to indicate explicitly that the consumer's progress has reached the stage that the decision to execute or to postpone the action labelled “C1” is relevant.

To ensure that the variable called “hungry” has this meaning, we must
1) insert within the consumer's cycle the assignment “hungry:= true” just in front of the statement labelled “C1”;
2) include the assignment “hungry:= false” as part of the action labelled “C1”;
3) initiate in the universe the variable called “hungry” in accordance with the starting point in the consumer’s cycle.

The variable called “hungry” is an explicit coding of the consumer’s progress, analogous to the variable called “n”, introduced as an explicit coding of the number of portions in the buffer. We arrive at Version 2:

begin integer n; Boolean hungry;
      initiate an empty buffer including "n:= 0";
      hungry := false;
   parbegin
producer: begin local initiation of the producer;
            P1: produce next portion locally;
            P2: transmit portion into the buffer including "n:= n + 1";
                goto P1
          end;
consumer: begin local initiation of the consumer;
            C0: hungry:= true;
            C1: transmit portion from buffer including "n:= n � 1" and
                                 "hungry:= false";
            C2: consume new portion locally;
                goto C0
          end
   parend
end

From relation (3) and the meaning of the variable called “hungry” we now deduce that the action labelled “C1” should take place whenever

| n ≥ 1 and hungry | (4)

becomes true, the action labelled “C1” itself causing (4) to become false again. In other words: we must see to it that (4) characterizes what we could call “an unstable situation”, for as soon as it emerges it should be resolved by the action labelled “C1”.

Having no permanently active observer that will give alarm whenever the unstable situation arises, we must allocate the inspection for the unstable situation (and, if found, its subsequent resolution by action “C1”) somewhere in the sequential processes. The necessary and sufficient measure is to attach this inspection as an appendix to each action that may have generated the unstable situation from a stable one, thus pinning the responsibility to resolve the unstable situation down to the process that has generated it.

Some elementary logic applied to (4) tells us that this transition can only be effected by an action assigning the value true to the variable called “hungry” or by an action increasing the value of the variable called “n” (or by an action doing both, not occurring in this example). In terms of Version 2: the instability may be reached as a result of the action labelled “C0” (on account of “hungry:= true”) and of the action labelled “P2” (on account of “n := n + 1”). So the action labelled “P2” —allocated in the producer— might get attached to it as a appendix the action labelled “C1”, originally allocated in consumer!

6. Interlude on synchronizinq primitives.

At this stage of the discussion we must insert an interlude that has nothing to do with this particular problem, nor with the main train of thought of this paper The interlude has been inserted because I expect many a reader to be unfamiliar with the basic problems of programming parallel processes, the field from which our example happens to have been taken.

We need primitives to control that processes may go to sleep or may be woken up. For this purpose we introduce
1) special purpose binary valued variables, called “semaphores”. A semaphore may have the values 0 and 1. Semaphores are allocated in the surrounding universe and are initiated before the parallel processes are started. (Semaphores can be (and have been) generalized from two-valued quantities to non-negative integers. In this article we do not do so, for our example is so simple that the generalized semaphore would provide a ready made solution!)
2) two special operations, called the P- and the V-operation respectively. The parallel processes shall access the semaphores via these operations only.

The P-operation on a semaphore can only be completed at a moment that the semaphore value equals 1. Its completion implies that the semaphore value is reset to 0. If a process initiates a P-operation on a semaphore with at that moment a value equal to 0, “the process goes to sleep, the P-operation remains pending on this semaphore”.

The V-operation on a semaphore is only defined if its initial value equals 0. It will then set the semaphore to 1. If no P-operation is pending on this semaphore the V-operation has no further effect. If one or more P-operations are pending on it, the V-operation will have the further effect that exactly one of the pending P-operations will be completed (thereby resetting the semaphore to the value 0), i.e. the process in which this P-operation occurred is woken up again.

As a result a semaphore value equal to 1 implies that there are at that moment no P-operations pending on it.

The semaphores are used for two entirely distinct purposes; both standard usages will occur in the example.

On the one hand we have the so-called “private semaphores”, each belonging to a specific sequential process, that will be the only one to perform a P-operation on it, viz. where the process might need to be delayed until some event has occurred: the semaphore values 0 and 1 at the initiation of the P-operation represent the situation that the event in question has not yet or has already occurred. As a rule the universe initiates private semaphores with the value 0.

On the other hand we have the semaphore(s) used for the implementation of so-called “critical sections”, the executions of which have to exclude each other in time. Such critical sections can be implemented by opening them with a P-operation and closing them with a V-operation, all on the same semaphore with initial value 1. At each moment the value of such a semaphore for mutual exclusion equals the number of processes allowed to enter a section critical to it. The purpose of critical sections is to cater for unambiguous modification and interpretation of universal variables (such as “n” and “hungry” in our example).

Alternatively: at a certain level of abstraction we can visualize a single sequential process as a succession of “immediate actions”; the time taken to perform them is logically immaterial, only the states (as given by the values of the variables) observable in between the actions have on that level a logical significance. It is only when we shift to a lower level of abstraction and implement the actions themselves by means of (smaller) sequential sub-processes that the intermediate states as well as their periods of execution enter the picture. And it is only at this lower level that “mutual exclusion in time” has a significance. In a single sequential process successive actions (now regarded as sub-processes) exclude each other in time automatically, because the next one will only be initiated after the preceding one has been completed. In multiprogramming the mutual exclusion at the lower level of abstraction is no longer automatically guaranteed and the fact that on the higher level we regard them as single “immediate actions” requires then explicit recognition. This is exactly what the critical sections cater for.

7. Resolution of the unstable situation and synchronization of the processes.

Our analysis of the unstable situation ended with the conclusion that the action labelled “C1”, originally allocated in the consumer, will be attached as a conditional appendix to the actions labelled “C0” and “P2” respectively,to the ones that might generate the unstable situation.

To pin the responsibility for the resolution of the unstable situation down to the process that has generated it, the latter one must be uniquely defined (which is not the case if the effective assignments “n:= 1” as part of P2 and “hungry:= true” as part of C0 are allowed to take place simultaneously) and it must have resolved the unstable situation before the other process may have discovered it. In other words, creation of the unstable situation and its subsequent resolution must be regarded as a single “immediate action” in the sense of the last paragraph of the interlude. We shall implement them by critical sections controlled by a semaphore, “mutex” say, that will be initiated with the value 1.

Finally, in Version 2 the sequential nature of the consumer guaranteed that execution of the action labelled “C2” would be preceded by one execution of action labelled “C1”. This implicit sequencing can be made explicit with the aid of a private semaphore of the consumer, “consem” say, (to be initiated with the value 0) by concluding the action labelled “C1” with “V(consem)” and opening the action labelled “C2” with “P(consem)”. The sequencing has to be made explicit because the action labelled “C1” may now occur as an activity of the producer.

After these considerations the final version of the program is given. For reasons of clarity and economy (of writing and thinking) the action labelled “C1” has been included in the body of a procedure declared in the universe.

Note 1. The program given below does not pretend to be the only, or the best or the most economical solution. It pretends to be a correct solution. It is general in the sense that more complicated similar problems can be solved along the same pattern.

Note 2. As announced (in section 2) the potential parallelism of the action "transmit portion into the buffer" and "transmit portion from buffer" would would be discarded if desired. This indeed has happened, as the actions only occur within critical sections. The generalization to more producers, more consuners etc. is now straightforward.

Note 3. The step from Version 2 to the Final Version is rather large: for various unofficial referees of the preliminary version of this paper the Final Version still came straight from "The Magician's Box". I can understand their feelings, I have not succeeded in remedying the situation, "in buffering the shack of invention".

Final Version:

begin integer n; Boolean hungry;semaphore mutex, consem;
      procedure resolve instability if present;
      begin if n ≥ 1 and hungry then
            begin transmit portion from buffer; n:= n - 1;
                  hungry:= false; V(consem)
            end
      end;
      initiate an empty buffer; n:= 0;
      hungry := false; mutex:= 1; consem:= 0;
   parbegin
producer: begin local initiation of the producer;
            P1: produce next portion locally;
            P2: P(mutex);
                transmit portion into the buffer; n:= n + 1;
                resolve instability if present;
                V(mutex);
                goto P1
          end;
consumer: begin local initiation of the consumer;
            C0: P(mutex);
                hungry:= true; resolve instability if present;
                V(mutex);
            C2: P(consem);consume new portion locally;
                goto C0
          end
   parend
end

The above is as faithful a reproduction as I can give ot the kind of reasoning we applied in the construction of a multiprogramming system, albeit interlaced with explanatory paragraphs, covering the insights we had already gained at an earlier stage by just thinking about the problems involved in the programming of parallel processes. At the end, when we were all familiar with this type of problem, the reasoning needed to derive the program from specifications much more complicated than the present example, used to be given on a single page or less.

8. Concluding remarks.

First, one can remark that I have not done much more than to make explicit what the sure and competent programmer has already done for years, be it mostly intuitively and unconsciously. I admit so, but without any shame: making his behaviour conscious and explicit seems a relevant step in the process of transforming the Art of Programming into the Science of Programming. My point is that this reasoning can and should be done explicitly.

Second, I should like to stress that by using the verb “to derive” I do not intend to suggest any form of automatism, nor to underestimate the amount of mathematical invention involved in all non-trivial programming (On the contrary!) But I do suggest the constructive approach sketched in this paper as an accompanying justification of his inventions, as a tool to check during the process of invention that he is not being lead astray, as a reliable and inspiring guide.

Third, I am fully aware that the style of reasoning I have applied, though possibly appealing to some, might easily appal others. For this difference in taste I blame them as little as they should blame me. I can only hope that they will find a way to follow the constructive approach in a style satisfactory to them.

Finally, I should like to point out that the constructive approach to program correctness sheds some new light on the debugging problem. Personally I cannot refrain from feeling that many debugging aids that are en vogue now are invented as a compensation for the shortcomings of a programming technique that will be denounced as obsolete within the near future.

Acknowledgements.

Acknowledgements are due to my closest collaborators C.Bron, A.N.Habermann, F.J.A.Hendriks, E.Ligtmans and P.A.Voorhoeve, for by working in the way they did, convinced me of the practicability of the constructive approach when faced with a large problem.

Acknowledgements are also due —although they may be unaware of the fact� to Peter Naur and my colleague Gerhard W.Veltkamp. To the former because he convinced that something should and could be done regarding program correctness, to the latter for his inspiring faith in my efforts, his patience when listening to me and his unrelenting, pityless criticism whenever I indulged in disguising sloppy reasoning by means of a verbal show.

Eindhoven, August 1967 – February 1968

[1] | Robert W.Floyd “Assigning Meanings to Programs” distributed at NATO Summerschool on Programming Languages, Villard-de-Lans (Isere, France) September 1966
[2] | John McCarthy and James Painter “Correctness of a Compiler For Arithmetic Expressions”, Technical Report No CS38, April 29, 1966, Computer Science Department, Stanford University
[3] | Peter Naur “Proof of Algorithms by General Snapshots”, BIT vol.6, 1966 pg. 310 - 316.

Transcribed by Martin van der Burgt
revised 18-May-2017

EWD 214

ACM Symposium in Gatlinburg "Operating Systems Principles".

Het symposium was teleurstellend, omdat het bitter weinig over "principles" ging en meer over "multi-access systems" in het bijzonder dan over "operating systems" in het algemeen. De "invited comments" waren over het algemeen beter dan de officiële bijdragen.

Er waren ongeveer 160 man, uit Zweden (1), uit Duitsland (1), uit Nederland (3), uit Frankrijk (2), uit Engeland (ongeveer 10) en uit de USA. Er waren 17 bijdragen (14 uit de USA, 2 uit Engeland en de mijne).

Uit roddel heb ik veel opgestoken. De grote moeilijkheid voor de Amerikaanse computerindustrie is het exploiteren van intellect, ze doen veel te weinig aan onderzoek. Het zijn Managements Science en de Business Schools, die hiervan de schuld kregen. De enige computerindustrie, die noemenswaard aan onderzoek doet is de IBM, nl. in Yorktown Heights. Tot voor kort was dit een reservaat, waarheen goede mensen van de concurrenctie werden weggezogen, dat voor IBM een statussymbool was, dat verder niet de minste invloed had op de "Company Policy", want die werd gemaakt in Poughkeepsie. Sinds kort is de interne status van Yorktown Heights veranderd in a "Research Division", zulks ten detrimente van het werkklimaat. ("We must now write silly reports for management morons.") General Electric leeft in een soort symbiose met MIT, maar dat is niet erg bevredigend voor GE, die geen kans ziet om de mensen van de campus los te weken. ("You cannot do this kind of work under the management of a man who has been taught how to make washing machines. The best these guys can do is to optimize a steady state solution for a production process; directors fail to see that in our field we just have no steady states...")

De "discussions from the floor" waren doorgaans belabberd, meer dan de helft was commerciële holklap, die inderdaad elke research moet afstoten. Vooral het "IBMerese" was heel erg.

Project MULTICS (GE en MIT samen) is een hoofdstuk apart. Ik herinner me hoe ik gedeprimeerd uit Hongarije terugkwam, ziende hoe fnuikend het is voor het peil van het denken, wanneer je probeert om onbetrouwbare, obsolete apparatuur toch te gebruiken. MULTICS was andersom deprimerend. Het treft je het meeste als een samenraapsel van ondoordachte "gadgets, gimmicks and contraptions", geïntroduceerd meer omdat ze zagen dat ze ze konden maken, dan dat ze wisten hoe ze ze moesten gebruiken. En daar zuchten ze dan nu onder, wat ook tot bewustzijnsvernauwingen leidt. De absolute afwezigheid van enige invloed van wiskundig denken was opvallend; dit laatste voel ik als het zoveelste symptoom van een diepgeworteld Amerikaans wantrouwen jegens de intellectueel.

Voor de IBM360 had men over het algemeen geen goed woord over. De EL X8 heeft grote indruk gemaakt, vooral bij de mensen van MIT, die dachten dat de mogelijkheid "to attach a new command to an active chain" het privilege van de GE645 was. Later bleek de toekomstige machine van Burrough's het ook te zullen kunnen.

Mensen van "The Mathematical Laboratory, Cambridge" hadden bijzonder weinig waardering voor de activiteiten op het gebied van Computer Education door hun Department of Electrical Engineering (of zo iets). "They have an IBM machine, their instruction is of similar quality." Waar hadden we zulke geluiden ook al weer eerder gehoord?

Ik kreeg de prijs voor de beste voordracht, de grappigste uitnodiging was om na afloop meteen mee te komen naar Palo Alto om mijn critisch oog te laten gaan over het ontwerp voor de volgende machine van Burrough's.

transcribed by Angelo van der Sijpt
revised Mon, 22 Jan 2007

EWD215

A Case against the GO TO Statement.

by Edsger W.Dijkstra
Technological University
Eindhoven, The Netherlands

Since a number of years I am familiar with the observation that the quality of programmers is a decreasing function of the density of go to statements in the programs they produce. Later I discovered why the use of the go to statement has such disastrous effects and did I become convinced that the go to statement should be abolished from all "higher level" programming languages (i.e. everything except —perhaps— plain machine code). At that time I did not attach too much importance to this discovery; I now submit my considerations for publication because in very recent discussions in which the subject turned up, I have been urged to do so.

My first remark is that, although the programmer’s activity ends when he has constructed a correct program, the process taking place under control of his program is the true subject matter of his activity, for it is this process that has to effectuate the desired effect, it is this process that in its dynamic behaviour has to satisfy the desired specifications. Yet, once the program has been made, the “making” of the corresponding process is delegated to the machine.

My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost best to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.

Let us now consider how we can characterize the progress of a process. (You may think about this question in a very concrete manner: suppose that a process, considered as a time succession of actions, is stopped after an arbitrary action, what data do we have to fix in order that we can redo the process until that very same point?) If the program text is a pure concatenation of, say, assignment statements (for the purpose of this discussion regarded as the descriptions of single actions) it is sufficient to point in the program text to a point between two successive action descriptions. (In the absence of go to statements I can permit myself the syntactic ambiguity in the last three words of the previous sentence: if we parse them as "successive (action descriptions)" we mean successive in text space, if we parse as "(successive action) descriptions" we mean successive in time.) Let us call such a pointer to a suitable place in the text a "textual index".

When we include conditional clauses (if B then A), alternative clauses (if B then A1 else A2), choice clauses as introduced by C.A.R.Hoare (case[i] of (A1, A2,.....,An)) or conditional expressions as introduced by J. McCarthy (B1 → E1, B2 → E2,....., Bn → En), the fact remains that the progress of the process remains characterized by a single textual index.

As soon as we include in our language procedures we must admit that a single textual index is no longer sufficient: in the case that a textual index points to the interior of a procedure body the dynamic progress is only characterized when we also give to which call of the procedure we refer. With the inclusion of procedures we can characterize the progress of the process via a sequence of textual indices, the length of this sequence being equal to the dynamic depth of procedure calling.

Let us now consider repetition clauses (like, while B repeat A or repeat A until B). Logically speaking, such clauses are now superfluous, because we can express repetition with the aid of recursive procedures. For reasons of realism I don't wish to exclude them: on the one hand repetition clauses can be implemented quite comfortably with present day finite equipment, on the other hand the reasoning pattern known as “induction” makes us well equipped to retain our intellectual grasp on the processes generated by repetition clauses. With the inclusion of the repetition clauses textual indices are no longer sufficient to describe the dynamic progress of the process. With each entry into a repetition clauses, however, we can associate a so-called “dynamic index”, inexorably counting the ordinal number of the corresponding current repetition. As repetition clauses (just as procedure calls) may be applied nestedly, we find that now the progress of the process can always be uniquely characterized by a (mixed) sequence of textual and/or dynamic indices.

The main point is that the values of these indices are outside programmer's control: they are generated (either by the write up of his program or by the dynamic evolution of the process) whether he wishes or not. They provide independent coordinates in which to describe the progress of the process.

Why do we need such independent coordinates? The reason is—and this seems to be inherent to sequential processes—that we can interpret the value of a variable only with respect to the progress of the process. If we wish to count the number, n say, of people in an initially empty room, we can achieve this by increasing n by 1 whenever we see someone entering the room; in the in-between moment that we have observed someone entering the room but have not yet performed the subsequent increase of n, its value equals the number of people in the room minus one!

The unbridled use of the go to statement has as an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. Usually, people take into account as well the values of some well chosen variables, but this is out of the question because it is relative to the progress that the meaning of these values is to be understood! With the go to statement one can, of course, still describe the progress uniquely by a counter counting the number of actions performed since program start (viz. a kind of normalized clock). The difficulty is that such a coordinate, although unique, is utterly unhelpful: in such a coordinate system it becomes an extremely complicated affair to define all those points of progress where, say, n equals the number of persons in the room minus one!

The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one's program. One can regard and appreciate the clauses considered as bridling its use. I do not claim that the clauses mentioned are exhaustive in the sense that they will satisfy all needs; but whatever clauses are suggested (e.g. abortion clauses) they should satisfy the requirement that a programmer independent coordinate system can be maintained to describe the process in a helpful and manageable way.

It is hard to end this article with a fair acknowledgement: am I to judge by whom my thinking has been influenced? It is fairly obvious that I am not uninfluenced by Peter Landin and Christopher Strachey, and that I do not regret their influence upon me. Finally I should like to record (as I remember it quite distinctly) how Heinz Zemanek at the pre-ALGOL meeting in early 1959 in Copenhagen quite explicitly expressed his doubts whether the go to statement should be treated on equal syntactic footing with the assignment statement. To a modest extent I blame myself for not having then drawn the consequences of his remark.

The remark about the undesirability of the go to statement is far from new. I remember having read the explicit recommendation to restrict the use of the go to statement to alarm exits, but I have not been able to trace it; presumably, it has been made by C.A.R. Hoare. In [1, Sec. 3.2.1] Wirth and Hoare together make a remark in the same direction in motivating the case construction: “Like the conditional, it mirrors the dynamic structure of a program more clearly than go to statements and switches, and it eliminates the need for introducing a large number of labels in the program.”

In [2] Guiseppe [sic] Jacopini seems to have proved the (logical) superfluousness of the go to statement. The exercise to translate an arbitrary flow diagram more or less mechanically into a jumpless one, however, is not to be recommended. Then the resulting flow diagram cannot be expected to be more transparent than the original one.

REFERENCES:

Wirth, Niklaus, and Hoare, C.A.R. A contribution to the development of ALGOL. Comm. ACM 9 (June 1966), 413–432.

Böhm, Corrado, and Jacopini, Guiseppe. Flow diagrams, Turing machines and languages with only two formation rules. Comm. ACM 9 (May 1966), 366–371.

Transcribed by Guy Haworth.

Formatting revised and last two paragraphs and reference list added by H. Richards. The additions are absent from the typescript furnished to the archive but are present in the version published in Comm. ACM 11 (March 1968), 147–148 under the title “Go To Statement Considered Harmful”. Thanks to Mark Minich for reporting the discrepancy.

Last revised on Fri, 8 Apr 2011.

EWD221 - 0

array d[0:36];
d[0] := 0; d[1] := 0; d[2] := 0; d[3] := 0; d[4] := 0; d[5] := 0;
k := 5;
4 < k and k < 36 herhaal

begin j := k-1; geluk := true;
j ≥ 4 and geluk herhaal
begin gelijk := true; h := 0;
h ≤ 4 and gelijk herhaal
begin gelijk := (d[k-h] = d[j-h]); h := h+1 end;
gelijk zoja geluk := false; j := j-1
end;
geluk dan
begin k := k+1; k ≤ 31 dan d[k] := 0 anders d[k] := d[k-32] and
      anders
begin k > 31 zoja k := 31;
d[k] = 1 zoja k := k-1;
d[k] := 1
end
end

Transcribed by Mikhail Esteves

Last revised on Sat, 19 Jul 2003.

EWD 222

Verslag van het bezoek aan Grenoble en Parijs (6-11 december 1967)

De stad Grenoble staat volslagen op zijn kop vanwege de komende Olympische Winterspelen (men rekent o.a. op 2000 tot 2500 extra zieken en gewonden plus enkele 10-tallen doden). De algemene nervositeit werd iets minder toen het eindelijk behoorlijk begon te sneeuwen; gelukkig had ik op het laatste moment voor mijn vertrek uit Eindhoven bedacht, dat dichte schoenen wellicht geschikter waren dan slippers.

Ik ben ondergebracht in het eerste perfecte (Franse) hotel, dat ik ooit heb meegemaakt, en werd bij mijn aankomst opgevangen door Griffiths, een Engelsman, die verleden jaar in Villard-de-Lens deel uit maakte van het Britse contingent, maar inmiddels min of meer in dienst is bij de Universiteit van Grenoble. Tot zover was de organisatie perfect: een tegengestelde ervaring was dat, hoewel was afgesproken dat de Universiteit de (considerabele) hotelrekening betalen zou, dit overal bekend was behalve bij de receptie van het hotel!

Ik ben twee volle dagen in het instituut voor toegepaste wiskunde geweest: zuivere wiskunde—en later heb ik begrepen, dat dat typerend is—zit in een volslagen ander gebouw. Donderdagmorgen hebben enige medewerkers mij een indruk gegeven van wat ze deden—presentatie opvallend helder, zeker wanneer je in aanmerking neemt hoe slecht het Frans zich hier voor leent. Hoewel ik officieel alleen vrijdagmorgen voor het officiële colloquium spreken zou (in wezen hetzelfde verhaal als in Gatlinburg etc.) heb ik, voor een iets kleiner gehoor donderdagmiddag een volledig ongeprepareerde voordracht van twee uur gehouden over de synchronisatie tussen het centraal rekenorgaan van de EL-X8 en de peripherieapparatuur. Een grote fractie van het gehoor bestond uit mensen van IBM (zie later) en het verhaal maakte, hoewel ik zelf niet erg tevreden was over de manier, waarop ik presenteerde, daardoor een enorme indruk. Vrijdagmorgen heb ik voor een inmiddels groter publiek, de generale repetitie gehouden (van weer twee uur) van wat ik maandag in Parijs vertellen wil. (Titel "Towards correct programs" onderwerp "An effort to increase our ability to create reliable mechanisms"). In Parijs verwacht ik minder Britten onder mijn gehoor (die aanzienlijk tot de levendigheid van de discussie bijdroegen) zodat ik hoop het daar wat sneller te kunnen doen. (Wat wel goed uitkomt, want ik moet dan een vliegtuig halen.)

De aanwezigheid van de Britten houdt verband met het feit dat de Universiteit van Grenoble op het ogenblik een multi-console configuratie heeft (in eerste instantie met een PDP-8 als "buffermachine" en voor het grotere spul wordt dan een IBM 7044 ingeschakeld) en dat ze van plan zijn een dergelijk systeem op te bouwen met behulp van een IBM 360/67. Dit laatste wordt ontwikkeld in samenwerking met IBM; in het kader van dit contract heeft de Universiteit b.v. Griffiths in dienst. Hoe dit allemaal tot stand gekomen is heb ik niet ontdekt: men is nl. heilig overtuigd van de bezwaren van de IBM 360 voor zulk soort toepassingen en over de ongeschiktheid van de IBM-terminals zijn ze heel openhartig.

Het systeem met ±24 teletypes, de PDP-8 heb ik in werking gezien, in een instructielokaal vol studenten. De demonstratie was perfect: na 20 minuten derailleerde het systeem, zodat iedere student zijn werk van ± het laatste uur de mist zag ingaan en opnieuw kon beginnen. Et populus murmuravit contra Moisen... Ik verwachtte een rel, "an open revolte", maar het werd gelaten geaccepteerd, het gebeurde eens per week. De instructeur gaf de schuld aan de apparatuur, maar kreeg van mijn begeleiders geen bijval. Wat niet verwonderlijk is, gezien de betrouwbaarheid van de teleprinters en de PDP-8. Wij houden het op "a lurking bug".

De jongens achter de toetsenborden waren enthousiast bezig. Ik heb het angstige vermoeden, dat de oorzaak van hun enthousiasme gezocht moest worden in het feit, dat hun taak zo onnozel was, dat ze het nog konden zonder intellectuele inspanning. Bij de educatieve waarde van de hele opzet zet ik enorme vraagtekens—"Het enige, dat je met een kleine machine doceren kunt, is hoe je met een kleine machine klungelt". Ik heb dit voorzichtig aan mijn gastheer Bolliet laten merken, die mij onmiddellijk bijviel. De multiconsole-configuratie is meer een statussymbool, en dit is, wat Grenoble hard, hard nodig heeft.

Uit roddel heb ik min of meer begrepen hoe Grenoble vechten moet tegen Parijs en Bourbaki. Een combinatie van wettelijke regelingen en gekonkel heeft b.v. de volgende gevolgen:
1. Wie wil promoveren over een toegepast wiskundig onderwerp moet bovendien een verhandeling schrijven over een hem opgelegd, niet door hem zelf te kiezen, onderwerp uit de zuivere wiskunde (zulks uit te maken door Bourbaki himself te Parijs). De schade, die deze barriere voor het toepassen van wiskunde toebrengt aan de Franse economie moet enorm zijn.
2. Om hoogleraar te kunnen worden moet men aan zoveel wettelijke vereisten voldoen, dat het b.v. practisch onmogelijk is om in het buitenland getraind intellect voor deze posten te importeren. (Mag niet van Parijs)
Iemand als Bolliet, die een afdeling Computing Science heeft opgebouwd, die 200 studenten verzorgt, heeft in de hierarchie van de Universiteiten van Frankrijk een heel ondergeschikte, in elk geval onzekere positie. Parijs ziet de bloei van Grenoble met lede ogen en zal alles in het werk stellen om dit tegen te gaan. Fijn land! En het is dacht ik, juist Grenoble's positie van verdrukten, die IBM de mogelijkheid gegeven heeft dit instituut zozeer te infiltreren. Toen ik mijn vrees uitte, dat in de komende jaren een goed stuk van Computer Science wel eens kon degenereren in leren leven met en knutselen aan het inmiddels al beruchte "Operating System 360", oogstte ik een grimmige glimlach ten teken, dat de vrees gedeeld werd.

De zaterdag heb ik in Grenoble doorgebracht op een allerplezierigste manier, die dunkt me alleen in Frankrijk mogelijk is: in haar appartement serveerde onze charmante gastvrouw haar gasten een lunch, die duurde van 12.15 tot 17.30 uur.

Ik heb wel begrepen, dat men, althans in Grenoble, "The French Chapter of the ACM" niet als wetenschappelijke, maar als politieke instelling beschouwt zodat ik niet met een erg gerust hart naar Parijs ga. Van de drie verhalen, die ik in Frankrijk heb gehouden, beschouw ik de voordracht, die ik voor Parijs heb voorbereid, duidelijk als de belangrijkste ("The Gatlinburg story" raakt natuurlijk ook wel wat versleten), maar toen ik hem in Grenoble ten doop hield, kwam hij maar gedeeltelijk over het voetlicht. Uit een gehoor van zestig waren een stuk of tien—mensen met ervaring in grote projecten—duidelijk gegrepen: dat tiental is in elk geval meer dan van tevoren overtuigd van de mate, waarin "Simplex Veri Sigillum" voor het programmeursvak geldt. De resterende vijftig waren beleefd enthousiast omdat ze het verhaal van begin tot einde hadden kunnen begrijpen—complimenteerde me bij wijze van spreken over de elegance van de oplossing, waarmee ik een en ander illustreerde—maar dat de totale begrijpbaarheid van mijn verhaal nu juist de kern van mijn betoog (zeg "boodschap", zo je wilt) was, ontging hen geloof ik. Er zijn kennelijk mensen, die pas het gevoel hebben van een voordracht iets geleerd te hebben, mits ze de spreker niet hebben begrepen.

In Parijs een gehoor van een man of zestig, waaronder een stuk of tien intelligent reageerden.

| E W.D.

transcribed by Angelo van der Sijpt
revised Sun, 7 Oct 2007

  EWD 224

14 januari 1968

HEEL VERTROUWELIJK

Het volgende beoogt een catalogus van bedreigingen voor het goed functioneren van de onderafdeling; het is een uiting van grote bezorgdheid.

A)   Het researchklimaat wordt bedreigd door een puriteins schuldgevoel. Als we lekker aan het werk zijn, voelen we ons als een vis in het water. Dit geeft ons het gevoel, dat we ons in onze hobby uitleven en dan komt de twijfel "Wie ben ik, dat ik doen mag, waarin ik het meeste zin heb?". Het is gewoon moeilijk om - hetzij met betrekking tot jezelf, dan wel met betrekking tot een ander - het vertrouwen op te brengen, dat iemand de maatschappij niet beter dienen kan dan juist "door zichzelf te zijn". Dit zullen we toch moeten opbrengen!

B)   Om je werk goed te doen, moet je er plezier in hebben, moet je je ermee kunnen identificeren. En als iemand er manifest plezier in heeft, dan loopt hij de kans om het onder A gesignaleerde schuldgevoel - hetzij bij zichzelf, dan wel bij anderen - op te wekken. Maar draaien we dan de zaak niet om? Is het niet veelal zo, dat het een kwestie van lijfsbehoud en levenskunst is, om in een op je genomen taak je voldoening en je genoegen te vinden?

C)   Het researchklimaat wordt bedreigd door een eerlijkheidsoverweging. Veelal komen wij niet toe aan wat we zouden willen doen en niets ligt meer voor de hand dan dat we deze onproductiviteit wijten aan de omstandigheden en nevenverplichtingen. (De man die zich beklaagt, dat hij het zo druk heeft, voegt daar nimmer aan toe "Ik doe zoveel", maar altijd "Ik kom nergens meer aan toe".) Ten overstaan van iemand, die wel productief is is de vanzelfsprekende reactie dat de man "kennelijk te weinig klussen heeft", een misverstand, waarin nodig correctief moet worden ingegrepen.

D)   De dichotomie ten aanzien van het hebben van afstudeerders: op enkele grensfiguren na valt de onderafdeling in tweeen uiteen, collegae met en collegae zonder afstudeerders. Het gevaar bestaat, dat zij zonder afstudeerders gefrustreerd raken door het gevoel, niet tot hun recht te komen, terwijl zij met afstudeerders gefrustreerd raken door het gevoel, het vuile werk te kunnen opknappen. Ten aanzien van deze dichotomie moeten we kiezen of kabelen, of er wat aan doen, of er mee leren te leven. Ik suggereer het laatste. We hebben allemaal ons specialisme of onze specialismen en daarvoor hoeven we ons niet te schamen, immers daarom zijn we hier benoemd! Vergeleken met het werkterrein, dat we gezamenlijk bestrijken, is de opgave van een TH tamelijk gericht en het is daarom vanzelfsprekend, dat sommigen meer met afstudeerders gezegend dan wel gestraft zijn dan anderen. Persoonlijk ben ik alleen maar blij en dankbaar, dat wij in een dergelijke diversiteit rond te tafel zitten, want ik kan me niet voorstellen, dat de ene helft niet profiteren kan van de andere (en dat geldt in beide richtingen).

E)   Een mogelijke ontaarding van het onder D gesignaleerde, die optreden kan, zodra zij zonder afstudeerders dit er aan gaan wijten, dat onze studenten niet goed genoeg voor hen zouden zijn. Misschien is het inderdaad wel zo, dat ze alleen met een heel goede iets kunnen bereiken, dat kan zijn. In geen geval mag aan het onvermogen een matige jongen tot bruikbaar mens op te kweken het prerogatief ontleend worden "dat die enkele goede natuurlijk voor hen is" om vervolgens neer te zien op wat de rest van de rest terechtbrengt. Omgekeerd: wie van een droeve kandidaat zo goed mogelijk een ingenieur maakt hoeft als afstudeerhoogleraar niet zich tegenover zijn collegae voor het overeenkomstig droevige afstudeerwerk te generen want het is immers de onderafdeling als geheel, die deze jongen tot het ingenieursexamen heeft toegelaten.

F)   In tweeerlei opzicht heeft ons denken de schaalvergroting niet bijgehouden; de vraag dient gesteld te worden of het oude ideaal uit de opbouwfase van de onderafdeling "We zijn een geheel en iedereen kan alles" nog hanteerbaar en nog practisch is. De onverwerkte schaalvergroting manifesteert zich
1)   in het feit, dat we inmiddels als onderafdeling veel meer specialismen herbergen
2)   in het feit, dat we iedereen zijn tijd willen laten verdelen over de twee activiteiten van de onderafdeling, onderwijs en onderzoek, terwijl er inmiddels vier vrij verschillende activiteiten zijn:
          1) basisonderwijs voor andere afdelingen
          2) Wsk-onderwijs, inclusief specialistisch onderwijs
          3) onderzoek
          4) service-bedrijf (zowel intern als extern).
In onderafdelingsvergaderingen hebben we neiging om voor deze meerslachtigheid van taakstelling de ogen te sluiten. Het resultaat is, dat aan ieder staflid de conflictsituatie gedelegeerd wordt, waar wij als senaatsleden omheen lopen.

G)   We gaan gebukt onder een (overdreven) appreciatie van onderzoek en depreciatie van het basisonderwijs. Wat we daaraan moeten doen is me niet duidelijk, wel is me duidelijk, dat dit door de vijftig-procent-regeling alleen maar in de hand wordt gewerkt, want de vijftig procent onderzoek wordt door de staf ervaren als verguldsel voor de pil van de vijftig procent onderwijs, vooral als dit basisonderwijs betreft. Zijn we hier zelf schuld aan? Zodra je sollicitanten op hun onderzoekcapaciteiten selecteert is het in elk geval niet verwonderlijk, als je een staf kweekt, die het basisonderwijs meer als last dan als taak ervaart.

H)   We hebben het allemaal zo goed met de wiskundig ingenieur voor, dat een irreeel idealisme, dat schapen met zes poten wil fokken, de kop opsteekt, met alle teleurstellingen van dien. Vergeleken bij andere curricula lijkt ons programma ontstellend breed. De kreet "Een wiskundig ingenieur moet in elk geval een goed wiskundige zijn" is in al zijn nobelheid gevaarlijk, gevaarlijker naarmate wij precieser menen te weten, wat wiskunde is en wat niet. Het gevaar is groot, dat wij over vijf jaar een soort reincultuur bedrijven die heel veel lijkt op wat we nu de universiteiten verwijten. Misschien doen we er beter aan om zonder al te veel vooropgestelde ideeen over wat nu wiskunde is en wat niet te proberen om bruikbare mensen op te kweken.
     Noot 1. Die mensen zullen van een verscheidenheid zijn, die moeilijk verteerbaar is voor wie leeft in het idee van "de eenheid van de wiskunde", de ontwikkeling zal sommigen van ons pijn doen.
     Noot 2. Van de zijde van studenten zullen we hierin niet aangemoedigd worden: het zijn juist in zeker zin "goede" studenten - dwz, het type, dat ons in een heleboel opzichten wel aanspreekt - die ons naar de reincultuur drijven.
     Noot 3. Ik hoor de verontwaardiging al "Als wij niet mogen weten, wat wiskunde is, waar blijven we dan? Is dit niet levensgevaarlijk?" Ja, maar wie vaart op een dubieus kompas, kan zich dit beter bewust zijn dan er blindelings op vertrouwen!

I)   Een hoop van de gesignaleerde bedreigingen houden direct verband met de omvang van de onderafdeling, zoals communicatiemoeilijkheden, diversiteit van inzichten, doelstellingen, normen etc. Aangezien de onderafdeling alleen maar groter zal worden, zal een doorgaan met verdoezelen alleen maar tot grotere moeilijkheden aanleiding kunnen geven. Vandaar dit stuk.

Edsger

transcribed by Jeanine Daems
revised Mon, 13 Nov 2006

EWD227

Copyright Notice

The following manuscript

EWD 227: Stepwise program construction

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 1-14 of

Edsger W. Dijkstra, Selected Writings 0n Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN O-387-90652-5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

My dear Friend or Relation, Master, Colleague or Pupil,

Paraphrasing the ominous sentence: "This .......... has been placed here for your convenience.", which is usually used to explain the presence of all sorts of American hotel room contraptions, I should like to say "The enclosed manuscript has been sent to you for your enjoyment.".

I would not dare to send it to you if you regarded it as the next item for the evergrowing pile of tasks still to be done. I know that the manuscript is long but I have let it grow that way in the hope that the intellectual effort needed for its digestion is inversionally proportional to its length. And your enjoyment may be proportional to it. So I don't apologize for its length.*

There are no shattering discoveries in it: it is the kind of peaceful prose that I write (mainly for my own distraction?) when a somewhat poor condition forces me for some period of time to some sort of inactivity. It will certainly be less gloomy than this eveningÎs front page news!

When you have read it and feel like dropping me a line, please don't hesitate to do so; I will receive it gladly.

Yours sincerely

Edsger W.Dijkstra

Department of Mathematics

Technological University Eindhoven

P.O. Box 513

EINDHOVEN

The Netherlands

* There is no point in denying it: I do like Franz Schubert's music.

Stepwise Program Construction.

Over the past years I have been (heavily) engaged in a number of (at that time) advanced programming projects that could be considered as large in comparison to the available manpower. I am still in the active process of learning from the experience gained, one of the immediate goals of this learning process being the discovery of better ways to construct even "small programs" in a reliable fashion. Although large, advanced and sophisticated programming efforts are more spectacular, we must not forget that quite a lot of machine time and programmer's energy is really spent on small, down-to-earth projects and the present efforts to make computing facilities more directly accessible for the individual user will only reinforce this tendency.

For the interested reader I am going to make two programs and, besides that, I am going to show the individual steps in which they have been constructed. The`examples serve to illustrate parts of my present understanding of the demands, that the task of programming makes upon the human mind.

In my approach there are some central themes that I shall just mention for the proper understanding of the following. The one theme is that, although the program made by the programmer is his final product, the computations evoked by it are the true subject matter of his trade: he has to guarantee that the computations —the "making" of which he leaves to the machine— evoked by his program will have the desired effect. As a result he has the duty to structure his program in a useful way, where usefulness (among other things) implies that the form of the program admits trustworthy statements about the corresponding computations. The second theme is that the mental aids available to the human programmer are, in fact, very few. They are enumeration, mathematical induction and abstraction, where the appeal to enumeration has to satisfy the severe boundary condition that the number of cases to be considered separately, should be very, very small. The introduction of suitable abstractions is our only mental aid to reduce the appeal to enumeration, to organize and master complexity. Mathematical induction has been mentioned explicitly because it is the appropriate (and only!) established pattern of reasoning by which we can understand programs with either repetitive clauses or recursive procedures. As a corollary I mention the fact that for some time I knew that as a programmer I could live quite happily without any form of go to statements but that in the mean time my considered opinion is that I cannot live happily with the go to statement.

To avoid misunderstanding I should like to state explicitly that I do not claim that the two programs produced are the best possible, measured (probably!) in terms of your private yard-stick. I do claim that they are fairly good and reasonable in terms of the average yard-stick, i.e. that they present utterly realistic solutions. I do claim to have achieved a degree of clarity and transparency of an order of magnitude better than the average programmer's solution, that my solutions have been reached with an intellectual effort considerably below average and that they admit exhaustive verification. And that is more than can be said about many a program.

The reason to treat two examples is because they have been drawn from vastly different fields: the one dealing with prime numbers is a so-called scientific application, the other, dealing with the idiosyncrasies of Flexowriters, is a so-called clerical application. These two fields are often regarded as completely foreign to each other: the successful application of the same discipline as illustrated below gives a strong support to the assumption that the difference between scientific and clerical machine usage is by no means an inherent difference, but more probably the result of a difference in intellectual level and professional training of the people engaged.

(Note. I do not feel myself called to justify the choice of my examples, which are a kind of random draws from what is happening around me: emotionally speaking, prime numbers leave me as unaffected as Flexowriters.)

The construction of a table of the first 1000 prime numbers.

"Given an integer array p[1:1000], make a program making its elements in order of increasing subscript value equal to the successive prime numbers, where 2 is considered as the first prime number."

Well-defined as this task may seem to the benevolent reader, as we go along we shall discover an undefined boundary between the amount of mathematical knowledge the programmer is willing to embody in his program and the amount of computation he leaves to the machine.

To start with: for the task to make sense it must be known that at least 1000 primes actually exist. We grant the programmer this knowledge and at a certain stage of program construction we allow him to appeal to this fact when he has to prove that his program does indeed halt.

We shall now give the coarsest version of the program, viz. version 0:

begin "assign to the array p the prime table as described" end

When this action occurs among the well-understood and well-defined repertoire of actions from which the computation has to be composed, version 0 solves our problem. For the sake of argument we now assume that this action does not occur among the repertoire; particularly we restrict ourselves to repertoires in which we can operate on arrays only element wise. This implies that in our next version the order in which the elements of the array p will get their desired value has to be expressed and in it we shall try to express just that and preferably nothing more.

An obvious version of the program then starts with

begin p[1]:= 2; p[2]:= 3; p[3]:= 5; p[4]:= 7; p[5]:= 11;.......

implying that the programmer's knowledge includes a table of the first 1000 primes. We shall not pursue this version, as it would imply that the programmer hardly needed the machine at all.

The first prime number being given (=2), the thousandst being assumed unknown to the programmer, the most natural order to fill the elements of the array p is in order of increasing subscript value and if we express just that (with a simple repetitive while do clause) we come to version 1a:

begin integer k,j; k:= 1; j:= 1;
      while k ≤ 1000 do
      begin "increase j until the next prime number";
            p[k]:= j; k:= k + 1
      end
end

Identifying k as the subscript value of the element whose turn it is to be filled the correctness of version 1a is easily proved by mathematical induction (under the assumption of the existence of a sufficient number of primes).

Version 1a is a perfect program when the operation described by "increase j until the next prime number" occurs among the repertoire, but let us suppose that it does not. In that case we have to express how j is increased and in our next elaboration we shall try to express just that and preferably nothing more. With a simple repetitive repeat until clause (which may act upon a sequence of statements) we come for "increase j until the next prime number" to version 2a:

begin boolean jprime;
      repeat j:= j + 1;
             "give to jprime the meaning: j is a prime number"
      until jprime
end

If we substitute version 2a for the appropriate operation in version 1a our resulting program is undoubtedly correct. But if we assume that the programmer knows that, apart from 2, all prime numbers are odd, then we may expect that he will be dissatisfied with the obvious inefficiency of version 2a. The price to be paid for this, call it "lack of clairvoyance" is a revision of version 1a, in which the prime number 2 is dealt with separately, after which the cycle can deal with the odd primes. So we come to version 1b:

begin integer k,j; p[1]:= 2; k:= 2; j:= 1;
      while k ≤ 1000 do
      begin "increase odd j until the next odd prime number";
            p[k]:= j; k:= k + 1
      end
end

where the analogous elaboration of the operation between quotes leads to version 2b:

begin boolean jprime;
      repeat j:= j + 2;
             "give to jprime for odd j the meaning:
             j is a prime number"
      until jprime
end

The above oscillation between versions 1 and versions 2 is in fact nothing else but moving the interface between the overall structure and the primitive that has to fit in this structure. This is definitely not attractive, but with a sufficient lack of clairvoyance and being forced to take our decisions in sequence, I see no other way: we can regard our efforts as experiments to explore where the interface can be most conveniently chosen.

Encouraged by the success of treating 2 apart, we investigate what can be gained by treating 3 apart as well. For this purpose we introduce the property "throdd", i.e. neither divisible by 2, nor by 3. The throdd numbers are of the form 6N+1 or 6N+5. By definition, 2 and 3 are the only prime numbers not contained in the set of throdd numbers and so we come to version 1c:

begin integer k,j; p[1]:= 2; p[2]:= 3; k:= 3; j:= 1;
      while k ≤ 1000 do
      begin "increase throdd j until
            the next throdd prime number";
            p[k]:= j; k:= k + 1
      end
end

where the analogous elaboration of the operation between quotes leads to version 2c:

begin boolean jprime;
      repeat "increase throdd j until the next throdd value";
             "give to jprime for throdd j
             the meaning: j is a prime number"
      until jprime
end

This is only an improvement when the operation "increase throdd j until the next throdd value" is easily implemented. The proper increase of j is a function of j: call it "INC(j)". Its value is =4 when j=6N+1, its value is =2 when j=6N+5. Instead of freshly evaluating the function INC(j) whenever we need it, we introduce a separate variable, inc say, to record the current value of INC(j), corresponding to the current value of j. The variable inc has to be set initially when j is set, it has to be adjusted whenever the value of j is changed. (The introduction of inc is an instance of a standard programmer's device to trade variable space for computation speed.) Using list-assignments to stress that inc is just a companion of j, the introduction of inc and the elaboration of "increase throdd j until the next throdd value" leads to version 1d:

begin integer k,j,inc; p[1]:= 2; p[2]:= 3; k:= 3;
      (j,inc):= (1,4);
      while k ≤ 1000 do
      begin "increase throdd j, adjustment of inc included,
            until the next throdd prime number";
            p[k]:= j; k:= k + 1
      end
end

where the elaboration of the operation between quotes leads to version 2d:

begin boolean jprime;
      repeat (j,inc):= (j + inc, 6 - inc);
            "give to jprime for throdd j the meaning:
            j is a prime number"
      until jprime
end

There is no indication that any gain will result from taking the next prime (i.e. 5) out of the cycle as well and we shall not try it.

Again, when "give to jprime for throdd j the meaning: j is a prime number" is an operation from the presupposed repertoire, then our program is finished. We now assume that it is not, in other words we have to evoke a computation deciding whether a given throdd j has a factor. It is only at this stage that the algebra really enters the picture. Here we make use of the knowledge that we only need to try prime numbers as factors; furthermore we shall use that the prime numbers to be tried can already be found in the filled portion of the array p.

We use the facts that

 j being a throdd value, the smallest potential factor to be tried is p[3], i.e. the first prime above 3;

the largest prime factor we have to try is p[ord-1], when p[ord] is the smallest prime number whose square exceeds j.

If this set is not empty, we have a chance of finding a factor and as soon as a factor has been found, the investigation of this particular j value can be stopped. We have to decide in which order the prime numbers from the set will be tried and we shall do so in order of increasing magnitude because the smaller a prime number the larger the probability of its being a factor of j.

In our first elaboration of "give to jprime for throdd j the meaning: j is a prime number" we come to version 3d:

begin integer n,ord; boolean nofactorfound;
      ord:= 1; while p[ord]^2 ≤ j do ord:= ord + 1;
      n:= 3; nofactorfound:= true;
      while n < ord and nofactorfound do
      begin "give to nofactorfound the meaning:
            p[n] is no factor of j";
            n:= n + 1
      end;
      jprime := nofactorfound
end

Here we make two observations. The boolean variable celled "nofactorfound" is superfluous, we could have used jprime instead, so that the last assignment statement can be removed. Furthermore, ord is a function of j that we need not recompute freshly every time, but that we can and should treat along the same line as inc. The latter remark causes the final revision of version 1, leading to version 1e:

begin integer k,j,inc,ord; p[1]:= 2; p[2]:= 3; k:= 3;
      (j,inc,ord):= (1,4,1);
      while k ≤ 1000 do
      begin "increase throdd j, adjustment of inc and
            ord included, until the next throdd prime number";
            p[k]:= j; k:= k + 1
      end
end

where the elaboration of the operation between quotes leads to version 2e:

begin boolean jprime;
      repeat (j,inc):= (j + inc, 6 - inc);
      while p[ord]^2 ≤ j do ord:= ord +1;
            "give for throdd j, using p and ord, to jprime
            the meaning: j is a prime number"
      until jprime
end

(Remark: here "while p[ord]^2 ≤ j do" can be replaced by "if p[ord]^2 ≤ j then", but to my taste the marginal gain in efficiency is not worth the intellectual effort to prove its validity. A programmer should learn to be lazy at the right moment and to let the principle "Safety First" prevail!)

Elaboration of the operation between quotes gives a variant of version 3d, viz. version 3e:

begin integer n; n:= 3; jprime:= true;
      while n < ord and jprime do
      begin "give to jprime the meaning: p[n] is no
            factor of j";
      n:= n + 1
      end
end

For "give to jprime the meaning: p[n] is no factor of j" we may write under the assumption of decent real arithmetic

begin real q; q:= j / p[n]; jprime := (entier(q) != q) end;

we shall assume the availability of the integer division and write version 4e:

jprime := (j != (j / p[n]) * p[n])

Finally we perform all substitutions to construct a single statement.

begin integer k,j,inc, ord; p[1]:= 2; p[2]:= 3; k:= 3;
      (j,inc,ord):= (1,4,1);
      while k ≤ 1000 do
      begin begin boolean jprime;
                  repeat (j,inc):= (j + inc, 6 - inc);
                        while p[ord]^2 ≤ j do ord:= ord + 1;
                        begin integer n;
                              n:= 3; jprime:= true;
                              while n < ord and jprime do
                              begin jprime:=(j != (j/p[n])*p[n]);
                                    n:= n + 1
                              end
                        end
                  until jprime
            end;
            p[k]:= j; k:= k + 1
      end
end

We could have made the inner blocks into compound statements by moving the declarations for jprime and n to the outside. We have not done so: clarity does not gain by it and whether there is a point in doing it is rather dependent on the implementation.

And thus ends the treatment of the first example.

The unique reporting of the printed page as produced on a Flexowriter.

For our purpose we can regard a Flexowriter as a kind of electric typewriter which is operated only via the keys of its keyboard. Whenever a key is pressed, a configuration characteristic for this key is punched in a paper tape which is then moved on over one position. Typing a page thus implies the production of a paper tape specifying what has been typed. (Indeed: besides the punching station the Flexowriter has also a reading station, from which the printing mechanism can be controlled. By inserting the paper tape just produced into the reading station one can obtain another copy of the printed page.)

We want to program a routine which reads such a paper tape and gives, when called repeatedly, a unique description of the corresponding page image, according to conventions to be described below. As we go along we shall see that this is no trivial matter, because (mainly due to the construction of the Flexowriter) the very same page image may correspond to many paper tapes, greatly varying among each other. (In our example we shall simplify the real situation slightly: we shall exclude the unexpected occurrence of "end of tape" and exclude the situation that the paper tape reader of the computer discovers —due to some error in punching or reading— an illegal configuration. Even thus simplified, the problem is messy and intricate enough to serve our purpose!)

Two remarks about the form in which we shall present our solution:

the routine will be coded as an operator, operating in a local universe of permanently existing variables; we shall use small letters for their identifiers.

constants, referring to the integer values associated with characters will be denoted by identifiers composed from capital letters.

In its coarsest form the local universe contains one integer variable, called "charf" and the operator can be described by version 0:

begin "assign to charf the next value" end

Our Flexowriter has equal spacing, i.e. each line has a fixed number of print positions. There is a finite number of so-called "position characters" (this thanks to the absence of a backspace key on our Flexowriters, that would allow a practically unlimited number of superpositions) and each position character can occur at each print position of the page. A numerical code for the position characters has been chosen and the operator reports by assigning to charf the numerical value associated with the position character in the current print position, dealing with the print positions in each line in order from left to right and with the lines in order from top to bottom.

With respect to the left margin we assume that its position on the printed page is given; to indicate the right hand end of a line we have extended the range of charf values with an additional one, denoted by "RET" (i.e. New Line, Carriage Return) and require for the sake of uniqueness that all "invisible" spaces at the right hand end of a line are suppressed. It is as if RET is counted among the visible position characters but that its (symbolic) printing position has to be aligned to the left as far as possible.

It is the purpose of version 1 to suppress any spaces at the right hand end of each line; for its benefit the local universe has been extended with two integer variables:

charf1: | the range of this variable equals that of charf, but in the time sequence of its values invisible spaces at the right hand end of each line will still occur (if present, of course)
stock: | this is a counter; its value equals the number of times that charf can be filled with a next value, before charf1 has to be refilled. It requires the initial setting "stock:= 0".

Version 1 implements the look ahead whenever via charf1 one or more spaces are reported; when followed by RET they have to be suppressed, otherwise they have to be transmitted.

version1:

begin if stock = 0 then
      begin repeat "assign to charf1 the next value";
                   stock:= stock + 1
            until charf1 != SPACE;
            if charf1 = RET then stock := 1
      end
      charf:=(if stock > 1 then SPACE else charf1);
      stock:= stock - 1
end

Our next complication is that the "position character" as reported in charf1 (with the exception of RET) may be composed of three parts: by means of the mechanism of a so-called non-escaping key (i.e. one that leaves the carriage position as it is) one can superpose various "key characters" in the same print position. We have in fact two such key characters, viz. underlining and a vertical stroke. It is the purpose of version2 (an elaboration of "assign to charf1 the next value") to combine the key characters referring to the same print position.

We have to take into account

that non-escaping key characters have to be combined with the first following escaping key character

that repetition of the same non-escaping key character in the same print position must be considered as equivalent to its single occurrence.

For the benefit of version2 we extend the local universe with one integer variable,

charf2: | the range of this variable covers those charf values corresponding to position characters, produced without non-escaping key characters plus the values denoted by UNDER and STROKE.

As a matter of fact, 0 ≤ charf2 ≤ 127 will be satisfied; the presence of underlining will be coded in charf1 by an increase of 128, that of a stroke by an increase of 256.

Our tentative elaboration of "assign to charf1 the next value" gives rise to version2 (here CRAZY2 denotes a constant value well beyond the range of charf2)

version2:

begin integer under, stroke;
      under:= 0; stroke:= 0; charf1:= CRAZY2;
      repeat "assign to charf2 the next value";
            if charf2 = UNDER then under:= 128
                              else
            if charf2 = STROKE then stroke:= 256
                               else
                  charf1:= charf2
      until charf1 != CRAZY2;
      charf1:= charf1 + under + stroke
end

We have said "tentative elaboration", because as it stands, this version will not prevent, say, the transmission of an underlined RET: "charf2 = UNDER" followed by "charf2 = RET" requires the insertion of an additional space to be underlined. As pure spaces (i.e. without underlining or stroke) preceding RET will be suppressed by version 1 anyhow, we can (and shall) remedy this situation by imposing upon "assign to charf2 the next value" the requirement that it will never transmit RET unless immediately preceded by a transmission of SPACE.

The next complication is that our Flexowriters are equipped with a tabulator key TAB which, when pressed, gives rise to a punching in the paper tape, while the carriage moves on until the next tabulator stop that is more than one position to the right of the current position: the carriage moves over at least two positions. The positions of the tabulator stops are standardized (once every eight positions) but it implies that the algorithm deriving the number of spaces corresponding to TAB must be aware of the current position of the carriage (at least modulo 8). It is the purpose of version3 —the elaboration of "assign to charf2 the next value"— to translate tabulations into the equivalent number of spaces and to insert a SPACE before RET.

For its benetit we introduce into the local universe three integer variables.

charf3: | the range of this variable is that of charf2, extended with TAB;
pos: | keeps track of the current carriage position; when "charf2 = RET" occurs it will be set to zero, when "charf2 = TAB" occurs it will be increased until the proper multiple of 8 etc. It requires an initial setting, say "pos:= 0".
substock: | this is a counter; its value equals the number of times that charf2 can be filled with its next value before charf3 has to be refilled. It requires the initial setting "substock:= 0".

We arrive at the following elaboration ot "assign to charf2 the next value". (Note. As it stands I am not very much satistied with the coding of version3. The way in which SPACE before RET is smuggled in, for instance, is too tricky. As it stands it is, however, the first version I wrote down for it.)

version3:

begin if substock = 0 then
      begin "assign to charf3 the next value";
            if charf3 != UNDER and charf3 != STROKE then pos:= pos + 1;
            if charf3 != RET and charf3 != TAB then charf2 := charf3
                                               else
            begin charf2:= SPACE;
                  if charf3 = RET then
                  begin substock:= 1; pos:= 0 end
                                  else
                  begin substock:= (pos + 8 + 1) * 8 - pos;
                        pos:= pos + substock end
            end
      end            else
      begin charf2:=(if charf3 = TAB then SPACE else RET);
            substock:= substock - 1
      end
end

The last complication presented by the structure of the Flexowriter is its built-in memory element, called "the case". It is in one of two states, called "upper case" and "lower case" respectively. When it is in the state upper case it remains in this state until the key "LOWER CASE" is pressed, what furthermore results in punching the value "LC" in the paper tape; when it is in the state lower case, it remains in this state until the key "UPPER CASE" is pressed, what results in punching the value "UC" in the paper tape. When pressing any of the other keys, the punching is only dependent on the key pressed, the painting is (except for the space bar, the tabulator and the carriage return) dependent on the current case as well.

In version4 —an elaboration of "assign to charf3 the next value"— we have to implement the influence of the case punchings. For the benefit of it we extend the local universe with two integer variables

octade: | used to record the next punching on the paper tape
case: | this variable may have the values LC or UC (ur possibly a third one, meaning "undefined", because space, tabulation and carriage return can be processed case independently). It must get an initial value, say "case:= LC".

At this same level we implement that two legal punchings (BLANK and ERASE, corresponding to no holes and all holes respectively) are skipped without any possible effect on the page image. CRAZY3 denotes a constant outside the legal range for charf3.

version4:

begin charf3:= CRAZY3;
      repeat "give octade its next value";
             if octade != BLANK and octade != ERASE then
             begin if octade = LC or octade = UC
                     then case:= octade
                     else charf3:= fun(case, octade)
             end
      until charf3 != CRAZY3
end

With "give octade its next value" I indicate the paper tape read instruction and I shall not elaborate it any further. The function "fun(case,octade)" is also left undescribed: it is too much dependent on the special numerical codes; we only mention that upper and lower case space (tab or ret) must both be transmitted as SPACE (TAB or RET).

The successive insertions of version "i + 1" into version "i" is left to the industrious reader (or should I say "writer"?).

Concluding Remarks.

Before stressing the similarity of the ways in which our two problems have been solved I should draw attention to a difference. In the first example I have paid considerable attention to the decision where to put the interface between the successive levels, in the second one I did no longer do so. I do not believe that the origin of this difference is in any way related to the supposed contrast between "scientific" and "clerical" machine applications, for it has a perfect historical and psychological explanation. The historical explanation is that I have used the prime number table generation problem in a number of oral examinations, the psychological explanation is that, treating the second example I am getting tired and perfectly willing to leave to my readers the intellectual satisfaction of improvement.

Personally I am much more impressed by the similarity of the ways in which the two rather different programs have been constructed. The successive versions appear as successive levels of elaboration. It is apparently essential for each level to make a clear separation between "what it does" and "how it works". The description of "what it does", the definition of its net effect requires the introduction of the adequate concepts and both examples seem to show a way in which we can use our power of abstraction to reduce the appeal to be made upon enumeration.

As stated in the introduction we may expect that computers will become more directly accessible for the individual user and we may expect that the latter should like to use its capabilities for the text manipulations involved in program composition. At present I am rather unsure about the true nature of the text manipulations the user would then like to perform: it is certainly something more structured than just deletion and insertion of characters or lines! In the fervent hope of getting a better understanding of what these manipulations are I have reported two instances of program construction as detailed and as honestly as I possibly could.

Finally: if I did hit a worth-while nail on its head, then this manuscript should end with a proper acknowledgement, giving honour where honour is due. Under the present circumstances I can only express my gratitude to.... my Friends or Relations, my Masters, Colleagues and Pupils.

Eindhoven. February 1968

transcribed by Saleem Shafi
revised Fri, 12 Dec 2008

EWD229

E.W.Dijkstra Plataanstraat 5 NUENEN (NB) | dinstag 19 maart 1968

Aan de leden van de Commissie Wetenschapsbeleid.

Het volgende bevat opmerkingen, die ik gisteren had moeten maken, maar daar is toen niet van gekomen. (Ik ben altijd al een beetje langzaam, nu helemaal.)

1) Het volgende citest van Peter Naur zou ik onder Uw aandacht willen brengen: "In the development of ideas of computer science and of corresponding curricula it is possible to distinguish several stages. At the first stage the subject is not properly separated from its applications. At this stage the distinctions between areas like scientific computing, administrative data processing, and systems programming are put at the basis of the subject. At a later stage it is recognized that it is possible to talk of common ideas basic to programming, aspects like effectiveness, which can be conceived of independently of any specific application. At this stage it is still possible to let the development beyond the most elementary level be heavily application oriented, as is clearly exemplified in the curriculum proposed by the ACM Curriculum Committee on Computer Science.

The purpose of the present paper is to pursue the idea that the development of computer science from certain basic concepts need not stop at the most elementary level, but can usefully be continued considerably further. A case will be made that it is possible and convenient to distinguish a specific discipline, datalogy, the science of date and date processes, which will provide a conceptual frame for many of the ideas which are now associated with such subjects as Algorithmic Processes, Computer Programming, Information Structures, Algorithmic Languages, Programming Systems, and Formal Languages."

De moraal is, dat wij Computing Science van de toepassingsgebieden moeten losmaken; het is atavisme om dat niet te doen. (Computing Science enten op numerike wiskunde is in wezen hetzelfde atavisme, alleen in mildere vorm.)

2) Het koppeln van Computing Science aan de electronica is een dergelijk soort atavisme. Historisch verklaarbaar maar intrinsiek onjuist. De volle waanzin zie je in Utrecht bij het "Electronisch Reken Centrum": van beleng is alleen het functionele aspect van hun apparatuur en dat dat nu grotendeeis electronisch (en niet bv. chemisch) gaat is in dit instittu volslagen irrelevant. Het zou hetzelfde soort misvatting zijn om meetkunde te beschouwen als een tak van de werktuigbouwkunde, omdat je instrumentmakers nodig hebt voor de vervaardiging van passer en lineaal.

3) Waneer Bouwkamp betoogt, dat computing science niet een kwestie van louter wiskundigen is, kan ik dit slechts met hem eens zijn, als hij een vrij enge opvatting over de wiskundige huldigt (+/- de analyticus en de numericus). Ik ben geneigd de zaak om te draaien en iedereen, die het vak computing science voor mijn gevoel op een deugdelijke manier bedrijft, op grond daarvan als wiskundige te beschouwen.

4) Wanneer Veltkamp "ons onvoldoende breed" windt, ben ik dat roerend met hem eens en versterking zal ik toejuichen. Als hij bedoelt, dat van de activiteiten van vloer 10 te weinig tot de student doordringt, dat er college gegeven moet worden over compiler constructie en over de constructie van operating systems, dan ga ik een groot vraagteken zetten. Je moet die jongens leren, hoe ze een groot programma maken — en als het zo uitkomt kan je een stukje vertaler of systeem als illustratiemateriaal gebruiken, meer meer niet.

E.W.Dijkstra             

transcribed by Carl Ludwigson
revised Thu, 4 Nov 2010

EWD230

To the EDITOR ALGOL 68
Mathematische Centrum
2de Boerhaavestraat 49
AMSTERDAM(O)
The Netherlands
[Copies to members of IFIP.WG.2.1]

Department of Mathematics
Technological University
Postbox 513
EINDHOVEN
The Netherlands

           {Reader's reaction:
"there are writings which are lovable although ungrammatical, and there are other writings which are extremely grammatical, but are disgusting. This is something that I cannot explain to superficial persons."

from the Epigram of Chang Ch'ao "On Flowers and Women" as quoted by Lin Yutang in "The Importance of Living"

           Author's defence:
"My tragic tale I won't prolong
          sing rickety, tickety tin,
my tragic tale I won't prolong
and if you did not enjoy my song
you've yourselves to blame if it's too long:
you should never have let me begin....

from "The Irish ballad" by Tom Lehrer}

Dear Editor,

Thank you for sending me MR93, which has absorbed a considerable fraction of my available mental energy since it is in my possession. It must have been very hard work to compose it; alas, it also makes rather grim reading. The document turned out like I expected it to be, only much more so.

The more I see of it, the more unhappy I become. I know it is a hard thing to say to an author who has struggled for many years, but the proper fate of this document may indeed range from being subjected to minor corrections to being completely rejected. If the latter is the most sensible thing to do, sending errata sheets and lots of people trying to understand what it is all about seems a sad waste of energy.

On account of the draft report my faith in WG.2.1 (at least in its present constitution) is very low. The draft report is thick and difficult, in fact too thick and too difficult to inspire much confidence. Is there any hope of weeding all errors from a work of such size and complexity? Is there any hope of a convincing demonstration that the proposal does not contain pitfalls any more? And is then this manuscript, that the Computing Community has been waiting for? I am very sorry for you, but I am having a hard time if I try to believe all that.

Size and complexity of the defining apparatus you needed terrify me. Being well-acquainted with your ingenuity I think it a safe assumption that ALGOL 68 as conceived can hardly be defined by significantly more concise and transparent means. Having "Simplex Veri Sigillum" as one of my mottoes -particularly with respect to programming- I feel inclined to put the blame on the language you tried to define. If this is correct, WG.2.1 should return to its proper subject matter, viz. programming languages.

I don't know what is going to happen with MR93 in WG.2.1. I expect a strong political pressure to recommend it and can see many of the fake arguments seemingly supporting the decision. (E.g. "So much has been put in it, that we cannot afford to reject it." or "It becomes absolutely necessary to produce a document and if we reject this, we are back where we were a couple of years ago." or "Who has anything better?". We can be sure that they will all turn up!) If MR93 turns out to be the dead alley I am now afraid it is, it will be more the fate of WG.2.1 than that of MR93 that will be at stake, viz. whether WG.2.1 will make itself ridiculous by recommending it. It makes me very miserable.

For you I most sincerely hope that your tremendous efforts will prove to have been well-directed, but I am terribly afraid.....

Yours ever

Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Wed, 26 May 2004

  EWD 231

Causerie, gehouden op 23 april 1968 ter gelegenheid van de ontvangst van leraren

De Rekenautomaat als Gebruiksvoorwerp

Om te beginnen wil ik verklaren, dat ik het een groot voorrecht acht U te mogen toespreken. U vormt nl. het gehoor, waar wij altijd op hopen, maar dat ons zelden gegeven wordt: U bent de beroemde, maar zeldzame "Intelligente leek". Ik zal daarom alle technische termen en dure woorden uit het jargon, waarmee sprekers "pour &eacute;pater le bourgeois" hun betoog zovaak larderen, angstvallig vermijden.

Nu ik het toch over mijn woordkeus heb: ik moet bekennen, dat deze in sterke mate negatief is beinvloed door de gebruikelijke publiciteit, die aan rekenmachines wordt gegeven, of het nu de sensationele advertenties van computerfabrikanten zijn, dan wel de stukken opgewonden journalistiek, die we vinden in het zondagsochtendblad, dat we tegenwoordig zaterdagavond al in de bus krijgen. Zonder die negatieve beinvloeding had ik een veel pakkendere titel gekozen, zoiets als "De moderne computer: het electronisch brein in wetenschap, bedrijf en samenleving" of zo. Maar dat wil ik juist niet doen. Analoog aan wat theologen de "Entmythologisierung" noemen, zou ik deze causerie willen plaatsen in het teken van de "desensationalisatie": ik wil proberen om U in dit half uur wat tegengif toe te dienen voor alle sensationele publiciteit over rekenautomaten, waaraan wij aldoor worden blootgesteld.

De gangbare publiciteit is sensationeel: rekenautomaten worden altijd computers genoemd, want zo'n buitenlandse term is al door een halo van geheimzinnige macht omgeven. Verder wordt er bij voorkeur in superlatieven over gesproken: ongelofelijk duur, onvoorstelbaar machtig, fabelachtig snel, uitgerust met een ijzersterk geheugen, het begin van de volgende maatschappelijke revolutie, enzovoort.....

Laten we de eerste krachtterm eens bij de kop vatten en kijken of we ons daartegenover iets nuchterder kunnen opstellen: hun prijs. Je hoort steeds maar, dat rekenautomaten zo ontstellend duur zijn. Dit verschijnsel heeft twee aspecten: de prijs zelf en... de publiciteit, die aan de prijs geschonken wordt.

Met betrekking tot het laatste doen we er goed aan te beseffen, dat voor menig instituut de rekenautomaat, die het beheert en gebruikt, fungeert als statussymbool: de prijs van de machine fungeert voor het bezittende instituut als het tastbare bewijs van eigen importantie. Maar het is duidelijk, dat dit statussymbool alleen maar effectief als zodanig werkt, wanneer je te pas en te onpas de prijs, bij voorkeur naar boven afgerond op een geheel aantal millioenen, van de daken schreeuwt! Met de slee van een wagen, die je als particulier voor je deur hebt staan "to keep up with the Joneses" hoeft dat niet meer, omdat bij een auto de prijs door omvang en chroomstrips er duidelijk van afstraalt. Als iemand de prijs van zijn rekenmachine noemt, moet U zich daardoor niet laten overdonderen, want dat was juist zijn bedoeling! Tussen neus en lippen door laat ik bv. even vallen, dat het Rekencentrum van de TH een machine van 3.000.000 heeft: om het er nog eens extra in te drukken reken ik U ten overvloede voor dat dit met 3000 studenten neerkomt op een investering van fl. 1000 per student, opdat U naar huis zult gaan, diep onder de indruk van wat hier in Eindhoven de TH voor zijn studenten overheeft..... Voelt U het fijntjes, de bluf, de humbug?

Tot zover de publiciteit, die aan de prijs gegeven wordt. Nadat we de prijsbeleving van sensatie en emotie ontdaan hebben, blijft het feit daar, dat dit soort apparatuur aan de prijzige kant is en ik wil proberen om U daarvoor enig begrip bij te brengen, opdat U zich minder aan de prijs vergaapt.

Als jongetje rekende ik prijzen om in ijsjes: een keer met de tram kostte twee ijsjes. Later becijfer je, dat een huis bijv. 15 VW's kost. Laten we nu een rekenautomaat, een stuk rekengereedschap, eens vergelijken met een veel simpeler stuk gereedschap, zeg een nagelschaartje: kunnen we dan begrijpen dat een rekenautomaat bijv. evenveel kost als een millioen nagelschaartjes?

Als U een stuk gereedschap koopt, dan eist U daarvan, dat het doet, wat U ervan verwacht en waarvoor het verkocht wordt en U wilt zich daarvan zelfs graag overtuigen. Als U een nagelschaartje koopt, probeert U het daarom eerst in de winkel: eerst wat nagels van Uw linkerhand, want die knippen het gemakkelijkst en als die mooi afgeknipt worden probeert U nog wat nagels van Uw rechterhand en als dat ook mooi gaat concludeert U, dat het schaartje U wel bevalt: U hebt naar genoegen vastgesteld, dat het inderdaad nagels knipt en dus gaat U tot de aanschaf over.

Maar nou een rekenautomaat: de fabrikant vertelt U o.a. dat zijn machine bijv. twee willekeurige getallen van 8 cijfers in 10 microseconde feilloos met elkaar vermenigvuldigt. Nou, zo'n claim liegt er niet om en wat ligt nu meer voor de hand dan dat U, voordat U tot aanschaf overgaat, net als bij het nagelschaartje, de machine even al deze vermenigvuldigingen laat doen, om te kijken of het product inderdaad steeds correct berekend wordt. De machine is immers zo snel, laat hem zijn kunsten maar even vertonen! We willen het wel eens zien!

Maar als we zo denken, dan hebben we ons een paar grootteordes vergist. Als we getallen van acht cijfers met elkaar vermenigvuldigen, dan zijn er 10 tot de 16de verschillende vermenigvuldigingen, die we moeten proberen. Elke vermenigvuldiging vergt 10 microseconde, d.w.z. 10 tot de 5de per sec., zodat dit pakket vermenigvuldigingen 10 tot de 11de sec. vergt; met 100 000 sec. in een etmaal komen we op millioenen etmalen, is ongeveer 3000 jaar. De machine zou, in weerwil van zijn fantastische snelheid, 3000 jaar lang constant dag en nacht moeten staan vermenigvuldigen voordat elke mogelijke vermenigvuldiging van twee getallen van 8 cijfers een keer aan de beurt geweest is!

De moraal van deze berekening is, dat een rekenautomaat inderdaad een heel ander soort gereedschap is dan een nagelschaartje, dat naast fabricageproblemen het aspect van de kwaliteitscontrole en onderhoud om het voorzichtig uit te drukken er wel een paar facetten heeft bijgekregen. Een en ander klemt des te meer, omdat rekenautomaten juist aan hun grote betrouwbaarheid een goed stuk van hun bruikbaarheid ontlenen. Met deze uitwijding hoop ik U ervan overtuigd te hebben, dat rekenautomaten bij nadere beschouwing inderdaad vrij miraculeuze precisie-instrumenten zijn, dat, mogen ze dan vrij duur zijn, we aan de andere kant toch ook wel bijzondere waar voor ons geld krijgen. En tenslotte hoop ik, dat U in genoemde overtuiging zich niet meer zo erg aan hun prijs vergapen zult.

De volgende sensationele superlatief, die ik te lijf wil gaan, is hun veel geadverteerde snelheid: ik zeg altijd maar zo, we rekenen met de lichtsnelheid, en berekeningen, die vroeger lichtjaren vergden, doen we tegenwoordig in seconden. Voor een goed begrip wil ik vooropstellen, dat deze snelheid soms op een volslagen misleidende manier geadverteerd wordt: wanneer er geadverteerd wordt "Onze computers nemen voor U meer dan 500 000 beslissingen per seconde" dan is hier het woord "beslissing" gebruikt in een betekenis, die niets meer gemeen heeft met de betekenis, die wij er normaal aan toekennen: een afwegen van pro en contra, een handeling waarvan wij de wijsheid kunnen bewonderen en zo.

Zoniet misleiding, dan toch wel vertekening, vinden we in de opmerking dat rekenautomaten cijferwerk millioen tot milljard maal zo snel kunnen als een mens. Lawenoueerlijkweze: die machine is er voor gemaakt en kan dan ook bitter weinig anders. En dat ik, of een van U allen for that matter, in de wieg gelegd zijn om louter cijferwerk te verrichten, nee, dat wil er bij mij niet in. De vergelijking is vertekenend om de erin vervatte suggestie, dat een rekenautomaat, die millioen maal zo snel cijfert als een mens, over de hele linie millioen maal zo veel kan.... millioen maal zo hard verliefd zijn bijv.

Inplaats van ons door deze snelheid te laten overdonderen kunnen we ons, om een en ander in een juister perspectief te zien, beter afvragen, waarom ze eigenlijk zo ontzettend snel moeten zijn.

Hiervoor zijn drie redenen aan te geven. Er is ten eerste eenn technische reden: de constructie van betrouwbare rekenautomaten wordt terecht beschouwd als een van de triomfen van de electrotechniek der laatste decennieen. Dit is met name mogelijk gemaakt doordat men zich tot constructies beperkt heeft, waarin (op zekere korrelgrootte beschouwd) op elk moment nooit meer dan 1 handeling tegelijkertijd wordt uitgevoerd. Het feit dat alle handelingen achter elkaar uitgevoerd moeten worden, dat de machine pas aan de volgende handeling kan beginnen als de vorige voltooid is, dat ze plaatsvinden als kralen van de ketting die langs het draadje genaamd "de Tijd" geregen wordt, heeft natuurlijk tot gevolg dat als men wil, dat in een bescheiden tijdsbestek een groot aantal handelingen plaatsvindt, er voor elke individuele handeling maar heel weinig tijd ter beschikking is. Rekenautomaten verrichten hun handelingen zo snel omdat dit, paradoxalerwijze, technisch makkelijker is.

Ten tweede maakt de beperking tot machines die op elk moment maar 1 handeling uitvoeren, de werkzaamheden, die door de machine verricht moeten worden, vanuit logisch standpunt bezien veel gemakkelijker organiseerbaar. De logische voorliefde voor "pas met het volgende beginnen als het vorige is afgehandeld" is niet los te denken van de manier waarop wij als mensen met elkaar communiceren: wie spreekt of schrijft produceert bijv. zijn zinnen woord voor woord, zijn betoog zin na zin. Ter verduidelijking moge ik U een parafrase geven: laat in een stad een handeling zijn een autorit van vertrekpunt naar bestemming. Als nu het verkeer zo afgehandeld zou kunnen worden, dat er steeds maar 1 auto op de weg is, zodat de volgende auto pas vertrekt als de vorige zijn bestemming bereikt heeft, dan is in deze stad verkeersregeling, stoplichten en de hele ratteplan overbodig. Je hoeft niet eens meer rechts te houden! Dit ter illustratie van de logische eenvoud die met de tijdopeenvolging bereikt kan worden: allerlei logische conflicten - het abstract analogon van botsingen op kruispunten - worden automatisch omzeild.

Er is een derde en laatste oorzaak en die verklaart, waarom de machine zoveel handelingen verrichten moet voordat hij een zinnig resultaat bereikt heeft. De oorzaak hiervan is, dat allerlei gewone zaken op de keper beschouwd veel moeilijker zijn dan wij ons doorgaans realiseren. Ik wil U een klein voorbeeld geven. Ik fluit zeven tonen en vraag aan U om dit te herkennen...... Akkoord, U hoort de Marseillaise. Door de Marseillaise te horen getuigt U van slecht psychologisch inzicht, want mijn afkeer van De Gaulle is dusdanig, dat ik nooit dit volkslied, waarvan de woorden bovendien invulgariteit met de melodie wedijveren, in publiek zou aanheffen. Wat ik natuurlijk floot was de pianoinzet van het concert in C, KV503 van Mozart..... Waarmee ik U even aan den lijve heb willen laten ervaren, dat bijv. het herkenningsprobleem moeilijker is dan U denkt.

Aan collega Freudenthal ontleen ik het volgende voorbeeld: het werk van de portier, die beleefd de deur openhoudt, als iemand een gebouw wil binnengaan, is wel ongeveer het stomste wat we kunnen bedenken en bij allerlei gebouwen als banken, air terminals etc. vindt U die portier dan ook geautomatiseerd met behulp van een fotocel of een drukdetector onder de mat. Zouden wij echter ook willen automatiseren, dat de binnenkomende gesexed wordt en de automaat netjes willen laten zeggen "Welkom mijnheer" of "Welkom Dame", dan zouden we voor waarschijnlijk onoverkomelijke moeilijkheden komen te staan, zelfs als de automaat alleen correct zou hoeven te werken voor mannen met korte haren en lange broeken en meisjes van een aggressieve vrouwelijkheid met lange haren en in minirokjes als keukenvalletjes..... Dergelijke herkenningsproblemen, waarbij wij in het dagelijks leven nauwelijks stilstaan omdat we ze aan de lopende band onbewust verrichten, blijken bij nadere analyse voor een automaat vaak helse, zoniet onmogelijke opgaven. Ik noem slechts het lezen van met de hand beschreven formulieren!

Beroemd is het verhaal van de student die doordat hij een bijbaantje had gehad voor kwam in de administratie van de inkomstenbelasting. Een jaar later zat hij voor een examen en verdiende hij niets en over dat jaar kreeg hij geheel correct overigens, een aanslag van 0 gulden en 0 cent, een aanslag, die de studentn begrijpelijkerwijze negeerde. Dit had evenwel tot gevolg dat hij na enkele maanden een aanmaning kreeg wegens achterstallige betaling van... 0 gulden en 0 cent! Een menselijke klerk zou, zonder zich van een beslissing bewust te zijn, in dit geval het aanslagbiljet niet verzonden hebben: voor een rekenautomaat betekent dit dat <u>elke</u> keer, wanneer een aanslag berekend is, vervolgens getest moet worden of het bedrag soms 0 gulden en 0 cent is om in dat exceptionele geval de verzending te kunnen onderdrukken. Samenvattend kunnen we zeggen "rekenautomaten moeten zo snel zijn, want anders kwamen ze helemaal nergens".

Onderschatting van hoe moeilijk en ingewikkeld allerlei alledaagse processen zijn is, zeker in de begintijd van de automatisering, er voor verantwoordelijk geweest dat een aantal grootscheeps opgezette automatiseringsprojecten, met name in de administratief-organisatorische sectie van het bedrijfsleven, beruchte debacles zijn geworden. Doorgaans kreeg de rekenmachine hiervan de schuld, maar ik geloof niet, dat die voorstelling van zaken helemaal eerlijk was. Je kunt nl. met evenveel recht stellen, dat naar de normen van een ordelijk denkend mens het bedrijfsgebeuren een onbeschrijfelijke chaos is, een chaos die door zijn onbeschrijfelijkheid qualitate qua elke automatisering tart.

Ik noem die chaos even, omdat er stemmen opgaan het Nederlandse Universitaire bestel te louteren door uit het bedrijfsleven bekende organisatietechnieken er in te voeren. Maar als je ziet hoe ontstellend chaotisch en ineffici&euml;nt het bedrijfsleven functioneert, dan is dat idee gewoon een lachertje, om niet te zeggen een gillerd: we zouden als hogeronderwijs bij de duivel te biecht gaan. Van de meeste bedrijven krijg je de indruk, dat ze alleen maar niet over de kop gaan doordat het bij de concurrent net zo knullig toegaat.... Japanse bedrijven misschien uitgezonderd maar die zouden ons dan ook best eens uit de markt kunnen drukken. Dit terzijde.

Wij gaan de volgende klasse opgewonden superlatieven te lijf: rekenautomaten zijn zo fabelachtig machtig, electronische breinen verdringen het intellect, anno 2000 worden we door robots geregeerd en dergelijke. Naar aanleiding van deze verontrusting wil ik U ter afkoeling een stukje van een ander voorlezen: omdat mijn uitspraak van het Frans niet zo gesmeerd verloopt en opdat U de schrijver niet direct herkennen zult, het ik het zo goed mogelijk vertaald.

Begin citaat: "Het gebruik van een geleerd instrument heeft van jou geen dorre technicus gemaakt. Mij dunkt, dat zij, die door onze technische vooruitgang in paniek raken, doel en middel met elkaar verwarren. ... De machine is geen doel, zij is gereedschap, een stuk gereedschap net als een ploeg.

Als wij geloven, dat de machine de mens vernedert, dan komt dat misschien omdat wij onvoldoende gemakkelijk een stap achteruit doen om van een afstandje de gevolgen van alle veranderingen even snel te verwerken als wij ze zijn ondergaan. Wat zijn die 100 jaar van de machine vergeleken met de 200 000 jaar geschiedenis der mensheid? Wij hebben nog nauwelijks dit landschap van kolenmijnen en electrische cetrales om ons heen opgebouwd. We wonen als mensheid nauwelijks in dit nieuwe huis, dat we nog niet eens afgebouwd hebben! Alles om ons heen is zo snel veranderd: menselijke betrekkingen, werkomstandigheden, gewoontes. Zelfs het beeld dat wij ons vanzelf koesteren schudt op zijn intiemste grondvesten. Begrippen als vertrekken, wegzijn, thuiskomen, dekken, hoewel de woorden gelijkgebleven zijn, niet meer dezelfde werkelijkheid. Om de wereld van vandaag te vatten, moeten we ons behelpen met de woorden van gisteren. En het leven van gisteren lijkt ons menswaardiger, louter en alleen omdat het leven van gisteren beter past bij onze taal!

Elke vooruitgang verjaagt ons een beetje verder uit de gewoontes, die we ons net eigen gemaakt hadden; wij zijn als emigranten, die hun nieuwe vaderland nog niet gesticht hebben.....

Maar ons huis zal beetje bij beetje weer bewoonbaar worden: naarmate de machine volmaakter zal zijn, zal zij haar rol harmonischer vervullen". Einde van het citaat.

Dit had vandaag naar aanleiding van de rekenautomaat geschreven kunnen zijn: het is echter meer dan 30 jaar oud en refereert naar het 1-motorige vliegtuigje waarmee Antoine, Comte de Saint-Exupery de postzakken over de Sahara vloog. Ik heb een en ander geciteerd om te laten zien, dat de huidige verontrusting een verontrusting aller tijden is. Het is de uiting van een overigens gezond conservatisme, dat door de eeuwen bestaan heeft en zal blijven bestaan: de behoefte aan voldoende continuiteit om onszelf nog als zodanig te kunnen herkennen.

Maar goed, wat doen we met het angstvisioen, dat de mensheid anno 2000 door rekenautomaten geregeerd, om niet te zeggen gekoeieneerd zal worden? Enerzijds kan je je als neutrale derde opstellen en zeggen "Wel, als de mensen het zover laten komen, verdienen ze ook niet beter." Mijn reactie is anders: ik geloof het niet. Rekenmachines zullen niet weg te denken zijn uit de samenleving, akkoord, maar dat is nog iets heel anders dan "beheersen" of "regeren"!

Ze zullen de samenleving tekenen, zoals deze een paar honderd jaar geleden getekend werd door kindersterfte, stormrampen, overstromingen, droogte, pest, cholera en godsdiensttwisten... Ik wil U wel vertellen dat voor mij de keus dan niet moeilijk is: ik leef liever morgen met rekenautomaten dan dat ik een paar honderd jaar geleden aan de pest stierf! Van rekenautomaten kun je bovendien vaststellen, dat ze niet levensgevaarlijk zijn als de producten van de physica en de biochemie, en dat ze niet stinken zoals auto's en chemische industrie&euml;n en niet zo lawaaierig zijn als straalvliegtuigen. Kortom van de hele scala technische verworvenheden is het een van de aangenaamste om mee te leven. Bovendien is het in de machinekamer altijd lekker koel, want die heeft w&egrave;l air-conditioning.

Vanwaar dan deze paniek der futurologen? Ik zou de veronderstelling willen wagen, dat de verklaring hiervoor meer gezocht moet worden in onze psyche dan in een re&euml;el gevaar dat van rekenautomaten zou dreigen. Door zijn onbekendheid, zijn onbegrepenheid heeft de rekenautomaat iets magisch, dreigends en onheilspellend. En daarenboven: de rekenautomaat komt ons in zijn verrichtingen iets te na, iets nader dan ons lief is. Door zijn quasi-intelligente prestaties voelen we ons in eerste instantie gegrepen, iets van onze menselijke uniekheid valt in duigen.

We voelen ons door de rekenautomaat die millioenen maal zo snel cijfert als wijzelf meer in onze waardigheid aangetast dan door het straalvliegtuig, dat oneindig veel beter vliegt dan wij zelf, tenminste zolang we nog geen engeltje zijn.

Het komt ons gewoon iets te na, net als vanwege alle emotionele associaties... harttransplantaties. De publiciteit vertoont in beide gevallen grote overeenkomst! Maar het zal wel wennen, net zo goed als we geen spier meer vertrekken bij bemande ruimtevluchten, hoewel we de eerste keer, dat we wisten dat er een kerel rondcirkelde, die nog heelhuids terug moest komen, collectief in de zenuwen hebben gelegen. Wij waren voor die spanning immers niet zo goed opgeleid als die astronaut...

Terug naar de rekenautomaten: in de handen van een geheime politie kunnen ze natuurlijk worden tot een uiterst gevaarlijk wapen, maar wat kan dat niet? Wie The Organization Man van White of het veel goedkopere Life in 1984 leest, lopen af en toe de rillingen over de rug, maar dat is toch ook de bedoeling van die boeken? Als alle gereedschap kunnen ook rekenautomaten ten goede en ten kwade worden aangewend, maar ik zie niet in, waarom bij rekenautomaten het gevaar nu juist extra groot zou zijn. Ik zou bijna willen zeggen: "Integendeel".

Wat mij veel meer beangstigt zijn opgezweepte volksmassa's en de pompeuze taalverstarring, die aan het rechtlijnig denken van elk extremisme ten grondslag ligt. En als men van de omgang met rekenautomaten iets leert, dan is het juist dat al wat wezenlijk is, zich niet zo gemakkelijk in een enkele formule vangen laat.

Volgens zonnige optimisten zal de automatisering eindelijk de mensheid in staat stellen om bevrijd van slavenwerk een menswaardig bestaan te leiden. Pessimisten tekenen daarbij aan, dat het merendeel van de mensheid met het inrichten van dat menswaardige bestaan grote moeite zal hebben. Beide uitspraken gaan uit van een vrij specifiek waardeoordeel over de mens en zijn werk; ik neem aan, dat we in geval van nood dit oordeel wel weten aan te passen.

Zonder ons in waardeoordelen te begeven, kunnen we wel een paar nuchtere constateringen doen. Men hoeft geen groot profeet te zijn om te voorspellen dat een aantal van de eenvoudigere functies het eerst voor de bijl zal gaan. Het is ook duidelijk, dat het geestelijk niveau van de man, die met een automaat mensen werk uit handen kan nemen, enige niveaux hoger moet zijn dan dat van de mensen, wier werk wordt overgenomen en de moraal is, dat de relatieve behoefte aan elite eer toe dan af zal nemen. Dit is een opmerking die ik tegenover U, leermeesters der volgende generatie, niet graag zou hebben verzwegen. Wat thans nog moderne bedrijfsvoering heet is over 't algemeen vrij expliciet gericht op de exploitatie van de middelmaat: allicht, want daarvan heb je er zoveel. Binnen afzienbare tijd kon het er wel eens veel meer om gaan, in hoeverre het bedrijfsleven in staat is om de potenti&euml;le vruchten van het werk van de elite te plukken en ik ben daar niet gerust op. In dit licht bezien zijn plannen om de bedrijfsvoering van het Nederlandse Hogeronderwijs te schoeien op de thans nog geaccepteerde bedrijfskundige leest, ronduit beangstigend. Het tragische is, dat invloedrijke en overigens niet van gezonde inzichten gespeende lieden van dergelijke maatregelen heil verwachten.

Tenslotte: hoe bevalt me nu eigenlijk de rekenautomaat als gebruiksvoorwerp? Uit eigen ervaring kan ik alleen maar zeggen "heerlijk". Het is een fascinerend, flexibel en betrouwbaar stuk gereedschap, dat je van alles zou kunnen laten doen, als je maar wist hoe. En in de praktijk ontdek je gauw, dat we dat maar heel zelden weten, word je er dagelijks mee geconfronteerd, dat wij mensen maar heel, heel kleine hoofdjes hebben, waarvan we nog niet eens weten hoe ze werken ook. Gebruik van een rekenautomaat mondt meestal uit in een louterend lesje in de bescheidenheid en juist daarom noem ik hem "een heerlijk stuk gereedschap".

Ik heb gezegd.

Prof.dr. E.W. Dijkstra.

transcribed by Jeanine Daems
revised Sat, 27 Jan 2007

EWD 232

Pretentie en doelstelling van het THE multiprogrammeringsproject.

Zoals bekend bestaat 90% van de wereldbevolking uit kruideniers. Omdat onder programmeurs het percentage ten minste zo hoog is, leid ik de overige sprekers in.

Het is mijn ervaring dat de overgrote meerderheid der programmeurs, systeembouwers en zelfs machinebouwers hun werk in eerste instantie beschouwen als een optimaliseringsopgave, nl. de minimalisering van wat ze de "cost/performance ratio" noemen. Wij hebben geweigerd—of, zo U wilt, ik heb geweigerd en mijn medewerkers zijn mij hierin bijgevallen—om aan dit efficiencystreven het primaat te geven en wij hebben het multiprogrammeringsproject in eerste instantie beschouwd als intellectuele uitdaging: hoe kan je zorgen dat in een dergelijk systeem de complexiteit je niet boven het hoofd groeit, hoe kan je zorgen dat je het ontwerp- en constructieproces blijft beheersen. Slechts binnen de speelruimte, die ons hierdoor gelaten werd hebben wij efficiencyoverwegingen ons doen en laten laten beïnvloeden.

Ik heb ervaren dat geschilderde relativering van de efficiency eis voor hen, die van efficiency hun heilig ideaal gemaakt hebben, niets meer of minder dan heiligschennis is. Ik ben dan ook bejegend als de rebel, die zich niet aan de spelregels gehouden heeft. Wanneer na afloop blijkt, dat wij in weerwil van de veronachtzaming waarvan we beschuldigd werden, een systeem geschapen hebben, waarvan de "performance figures" in dezelfde orde van grootte liggen, dan is de boot helemaal aan. Voor kruideniers is dit natuurlijk ook heel frustrerend en het ontlokt allerlei verzetsreacties tot bijna onverbloemde verdachtmakingen toe.

Maar ik vraag U een pas terug te doen. Lange tijd hebben rekenautomaten alleen fixed point arithmetiek ingebouwd gehad, niet alleen omdat floating point arithmetiek moeilijker te bouwen was, maar ook omdat John von Neumann ervan overtuigd was, dat je floating point arithmetiek niet nodig had, je kon je probleem best schalen. Desalnietemin zijn software makers met veronachtzaming van enige efficiency eisen floating point arithmetiek gaan implementeren en nu zijn we blij, dat dit in de hardware zit. Je zou in een moment van optimisme kunnen denken, dat de mensheid van die ervaring geleerd zou hebben, maar niets daarvan. Een aantal jaren later bij de opkomst van de programmeertalen, werd er weer moord en brand geschreeuwd, nl. door die programmeurs die in een gewiekste exploitatie van een speciale machine code hun hoogste goed zagen. En ettelijken zijn daarin blijven steken. En nu heb je de volgende generatie moord-en-brand-schreeuwers, nl. de programmeurs die de exploitatie van een specifieke configuratie als hun hoogste taak zien. Het wordt eentonig.

Maar het is duidelijk dat men de kunst van het programmeren, de kunst van het machinegebruik alleen dan verder kan helpen, wanneer men, zo daar goede gronden voor aanwezig zijn, bereid is de platgetreden paden te verlaten. En hierin ligt een van de redenen, waarom ik aan efficiency overwegingen niet het primaat wil geven: dat is nl. zo verlammend. Ik wil ze wel in het oog houden, maar dat is heel iets anders. En er waren ditmaal goede gronden. Toen we er aan begonnen, zijn we nog voor gek versleten—schriftelijk zelfs, maar ik zal de firma die dat gedaan heeft, niet noemen. U mag één keer raden—de ontwikkeling heeft aangetoond dat er in de rest van de wereld (laten we het voorzichtig uitdrukken) meer van zulke gekken te vinden waren.

Nu over het project zelf. Ik heb de EL X8, waarvoor we dit gedaan hebben, nooit beschouwd als speciaal voor multiprogrammering ontworpen, eer als inspirerende machine om het mee te proberen. Ik noem in dit verband speciaal de interrupt hardware, waarop je op logische gronden verliefd kunt worden. Ik wil hier graag met nadruk verklaren dat het entameren van het multiprogrammeringsproject onverantwoord zou zijn geweest, als wij niet met zekerheid hadden kunnen aannemen dat we, in geval het niet zou lukken, de software van het MC achter de hand zouden hebben om hier het Rekencentrum te bedrijven. Zonder dat vertrouwen hadden wij ons nooit kunnen permitteren dit stukje "Hogeschool programmering" weg te geven. Ik wil graag aan de vergetelheid onttrekken dat het tot begin 1967 geduurd heeft, voordat wij er vertrouwen in begonnen te krijgen, dat we een werkend "workable" systeem zouden produceren. En zelfs sindsdien heeft dat vertrouwen nog wel eens gewankeld. Je vergeet dit zo gauw, maar we zijn heel vaak heel bang geweest.

Wie een multiprogrammeersysteem ontwerpt, loopt onmiddellijk tegen de toewijzingsproblemen aan. Je kunt het je in dezen makkelijk maken en royaal met vaste toewijzingen werken, je kunt moeilijk maken en zoveel mogelijk dynamisch uitwisselbaar houden. Wij zijn in de laatste richting vrij ver gegaan en hebben ons over dit beoogde raffinement allerlei ellende op de hals gehaald. Voor kenners noem ik de bankiersalgorithme als notoir voorbeeld; voorts noem ik de bereidheid van het systeem om de geheugenruimte, die normaal voor transportbuffering ter beschikking staat, dynamisch in te krimpen als meer ruimte voor de programmaverwerking nodig blijkt. Tilt men niet zo zwaar aan dit raffinement, dan kan men een goed stuk van het systeem beschouwen als "self inflicted pain". In antwoord hierop zou ik, zonder nu mijzelf als masochist te willen presenteren, willen zeggen "Daar ging het ons in zekere zin om." Wij zijn geen lustprogrammeurs in de zin, dat we het ons liever moeilijk dan makkelijk hebben gemaakt. Integendeel, elke complicerende factor moest een aanwijsbaar doel dienen, voordat hij werd toegelaten en in het ontwerpstadium hebben we ook ettelijke er weer uitgepraat. Het ging ons wel om een opgave die alle mogelijkheid in zich borg om ondoenlijk moeilijk te worden om dan te ontdekken hoe men vervolgens het werk zo makkelijk kan houden dat men het tot een goed einde brengen kan.

Het multiprogrammeringssysteem is met een dubbel doel ontwikkeld. Ten eerste wilden we voor kleine programmaatjes de turn-around time verkorten. Van batch-processing systemen was ons bekend, dat de turn-around time vaak in de uren ging lopen, ook al vergde het programmaatje maar enkele minuten rekentijd. Aangezien wij door de studentenbevolking vele kleine programmaatjes verwachten vonden we dit onaantrekkelijk. Een multiprogrammeringssysteem, waarin een langdurig programma de machine niet blokkeert, schept een van de voorwaarden om de turn-around time voor kleintjes veel kleiner te laten zijn.

Ten tweede wilden we de mogelijkheid tot enkele gebruiksvormen scheppen, die zonder multiprogrammering zouden afketsen op te inefficiënte benutting van het rekenorgaan. We wilden de programmeur ontlasten van de plicht rekening te houden met de tweeslachtigheid van het geheugen: het systeem verzorgt automatisch de noodzakelijke transporten tussen langzaam en snel geheugen als het snelle geheugen te klein blijkt. Dit geschiedt volgens "demand pageing", dus, informatie wordt pas uit het langzame geheugen voorgaats gehaald als het verwerkende proces er aan toe is en de informatie op dat moment niet in de kernen aanwezig is. Gedurende het dan volgende transport kan het verwerkende proces niet verder! Multiprogrammering is een methode om gedurende die transporttijd nochtans emplooi voor het rekenorgaan te vinden. Vervolgens wilden we de machine kunnen gebruiken voor processen, die qualitate qua slechts op een fractie van de tijd van het rekenorgaan beslag leggen. Wij noemen in dit verband de extra bandlezer en bandponser, waarmee men "in een hoekje van de machine" banden dan copiëren, corrigeren etc. en de tweede teleprinter die voor experimenteel conversationeel werk bestemd is, en een dezer weken in het systeem zal worden opgenomen. De derde toepassing, waarmee we rekening willen houden was online koppeling met meet-apparatuur. Dit laatste is nog niet gerealiseerd, in de enkele gevallen, dat er sprake van is geweest bleken de hieraan verbonden verplichtingen kwantitatief gezien prohibitief te zijn.

Wat wij niet hebben wilen maken was een multi-access systeem dat consoles alom bedient. Dat was één à twee jaar geleden "le dernier cri" maar ik houd er ernstig rekening mee dat dit in zijn huidige vorm een modegril van voorbijgaande aard zal blijken. Ik, voor mij, zou de installatie van een dergelijk systeem ook niet durven aanbevelen voordat mij een verantwoorde wijze van gebruik voor ogen stond. Maar zoiets hebben we met dit systeem ten duidelijkste dus niet geprobeerd.

Rest mij slechts U te danken voor Uw aanwezigheid en Uw belangstelling en het woord te geven aan de volgende sprekers.

transcribed by Angelo van der Sijpt
revised Mon, 12 Feb 2007

EWD235

Contractie en expansie.

Samenvatting. Twee operaties, “contractie” resp. “expansie” gedoopt, worden onderkend. Zij worden bestudeerd in hun samenhang met assemblage, adresarithmetiek, geheugenindeling en protectie. Een en ander lijkt er op te wijzen, dat het begrip “adresruimte” en deszelfs zinvolheid voor een hernieuwd critisch onderzoek in aanmerking komen. NB. Als associatieve geheugens op grote schaal ter beschikking komen, verliest dit onderzoek een aanzienlijk stuk van zijn relevantie.

1. Open en gesloten adressering.

Ik spreek van een gesloten adressering, wanneer de objecten van een verzameling geidentificeerd zijn door consecutief oplopende nummers, zeg bij nul te beginnen. Een gesloten adressering laat zich implementeren door een op consecutieve geheugenplaatsen opgeborgen tabelletje: de adresarithmetiek —dwz. de overgang van identificerend nummer naar ~physisch adresimpliceert optelling van identificerend nummer en ~physisch beginadres van het tabelletje.

Ik spreek van een open adressering wanneer de objecten van een verzameling geidentificeerd zijn door (nonnegatieve) nummers, waarbij het maximale nummer (veel) groter is dan het aantal objecten in de verzameling. In principe is een open adressering op dezelfde wijze te implementeren als een gesloten, als we nl. de gaten in de tabel voor lief nemen. Ik ga echter van een open adressering spreken als we ons dit niet meer kunnen veroorloven en we naar andere technieken moeten omzien (hashed adressing, associatieve geheugens, naamlijsten die gescand moeten worden etc.) Opm. De openheid van een adressering is dus een gradueel begrip: hij kan zo'n klein beetje open zijn, dat we hem nog als gesloten kunnen beschouwen.

Uitgangspunt van dit onderzoek is de observatie dat een beroep op open adressering vaak zo kostbaar is, dat men zoekt naar wegen om het aantal malen dat dit moet gebeuren, te reduceren. Het is hier, dat de operatie's contractie en expansie een rol spelen.

2. De operaties “contractie” en “expansie”.

De operaties “contractie” en “expansie” zijn elkaars inverse.

Gegeven een grote verzameling objecten, waarvan ik eenvoudshalve aanneem, dat zij hierin door een gesloten adressering geidentificeerd zijn. We noemen dit even “de globale adressering”. Indien in een zekere context slechts naar een relatief kleine keuze van deze objecten gerefereerd wordt, dan is de globale adressering betrokken op deze keuze een open adressering. We spreken van contractie wanneer de gekozen objecten ten bate van de genoemde context aansluitend hernummerd worden; deze aldus ingevoerde “locale adressering” is betrokken op deze keuze dan gesloten. De locale adressering is een exploitatie van de wetenschap dat de context in kwestie zich afspeelt in een gecontraheerd universum.

Gegeven een context die via een gesloten adressering elementen van een verzameling bespeelt, dan spreken we van expansie als we genoemde verzameling gaan beschouwen als deel van een grotere verzameling en daarmee de elementen als elementen uit een grotere verzameling. De overgang van de locale adressering naar een globale is veronachtzaming van de wetenschap, dat de genoemde context zich in het gecontraheerde universum afspeelt.

(Ik zal in nog iets ruimer verband van expansie spreken, nl. als onze objecten informatiehoeveelheden zijn, voor elk waarvan een aansluitend stuk geheugen ter beschikking moet worden gesteld. De overgang van identificeren door nummer naar identificeren door beginadres zal ik ook expansie noemen.)

3. De organisatie van een subroutinebibliotheek.

In deze sectie beschrijf ik een subroutineorganisatie die de kenners zal treffen als een verder doorgevoerde automatisering van de subroutineorganisatie van de EDSAC 1 (1949). De keuze is hierop gevallen omdat dit het eenvoudigste voorbeeld lijkt waarmee we kunnen illustreren hoe expansie en contractie functioneren.

We beschouwen een subroutinebibliotheek met een zeer groot aantal subroutines. Ik neem aan, dat de routines in de bibliotheek geidentificeerd zijn door catalogusnummer CN en dat catalogusnummers in de totale bibliotheek een gesloten adressering vormen.

Subroutineteksten verwijzen als regel naar zichzelf en naar enkele andere subroutines in de bibliotheek. Men zou dit in termen van catalogusnummers kunnen doen; in plaats daarvan wordt ten bate van de formulering van de routine contractie gepleegd en verwijst de subroutinetekst in een gesloten locale terminologie naar zichzelf en die paar anderen. (In de EDSAC-organisatie heetten de locale namen “code letters”, bij de ARMAC en de X1 hebben ze als “sluitletters” nog jaren doorgeleefd.) Bij elke subroutine hoort een zg. “expansietabel”, die de locale terminologie vertaalt in catalogusnummers; de expansietabel bevat dus een rijtje CN-waarden.

Zodoende kan een subroutinetekst zelf geformuleerd worden op een wijze die onafhankelijk is van de bibliotheek waarvan hij deel uitmaakt (dwz. onafhankelijk van de omvang van de bibliotheek en de hierin gebruikte catalogusnummers). De locale terminologie heeft geen groter onderscheidend vermogen nodig dan vereist voor het onderscheid tussen de subroutines waarnaar hij werkelijk verwijst. Als om een of andere reden herindeling van de bibliotheek met verandering van de catalogusnummers gewenst is, dan beperkt de hieruit voortvloeiende bijwerkplicht zich tot de goed geisoleerde expansietabellen. Tenslotte biedt de expansietabel de uitwendige referenties op een presenteerblaadje.

Nu het probleem van assemblage; opdat dit een probleem zij neem ik aan dat de bibliotheek veel te groot is om permanent in het werkgeheugen te bivakkeren; voorts neem ik aan dat slechte een kleine fractie van de bibliotheek in een programma wordt opgenomen.

Als nu benodigde teksten en bijbehorende expansietabellen onveranderd in het geheugen zijn gekomen, welke mechanismen hebben we dan nog nodig?

Om steeds de heersende locale terminologie te kunnen interpreteren veronderstel ik aanwezig een toegewijd register, bevattende het beginadres van de vigerende expansietabel. Daar vinden we echter in eerste instantie het catalogusnummer terwijl men, om een subroutine aan te kunnen roepen, beginadressen van tekst en expansietabel moet weten. Sinds invoer zijn deze gegevens bekend; doordat echter maar een klein gedeelte van de bibliotheek in het werkgeheugen is opgenomen, vormt net catalogusnummer hiervoor een uiterst open adressering.

Het antwoord hierop is contractie. Voor de in het programma opgenomen routines voert men een gesloten adressering in; laten we deze de “selectienummers” SN noemen. De taak van het assemblageprogramma omvat nu

1) het toekennen van selectienummers aan op te nemen routines

2) het bijwerken van op te nemen expansietabellen, zodat elke entry (ook) het toegekende selectienummer bevat

3) het invullen van de zg. “selectietabel”; dit is een expansietabel voor het hele programma voor de overgang van selectienummer naar de beginadressen.

Assemblage presenteert zich hier dus als contractie; omdat dat een vervelende operatie is loont het de moeite dit eenmalig per programma te doen. Subroutineteksten zijn ongewijzigd gebleven, de expansietabellen zijn per entry uitgebreid.

4. Vermindering van diepte van indirecte adressering.

De overgang van de locale terminologie van een subroutinetekst naar physisch adres kost nu tweemaal het raadplegen van een expansietabel

a) het raadplegen van de expansietabel van de heersende subroutine geeft een selectienummer SN

b) met deze SN-waarde raadplegen van de selectietabel van het programma geeft een physisch adres.

Als deze tweevoudige expansie te tijdrovend geacht wordt staan ons ter bespoediging twee wegen open, nl. het kortsluiten van de eerste, resp. de tweede expansie!

Methode A. Men laat het assemblageprogramma de subroutineteksten herschrijven door de locale terminologie te vervangen door SN’s. De expansietabellen hoeven dan tijdens uitvoering niet meer geraadpleegd te worden: onder controle van de door de programmatekst geleverde SN-waarde kan in de selectietabel meteen het adres gevonden worden.

Methode B. De expansietabellen van de subroutines worden uitgebreid, zodat elke entry nu ook de beginadressen bevat, waardoor het frequent raadplegen van de selectietabel vervalt.

Methode A, die het meest de kant van klassieke assemblage uitgaat, heeft als grootste voordelen

1) het toegewijde register dat verwijst naar het begin van de heersende expansietabel kan vervallen (inclusief de hiermee geassocieerde reden herstelprocedures).

2) van elke subroutine komt het beginadres slechts 1 keer in de administratie voor (nl. in de selectietabel) wat herziening van een dergelijk adres wel vergemakkelijkt.

Het nadeel van methode A is echter, dat de programmatekst niet meer onveranderd in het geheugen staat maar in een vorm, die afhangt van het grotere geheel, waar deze tekst nu deel van uitmaakt. En hoe langer ik erover nadenk, hoe zwaarder ik die prijs ga vinden.

Het punt is, dat expansie structuur verduistert en daarom zou men liefst het resultaat van de expansieoperatie zo volatiel mogelijk houden. Voelt men zich desondanks toch geroepen om een resultaat van expansie te laten beklijven, dan is dit minder schadelijk wanneer dit beklijven tot de tabellen beperkt blijft dan wanneer het expansieresultaat tot je laagste niveau, de programmatekst, diffundeert.

Ik moge hiervan een paar voorbeelden noemen..

Methode A vraagt om iets als een “linkage editor”, die bij methode B practisch vervalt.

Methode A maakt het onmogelijk om verschillende programma’s van de zelfde subroutinetekst gebruik te laten maken.

Als men de ene overblijvende expansie versnellen wil, dan vraagt dit bij methode A om een stukje heel snel geheugen zolang als de selectietabel (en als dat er niet is —de selectietabel groeit door combinatie!— om een klein associatief geheugen, dat de relevantste beginadressen bijhoudt); bij methode B kan volstaan worden met een snel geheugentje groot genoeg voor een expansietabel.

20 juni 1968 | E.W.Dijkstra

N.V. PHILIPS’ COMPUTER INDUSTRIE
APELDOORN

transcribed by Bart Vreugdenhil
revised 29-Dec-2011

  EWD 236

Complexity controlled by hierarchical ordering of function and variability.

by Edsger W. Dijkstra

     Reviewing recent experiences gained during the design and construction of a multiprogramming system I find myself torn between two apparently conflicting conclusions. Confining myself to the difficulties more or less mastered I feel that such a job is (or at least should be) rather easy; turning my attention to the remaining problems such a job strikes me as cruelly difficult. The difficulties that have been overcome reasonably well are related to the reliability and the producibility of the system, the unsolved problems are related to the sequencing of the decisions in the design process itself.

     I shall mainly describe where we feel that we have been successful. This choice has not been motivated by reasons of advertisement for one’s own achievements; it is more that a good knowledge of what — and what little! — we can do successfully, seems a safe starting point for further efforts, safer at least than starting with a long list of requirements without a careful analysis whether these requirements are compatible with each other.

     Basic software such as an operating system is regarded as an integral part of the machine, in other words: it is its function to transform a (for its user or for its manager) less attractive machine (or class of machines) into a more attractive one. If this transformation is a trivial one, the problem is solved; if not, I see only one way out of it, viz. ‘Divide and Rule’, i.e. effectuate the transformation of the given machine into the desired one in a modest number of steps, each of them (hopefully!) trivial. As far as the applicability of this dissection technique is concerned the construction of an operating system is not very much different from any other large programming effort.

     The situation shows resemblance to the organization of a subroutine library in which each subroutine can be considered as being of a certain ‘height’, given according to the following rule: a subroutine that does not call any other subroutine is of height 0, a subroutine calling one or more other subroutines is of height one higher than that of the highest height among the ones called by it. Such a rule divides a library into a hierarchical set of layers. The similarity is given by the consideration that loading the subroutines of layer 0 can be regarded as a transformation of the given machine into one that is more attractive for the formulation of the subroutines of layer 1.

     Similarly the software of our multiprogramming system can be regarded as structured in layers. We conceive an ordered sequence of machines: A[0], A[1], ... A[n], where A[0] is the given hardware machine and where the software of layer i transforms machine A[i] into A[i+1]. The software of layer i is defined in terms of machine A[i], it is to be executed by machine A[i], the software of layer i uses machine A[i] to make machine A[i+1].

     Compared with the library organization there are some marked differences. In the system the ‘Units of dissection’ are no longer restricted to subroutines, but this is a minor difference compared with the next one. Adding a subroutine of height 0 to the library is often regarded as an extension of the primitive repertoire which from then onwards is at the programmer’s disposal. The fact that, when the subroutine is used, storage space and processor time have been traded for the new primitive can often be ignored, viz. as long as the store is large enough and the machine is fast enough. Consequently the new library subroutine is regarded as a pure extension. One of the main functions of an operating system, however, happens to be resource allocation, i.e. the software of layer i will use some of the resources of machine A[i] to provide resources for machine A[i+1]: in machine A[i+1] and higher these used resources of machine A[i] must be regarded as no longer there! The explicit introduction (and functional description!) of the intermediate machines A[1] through A[n–1] has been more than more word-play: it has safeguarded us against much confusion as is usually generated by a set of tacit assumptions. Phrasing the structure of our total task as the design of an ordered sequence of machines provided us with a useful framework in marking the successive stages of design and production of the system.

     But a framework is not very useful unless one has at least a guiding principle as how to fill it. Given a hardware machine A[0] and the broad characteristics of the final machine A[n] (the value of ‘n’ as yet being undecided) the decisions we had to take fell into two different classes:
1)     we had to dissect the total task of the system into a number of subtasks
2)     we had to decide how the software taking care of those various subtasks should be layered. It is only then that the intermediate machines (and the ordinal number ‘n’ of the final machine) are defined.

     Roughly speaking the decisions of the first class (the dissection) have been taken on account of an analysis of the total task of transforming A[0] into A[n], while the decisions of the second class (the ordering) have been much more hardware bound.

     The total task of creating machine A[n] has been regarded as the implementation of an abstraction from the physical reality as provided by machine A[0] and in the dissection process this total abstraction has been split up in a number of independent abstractions. Specific properties of A[0], the reality from which we wanted to implement, were:
1)     the presence of a single central processor (we wanted to provide for multiprogramming)
2)     the presence of a two level store, i.e. core and drum (we wanted to offer each user some sort of homogenous store)
3)     the actual number, speed and identity (not the type) of the physically available pieces of I/O equipment (readers, punches, plotters, printers, etc.)

     The subsequent ordering in layers has been guided by convenience and was therefore, as said, more hardware bound. It was recognized that the provision of virtual processors for each user program could conveniently be used to provide also one virtual processor for each of the sequential processes to be performed in relatively close synchronism with each of the (mutually asynchronous) pieces of I/O equipment. The software describing these processes was thereby placed in layers above the one in which the abstraction from our single processor had to be implemented.

     The abstraction from the given two level store implied automatic transports between these two levels. A careful analysis of, on the one hand, the way in which the drum channel signalled completion of a transfer and, on the other hand, the resulting actions to be taken on account of such a completion signal, revealed the need for a separate sequential process — and therefore the existence of a virtual processor — to be performed in synchronism with the drum channel activity. It was only then that we had arguments to place the software abstracting from the single processor below the software abstracting from the two level store. In actual fact they came in layer 0 and 1 respectively. To place the software abstracting from the two level store in layer 1 was decided when it was discovered that the remaining software could make good use of the quasi homogeneous store, etc. It was in this stage of the design that the intermediate machines A[1], A[2], ... got defined (in this order).

     At face value our approach has much to recommend itself. For instance, a fair amount of modularity is catered for as far as changes in the configuration are concerned. The software of layer 0 takes care of processor allocation; if our configuration would be extended with a second central processor in the same core memory then only the software of layer 0 would need adaption. If our backing store were extended with a second drum only the software of layer 1, taking care of storage allocation, would need adaptation, etc.

     But this modularity (although I am willing to stress it for selling purposes) is only a consequence of the dissection and is rather independent of the chosen hierarchical ordering in the various layers, and whether I can sell this, remains to be seen. The ordering has been motivated by ‘convenience’....

     The point is that what is put in layer 0 penetrates the whole of the design on top of it and the decision what to put there has far reaching consequences. Prior to the design of this multiprogramming system I had designed, together with C.S. Scholten, a set of sequencing primitives for the mutual synchronization of a number of independent processors and I knew in the mean time a systematic way to use these primitives for the regulation of the harmonious cooperation between a number of sequential machines (virtual or not). These primitives have been implemented at layer 0 and are an essential asset of the intermediate machine A[1]. I have still the feeling that the decision to put processor allocation in layer 0 has been a lucky one: among other things it has reduced the number of states to be considered when an interrupt arrives to such a small number that we could try them all and that I am convinced that in this respect the system is without lurking bugs. Fine, but how am I to judge the influence of my bias due to the fact that I happened to know by experience that machine A[1], with these primitives included) was a logically sound foundation?

transcribed by Hamilton Richards
revised Fri, 19 Jan 2007

EWD237

A preliminary investigation into Computer Assisted Programming

This is a very tentative document on an effort to increase our programming ability.

I feel that this problem will become very urgent: the programmer finds his task in the field of tension between the available machines and the computations we want to have performed by them. As available machines become more and more powerful, mankind will become more and more ambitious in their applications and programs will grow in size and complexity. It takes no greak prophet to forecast that in the years to come the mechanical execution of the program once it is there will be the minor problem, whereas the major problem will be the process of program composition itself.

I accept that the intellectual effort needed to compose a program (measured in some loose sense) is an increasing function of program length (measured in an equally loose sense). The point is to what functional dependence we are aiming! I accept a programming technique such that the effort needed is proportional to the length. As long as we only have a programming technique such that the effort needed is proportional to, say, length squared, we had better admit defeat. (I am afraid current programming techniques are often even worse than that: sometimes I suspect an exponential growth of the effort needed!)

Over the past ten years we have witnessed an explosive increase of our programming ability as embodied by the advent of the so-called "higher level programming languages". Yet I have the feeling that they have done more to decrease some rates of proportionality than to change the functional dependence itself. We all know that the use of higher level programming languages made the construction of larger programs feasible; but we also know that at a certain stage a program written in a higher level programming language becomes just as intricate as the machine code programs of ten years ago. When one hits ones head at the ceiling it is a meagre consolation to know that it was at the ceiling of the next floor: the pain is just the same!

In the past year I have done a number of experiments. They were non-mechanical in the sense that I still viewed the programmer's task as producing a handwritten program text. In other words: I have been looking for a mental discipline. As yet, I do not regard these investigations as closed.

Among other things I have tried to behave, consciously, as "the ideal programmer" as I saw him at that moment. Without recording the experiments in detail now, I should like to give the core of some observations made.

First, the effort has been non-empty in the sense that I am appalled now by programs I made only three years ago. (This is a very strong observation, for among the appalling programs is the first one occurring for illuminating purposes(!) in an introductory(!) course on "Algorithms". At the time of writing —I remember quite well— I was delighted by its clarity!)

Second, the experiments have convinced me that "first making the program and then debugging it" is like putting the cart before the horse. The more I think about "debugging" in this sense, the more hopeless it becomes; in actual fact it now strikes me as a dead alley. And I am now much more in favour of a constructive approach to the problem of program correctness, i.e. to control the process of program composition in such a way as to prevent bugs from entering the construction.

I know that this goal strikes many as impossible to achieve, particularly those who have never tried it seriously. I will not deny that it is hard work —making a large and complicated program will be hard work anyhow!—; my claim is that when one makes a conscious effort at it, it is more feasible than trying to get a program correct when the problem of correctness has been left to the debugging phase.

Third, I have observed that by the time the program was completed, so was its "documentation". Here I use the term "documentation" in a completely informal sense, as a guide to understanding the program. Approaching the program through this documentation is reading the proof of its correctness.

Finally, the observation that even in the construction of very small programs the production of its documentation (or should I say "prae-documentation" to drive the message home?) is already a very rewarding excercise. In the last year I have taken oral examinations of the course "Introduction into the Art of Programming". (The oral examinations took more of my time than the actual lecturing, but as far as I am concerned the time has been well-spent. I got the feedback necessary to improve the lectures; above that it gave me an opportunity for direct observation of programmer's misbehaviour!) Lately, a student left open the boolean expression controlling a repetition clause and he had not made the prae-documentation explicit, neither in writing nor in his mind; when he had to fill in the correct boolean expression I saw him reading, statement after statement, the interior clause five(!) times and then he filled in the boolean expression (erroneously, by the way), whereas two lines of reasoning would have been sufficient. It was a most convincing affirmation of my fear that many a programmer loses much time and energy in trying to read the meaning of what he has written.

Summarizing, I can state without exaggeration that a very promising discipline is emerging; even when the project of Computer Assisted Programming does not materialize, this line of thought will be pursued.

The purpose of this paper is to raise the question whether it is sufficient to regard documentation purely as a human guide to the program or whether we must try to regard it as an essential part of it. It is impossible to give a motivated answer to the question "How" before we have an idea of the kind of benefits we hope to derive from it.

Why is it so hard, at present, to force programmers to make the appropriate prae-documentation? There is a historical reason: they have not been trained to do so. There is a psychological reason: they overestimate their powers and think that they can do without it and experience the making of prae-documentation as an additional burden. There is a practical reason, justifying this latter point of view: whatever documentation they prepare about the program they are making, it remains a guide for humans and it cannot be mechanically used in the actual composition of the program (unless one regards an ALGOL-text as "documentation" about the corresponding object program).

The next remark is related to the fact that every large program will have to exist in a number of versions. (A first version may be logically correct, but its performance may be unsatisfactory; above that the demands made upon it will vary during its lifetime.)

The naive approach to this situation is that we must be able to modify an existing program (program maintenance); the task to be performed is then presented as one of text manipulation.

I would like to approach this problem from another angle and would like to treat the task of program composition and that of program modification as essentially the same.

In the process of program composition many "small" decisions have to be taken: some of these decisions can be taken in parallel (i.e. independent of each other), other decisions must be taken one after another (i.e. it is the one decision that makes the other relevant). It is certainly the task of the prae-documentation to record the intermediate stages.

If a program has to exist in two versions I do not like to regard (the text of) the one as a modification of (the text of) the other, I should like to relate them both to their common ancestor that (hopefully!) occurs already in the prae-documentation. The first intention is that the two versions share their respective correctness proofs as much as possible; the second intention is that they share mechanically as much as possible of the common (or "equal") coding.

In making a program I want to regard the target program no longer as an isolated object, I wish to treat it as a member of a structured class of similar programs (either alternative programs for the same task or different programs for similar tasks).

At first sight this may seem to impose a considerable additional burden on the shoulders of the poor programmer: instead of requiring the construction of a single program we require at least the conception of a whole class of programs. But I am not so sure. If you have to prove that three perpendiculars of a given triangle pass though one point, you prove it for any triangle! That is what abstraction does for you and abstraction permeates the whole subject. To have a specific computation performed one writes an alogrithm that could perform a whole class of computations and one proves theorems about the whole class although finally perhaps only one of the class will be performed!

Similar remarks apply to the design process itself, which by its (or "our"!) very nature is a sequential one. At a certain intermediate stage one does not have an incomplete program that has to be completed to make sense, one has a program that at a certain level of detail (or, viewing it from the other side, "at a certain level of abstraction") is complete and correct. As such one has abstracted from the decisions that are still to be made!

Much of the programmer's wisdom will be reflected in the choices of programs he includes in the class considered. As said before: later program modifications should be anticipated already in the prae-documentation which should already contain a (hopefully) close ancestor for the next version. This is already now a vital part of the programmer's duty; a system of Computer Assisted Programming may act as a reminder to this obligation.

I must mention two other considerations that suggest that some form of documentation about the program should be regarded as an integral part of it. At present we feed the machine with programs and this is the bare minimum, because the machine can execute a program "without understanding it". But as long as only the bare program and nothing else is inside the machine we are faced with two problems —already urgent now— that are pretty hopeless.

The one problem is the design of a proper reaction to a detected malfunctioning of a piece of selfchecking machinery —parity check, say. We have no scale along which to measure the size of the calamity: in our system the effect of a machine error may be confined to a single program or the system as a whole may derail. I feel that the present absence of a grip on the structure of the computations is one of the main causes of the current failure to construct dual systems for larger safety.

The second problem —one that attracts me much more than partial fault recovery— is to modify a program while it is working. Although the need is obvious we don't even have the concepts in terms of which the problem can be clearly stated.

To keep in mind that in the future the computer itself may play an active (or to use the present OK terminology: "interactive") role in the process of program composition has the following motivation. If it does not materialize, it will nevertheless be a constant reminder to look for a formal method to give the prae-documentation. Being rather verbal such a constant reminder will be very useful. If it does materialize, there are many potential benefits, apart from the final product.

To start with, the system itself will be "a large, complicated program" and it should assist in its own construction. A kind of logical bootstrapping. The construction of the system itself will be the first testcase of the methods! A next consideration is that using the system to construct itself will provide in a nutshell the laboratory conditions for a program to be changed while it is in action!

Finally, why should I try to do it? I think it safe to say that the relevance of the project is beyond question. Then two questions remain: is no one else already doing it and am I sufficiently equipped to try it? To get some kind of answer to the first part of the question I have pumped Brian Randell but as far as he knew what he had seen of my approach seemed to him rather unique. Industrial concern seems to center on a PERT-like speeding up of a specific design and on the timely discovery (by simulation) where bottlenecks are to be expected in the performance more than on a classification of the possible designs on account of the degrees of freedom. Correctness proofs are certainly "in the air" (McCarthy, Naur, Floyd, Hoare in "The Axiomatic Method"), to use them as guiding principle in the process of program composition I have only seen by Floyd ("Assigning Meanings to Programs"), but as far as I know, Floyd has no actual experience in designing large programs.

This leaves the question "Why I?". I have, I think a claim to priority. I quote myself (1962) "In particular I would require of a programming language that it should facilitate the work of the programmer as much as possible, especially in the most difficult aspects of his task, such as creating confidence in the correctness of his program. This is already difficult in the case of a specific program that must produce a finite set of results. But then the programmer only has to show (afterwards) that if there were any flaws in his program they apparently did not matter (e.g. when the converging of his program is not guaranteed beforehand). The duty of verification becomes much more difficult once the programmer sets himself the task of constructing algorithms with the pretence of general applicability.

But the publication of such algorithms is precisely one of the important fields of application for a generally accepted machine independent programming language. In this connection, the dubious quality of many of the ALGOL 60 algorithms published so far is a warning not to be ignored."

Then came the multiprogramming system in the asynchronous part of which the design has been heavily influenced by correctness concerns; and this to our great advantage. In its connection three remarks are in order. First that the very high fame/publicity ratio can be taken as an indication that such an approach is (still) fairly exceptional. Second, that although this was not our primary aim, the approach brought with it in a very natural fashion a fair amount of modularity (whatever that may mean exactly). Finally, and this is now very important, that the final product shows where we have failed: the last —I would like to say: "extensive"— production phase has been too primitive and the resulting system too monolithic. It is an unmanagable, unmodifiable program, not in principle but for the labour involved. I feel that this is mainly the result of our manual production technique. It is, I think, also caused by the fact that at the end our self-discipline failed and we did not stick to our principles: at the lowest level —and there is so much lowest level!— we just programmed.

To the question "Why I?" I am inclined to answer the following. It is the natural consequence of my concerns over the last six or more years, extensive experiences gained are relevant and, reviewing them, I am beginning to get a feeling where I succeeded and where I failed, where and why.

Two final remarks about the possible scope of the project. In my more optimistic moments I do not exclude the possibility that the techniques will evolve so much to such a point that I can transform in a number of well understood steps an interpreter for an algebraic language into a compiler for that same language. If this turns out to be possible, the bootstrapping technique becomes more realistic. The second remark is that I may make the impression of reinventing flowdiagrams. Perhaps this impression is correct; there may be a point in doing so! The technique of flowdiagrams has been conceived at a time that programs were several orders of magnitude smaller than the programs we have to make now and may very well be in need of revision.

transcribed by Arnout Engelen
revised Sat, 28 Jul 2007

EWD238 - 0

Computation versus program.

I will use two simple examples to illustrate a very basic experience. Two computations that produce the same output are equivalent in that sense and a priori not in any other.

In the relation between program and computation we observe the program spread out in text space and the computation spread out in time. For any given combination of program and computation the so-called sequencing describes how progress of the computation (as time "progresses") is mapped on progress through the program (as text "progresses").

What is emerging are ways to compare programs; one wants to do so in order to compare the corresponding computations. The basic experience is that it is impossible (or fruitless, or terribly hard or unattractive or what you wish) to compare computations by comparing the corresponding programs when on the level of comparison the sequencings through the two programs differ.

In a little bit more detail: when we can parse two computations as a sequence of actions and we can map the two sequences of actions on each other, we can compare them by comparing the program texts, provided that the program texts can be equally parsed in instructions, each of them corresponding to an action.

Let me give two examples, an abstract one and a concrete one. The abstract example is the following one. Excluding side effects of boolean inspection and B2 constant

"while B1 do if B2 then S1
                   else S2"

is equivalent with

"if B2 then while B1 do S1
       else while B1 do S2"  .

The first construction is primarily one in which sequencing is controlled by a repetition clause, the second construction is primarily one in which sequencing is controlled by an alternative clause. I can establish the equivalence of the output of the computations but I cannot regard them as equivalent in any other useful sense.

The concrete example is to construct a program generating non-empty sequences of 0's, 1's and 2's without non-empty, element-wise equal adjoining subsequences, generating these sequences in alphabetic order until a sequence of length 100 (i.e. of 100 digits) has been generated. (The start of the list of sequences to be generated is:)

0
01
010
0102
01020
010201
0102010
0102012    )

EWD238 - 1

The programmer may make use of the knowledge that a sequence of length 100 satisfying the conditions actually exists. Each solution (apart from the first one) is an extension (with one digit) of a solution and the algorithm is therefore a straightforward backtracking one.

We are looking for the "good" sequences, we assume a primitive available investigating whether a trial sequence is good. If it is good, the trial sequence is printed and extended with a zero to give the next trial sequence; if the trial sequence is no good we perform on it the operation "increase" to get the next trial sequence, i.e. final digits = 2 are removed and then the last digit remaining is increased by 1. (The existence of a solution of length 100 and our stopping there will see to it that removal of final digits = 2 will never give rise to an empty sequence.)

Version 1a uses the fact that a single zero is the first true solution.

Version 1a

    "Set trial sequence to single zero (and length to 1);
while length < 101 do
   begin length < 101 do
      begin if good then
     begin print trial sequence; extend trial sequence with zero end
             else
   increase trial sequence
   end"

Version 1b regards the empty sequence as a virtual solution, not to be printed:

    "Set trial sequence empty (and length to 1);
while length < 100 do
   begin extend trial sequence with zero;
         while no good do increase trial sequence;
print trial sequence
   end"

One marked difference is in the statement to be repeated. In Version 1a (conditional) printing of a solution precedes the generation of a next trial, in Version 1b the printing is at the end of the repeated statement. This difference explains the difference in initialization and repetition test. But this is a minor difference as Version 1c shows:

Version 1c:

    "Set trial sequence to single zero (and length to 1);
while length < 101 do
   begin while no good do increase trial sequence;
        print trial sequence;
        extend trial sequence with zero
   end"

The tremendous difference is, that in version 1a the two repetitions are merged into one, while version 1b can be regarded as a detailing of version 0b:

    "Set current sequence to virtual solution (and length to 0);
while length < 100 do
   begin transform current sequence to next solution;
         print current sequence
   end"

Versions 1a and 1b are fairly incomparable. That was my basic experience.

EWD238 - 2

On reflection I shall ask attention for a third example as it presents a border case. Given two arrays X[1:N] and Y[1:N] and a boolean "equal", make a program that gives to "equal" the meaning "the two given arrays are element-wise equal". Empty arrays are regarded as equal.

One cannot compare the two arrays at a single stroke, one has to do so element-wise; we introduce the integer "j" and give to the variable "equal" the following meaning "among the first j pairs of elements no difference has been found" and arrive at the following program part

Version 1:

j := 0; equal := true;
while j < N do
     begin j := j + 1; equal := equal and (X[j] = Y[j]) end

This does the job: the initial situation is in accordance with j = 0, the statement under the repetition clause implements the induction step from j to j + 1 (no difference so far and no new difference) and by the time that j = N we have the desired value.

       Inspecting the assignment

               "equal := equal and ....."

we can conclude that one "equal = false" holds, this relation will be permanent and therefore further execution of the repetition clause makes no sense. (Mind you, we are only interested in the final value of "equal") This observation gives rise to the following program section

Version 2:

j := 0; equal := true;
while j < N and equal do
     begin j := j+1; equal := equal and (X[j] = Y[j]) end

But now we have made the program in such a way that the repeated statement will only start execution with "equal = true" and as a result "equal and" can be omitted:

Version 3:

j := 0; equal := true;
while j < N and equal do
     begin j := j + 1; equal := (X[j] = Y[i]) end

and that, presumably, will be our final version.

The above is a form of "program patching" that I abhor. For instance, the conclusion that led to Version 2 was derived from reading Version 1; Version 2 is fairly ridiculous anyway, it only occurred as a stepping stone between the other two versions. The question is: how are Version 1 and Version 3 related to each other? The sequencing is different, yet sufficiently similar that I can map them on each other.

We have N+1 functions EQUAL[j] for 0 ≤ j ≤ N, defined upon the arrays and given by

EQUAL[0] = true
EQUAL[j] = EQUAL[j-1] and (X[j] = Y[j])

and in terms of these functions it is requested to perform the assignment

equal := EQUAL[N]

EWD238 - 3

The common ancestor of Versions 1 and 3 would be something like

j := 0; equal := EQUAL[0];
while "perhaps equal ≠ EQUAL[N]" do
     begin j := j + 1; "equal := EQUAL[j]" end

Now this is tricky and not too well formulated. Each time the inspection is done, the relation "equal = EQUAL[j]" will hold because the common ancestor is made that way. At each inspection either "equal = EQUAL[N]" or not; I have included the word "perhaps" and have put the conditions within quotes, just to be on the safe side, in order to indicate whether we dare to guarantee that the equality holds. If we refuse to give this guarantee, well then "perhaps" the inequality holds.

Another way of saying why I have put the inspection within quotes is that I have given what meaning I shall attach to the truth and falsity of the boolean expression, without stating what expression it is.

Our choice for the inspection depends on our laziness, on the amount of mathematical analysis we wish to spend on the definition of the functions EQUAL. We can be lazy and say just: well, at the moment of inspection I know that

equal = EQUAL [j]

and I refuse to conclude that

equal = EQUAL [N]

before

    j = N

holds. This leads to Version 1.

We can apply some analysis to the recurrence relation and conclude that for any j

EQUAL[j] = false implies EQUAL[i] = false for all i ≥ j .

The class of situations under which we are now willing to guarantee the equality "equal = EQUAL[N]" is then widened to "j = N or equal = false" and this leads to version 3.

Now the really tricky thing is the following. We can regard the inspection "perhaps equal = EQUAL[N]" as an open primitive to be chosen later on; but the choice we make defines the set of circumstances under which the statement to be repeated has to be executed. In version 1, the only thing we can do is to follow the recurrence relation literally. In version 3 the computation of EQUAL[j] is restricted to the case EQUAL[j-1] = true, so what is demanded of the other quoted action

"equal := EQUAL[j]"

depends on the choice of the inspection. In version 3 it can be implemented by

"equal := (X[j] = Y[j]) or "if X[j] ≠ Y[j] then equal := false" ,

using the here known fact that initially "equal = true" will hold.

My common ancestor is an awkward parent!

Transcribed by Mikhail Esteves

Last revised on Wed, 30 Jul 2003.

EWD 239

On trading storage against computation time.

In present day sequential computers we can distinguish two main components, an active one (the processor) and a passive one (the store). The active component has the specific function to be fast, the passive one has the specific function to be large. The following is written under the assumption that this functional division is here to stay. (Personally I feel that it is this functional division thanks to which the reliable construction of both large and fast computers has become possible.)

From the point of view of the programmer storage space and computation time are two distinct resources and I regard it as one of the responsibilities of the programmer —rather than of the system— to allocate them, i.e. to divide the load between them. It is to the consequences of this responsibility that the present report is devoted. The report is not devoted to techniques needed to estimate the various loads, i.e. to give quantitative criteria to influence the programmer's choice. It is devoted to the logical relation between the alternatives among which the programmer has the choice.

I claim that the basic relation between two alternatives is given by the following pattern.

Given a program asking regularly for the value FUN(arg) where FUN is a given function defined on the current value of one or more variables of the state space called (together) arg.

In version A, only the current value of arg is stored and the value FUN(arg) is computed whenever needed.

In version B, an additional variable fun say, is introduced, whose sole purpose is to record the value FUN(arg) for the current value of arg.

Where version A has
                                arg:=....... (i.e. assignment to arg)
version B will have
                                arg:=.......; fun:= FUN(arg)
thereby maintaining the relation
                                fun = FUN(arg
Where version A calls for FUN(arg), version B will call for the current value of fun.

There are two possible reasons to prefer version B above version A.
1)   When the value of FUN(arg) is more frequently requested than assignments to arg take place, version B requires less frequent computation time. (If necessary, the technique can be refined by the introduction of a boolean fun up to date indicating whether fun = FUN(arg) holds. Assignment to arg is then
                                arg:=.......; fun up to date:= false ;
in this way one can suppress superfluous computation of FUN(arg) as might be generated by version B.)
2)   Often it is difficult to compute FUN(arg) from scratch for arbitrary values of arg, but is it much easier to compute the change of FUN(arg) on account of the change of arg. (Often this consideration will be the very body of the algorithm, e.g. when FUN is defined in terms of a recurrence relation; see the last example of EWD238, where j has to be taken as one of the arguments.)

We shall now turn to an example with which we have played extensively. Consider 32 positions arranged in a circle. Please make a program generating all ways in which they can be filled with 0's and 1's (one digit per position) such that the 32 quintuples of adjoining positions present the 32 possible configurations of five binary digits. Solutions that can be mapped on each other by rotation will be regarded as equivalent, the solutions are to be given as strings of 32 digits with five zeros leading and they have to be generated in alphabetical order.

C.Ligtmans has shown that this cyclic problem is equivalent to the following linear one. Fill a linear array of 36 positions with 0's and 1's (one digit per position) such that the 32 quintuples of adjoining positions present the 32 configurations of five binary digits. (When the linear array contains a solution the sequence formed by the first four digits will be equal to the sequence formed by the last four digits and as a result "the ring will close".) We shall tackle the linear problem.

We introduce a structured variable called sequence consisting of four zeros followed by k binary digits. When k=0 we call the sequence empty, when k=32 we call the sequence full; k equals the number of ways in which a quintuple of five adjoining positions can be chosen in the sequence.

Furthermore we introduce a binary variable, called candidate, representing the value by which the algorithm seeks to extend the sequence. The operation inverse to "extend sequence with candidate" is "take candidate from sequence", by which the last digit is taken away from the sequence and is assigned to the candidate.

The algorithm maintains the sequence in such a way that the sequence will never contain two different quintuples presenting the same pattern of five digits. The question "sequence extendable with candidate" asks whether extension would not give rise to a sequence violating the condition of different digit patterns. We can make the following two remarks
1)   As k equals the number of quintuples, as all quintuples on the sequence must present different digit patterns and the number of different digit patterns equals 32, k will satisfy k ≤ 32.
2)   Whenever k=32 the sequence presents a solution on the linear problem and on account of the equivalence established by Ligtmans the 32 leading digits of the sequence present a solution of the circular problem.

We now give the structure of the backtracking algorithm that prints the solutions in alphabetical order

set sequence empty; set candidate to zero;
repeat
        if sequence extendable with candidate  | then
                begin extend sequence with candidate; set candidate to zero;
                        if sequence full do print solution
                end
| else
                begin while candidate set to one do take candidate from sequence
                        set candidate to one
                end
until sequence empty

The above has been described as "the structure" of an algorithm. Can we regard it as "an algorithm"? I think we can.

The nine statements ("set sequence empty"; "set candidate to zero" etc.) have to be regarded as names of instructions of the well-understood repertoire (the primitive repertoire), candidate and sequence have to be understood as coordinates of the state space.

What do we have to assume (or: to define?) about the operations and the objects in order that this program makes sense? (I apologize for this probably impure question, for what is "making sense"? Nevertheless, I go on.)

Candidate is a two state object (the states being called zero and one respectively), these states can be set and inspected.

Sequence is a finite state object. A unique state of this object is called "empty". (Otherwise "set sequence empty" would be indeterminate.)

On a value pair sequence-candidate a boolean function "sequence extendable with candidate" is defined; if this function is true, the operand "extend sequence with candidate" is defined, giving a new sequence, and "take candidate from sequence" is then the inverse operator.

There is a boolean function full defined on the object sequence; its value on the empty sequence is irrelevant.

The object values that can be made by further extension of the empty sequence extended with a zero are scanned, whenever a value satisfying the criterion full is met (a function of) it is printed.

We can regard a set of properties as the above —when more carefully defined— as a set of axioms on objects and operations and on this level they must be sufficient to understand this program, to prove that it ends, that it produces all values satisfying full and all only once etc. On this same level we can make more algorithms, in this sense we have "a real machine"! E.g.

Set sequence empty; set candidate to zero;
if sequence extendable with candidate do
begin extend sequence with candidate;
        repeat
        if sequence extendable with candidate  | then
                begin extend sequence with candidate; set candidate to zero;
                        if sequence full do print solution
                end
| else
                begin while candidate set to one do take candidate from sequence;
                        take candidate from sequence;
                        if non sequence empty do extend sequence with candidate;
                        set candidate to one
                end
        until sequence empty
end

This program scans the object values that can be made by further extension of the sequence value created by extending the empty sequence twice with a zero. My question is: to what extent can we regard the particular example of the 36 positions as a specific model, a representation? Or: can we regard the above "abstract algorithm" as the abstracted ancestor of a wide class of backtracking algorithms? And, if so, to what use?

A discussion with J.M.Rutledge, IBM Research (16th July 1968) has convinced me that the version at the bottom of EWD239–1 serves a purpose. Without mentioning the quintuple problem one can prove its correctness, provided
1)   one gives the properties of the operations and functions defined on the objects candidate and sequence
2)   one gives a sharp definition of the required behaviour, i.e. the specification. This is very encouraging and this is what I wanted.

To my regret I have to part from this version, because it will lead me into difficulties that I should like to avoid. Let me sketch them.

The next step in my process would be the introduction of a canonical state space in terms of which all operations can be specified, particularly the functions full and sequence extendable with candidate. This I can do. To make a more realistic program, I intend to define functions on this canonical state space in order that I can use it to store "current values" as sketched in EWD239–0.

Now one or two problems arise. I have to define a function on sequence and candidate and the result is that I should like to introduce "extend sequence with candidate and set candidate to zero", instead of "extend sequence with candidate; set candidate to zero" for, at the separating semicolon the new function is fairly meaningless. Also: in the statements
        "while candidate set to one do take candidate from sequence;
         set candidate to one"
we have a similar situation, not so much at the separating semicolon but in the course of the repetition. Some of the new functions are "immaterial for some time" and to impose upon the program the duty to keep these tabulated values up to date on such a microscopic level is irrealistic.

The next goal therefore is to give more levels, in such a way that functional relationships that we want to introduce are guaranteed to hold at the semicolons of a given level! (This will be the case anyhow: the relations do not hold at the semicolons of the level making the adjustments.)

Rutledge has made a point: the fact that candidate is a twovalued variable, the sequence has something to do with what they call the free monoid on a binary alphabet can be concluded from the properties stated. Only full and sequence extendable with candidate pin the program down on the quintuple problem. The moral of this remark is that no flexibility is lost when we introduce the free monoid on this level, if it is only to define the desired properties of the operations.

So here we go again, this time with very cautiously, for the time being not bothering ourselves too much about the relation between successive versions.

The crudest version is

version 0:         "do all work"     .

This, although correct, is hardly helpful, we cannot do much with it either. Then comes

version 1:         "generate all solutions"

suggesting that a number (possibly zero) of "solutions" have to be generated. The number must now be finite.

version 2:         "generate all solutions in alphabetical order".

This version tells us more, it tells that the solutions have an ordering that is called alphabetical and that they have to be generated in this order.

version 3:         "generate in alphabetical order all bit sequences that are solutions"

Here we have told much more, we have said that we are looking for bitsequences in terms of which the alphabetical order can be defined. (We can take it for granted that this restricts ourselves implicitly to finite bitsequences.)

We do not know whether there are solutions at all. We do not know a first solution, also we do not recognize a last solution when we encounter it. The structure at the bottom side of EWD238–1 is therefore unattractive (containing "transform current sequence to next solution").

We do know, however, a criterion "acceptable" (in our example: containing no quintuples presenting the same pattern) with the following properties
1)   the set of acceptable sequences is not empty and finite
2)   we know a first member of the set
3)   we know a virtual last member of the set (for "virtual" see below)
4)   solutions are all acceptable sequences (excluding the virtual one) satisfying a further criterion full
5)   we can transform an acceptable sequence into the next one (next in alphabetic order).

About virtual: if we are looking for the sequences with a zero leading, the virtual last one would be the first acceptable sequence with a one leading. Also, if the first acceptable sequence is the empty sequence, the virtual last one may again be the empty sequence.

We can now make the following program:

version 4:
        set sequence to first acceptable one;
        repeat if sequence full do print solution;
                transform sequence into next acceptable one
        until sequence is (first or) last member

Remark: the first member is not subjected to the final test for the last member, therefore this test needs only to distinguish between the last member and the others, the first one excluded! There is no objection to the first one satisfying the test as well, but also no obligation; therefore "first or" has been put between parentheses.

We also know about the property "acceptable" that
6)   no extension of a sequence that is not acceptable will be acceptable.

This property enables us to implement "transform sequence into next acceptable one" —knowing that its initial value is indeed acceptable— as follows:

section 4.1: transform sequence into next acceptable one:
        "extend sequence with zero;
        while non acceptable do concrease sequence"

The effect of the operation concrease is defined in the following way: if the old sequence does not contain a zero the result is the empty sequence, if the old sequence does contain a zero, the result is a copy of the old one up to and excluding the last zero, extended with a one.

The present state is very encouraging, the important property 6 is only exploited in a next level of detail, it is here that backtracking is described, that the alphabetical order is catered for.

(Few days later.)

I must apologize, for I am afraid that I have gone too fast. I am going to modify version 4 of the previous page. The fact is that I have not expressed a changed interpretation of the current value of sequence, I have not expressed that the acceptable sequences fall into two different classes, those that are solutions and those that are not. I try to remedy this by a new version 4:

set sequence to first acceptable one;
repeat if sequence full do begin accept sequence as solution; print solution end;
        transform sequence into next acceptable one
until sequence is (first or) last member

The transition from the old to the new version 4 is not striking, because "accept sequence as solution" is in all probability an empty action. (For the sake of completeness I mention that I have been hesitating between "print solution" and "print sequence"; the statement "accept sequence as solution" implies more or less —is meant to indicate— that the two formulations are equivalent.)

The transition is more marked when I give the new section 4.1 on top of this page. In section 4 the sequence is always "acceptable", in section 4.1, where we exploit the important property 6 of "acceptability" we consider for the first time sequences that are not guaranteed acceptable. I call them "doubtful": a sequence is called doubtful when it is a one-digit extension of an acceptable sequence, property 6 tells us that when looking for acceptable sequences, we can confine our attention (the machine’s attention!) to doubtful sequences.

With this definition of doubtful, section 4.1, new version, would be something like

transform acceptable sequence into next doubtful one;
while doubtful sequence non acceptable do
        transform doubtful sequence into next doubtful one;
accept sequence as acceptable

The purpose of this new version is twofold. On the one hand it expresses that only doubtful sequences are subjected to the test "acceptable", on the other hand it allows us to introduce different representations for doubtful and acceptable sequences. The rules for doubtful sequences hold "at the semicolons" at this level. The first statement makes from an acceptable sequence a doubtful one, the last one makes from a doubtful sequence an acceptable one. This allows us to introduce for acceptable sequences a representation unfit for arbitrary doubtful ones. I shall return to this later.

Now I think that the time has come (experience makes me expect that I shall regret it within a few pages!) to introduce what I have called "the canonical state space" i.e. the variables that I need to pin the program down on the specific problem, in this case the quintuple problem.

We introduce the integer k, satisfying 0 ≤ k and the array d, to represent the value of

sequence:   0 0 0 0 d[0] ... d[k]    .

Putting the zeros also in the array d and using the fact that k will satisfy k ≤ 32 we can declare
        array d[–4: 32].

In terms of these variables we can now give the bodies of the instructions used in the middle of EWD239–5

set sequence to first acceptable one:
       d[–4]:= d[–3]:= d[–2]:= d[–1]:= d[0]:= 0; k:= 0

sequence full:
       k = 31

accept sequence as solution:
        " " (i.e. empty statement)

print solution:
        "print the 32 leading elements of the array d" (I refuse to go into more detail)

transform sequence into next acceptable one, see below

sequence is (first or) last member:
       d[0] = 1 (only satisfied by the last member) or
       k = 0 (satisfied by first and last member).

For "transform sequence into next acceptable one" we have a more detailed version on the bottom of page EWD239–5, in which the criterion "acceptable" is mentioned. In order to define it, we define upon the sequence k+1 function values
        h(i) ="binary value of bit sequence d[i–4]...d[i]" for 0 ≤ i ≤ k
and a sequence is called "acceptable" if all the k+1 values h(i) are different (this expresses the requirement that no two different quintuples present the same bit pattern).

At the semicolon of the detailing of "transform sequence into next acceptable one" the sequence is called "doubtful", i.e. a one digit extension of an acceptable sequence. As only doubtful sequences are subjected to the test acceptable it is sufficient to compare h(k) with h(i) for i<k.

The next step in detailing now gives:

transform acceptable sequence into next doubtful one:
       k:= k + 1; d[k]:= 0

doubtful sequence non acceptable:
        for all i, 0 < i < k holds: h(i) ≠ h(k)

transform doubtful sequence into next doubtful one:
       while d[k] = 1 do k:= k – 1; d[k]:= 1
(as a result of first and last member, the minimum value of k generated by this operation will be = 0; the final assignment replaces a 0 by a 1.)

accept sequence as acceptable:
        " " (also empty statement).

Now at last we get to the subject of this report, trading storage against computation time. We have two alternatives, either we compute the functions h(i) when we need them, or we tabulate them. Computing them when we need them presents itself as a further detailing of "doubtful sequence non acceptable", we shall investigate the consequences of tabulating them.

For this purpose we introduce the array H[0:32] and we postulate that
        H[i] = h[i] will hold for 0 ≤ i ≤ k
but we have to state on which levels this will hold. It will certainly hold for the outer level (the one of the acceptable sequences, middle of page EWD239–5) I decide that it will also hold for the level of the doubtful sequences.

It implies an addition to a number of bodies

set sequence to first acceptable one:
        is extended with "H[0]:= 0"

transform acceptable sequence into next doubtful one:
        is extended with "H[k]:= (2 * H[k–1]) mod 32"
(at this moment "k > 1" is guaranteed to hold)

transform doubtful sequence into next doubtful one:
        is extended with "H[k]:= H[k] + 1"

In the above three extensions the particular choice for the quintuple pattern characterizing function h(i) has found its deposit.

In terms of tabulated values H[i] the analysis for "doubtful sequence non acceptable" would still require scanning. We can repeat the trick by tabulating how often a value occurs in the sequence H[0]....H[k].

This now can be done in two ways. We can introduce the
integer array times[0:31] such that for all j
        times[j] = the number of times that the value j occurs among H[0]...H[k]

Let us make this to hold for both acceptable and doubtful sequences. The function is defined on H and k, modifications are to be expected by the three extensions just given and by modifications of k.

The extension of "set sequences to first acceptable one" is extended with
        times[0]:= 1; other values of times set to 0

The extension of "transform acceptable sequences into next doubtful one" is extended with
        times[H[k]]:= times[H[k]] + 1

And the new version of "transform doubtful sequence into next doubtful one" becomes
       while d[k] do begin times[H[k]]:= times[H[k]] – 1; k:= k – 1 end;
        d[k]:= 1; times[H[k]]:= times[H[k]] – 1; H[k]:= H[k] + 1; times[H[k]]:= times[H[k]] + 1

The last "doubtful sequence non acceptable" is now simply
        times[H[k]] > 1    .

The introduction of the array times is somewhat awkward. One of the nasty things is that its values are restricted to 0 and 1 and only "times[H[k]]" can ever get the value = 2. And this is to be modified immediately.
Additions and subtractions from these elements are usually just setting to 1 or 0.

Here we can use an alternative solution, we do not introduce the array times, but the boolean array IN.

In the outer level (acceptable sequences)
IN[j] means "the value j occurs (once!) in the sequence H[0]...H[k]"

In the inner level (doubtful sequences)
IN[j] means "the value j occurs (once!) in the sequence H[0]...H[k–1]"   .

We now review all instructions.

set sequence to first acceptable one:
       d[–4]:= d[–3]:= d[–2]:= d[–1]:= d[0]:= 0; k:= 0;
        H[0]:= 0; IN[0]:= true; remaining elements of IN become false

sequence full:
       k = 31 (unchanged)

accept sequence as solution:
        " " (unchanged)

print solution   (unchanged)

sequence is (first or) last member   (unchanged)

transform acceptable sequence into next doubtful one
       k:= k + 1; d[k]:= 0; H[k]:= (2 * H[k–1]) mod 32
(as the sequence changes from acceptable to doubtful, IN is left unchanged)

doubtful sequence non acceptable:
        IN[H[k]]

transform doubtful sequence into next doubtful one:
       while d[k] = 1 do begin k:= k – 1; IN[H[k]]:= false end;
        d[k]:= 1; H[k]:= H[k] + 1
(Compare this with the top lines of this page!)

And finally "accept sequence as acceptable" that was empty until now, gets the form IN[H[k]], on account of the changing definition.

By now I trust that my reader will have lost the various versions and his way through them; this was somewhat intentional. It shows the need for a clerical aid, a hierarchical assembler or possibly .... computer assistance!

transcribed by Corrado Cantelmi
revised 26-Nov-2011

EWD 240

The moral of EWD237 - EWD239.

What is relevant and somewhat novel.

1)     The firm attitude that giving the correctness proof and composing the program are activities to be merged.

2)     The firm attitude that one should not only consider one's final program but that it should be regarded as member of a class of related programs.

3)     The discovery that "changing a decision" and "postponing a decision" are intimately related. As "postponing a decision" is an essential aspect of the process of program composition, this should be done in such a way as to anticipate modifications.

4)     Postponing a decision may be "postponing the precise choice of the actual problem to be solved". Alternative programs for the same problem can be related to a common ancestor in very much the same way as a common ancestor can model the programs for similar problems.

5)     Such a common ancestor will be a rather abstract program. Relevant (and new for me) is the discovery that such an abstract program can be studied in its own right and is not just a vague sketch of what we are going to do, needing further detailing to make sense.

6)     That functional relationships can be introduced that are to hold at the semicolons is known. New seems the discovery that the range of validity can be made dependent on the level on which the semicolon occurs.

7)     New seems the discovery that these levels are the levels as suggested by "analysis of the problem" or "detailing of the algorithm", which seem to be two names for the same thing.

Things to be done.

An analysis of the relations between the different members of the same program class.

This is to be done in the hope of obtaining a classification of the types of abstractions considered.

This is to be done in the hope of obtaining an insight in the internal structure of this class (probably in relation to the structure of its members).

This is to be done in the hope of finding an adequate bookkeeping system.

This has to be done before we can do further experiments (see the cross-referencing mess on the last pages of EWD239!); it has also to be done before we can get an idea of what benefit we could derive from computer assistance.

transcribed by Corrado Cantelmi
revised Fri, 2 May 2008

EWD241

Towards correct programs.

The purpose of this paper is to stress what mental aids we have at our disposal in designing and understanding algorithms, to show some patterns of programming that we may hope to apply without losing our intellectual grasp on what we are doing and to stress the need that our programs (i.e. the final program and the intermediate programs leading to it) mirror as closely as possible our understanding of the problem and the algorithms solving it.

Among the mental aids available I should like to mention three explicitly:

1)     Enumeration

2)     Mathematical Induction

3)     Abstraction.

I regard as an appeal to Enumeration the mental effort required to understand either a sequential program generating a fixed time sequence of actions or a conditional or alternative clause (the so-called "case construction" included). As one of the principle properties of the human mind I take that the appeal to enumeration should be small. In particular this means
1a) that the text describing a sequential program fragment should generate a small number of actions (i.e. that the corresponding computation can be grouped, understood as the time succession of a small number of actions)
1b) that the number of cases to be distinguished in an alternative clause should be small.

Mathematical induction is mentioned explicitly because it is the standard pattern of reasoning to understand recursive procedures and the (much more common) loops; I shall restrict myself to loops generated by some form of repetition clause.

Abstraction is regarded as the main mental tool needed for the application of mathematical induction —i.e. to form the concepts in terms of which the net effect of the induction step can be described— and valuable in the effort to reduce the appeal to enumeration: in the case of an alternative clause it should provide the concepts in terms of which the net effect can be described regardless of the path taken.

With the above in mind I shall tackle the following problem. Given 32 cyclically arranged positions, make a program generating all ways (if any) in which these positions can be filled with zeros and ones (one digit per position) such that the 32 quintuples of five adjoining positions present the 32 different patterns of five binary digits. Fillings that only differ from each other by rotation are regarded as equivalent, all solutions have to be generated with the five zeros leading. (The last sentence reduces the number of "independent solutions" by a factor 32.)

C. Ligtmans has shown that the above cyclic problem is equivalent to the following linear problem. Given a linear array of 36 positions, make a program generating all ways (if any) in which these positions can be filled with zeros and ones (one digit per position) such that the 32 quintuples of five adjoining positions present the 32 different patterns of five binary digits. We may restrict ourselves to sequences staring with five zeros, the 32 leading digits of a solution of the linear problem present a solution of the cyclic one and vice versa. (The proof by C. Ligtmans runs as follows. Each solution of the linear problem starts with 000001... —because the pattern 00000 may occur only once—; furthermore the pattern 10000 must occur once; as the latter patterns can only be followed by 00000 or 00001 (presented already by the first two quintuples), the pattern 10000 cannot occur in the interior of the linear sequence and therefore it must occur at the end. As a result each solution of the linear problem ends with four zeros and therefore the ring closes!) We shall solve the linear problem, imposing the further condition that the solutions (if more than one) have to be generated in alphabetical order.

The coarsest description of the program is as a single instruction
Version 0:

"do all work"     .

This description is completely general, but also completely useless, for it reflects none of our understanding of the problem nor anything about the structure of the algorithm. In order to be able to proceed we have to analyse the problem further.

I take for granted that, given a sequence of 36 binary digits the boolean function stating whether this sequence represents a solution is computable and that we could write an algorithm computing it. In principle we could write a program generating all 36-digit sequences with five leading zeros in alphabetical order and subjecting all these sequences to the test just mentioned, thereby selecting those satisfying the test. This gives a very unrealistic program and we shall not pursue it; we only remark that generating the trial sequences in alphabetical order will ensure that the solutions, when found, will be found in alphabetical order as well.

Remark. Our final program could be regarded as a derivation from the one sketched above, viz. by the introduction of some significant short-cuts. At present I do not feel inclined to stress this relation any further for it seems too tightly connected with this specific problem.

In our next approach we shall again generate our solutions by (generating and) scanning a larger set of sequences from which by a suitable criterion all solutions will be selected.

Let us define as "length of a sequence" the number of quintuples it contains (i.e. length = number of digits – 4). Let us call a sequence "acceptable" if no two different quintuples in it present the same digit pattern. With these definitions the solutions are a subset of the set of acceptable sequences, viz. those with length = 32.

We do not know whether there are any solutions at all but we do know that the set of acceptable sequences is non-empty (e.g. "00000"); we do not have a ready made criterion to recognize "the last solution" when we encounter it, in our set of acceptable sequences, however, we can designate a "virtual last one" (viz. "00001"): when that one is encountered we know that all acceptable sequences with five zeros leading have been scanned and that no further solutions will be found.

Summarizing, we know of the set of acceptable sequences

1)      it is non-empty and finite

2)      we know a first member ("00000")

3)      we know a virtual last member ("00001")

4)      we can transfer an acceptable sequence into the next acceptable sequence

5)      solutions are all acceptable sequences (excluding the virtual one) satisfying the further condition "length of sequence equals 32".

The transition from considering only the set of solutions to considering the set of acceptable sequences seems to mark a step in our analysis sufficiently relevant to justify that it be expressed in our first refinement, a program in which all instructions operate upon (a still rather abstract) object, called "sequence".

Version 1:

"set sequence to first acceptable one;

repeat if length of sequence equals 32 do

begin accept sequence as solution;

print solution

end;

transform sequence into next acceptable one

until sequence is (first or) virtual last member"

In explaining this program, two remarks seem appropriate.
Remark 1.      The final test "sequence is (first or) virtual last member" has to distinguish the virtual last member from all members excluding the first one, as the first one will not be subjected to the test. Basically there would be no objection to the first member being equal to the virtual last one (say: the empty sequence). The above freedom is expressed by putting "first or" within parentheses.
Remark 2.      The statement "accept sequence as solution" may well puzzle the reader. It may turn out to be an empty statement. It is inserted to express that "at the following semicolon" the sequence is regarded as representing a solution. (One may think of it as extracting the 32 leading digits.)

The criterion "acceptable" has a further important property:
6) no extension of a sequence that is not acceptable will be acceptable.

and it is this important property that will be exploited in the refinement of "transform sequence into next acceptable one". As a direct consequence of property 6, the acceptability test need only be applied to so-called "promising sequences", where a promising sequence is defined as a one-digit extension of an acceptable sequence. This leads to our next refinement

transform sequence into next acceptable one:

"transform acceptable sequence into next promising one;

while promising sequence not acceptable do

transform promising sequence into next promising one;

accept sequence as acceptable"

When we regard "transform sequence into next acceptable one" as an available primitive, the value of "sequence" as always acceptable; it is only in the interior of its dissection —viz. at the semicolons of the above refinement— that the current value of "sequence" is a promising sequence.

In view of the required alphabetical ordering "transform acceptable sequence into next promising one" forms a new sequence equal to the old one extended with a zero, while "transform promising sequence into next promising one" forms a new sequence equal to the old one up to and excluding the last zero, followed by a one, or more explicitly as in the next refinement

transform promising sequence into next promising one:

"while sequence ends with a one do remove final digit from sequence;

replace final zero by a one".

In the above step-wise refinements we have focused our attention upon the sequencing of the program. Now the time has come to introduce more explicit the decisions as how the still rather abstract object called "sequence" has to be represented.

We introduce an integer k and decide that k = length of the sequence. Furthermore we introduce an integer array d[-3:33] to represent the digits with

d[-3] d[-2].....d[k] representing the sequence. | (1)

Remark 1:     d[-3] through d[0] will be equal to zero.

Remark 2:     The maximum length of an acceptable sequence = 32; as the algorithm handles promising sequences and a promising sequence is a one-digit extension of an acceptable one, the maximum length of the sequence is 33.

The above conventions serve as a basis for the more explicit statement of the property "acceptable". We have to characterize digit patterns as presented by the quintuples contained in the current value of the sequence. I propose to characterize such a digit pattern by the integer value one gets when interpreting the digits of such a quintuple as the digits of a binary number. In other words we define the function H(i) for 1 ≤ i ≤ k

H(i) = d[i-4]*16 + d[i-3]*8 + d[i-2]*4 + d[i-1]*2 + d[i] | (2)

The property "acceptable" means that

for 1 ≤ i, j ≤ k, i ≠ j implies H(i) ≠ H(j). | (3)

At each moment the function H(i) is defined on the current value of sequence for 1 ≤ i ≤ k. Instead of recomputing these function values whenever we need them (i.e. in the acceptability test) we can tabulate them in an integer array h[1:33].

Our convention is that for all sequence values will hold

h[i] = H(i) for 1 ≤ i ≤ k. | (4)

This convention implies that modifications of the value of sequence in general includes updating of the array h in order to maintain relation (4).

The acceptability test is now -analogous to (3)- that for 1 ≤ i, j ≤ k i ≠ j implies h[i] ≠ h[j].

Next we exploit the fact that the only sequences to be subjected to the acceptability test are promising sequences, i.e. one-digit extensions of an acceptable sequence. For a promising sequence we can conclude that it is acceptable if and only if

h[i] ≠ h[k] for 1 ≤ i < k | (5)

i.e. when the last quintuple presents a pattern different from all the preceding ones.

This, again, would imply scanning, but we can repeat the trick and tabulate whether a certain digit pattern already occurs. The most elegant way is to produce a boolean array in[0:31] where for 0 ≤ m ≤ 31 in[m] means:

for an acceptable sequence: m occurs among h[1]...h[k]

for a promising sequence: m occurs among h[1]...h[k-1]

(6)

Note. When the sequence is acceptable, each pattern can only be presented once and a boolean variable is sufficient to record whether it occurs. In a promising sequence h[k] may equal h[i] for i < k; therefore convention 6 distinguishes between acceptable and promising sequences.

We now give the final version of the program. What were names of primitives now occur as labels (either of statements or expressions).

begin integer k; integer array d[-3:33];

integer array h[1:33]; boolean array in[0:31];

set sequence to first acceptable one:

begin d[-3]:= d[-2]:= d[-1]:= d[0]:= d[1]:= 0; k:=1;

h[1]:= 0; in[0]:= true;

begin integer m; m:= 1;

repeat in[m]:= false; m:= m + 1 until m = 32

end

end;

repeat if length of sequence equals 32: (k = 32) do

begin accept sequence as solution: new line carriage return;

print solution;

begin integer m; m:= 0;

repeat print(d[m-3]); m := m + 1 until m = 32

end

end;

transform sequence into next acceptable one:

begin transform acceptable sequence into next promising one:

begin k:= k + 1; d[k]:= 0;

h[k]:= 2 * h[k-1] - 32 * d[k - 4]

end;

while promising sequence non acceptable: (in[h[k]]) do

transform promising sequence into next acceptable one:

begin while sequence ends with a one: (d[k] = 1) do

remove final digit from sequence:

begin k:= k - 1; in[h[k]]:= false end;

replace final zero by a one:

begin d[k]:= 1; h[k]:= h[k] + 1 end

end;

accept sequence as acceptable: in[h[k]]:= true

end

until sequence is virtual last member: (k = 1)

end

In explanation:

1)       "accept sequence as solution", that could have been an empty statement has been given the meaning of transition to a new line

2)       "accept sequence as acceptable" has got contents, due to convention (6) where distinction is made between promising and acceptable sequences.

Concluding Remarks.

We have shown successive program versions, leading from the original problem statement to the final program. In our final program, the merging of these successive versions has been done by hand and the more abstract versions have been reduced to comment in the form of labels.

For large programs this merging process itself becomes a major data processing task and I expect the growth of interactive program composition techniques in which the service of computers will be enlisted for the benefit of this process.

Furthermore: at present the more abstract versions are only reflected as explanatory comment, inserted for human understanding. The origin of this is that we want at present a program formulated at a constant semantic level, viz. the level of the programming language. For the more abstract versions we have at present during run time no mechanical use. In future I expect the more abstract versions to be an integral part of the program.

Finally, we have considered only a single line of programs leading from the problem statement to a working problem expressed at the desired semantic level. In future I expect that this single line will be extended to a more or less tree-structured class of programs in which is also room for alternatives, thus structurely tying together program composition and program modification.

Edsger W. Dijkstra
Department of Mathematics
Technological University
P.O. Box 513
EINDHOVEN
The Netherlands

(This paper has been produced in relation to a talk given at the University of Grenoble in December 1967.)

transcribed by Jordan Olsommer
revised Wed, 30 Nov 2005

EWD 243

Bijdrage voor de subcommissie Aanschaffingsbeleid Rekenautomaten.

De subcommissie stelt zich tot taak om, de totale rekenbehoefte van de THE in aanmerking nemend, een advies uit te brengen aan de Commissie ten aanzien van de keuze, opstelling en technische organisatie van het gebruik van geschikte automatische digitale rekenapparatuur (in het centrale rekencentrum).

Bovengenoemde taakstelling bevat "de totale rekenbehoefte aan de THE" als sterkste bindende element. Weinig quantitatief en meer structureel denkend als ik ben voel ik sterke behoefte deze "totale rekenbehoefte" zoals je die zonder onderzoek en enquete al voelt aankomen, qualitatief te ontleden, opdat wij een helderder beeld krijgen welke soorten rekenwerk wij zinvol kunnen en moeten onderscheiden. Het lijkt mij dienstig wanneer wij, als commissieleden, het er samen over eens kunnen worden, wat in naam van onze taak "zinvolle onderscheidingen" zijn, kortom welke aspecten van rekenwerk wij in onze beschouwing willen betrekken en van welke wij menen te kunnen abstraheren.

Aangezien de rekenactiviteiten door apparatuur verricht zullen moeten worden en van ons gevraagd wordt over deze apparatuur een voorstel te doen, vormen de materiele eisen die door het rekenwerk gesteld worden, een belangrijk aspect. Dit is vanzelfsprekend. De vraag rijst dan wel onmiddellijk: "Welke materiele eisen dienen we hierbij te onderscheiden?".

Daarnaast is voor mij een belangrijk aspect van rekenwerk "Welk belang is ermee gediend?" Het lijkt mij absoluut noodzakelijk dat wij er ons in verdiepen aan welke verschillende belangen het rekenwerk zelf, danwel de manier waarop het wordt uitgevoerd, zijn importantie ontleent. Als er nl. een compromis getroffen moet worden, dan wel als we aan zien komen, dat eenzelfde faciliteit verdeeld zal gaan worden over in dit opzicht verschillende activiteiten, dan acht ik het onze gemeenschappelijke plicht waar mogelijk ervoor te waken dat de kwetsbaarste belangen voldoende beschermd zijn. Ook in dezen lijkt mij een communis opinio voor het vruchtbaar werken van de subcommissie uiterst wenselijk. (Mijn doorgaans deprimerende commissieervaring vertelt mij dat veel vruchteloos geharrewar ontstaat als men om der lieven vredes wille om deze hete brij heen probeert te lopen!)

Omdat het mijn indruk is, dat genoeg mensen zich geroepen voelen om zich in de zowel quantitatieve als (eerst!) qualitatieve materiele eisen te verdiepen, wil ik proberen om als eerste bijdrage tot een soort belangen-indeling te komen.

Enkele opmerkingen vooraf. Het gaat hier om een indeling van belangen en niet van activiteiten: als het meezit kan dezelfde activiteit verschillende belangen dienen (met alle voor- en nadelen van dien!). Ten tweede komt natuurlijk de relatie van "iets ten dienste van iets anders" naar voren. We moeten de ogen openhouden voor het verschijnsel dat dienstverlening in de ogen van hen, die zich met deze taak belast hebben, altijd neigt te verschuiven van middel tot iets naar doel op zichzelf. Als de dienstverlening de dienst gaat uitmaken is deze ontwikkeling compleet! Deze organisatorische verschuiving heeft zijn wetenschappelijk analogon (in onze academische waardenschaal hoger aangeschreven, maar uit bepaalde economische gezichtspunten waarschijnlijk even schadelijk) nl. de verschuiving van "doen" naar "er over denken hoe je het zou moeten doen"; dit heet dan perfectie en ontwikkeling van de methode. Hier is wijsheid en eerlijkheid meer geboden dan waar elders, want dit verschijnsel is zo intiem met automatisering verweven, immers "programming is the art of computing without actually doing it". Ten laatste: een doel van automatisering is om werk overbodig te maken. Dwars daartegen in moeten we voor onze afstudeerders werk scheppen. Van deze tweeslachtigheid verwacht ik, dat hij een voortdurende bron van verwarring zal blijken.

Nemen wij nu aan—dat is natuurlijk al een idealisatie!—dat elke rekenactiviteit een belang zal dienen, dan is een van de aspecten van deze belangen het type kapstok, waaraan ze hun gewicht ontlenen. Het lijkt me goed deze van te voren te onderkennen om waar mogelijk latere conflicten te voorkomen. Laten we proberen te voorzien welke dwangmiddelen voor chantage gebruikt kunnen worden.

1) Het "vele-mensen-belang". (Te onderkennen bij massainstructie, salaris-, studenten- en tentamenadministratie; is voor bibliotheekautomatisering ook bruikbaar als hefboom.)

2) Het "dure-apparaat-belang". (Te onderkennen bij verwerking van meetgegevens van cyclotron, kernreactor; het is ook te onderkennen bij installatieuitbreidingen die men via salamitechnieken tot stand probeert te brengen. Als men zich tot de aanschaf van genoeg educatieve terminals heeft laten verleiden, zou onderwijsresearch hiervan gebruik kunnen maken. Verder in een rekencentrum bij het vergaren etc. van gegevens over computergebruik, het inteeltgeval.)

3) Het "mensenlevens-belang". (Te onderkennen bij medische informatieverwerking; zo kan je faciliteiten, nodig voor on-line patientenbewaking verder wel afschrijven!)

4) Het "statusbelang". (Te verwachten bij medische toepassingen, onderwijsresearch—observatie van studentengedrag, on-line koppeling ter boeking van de reactietijd die de onnozele student nodig heeft om op een onnozele vraag een onnozel antwoord te geven—en, als efficiencyverhoging van het universitaire bedrijf nog lang een onderwerp van krantenartikelen blijft, bedrijfsvoering van de THE, planning, studentenprognoses etc. In het algemeen bij projecten met een natuurlijke dan wel gekweekte reclamewaarde. Architectuur, city-planning en recreatie?)

5) Het "geld-is-heilig-belang". (Salarisadministratie, afd. inkoop.)

6) Het "OK-configuratie-belang". (Ik doel hier op de toepassingen, die gezocht worden bij een OK-configuratie; terminals zijn duidelijk "in", van allerlei soort, maar vooralsnog worden graphical displays beschouwd als de oplossing voor een probleem, dat nog gevonden moet worden. Het "dure-apparaat-belang" gaat dan meespelen. Ik doel tevens op de problemen, die kunnen rijzen, wanneer men een constellatie/configuratie kiest, die politiek "in" is. Ik bedoel, dat het fataal is "to persuade oneself into the appropriate feelings": al doen we maar 10 procent van de interdisciplinaire kruisbestuiving, die door de regenten als reddende engel is geheiligd, dan zijn we over een paar jaar zo bestoven, dat we van pure bevruchtheid niet meer weten, wat we moeten doen en zal het een zegen zijn weer gewoon aan het werk te kunnen.)

7) Het "kleine-groepje-research-belang". (Ik doel hier op de individuele researchprojecten, dan wel de projecten, waarmee een klein groepje zich geidentificeerd heeft, waarbij het project zijn gewicht moet ontlenen aan vertrouwen in de auteur(s) of erkenning van zijn zinvolheid. Als bv. een paar mensen gaan liefhebberen in de problemen van bibliotheekautomatisering zonder dat in hoogste instatie beslist is, dat zij de bibliotheek gaan automatiseren, dan speelt het "vele-mensen-belang" bij dat liefhebberen nog niet mee.)

8) Het "kleine-groepje-educatieve-belang". (Hogerejaars practica, individuele stages. Hier hoeft de machine wellicht helemaal geen interressante resultaten af te leveren. Het "quod" kan volledig secindair zijn, als eerstehands ervaring met het "quo modo" het doel is. Kan je het met punt7 koppelen, dan is dat zoals gezegd, meegenomen.)

Totzover de kapstokken, die ik in eerste instantie bedenken kan. Zij geven ons een eerste indruk van de krachten, waarmee we rekening moeten houden als er touwgetrokken gaat worden. Nu heeft het zin om ons rekenschap te geven van de oorzaken van mogelijke conflicten, van de manieren, waarop verschillende activiteiten elkaar voor de voeten kunnen lopen.

Om te beginnen heb je de zuiver quantitatieve, waarom ik me nu wederom niet zal bekommeren omdat ik aanneem, dat anderen dat wel zullen doen. In plaats daarvan vraag ik aandacht voor een structurele conflictbron.

In een rekenbedrijf is een groot aantal logisch gerangschikte hierarchische lagen te onderkennen, bv. (voor de vuist weg)
         1) circuitry
         2) opdrachtcode
         3) configuratiearchitectuur
         4) operating system
         5) vertaler(s) en assembler(s)
         6) probleemgerichte software
         7) organisatie rekencentrum
en het is steeds de vorige laag, die de basis is voor de volgende. Het is nu de vraag op welk niveau de diverse groepen van de THE hun wetenschappelijke verantwoordelijkheid voelen liggen, zowel ten aanzien van onderzoek als ten aanzien van onderwijs. Om de belangen van laag N veilig te stellen kan men zich op laag N-1 nl. geen experimenten veroorloven! Ook al heb je een machine, waarvan de opdrachtencode via microprogrammering gewijzigd kan worden, dan zal daar nooit iets van terechtkomen als de machine in kwestie bestemd is voor de verwezenlijking van een solide hoeveelheid bestaande software, je bent althans aan handen en voeten gebonden. Een niveau hoger herhaalt dit verschijnsel zich: bedrijfscontinuiteit maakt, dat op die machine geen ruimte meer is voor experimenteren met basic software. (Zo zal ik zelf al heel blij zijn, wanneer software research en een niveau hoger een practicum programmering zonder met elkaar in conflict te raken op één installatie ondergebracht kunnen worden; in innige verweving bedoel ik. Zelfs onder straffe eenhoofdige leiding zal dat een boel vakmanschap vergen.) Dit zijn geen problemen om optimistsich overheen te huppelen. Ik verwijs naar Forsythe, IFIP 1968. Verder naar groepen, die uit de 360-serie een machine gekozen hebben met o.a. het argument, dat de opdrachtcode gewijzigd zou kunnen worden, waar dit een irreele overweging is gebleken. Verder naar de tot onmogelijkheid leidende moeilijkheden software ontwikkeling compatibel te houden met de door de fabrikant geleverde operating systems.

In het kundig peilen van het niveau waarin iemands wetenschappelijke verantwoordelijkheid ligt, ligt een subtiele taak voor de commissie, die de behoeften onderzoekt!

16 september 1968 | Edsger W.Dijkstra

transcribed by Angelo van der Sijpt
revised Tue, 12 Dec 2006

EWD244

Een educatief dilemma.

      Gemakshalve neem ik aan dat ook in de toekomst een grote machine het hart van het Rekencentrum zal uitmaken; kortheidshalve noem ik deze machine "de productiemachine". Deze zal vele, soms terecht veeleisende mensen dienen, waaronder naar wij hopen het merendeel van onze promovendi, afstudeerders en stageaires, voorzover ze de productiemachine gebruiken kunnen. Wij zijn het er, dacht ik, met zijn allen over eens, dat zij, gezien wat ze kunnen uitdragen, een belangrijke groep vertegenwoordigen.
      De keuze van de productiemachine is voor hem, die zich het professioneel bedrijven van een rekencentrum tot taak gesteld heeft, van grote interesse; voor hen, die voor hun werk op de productiemachine aangewezen zullen zijn, is de keuze slechts van afgeleid
      Veronachtzamen we de gangbare elementen als chantage, bedreigen en omkoping, dan zou het me niet verbazen wanneer de keuze van de productiemachine verder —en dat dan niet eens zo erg ten onrechte!— op hem valt vanwege zijn productiecapaciteit. Is dit veiligstellen van de productie de eerste zorg, dan kan ik me niet anders voorstellen dan dat de productiemachine een veilige keus wordt, niet te ver van het gebaande pad, kortom een machine van vandaag, waarvan je weet, wat je er aan hebt. (Sic.) In de zin dat "de beproefde methode" niet meer interessant is, moeten we stellen dat de veilige keus, de alledaagst machine, vandaag vervelend is, morgen achter en overmorgen achterlijk zal zijn.

      Het dilemma is evenwel, hoe "Kurzfristig" wij ons als instelling van hogeronderwijs mogen opstellen. Van vele zijden wordt er nl. pressie op ons uitgeoefend om dit in vrij sterke mate te doen. Deze pressie komt ten eerste van de bedrijfsvoering van onze interne productieeenheid (zie boven), komt ten tweede van onze studenten —vooral van de minderbegaafden— die zich veiliger voelen, wanneer ze met een actuele bruikbaarheid worden afgeleverd, komt ten derde van het bedrijfsleven, dat met de plicht zich vandaag het hoofd boven water te houden vaak niet ongenegen is een wilde wissel op de dag van morgen te trekken, de pressie komt tenslotte ook uit eigen boezem: hoe verder te toekomst, hoe gladder het ijs en wie langer probeert te kijken dan de neus van zijn collega's gemiddeld lang is loopt een gerede kans het verwijt te krijgen, dat hij met zijn neus in de lucht loopt. De vloek is, dat hetzelfde economische belang, dat alom kortzichtigheid lijkt te dicteren, het belang van de juiste langzichtigheid alleen maar onderstreept.
      In het licht van de overweging dat het specifiek de taak van het hogeronderwijs is om in te springen, waar de rest van de maatschappij te kort schiet, om met de meeste deskundigheid en geloof in eigen inzichten het kostbaar tegenwicht te fourneren —hoe ondankbaar deze taak en hoe pretentieus deze taakstelling op elk moment ook moge schijnen!— moet zelfs een vraagteken gezet worden bij het streven het hart van het rekencentrum een productieeenheid als ieder ander te maken. Is het —en zulks lijkt me het geval— onmogelijk om daar ver bovenuit te stijgen, dan dienen we te overwegen, inhoeverre we in de rest van onze educatieve activiteiten deze roeping trouw kunnen blijven.
      Ter voorkoming van misverstand: ik het hier niet over de enkele computerspecialist, die mits "weltfremd" zijn ongebreidelde lust tot perfectie kan botvieren, ik heb het hier over de gemiddelde gebruiker, die wij denken af te leveren. Dit klemt nl. in tweeerlei opzicht: ten eerste is de normale computer gebruiker aartsconservatief (van Grace M.Hopper gaat het verhaal, dat zij ter symbolisering hiervan op haar kamer een klok heeft laten installeren, die achteruitloopt!), ten tweede beroept de computerfabrikant, die ook liever zijn vingers niet brandt, zich maar al te graag (en niet geheel ten onrechte) op de achterlijkheid van zijn klanten, die iets beters toch niet zouden weten te apprecieren.
      Is het oppervlakkig gezien onze educatieve taak ten aanzien van de programmering om in de eerste plaats onze studenten wegwijs te maken op onze eigen productiefaciliteit, bij nader inzien kon dat wel eens juist omgekeerd zijn. Het kon wel eens juist onze plicht zijn om ervoor te waken dat wat wij doceren niet beinvloed wordt door wat de THE uit productieoverwegingen vandaag heeft aangeschaft. Het kon wel eens juist onze plicht zijn ons onderwijs zo in te richten om onze studenten, wanneer ze aan het echte gebruik van onze productiefaciliteit toekomen, hen dit te laten ervaren als "een zich behelpen met de mogelijkheden van heden". En het kon wel eens juist onze plicht zijn zulk onderwijs materieel mogelijk te maken.

      Wij knappen onze studenten wellicht op met vooroordelen, waaronder zij zo zij willen, hun leven lang kunnen lijden. Maar, zin op niet, onze academici zijn erfdragers van onze cultuur en zouden wij niet schromelijk te kortschieten, als wij hen de kans, deze last op zich te nemen, onthielden?

30 september 1968 | Edsger W.Dijkstra

transcribed by Joost Gabriels
revised Fri, 4 Mar 2005

EWD245 - 0

On useful structuring
by Edsger W. Dijkstra

The purpose of this minor contribution is to stress the urgency to make a conscious effort at exploiting "structure" as a useful thinking aid. Furthermore it gives some of the conclusions such an effort has led me to so far.

To start with, I take for granted that all of us acknowledge that the software failure is an undisputable fact: this recognition was why this conference on software engineering was organized, its acknowledgement is why we have accepted to participate. Hardware is rushing ahead of our programming ability and unless something drastic happens the situation will only get worse and worse. For: with more and more powerful machines becoming generally available society will be more ambitious in these applications and will be demanding more from the poor programmer who finds his tasks in the field of tension between the things to be done and the available tools. The scope of his task is just exploding.

At face value our main shortcoming is that we have let ourselves be lured into constructing elaborate mechanisms, the actual behaviour of which has grown far beyond our mental grasp or even worse: the misbehaviour of which is well beyond our control. As a professional community we play the Sorcerer's Apprentice over and over again.

Closer scrutiny reveals the current source of the trouble: viz. unstructured multitude and bigness, insufficiently organised complexity with its bastards such as Chaos, Unreliability, Unadaptability and the like. To regain control over what we are doing and what we are making constitutes for me the main challenge of software engineering.

EWD245 - 1

-2-

Now, closer to the problem at hand. It would be helpful if all of us recognised that although the programmer only makes programs, the true subject matter of his trade are the possible computations evoked by them. In actual fact: the computation is the happening that has to effectuate the desired effect or in other words, when a programmer claims that his program is correct, he actually makes a statement about the computations!

Trivial as this remark may seem I must state that it has had a profound influence on my thinking and my programming. Once I was really aware of my mind's task to bridge the conceptual gap between the static program and the dynamic computation, I have restricted myself to the most straightforward sequencing clauses, finding myself in general unable to cope with programs containing go to statements. I will return to sequencing control later on, at present we note that here is an element of structure greatly assisting me in understandability of what we are making.

After long and, I must admit, rather painful struggles, I came to the following conclusion: doing something and knowing what you have done implies that your act is presented as a choice from what you could have done. In particular: making a program implies taking a whole class of programs into account: alternative programs for the same job or for related jobs, and programs on various levels of detail. In doing so I made the following observations which may inspire you: they seemed relevant in the light of my experience.

1. Different members of the program class can only share their correctness proof to the extent that they enjoy the same structure. In other words: comparing programs with the aim of comparing the corresponding computations is only a fruitful activity to the extent that they exhibit the same sequencing.

EWD245 - 2

-3-

2. A flowchart need not be regarded as a vague sketch of what we are going to do, a sketch that only makes sense when the details have been filled in. On the contrary: at the appropriate level of abstraction it can be regarded as a program existing in its own right.

3. It may very well be that certain aspects of the original problem statement are only reflected at the lower levels of greater detail: this just means that at the higher level one has a program solving a generalised problem.

4. I tend to think of the program consisting of a set of hierarchical layers, performing in steps the transition from what we have got into what we should like to have. The right of existence of these separate layers is that in each layer an independent abstraction is implemented: an identified choice is condensed in its coding. One of the trickiest kind of alternatives to compare turned out to be analagous to the design decision whether something shall be done by software or by a machine instruction. This observation is, I think, encouraging.

Finally, to ride another little pet horse of mine: experience has given me a strong indication that provided the software is properly constructed its correctness can be claimed much more convincingly by a convincing proof of its correctness than can ever be achieved by the all too common procedure of testing and debugging. I know that the truth of this statement is doubted by many, but always by those who did not try to apply the method.

Transcribed by Richard Walker.

Last revised on Wed, 9 Jul 2003.

  EWD 246

Verslag van het bezoek aan de NATO Conference on Software Engineering.

Voor het eerst kost het mij grote moeite om na een reis een verslag te schrijven. Ik heb zo veel gehoord, dat ik het nog niet gesorteerd heb, ik heb meer indrukken opgedaan dan ik in de gauwigheid heb kunnen verwerken en tenslotte: de vertrouwelijkheid nam dusdanige vormen aan dat ik niet precies weet wat ik wel en wat ik niet aan papier kan toevertrouwen.

Ter verduidelijking van de situatie wil ik proberen een paar van de oorzaken te noemen, die tot deze bijzondere omstandigheden aanleiding hebben gegeven.

Om te beginnen was de groep een ongebruikelijke collectie, ongebruikelijk in de zin dat velen hier elkaar voor het eerst ontmoetten. (Om een indruk te geven: 24 van de 55 deelnemers had ik nooit eerder ontmoet en ik heb de indruk dat de meesten zich in een soortgelijke positie bevonden.)

Dit maakte de conferentie boeiend omdat we allemaal met nieuwe werelden van ervaring kennismaakten. Een nevenvoordeel was, dat deze conferentie hierdoor niet gevoeld werd als voortzetting van een groepsactiviteit die tot "the establishment" behoort, zoals IFIP-commissies met hun inmiddels traditioneel geworden manier om discussies te laten verzanden. Hierdoor was het allemaal erg verfrissend, een soort tegengif tegen de inteelt: in de loop van de dagen werd het gewoonte juist niet [emph] bij vriendjes te gaan zitten (zo sterk, dat ik geen gelegenheid heb gehad alles met Peter Naur te bespreken, dat ik met hem bespreken wilde).

Verder werd men, in weerwil van de bandrecorder, bijzonder openhartig, zo erg zelfs, dat in de slotzitting verzekerd werd dat na de preparatie van een publiceerbaar document, de banden uitgewist zouden worden. Er is uit vele scholen geklapt. Voor deze openhartigheid zijn wel een paar oorzaken aan te geven. Ten eerste was menigeen in een voldoend hoge positie om zich wel het een en ander te kunnen permitteren en sprak men met voldoende kennis van zaken om de feiten te kunnen geven en het trekken van conclusies bij wijze van spreken aan het publiek over te kunnen laten. Ten tweede is de software failure nu zo manifest, dat het niet goed meer mogelijk is om hier de ogen voor te sluiten. Ten derde heeft de openingstoespraak van Fritz Bauer ongetwijfeld tot deze openhartigheid bijgedragen.

Na dit samenhangende stuk wat losse, soms meer persoonlijke opmerkingen.

Het was verfrissend te ervaren dat de "software failure" door dit gezelschap op een enkele uitzondering na in zijn volle omvang zonder er om heen te draaien erkend werd. Dit is immers de eerste voorwaarde, opdat er serieus wat aan gedaan wordt. Vooral mensen uit het bedrijfsleven waren zielsgelukkig, dat ze het nu eindelijk zeggen mochten! (Er was er eentje, ik ben gelukkig vergeten wie, die zowat stond te snotteren in de trant van "Binnenskamers kunnen we dit nu wel allemaal zeggen, maar naar buiten kan dit toch niet "without the profession losing its face"!)

Er zijn bijzonder harde noten gekraakt over de rol van de computer manufacturer in dit alles en een meer dan evenredig deel (vergeleken bij het marktaandeel) kon IBM in zijn zak steken. Hoeveel ik hiervan laat doorsiepelen weet ik nog niet. Het is jullie genoegzaam bekend dat deze firma mijn sympathie niet heeft. Om te beginnen vond ik hun producten slecht, later vond ik hun verkoopsmethoden infaam. Nu de THE weer voor het probleem van computerkeuze staat, kan al wat ik in deze richting rapporteer haast niet anders uitgelegd worden als stemming maken tegen IBM. Laat me zwart op wit verklaren dat wat ik in deze richting rapporteer, geen overdrijving is. Als ik me kras uitdruk, verdenk me er dan niet van, dat ik uit persoonlijke wrok of zo er nog een schepje boven opleg. Ik zou nl. niet eens weten hoe, hoe ongeloofwaardig dat ook moge schijnen! Het waren niet alleen gefrustreerde klanten of concurrenten, het kwam net zo goed van binnenuit. Noch klant noch werknemer zijnde heb ik me buiten deze discussies gehouden. Maar ik heb wel met klapperende oortjes zitten luisteren!

Vooral "the sales department" heeft het erg moeten ontgelden: naar binnen het volledig onmogelijk makend om met een fatsoenlijk product te komen, naar buiten een oplichtersbende. De kale hardware van de 360 werd unaniem getaxeerd als "a poor machine", hardware + software als deplorabel. De opbouw van het operating system is uitgegroeid tot een kermis met 3000 programmeurs die gemiddeld 1 jaar ervaring hadden. Onlangs is de 16de versie uitgekomen, waarin t.o.v. de 15de, naast wat uitbreidingen, nog 1057 fouten gecorrigeerd zijn! Voor klanten die voor hun software op de fabrikant waren aangewezen is het heel gewoon dat ze twee jaar na installatie van "this wonderful machine" nog steeds niet over een bruikbaar systeem beschikten. Een ander symptoom van de mate, waarin de boel in de soep is gelopen is het feit, dat over de laatste 10 jaar de omvang van basic software met een factor 1.7 per jaar is toegenomen.

Omdat ik (terecht of niet) de naam heb als een van de eersten dit debacle voorspeld te hebben, namen sommigen aan, dat deze onthullingen mij grote voldoening moesten schenken, maar ik voelde me niet lekker. Omdat de werkelijkheid zoveel erger was dan ik ooit gevreesd had? Omdat ik een nieuw evangelie moest vinden om te preken? Omdat ik bevangen werd door een gevoel van machteloosheid, dat ik het zo weinig had kunnen voorkomen? Ik weet het niet. De intensieve confrontatie met de macht van econimische [sic] pressie, de vernietigende en corrumperende invloed daarvan maakte deze seance voor mij tegelijkertijd nogal deprimerend.

Opvallend was wat vooral Amerikanen zeiden over de plaats van Software Engineering in Education. Het werd heel nadrukkelijk niet toevertrouwd aan Mathematics Departments ("The real mathematician is utterly useless"), het werd even nadrukkelijk niet toevertrouwd aan Departments of Computer Science ("The only thing they do is to turn out people to staf other Computer Science Departments"). Ter verfrissing van de discussie heb ik "The mathematical engineer" genoemd, maar velen ervaarden dit als een contradictio in terminis. Op de vraag in hoeverre software engineering eigenlijk een wiskundige activiteit was, was de consensus "by content no, by method yes", maar vooral Amerikanen en Duitsers waren erg gedesiluusioneerd [sic], hadden niet het minste vertrouwen in het aanpassingsvermogen van hun wiskundige collegae en werden bij het gebruik van de term "mathematical" duidelijk kopschuw. Het gedrag van sommige anderen (in het bijzonder van prof. Hume, Dept. of Computer Science, Univ. of Toronto) heeft mij wel meer begrip voor die kopschuwheid bijgebracht.

Als persoon heb ik heel gespannen zitten luisteren om de betekenis te peilen van het project, dat ik nu onder handen heb. Van het belang ben ik meer dan ooit overtuigd, mede doordat wat ik probeer minder uniek blijkt dan ik dacht. Door de bank genomen is de ervaring een aansporing om op de ingeslagen weg voort te gaan; ik kreeg steeds de indruk inmiddels dieper geploegd te hebben dan anderen. Mijn zelfvertrouwen is wel een aantal keren ernstig aan het wankelen gebracht vanwege mijn minieme ervaring: Amerikanen overdonderen mij altijd en het duurt een of twee dagen voordat ik me daarvan hersteld heb. Dat "Al doende leert men" geen automatisme is wist ik al; sterker "Too much experience may corrupt the soundness of your judgement". Kortom, mijn constant pogen om van mijn zwakte mijn kracht te maken is door de hele confrontatie zo mogelijk alleen maar versterkt. Tot zover mijn verslag, wellicht alleen nog maar in eerste ronde.

Edsger W. Dijkstra

transcribed by Jeanine Daems
revised Wed, 17 Jan 2007

  EWD 247

My comments fall in three distinct classes.

1.Is an international institute the proper vehicle?
The report of the NATO Study Group on Computer Science is not very convincing on this point. If the goal is so important it fails to show why private enterprise could not undertake such a project. The fate of co-operative bodies such as ICC, in Rome is a warning that should not be ignored. Particularly in this case, where the competence of the top-people engaged is of so vital importance, the usual boundary conditions on nationality can only be expected to be very harmful.

2. How has the project been chosen?
Having heard Dr. M.D. McIlroy's talk at the NATO Conference on Software Engineering at Garmisch, October 1968 and having read the aforementioned report, one cannot escape the impression that a very tentative suggestion made by Dr. M.D. McIlroy has been welcomed as a means of giving substance to an otherwise empty construction. Some of the considerations in the report strike me less as motivations having led to the worthiness of the cause than as afterwards dressing it up in OK-sentences. I quote "An area ripe for engineering progress is the fabrication, along standardized lines, of a range of software components that can efficiently bridge the hardware-software gap in a multiplicity of actual applications on a multiplicity of actual machines."

3. How feasible and how desirable seems the project?
I would classify the talk of Dr. McIlroy (for whom I have the greatest respect) as a worthy contribution to the famous and much-needed "Journal for half-baked Ideas.
It has been inspired and recommended by an analogy to the automobile industry, as is still reflected by the sentence in the report: "This would be an attempt to bring about a change from handicraft to industrialised production with consequent improved efficiency and reduction in price" but the analogy is misleading for in contrast to any hardware industry, the cost of making replicas of a design is small in the software industry. I fully agree that software engi- neering should rise as soon as possible above the handicraft level (it does already!) but to tackle this by "automated software [component] production" before the basic disciplines of programming are much better understood than they are now strikes me as rather premature.
Even if it could be done I have grave doubts to its desirability. Underlying the stress on "component production" we find the tacid assumption that, macroscopically speaking, present-day systems are desirable in structure and that our sole difficulty to-day lies in our insufficient ability to make such systems. I would venture the opinion that the main source of our present-day troubles is not our production technique but the kind of object we are trying to produce. Standardized component production, once established, seems hardly a fertile ground for a more basic rearrangement of our thoughts about system structure. And it is exactly there where I expect the greatest potential benefit.

Edsger W. Dijkstra.            

transcribed by Reynir Stefansson
revised Mon, 18 Apr 2005

EWD 247a

1.1. Prof.dr. E.W. Dijkstra.
1.2. Fundamentele Programmering.
1.3. Onderafdeling der Wiskunde.
1.4. Het ontwerp van een discipline ter verhoging van ons programmerend vermogen.
  De nadruk ligt hierbij op het compositieproces zelve. Eerste onderzoekingen
  hebben aangetoond:
  a. dat men niet een enkel programma maar een klasse programma's in beschouwing
moet nemen;
  b. dat het essentieel is deze klasse zonder "duplicering" te kunnen beschij-
ven opdat wat verschillende programma's uit de klasse gemeenschappelijk
kunnen gebruiken ook slechts eenmaal in de hele opbouw voorkomt;
  c. dat de logische beheersingen van "uitgestelde beslissing" en "gewijzigde
beslissing" zo sterke overeenkomst vertonen, dat het vruchtbaar is om
van "adaptability" een van de belangrijkste ontwerpcriteria te maken.
     We rekenen erop, dat dit project kan uitmonden in de constructie van een
     "programming tool".
1.5. Ja, maar het project is nog in het papieren stadium.
1.6. Het project staat op het werkprogramma: hoe definitief zal afhangen van
  hoe veelbelovend het blijft. Op het moment verwachten we er bijzonder veel
  van.
1.7. Als de ontwikkeling van discipline naar "programming tool" doorzet, is het
     bespelen van terminals een hoeksteen.
     Dus c., hoewel ik niet wil kiezen, of onze invoer "data" of "programma"
     genoemd moet worden: bij de mechanisatie is de bedoeling van een machine
     gebruik te kunnen maken voor de opbouw van grote programma's. Zo je wilt
     kan dit project gezien worden als een poging op systematische wijze via
     terminals programma's op te bouwen.
1.8. In de komende jaren: ik houd er rekening mee, dat in 1970 de behoefte aan
     access gaat spelen.
1.9. Het project wordt uitgevoerd door de groep Fundamentele Programmering;
     wij hopen ook afstudeerders hierin te kunnen betrekken. De vraag "Wie maakt
     de programma's" ligt wat moeilijk: het project is niet anders dan het
     maken van programma's. We hopen op een bootstrapping, waarbij het systeem
     in embrionale vorm reeds gebruikt kan worden bij zijn eigen opbouw.
1.10 Moeilijk. Het systeem bespelen en gebruiken valt nl. onder "programmeerwerk",
     Hoe groot het embrio zal zijn, met andere woorden hoe effectief de boot-
     strapping is nog niet te begroten.

2.1. Twee terminale simultaan ter beschikking lijkt een minimum, nodig om
     de relevante logische problemen van programmawijziging tijdens programma-
     activiteit reeds te ontmoeten. Als het systeem een standaardfunctie in
     het programmeerpracticum krijgt, hangt de behoefte af van studentenaan-
     tallen. Als het project uitgroeit boven de status van "workshop" en
     algemeen gebruikt programmeergereedschap wordt, ligt dit kwantitatieve
     aspect nog heel anders. (Maar dit laatste verwacht ik niet voor, zeg, 1972.)
     In aard van terminal aarzelen we tussen teleprinter en character display
     met toetsenbord. De schatting is, dat character display met toetsenbord het
     belangrijkste actieve element wordt en uitvoer op andere media niet door
     de "programma componist" gezien hoeft te worden.
2.2. Niet te schatten.
2.3. Een groot secundair geheugen, opgewassen tegen "resident information"
     lijkt een conditie sine qua non voor succesvolle mechanisatie.
2.4. Als het programmeergereedschap groeit tot wat ik hoop en het gebruikt
     wordt voor de simultane opbouw van een aantal grote programma's, zal er
     emplooi zijn voor millioenen woorden secundair geheugen. (Elders is de
     bruikbaarheid van secundair geheugen onderschat!) Behoefte aan primair
     geheugen is slecht te schatten: veel zal er van afhangen, hoeveel terminals
     ermee spelen en of het van "workshop" groeit tot productiegereedschap.
     Eerste exploratie wijst wel in de richting dat een eventuele scheiding
     tussen het mechanisme voor programma compositie en dat voor programma
     executie alleen maar artificieel is.
2.5. Ik hoop op den duur continu.
2.5.1. Ik weet niet, hoe ik deze vraag moet beantwoorden.
2.5.2. "   "     "    "  "    "   "     "        "
2.5.3. "   "     "    "  "    "   "     "        "
2.5.4. "   "     "    "  "    "   "     "        "
2.5.5. Veel, maar het mag van mij ook in primair geheugen.
2.6.   Ik weet niet, hoe ik deze vraag moet beantwoorden.
2.7. Soms seconden, soms uren (zie 2.1.)
2.8. Ik weet niet, hoe ik deze vraag moet beantwoorden.
2.9. Informatieverlies is een klein rampje, scheduled maintenance hindert
     nauwelijks.
2.10.Essentieel (zie boven).
2.11.Vraag niet van toepassing.
2.12.Geen, voor zover ik zie.
2.13.Geen.

3.1. Ik weet niet, of het dit doet (als met locale apparatuur rekenapparatuur
     bedoeld is). Het hangt er erg vanaf, in hoeverre de harde software van de
     centrale machine tegen deze nieuw manier van machinegebruik op realistische
     manier is opgewassen.
3.2. Niet van toepassing.
3.3. Als het met locale apparatuur moet op den duur hoop ik 8 uur per dag.
3.4. Ik weet niet hoe ik deze vraag moet beantwoorden.
3.5. Ja (zie 2.4 laatste zin), nee als niet voldaan is aan laatste zin van 3.1.
4.   Niet van toepassing.

transcribed by Bart Vreugdenhil
revised 28-Nov-2011

  EWD 251

Requirements of Programming Tools.

We feel that the design of a programming language should be guided by a conception as clear as possible of the requirements it should satisfy. Regarding a programming language as a tool to be used by the programmer and taking the position that, for the tool to be really useful, it should assist the programmer as much as possible in the most difficult aspects of his task, we hope to derive the necessary clues from a careful analysis of (nature and source of) his difficulties, giving due recognition to the growth (in scale and scope) of his task.

Among the major difficulties we recognize his duty to create reliable mechanisms and to create programs in such a fashion that the possibility of program modification has been catered for as much as desirable. These difficulties are mentioned explicitly because from their analysis we expect, if not yet a discipline, at least new guidelines for the creating programmer.

We have avoided the word "language" in our subject description and have used the somewhat more general term "tool" as an expression of our feeling that current practice of program composition is in urgent need of revision and the "programming languages" as they are used now may turn out to be too tightly connected with the current practice to remain an adequate term for the tools eventually needed.

We expect the Working Group to act as a forum between a rather small number of sufficiently kindred spirits with sufficiently different backgrounds, so that it can provide an opportunity for mutual education and inspiration.

We feel it appropriate to suggest that IFIP could sponsor this activity. The motivation of the effort seems well-justified, its potential incompatibility with vested interests (of shorter range) could well justify some protection such as IFIP could provide.

Edsger W.Dijkstra

transcribed by Felipe Febrero Hidalgo
revised Sun, 19 Dec 2004

EWD 252

Mijn laatste verslag van een bijeenkomst van W.G.2.1.

Een en ander was zo mogelijk nog walgelijker dan de vorige bijeenkomst in North Berwick. Het was besloten, dat het document, waarover beslist zou worden in München voor 1 Oktober in ons bezit zou zijn; omtrent die datum kregen wij rapport MR99. Aan het begin van de bijeenkomst in München kregen we een nieuw rapport MR100. Het verschil tussen deze twee werd door van W. naar behoefte (zijn behoefte, wel te verstaan) gebruikt. Als het er om ging aan te tonen, dat hij aan zijn verplichting van 1 Oktober voldaan had, dan werd het verschil tussen deze twee documenten gebagatelliseerd, als het er om ging het huidige gezelschap recht van spreken te ontzeggen werd er de aandacht op gevestigd, dat niemand van dit gezelschap MR100 voldoende diepgaand bestudeerd kon hebben! Kortom, the usual trick.

Een groot gedeelte van de week is er aan gespendeerd om een "Cover Letter" op te stellen, die voldoende reserve tot uiting bracht om unaniem ondertekend te kunnen worden. Deze heeft de staat bereikt, dat een straw vote ten aanzien van zijn acceptabiliteit haalde zoiets als 34 voor, twee tegen en een onthouding, kortom het begon er op te lijken. Op de laatste morgen bleek de meegaandheid van van W. alleen maar taktiek geweest te zijn om de oppositie te sussen en kwam hij met een verbeterde versie, die voor een solide minderheid onacceptabel was. Zoals is gezegd "It takes two drivers to avoid a collision" en van W. heeft het hier op aangestuurd, wellicht de misrekening makend, dat het volgende Minority Report, dat in ontwerp sinds dinsdagmorgen gecirculeerd had, of zo duidelijk gesteld was, dat het geen ondersteuning zou vinden, of op formele gronden onder tafel gewerkt zou kunnen worden. Toen het wel ondersteuning vond, heeft hij het tweede geprobeerd maar zulks is mislukt.

Ik laat hier de tekst van het minderheidsrapport volgen:

Minority Report.

We regard the current report as the fruit of an effort to apply a methodology for language definition to a newly designed programming language. We regard the effort as an experiment and professional honesty compels us to state that in our considered opinion we judge the experiment to be a failure in both respects.

The failure of the description methodology is most readily demonstrated by the sheer size of the report in which, as stated on many occasions by its authors, "every word and every symbol matters" and by the extreme difficulty of achieving correctness. The extensive new terminology and the typographical mannerisms are equally unmistakable symptoms of failure. We are aware of the tremendous amount of work that has gone into the production of the report, but this confirms us in our opinion that adequacy is not the term that we should employ of its approach. We regard the high degree of inaccessibility of its contents as a warning that should not be ignored by dismissing the problems of "the uninitiated reader". That closer scrutiny has revealed grave deficiencies was only to be expected.

Now the language itself, which should be judged, among other things, as a language in which to compose programs. Considered as such, a programming language implies a conception of the programmer's task. We recognize that over the last decade the processing power of commonly available machines has grown tremendously and that society has increased its ambition in their application in proportion to this growth. As a result the programmer of today and tomorrow, finding his task in the field of tension between available equipment and desired applications, finds himself faced with tasks of completely different and still growing scope and scale. More than ever it will be required from an adequate programming tool that it assists, by structure, the programmer in the most difficult aspects of his job, viz. in the reliable creation of sophisticated programs. In this respect we fail to see how the language proposed here is a significant step forward: on the contrary, we feel that its implicit view of the programmer's task is very much the same as, say, ten years ago. This forces upon us the conclusion that, regarded as a programming tool, the language must be regarded as obsolete.

The present minority report has been written by us because if we had not done so, we would have forsaken our professional responsibility toward the computing community. We therefore propose that this Report on the Algorithmic Language ALGOL 68 should not be published under IFIP sponsorship. If it is so published, we recommend that this "minority report" be included in the publication.

Signed:          | Edsger W.Dijkstra
| Fraser Duncan
| Tony Hoare
| Brian Randell
| Gerhard Seegmueller
| Wladislaw M.Turski
| Mike Woodger

Bij discussie bleek, dat omissie van de laatste vier regels van de een na laatste paragraaf (te beginnen bij "on the contrary...") er nog zo vier handtekeningen bij te krijgen waren geweest; de ondertekenaars hebben niet mede ondertekend uit naam van de afwezigen, wier "proxy" hen was toevertrouwd (twee of drie). Dat was dan dat.

Er wordt (door onze parent committee) onderzocht of de oprichting van een nieuwe Working Group (W.G.2.3 of 2.4) "On Requirements of Programming Tools" kan worden samengesteld opdat een zich in de laatste vergaderingen uitkristalliserend minderheidsstandpunt vrucht drage. Het was opvallend te zien, hoe vele van de leden van WG2.1 hier niet zonder afgunst belangstelling voor toonden; het heeft ons de grootste moeite gekost om de Chairman er van te weerhouden de deur naar deze nieuwe Working Group wijd open te zetten. Wat we zo proefden was "Gee, that sounds interesting..." en hoe vermakelijk dat ook was om waar te nemen, het is een beetje moeilijk werk te ondernemen met mensen, die zulks in het verleden constant verhinderd hebben.

Om met een citaat van Dorothy Sayers te eindigen "I consider it a disgraceful ending to a most disastrous affair". Het is ontmoedigend om te zien, waartoe iemand, vertrouwend op takt en taktiek, zich kan laten verleiden; persoonlijk put ik slechts troost uit de overweging dat voor mij die verleiding niet zo groot is!

| Edsger W.Dijkstra

transcribed by Angelo van der Sijpt
revised Fri, 12 Jan 2007

EWD 252a

Ontwerp voorwoord.

Deze brochure is samengesteld om U behulpzaam te zijn bij de keuze van een afstudeerrichting, bij het bepalen van een voorkeur voor een afstudeerhoogleraar en bij de samenstelling van (voornamelijk) Uw afstudeerprogramma voorzover dit keuzevakken en stages betreft. De meest informatieve manier leek om elke hoogleraar van de Onderafdeling der Wiskunde zijn eigen bijdrage te laten schrijven, terwijl een redacteur de brochure van een inleiding zou moeten voorzien en het daarheen zou moeten leiden dat de diverse bijdragen voldoende homogeen van stijl en pretentie zijn om voor U een vergelijking enigszins mogelijk te maken. En het is deze redacteurstaak die ik gaarne op mij heb genomen, omdat ik ten volle besef hoe moeilijk deze keuze (tussen U eigenlijk nog onbekende alternatieven!) U vaak moet vallen.

Wij kunnen U slechts informatie geven, voorzover die ons relevant voorkomt opdat U een iets duidelijker inzicht krijgt, waartussen U kiest. Om teleurstelling te voorkomen wil ik vooropstellen, dat het heel erg de vraag is of daarmee de keuze voor U makkelijker zal worden: naarmate de alternatieven duidelijker een beeld moeten vormen van wie U bent en wat U wilt. Zo zal bv. de ene student een keuzevak kiezen omdat het hem makkelijker voorkomt, overwegend dat hij daarmee zijn afstuderen bespoedigt, terwijl een andere student een keuzevak zal kiezen, juist omdat het hem moeilijk voorkomt, overwegend dat wanneer hij zich in zijn studententijd niet met de betrokken materie vertrouwd maakt het er waarschijnlijk later nooit meer van zal komen. Zo zal de ene student een keuzevak kiezen omdat het bij zijn afstudeerrichting aansluit, maar zal een ander een keuzevak kiezen juist omdat het zo weinig met zijn afstudeerrichting te maken heeft. Kortom, bij de keerzijde van de medaille, bij het "Ken Uzelve" kan deze brochure U uit de aard der zaak niet helpen.

U kunt ook niet verwachten dat deze brochure U alle informatie geeft, die U zou willen hebben omdat wij niet kunnen voorzien op grond van welke criteria U verkiest te kiezen. Het is in dit verband wellicht nuttig er op te wijzen, dat ik aan mijn redacteurschap niet de vrijheid ontleen eigenmachtig (redactionele) wijzigingen in de bijdragen mijner collegae te brengen: hun bijdragen, zoals gepubliceerd, zijn van begin tot eind door henzelf geschreven en voor hun eigen tekst dragen ze de volle verantwoordelijkheid, opdat U desgewenst de wijze, waarop zij over hun werk schrijven, bv. of ze het als makkelijk dan wel als moeilijk afschilderen, eveneens in Uw keuze kunt betrekken.

Een vraag, die U zich bij de keuze van een afstudeerrichting stellen moet, is "Hoeveel hangt voor mij van de keuze af?" en mijn neiging is om, ongehoord Uw antwoord, te zeggen "Minder dan U denkt.". Ik krijg nl. de indruk dat veel studenten tamelijk zwaar tillen aan de keuze, alsof deze keuze bepalend zou zijn voor de professionele activiteit voor de rest van het leven, een indruk, die door de belangstelling voor "toekomstmogelijkheden" versterkt wordt. Gezien de bijzonder snelle en drastische verschuiving in de eisen, die de maatschappij aan zijn technici stelt, moet ik hier een ernstige waarschuwing laten horen: ik verwacht van het merendeel van onze wiskundige ingenieurs dat ze in de loop van hun leven terecht zullen komen in professionele activiteiten waarin hun afstudeerrichting van weleer niet meer te herkennen is. Sterker, ik hoop dat menig wiskundig ingenieur zich in die hoedanigheid verdienstelijk zal maken op een werkterrein dat thans niet of nauwelijks voorzien lijkt! Over de lange termijn gezien kon wat een student precies gedaan heeft daarom wel eens minder belangrijk zijn, dan dat hij iets gedaan heeft en geleerd heeft dat goed te doen.

| E.W.Dijkstra

Ontwerp "Over de afstudeerrichting "Fundamentele Programmering"."

Fundamentele programmering houdt zich, zoals de naam zegt, bezig met programmeren, hetzij als activiteit, dan wel als object van studie. Programmeren is de kunst iets groots en ingewikkelds zo ordelijk op te zetten en uit te werken, dat men (als persoon of als groep) zijn intellectuele greep op zijn schepping blijft behouden, dat men ongestructureerde veelheid temt en deszelfs bastaard Chaos zo effectief mogelijk weet te vermijden.

Welke kennis en welke vaardigheden zijn hierbij vereist? In het kort zou ik willen zeggen: vrij weinig specifieke kennis, maar des te meer vaardigheid en zelfkennis. Uit de rest van het wiskundig curriculum kan ik nauwelijks onderwerpen kiezen, waarvan ik zeggen kan "Die zijn onmisbaar.", een onvermogen dat ten nauwste verband houdt met het feit dat moderne rekenautomaten, als mathematische machines beschouwd, hun naam "general purpose equipment" terecht en met ere dragen.

De aansluiting met de rest van het wiskundig curriculum is drieërlei.

Ten eerste via een groot applicatiegebied. Wie voor een of andere toepassing een programma maakt, moet niet alleen kunnen programmeren, hij moet ook de totale taak, die de machine in die toepassing is toegedacht, kennen. En elke keer dat (zoals vaak) deze taakstelling een afwegen van mogelijkheden versus desiderata is, is inzicht in het toepassingsgebied op zijn zachtst gezegd meegenomen. Het is via de applicatie dat bv. kennis van lineaire algebra, differentiaalvergelijkingen, statistiek en numerieke wiskunde van groot nut kunnen blijken.

Ten tweede—en hier fungeert de wiskundige ervaring als algemene ontwikkeling ten aanzien van het programmeren zelf, ongeacht de toepassing—omdat een goed programma zo ongeveer uit componenten wordt opgebouwd als een wiskundige theorie uit stellingen. Het is daarom dat ik van afstudeerders verwacht, dat zij door eerder opgedane ervaring een goed ontwikkeld gevoel voor de logische samenhang van wiskundige theorieën hebben: deze ervaring dient bij het opbouwen van programma's te worden overgedragen (ik denk hier bv. aan groepentheorie.)

Ten derde omdat van de programmeur, die de correctheid van zijn programma bewijzen moet, vertrouwdheid met (in hoofdzaak discrete) bewijstechnieken gevraagd wordt benevens, naast de discreet-logische aspecten, enig stochastisch benul opdat hij oog hebben voor de quantitatieve aspecten van het gedrag van (de machine werkend onder controle van) zijn programma. Als hij staande voor een keuze die op dergelijke quantitatieve gronden genomen worde, handig een verantwoorde schatting kan maken, dan is dat meegenomen.

Een en ander impliceert dat ik bij afstudeerders vrij liberaal kan zijn ten aanzien van welke stof ze uit de rest van het curriculum hebben gekozen; daar tegenover staat echter, dat ze dan wel behoorlijk boven die stof moeten staan.

Welke vaardigheden worden vereist? Uit de analogie tussen een programma enerzijds en een theorie anderzijds volgt, dat men vrij creatief moet zijn en moet beschikken over een "zakelijk" abstractievermogen. (Met de toevoeging "zakelijk" bedoel ik, dat men niet alleen nieuwe begrippen moet kunnen invoeren, maar daarbij een wijd open oog moet hebben voor hun hanteerbaarheid en hun nut.)

Vervolgens stel het vak hoge eisen aan iemands vermogen tot zindelijk (den desgewenst toch beeldend) taalgebruik: men heeft dit nodig voor de (frequente!) introductie van nieuwe begrippen, men heeft dit nodig omdat programmeren vaak en groepsactiviteit is, waarin in discussies de relevante begrippen nog gevonden moeten worden, men heeft dit tenslotte nodig als tegengif, ter ontmaskering van de reclame-slogans, waarvan dit vak helaas vergeven is.

Ten leste moet de programmeur een ver-ontwikkeld orgaan hebben voor volledigheid, nauwkeurigheid en netheid, kortom een liefde voor detail. Wie als programmeur meent op deze nederige deugden te kunnen neerzien, heeft het verkeerde vak gekozen.

Tenslotte een enkele alinea over de toekomstmogelijkheden. Ik zou me met een beroep op "The computer is here to stay" hiervan kunnen afmaken met een simpel "Riant natuurlijk!", ware het niet dat ik mijzelf vandaag de dag wel drie maal zou bedenken voordat ik het vak "Software engineering" zou kiezen. (Aan het einde van mijn eigen studententijd heb ik me wel meer dan drie maal bedacht, maar ik had het makkelijker, want het vak bestond nog niet en in mijn jeugdige onnozelheid voorzag ik niet, hoe dilettantisme en belangenstrijd dit bedrijf later vertroebelen zouden.) Het punt is nl. dat het intellectueel niveau, dat eigenlijk voor dit werk nodig is, over het algemeen zwaar onderschat wordt, waardoor de meeste programmeurs, gewapend met te primitieve denkhulpmiddelen, worstelen met problemen, die hun capaciteiten aanzienlijk te boven gaan. Hun product is navenant, hun enige troost is, dat zij het zelf niet beseffen en dat hun chef (nog) denkt, dat het nu eenmaal niet beter kan. De maatschappelijke gevolgen van de huidige praktijk van computergebruik worden echter zo onaanvaardbaar, dat hier verandering in moet (en ook zal) komen. Voor de zwakke broeder betekent dit, dat het vak hem nog verder boven het hoofd zal groeien; voor de begaafde betekent dit, dat hij een gerede kans loopt nog God weet hoeveel jaren te moeten werken in een sfeer, die nu al als achterlijk gedisqualificeerd kan worden: een leger doorgeschoten boekhouders zal zich uit lijfsbehoud genoodzaakt zien, hem de voet dwars te zetten!

| E.W.Dijkstra

transcribed by Angelo van der Sijpt
revised Thu, 7 Feb 2008

EWD253

Tentamen Co-operating Sequential Processes | jan. 1969

Aan een ronde tafel zijn 8 regelmatig lange de omtrek verdeelde zitplaatsen, cyclisch genummerd van 0 t/m 7; de leden van een gezelschap van 8 personen zijn eveneens genummerd 0 t/m 7, ieder mag alleen op zijn eigen plaats —dwz. de plaats, die zijn eigen nummer draagt— aan tafel zitten.

Het gedragspatroon van elk der personen bestaat in eerste instantie uit een niet eindigende alternering van twee handelingen, nl. "ijsberen" en "op je plaats zitten", te beginnen met "ijsberen".

Gevraagd wordt om in het gedrag van de leden een zodanige onderlinge synchronisatie te programmeren, dat het zwaartepunt van de bezette plaatsen niet samenvalt met het middelpunt van de tafel; alle zitplaatsen onbezet geldt hierbij (vanwege de ongedefinieerdheid van genoemd zwaartepunt) als toelaatbare toestand.

Bewijs de correctheid van Uw oplossing en toon aan dat hij (ook voor elke deelverzameling van het gezelschap) vrij is van het gevaar voor dodelijke omarming.

Tentaminandi wordt verzocht het papier slechts eenzijdig en zo leesbaar mogelijk te beschrijven.

prof.dr.E.W.Dijkstra

transcribed by Carl Ludwigson
revised Thu, 4 Nov 2010

EWD253a

Ontwerp Collegebeschrijving "Inleiding tot de kunst van het programmeren."

Het is de bedoeling van dit college, dat de student vertrouwd wordt met een aspect van de taak van de programmeur, dat hij nl. leert voor gegeven opgaven opgaven hand in hand een rekenproces te concipieren en een algoritme te schrijven, die dit rekenproces kan oproepen. Het college is niet een opleiding in het gebruik van specifieke programmeertalen of machines, integendeel: het beoogt de student vertrouwd te maken met een begrippenarsenaal, dat hem in staat stelle rekenproces en algorithme te structureren op een wijze, die herkenbaar zal blijven, ongeacht het specifieke gereedschap, dat hij later komt te bespelen. Ik wil hem een stijlbesef bijbrengen, dat bij het maken van "grote programma's" er beslissend voor is of de opgave überhaupt tot een goed einde gebracht kan worden en dat bij "kleine programma's" sneller tot een beter programma leidt.

Ik heb dit college nu (voorjaar 1969) tweemaal gegeven. Ik verwacht dat de (in het verleden wel aangestipte) problemen die specifiek zijn voor grote programma's, in de komende jaren meer op de achtergrond zullen raken –en wellicht het onderwerp van een apart college worden– en dat dit college, om een hogere "vertrouwdheidsgraad" te bereiken, meer kleine voorbeelden zal behandelen en van meer oefenmateriaal voorzien zal worden.

Ter vermijding van misverstand: dit college gaat niet in de eerste plaats over rekenmachines, noch over programma's, maar over de activiteit programmeren. Om valse verwachtingen te voorkomen: ik kan geen recepten geven die een gebrek aan inventiviteit kunnen compenseren, ik kan slechts proberen de student vertrouwd te maken met een ideaal van logische hanteerbaarheid.

Als voorkennis verwacht ik niet meer dan het algemene college "Algorithmen" uit het vierde semester.

Tenslotte: voor wie is dit college bestemd? Ik zou zeggen, voor allen, die verwachten later met automatische rekenmachines te maken te zullen krijgen. (Diep in mijn hart hoop ik meer, want het eigenlijke, onuitgesproken onderwerp van dit college is zoiets als "Hoe tem je complexiteit?" en dat dit toevallig op de programmeurstaak is toegespitst is alleen maar een gevolg van mijn verleden!)

E.W.Dijkstra

transcribed by F. Koenders
revised Thu, 13 Nov 2008

EWD 254

Computer Science of enkel Software Engineering?

We kunnen zo ongeveer de volgende gebieden (in volgorde) onderscheiden:

1)     hardware fabricage

2)     hardware ontwerp (circuitry, plaatsing)

3)     hardware specificatie (architectuur, functioneel ontwerp)

4)     software engineering (specificatie, ontwerp, fabricage, aanpassing)

5)     toepassingen en methoden, hierop gericht.

en de vraag is, op welke gebieden de onderafdeling der wiskunde zich concentreert.

1)     Ik denk hier aan opdamptechnieken, het valt misschien meer onder de physica der vaste stoffen dan onder electrotechniek, het valt in elk geval buiten het terrein van de onderafdeling der wiskunde.

2)     Dit gebied valt onder electrotechniek: hier zijn wel wiskundige problemen, nl. die van de schakeltheorie (equivalentie en zo) en optimaliseringsopgaven onder combinaritorische vrijheden. Hier fungeert de wiskunde voor mijn gevoel als toeleveringsbedrijf, het gebied valt buiten de wiskunde als zodanig.

3)     Dit gebied ligt op de grens van electrotechniek en wiskunde: de vorige gebieden perken het realiseerbare af, software levert en motiveert de verlangens. Het wordt daardoor tot een meer wiskundige activiteit dan de vorige twee. Tevens fungeert wiskunde hier weer als toeleveringsbedrijf (bv. via de stochastiek en simulatie ter optimalisering of tijdige detectie van knelpunten).

4)     Dit gebied ligt als abstracte discipline op het gebied van de onderafdeling der wiskunde; overige takken der wiskunde (bewijstheorie en stochastiek) kunnen weer als toeleveringsbedrijf functioneren.

5)     Via de toepassingen waaiert het gebied in zijn totaliteit ver uit buiten de competentie van de wiskunde; wel ligt er een duidelijke taak op het gebied van methoden (numerieke, optimaliseringstechniek, programmeertalen, heuristiek, simulatie en programmeren). Hier is de rekenautomaat in hoofdzaak gereedschap, de wiskunde toeleveringsbedrijf en ligt het doel in het toepassingsgebied.

Gebieden 1) en 2) vallen duidelijk buiten ons directe werkterrein, 4) en 5) vallen er duidelijk binnen. Gebied 3) —wat ik vroeger deed— is het vraagpunt en het is de vraag of we dit laten schieten of niet. Betrekken we het in de activiteiten, dan tenderen we naar Computer Science, laten we het schieten, dan blijft 4) —wat ik nu doe— over als bouwsteen van een wiskundige richting “Software Engineering”. (In deze indeling taxeer ik Lunbeck hoofdzakelijk in 5, met dien verstande, dat ik van hem uitbreiding van het toepassingsgebied en bijbehorende methodenontwikkeling verwacht.)

Mijn neiging is op het ogenblik erg om 3) te laten schieten en me op 4) te concentreren en me daarbij meer te laten sturen door wat je als mens kan en zou willen dan wat op bestaande apparatuur vraagt. Ik wil proberen om wat van de overwegingen bloot te leggen, die tot deze plaatsbepaling van mij geleid hebben, omdat ze voor een gedeelte ongetwijfeld relevant zijn voor de plaatsbepaling van de onderafdeling in dit vakgebied.

De overgang van 3 naar vier was om te beginnen om historische redenen noodzakelijk: te lang zijn rekenautomaten ontworpen op grond van technische mogelijkheden (een begrijpelijke traditie!) en te lang is het probleem hoe je ze nu eigenlijk gebruikt naar later gedelegeerd. Om iets verstandigers te zeggen over hoe machines er eigenlijk uit zouden moeten zien, was 4) dus noodzakelijk. Inmiddels heeft dit mij helemaal opgeslokt en is mijn neiging om 3 te laten waaien. Waarom? Defaitisme en onmacht, zo je wilt.

Een belangrijke, opportunistische overweging is ongetwijfeld dat de TH niet beschikt over de electrotechnische gesprekspartner, die hiervoor nodig zou zijn. Dat Heetman in dezen incompetent is wordt nog verzwaard door het feit, dat hij de grenzen van zijn eigen competentie niet kent. Tengevolge daarvan zie ik pogingen tot samenwerking als heilloos en frustrerend en zelfbescherming noodt mij om contact met hem te minimaliseren. Het heeft toch geen zin. Dit is een profane, practische overweging, maar het is voor mij een heel sterk motief om mij terug te trekken op het gebied, dat ik onafhankelijk op een nette manier bestrijken kan, om het stuk er uit te lichten, dat past in het beeld van de wiskundig ingenieur. (Dit soort gesprekspartner had ik nog wel, toe ik Electrologica adviseerde, nu ik Philips-Electrologica adviseer is dat veel minder omdat het concept van het verkoopbare product daar pregnanter naar voren komt.)

Naast deze interne rem is er een externe: sinds universiteiten niet meer laboratoriummachines ontwerpen en bouwen, sinds de machine geworden (verworden?) is tot een industrieel serieproduct, zit de industriele machineontwerper aan handen en voeten gebonden, zijn terms of reference liggen voor 88 procent hardstikke vast, het gaat er niet meer om om iets goeds (dwz. beters) te maken, het gaat er om om hetzelfde te maken, maar liefst goedkoper. Wat zal ik dan leuke machines ontwerpen, of, op kleinere schaal: normen voor gezonde hardware specificaties, als je die ideeen nog niet aan de straatstenen kwijtkunt? Dit klinkt misschien erg bitter (is het misschien ook wel) maar het is een realiteit, waarvoor ik niet mijn kop in het zand wil steken. Het puin, dat op het ogenblik tot norm verheven wordt, (omdat iedereen het koopt) is afstotend.

transcribed by Bart Vreugdenhil
revised 28-Nov-2011

EWD254a

Hoger order adressering.

Als men programmaonderdelen of bibliotheekprocedures onafhankelijk wil vertalen impliceert dit de introductie van locale terminologieen (immers: zonder locale terminologieen waren de vertalingen niet onafhankelijk!).

Wie dergelijke onafhankelijk vertaalde stukken wil samenbreien, verplicht zich tot de introductie van een interlocale terminologie, waarin elk globaal object in het hele breiwerk uniek benoemd is.

Om te vermijden, dat teksten in dit samenbreien extensief worden bij gewerkt, voert men tabelletjes in, die steeds een locale terminologie in de interlocale overvoeren. We bereiken hiermee het volgende

1) de samenbreibeslissingen (inbedbeslissingen) zijn in de tabellen gelocaliseerd, wat voor wijzigen bv. belangrijk is.

2) als eenzelfde text in verschillende breisels voorkomt (denk aan bibliotheekprocedures), dan hoeven we slechts het tabelletje in veelvoud in te voeren.

3) als de diepte van adressering niet in de programmatext maar in de entry van de tabelletjes te vinden is, dan hebben we een flexibel middel ter versnelling (indien nodig).

4) elke locale terminologie kan een gesloten adressering zijn, met enige voorzorgen kunnen we de interlocale terminologie ook (grotendeels) gesloten houden.

Je eerste idee is, om elk vertaald stuk te voorzien van een catalogus, waaruit bij samenbreien het locale tabelletje kan worden samengesteld. (Dit zal “naamtechnisch” wel op contractie neerkomen!) Een programma, dat uit vijf onafhankelijk vertaalde stukken wordt opgebouwd bevat dan zes tabellen: eentje voor elke locale terminologie (dat zijn er al vijf) en eentje voor de interlocale terminologie (waarin we voor elk object uniek bv. kunnen bijhouden, waar het zich bevindt).

We doen er goed aan te beseffen, dat we met de introductie van deze zes tabellen al aan het implementeren geslagen zijn! In het programma zijn het de vijf locale terminologieen, die een duidelijk gescheiden identiteit hebben: wat we vragen is een of ander vertaalmechanisme van locale naar interlocale naam (of zo).

Ik wil voorlopig proberen de vijf locale tabellen en de ene interlocale zo gelijk mogelijk te beschouwen en wel om de volgende redenen:

1) als ons breiwerk uit een onafhankelijk vertaald stuk bestaat —stel dat dat denkbaar is— dan kunnen locale en interlocale terminologie samenvallen.

2) als we in “interlocale terminologie” denken aan de nomenclatuur voor segmenten, dan moeten we niet schrikken als sommige entries van de interlocale tabel doorverwijzen naar een met andere programma’s gedeeld universum: ik denk dan de procedurebibliotheek.

3) ik zie niet in, waarom bv. aan-afwezigheidsadministratie van een segment, dat slechts in één locale terminologie benoemd is, niet in de bijbehorende locale tabel gevoerd zou kunnen worden. Dit zou efficienter kunnen zijn.

Zolang men zich beperkt tot vertaal— en linkingproblemen maakt men het zich echter heel makkelijk. Het punt is nl. dat op elk moment dat een (nieuwe) interlocale terminologie moet worden ingevoerd “elk segment er al is”. Je kan die segmenten op een rijtje zetten en dan nummeren. De te identificeren populatie is bekend op het moment dat de identificatoren moeten worden ingevoerd. Wie zich tot deze constellatie beperkt, dreigt te ontgaan dat elk mechanisme, volgens welke we objecten aan een reeds bestaande (en intern geidentificeerde) populatie kunnen toevoegen of er van kunnen afnemen, achter de schermen een algorithme impliceert voor de toekenning van de nieuwe identificator.

Ter onderscheiding van wat we besproken hebben en wat nu komt noem ik wat we gehad hebben statische (locale en interlocale) adressen en wat nu komt dynamische (interlocale en interlocale) adressen. Ik zal ook wel spreken van “statische context” en “dynamische context”.

Bij de dynamische locale adressen hebben we er voor te zorgen, dat in eenzelfde programma hetzelfde dynamische adres in verschillende incarnaties naar verschillende variabelen kan wijzen. Zulks betekent, dat we per incarnatie een tabelletje voor de locale dynamische terminologie invoeren. Er zijn, dacht ik, een aantal redenen om statische en dynamische locale adressen naar aparte tabellen te laten verwijzen. Er is een heel prozaische reden: als we ze in één tabel willen onderbrengen, dan wil je dacht ik de dynamische adressen wel apart hebben —zeg aan het hoge eind— en dat sorteerproces compliceert je vertaalproces een beetje. Er is een tweede reden en die is practischer: als je de zaak steeds in een tabel wilt onderbrengen dan moet je bij elke procedureaanroep dat constante stuk van de statische context, dat bij assemblage is ontstaan, copieren. En als je zoekt kan je, dacht ik, ook nog wel een formulering vinden, die fundamenteler aandoet, nl. dat beide tabellen, ieder voor zich, bedoeld zijn om het systeem opgewassen te maken tegen een heel ander soort combinatorische variatie, nl. verschillende namen voor hetzelfde, versus dezelfde naam voor iets anders.

De interpretatie van locale adressen vergt nu dus de kennis van twee tabellen, de statische en de dynamische. Vanwege verschillende procedureincarnatie’s moeten we de combinatie van eenzelfde statische context met vele dynamische contexten toestaan. Moet men ook omgekeerd de combinatie van eenzelfde dynamische context met verschillende statische contexten toestaan?

Ik heb het geval onderzocht, dat dit niet was toegestaan, dwz. dat elke dynamische context tijdens zijn leven altijd met een vaste statische context gecombineerd zou worden. Toen ik met die analyse klaar was, vroeg ik me echter af, wat er dan wel was overgebleven van het ideaal van “onafhankelijke vertaling van delen”: een en ander lijkt er dan nl. ernstig op, dat elke procedure dan combinerende de dynamische context nl. met de statisch locale terminologie in zijn geheel vertaald moet worden. En aangezien ik er aan gewend ben desgewenst een programma als een procedure te beschouwen, zou elk programma in zijn geheel vertaald moeten worden. Met de restrictie “slechts een statische context per dynamische” lijkt een stukje kind met het badwater weggegooid.

Ik stel me in het volgende voor, dat we geen aparte pagina’s kennen, voor segmenten enerzijds een maximale lengte accepteren, anderzijds niet opzien tegen kleine segmentjes. Er staat ons een dergelijke geheugenbespeling voor ogen, laadt ons proberen het er mee te doen!

In dat geval ligt het voor de hand om te overwegen naast de statisch interlocale tabel ook een dynamisch interlocale tabel in te voeren. Het alternatief is om slechts één interlocale tabel te hebben: wat via de statisch locale tabellen gerefereerd wordt komt dan in de bodem, terwijl daarop de dynamische tabel stack-fashion (stapelsgewijze is natuurlijk goed Nederlands!) groeien en krimpen kan. Dat betekent wel zowat, dat “linking” voltooid moet zijn voordat executie begint! Ik neem dus aan, dat we een aparte dynamische interlocale tabel hebben voor de unieke identiteit van de dynamische segmenten.

Ik stel me voor dat bij blokbinnenkomst voor de locale scalairen een segment geintroduceerd wordt. De verwerking van de arraydeclaratie kan zijn dat (in dit segment) de parameters worden opgezet die subscriptiewaarden omrekenen tot dynamisch interlocale adressen en dat zoveel segmenten worden geintroduceerd als voor dit array nodig. (NB. Als we de dynamisch interlocale tabel stacksgewijze bedrijven, dan kunnen we voor een groot array opeenvolgende interlocale segmentnummers uitdelen; dan rekenen we dus aan het dynamisch-interlokale adres. Een interlocaal segmentnummer wordt dan echt een nummer!) Wat het systeem betreft zijn segmenten voor locale scalairen en voor locale arrays op practisch dezelfde leest geschoeid en dat is hoopgevend.

Nu het moeilijke artikel van de procedureaanroep. Ik moet me in dit stadium beperken tot een eerste verkenning. We zitten met:

1) het meegeven van parameters, inclusief terugkeerinformatie

2) het springen naar een ander punt en eventueel een herdefinitie van de statische context

3) het creeren van een nieuwe geinitialiseerde dynamische context en het hierop overgaan.

Het meegeven van de parameters komt kennelijk ten laste van de calling sequence. In de daar heersende dynamische context kome een parametersegment voor, waarin de calling sequence de gegevens ad 1 invulle (wellicht uitgezonderd de terugkeerinformatie).

De karakterisering van de procedure bevatte de gegevens ad 2 (voor de sprong) en een karakterisering van de dynamische context waaruit de bodem van de te creeren dynamische context geinitialiseerd dient te worden.

Er kan nu een subroutinesprong uitgevoerd worden met als parameters

a1) de procedurekarakterisering (zie vorige alinea)

a2) de naam van het parametersegment (ik stel me voor, dat dit de interlocale naam al is, maar daarvan ben ik niet helemaal zeker)

De subroutinesprong bergt (bv. op een vaste plaats van het parametersegment) de terugkeerinformatie (in elk geval terugkeerplaats en statische context, dynamische context mag wat later) en de sprong naar de eerste opdracht van de procedure wordt uitgevoerd, terwijl de dynamische context van de calling sequence nog vigeert! Onder controle van deze text kan nu een nieuwe dynamische context gecreeerd worden. (Als voor deze creatie de lengte van de dynamische tabel nodig is en deze is een functie van de blokhoogte en van interne nesting van blokken, dan kunnen we deze gegevens, dacht ik, aan het begin van de procedure bij executie bekend veronderstellen.) Ik neem aan, dat gegevens a1 en a2 nog beschikbaar zijn. Uit a1 komt het gegeven uit welke dynamische context de nieuw geprepareerde gevuld moet worden (de proceduretext kan de blokhoogte suppleren). Vervolgens zal— en dat is eigenlijk de overgang van het parametersegment van actueel parametersegment in de calling sequence naar formeel parametersegment van de procedure— de procedure zelf een element (het volgende neem ik aan) van de dynamische tabel in preparatie initialiseren voor het parametersegment. Omdat gegeven a2 nog bekend verondersteld wordt en de procedure zelf de eigen naam van het formele parametersegment kent, zijn hiervoor alle gegevens ter beschikking. Tenslotte kan de procedure de dynamische context in opbouw uitbreiden met een segment voor de eigen localen en moet de dynamische context in opbouw de vigerende worden.

Dit hele stuk initialisatie en introductie van de nieuwe dynamische context kan de procedure dus zelf commanderen. Ik kan me voorstellen dat de ongeinitialiseerde nieuwe dynamische context meteen al “de vigerende” wordt. Initialisatie en introductie van een nieuw segment hebben dan per definitie betrekking op de vigerende dynamische context en dat lijkt wel prettig. Je zit dan wel een tijdje met “verboden dynamische adressen” (ongedefinieerde).

Opm1. Voor apart vertaalde procedureonderdelen mag de statische context voor “externals” van het onderdeel, die verwijzen naar localen van de hele procedure bv., als entry een dynamisch adres bevatten, dat per definitie verwijst naar de op dat moment vigerende dynamische context! Een dynamisch adres is statisch (bij textopbouw, maar ook bij samenbreien) heel goed manipuleerbaar. Dit geeft een belangrijk stuk vrijheid, bv. voor procedures uit de bibliotheek, die je “own’s” wilt geven, geadresseerd in de bodem van de stapel van het aanroepende programma.

Opm2. Dat het parametersegment bij call van dynamische naam verandert lijkt me uiterst gezond.

Opm3. Dat een dynamische context niet meer (zoals in mijn eerste opzet) vast aan één statische context gekoppeld is lijkt me een verbetering. Dit maakt het nl. mogelijk statische en dynamische context onafhankelijk om te zetten, dwz. nadat de statische context is omgezet kan de proceduretext zelf beginnen met de creatie van een nieuwe eigen dynamische context. In mijn eerste opzet moest dat veel gekunstelder.

Opm4. De terugkeerinformatie stel ik me voor te bevatten

1) dynamische context (wijzer)

2) statische context (wijzer)

3) locaal terugkeeradres (in termen van 2.)

N.V. PHILIPS’ COMPUTER INDUSTRIE
APELDOORN

transcribed by Bart Vreugdenhil
revised 08-Jan-2012

EWD 255

Over de IBM360

Een eerste serie bezwaren geldt de functionele specificatie van de kanaalorganisatie. Deze is ontworpen met de bedoeling dat de CPU een keten commando's ter sequentiele afwerking aan een kanaal kan aanbieden. De hardware is echter slecht bruikbaar doordat:
1) als een kanaal een interruptie signaal naar de CPU zendt voordat een vorig signaal van dit kanaal door de CPU gehonoreerd is, het vorige interruptie signaal onder tafel raakt;
2) het onmogelijk is op een betrouwbare manier een commando aan te haken aan een keten, die door het kanaal in bewerking is: probeert de CPU dit, dan is onder omstandigheden niet meer betrouwbaar vast te stellen, of het kanaal dit nieuwe commando nu nog wel of juist niet meer heeft uitgevoerd. (Deze onmogelijkheid is het gevolg van het feit dat de lengte van de commandoketen is aangegeven door markering van de laatste schakel.)
3) als de uitvoering van een commando mislukt, dit feit wel gemeld wordt, maar het kanaal na deze mislukking het volgende commando in de keten gaat uitvoeren alsof er niets mislukt was.

Ten gevolge van deze tekortkomingen kan de commandoketen niet gebruikt worden zoals bedoeld was en staat het operating system voor anders vermijdmare morele haastsituaties. (Zij, die niet in operating systems thuis zijn, voelen dit waarschijnlijk als detailcritiek. Ik vind het gesignaleerde defect echter een alarmerende indicatie ten aanzien van de competentie van het ontwerpersteam: hier is geen kwestie van smaak of stijl, er is met een zinvolle bedoeling het een en ander ontworpen terwijl een simpele redenering aantoont, dat de geboden faciliteiten ontoereikend zijn.)

Een tweede serie bezwaren bestaat uit voorbeelden, dat de ontwerpers de programma's teveel belast hebben met het beheer van de componenten van de machine, in plaats van het programma het proces op een abstracter niveau te laten vastleggen, het specifieke componentenbeheer aan systeem/machine delegerend. Voorbeelden hiervan zijn de volgende.
1) Peripherieapparaten kunnen slechts bediend worden door ze te koppelen aan een kanaal en vervolgens aan dit kanaal de commando's te geven. En dat terwijl het kanaal logisch geen betekenis heeft, het peripherieapparaat wel.
2) Het rekenorgaan bevat een groot aantal registers, waarvan in de programmatext expliciet staat aangegeven, welke er in elke opdracht gebruikt worden. Dit heeft onaangename gevolgen:
    2a) dat compilers met het probleem "register allocation" geconfronteerd worden, wat leidt tot een aan vertaaltijd kostbaar optimaliseringsproces
    2b) dat het soort statuswisseling, dat optreedt bij subroutineaanroep en multiprogrammering onontkoombaar tijdrovend wordt door red- en herstelplichten van registerinhouden (nodig of niet!).
Hier is het ontwerp microscopisch geoptimaliseerd, terwijl je macroscopisch de prijs vele malen betalen moet:
    ad 2a) de tijdrovendheid van het vertaalproces is verantwoordelijk voor de behoefte aan "onafhankelijk voorvertaalde programmaonderdelen", welker combinatie de behoefte aan een zg. linkage editor gecreeerd heeft;
    ad 2b) als qua tijd de schoen begint te knellen, moet je de subroutineaanroep vervangen door een aangepaste copie van de subroutinetext, wat aanleiding geeft tot heel lange programma's, zo lang, dat hun assemblage "a major processing task" wordt (Asher Oppler, IFIP 1965). IBM wil de dan benodigde geheugens graag leveren!

3) In plaats van dat het programma informatie adresseert, moet het geheugen adresseren, hetzij in kernen, hetzij disks, tengevolge waarvan elk programma individueel belast is met een prive- organisatie van "overlay's" en transporten tussen langzaam en snel geheugen. Dit heeft vrij rampzalige consequenties:
3a) Standaardprogramma's moeten bestaan in verschillende versies, al naar behoefte aan kerngeheugen. De wens programma's van anderen te gebruiken (APT voor de 360 bv.) kan je dwingen om je installatie met minstens zoveel kerngeheugen uit te rusten. Evenzo: vergroting van het kerngeheugen geeft niet geruisloos -dwz. zonder herprogrammering- efficiencywinst.
3b) De enige manier, waarop verschillende programma's enkelvoudig in het kerngeheugen aanwezige gemeenschappelijke routines samen kunnen gebruiken eist, dat deze routines permanent in het kerngeheugen staan. Omdat je hier dan weer zuinig mee moet zijn, is de behoefte aan "system generation" geschapen, systeemaanpassing aan de "problem mix", met alle ellende van dien: het is een tijdrovend proces en bovendien wil je het niet, want je "problem mix" kan immers veranderen!
3c) Het feit dat programma's gedurende hun executie een consecutief, onverschuifbaar stuk kerngeheugen bezetten verzwaart de scheduling task onnodig en buiten proportie, het resulterende systeem blijft stroef hanteerbaar.

Kortom: inbeddingsdetails, waarvan door iets geraffineerdere hardware geabstraheerd had kunnen worden, eisen nu hun expliciete representatie in de programma's. Enerzijds verzwaart deze onnodige explicietheid de programmaopbouw, anderzijds schaadt deze premature fixering de souplesse, waarmee de installatie nu nog gebruikt kan worden.

Het ongelofelijke is, dat deze machine nu geadverteerd wordt met het "wonderful operating system", dat zoveel lasten van de schouders van de programmeur afneemt. Men verdoezelt hierbij:
a) dat een groot gedeelte van deze lasten door de hardware zijn ontstaan en in een beter ontwerp lichter of non-existent waren geweest;
b) dat dit operating system een schrikbarende overhead impliceert (maar IBM wil je graag een sneller model uit de serie leveren);
c) dat de lasten de facto niet zijn opgevangen, maar overgeheveld zijn naar de directie van het rekencentrum, die de machine moet dimensioneren en beheren;
d) dat het maken van dit operating system een opgave is gebleken, die het programmerend vermogen van de fabrikant te boven is gegaan;
e) dat het systeem een zo barokke monstruositeit is geworden, dat geen gebruiker zich meer aan aanpassing kan wagen.

Ten leste, zoals de 709-serie me altijd getroffen heeft als een wanhopige poging om tapes als back up store te gebruiken, zo treft de 360-serie me als disk units met begeleidende electronica. Het zou me niet verbazen, als de wat teleurstellende performance van de snellere modellen in feite neerkomt op het feit, dat het snellere model, zeg, vier maal zo snel op de armbeweging staat te wachten. Hoe ze uit deze vicieuze cirkel moeten komen is me niet duidelijk: deze discrepantie opvangen door multiprogrammering is van de kant van de CPU erg onaantrekkelijk, overgang op "one-head-per-track-disks" zou wel eens veel van de motivering van het huidige operating system kunnen ontzenuwen.

transcribed by Hans Terlouw
revised Thu, 3 Dec 2009

EWD257

Verslag bezoek aan MIT.

MIT is heel duidelijk een elite instituut met de meeste voor- en nadelen van dien. Nadelen zign ej zeker isolationisme en gevaar voor inteelt. Voordelen zijn dat ze op 7000 studenten (waarvan de helft graduates) 900 faculty-member hebben en het niveen duidelijk hoog is. Orvallend is het wederzijds respect de cellegae prezen heter werkklimaat aan met "the kids are really bright". De studenten wisten wie ze voor zich hadden en spraken vaak met groot respect over hun leermeesters. (Ze beklaagden zich wel, dat hoogleraren vaak zo ontoegankelijk waren! Waar hebben we dat meer gehoord?)

Ik heb er acht voordrachten gehouden voor een constant gehoor van 100 man en de lezingen waren een groot succes. Mijn moeite werd elkte keer met een spontaan applaus beloond, de laatste zes voordrachten zijn op videotape opgenomen, tijdens mijn verblijf zijn ze afgespeeld, werd een volgende vertoning aangevraagd, en kwam er zelfs een verzoek van buiten voor een copie van de tapes. Het is niet zo, dat Amerikaanse studenten spontaan interrumperen, hoewel ik daar in het algemeen om gevraagd had: ik moest duidelijk gelgenheid tot vragen en commentaar geven. Dan kwam het wel. Het soort bespiegelingen, waaraan ik ze blootgesteld heb was kennelijk helemaal nieuw voor ze, en ik heb veel "onderlinge discussies" los gemaakt, die meer dan eens in mijn maker eindigden.

Aan alle Amerikaanse instituten die ik heb meegemaakt, was het rekeninstituut los van computer science. In MIT was die scheiding pas recent aangebrach; het algemeen oordeel was, dat ze hier te lang mee gewach hadden. In Pittsburg was Computer Science een apart Department, voornamelijk op grond van de motivering det wanneer je computer science in een ander department onderbrengt, dit andere department onvoldoende begrip en competente supervisie kan opbrengen. In MIT was het ondergebracht onder het Department of Electrical Engineering en die situatie was duidelijk niet ideaal. Het is gegroeid onder Robert Fano, die toen informatie-theorie doodliep, hierop overgeschakeld was. Fano is heel evident een groot man, maar ter zake onvoldoende competent. De groep was daardoor niet en geheel, je had vier vrij gescheiden activiteiten. Niemand was hier gelukkig onder, en van diverse kanten werd de behoefte aan "technically strong leadership" geuit. Fano was zich al wat aan het terugtrekken.

Duidelijk was de afwezighed in Amerika van een krachtige traditie van toegepaste wiskunde: de theoritici waren er te puur, de parctici waren er te pragmatisch. Dat is waarschijnlijk de reden, dat mijn verhaal zo insloeg: ik had beide extremen wat te vertellen. (Ik had ook tussen wal en schip in kunnen komen, bedenk ik nu.).

In Princeton heb ik een voordrach gehouden, die niet erg goed liep. Van tevoren had ik geluncht met mijn gastheer, die een vrij vervelende en domme jongen is en ik was niet meer in de stemming. In Yorktown Heights liep het lekker der; er was daar een grote afvaardiging uit Poughkeepsie, wat in de discussie wel te merken was. In Waterloo (Ontario) liep het leuk,m aar inmiddles meer door mijn routine dan dat het gehoor erg inspirerend was; Waterlooo vond ik, hoewel er twee heel leuke jongens waren, als geheel dprimerend. De laatste week in Pittsburg was, hoewel ik inmiddels wel erg naar huis begon te verlanngen, leuk. Ik kan voor Perks also computer scienties niet veel respect hebben, als gangmaker en inspirato is hij voortreffelijk. Ik had dit jaren geleden al gehoord en het was leuk, dit bevestigd te zien. Tegen aandrang mijn verblijf met een week te verlengen, opdat ik (op een eilandje voor de kust van Californie) de blik can twintig "top designers" van Burroughs, Pasadende, zou helpen verruimen heb ik, hoewel het vast heel luek zou zijn en in elk geval financieel heel attractief, weerstand geboden. Ik wou naar huis.

18 april 1969.

E.W. Dijkstra.

transcribed by Andreas Jonsson
revised Sat, 16 Oct 2004

| EWD 259

Toekomstverwachting Fundamentele Programmering.

Onderhanden is een onderzoeksproject naar de mogelijkheden om ons programmerend vermogen een orde van grootte te verhogen. De motivering voor dit onderzoek is gelegen in de observatie, dat de huidige State of the Art ten duidelijkste een gezonde methodologie ontbeert, met alle nadelige gevolgen van dien: “kleine” programma's worden met vallen en opstaan gemaakt, “grote” programma's ontaarden maar al te vaak in debacles. De reden dat dit onderzoek ter hand heb genomen is omdat ik dacht in dezen mijn steentjes te kunnen bijdragen, een hoop die op grond van aard, bezorgdheid, werkwijze, ervaringen in het verleden bereikte resultaten niet helemaal ongerechtvaardigd lijkt.

Ik ben nu zo' ongeveer een jaar bezig. Het eerste half jaar is gaan zitten in een analyse van waarom programmeren zo vaak zo onmenselijk moeilijk wordt (“een catalogus van ons onvermogen”) en een uitzoeken van wat we nog betrouwbaar kunnen zonder ons voorstellings- of overzichtsvermogen te zeer te overbelasten (“een catalogus van onze relevante vermogens”). Dit alles om gevoel te krijgen tot wat voor programmastructuren we ons in naam van de concipieerbaarheid zouden moeten proberen te beperken.

In het tweede halfjaar heb ik allerlei programmastructuren geprobeerd, aanvankelijk nog erg tastend in het donker. (Het grote probleem bij deze experimenten was natuurlijk om ze zo goedkoop mogelijk uit te voeren, om “speelmateriaal” van nét voldoende complexiteit te vinden, zodat er iets van te leren viel). Duidelijke aanwijzingen ter zake van een nuttige structuur hebben zich pas aangediend toen ik serieus recht liet wedervaren aan de eis van “aanpasbaarheid”, dwz. dat elk groot programma (althans potentieel) in honderden aanverwante versies moet kunnen bestaan, zonder dat de hiervoor benodigde intellectuele investering evenredig met dit aantal stijgen mag. Sindsdien zijn mijn ervaringen uiterst bemoedigend: de eis van bewijsbaarheid, dat het programma correct is, evenals de eis, dat het programma aanpasbaar zij, blijken, wanneer ter harte genomen,de taak van de programmeur aanzienlijk te verlichten, omdat ze hem voor allerlei verwarrende kronkels behoeden.

De meest significante uitslag van de experimenten tot op heden is wellicht dat duidelijk aan het licht is gekomen dat programmeertalen, zoals die op het ogenblik en vogue zijn (inclusief al hun varianten) als programmeervehikel inadequaat zijn, wanneer we de eis stellen, dat we het programma zo willen formuleren als we het begrijpen en concipiëren kunnen. Er kleeft aan hen nog hetzelfde bezwaar dat ook kleefde aan de machinetalen, nl. dat het programma in wezen geschreven en begrepen moet worden op eenzelfde semantisch niveau. Als ik nu een ALGOL-programma bedenk, merk ik, dat ik het op de mij inmiddels aangeleerde “getrapte” manier concipieer en opschrijf – met grote winst aan tijd en betrouwbaarheid; maar wat ik dan heb opgeschreven, moet ik “met de hand” zo goed en zo kwaad als het gaat in ALGOL vertalen. Aan den lijve heb ik ervaren, hoe riskant dit proces is; nu weet ik, hoe “onleesbaar” bv. ALGOL-programma's zijn en begin ik in te zien, waarom.

Wat begonnen is als het zoeken naar een geestelijke discipline “Hoe programmeren we voor een gegeven machine, resp. in een gegeven programmeertaal?” groeit naar de ontwikkeling van een nieuw ”programmeergereedschap”. Nu speel ik nog, maar er komt (hoop ik!) een moment, dat dit gereedschap er om vraagt om tot een voldoend compleet systeem voltooid te worden en tot een werkend systeem geimplementeerd te worden. (En met “werkend” bedoel ik: met een realistische graad van performance: “the proof of the pudding is the eating”, maar dat werkt niet echt, als je eens per maand een muizenhapje nemen mag!)

Op de mogelijkheden hiervoor kan ik op tweeenhalve manier aandringen. (Naarmate het project volgroeit met meer klem en wellicht met drie).

1)    Het project streeft een uiterst practisch doel na en zij realistisch. Zonder de realisatiemogelijkheden word ik gedoemd tot de rol van kamergeleerde (resp kamerdromer), een bespiegelende functie, die ik – dacht ik – nog niet verdien. (Terzijde: dit is een mieters dubbelzinnige formulering!)

2)    Als in mijn hoofd het gereedschap tot een voldoende graad van volledigheid ontwikkeld is, dan heb ik het nodig om studenten metterdaad te leren programmeren. Studenten leren om zich te behelpen met een stuk gereedschap waarvan je de gebreken inmiddels kent is erg en deprimerend genoeg; op het moment, dat je weet, hoe je deze gebreken ondervangen kunt, wordt zulks de academie onwaardig.

3)    (Dit is voorhands het halve argument.) Als het gereedschap conceptueel uit de verf is gekomen, dan is deszelfs implementering nog een aanzienlijk software project, dat wij zelf voor onze rekening zullen moeten nemen. De vraag is, in hoeverre via geraffineerde “bootstrapping” het stuk gereedschap in ontwikkeling zinnig gebruikt kan worden voor zijn eigen opbouw. Het antwoord hierop weet ik nog niet. Als het echter bevestigend luidt, ligt hier een ideaal werkterrein voor afstudeerders: beter kunnen ze het dan niet hebben!

Als de belofte, die dit project lijkt in te houden, vervuld worden, is het een project voor tenminste twee vaste medewerkers. We moeten proberen om het zó te organiseren, dat meer mensen (vaste medewerkers, afstudeerders of misschien zelfs stageaires) hieraan kunnen meewerken, opdat zij ervan leren. Uit educatieve overwegingen is dit gewenst, over het bereikbare aantal is in dit stadium – nl. voordat een solide stuk ontwerpwerk gedaan is – nog geen verantwoorde uitspraak te doen. (Mijn persoonlijke neiging is om met kleine groepen te werken en, eventueel ten koste van de doorlooptijd, de hoeveelheid werk te minimaliseren. Weet ik enerzijds dat premature parallellisering tot debacles leidt, anderzijds weet ik ook (van dichtbij) dat het streven om parallelle ontwikkeling mogelijk te maken, een ontwerp zeer ten goede komt. Ik zal mijn best doen.)

Als het project op gang komt en wil blijven, zullen de vaste medewerkers zich hier volledig aan moeten wijden en tegen de tijd, dat we een machine in onze werkzaamheden kunnen inschakelen, ongelimiteerd acces tot deze machine hebben.

transcribed by Martin van der Burgt
revised 2013-06-20

EWD 260

Plotting a curve with a printer.

given:  0 ≤ fx(i) < 100   and   0 ≤ fy(i) < 50   for   0 ≤ i < 1000

COMPFIRST

begin

draw: {build; print};

var image;

instr build(image), print(image)

end

CLEARFIRST

begin

build: {clear; setmarks};

instr clear(image), setmarks(image)

end

ISCANNER

begin integer i;

setmarks: {i:= 0; while i < 1000 do {addmarks; i plus 1}};

instr addmark(i,image)

end

COMPPOS

begin integer x, y;

addmark: {x:= fx(i); y:=fy(i); markpos};

instr markpos(x,y,image)

end

LINER

begin integer j;

image: {array line[0:49]};

print: {j:= 49; while j ≥ 0 do {lineprint(line[j]); j minus 1}};

clear: {j:= 49; while j ≥ 0 do {lineclear(line[j]); j minus 1}};

markpos: {linemark(line[y])};

type line;

instr lineprint(line), lineclear(line), linemark(x,line)

end

LONGREP

begin integer k;

line: {integer array sym[0:99]};

lineprint: {k:= 0; while k < 100 do {PRSYM(sym[k]); k plus 1}; NLCR};

lineclear: {k:= 0; while k < 100 do { sym[k]:= space; k plus 1}};

linemark: {sym[x]:= mark}

end

SHORTREP

begin integer k;

line: {integer f; integer array sym[0:99]};

lineprint: {k:= 0; while k < f do {PRSYM(sym[k]); k plus 1}; NLCR};

lineclear: {f:= 0};

linemark: {while f ≤ x do {sym[f]:= space; f plus 1};

           sym[x]:= mark}

end

N.V.PHILIPS' COMPUTER INDUSTRIE
APELDOORN

transcribed by Corrado Cantelmi
revised Fri, 2 May 2008

EWD 261

Hoe wiskundig programmeren is.

     Een (goed opgezet) programma vertoont een grote structurele analogie met elke (goed opgezette) mathematische theorie. Het werk van de programmeur onderscheidt zich daardoor voor mijn gevoel niet wezenlijk van dat van de creatieve mathematicus.

     Er zijn echter (meer of minder) duidelijke accentsverschillen:
1)   de basisconcepten der programmering zijn gering in aantal en vrij simpel (misleidend simpel, zo je wilt); het is daardoor een ideaal oefenterrein voor ontwikkeling. (Daarbij komt nog de louterende, correctieve invloed van de eis, dat het programma uiteindelijk echt moet werken!)
2)   veel wiskundeonderwijs doceert bestaande theorieen, dwz. maakt de student vertrouwd met een specifiek (uitgebreid) begrippenarsenaal; de programmeur zal evenwel iedere keer het passende begrippenarsenaal zelf moeten ontwikkelen. Dit beroep op zijn actief abstractievermogen maakt programmeren tot een naar aard creatiever werk dan die wiskundebeoefening, die zich beperkt tot het toepassen van bestaande theorieen.
3)   doordat vele programma's zo groot zijn en nochtans werken moeten, leert de programmeur een bewustere ontwikkelingsmethodologie. En dat is, wat je moet proberen te doceren! Voor extensieve kennisoverdracht zie ik veel minder rechtvaardiging.

transcribed by Andreas Jonsson
revised Wed, 20 Apr 2011

  EWD 264

On Understanding Programs.

     On a number of occasions I have stated the requirement that if we ever want to be able to compose really large programs reliably, we need a discipline such that the intellectual effort E (measured in some loose sense) needed to understand a program does not grow more rapidly than proportional to the program length L (measured in an equally loose sense) and that if the best we can attain is a growth of E proportional to, say L², we had better admit defeat. As an aside I used to express my fear that many programs were written in such a fashion that the functional dependence was more like an exponential growth!

      I now offer, for the reader's consideration, an example showing how the same program can be understood in two different ways: in the one way, E grows proportional to L, in the other way it grows (even worse than) exponentially.

      I express E in the number of "steps of reasoning" needed, a number which is determined as follows.

      Let us consider a "stretched" program of the form

"S₁; S₂; ...; SN" | (1)

i.e. the corresponding computations are a time-succession of the executions of S₁ through SN in that order. When the nett effect of the execution of each individual statement Si is given, my measuring convention states that it takes N steps to understand program (1), i.e. to establish that the cumulative effect of N successive actions satisfies the requirements imposed upon the computations evoked by program (1).

      In the case of a program of the form

"if B then S₁ else S₂" | (2)

where, again, the nett effect of the execution of the statements S₁ and S₂ has been given, my measuring convention states that it takes 2 steps to understand program (2), viz. one step for the case B and another for the case non B.

      Consider now a program of the form

"if B₁ then S₁₁ else S₁₂;
 if B₂ then S₂₁ else S₂₂;
                     .
                     .
                     .
 if BN then SN ₁ else SN ₂"
(3)

      According to the measuring convention it takes 2 steps per alternative statement to understand it, i.e. to establish that the nett effect of

"if Bi then S i ₁ else S i ₂" |

is equivalent to that of the execution of an abstract statement S i . Having N such alternative statements it takes us 2N steps to reduce program (3) to one of the form of program (1); to understand the latter form of the program takes us another N steps, giving 3N steps of reasoning in toto.

      If we had not introduced the abstract statements S i , but had tried to understand program (3) directly in terms of executions of the statements S i j , each such computation would be the cumulative effect of N such statement executions and would as such require N steps to understand it. Trying to understand the algorithm in terms of the S i j , however, implies that we have to distinguish between 2N different routings through the program and this would lead to N*2N steps of reasoning!

      If by now the reader protests that the second way to try to understand program (3) is utterly foolish, then I have him exactly in the position where I want him to be, for then we could not agree more fully. The point is, that any effort to improve upon the second method yields a method more similar to the first one: one will find oneself introducing the abstract statements S i (or combinations of them)!

      The whole demonstration is an urgent plea to use our powers of abstraction as consciously as possible (and to restrict ourselves in programming to those program structures in which these powers can be exploited at greatest advantage!) The reader who has followed me thus far may wonder whether he has been confronted with something deep or something trivial. So did I, when I discovered this example; I have, however, decided to submit it for publication when I felt that it was probably both.

Edsger W.Dijkstra
Technological University
EINDHOVEN
The Netherlands

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

EWD 267

Over de toekomst van Computer Science.

Het centrale probleem van Computer Science vandaag is, op welke wijze we wat voor machines zouden willen gebruiken. Vandaag is dit probleem nog open: doordat we nog niet weten, hoe we zouden willen, dat een “gebruiksaanwijzing” er uitzag, komen er machines op de markt, waarvan het een probleem is, hoe je ze gebruiken moet. Maar het is niet alleen dat ik hoop, dat dit laatste probleem een bijzonder vluchtige taakstelling zal blijken, ik verwacht zulks ook. Binnen tien jaar verwacht ik voldoende (zelf)kennis van “de Programmeur”, dat wij een duidelijk beeld hebben wat voor machines goed bruikbaar zijn; tegelijkertijd zullen we dan weten, hoe we deze machines willen gebruiken. Zodra het niet meer de machines zijn, die de problemen stellen, is naar mijn smaak Computer Science klaar.

De tijdspanne van tien jaar voor de voltooiing van Computer Science treft wellicht als bijzonder kort (en nadat het plaatsgevonden heeft, duurt het waarschijnlijk nog wel een kwart eeuw, voordat de voltooiing tot iedereen is doorgedrongen!); ik heb er echter de volgende gronden voor.
1)     sinds dit onderzoek grotendeels gedreven wordt door de analyse van op wat voor wijze een mens betrouwbaar werken kan, is duidelijk een in de tijd vrij constant element geintroduceerd: ongeacht alle gepraat over de kloof tussen de generaties is de mens, als je een stap terugdoet, een vrij constant gegeven.
2)     er wordt door allerlei mensen bewust aan gewerkt en er wordt heel duidelijke voortgang geboekt.
3)     nu is het nog zo, dat een nieuwe hardware technologie oude kennis en vaardigheden op slag obsoleet kan maken en een hele klasse nieuwe problemen stellen kan: de hardware jongens maken een gadget, waarvan je opnieuw niet weet, hoe je het in hemelsnaam op een ordelijke manier gebruiken moet. Over tien jaar verwacht ik een zo duidelijk inzicht in onze mogelijkheden en beperkingen, dat hierdoor metterdaad, ook wanneer zich een nieuwe technologie aandient, het hardware ontwerp gestuurd kan worden tot een bruikbaar apparaat. Software ontwikkeling wordt nl. ook voor de fabrikant van machines een zo levensgroot probleem, dat ik me niet kan voorstellen dat men zich nog veel langer veroorloven kan hardware eerst autonoom te ontwikkelen en vervolgens als taakstelling aan de software over te dragen.

Hoe groot is het vak, wanneer het over tien jaar klaar is? Ik heb geen maat om dat uit te drukken, maar ik zou willen zeggen: klein, althans inkrimpend. Het bewerkstelligen van deze inkrimping is nl. de taakstelling van zijn ontwikkeling! (Uit de VS hoor je —overigens typisch Amerikaanse!— geluiden als: er zullen steeds meer probleemgebonden talen komen, er zullen dus heel veel compilers gemaakt moeten worden en het is dus nodig, dat we nog veel beter leren en doceren, hoe je compilers maakt. Compilerontwikkeling is in die gedachtegang een hoeksteen. Maar als je een pas terugdoet, constateer je dat wanneer compilerbouw een probleem is, dit grotendeels te wijten is aan de taal of de machine (of aan beide, c.q. de combinatie van de twee) en ik verwacht over tien jaar het inzicht waaraan bv. taal en machine getoetst kunnen worden, zodat compiler constructie geen groot probleem meer hoeft te zijn. Het is de functie van de ontwikkeling om onze huidige moeilijkheden waar mogelijk als “self-inflicted pains” te ontmaskeren, in plaats van nieuwe pijnstillende middelen te zoeken!)

{Terzijde: ik merk, dat het erg natuurlijk komt om “ontwikkeling” van een vak onmiddellijk met kwantitatieve “groei” te associeren, zo natuurlijk, dat ik met de vorige paragraaf bijzonder ben ingenomen.}

De tegenwerping is natuurlijk onmiddellijk: “Toegegeven, dat het de functie van inzicht is, om specifieke kennis overbodig te maken. Maar waarom durf je dan te hopen, dat het juist Computer Science zal zijn, waar deze inkrimping geeffectueerd zal worden, waar het nodige inzicht groeien zal?”.

Ik kan hierop een serie heel persoonlijke antwoorden geven, zoals “Ik moet in naam van mijn arbeidsvreugde wel hopen, want als ik het niet hoopte, zou het vuur waarmee ik me voor Computer Science in zet, rap gedoofd zijn en dat vuur is me te dierbaar.”, maar ik wil proberen een wat onpersoonlijker antwoord te geven.

Op grond van hun versatiliteit en macht worden computers voornamelijk geapprecieerd als gereedschap en vanwege hun nog hoge prijs, waar we begrijpelijkerwijs tegenaan hikken , is programmeren in veler ogen primair een optimaliseringsopgave, nl. een minimalisering van het gebruik. Naarmate machines goedkoper en machtiger gaan worden, zal de schoen minder vaak minder hard knellen en zullen efficiencyoverwegingen minder vooropstaan. Naarmate machines evenwel machtiger worden zal de mensheid evenredig ambitieuzer worden in hun toepassingen en deze schaalvergroting zal de taak van de programmeur, die zijn werkterrein immers vindt in het spanningsveld tussen (exploderende) wensen en mogelijkheden, meer en meer maken tot een intellectuele uitdaging van de eerste orde. Dat is het al, maar de eerste ronde hebben we, doordat we de uitdaging onvoldoende onderkend hebben, verloren! Het is een hoopvol teken, dat deze onderschatting erkend begint te worden (zij het, toegegeven, schoorvoetend en beslist niet door iedereen).

In een aantal opzichten lijkt programmering, wanneer de uitdaging eenmaal onderkend is, het ideale gebied om de uitdaging te aanvaarden en met (zo je rot wil zijn: goedkoop) succes te beantwoorden:
1)     het is, als wiskunde, een abstracte wetenschap, die zo schoon kan zijn als je hem opzet, in tegenstelling tot alle natuurwetenschappen, die een overweldigende hoeveelheid duistere observaties moeten ordenen;
2)     in relatie tot andere takken van de wiskunde is de conceptuele basis van de programmeur doodsimpel: alle moeilijkheden van het continuum, oneindigheid, keuzexioma’s e.d. worden de programmeur bespaard en je kunt programmeren dan ook beschouwen als een “beschermd oefenterrein” par excellence;
3)     van het feit, dat elk programma ook nog werken moet, gaat een constante, corrigerende werking uit;
4)     het veld ontleent zijn rijkdom niet aan de smalheid van zijn basis , maar aan de macht van de feitelijk aanwezige apparatuur, die nauwelijks een bovengrens oplegt aan de “sophistication” van wat je met de machine doet;
5)     wat je met de huidige machines al doen kunt, is al zo enorm “groot”, dat de behoefte aan een heel bewuste methodologie zich onmiskenbaar presenteert;
6)     en dit is een practische kwestie, er is zoveel mee gemoeid, de maatschappelijke pressie is zo sterk, dat dit gebied niet links kan blijven liggen.

Het is daarom, dat ik vol goede moed ben. Het is mede daarom, dat ik verwacht, dat wij de betekenis van rekenautomaten schromelijk zullen onderschatten zolang wij ze blijven apprecieren in hun hoedanigheid van gereedschap, hoewel ze als zodanig het aangezicht van onze maatschappij veranderen; in hun hoedanigheid van intellectuele uitdaging verwacht ik van hen een veel dieper gaande invloed op onze cultuur.

transcribed by Bart Vreugdenhil
revised 28-Nov-2011

EWD268 - 0

Structured programming

Edsger W. Dijkstra
Technological University
EINDHOVEN, The Netherlands

0. Introduction.

This working document reports on experience and insights gained in programming experiments performed by the author in the last year. The leading question was if it was conceivable to increase our programming ability by an order of magnitude and what techniques (mental, organizational or mechanical) should then be applied in the process of program composition. The programming experiments were undertaken to shed light upon these matters.

1. Program size.

1.0) My real concern is with intrinsically large programs. By "intrinsically large" I mean programs that are large due to the complexity of their task, in contrast to programs that have exploded (by inadequacy of the equipment, unhappy decisions, poor understanding of the problem, etc.). The fact that, for practical reasons, my experiments had thus far to be carried out with rather small programs did present a serious difficulty; I have tried to overcome this by treating problems of size explicitly and by trying to find their consequences as much as possible by analysis, inspection and reflection rather than by (as yet too expensive) experiments.

In doing so I found a number of subgoals that, apparently, we have to learn to achieve (if we don’t already know how to do that).

1.1) If a large program is a composition of N "program components", the confidence level of the individual components must be exceptionally high if N is very large. If the individual components can be made with the probability “p” of being correct, the probability that the whole program functions properly will not exceed

P=pN              :

for large N, p must be practically equal to one if P is to differ significantly from zero. Combining subsets into larger components from which then the whole program is composed, presents no remedy:

pN/2 * pN/2 still equals pN           !)

As a consequence, the problem of program correctness (confidence level) was one of my primary concerns.

1.2) The effort --be it intellectual or experimental-- needed to demonstrate the correctness of a program in a sufficiently convincing manner may (measured in some loose sense) not grow more rapidly than in proportion to the program length (measured in an equally loose sense). If, for instance, the labour involved in verifying the correct composition of a whole program out of N program components (each of them individually assumed to be correct) still grows exponentially with N, we had better admit defeat.

1.3) Any large program will exist during its life-time in a multitude of different versions, so that in composing a large program we are not so much concerned with a single program, but with a whole family of related programs, containing alternative programs for the same job and/or similar programs for similar jobs. A program therefore should be conceived and understood as a member of a family; it should be so structured out of components that various members of this family, sharing components, do not only share the correctness demonstration of the shared components but also of the shared substructure.

EWD268 - 1

So much for the large size of the individual programs and the large number of (potential) members of their family.

2. Program correctness.

2.0) An assertion of program correctness is an assertion about the net effects of the computations that may be evoked by this program. Investigating how such assertions can be justified, I came to the following conclusions:

2.1) The number of different inputs, i.e. the number of different computations for which the assertions claim to hold is so fantastically high that demonstration of correctness by sampling is completely out of the question. Program testing can be used to show the presence of bugs, but never to show their absence! Therefore, proof of program correctness should depend only upon the program text.

2.2) By a number of people it has been shown that program correctness can be proved. Highly formal correctness proofs have been given; also correctness proofs have been given for "normal programs", i.e. programs not written with a proof procedure in mind. As is to be expected (and nobody is to be blamed for that) the circulating examples are concerned with rather small programs and, unless measures are taken, the amount of labour involved in proving might well (c.q. will) explode with program size.

2.3) Therefore, I have not focused my attention on the question "How do we prove the correctness of a given program?" but on the questions "for what program structures can we give correctness proofs without undue labour, even if the programs get large?" and, as a sequel, "How do we make, for a given task, such a well-structured program?". My willingness to confine my attention to such "well-structured programs" (as a subset of the set of all possible programs) is based on my belief that we can find such a well structured subset satisfying our programming needs, i.e. that for each programmable task this subset contains enough realistic programs.

2.4) This what I call "constructive approach to the problem of program correctness" can be taken a step further. It is not restricted to general considerations as to what program structures are attractive from the point of view of provability; in a number of specific, very difficult programming tasks I have finally succeeded in constructing a program by analyzing how a proof could be given that a class of computations would satisfy certain requirements: from the requirements of the proof the program followed.

3. The relation between program and computation.

3.0) Investigating how assertions about the possible computations (evolving in time) can be made on account of the static program text, I have concluded that adherence to rigid sequencing disciplines is essential, so as to allow step-wise abstraction from the possibly different routing. In particular: when programs for a sequential computer are expressed as a linear sequence of basic symbols of a programming language, sequencing should be controlled by alternative, conditional and repetitive clauses and procedure calls, rather than by statements transferring control to labelled points.

3.1) The need for step-wise abstraction from local sequencing is perhaps most convincingly shown by the following demonstration:

Let us consider a "stretched" program of the form

"S₁; S₂; . . .; SN" (1)

and let us introduce the measuring convention that when the net effect of the execution of each individual statement Sj has been given, it takes N steps of reasoning to establish the correctness of program (1), i.e. to establish that the

EWD268 - 2

cumulative net effect of the N actions in succession satisfies the requirements imposed upon the computations evoked by program (1).

For a statement of the form

"if B then S₁ else S₂" (2)

w[h]ere, again, the net effect of the execution of the constituent statements S₁ and S₂ has been given; we introduce the measuring convention that it takes 2 steps of reasoning to establish the net effect of program (2), viz. one for the case B and one for the case non B.

Consider now a program of the form

"if B₁ then S₁₁ else S₁₂;
 if B₂ then S₂₁ else S₂₂;
    .
    .
    .
    .
 if BN then SN1 else SN2" (3)

According to the measuring convention it takes 2 steps per alternative statement to understand it, i.e. to establish that the net effect of

"if Bi then Si1 else Si2"

is equivalent to that of the execution of an abstract statement S₁. Having N such alternative statements, it takes us 2N steps to reduce program (3) to one of the form of program (1); to understand the latter form of the program takes us another N steps, giving 3N steps in toto.

If we had refused to introduce the abstract statements Si but had tried to understand program (3) directly in terms of executions of the statements Sij, each such computation would be the cumulative effect of N such statement executions and would as such require N steps to understand it. Trying to understand the algorithm in terms of the Sij implies that we have to distinguish between 2N different routings through the program and this would lead to N*2N steps of reasoning!

I trust that the above calculation convincingly demonstrates the need for the introduction of the abstract statements Si. An aspect of my constructive approach is not to reduce a given program (3) to an abstract program (1), but to start with the latter.

4. Abstract data structures.

4.0) Understanding a program composed from a modest number of abstract statements again becomes an exploding task if the definition of the net effect of the constituent statements is sufficiently unwieldy. This can be overcome by the introduction of suitable abstract data structures. The situation is greatly analogous to the way in which we can understand an ALGOL-program operating on integers without having to bother about the number representation of the implementation used. The only difference is that now the programmer must invent his own concepts (analogous to the "ready-made" integer) and his own operations upon them (analogous to the "ready-made" arithmetic operations).

4.1) In the refinement of an abstract program (i.e. composed from abstract statements operating on abstract data structures) we observe the phenomenon of "joint refinement". For abstract data structures of a given type a certain representation is chosen in terms of new (perhaps still rather abstract) data structures. The immediate consequence of this design decision is that the abstract statements operating upon the original abstract data structure have to be redefined in terms of algorithmic refinements operating upon the new data structures in terms of which it was decided to represent the original abstract data structure. Such a joint refinement of data structure and associated statements should be an isolated unit of the program text: it embodies the immediate consequences of an (independent) design decision and is as such the natural unit of interchange for program modification. It is an example of what I have grown into calling "a pearl".

EWD268 - 3

5. Programs as necklaces strung from pearls.

5.0) I have grown to regard a program as an ordered set of pearls, a "necklace". The top pearl describes the program in its most abstract form, in all lower pearls one or more concepts used above are explained (refined) in terms of concepts to be explained (refined) in pearls below it, while the bottom pearl eventually explains what still has to be explained in terms of a standard interface (=machine). The pearl seems to be a natural program module.

5.1) As each pearl embodies a specific design decision (or, as the case may be, a specific aspect of the original problem statement) it is the natural unit of interchange in program modification (or, as the case may be, program adaptation to a change in problem statement).

5.2) Pearls and necklace give a clear status to an "incomplete program", consisting of the top half of a necklace; it can be regarded as a complete program to be executed by a suitable machine (of which the bottom half of the necklace gives a feasible implementation). As such, the correctness of the upper half of the necklace can be established regardless of the choice of the bottom half.

5.3) Between two successive pearls we can make a "cut", which is a manual for a machine provided by the part of the necklace below the cut and used by the program represented by the part of the necklace above the cut. This manual serves as an interface between the two parts of the necklace. We feel this form of interface more helpful than regarding data representation as an interface between operations, in particular more helpful towards ensuring the combinatorial freedom required for program adaptation.

5.4) The combinatorial freedom just mentioned seems to be the only way in which we can make a program as part of a family or "in many (potential) versions" without the labour involved increasing proportional to the number of members of the family. The family becomes the set of those selections from a given collection of pearls that can be strung into a fitting necklace.

6. Concluding remarks.

6.0) Pearls in a necklace have a strict logical order, say "from top to bottom". I would like to stress that this order may be radically different from the order (in time) in which they are designed.

6.1) Pearls have emerged as program modules when I tried to map upon each other as completely as possible, the numerous members of a class of related programs. The abstraction process involved in this mapping turns out (not, amazingly, as an afterthought!) to be the same as the one that can be used to reduce the amount of intellectual labour involved in correctness proofs. This is very encouraging.

6.2) As said before, the programming experiments have been carried out with relatively small programs. Although, personally, I firmly believe that they show the way towards more reliable composition of really large programs, I should like to stress that as yet I have no experimental evidence for this. The experimental evidence gained so far shows an increasing ability to compose programs of the size I tried. Although I tried to do it, I feel that I have given but little recognition to the requirements of program development such as is needed when one wishes to employ a large crowd; I have no experience with the Chinese Army approach, nor am I convinced of its virtues.

August 1969

Transcribed by Ham Richards

Last revised on Tue, 8 Jul 2003.

EWD270

Aan de keuzecommissie rekenmachine.

Ik kom meer en meer tot de overtuiging dat een van de effectiefste manieren om wetenschappelijk peil en economie van een land een gevoelige klap toe te brengen, moet zijn de grootscheepse import van de thans meest gangbare Amerikaanse hardware en de bijbehorende, barokke software: vanaf dat moment is nl. een goed deel van het (schaars) beschikbare professionele potentieel opgezogen door de ondankbare taak in deze zich steeds wijzigende morstruositeit zijn weg te blijven vinden, een soort van “interne brain drain” (Enige maanden geleden hoorde ik het gerucht dat de volgende Russische machine-serie een getrouwe copie van de 360-serie zou zijn: als dat waar is beschouw ik dit als een van de Amerikaanse triomfen in de koude oorlog!) Een en ander wordt vaak nog verergerd door de omstandigheid dat het ontvangende land niet rijk genoeg is om de inefficiency van de geboden software in gemoedsrust te kunnen accepteren, maar (doorgaans ten onrechte!) denkt zich wel te kunnen permitteren eraan te gaan sleutelen!

Edoch, de kwaliteit van het gereedschap, waarmee mensen hun resultaten proberen te bereiken, vindt zijn directe weerspiegeling in de omvang en het intellectuele niveau van hun beslommeringen. Zo is het vooral deze "degrading influence" van obsolete apparatuur op het intellectuele niveau van werk en werkers, die het bezoeken van rekencentra 0onmiddellijk achter het ijzeren gordijn zo deprimerend maakt: het zich moeten behelpen met inmiddels zo aantoonbaar inadequate hulpmiddelen trof mij als zonder meer mensonterend. Mutatis mutandis geldt hetzelfde ten aanzien van mensen die opgroeien en zich behelpen moeten in wat inmiddels aangeduid begint te worden als “a pure FORTRAN environment”: op een gegeven moment kunnen zij programmeerproblemen mentaal niet anders meer grijpen dan vertaald in —en daardoor mistekend!— de idiosyncrasies van hun dagelijks gereedschap. Als je met zulke mensen praat, gaat er een wereld van onbegrip voor je open.....

Als alle machines op de markt even onbeholpen bruikbaar zouden zijn en elkaar daardoor in hun normatieve (maar daardoor niet minder verderfelijke) invloed op hun gebruikers niet veel zouden ontlopen —dwz. in dat opzicht soortgelijke machines zouden zijn— kan aan dat kwaliteitsaspect geen keuze- criterium ontleend worden en kan men proberen de keuze door de gangbare, nogal economisch getinte overwegingen te laten leiden. Nu het er echter, na onze studie van de markt, steeds overtuigender op begint te lijken dat de B6500 qua ontwerp met kop en schouders boven de rest uitsteekt en door zijn synthese van hard- en software een machine beloof te zijn, die qua hanteerbaarheid onvergelijkbaar veel beter is dan alle andere, nu wordt de invloed van de machine op zijn omgeving plotseling een van de meest relevante keuzecriteria.

Onder de gegeven omstandigheden is het onze plicht 1) geen middel onbeproefd te laten om onze indruk van de B6500 te verifieren 2) als genoemd onderzoek positief uitvalt geen (oirbaar) middel onbeproefd te laten een dergelijke machine voor de THE te bemachtigen.

Ik ben mij ervan bewust dat een en ander niet zonder problemen is. Een duidelijke moeilijkheid is het feit dat Burroughs hier te lande commercieel nog niet sterk vertegenwoordigd is. Komen wij echter tot de conclusie, dat zulks voor Nederland alleen maar jammer is, dan zullen wij Burroughs moeten helpen en alles in het werk moeten stellen —bv. door de aanleiding te verschaffen!— dat deze vertegenwoordiging sterker wordt. Serieuze belangstelling onzerzijds zal voor Burroughs een dergelijke versterking waarschijnlijk voldoende interessant maken.

Een tweede moeilijkheid is, dat zowel van buiten als van binnen de THE conservatieve aandrang zal worden uitgeoefend: de introductie van een B6500 zal als storend element lang niet door iedereen gewaardeerd worden. Van zuster- instellingen, die een dergelijke stap als critiek op hun conventionele keuze kunnen uitleggen, is weinig steun te verwachten. Ook intern zijn er nivellerende krachten, mensen die de THE in dit opzicht liever zouden terugdringen van zijn vooruitgeschoven positie tot een normaal derderangsinstituut waarin zij zichzelf beter thuisvoelen of, zoals ze zullen motiveren "we de studenten realistischer voorbereiden op hun toekomstige taak".

Ten derde zitten we met de moeilijkheid, dat de traditionele keuze bij uitstek de keuze van de incompetente lafaard is. (Illustratief is in dezen het verhaal van het adviesbureau dat terzake van machinekeuze een advies moest uitbrengen. Toen dit een non-IBM-advies werd, bleek de adviesaanvragen een formaliteit te zijn omdat de facto de keuze al op IBM gevallen was en wel met de motivering “We hebben tot nog toe IBM apparatuur gehad en daar hebben we al zoveel ellende meegehad, dat we met producten van een andere firma helemaal niet in zee durven gaan.”) Wie zich tot de traditionele markt beperkt, weet —of althans: hoort te weten— wat voor ellende hij in huis haalt, maar hoe rot het daarna ook loopt, hij weet zich tegenover "management" gedekt! De maar al te vaak gehanteerde nauwelijks verkapte drogreden van de compatibiliteit appelleert onomwonden aan de geborgenheid van de middelmatigheid.

Het is evenwel de functie van de Universiteit —bij uitstek de functie van de Universiteit, mag ik wel zeggen— om in een maatschappij niet achter de ont- wikkeling aan te hollen maat in plaats daarvan baanbrekend deze ontwikkeling te anticiperen en te sturen. De opvatting dat deze universitaire plicht zich niet zou uitstrekken tot “het rekencentrum dat immers alleen maar diensten hoeft te verlenen” is een grove misvatting.

E.W.Dijkstra

transcribed by Bart Vreugdenhil
revised 26-Dec-2011

  EWD 272

Verslag van de tweede "Conference on Software Engineering", georganiseerd door de NATO Science Committee te Rome, 27–31 oktober 1969.

Terwijl de eerste "Conference on Software Engineering", die vorig jaar oktober te Garmisch werd gehouden, een van de opwindendste conferenties is geweest die ik ooit heb meegemaakt, was deze een vijfdaagse marteling. Vorig jaar waren de deelnemers door de bank genomen zo hoog in hun plaatselijke hierarchie, dat ze zich konden permiteren om eerlijk te zijn en de conferentie niet nodig hadden om erkenning te zoeken; dit keer kwam het merendeel niet om te luisteren, maar om iets te verkopen. Dat lag niet alleen aan de mensen: vorig jaar werd de omvang van de "software failure" onverbloemd aan het licht gebracht, deze conferentie was gewijd aan "wat doen we er nu aan"; terwijl vorig jaar "negatief" was geweest, moest het dit jaar "positief" zijn. Maar het is natuurlijk een beetje moeilijk om met geneesmiddelen voor een ziekte aan te komen dragen, waarvan je de symptomen gezien hebt maar waarvan je nog geen diagnose gesteld hebt. Het geheel had dan ook weg van kwakzalverij. Wat aangedragen werd of voorgesteld werd om te ontwikkelen waren allemaal van hetzelfde soort lapmiddelen, waarvan de ontoereikendheid in de jaren achter ons overtuigend is aangetoond, maar het merendeel der deelnemers was ditmaal niet in staat om dit te erkennen en bleef zorgvuldig als kat om de hete brij heenlopen. Heel ras werd de discussie beheerst door de vruchteloze en vulgaire tegenstelling "theorie" en "praktijk". John Buxton heeft nog een dappere poging gedaan dit te doorbreken door een keer te beginnen met zoiets als: "recently I changed, as some of you may know, the ivory tower of industry for the sordid battle field of pure science..." maar het mocht niet baten.

Wat mij het meeste heeft getroffen was een sfeer van totale verlamming. Er werd cijfermateriaal aangedragen om aan te tonen dat "debugging and testing" allang meer dan vijftig procent van de kosten uitmaken en dat ze ontoereikend zijn om de fouten er uit te halen. Dus was er veel belangstelling voor "debugging aids", maar nauwelijks voor de vraag, waar de bugs vandaan kwamen.

Iedereen was het er over eens, dat bij de "Chinese Army Approach" ontstellende communicatiemoeilijkheden optreden en mensen langs elkaar gaan werken. Dus was er veel belangstelling voor automatisering van deze communicatie, maar nauwelijks voor de vraag of je het inzetten van zulke horden ook kunt omzeilen.

De verlamming werd manifest bij uitspraken "ach, eigenlijk is het goed genoeg, het hoeft niet beter: de aandelen IBM stijgen toch? En bovendien, je moet het groot zien: een software systeem is altijd ingebed in een groter geheel en daar worden ook fouten gemaakt" etc. Ik heb geregeld moeten denken aan een zin uit de kritiek uit Time op "the Organization Man" van William H. Whyte: "Is ours the society to be gouverned by the mediocrity of business method?".

Bij de extreme theoretici vond ik soortgelijke verlammingsverschijnselen, door formele vooroordelen: die waren als medici die weigerden om een aspirinetje tegen hoofdpijn voor te schrijven, zolang ze het elixir voor de eeuwige jeugd nog niet hadden.

Bah, bah, bah, driewerf bah!

Edsger W. Dijkstra

transcribed by Jeanine Daems
revised Wed, 17 Jan 2007

EWD 273

The Programming Task Considered as an Intellectual Challenge

Edsger W. Dijkstra

In contrast to my original intention to address you without the use of written notes, I have decided to read the text to you verbatim as it now lies before my very eyes. The chosen procedure often leads to a less lively, if not even soporific, performance; I can only express my hope that the duller presentation of my talk is somewhat compensated for by its contents ..... in one way or another. I feel it my duty and pleasure to warn you that this time I shall make full use of the traditional prerogative of the speaker, viz. to say what he wants to say, rather than to tell what his audience might want to hear. I am well aware of the fact that in consequence of this decision I might never be invited again, but if that would be for the loss or benefit of our confession is not for me to judge .....

Let me now mention and describe to you the experience which led to my decision to address you in the manner just announced. It was the second "Conference on Software Engineering", sponsored by the NATO Science Committee and held in Rome during the last week of October 1969. Had I been brought up in the tradition of the British understatement, I would probably have described that conference as "not completely successful"; now, however, the first expressions coming into my mind to describe, are rather "an utterly miserable affair" or "a wet mess".

In one respect, I am afraid, it was an honest conference: its sorry state may have been a true reflection of the present state of the art of software engineering as generally understood and practised. But before trying to trace possible origins of this sorry state of affairs, let me tell you what happened at the last day of the conference. After that, you can judge for yourself. The incident has been witnessed by some ten or twenty people.

Around five o'clock, just before the closing of the conference, I saw a pile of reproduced notes written by one of the participants, who handed a copy to me when he saw that I showed some signs of interest. Standing next to him I started to scan his notes, only to see to my horror that also this document, alas, contained nothing more meaningful than the pompous, superficial bla-bla-bla that we had been exposed to all through the week. My disgust got the better of me, I was seduced to rudeness and after one and a half page I put the paper back on the pile and turned myself, without any further comments, away from its author. End of the first act of this drama.

When the curtain rises for the second act it is four hours later, nine o'clock in the evening. Guilt about my rude behaviour is gnawing at my mind and to relieve it I pick the paper up again to reread it; this time I start at the end, planning to read it backwards. Then, at last, my eyes are opened: the paper has carefully worked towards a climax and this last sentence is glorious and superb nonsense. I suddenly discover that I had nearly been fooled by an elaborate leg pull: it was a parody, it was satire, produced by a kindred spirit! Full of excitement I show the document (that very few had seen) to the remaining participants that were still in the hotel: then people are reading it, smiling, chuckling or roaring with laughter, according to their temperament. But some don't laugh at all because they don't believe that it is satirical. In the argument that follows, the question "Is this a joke or is this serious?" remains unanswered and leaves the group divided into two camps. End of second act.

In the third act the author, who had been absent during the second act, returns and tells that this document had not been written as a parody, that he had recorded the conference as he had seen it. End of drama.

My conclusion is that when a number of people who are recognized as knowledgeable in the field cannot settle among themselves whether an apparently professional paper is serious or not, that this is alarming, that the present state of the art is indeed a sorry state of the art.

Another unmistakable symptom of the conference's misery was that some people, in reaction to it, changed their air line reservations and left before the conference had run to completion. I myself would have done so, if such a change of schedule would not have caused inconveniences to some other private arrangements I happened to have made.

I hope that the above will be accepted as a proper documentation for establishing, even beyond the mildest doubts, the existence of the misery. If I left it at that, I would indeed do a poor job, so my next step will be a somewhat closer scrutiny of the symptoms of the illness in order to see whether we can find at least some of its causes.

The most obvious symptom of the misery was that most of the discussion was dragged into the vulgar, but nonetheless rather fruitless controversy between "theory" and "practice". I know, and of course all of us know, that the qualifications "Theoretical" and "Practical" with exclusion of the other are applicable to quite a large percentage of the workers in the field. There are people who refuse to have anything to do with practical applications. There is the story of the man who was preparing his PhD Thesis under Hardy and the subject had to do with Fourier integrals; one day he was so reckless as to mention to Hardy that some people really used Fourier integrals, upon which Hardy answered that under those circumstances the man had to look for another subject. At the other side of the deplorable fence we have those that have given up hope of ever finding anything useful in the work of their more theoretically inclined colleagues; and of course, quite a lot of it is utterly useless. Although the distinction between "theoretical" and "practical" people may be applicable to, say, 95 percent of the workers in the field and the distinction can therefore be regarded as statistically significant, yet I call it fruitless, because it leaves no room for exploring what benefits could be derived from the remaining five percent, i.e. those people and those activities for which neither the qualification "untheoretical" nor the qualification "unpractical" can be justified. To ignore those five percents is a simplification of thought which throws away the child with the bathwater, and that is why I call the distinction vulgar and fruitless.

To attack the fence in another way: I am employed by a Technological University and educational product of my department gets the title of "Mathematical Engineer". I have often observed that many, in particular Americans, start laughing when they hear that title: it strikes them as a contradictio in terminis, for by definition they regard the engineer as useful and the mathematician as useless. I speak from another cultural tradition — otherwise I would not have undertaken my job. This implies that I get extremely suspicious when the engineer justifies adhoccery by an appeal to the presumed law of nature, summarized by "quick and dirty", for from my experience and from my understanding I feel that "quick and elegant" is a much more likely combination. I get suspicious when the mathematician regards the formality of approach as a holy goal all by itself, rather than as a profane means which might be useful (and occaisionally even vitally effective). Roughly speaking, a formal treatment is related to my power of understanding as an attorney's act to my sense of justice.

From now onwards I refuse to make that vulgar distinction, I hope that I have made my position quite clear and that I have given everyone his equal share and, by the way, I am vaguely wondering whether I have turned the 95 percent into my friends or my foes .....

OK, that was my introduction. Let me now start the lecture proper.

The starting point of my considerations is to be found at the "software failure". One or two years ago the wide-spread existence of this regrettable phenomenon has been established beyond doubt; as far as my information tells me, the software failure is still there as vigorous as ever and its effects are sufficiently alarming to justify our concern and attention. What, however, is it?

Depending on the specific instance of failure one chooses, it can be described in many, many ways. One of the most common forms starts with an exciting software project, but as it proceeds, deadlines are violated and what started as a fascinating thriller slowly turns into a drama, to be played by an ever-increasing number of actors, the majority of which know perhaps their own part but have certainly lost their grasp on the meaning of the performance as a whole. At last the curtain falls, only because it is too late to go on any more, but not because anything has really been completed, for the final piece of software is still full of bugs and will remain so for the rest of its days. There are other forms, but they all have in common, that it turns out to be very, very difficult to get the whole program working with an acceptable degree of reliability.

When we try to explain the present as the natural outcome of the recent past, we get a better understanding of what has happened. In the past ten, fifteen years, the power of commonly available computers has increased by a factor of a thousand. The ambition of society to apply these wonderful pieces of equipment has grown in proportion and the poor programmer, with his duties in this field of tension between equipment and goals, finds his task exploded in size, scope and sophistication. And the poor programmer just has not caught up. Looking backwards, we must conclude that the difficulty of the tasks ahead have been grossly underestimated in the past. Extrapolations concerning the numbers and power of computers to be installed have been made, but society's preparation for this oncoming wave of machinery has been the call for more and more programmers, rather than for more capable ones, who could derive their greater capability from a better understanding of the nature of the programming task.

How little the general programmer's attitude towards his work has changed during this period can be demonstrated in a variety of ways. During that NATO conference in Rome a number of debugging aids were discussed; it was then remarked by one of the participants that all the techniques mentioned were already known and used fifteen years ago, a statement that no one did deny! Secondly, the advent of higher level languages has been hailed as a tremendous step forward. OK, but is it sufficient? It enables us perhaps to cope with a factor 10 in scope, but not with a factor 1000. In the old days, programs of one or two thousand assembly code instructions were horrors, but in the mean time higher level language programmers produce — admittedly — larger programs of exactly the same degree of unreadability and unreliability, in which the role of the old machine-code tricks has been taken over by cunning higher level language tricks. Truly, I cannot see the difference ..... The conclusion is that, in spite of the factor thousand in scope, present day programming tries to solve its problems essentially with the same old methods. And therefore, if we want to improve matters, we should make it our serious business to minimize the usage of what is now by far our scarcest resource, viz. brainpower. The burning question is "Can we get a better understanding of the nature of the programming task, so that by virtue of this better understanding, programming becomes an order of magnitude easier, so that our ability to compose reliable programs is increased by a similar order of magnitude?"

The fact that program reliability becomes a key issue is not only shown to us by the evidence around use, it is also quite easy to see why. A very large program is, by necessity, composed from a large number, say N, individual components and the fact that N is large implies that the individual program components must be produced with a very high confidence level. If, for each individual component the probability of being right equals p, for the whole program the probability P of being right will satisfy

P ≤ pN

and if we want P to differ appreciably from zero, p must be very close to one, because N is so large.

A common approach to get a program correct is called "debugging" and when the most patent bugs have been found and removed one tries to raise the confidence level further by subjecting the piece of program to numerous test cases. From the failures around us we can derive ample evidence that this approach is inadequate. Believe it or not, but it has been suggested (at that very NATO conference in Rome) that what we really need now are "automatic test case generators" by which pieces of program to be validated can be exercised still more extensively. But will this really help? I don't think so.

When faced with a mechanism — be it hardware or software — one can ask oneself "How can I convince myself of its being correct?" As long as we regard the mechanism as a black box, the only thing we can do is to subject the mechanism to all possible inputs, all the time checking whether it produces the correct outputs. But for the kind of mechanisms we are considering this is absolutely out of the question, even for the fastest and simplest mechanisms. At my University we have a machine with a fixed point multiplier taking considerably less than 100 microseconds per multiplication. The total time taken by all possible multiplication, however, will exceed 30000 years. And that is only a multiplier! The number of cases one can try in practice is a negligable fraction of the total number of possible cases and whole classes of in some critical cases can be missed. The first moral of this story is that program testing can be used very effectively to show the presence of bugs, but never to show their absence.

But as long as we regard the mechanism as a black box, testing is the only thing we can do. The conclusion is that we cannot afford to regard the mechanism as a black box, i.e. we have to take its internal structure into account. One studies its internal structure and on account of this analysis one convinces oneself that if such and such cases work "all others must work as well". That is, the internal structure is exploited to reduce the number of still necessary testcases, for all the other ones (the vast majority) one tries to convince oneself by reasoning, the only problem being that the necessary amount of reasoning often becomes excessive.

This function of the mechanism's internal structure opens a new way to attack the reliability problem. Once we have seen that the confidence level can only be reached by virtue of the structure of the program, that the extent to which the program correctness can be established is not purely a function of its external specifications and behaviour, but depends critically upon its internal structure, then we can invert the question and ask ourselves "What forms of program structuring can we find, what elements of programming style and what forms of discipline, all for the benefit of the confidence level of our final product?"

Instead of trying to devise methods to establish the correctness of arbitrary, given programs, I am now looking for the subclass of "intellectually manageable programs", which can be understood and for which we can justify our belief in their proper operation under all circumstances without excessive amounts of reasoning. This is done in order to reduce the number of testcases needed; in the case of software I see no reason at all, why this approach could not be so effective that the number of testcases is eventually reduced to zero, i.e. that correctness can be shown a priori. Already now, debugging strikes me as putting the cart before the horse: instead of looking for more elaborate debugging aids, I would rather try to identify and to remove the more productive bug-generators!

In short, I suggest that the programmer should continue to understand what he is doing, that his growing product firmly remain within his intellectual grip. It is my sad experience that this suggestion is repulsive to the average experienced programmer, who clearly derives a major part of his professional excitement from not quite understanding what he is doing. In this streamlined age, one of our most undernourished psychological needs is the craving for Black Magic and apparently the automatic computer can satisfy this need for the professional software engineer, who is secretly enthralled by the gigcantic risks he takes in his daring irresponsibility. For his frustrations I have no remedy .....

Looking for "intellectually manageable" program structures one is immediately faced with the question "But how do we manage complex structures intellectually? What mental aids do we have, what patterns of thought are efficient? What are the intrinsic limitations of the human mind that we had better respect?" Without knowledge and experience, such questions would be hard to answer, but luckily enough our culture harbours, with a tradition of centuries, an intellectual discipline whose main purpose it is to apply efficient structuring to otherwise intellectually unmanageable complexity. This discipline is called "Mathematics". If we take the existence of the impressive body of Mathematics as the experimental evidence for the opinion that for the human mind the mathematical method is indeed, the most effective way to come to grips with complexity, we have no choice any longer: we should reshape our field of programming in such a way that their methods of understanding become equally applicable, for there are no other means. As an aside, I would like to point out that you cannot put aside my recommendation by saying "Oh gosh, yet another mathematician trying to sell the importance and universal applicability of his subject," because I happen not to be trained as a mathematician; I consider myself to be a programmer ..... But I have been asking myself for, say, the last two years, what kind of programs I would care to produce if I wanted to exploit my powers of abstraction for the purpose of understanding as effectively as is done in any other field of mathematics. In particular I have been investigating how one can use one's power of abstraction and one's ability to introduce concepts in order to achieve that. The number of cases between which is to be distinguished in one's reasoning, combine additively rather than multiplicatively. I would like to use the next part of my lecture to give you in bird's eye view a survey of my conclusions.

1)     When programming, one should constantly bear in mind that although the program text is the last thing that leaves the programmer's hands, the true subject matter of his trade consists of the possible computations that may be evoked by his commands, the computations, the "making" of which he delegates to the machine. When we say, sloppily, that a program is OK, we mean that the corresponding computations satisfy the requirements. In other words, we should regard the programmer's activity not as "producing programs", but rather as "designing a large class of computations". The obligation to keep our intellectual grip on what may happen in time, while the static program text is the last thing we can lay our hands upon, the obligation to understand the computations as they evolve in time via the tangible program text, yields an urgent plea to keep the sequencing rules, i.e. the mapping between the progress through the program text and the progress through the computation, as straightforward as possible. As a result I decided to abstain in sequential programming from the goto statement and to perform all sequencing control by conditional, alternative and repetitive clauses and the subroutine mechanisms. In view of our obligation to bridge mentally the conceptual gap between the static program text and the dynamic computations, I came identify the goto statement as one of the combinatorial complexity generators I was looking for.

2)     Another conclusion especially related to sequencing is the following. Whenever a construction is composed by means of a sequencing clause, encapsule it and find a description of its net effect in which the fact that it contains a clause is no longer transparent. If to write

"if x < 0 then x := -x"

this means "replace x by its absolute value" and the latter description is equally applicable to both cases. And if you have not a ready-made function (such as the absolute value) at your disposal in terms of which to describe the net effect of such a compound statement, invent this function and be sure that its properties are nice and also the ones you want. If you cannot find such a function, don't ignore that warning, for then you are on the verge of messing things up. To give you an analogy: when programming in machine code you can appeal to the add-instruction but in doing so it is immaterial for you whether the hardware invoked has a serial or a parallel adder.

3)     The above encapsulation of the internal structure of a program component is a specific instance of a more general principle, that we find applied in the structure of any mathematical theory: whenever a piece of mathematical reasoning appeals to a theorem, the only thing that matters on that level is what the theorem asserts and on that level it is equally immaterial how that theorem has been proved (elsewhere). An appeal to a theorem is not an abbreviation for a specific one of its possible proofs, the existence of the theorem as such allows the user to forget about its proof. We can — and should — apply the same principle in program composition, where it is rewarding to separate for each program component clearly "what it does" and "how it works". With the possible exception of the recursive routine, the level in which a component is used on account of what it does is always disjoint from the level which is concerned with how it works. These two sides of the same coin are very well known in the relation between main program and the subroutines it calls; our vision of this relation, however, becomes blurred as soon as we regard the calling sequence as an abbreviation of the body and as a result, try to understand the local activity at the same, homogeneous semantic level; one has then mentally destroyed a useful structure. This widespread confusion, I am sorry to say, seems to have been promoted and to be kept alive by Programming Linguistics, as inspired by Automata Theory.

4)     Was the previous point that it is unwise to take the internal structure of a program component into account on the level where it is used on account of what it does, this point makes the same statement with respect to compound data structures, which are ultimately represented by aggregates of variables of more primitive types. The levels in which only the collection of the possible values matter is quite distinct from the level which is concerned with the question how these composite values can be represented by aggregates of values of simpler types. One of the most common sources of program errors seems to be that an operation on a variable is inadvertently coded in terms of components of a specific representation. To give again a very simple example: for a binary machine one may be tempted to replace the question "is this integer even?" by "is its least significant digit zero?". Later, going with the program from one binary machine to another one discovers that this translation is not valid when negative numbers are represented by 1's complements. With the subroutine we have the two sides of the operational coin, viz. "what does it do for you" versus "how does it"; with abstract data types we have the two sides of the representational coin, viz. "what values can it take" versus "how are these values represented". Most current programming languages cater via the subroutine mechanism reasonably well for the operational abstraction but their mechanisms for representational abstraction, if any, are less convincing. The possibility to have representational abstraction reflected in the program code seems, however, equally essential.

5)     A program should be regarded not as an object all by itself but as a member of a class of related programs, containing both alternative programs for the same job and similar programs for similar jobs. We wish to regard transition from one member of this class to another member of this class as replacing one or more program modules by one or more alternative program modules. Hereby insisting that the correctness proof for the unaffected modules and their interrelationship remains unaffected as well. The analysis of the latter requirement gave me a very much clearer understanding of how different levels of abstraction can be distinguished in a large program and how the distinction between these various levels of abstraction can be used to good advantage, and it enabled me to give a reasonably specific contents to the goal of "program modularity", which is often hardly more than a motherhood statement. Specific consequences of this analysis have been
5a)     a proper module is in general more than a subroutine: in its general form it reflects — or "documents", if you wish — all consequences of a locally independent design decision, in general involving a set of joint representational and operational refinements;
5b)     the adequacy of context-free methods for representing program structure seems to have been over-estimated.

So far for the survey of the conclusions I reached when I tried to reshape our programming activity into one which is better adapted to our mental capacities and limitations. I could only give you a bird's eye view of them; yet I hope that you have grasped some of their flavour and, possibly even, some concrete guidance. The survey is by no means complete, other insights will follow, perhaps as the fruits of my own activity but hopefully they will be gained by others as well.

Although I have done my best to be as clear as possible, I fear that I must have failed to reach anyone in my audience — if any — who, on account of his current environment, identifies the task of programming with the task of writing programs in FORTRAN — a programming tool which, indeed, was a great step forward when it was conceived some fifteen years ago but which, by now, should be regarded as a lower level language, as a low grade coding device. If he sticks to that conception of his task, he will fail to understand me, as one of my morals is that in the mean time his programming tool and the thinking habits induced by, have grown hopelessly inadequate. This fear of being misunderstood is, alas, supported by many a disappointing experience. As a teacher it is my job to help programmers in clearing up their own thinking. Often this is a highly rewarding activity, equally delightful and instructive for both parties. But when talking to the produce as grown in what is getting known as "the pure FORTRAN environment", I am usually baffled, for unsuspected depths of misunderstanding open themselves before my very eyes. It is well known that we don't gain automatically from every experience, on the contrary, that the wrong experience may easily corrupt the soundness of our judgement. In the case of FORTRAN, it is my impression that its intellectually degrading influence is not commonly recognized, that too few people realize that the sooner we can forget that it ever existed, the better, as it is now too inadequate, too difficult, and therefore too expensive and too risky to use.

In connection to the preceding paragraph about FORTRAN I would like to give a short explanation of my silence about COBOL. The point is that I have neither first-hand nor second-hand experience with COBOL's influence on its users. But the preceding paragraph was misunderstood by one of my colleagues who came from the mixed FORTRAN - COBOL environment: he was terribly puzzled, saying "Why attack FORTRAN's influence? For COBOL's influence is an order of magnitude worse!" End of explanation.

Meine verehrte Hörer und Hörerinnen — this had to be said in German as my English does not cater for this! — let me come to my final conclusions. Automatic computers are with us for twenty years and in the course of that period of time they have proved to be extremely flexible and powerful tools, the usage of which seem to be changing the face of the earth (and the moon, for that matter!). In spite of their tremendous influence on nearly every activity, whenever they are called to assist, it is my considered opinion that we underestimate the computer's significance for our culture as long as we only view them in their capacity of tools that can be used. In the long run that may turn out to be but a ripple on the surface of our culture. They have taught us much more: they have taught us that programming any non-trivial performance is really very difficult and I expect a much more profound influence from the the advent of the automatic computer in its capacity of a formidable intellectual challenge which is unequalled in the history of mankind. This opinion is meant as a very practical remark, for it means that unless the scope of this challenge is realized, unless we admit that the tasks ahead are so difficult that even the best of tools and methods will be hardly sufficient, the software failure will remain with us. We may continue to think that programming is not essentially difficult, that it can be done by accurate morons, provided you have enough of them, but then we continue to fool ourselves and no one can do so for a long time unpunished.

Finally: from my words some of you may have concluded that I am just spiteful and bitter. Let me reassure you: I am neither spiteful, nor bitter. Not yet ..... although I must admit that the major part of computing science (or perhaps more accurately: Programming Folklore) often strikes me as unchallenged prejudices, repeated over and over again as articles of faith. But in my introduction I have announced that I should say what I wanted to say. I know that I have used strong language and harsh words — but the time to be gentle has passed: the situation is much too serious to be covered by politeness.

The floor is now open for discussion and I thank you for your patience.

Eindhoven, dec. 1969.

Transcribed by Daniel C McCarthy.
Revised Mon, 17 Dec 2007.

EWD275

Structure of an extendable operating system.

For an operating system of the scope and purpose as the THE-multiprogramming system, the conception of a linearly ordered hierarchy of layers has proved to be unsurpassed sofar: instead of "complexity growing as the square of the number of system components" (Aron), each next layer is easier to add, because the environment in which it is to be understood is closer to our "ideal machine", i.e. our final goal. Knowing of no alternative arrangement with that pleasant property —and stronger: finding the existence of such an alternative hard to conceive!— I take the linearly ordered structure as my starting point.

In two vital respects, however, its structure calls for generalization.
1)     The THE-system has been designed to bridge a pre-defined, constant gap, i.e. the gap between the given hardware (an EL-X8 with given types of peripherals and backing store) and a given target, i.e. five parallel ALGOL-machines. Construction of the system and use of the system were, at that time, viewed as completely different activities, different in nature and taking place at different times. In the mean time, I regard the intermediate product, consisting of the hardware, covered by a few of the lower layers, as " a system" with its own right of existence and I regard the activity of adding a next layer no longer so radically different from what a user does when he feeds his ALGOL-program into the completed system. In other words, I would like to treat wherever possible, system embellishment and system usage as much as possible on the same footing. In this case, the natural extension of a fixed set of layers becomes a stack of layers.
2)     The target machine of the THE-system is not only constant in time, it is also homogeneous in the sense that we produce a set of equivalent ALGOL-machines. (In actual fact, one of the five is slightly special purpose, but that is irrelevant in this discussion.) We wish to create in parallel different environments. The obvious generalization of the stack of layers —corresponding to strictly nested environments— is a tree of layers. And if I were to design an operating system, I would do my utmost best to conceive it in such a fashion, that I can recognize such a tree structure, and this for two compelling reasons: as just shown, a tree structure is the very least we can hope to come out with, on the other hand it is my repeated experience that a tree-structure is about the most complicated structure of hierarchical nature that I can cope with. I don't feel like having a choice anymore.

Note. My above use of "parallel" refers to conceptual parallellism, or "independence", not to parallel execution in time of a number of sequential processes: what is regarded as a single layer, may contain a number of co-operating sequential processes! (The function of such a layer is to transform one machine into another: both source- and target-machine may contain asynchronous elements!)

I have given much thought —not all of it conclusive— to the question what abstraction from the hardware should be implemented in what layer. In particular I have been thinking of the question whether the bottom layer should implement the sequential processes and the next one the virtual store (as in the THE-system) or the other way round. The argument for the THE-arrangement was that the implementation of the virtual storage required —or at least could make good use of— a sequential process (the so-called "segment controller") synchronized with the drum interrupts. lf we take as a backing store a device with such a high transfer rate that demand paging is no longer a motivation for change in processor allocation, that argument is no longer valid. Yet I am inclined to try to put processor allocation as low as possible, because above that level, the interrupts have disappeared and the sooner that is achieved, the better. In the THE-system processor allocation at level zero is easy, because the number of processes is constant and the relevant information is kept resident in core. In an extendable operating system, however, the total number of processes (and semaphores or what you have) will vary in time and fixed allocation in core seems out of the question. My present idea is to look for a mixture: layer zero (and this may be in the hardware) will contain the access mechanisms for virtually addressed information "provided it is in core". Layer one will contain processor allocation, described in terms of virtual addresses, whereas the next layer will be storage allocation, which has the duty never to remove (but possibly to move in core) information pertaining to level one. As a result, level one will hardly make fixed core committments, yet will never produce a page fault.

Note. The concept of a virtual store is not restricted to multilevel storage machines. Also on a machine with a single level storage it is conceivable that virtual store is a very useful concept. In the latter case. level two would restrict its activity to rearrangement of the core store contents.

The function of a layer in the THE-system is to provide some facilities in terms of some others. Take for instance the layer in which peripherals are allocated. Below this layer we have unbuffered physical peripherals, above it we have information streams, i.e. buffered virtual peripherals. Above that layer a maintenance engineer has no longer the possibility to introduce a program for the unbuffered exercising of a specific peropheral, for it "is no longer there". If we wish to create that facility, one of the peripherals should be taken out of the common pool serving the virtual units and suddenly we have two environments: one environment for programs referring to virtual units (to be served by the remaining physical units) and one for the maintenance engineer. In a situation like that I see the first traces of a tree of environments emerging (environment is here used as "interface between software layers").

1)     the environment with the physical, unbuffered peripherals
2)     the environment with the specific unbuffered peripheral retained, plus virtual peripherals (to be served by the pool of the remaining physical peripherals)
3a)     for the users the environment of the virtual units
3b)     for the maintenance engineer the environment of the specific unit. (This example may be too simple: in practice, the maintenance engineer will probably use the remaining virtual units as well. OK, then we have the identity transformation —probably implemented by an empty layer— between 2 and 3b.)

A layer performs the transition from one environment to an environment on top of it. A translator has the function to produce such a layer. (In the THE-system we have at the users disposal an ALGOL-environment: when his program has been translated he has temporarily added a new layer, which provides the environment in which his data can be "interpreted"). This implies that a translator can only work when the environment, which serves as the "underface" of the layer it has to produce, is known, i.e. for its activation we must give "the underface" as a parameter. For a variety of reasons I am strongly inclined to relate this "underface parameter" very closely to the environment from which the translator is called. Traditional ALGOL-translators supply the environment of the Library as a constant presetting of (the bottom of) the name stack, as if the library has been declared in an (implicitly embracing) outer block. I would like to repeat this arrangement for inner blocks: a translator first translates the outermost block, thereby creating the environment in which the next set of inner blocks are to be understood. Then —and this closely resembles the start of the execution of the declarative part of the outermost block— the translator is called again for the translation of the procedures declared in the outermost block; these translator calls will get the newly created environment as the underface parameter. Here we have an arrangement in which the creation of a next layer can be considered as an activity to be understood in the environment which equally serves as the underface for the level to be created and this repeatedly. It is essential that the new environment can again accept programs. It is by such means that I should like to achieve that "building up and tayloring" of the system is not essentially different from using the system, that I hope to treat "job control language" and normal programming language on exactly the same footing.

Acknowledgements are due to Harry Whitfield, Edinburgh University, whose experience with software design for an ICL745 (a 360/67 type machine) had made him think of more attractive alternatives.

november 1969 | Edsger W.Dijkstra

transcribed by Hans Terlouw
revised Thu, 24 Dec 2009

EWD 278

Organisatie van onderzoek en onderwijs van Fundamentele Programmering.

1.     Uitgangspunt is de opvatting dat de opgave grote (klassen van) informatieverwerkende systemen (100.000 tot 1.000.000 opdrachten) beheers te ontwerpen en betrouwbaar te maken, primair een formidabele intellectuele uitdaging is, die in een aantal opzichten zonder precedent is.

1.1. “The mathematical basis of programming is very simple —misleadingly simple in fact.” (Stanley Gill.) De basis is zo simpel dat intellectuele beheersing denkbaar is tot een veel hogere graad van volledigheid dan in vele andere wetenschappen.

1.2. Omvang, snelheid en betrouwbaarheid van moderne apparatuur zijn zo duizelingwekkend, dat de programma’s, die nu realistisch uitgevoerd kunnen worden, qua “sophisticatian” hun triviale grondslag zo in de letterlijke zin “onvoorstelbaar” ver zijn ontstegen, dat alle onderschatting van de formidabiliteit van de intellectuele uitdaging een in het verleden gewortelde naiviteit lijkt.

2.     Doel van het onderzoek en onderwijs van Fundamentele Programmering zijn daarom het ontwikkelen en overdragen van denktechnieken, waarvan wij op goede gronden verwachten mogen, dat zij ons beter tegen de geschilderde uitdaging opgewassen maken, benevens het ontwikkelen van en vertrouwd maken met “a programming environment” waarin genoemde denktechnieken zo direct mogelijk zowel gebruikt als bruikbaar zijn.

3.     Onmiddellijk rijst de vraag met wat voor personeel een dergelijk project bemand zou moeten worden. Het lijkt vrij duidelijk, dat dit hoog gequalificeerd (of althans hoog qualificeerbaar) personeel moet zijn; op grond van vroegere ervaring en de steeds toenemende zuigkracht van buiten lijkt het een illusie te hopen, dat een dergelijk project met “blijvertjes” bemand kan worden; dit kan de THE nooit betalen. De THE kan ze alleen betalen als ze jong en nog onervaren zijn; mijn hoop is dies gevestigd op een paar uitnemende studentassistenten, afstudeerders en een of twee afgestudeerde wetenschappelijke assistenten, die nog wel een paar jaar willen blijven.

Naast deze practische overweging wijst ook de aard van het werk naar jeugdig personeel: er zal immers geen groot beroep gedaan hoeven te worden op brede kennis noch ervaring. (Zij dienen niet in het algemene basis-onderwijs betrokken te worden!) Het zal er veeleer op neerkomen of ik hen het vereiste vermogen tot abstraheren kan bijbrengen, of zij de quintessence van een (geestelijke en practische) discipline kunnen zien en zich er naar kunnen gedragen.

Het lijkt ook duidelijk dat mijn gedachten uitgaan naar een betrekkelijk klein aantal: ten eerste kan ik mijn gedachten niet in de ongetwijfeld vereiste intensiteit over een groot aantal mensen verdelen, ten tweede wordt bij toenemend aantal het gevaar dat de kern van het systeem te barok wordt, me veel te groot.

4.     Qua mechanische voorzieningen gaat mijn weloverwogen voorkeur uit naar een “dedicated machine”.

4.1.   In deze wereld worden rekenautomaten nog zo zeer beschouwd als duur gereedschap en niet als “materiegeworden uitdaging”, dat men ze alsmaar zo intensief mogelijk wil gebruiken voor iets anders. Deze economische pressie is zo groot, dat ik met alle waardering voor aangeboden bescherming van organisatorische aard, maar een enkele voldoend effectieve manier zie om de mechanische faciliteiten voldoende te beschermen: een “dedicated machine” die (bv. door de bewuste afwezigheid van compatibele software) anderszins onbruikbaar is.

4.2.   Mijn gedachten gaan uit naar een DEC-achtige machine: simpele opdrachtcode, maar heel snel met een behoorlijk omvangrijk primair geheugen en een heel groot secundair geheugen en simpele communicatieapparatuur (zeg ponsbandapparatuur, een paar teleprinters en een rustige regeldrukker). De bedoeling is om deze machine ijlings om te programmeren tot een machine met de primitiva waar ik op voort wil bouwen en vanaf dat moment de gegeven hardware code volslagen te vergeten. Als de electronica maar snel is kan ik me die interpretatieve vertraging wel veroorloven, terwijl de snelheidseisen ten aanzien van secundair geheugen verzacht worden. Een andere mogelijkheid is, dat er tegen die tijd realistisch microprogrammeerbare apparatuur op de markt is.

5.     Uit het voorafgaande is duidelijk, dat ik me heri richt tot programma’s, die in hun geheel niet in een achtermiddag of een maand te maken zijn, maar over programma’s van vele manjaren. Men kan hierover doceren, maar het soort object waarover men dan praat is zo “onvoorstelbaar” —daar zit nl. juist de kern van het probleem— dat de opleiding van op dit niveau competente programmeurs directere ervaring met “grootheid” vergt. Het ideale antwoord hierop is om in huis een dergelijk software project op poten te hebben, dat nadrukkelijk is opgezet om allerlei mensen op verschillend niveau aan te laten werken. Wat opgebouwd dient te worden is zoiets als een “extendable operating system”, dat qua hanteerbaarheid, documenteerbaarheid en begrijpelijkheid een orde van grootte beter ligt dan de huidige praktijk. De implicaties van deze eisen maken tegelijkertijd de hele onderneming tot een volwaardig onderzoekproject (waarover ik nog meer moet denken, voordat ik verantwoord een configuratie kan bestellen). Als het project de vruchten afwerpt die ik hoop —en waarvan ik niet zie, waarom ze niet haalbaar zouden zijn— zal het bij voortschrijdende sophistication steeds makkelijker worden om onervarenen er mee te laten spelen. Uiteindelijk kan het dan uitgroeien tot prakticumruimte voor het derdejaarscollege “Inleiding tot de kunst van het programmeren”.

november 1969 | Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 28-Nov-2011

  EWD 279

The programming laboratory project.

     The purpose of the project is twofold: to find the constituents of a better programming methodology and to apply them and try them out in the design and controlled growth of a large, sophisticated system.

      As target system I am envisaging a "programming laboratory", as I seem to need this for the education of software engineers. I regard programming primarily as an intellectual challenge and the full size and scope of this challenge only become manifest when we try to program something "large". But I cannot train future software engineers by only talking about large systems , for without first hand experience they cannot visualize, nor imagine what I am talking about. (This is precisely the programming problem: what happens inside the machine escapes our unaided imagination by several orders of magnitude!) The only way in which I can transmit what it feels like to partake in a many-man-year project is by letting them partake in it, be it only for a number of months perhaps. The advantage of the above target is its high demands on documentability, adaptability and extendibility; it is my firm intention to give quite specific contents to a concept of "modularity" —a term which is often used as a motherhood statement— and expect the stated goals to force me to do so. Preliminary investigations, carried out during the last year or so, have convinced me that the design of an environment satisfying such requirements is not trivial; on the contrary, I have come to regard it as a worthy research object.

      The kind of hardware I am looking for is a simple, very fast machine, with a reasonably sized primary store, a very large backing store, a line printer, a few keyboard terminals and paper tape peripherals and perhaps a single magnetic tape unit for safety reasons. Up till now the following considerations have been taking into account.

      I am only too aware of the fact that I would never have been able to conceive the run time system for the X1 ALGOL 60 implementation if the X1 would have had built-in floating point arithmetic: if that had been the case I would have felt obliged to use it and the relative price of the system overhead would then have been excessive. That is the reason why I am looking for a piece of simple, straightforward but fast hardware: I intend to write in its machine code an interpreter for another machine, to do so once and then to forget the given hardware machine code. If the hardware machine is sufficiently fast, the resulting performance will remain acceptable for a laboratory environment, while it will mitigate the speed requirements for the backing store which must be very large. One reason is that at present the programmer regards (pre)documentation as an additional burden, among other causes because he cannot profit mechanically from it; one of the purposes of the reshaping the programming activity is to find methods by which what is now called "documentation about the program" functions as an integral part of the program. Secondly I would like to do away with the off-line preparation of paper tapes or cards as part of the activity of program composition. This points to having the complete system documentation inside the machine, as readable as source text.

      The keyboard terminals are viewed as "the programmer's desk". I need at least two of them, to create the environment of parallel interactions (extensions or modifications) with the same program, perhaps an "operators console" in addition to that. If the laboratory grows towards an environment in which larger numbers of students can get experience, more might be needed for reasons of more intense usage of the system.

      My guess is that, particularly in the beginning, the main function of the line printer will be to act as a reproduction machine for the production of hard copies of (part of) the system information contained in the machine's storage. Readability of the printing will then be more important than extreme speed.

      The paper tape equipment is suggested as a means for getting started. I think that I would like to use the X8 ALGOL system to get off the ground. As the system grows, paper tape as back up system will be insufficient and a magnetic tape unit might come in handy-

*        *       *

      Since the above has been written, I have had two conversations in Erlangen, relevant to the project.

      One was with a number of people from Munich, one of which has been present at the NATO Conference in Rome in the last week of last October, where I had presented the quintessence and aim of the notion of "pearls". They were at that moment in the process of designing and implementing a tool for the construction of operating systems and could include at least a modest means catering for the "representation abstraction" as I had suggested. In Erlangen they showed me this with pride, joy and gratitude: they had already profited greatly from it. This was the second confirmation that the pearl concept seems to be a sound one (the first one came in a letter from Elliot Organick, but that was less elaborate).

      More directly concerned with the configuration was a discussion I had arranged with Horst Huenke from Bonn, concerning keyboard terminals. I have been hesitating for a long time whether I needed printing keyboard terminals (teleprinter or input/output writers) or keyboards with a character display tube. For lack of experience with the latter I have been thinking in terms of the first for the last few months. In answer to my inquiry, Horst have a strong plea for the terminals with character display tube. He warned me (himself) that his strong bias was undoubtedly also caused by
     1) his extreme sensitivity to noises
     2) the extremely poor input/output writer as coupled to an IBM 360.
But of out of the discussion came two arguments in favour of the display unit, both consequences of the fact that the human eye is so well adapted to ignoring what it is not interested in. The arguments were the following (the first one I had thought of, the second was new to me):
1) When one wishes to read something "in the system" —e.g. to look something up— typewriter speed is so painfully slow that one cannot ask for the "page" but must ask for the "line". This means that one must know the line and —if one indeed knows it— must also identify it via the keyboard. This is cumbersome.
2) Messages from the system must be more verbose for the novice than is needed for the expert. It is no solution to give your "degree of expertise" as this is not constant over the system: you may currently be an expert in one part but will no longer be one in a part which you have not been concerned with for a number of months. In view of the fact that in the course of the project I hope to have students joining it, this aspect of human communication should not be ignored. I am therefore aiming at character display terminals. As Horst pointed out "A line printer is then an absolute must!"

      So much for the configuration.

*        *       *

      A central theme of the project is the similarity between system usage and system construction. The THE system was designed to bridge a preset gap —viz. from the given hardware to the five ALGOL-machines. Construction and usage of the system were at that time viewed as completely different activities, different in nature, taking place at different times and to be done by different people. This preset gap gave birth to a system of a constant number of "layers". In the mean time I regard the intermediate product, consisting of the hardware, covered by a few of the lower layers, as "a system" with its own right of existence and I regard the activity of adding a next layer no longer so radically different from what a user does when he feeds in his ALGOL-program into the completed environment: by loading his program, he just creates a next environment, i.e. the environment in which his data are interpreted. The natural extension of the fixed set of layers of the THE system is a stack of layers, provided that we can add a layer which, in its turn, again can accept (manipulate and activate) a program, i.e. the next layer.

     A closer scrutiny reveals that "a stack of layers" is insufficient, we need a tree, because different environments have to be created in parallel. (In actual fact, this tree-structure can already be distinguished in the THE system, where at the top, five different ALGOL-programs may be running.) As "two" is the minimal degree of non-empty parallelism, at least two terminals will be needed. I trust that the tree-structure will not only be a conceptual aid, but that it will also play an essential role in the virtual storage management: the fact that each activity, by definition, only requires the nested environments to be found on its path to the root of the tree and that activities in parallel branches are by definition conceptually independent, is too fundamental a property not to be exploited in a systematic manner.

*        *       *

      In our programming methodology we wish to do justice to the following points of view and observations.
1) A program should be regarded as the design of a large class of possible computations: these computations —the "making" of which is left to the machine— are the final product about which the programmer must make his assertions.
2) Correctness proofs are essential. Programming first and then testing is putting the cart before the horse, program testing can be used to show the presence of bugs, but never to show their absence. Program composition and demonstration of correctness are two activities that should be merged. (To quote A.G. Fraser: "I just want to make the point that reliability really is a design issue, in the sense that unless you are conscious of the need for reliability throughout the design, you might as well give up.")
3) The requirement that the correctness proofs can be given without undue amounts of intellectual labour calls for conscious exploitation of our powers of abstraction and a programming tool in the usage of which our abstractions can be suitably reflected.
4) A program should not be regarded as an object all by itself but as a member of a family of related programs, i.e. either alternative programs for the same task or similar programs for similar tasks; the function of the levels of abstraction is to indicate to what extent the different members of the faculty can be mapped on each other. We have to recognize the similarity between "the changed decision" and "the postponed decision".
5) The potentially large number of members of the program family considered requires that the correctness proofs are concerned with the family rather than with an individual member. This requirement gives a rather clear picture of the logical function of modularity; the programming tool has to allow (or even to invite) the corresponding "textual encapsulation".

*        *       *

      In programming practice today, much attention is paid to documentation and one hears an urgent plea for pre-documentation. One is in trouble, however, as long as pre-documentation (a flow-chart, for instance) is regarded as describing intentions, as documentation about what is going to do, as it calls for the painful verification that the pre-documentation is still applicable. Rather than to regard pre-documentation as "statements about the program to be made" I would like to regard and treat it as an integral part of the program itself, I want it therefore inside the machine, mechanically exerting its influence as much as possible. (And I want this "even at run time", provided that this remains a relevant concept: I want to come to grips with the problems that are presently described by "changing a program while it is running".)

      The desire to have different levels of abstraction not only reflected in the process of program composition but also recognizably reflected in the activities taking place during the course of the actual computations, will greatly affect the design. It is expected that this requirement will give a fresh appraisal of the operations which are presently covered by names such as assembly, linking, loading, binding etc. The desire to retain at run time more structural information can be expected to increase the demands made on primary storage (by a factor of two, say); this should be kept in mind while detailing the configuration.

      On of my first concerns will be to find "a binding policy" (or rather: the basic primitives that allow us to exercise a class of binding policies). For this purpose I need a clear view of the degrees of combinatorial freedom called for by my concepts of modularity. Secondly I need a clear view of the requirements made by a virtual storage implementation. In order to complicate matters further —I remind the reader that it was my honest intention to do something difficult— it has been suggested that I should consider two levels of backing store (say a fixed-head-disc as second level store and a movable-head-disc as third level store). If this suggestion is followed, I shall not begin by paying extensive attention to the choice of an "optimum" strategy for the use of second and third level store, I would begin by implementing a straightforward one, the major part of my concerns being absorbed by the requirement that the replacement of one strategy by another would not be a major operation. As this strategy has to be implemented rather low in the system, this could easily be a very difficult problem, i.e. the kind of problem I should like to tackle. As a by-product we would eventually have a system in which we can easily experiment with different multilevel backing store strategies.

*        *       *

      I should like to add some comments on my attitude towards "efficiency". To start with: I do optimize, but not purely on the usage of the mechanical resources, I do optimize, however, on "brainpower" because I regard that already now as our scarcest resource; with more and more powerful machines becoming more and more generally available, I expect that, in the years to come, brainpower will become still more markedly the bottle neck. It is for this reason that I am quite keen on program manageability, i.e. the ease with which we can effectuate the transition from one version to another — and such a transition might be desired for the sake of "mechanical efficiency". For certain design decisions —the hard ones!— it is vain to hope that one can postpone them or, when taken, can isolate their consequences; there will be rather basic decisions that will not allow to be changed at a later stage without overthrowing everything built on top of them. This is one of the undeniable facts of life. Here the only principle available is "minimum likelihood of regret". From the past I know that in such cases I shall prefer the solution, the performance of which is the least sensitive to the future way of usage: I would rather decide to pay a constant price, "4", say, than the variable price "N" if keeping N low would impose an awkward burden on the programmer's shoulder or would impose too tough a scheduling task on the system (and its user population, for that matter!).

*        *       *

      If industrial support for this project is offered, it should be seriously considered, particularly because the hardware needed is likely to have financial consequences which are somewhat unusual for the Department of Mathematics. Clerical complications that could follow from such a support should (in some way or another) be kept to a minimum; furthermore it should be made perfectly clear to the supporting industry that this research has to be carried out without any form of secrecy. Without the explicit permission to talk and to write about the project to anyone I see fit, I shall certainly be unable to carry it out.

*        *       *

transcribed by Andreas Jonsson
revised Mon, 11 Jul 2005

  EWD 281

Aan de Commissie Wetenschapsbeleid.

Er is iets in mijn omgeving op de TH, dat mij erg remt in plaats van inspireert, en ik zou er een lief ding voor geven wanneer ik dit onder woorden kon brengen zonder mijzelf te idealiseren —de vermoorde onschuld uithangen is natuurlijk altijd makkelijk— en zonder de mensen in mijn omgeving zelfs maar in schijn te "beschuldigen": ten eerste geloof ik, dat hen nauwelijks smet of blaam treft, ten tweede zou ik aan zo'n formulering zo weinig hebben, want op hen, aan wie ik hem zou willen uitleggen, zou hij averechts werken.

Ik bevind mij in de toestand dat wanneer ik een jaar hard zou werken en geprest door de omstandigheden een paar kogels door de kerk zou jagen —dwz. enige "choices of evils", die ik nu rustig uitstel, zou maken meer op een geloof in "minimum likelihood of regret" dan op grond van algemeen erkende decisiecriteria— er een gerede kans bestaat dat ik me voor een nieuw project klaar zou voelen, een project —en nou komt de moeilijkheid— dat aan materiele faciliteiten wel eens een investering van 1 of 2 milljoen zou kunnen vergen. En nu legt iedereen met meer financiele kennis dan ik bezit, mij uit, dat als ik over een of twee jaar milljoenen "nodig" heb, dat ik de aanvrage daarvan nu wel moet beginnen te "organiseren". En nu komen mijn problemen.

Ik voel me voor dit soort organiseren helemaal niet in de wieg gelegd, want ik weet maar al te goed, waar dit op neer komt: je intenties verdedigen op gronden die de ander relevant voorkomen en je technieken schilderen op een manier, zodat ze de ander adequaat voorkomen. Maar dit is nu precies wat ik niet wil, want het zou de gepatenteerde manier zijn om dit project bij voorbaat de grond in te boren: immers, ik zou me aan zo'n charter gebonden voelen (afgezien ervan, dat het opstellen van zo'n charter me een jaar zou kosten, een jaar, dat ik eigenlijk zou moeten besteden aan het opstellen van mijn echte intenties en het uitwerken van de technieken, die ik echt wil gebruiken).

De kloof tussen mijn vakgenoten, voor wie de quintessence van het vak grotendeels minimalisering van benodigde hardware en rekentijd is, en mij, die "brainpower" wil sparen, is zo groot, dat ik hem alleen maar schijnbaar kan overbruggen door hem te verdoezelen. Zij leven voor een problematiek, die grotendeels zou vervagen, als je genoeg, voldoend snelle spullen zou hebben: ik probeer me voor te bereiden op de problemen, die dan manifest zullen worden.

Ik wil evenzo mijn technieken niet onderwerpen aan de heersende ideeen van adequaatheid, want in die ideeen, geworteld als ze zijn in vandaag (zo niet gisteren!) geloof ik niet zo heel erg: als ik me daardoor gebonden zou voelen, zou ik hoogstwaarschijnlijk iets doen, wat een ander ook kan (en waarschijnlijk, ergens ter wereld, ook wel doet, zodat ik het niet meer hoef te doen). Zo'n charter voor de anderen heeft het gevaar het project in de grond te boren omdat ik dan niet meer iets "helemaal geks" kan doen.

Deze opmerking is geen vrijbrief, hij is ingegeven door de nuchtere observering, dat alle "grote" dingen, die ik gedaan heb, destijds geentameerd zijn op een manier die toen "helemaal gek" was. (Onze ALGOL vertaler staat sinds het boek van Brian Randell and Lawford Russell model voor alle ALGOL vertalers, die nog gemaakt worden, maar het druiste destijd z&oacute; in tegen alles wat bestond —en wij geleerd hadden van Harry Huskey— dat ik toen voor de enige maal in mijn professionele leven met mijn vuist op tafel heb moeten slaan om het er door te krijgen. Mensen vergeten, hoe "gek" het toen was..... Over multiprogrammering kreeg de THE op het moment, dat wij er serieus aan wilden beginnen, van IBM in vijfvoud een —toegegeven— commerciele brief, dat multiprogrammering een irreeel idee was; toen we bijna klaar waren nog, wou Dick Mills van MIT, nadat hij me er drie uur over had horen spreken, nauwelijks geloven, dat ik over iets echts sprak: "Edsger, do you mean to tell me, that you really did this?!" Maar de hersenschim werkt lang niet onaardig en het werk heeft zoveel repercussies dat drie jaar later in Rome I.P. Sharp (Toronto) opmerkt "I believe that in time we will probably refer to the "Dijkstra School of [Software] Architecture".". Maar mensen vergeten, hoe "gek" het in den beginne was..... Op grond van die ervaringen heb ik neiging om te zeggen "Mag ik iets helemaal geks willen?" of misschien zelfs nog wat sterker "Moet ik niet iets helemaal geks willen, als ik denk dat ik het kan?") Zoveel over waarom het me tegen de borst stuit om een charter van 30 kantjes op te stellen ter verdediging van die een of twee milljoen.

Wat mij misschien nog veel meer hindert is de voorstelling van zaken, dat ik die milljoenen nodig heb en dat ik als eerste belanghebbende (sic!) met een verrekt goeie verdediging moet komen omdat, als het doorgaat, het ten koste van iets of iemand anders zou gaan. Tegen die voorstelling van zaken maak ik bezwaar omdat ik hem fundamenteel ongezond vind. Ik ervaar mijzelf nl. de laatste belanghebbende: het zou voor mij een hoop werk, een grote verantwoordelijkheid en een hoop spanning meebrengen: als ik het verleden extrapoleer hoef ik me weinig illusies te maken over de wissels die op mijn zelfvertrouwen getrokken zullen worden. Die "eerste belanghebbende" oogst in elk geval nachtmerries: dat is zijn investering! Als ik belanghebbenden moet opsommen, dan denk ik eerder aan de onderafdeling der wiskunde, de THE, mijn land en mijn vak.

Nou komen we aan het punt, dat ik zeg: "Je moet jezelf niet idealiseren." De herinnering aan een romantisch jeugdsentiment komt boven, nl. toen ik mijn eindexamen deed zonder enige uitgesproken intentie om wis— en natuurkunde te gaan studeren. Maar als mij in de groentijd gevraagd werd, waarom ik dit gekozen had, antwoordde ik —lieve blaag, die ik was— in alle eerlijkheid en onnozelheid "Omdat ik op grond van mijn eindexamencijfers mij hiertoe verplicht voel!" Nauwelijks een valide argument en om, ik weet niet meer wie, te citeren "Op school zijn we allemaal knap, maar dat komt later vanzelf in orde." Maar niet helemaal.

In een omgeving, die mijn faciliteiten beschouwt als verkregen ten koste van een ander —een collega, zeg— wil ik om (hoop ik) begrijpelijke redenen zo min mogelijk met de werving van die faciliteiten van doen hebben. En ik twijfel ook, of het goed zou zijn, als ik me daarvoor in moest zetten. Het onmiddellijke gevolg zou nl. zijn, dat ik mij moreel verplicht zou voelen het project te reduceren tot de minimum-dimensies, waarbij ik net hopen kan, dat het nog voldoend interessant is; die ondergrens kan ik dan voor budgettair denkende mensen vertalen in: "Zoveel heb ik nodig.". Maar is die constellatie verstandig? Zou er niet meer uit mij gehaald kunnen worden? Ik ben in het verleden heel voorzichtig en heel bezorgd geweest —als vrolijke Frans heb je geen nachtmerries!— en ik acht het niet uitgesloten, dat de wereld er meer bij gebaat zou zijn als ik werd overgehaald tot het meest ambitieuze project, dat ik nog aandurf. Wat ik dan nodig zou hebben is zo iets als een impressario; zou dit een rol zijn voor de Commissie Wetenschapsbeleid?

Zoals de verhoudingen nu tot mij komen, zie ik wel wat in een impressario, want er worden voor mijn gevoel teveel paarden achter de wagen gespannen. Ik attendeer mijn omgeving er op dat ik er ernstig rekening mee houd, dat ik, mits er voldoende aandrang op mij wordt uitgeoefend, over een jaar of zo met een volgens mij verantwoord voorstel tot spendering van een paar milljoen zou kunnen komen. Dit wordt uitgelegd "dat ik om een paar milljoen vraag" en is met de tegenvraag beantwoord of ik dit echt nodig heb om door te kunnen werken. Nou, ik hoop van niet! Ik bedoel, dat ik het ook niet helpen kan, dat rekenautomaten zo duur zijn, dat ik uit het feit dat allerlei instanties desondanks veel geld voor hun aanschaf over hebben afleid, dat het probleem van verstandig machinegebruik niet zonder importantie is en dat het me daarom geen zinloze tijdpassering leek, als ik me daaraan wijdde. Ik wil wel, maar als de maatschappij onvoldoende aandrang op mij uitoefent, c.q. niet de middelen ter beschikking wil stellen om dit werk mogelijk te maken op een manier, die ik zinvol acht, dan hoop en vertrouw ik —ik ben per slot van rekening nog geen 40— voldoend flexibel te zijn om op een goedkopere manier de rest van mijn leven zinvol te vullen. Dat is de reden waarom ik op de vraag "Heb je zoveel geld nodig?" uit de grond van mijn hart antwoord "Ik hoop van niet", daarbij wel aantekenend, dat dat me de vraag niet lijkt.

Over twee andere paarden achter wagens, die ik bespeurd hebm kan ik iets korter zijn. Ten eerste is opgemerkt, dat mij verweten zou kunnen worden, dat ik een researchproject had uitgezocht, dat met de huidige faciliteiten (lees: de EL X8) niet verwezenlijkt kon worden. Een andere verwoording van hetzelfde paard was de opmerking, dat dit meer een pr[o]ject van E.W. Dijkstra dan van de onderafdeling zou zijn. Ik ben in mijn appreciatie van de relatie werknemer/instituut heel homocentrisch (als er geen mensen waren om de TH te bevolken, had de hele TH geen zin) en kan als variant op "L'état, c'est Nous." slechts antwoorden "De onderafdeling, dat zijn wij." Dat je je researchprogramma over 5 of 6 jaar zou moeten laten beinvloeden door de machine, die vijf jaar geleden zeer zorgvuldig op andere doelstellingen gekozen (en zelfs gedeeltelijk ontworpen) is, was een geheel nieuwe gedachte voor me. Ik zou er zelf nooit op gekomen zijn en was met stomheid geslagen.

Het laatste paard achter de wagen was de opmerking dat, voordat deze bedragen gevoteerd werden, het wel zaak was om een onderzoek te plegen naar mijn "gedurigheid" omdat het natuurlijk naar zou zijn, wanneer ik halverwege het project mijn hielen zou lichten. En ik in mijn onbedorven onschuld alsmaar denken, dat het feit dat im over dit project begonnen was, begrepen zou worden als mijn bereidheid, zo niet mijn wens, om in de komende periode het zwaartepunt van mijn activiteiten meer in Eindhoven te leggen dan in het recente verleden wel het geval is geweest.

Soms zie ik wel wat in een impressario.......

Edsger W. Dijkstra

transcribed by Jeanine Daems
revised Sat, 27 Jan 2007

EWD282

A tree-structured system.

This report is a summary of the discussions we (i.e. Bomhoff, Bron, Feijen and I) held during January 1970, in a first effort to give some shape to the Programming Laboratory Project. It is a highly condensed summary: many detours and blind alleys will be left unmentioned. Beside that, it was the first month that this group of four people tried to think together and many a day was just spent in getting used to the other's way of coining words, of twisting sentences and of struggling with half-baked ideas.

We have assumed that programs are conveniently conceived and considered as "necklaces", i.e. as linearly ordered sets of "pearls". (I know only too well that the only convincing examples I have for this assumption are rather small examples, as trying it out for larger examples is too expensive now. I also dare to be content with that experimental evidence, at least for the time being, for after all, I arrived at the concept of pearls in a necklace by rather independent means and the examples worked out were only confirmations.) The relatively small examples gave already rise to rather long necklaces (6 pearls in a small program), it also became clear that my main goals (provability, adaptability) are served by small pearls. Therefore, if a large program can be made in a way in which these main goals are reasonably well achieved, we must be prepared to process programs composed as very long necklaces. Our first effort was to get a feeling for the implementational consequences of the great length of the necklaces.

The pearls are ordered in a linear hierarchy, at the bottom side we have "the machine", at the top we have —if we go to extremes— the famous pearl "Do All Work", the function of each pearl being to rebuild the machine underneath it into a more attractive machine to be used above it.

In the beginning it turned out to be very hard to come to grips with our problem, to discover what we were supposed to be talking about. The sky became somewhat clearer when we discovered the main source of our difficulty. Assuming that one has at one's disposal a sufficiently automated tool to compose programs from pearls, then we believe to have a tool that caters reasonably well for the operational and representational abstraction as far as the subject matter of these programs is concerned! But the problem we were tackling was "how to represent pearl texts inside the machine so that they can be interpreted reasonably efficiently". It is a kind of bootstrapping problem, but it took us some time to discover that this was the case. (The dilemma is perfectly clear if we think of subroutines, i.e. the well-known form for operational abstraction: whatever new operational primitive you wish to introduce, you can make a subroutine for it. But you cannot apply this standard technique when the primtive you want to make is... the subroutine jump!)

As announced in EWD279, one of our first concerns would be a binding policy. To rephrase the question: when you go along the necklace from bottom to top, you will find existing concepts losing their applicability and new concepts becoming applicable as you go along. In the pearls at the different levels, the object code must refer to them and the question becomes: in what terminology?

We have played with the following idea. Each pearl "owns" the concepts it introduces and distinguishes between them via a local index. Besides this, it distinguishes via an "underindex" between the concepts that are already there. Furthermore, we assumed that each concept is suitably identified globally by a couple, consisting of a global identification of the pearl owning it and the local index used by this pearl to distinguish between its property. Such a convention implies for each pearl a kind of "binding list" for the interpretation of underindex values and immediately one is faced with the question: what entries do we find in this binding list? In one extreme the entry contains by definition the bit pattern by which the immediately underlying pearl identifies the concept. This has the unquestionable advantage that whatever is built on top of a pearl is, in its representation, independent of the necklace structure underneath the pearl in question. Attractive as this might be, it seems to lead to unacceptable consequences:
1)    the individual binding lists tend to get very long, for the underindex values for each pearl have not only to distinguish between the existing concepts it really refers to, but also between those, that it only transmits to above.
2)    the accessing mechanism presents itself as a kind of indirect addressing in which the length of indirection is equal to the distance between the refering pearl and the owning one. This later aspect makes this solution hardly acceptable for a system that would like to promote programming in terms of small pearls and therefore long chains! With N layers the accessing speed would be proportional to 1/N and this we have rejected as general policy.

So a shortcut seems indicated and we have considered the other extreme: in the binding lists (or directly in the pearl object texts —this is only a minor difference) the accessing mechanism finds a bitpattern which directly identifies the concept in a global terminology, i.e. the access time will be independent of things such as pearl distance and chain length. In other words, we introduce a global terminology and allow this global terminology to diffuse through the binding lists of pearl texts. (Intermediate forms are conceivable, where at certain "major cuts" in the necklace a completely new terminology is introduced for all or parts of the concepts transmitted to above; we shall not pursue that now.)

This suggests a binding policy in the direction from bottom to top, or, if the necklace is generalized into a tree, starting at the root. Consider the stage where the tree has grown to a certain level and a next layer has to be added. The binding function of the translator then has the following function. The source text has to be interpreted in terms of the concepts, relevant at that level, a "source context". We can think of the source context as being defined along the necklace and by searching from top to bottom each source concept will be found and can be translated into the "object context" which covers all concepts along the chain. (In ALGOL 60, the only way to make an identifier, declared in an outer block, inaccessible in an inner block, is "redeclaration" of the same identifier in the inner block. A pearl could contain, besides the concepts it introduces, an "introduction list", say, also a "removal list", i.e. a list of existing concepts no longer applicable in the structures on top of it.)

We then see a mechanism emerging in which the object context only grows and grows as new pearls are added, while the binding function of the translator will have a strong protective function, i.e. it has to see to it, that object text —although it has the potential richness— never refers to a concept outside the corresponding source context. It is this mapping of source context into object context which strikes us now as the main aspect of the binding function: for lack of associative memories it is a painful process and for that very reason it seems a suitable candidate for what is usually called "the translation fase". It implies that the bottom part can be bound regardless of what will be built on top of it, it also implies that (more than trivial) rebuilding of a bottom part calls for "rebinding" of what has been built on top of it.

At present I expect us to take this decision: it is the only way I can see such that the performance does not degrade too much with increasing chain length. This decision in favour of "natural order of growth" will only be taken after much hesitation —as a matter of fact we already did so. The reason for hesitating was that taking this decision struck us as giving up hope "to change a program while it is running". It is quite clear that this will be difficult (if not impossible!) and for reasons of design strategy one must impose an upper limit on the period of time during which one allows oneself to be paralyzed by the (still apparent) unattainability of such a goal. I think it has paralyzed us long enough. The kind of flexibility necessary (but insufficient) for that goal seems very expensive; at present I hope that the decision of "natural order of growth" provides a framework in which the problem of dynamic program changing permits a more precise formulation.

*     *     *

The next thing we talked about —although not very extensively— was the representation of the object code, in particular the way in which it will be parsed under control of its order counter. If working in an interpretative mode slows down the performance by a factor of R, it is absolutely inacceptable if we have to pay that factor for every new pearl: for a necklace of length N we would then get a slowing down by a factor R↑N.

Our conclusion was very similar to the one we drew in connection with identification, where we concluded that the identifying bit patterns in the object code should control rather directly a global accessing mechanism, independent of pearl height etc. We concluded that at all levels the instruction stream should be parsed by essentially the same "instruction cycle", a requirement which asks for a very flexible instruction format.

Our current guess is to combine the format flexibility of stack machines which process the instruction stream as a string of syllables with the semantic flexibility of the "extra codes" as have been implemented in one or more English machines. To be more precise: instruction execution takes place with the aid of a stack, the top section of which is considered as containing the active registers, instruction register included. The instruction cycle reads syllables from the program text that are essentially copied on top of the stack. They are subjected to a minimum amount of interpretation: a distinction is made between "passive" and "active" syllables (say: on account of a dedicated bit in the syllable representation); as soon as an active syllable has been copied on top of the stack an operation is started as described (primarily) by the contents of the top of the stack. This should cater for the format flexibility. We hope to achieve the desired semantic flexibility by requiring that at each level active syllables can be used irrespective of the question whether they are conceived as identifying "a built-in function" or "a primitive explained by software". (This is essentially the notion of "extra codes"). If we succeed in doing this, we may build a software system in which the top layers are —structurally, at least— unsensitive to the question how many of the lower layers have been absorbed by the hardware. (This goal comes very naturally. At top side we wish the boundary between system building and system usage to become more vague; similarly at the bottom side with the (conceptual) boundary between hardware and software.)

We did not work this out in greater detail, we did discuss the question of "ideal syllable length". Our first (and second!) impression was that on the one hand it will be very hard to defend a specific choice for syllable length, but that on the other hand (on account of the global activity of the instruction stream parsing) it will be still harder to avoid the decision. Dear old Sartre!

*     *     *

A next discussion, again, took a long time to get to the point. We saw a tree-like structure emerging and the point in question turned out to be "for what purposes do we hope to exploit this tree-like structure?".

Our original, first candidate was the notion of "parallel and nested conceptual universes". Let me describe how this notion came into being. In the (constant) part of the THE-system we have a single set of layers; at one level we still have a drum, on top of it we have a new universe, in which we have a virtual store, but no drum anymore, the drum being "used up" for the implementation of the virtual store. But here one could think of a "split level", on the one hand a universe in which there is virtual store and on the other hand one in which (part of) the core store and (part of) the drum are still as available as ever, i.e. we have made two worlds, one in which the concept of the virtual store is applicable and one where it is not. From then onwards, two mutually independent subsystems can be developed. (In the top layer of the THE-system we actually do have the split level: the five PM's, which, when loaded with programs do create five mutually independent interpretative mechanisms, viz. the interpretative mechanisms for the five sets of user data.) The conceptual mutual independence of parallel branches is considered to imply potential parallellism of the sequential processes related to them: a single sequential process could not be related to two parallel branches, more than one sequential process in one branch was not excluded a priori. For after all: the function of a layer is "to rebuild a machine", the given machine as well as the target machine may have mutually asynchronous components. We shall return to this question in a moment.

A second purpose for which the tree-structure can be exploited is a straightforward one. If parallel branches are conceptually independent, the going on of a sequential process somewhere high up in the tree can only depend (primarily) on concepts explained along the path leading from its position in the tree downwards to the root. This has a number of consequences.

1)    For the effective executability of a sequential process, various degrees of "presence of information" can be defined. The highest form of presence is presence in primary store, the second form is dumped on secondary store but with the decriptors itself still present in primary store, the third form could have even the descriptor absent from primary store, etc. By placing the descriptors themselves in the appropriate position in the tree, it is conceivable that "off-path" descriptors could be dumped from primary store without introducing the well-known horror of the "recursive page fault".

2)    As primary reference will only be along the path leading downwards to the root, we only need an identifying terminology distinguishing elements along that path. As shown (by Brian Randell and myself) this circumstance is strongly suggestive for various speeding-up devices —e.g. the "stack display". Besides that, it makes parallel branches truly independent in the sense that in the representation of their texts the same identifying terminology can (and in all probability will) be issued by the translator. (Cf. numbering the Dutch babies for the sake of identification in order of moment of birth: such a convention requires synchronization all over the country between all maternity wards!)

We now return to the relation between the tree and sequencing. Consider a single chain of pearls. In one of the higher pearls a primitive is invoked. On the level where it is used, such a primitive represents a single action, and it is only when we show a more microscopic interest in what is happening that the activity of such a primitive presents itself, in its turn, as the execution of a sequential program. With this in mind we turn our attention to the critical sections as implemented in the THE-system. What are they? They are "single actions" in the program in which they occur. It is only because the basic machinery allows for a finer grained parallellism that we must encapsule the sequential sub-process by means of a P-V bracket pair operating on a semaphore introduced for mutual exclusion. It is the kind of mutual exclusion that on a lower level —say the cross bar switch— is guaranteed by the hardware. This observation is strongly suggestive for the following approach.

If a number of parallel processes contain sections critical with respect to each other (THE terminology), we can "take them out", consider them on the level of the parallel processes as primitives and refine them in the common trunk, in the implicit understanding that the common trunk will serve "one at a time", in exactly the same way as in multiprogramming, where the single central processor switches from one program to another only between instructions.

Arguments in favour of exploiting the tree structure for mutual exclusion as well, are the following ones. (To a certain extent this list amounts to an enumeration of anomalies in the THE-system!)

1)    Critical sections have been introduced for the unambiguous inspection and setting of common state variables; in the design of the THE-system it became a wise discipline never to access these common variable outside critical sections, not even in those cases where a piece of (usually very tricky) reasoning could justify it. In those years, the wisdom of this discipline was a "scientific discovery"; now we have made it, we must conclude that the common state variables should not be accessible from outside critical sections. As long as we regard them as normally accessible —but programs are not allowed to access them outside the critical sections— this calls for specific protection measures. By moving the critical sections to a common "secretary", down in the trunk, this problem is solved by structure.

2)    In the THE-system we use the same P- and V-operations on two very different kinds of semaphores. This is expensive and (worse!) confusing. I remember our "scientific discovery" that these two classes of semaphores were both attractive and sufficient. Again, this difference should preferably be represented by structure.

3)    For reasons of reaction time we had to introduce for the PM's a priority (as far as processor allocation was concerned) that varied in time: as soon as PM entered a critical section, it got the maximum priority as long as it stayed in the critical section: not the process itself was in a hurry, but its "being in a critical section" caused the urgency. In the necklace model, activity in the higher pearls only takes place by virtue of the activity of lower pearls and in that model it is quite natural to assign the highest priority to the lowest pearls. Also the priority rule of the THE system as far as critical sections are concedned, finds a natural place in the hierarchy we are considering.

4)    Hendriks has already pointed out that if our only mutual synchronization is in the form of mutual exclusion via perhaps many mutual exclusion semaphores, deadly embraces are guaranted to be absent, provided the bracket pairs are nested and the semaphores associated with the nested pairs are ordered in a tree fashion, i.e. exactly the kind of ordering we are considering! (In the THE-system his observation has not played a very important role because we only had two mutual exclusion semaphores. Having only one processor there was not much economic pressure to introduce more of them. But his remark was perfectly valid.)

transcribed by Pascal J. Bourguignon
revised Thu, 6 Jan 2011

20 april 1970 | EWD286

Verslag van mijn reis naar California.

De alles overheersende indruk van deze tocht is, dat de reis naar en van California niet leuk is. Ergens in het midden van de tocht heb je een non-stop vulcht van een uur of elf in een afgeladen volle Boeing 707, met alle franje voor en na ben je een uur of tweeentwintig onderweg. Voeg daarbij een tijdsverschil van negen uur : het betekent dat ze tegen de tijd dat je op je bestemming aankomt, de stukjes bij elkaar kunnen vegen. Het voordeel van de thuisreis is, dat je daarna t huis bent.

Vanaf London heb ik samen met Brian Randell gereisd. We kwamen tegen een uur of tien plaatselijke tijd in ons hotel aan en hebben toen het N-de maal (N groot) genuttigd en zijn naar bed gegaan. Dit was het Huntington Sheraton Hotel te Pasadena, vast heel duur. Ze waren er in dit hotel erg op ingesteld om de indruk van perfecte service te geven, meer dan de perfecte service zelf. Ik heb er het binnenstromen van twee society huwelijken en een “Charity Lunch” kunnen gadeslaan, benevens het bezorgen van een “money tree”, een kunstboeket van dollarbiljetten. Allemaal heel boeiend.

Donderdagmiddag en vrijdag zijn we samen op de fabriek van Burroughs, Pasadena op bezoek geweest, een bezoek, dat wat in de mist van het tijdsverschil is opgegaan, met uitzondering van vrijdagmorgen, toen ik naar aanleiding van een paar vragen van Ben Morselt in een kort tijdsbestek bijzonder veel gehoord heb. Dit was in een gesprek met B.A.Creech, een indrukwekkende man.

Mijn totale indruk van deze groep is dat er een aantal voortreffelijke mensen bij elkaar zit, mensen die weten wat ze doen en waarom ze het doen, die veel plezier met elkaar hebben, maar het niet altijd even makkelijk hebben met hun management. Burroughs bestaat als firma al sinds 1880 of zo en was een ouderwets familiebedrijf, dat in 1960 of zo “Electrodate” heeft opgekocht en je krijgt de indruk, dat de firma pas in 1964 —toen de laatste telg van het geslacht Burroughs uit de leiding verdween— het bedrijf langzamerhand is gaan ontdekken, wat ze hadden opgekocht. Maar het is al mooi dat de groep van Electrodata de fusie overleefd heeft. (Ik kan niet nalaten hier het verhaal tussen te lassen van de kip en het varken, die een fusie aangingen om samen “ham and eggs” op de markt te brengen. Toen het fusiecontract ondertekend was, realiseerde het varken zich ineens de fatale consequenties en bekloeg zich bij de kip, die onbewogen antwoordde “Maar bij een fusie gaat toch altijd een van de partners er aan!”) Het andere verhaal, waar ik aan denken moet, is van de Engelse onderhoudsman, die bij een hem niet goed bekende kaartponser gehaald werd, die wat kaarten had verkreukeld; de man maakte de zaak open, keek er eens goed in en riep toen in wanhoop en walging uit “Oh my God, what a triumph of engineering over design!”. Dit vonnis is op veel apparatuur van toepassing, niet op de B6500. Ze zijn met een consistent ontwerp begonnen en dat heeft onder de ontwikkelingsfase niet te veel geleden. (Een van de minder aantrekkelijke punten in deze machine is naar mijn smaak de manier, waarop physische adressen door de stack kunnen diffunderen; toen ik dit zag, was mijn eerste reactie “Wat jammer, dat ik niet in een vroeg stadium bij dit ontwerp betrokken ben geweest, dan was dit wellicht voorkomen”. Nu hoorde ik dat het er oorspronkelijk ook niet in zat, maar dat het er ingekomen was onder management pressure om tegemoet te komen aan “The number crunchers”. Een stukje achtergrondinformatie, waarvan ik het prettig vind om die te hebben.) Het enige bedenkelijke punt, dat ik heb opgevangen was de ervaring, dat deze machine, die zozeer gebouwd is op aanwijzing van de software makers, in het veld hogere eisen stelt aan de hardware maintenance engineer. Het resultaat is, dat de man die de software kent vaak een vitale rol speelt bij de trouble shooting. Het is heel begrijpelijk, ik kreeg de indruk, dat ze hier niet op gerekend hadden.

Daarna zijn we zes nachten op Catalina Island geweest voor een vijfdaagse bijeenkomst, waarin een twintig top designers van Burroughs aan invloeden van buiten werden blootgesteld. En ik was zo’n invloed van buiten, De werktijden waren van negen tot twaalf en van drie tot zes en een paar keer ’s avonds. Het speelde zich af in de patio van een in spaanse stijl gebouwde “Country Club”, men zat al naar gelang van smaak en vel in de zon of onder parasols. Ik heb ze een uur of zes toegesproken en op een paar uitzonderingen na (hardware designers uit Paoli) een kostelijk publiek, dat me een weer duidelijker beeld gegeven heeft van in hoeverre mijn verhaal relevant is. Ik heb doorgaans met veel genoegen geluisterd naar de andere “invloeden van buiten”, ze waren heel gevarieerd. Een man van Fairchild over integrated circuits; dit was wel een erg gestroomlijnd verhaal, compleet met dia’s en zo. een beetje een “slick commercial” maar als je daar nu doorheen zag, gaf hij wel een indruk van wat ons op hardwaregebied te wachten staat. Drie heel verschillende verhalen van Brian Randell, een over geheugenbeheer, dat ik nou wel ken en eigenlijk niet zo leuk vind, een verhaal over betrouwbaarheid en tenslotte —dit alles ter verruiming van de blik— een verhaal over Ludgate, een Ier, die in het begin van deze eeuw tussen Babbage en Aitken, een automaat heeft willen maken; deze Ier was helemaal vergeten en Brian heeft hem pas een maand of wat geleden ontdekt. Dan was er een man, die aan real time speach recognition and synthesis deed; ik heb dat niet allemaal begrepen, wat wel duidelijk was, is dat zo’n gebied vraagt om semi-special purpose apparatuur; wat hij daarvan vertelde verruimde mijn blik, je bent zo gauw geneigd, je helemaal tot special purpose apparatuur te beperken. Dan hadden we een soort architect-achtige man, die zich (al sinds negen jaar!) uitsluitend had beziggehouden met modellen, die je van papier kan vouwen. Hij vouwde regelmatige patronen in grote lappen papier en kon dan zo’n lap tot een koepel buigen. Sinds een jaar of wat probeerde hij om deze modellen in een rekenmachine te beschrijven en de machine via een display de beweeglijkheid te laten zien; dit was beslist een vrij unieke jongen, ergens natuurlijk knettergek, maar nog normaal genoeg om heel boeiend te zijn. Voorts iemand over “signal enhancing”, die via numerieke technieken contrastverbeteringen in foto’s en opzuivering van oude Caruso-opnamen had gepleegd. Tenslotte een man, die zich (van huis uit logical designer) serieus in de functionele specificatie van rekenorganen had verdiept(“The lost Art of Arithmetic”) en vervolgens zich had beziggehouden met de interpretatie van balletschrift en aan de hand van deze teksten inderdaad poppetjes met het goede soort heupgewieg over het scherm had laten dansen.

Mijn bezoek aan Stanford hierna heeft me wat teleurgesteld. Ik heb er veel geleerd, een beetje over de Verenigde Staten, waarschijnlijk veel meer over mijzelf. Er was veel te veel OK-research: of het was wat iedereen doet en afwijken leek alleen toegestaan als je het in makkelijk aansprekende, spectaculaire manier deed. Ik vermoed, dat de manier, waarop men gelden voor onderzoek moet organiseren, hier wel het een en ander mee te maken heeft. Aan het einde van mijn bezoek heb ik voor het Computer Science Seminar een lezing gehouden, die een groot succes werd. Na afloop werd er gezegd, dat ze het jammer vonden, dat ze dit niet hadden zien aankomen, want dan hadden ze het op videotape opgenomen; ik van mijn kant vond het wel zo rustig, dat het niet werd opgenomen, want ik heb mijn verachting voor het standaard marktproduct en mijn bezorgheid wegens de invloed die het op het denken van de mensen, die er mee proberen te leven, niet onder stoelen of banken gestoken. Als het opgenomen was, had ik waarschijnlijk minder vrijuit gesproken. Ik wist niet precies, hoever ik gaan kon, ik voerde het zachtjes op en bij mijn tweede cynisme had ik al een open doekje binnen,, wat wel een teken aan de wand was voor de frustratiegraad op een campus die met 360-en probeert te werken.

Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 29-Nov-2011

EWD– 287

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Preface.

The market is already so heavily overloaded with introductory texts on computers and computer programming that one must have rather specific reasons to justify the investment of one's time and energy in the writing of yet another "Short Introduction into the Art of Programming". The sole fact that one likes to write is, all by itself, an insufficient justification. Before undertaking such a task I should therefore ask myself "Why am I going to do it?" and also "What do I expect to be the distinguishing features of this little monograph?".

There is a simple, practical reason. At my University I teach, mainly for future Mathematical Engineers, an introduction into the art of programming and my students would welcome some underlying material. Besides that, without some form of lecture notes, my colleagues have very little idea of what I am really trying to teach! The contents of this course show signs of settling down -I have now given it three times- and therefore this seems the appropriate moment to produce a document that can serve as lecture notes.

There are purely local circumstances and as far as they ale concerned, a normal set of lecture notes -in Dutch, say- would do. The fact that I have not chosen this form means that I am aiming at a larger audience. Such an act is always somewhat presumptuous and the usual author's trick to save the image of his modesty is to tell that from various sides he has been urged to produce his manuscript - a trick that I could apply in this case without lying. But I don't think that I shall resort to that trick because I really believe that a larger audience than just my students can benefit from it, or even enjoy it.

The fact is that over the last years I have addressed myself to the question whether it was conceivable to increase our programming ability by an order of magnitude and what techniques (mental, organizational or mechanical) should then be applied in the proces of program composition. Personally, I felt these investigations very rewarding: I gained a much deeper understanding of the nature of the difficulty of the programming task, I become much more conscious about my"programming style", which improved considerably and, in general, found myself, when programming, in much better control of what I was doing than I had ever been before. Needless to say that my teaching was heavily influenced my these experiences.

The purpose of this little monograph is to assist the programming reader in cleaning up his own thinking, to transmit to him some mental disciplines by sticking to which he can avoid making his job unnecessarily difficult. It is born out of dissatisfaction with the usual kind of programming course, which now strikes me as the type of driving lessons in which one is taught how to handle a car instead of how to use a car to reach one's intended destination. This monograph is intended as a complement to such courses: I shall try to present programming � to quote N.Wirth� "as a discipline on its own merits, as a methodology of constructive reasoning applicable to any problem capable of algorithmic solution."

I expect the distinguishing feature of this little monograph to be its incompleteness, incompleteness in many, many respects.

It will not be self�contained in the sense that I assume my readers somewhat familiar with a decent higher level programming language. (This assumption is a direct consequence of the local circumstance that my students have had a modest prior exposure to the cleaner aspects of ALGOL 60.)

For those readers who identify the programmer's competence with a thorough knowledge of the idiosyncrasies of one or more of the baroque tools into which modern programming languages and systems have degenerated, the book will also be very incomplete, because I won't describe any programming language -not even the one I use" to that level of detail. I shall use some sort of programming language, say, as "a communication language", but not for the communication of algorithms, but for the communication of ways of thinking, as a vehicle for programming style.

In yet another respect, this little monograph will be very incomplete. As said above, I shall try to present programming "as a discipline on its own merits, as a methodology of constructive reasoning, applicable to any problem capable of algorithmic solution". At present, such a methodology does not yet exist in the full sense of the word, only elements of it have become apparent, others are just lurking behind our mental horizon. This, of course, is not very satisfactory, but it is a true reflection of the current, still rather poor state of the art. It is a consolation that no piece of scholarship ever reaches the state of perfection and I am telling myself that the conviciton that there is more to come is no justification for witholding what we have got.

It will also be incomplete as a result of the choice of the examples and the choice of the considerations. By necessity, the examples will be "small" programs, while the need for a discipline only becomes vital in the case of "large" programs. Dealing with small examples in an ad-hoc fashion gives the student not the slightest clue as how to keep the construction of a large program under his intellectual control, I hope to deal with the small examples in such a fashion, illustrating how we can avoid unmastered complexity, that methodological extrapolation to larger tasks- which, alas, fall outside the scope of this little document- is feasible. The choice of considerations is also kept to a strict minimum: we restrict ourselves to programming for purely sequential machines and when we have to consider a trade-off question, we shall usually present this in the form of a trade-off between computation time versus store requirements. In this respect the document may strike the reader as very strongly dated, perhaps even outdated by the time it appears in print. If so, I hope that I can justify my defense, that such a reader has failed to read between the lines: it is not so much the particular trade-off question chosen that matters, as the fact that the problem has been approached in such a fashion that we have made a conceptual framework in which such specific trade-off questions can he postponed until the appropriate moment. The only thing I can do at this stage is to urge my readers to read between the lines as much as possible. (If one tries to transmit ideas or methods, one can talk about them but that alone is insufficient, one must show examples illustrating them. When lecturing, it is my sad experience that after having dealt with a specific example, I find the attention of half my audience completely usurped by this example: they have forgotten that the example was only brought to their attention to illustrate something more general. This is a sad experience and no amount of prior warning that this misunderstanding is bound to happen if they are not careful, has ever enabled me to avoid it!) To put it in another way: it is my purpose to transmit the importance of good taste and style in programming, the specific elements of style presented serve only to illustrate what benefits can he derive from "style" in general. In this respect I feel akin to the teacher of composition at a conservatory: he does not teach his pupils how to compose a particular symphony, he must help his pupils to find their own style and must explain to them what is implied by this. (It has been this analogy that made me talk about "The Art of Programming".)

There in a further class of potential readers that will find this subject matter very incompletely dealt with, viz. those who identity the programmer's task with writing program in, say, FORTRAN or PL/l. One of my implicit morals will be that such programming languages, each in their own way, are vehicles inadequate to guide our thoughts. If FORTRAN has been called an infantile disorder, PL/1 must be classified as a fatal disease.

Although I would love to do it, it is impossible to give a true acknowledgment listing all persons whose relevant influence on my thinking I gratefully remember or should remember. With my apologies to all persons unmentioned I would like to make a few exceptions and list in alphabetic order: my mother mrs.B.E.Dijkstra � Kluyver, R.W.Floyd, C.A.R.'Hoare, P.Naur, B.Randell, D.T.Ross, N.Wirth and M.Woodger. None of the persons listed however, should in any way be held responsible for the views expressed (with the possible exception of my mother who is in some sense responsible for my existence).

Some fundamental notions .

In this suction a number of notions will be introduced, because they are fundamental to the whole activity of programming. They are so fundamental that they will not be dissected into more primitive concepts. As a result this section will be a very informal one, analogy, metaphor and natural language (poetry, if I were able!) being the only available vehicles to convey their contents and connotations.

It is not unusual �although a mistake- to consider the programmer's task to be the production of programs. (One finds terms as "software manufacturing", proposals to measure programmer productivity by the number of lines of code produced per month etc., although I have never seen the suggestion to measure composer productivity by the number of notes, monthly scribbled onhis score!) This mistake may be at the heart of the management failure which is so apparent in many large software efforts. It is a mistake, because the true subject matter of the programmer's activity is not the program he composes, but the class of possible computations that may be evoked by it, the "production" of which he delegates to the machine. It seems more fruitful to describe the programmer's activity, instead of "making a program",as "designing a class of computations". In this connection it should be borne in mind that the more relevant assertions about programs -e.g. about their correctness or their resource demands- indeed pertain to the computations, rather than to the last thing that leaves the programmer's hands, viz. the program text. It is for this reason that, when introducing the fundamental notions, I will start at the side of the computations, with the "happenings in time". The first notion is that of an action. An action is a happening, taking place in a finite period of time and establishing a well-defined, intended net effect. In this description, we have included the requirement that the action's net effect should be "intended", thereby stressing the purposefulness. If we are interested in the action at all, it will he by virtue of our interest in its net effect.

The requirement that the action should take place in a finite period of time is most essential: it implies that we can talk about the moment T0, when the action begins, and the later moment T1, when the action ends. We assume that the net effect of the action can he described by comparing "the state at moment T0" with "the state at moment T1".

An example of an action would be a housewife peeling the potatoes for the evening dinner. The net effect is that the potatoes for the evening dinner are at moment T0 still unpeeled, say in the potato basket in the cellar, while at moment T1 they will he peeled and, say, in the pan to be cooked in.

When we dissect such a happening as a time sequence of (sub)actions, the cumulative effect of which than equals the net effect of the total happening, then we say that we regard the happening as a seguential process, or process for short.

Whenever much a dissection is permissible, we can regard the same happening either as an action, or as a sequential process. When our interest is confined to the net effect, to the states "before and after", then we regard it as an action. If, however, we are interested in one or moreintermediate states as well, then we regard it as a process. In the latter case the moment T0 coincides with the begin of the first suhaction, the end of each subaction coincides with the begin of the next one, with the exception of the last subaction, whose end coincides with T1, the end of the whole happening.

I must stress, that whether some happening is regarded as an action or as a process it not so much an inherent property of the happening, it expresses our mood, the way in which we prefer to look at it. (Why we should want to look at it in different ways, will he left for later discussion.) Similarly, if we have chosen to regard the happening as a process, the way in which it has been dissected is also not so much an inherent property of the happening, it expresses which of its distinguishable intermediate states (for some reason or another) we wish to take into consideration.

The happening of the potato peeling housewife could for instance be described by the time-succession of the following four subactions of the housewife: "fetches the basket from the cellar; fetches the pan from the cupboard; peels the potatoes; returns the basket to the cellar" .

Here the total happening has been described as a time-succession of four subactions. In order to stress that we have given the description of a happening we have phrased it in the form of an eye-witness account. Note, that if the eye- witness did not bother to describe that the basket was fetched from the cellar before the pan was fetched from the cupboard, the first two lines would have been condensed into a single suhaction "fetches the basket from the cellar and the pan from the cupboard".

We postulate that in each happening we can recognize a pattern of behaviour or pattern for short; the happening occurs when this pattern is followed. The net effect of the happening is fully determined by the pattern and (possibly) the initial state (i.e. the state at moment T0). Different happenings may follow the some pattern, if these happenings establish different net effects, the net effect must have been dependent on the initial state as well and the corresponding initial states must have been different.

How we can recognize the same pattern in different happenings falls outside the scope of this text. If we meet a friend, we can recognize his face, no matter what facial expression he shows, it may be an expression we have never seen on his face before! Somehow we manage to abstract from the current expression, we recognize the same friend. Similarly with different happenings: we recognize the same pattern, abstracting from the possibly different initial states and net effects.

We return for a moment to the housewife. On a certain day she has peeled the potatoes for the evening dinner and we have an eye�witness account of this happening. The next day, again, she peels the potatoes for the evening dinner and the second happening gives rise to an eye-witneas account equal to the previous one. Can we say, without further ado "Obviously, the two accounts are equal to each other for on both occasions she has done exactly the same thing."?.

How correct or incorrect this last statement is depends on what we mean by "doing the same thing". We must be careful not to make the mistake of the journalist who, covering a marriage ceremony, told that the four bridesmaids wore the same dress What he meant to say was that the four dresses were made from material of the same design and �apart from possible differences in size- according to the some pattern.

The two actions of the housewife are as different from each other as the dresses are: they have, as happenings, at least a different identity, one took place yesterday, one today. As each potato can only be peeled once, the potatoes involved in the two happenings have different identities as well, the first time the basket may have been fuller than the second time, the number of potatoes peeled may differ etc.

Yet the two happenings are so similar that the same eye-witness account is accepted as adequate for both occasions and that we are willing to apply the same name to both actions (c.g. "peeling the potatoes for the evening dinner").

An algorithm is the description of a pattern of behaviour, expressed in terms of a well-understood, finite repertoire of named (so-called "primitive") actions of which it is assumed a priori that they can be done (i.e. can be caused to happen).

In writing down an algorithm, we start by considering the happening to take place as a process, dissected into a sequence of subactions to be done in succession. If such a subaction occurs in the well-understood, finite repertoire of named actions, the algorithm refers to it by its name. If such a subaction does not occur in the finite repertoire,the algorithm eventually refers to it by means of a subalgorithm, in which the subaction, in its turn, is regarded as a process, etc. until at the and all has been reduced to actions from the well-understood, finite repertoire.

The notion of an algorithm, an executable precept for the establishing of a certain net effect, is very well known from daily life: knitting patterns, directions for use, recipes and musical scores are all algorithms, And if one asks in an unfamiliar town for the way to the railway station, one asks essentially for an algorithm, for the description of a pattern of behaviour which, when followed, will lead to the desired goal.

In our description of an algorithm we have stressed that the primitive actions should be executable, that they could be done. "Go to the other side of the square." is perfectly OK, "Go to hell", however, is not an algorithm but a curse, because it cannot be done.

Besides that we have stressed that the repertoire should be well-understood: between the one who composed the algorithm and the one who intends to follow it, there should be no misunderstanding about this repertoire. (In this respect knitting patterns are, as a rule, excellent, recipes are of moderate quality while the instructions one gets when asking the way are usually incredibly bad!) How essential this lack of misunderstanding is may perhaps best be demonstrated by a recipe for jugger hare as it occurs in an old Dutch cookery-book; translated into English the recipe runs as follows: "One taketh a hare and prepareth jugged hare from it." The recipe is not exactly wrong, but it is hardly helpful!

Let us now contrast the eye-witness account of the potato peeling session: "fetches the basket from the cellar; fetches the pan from the cupboard; peels the potatoes; returns the basket to the cellar" with the corresponding algorithm -the set of instructions, say, the housewife might give to a new maid-: "fetch the basket from the cellar; fetch the pan from the cupboard; peel the potatoes; return the basket to the cellar" .

Comparing the two, we may well ask what we have gained, for it seems a roundabout way of doing: describing a pattern of behaviour which, when followed, will evoke the happening, while in the eye�witness account we had an excellent way of describing the happening itself.

What have we gained? Well, nothing, as long as we restrict ourselves to algorithms that can be given -as in our example- by a concatenation of names of actions, to be done in the given order. Under that restriction an eye-witness account of the actions "as they take place" is equally good. But the behaviour of the housewife (or the maid) could be a little bit more complicated: let us suppose that after the pan has been fetched, she puts on an apron if necessary, i.e. when she wears a light-coloured skirt and that on one day she uses the apron while on the other day she doesn't.

On a rather abstract level -i.e. without explicit mentioning of the apron and the condition under which it is used, a uniform eye-witness account would still do (in some fashion) for both sessions, e.g.: "fetches the basket from the cellar; fetches the pan from the cupboard; takes preparation as regards to clothing; peels the potatoes; returns the basket to the cellar" with the implcit understanding that "takes preparation as regards to clothing" covers the empty action when her skirt is not light-coloured and covers putting on an apron when her skirt is light-coloured.

If, however, we want to go into more detail and want to mention the apron explicitly, then "takes preparation as regards to clothing" has to be replaced in the eye-witness account of the one day's session by "sees that her skirt is light-coloured and therefore puts on an apron" and in the other day's session by "sees that her skirt is not light-coloured and therefore omits putting on an apron" .

The trouble is, that the eye-witness account cannot contain the single sentence: "puts on an apron if her skirt is light-coloured" for then the audience justly asks "does she do it or not?".In other words: in that degree of detail we cannot cover the two happenings by the same eye-witness account for in that degree of detail the two happenings differ!

It is here that the potential power of the algorithm becomes apparent, for we can recognize the same pattern of behaviour in the two happenings and by describing that pattern of behaviour we give something that is applicable under both circumstances, light- as well as dark-coloured skirt. This is possible thanks to the fact that what actually happens when a certain pattern of behaviour is followed may be co-determined by the state of affairs which is current when the action begins.

We see two things: the inspection whether the skirt is light-coloured and, depending on the outcome of this inspection, the action "put on an apron" is to take place or not. In order to express this conditional execution we need in our algorithm another connective besides the semicolon. In our example of the algorithm (I refer to the instructions to the new maid) the semicolon had a double function: in the text it separates one action name from the next action name but besides that it implied for the happening a certain amount of what is technically called "sequencing control", i.e. it was meant to imply that the end moment of the preceding action should co-incide with the begin of the following action. We now need another connective, indicating whether or not the inspection should be followed by the next action in the text. We write for instance the following algorithm: "fetch the basket from the cellar; fetch the pan from the cupboard; if skirt is light-coloured do put on an apron; peel the potatoes; return the basket to the cellar" .

(For historical reasons the so-called conditional connective {if ... do" is split into two symbols "if" and "do", enclosing the inspection.)

The conditional connective connects two actions, the first of which must be an so-called "inspection". This inspection describes a state of affairs, which may be true or false ("false" is the technical term for "not true"). The happening which is to take place corresponding the conditional compound "if inspection do action" may take one of two mutually exclusive forms: either the inspection gives the result true and it is followed by the action, or the inspection delivers the result false and thereby the whole compound action has been completed. The algorithm derives its superiority over the eye-witness account from the fact that it may contain connectives (such as the conditional connective) that imply a more elaborate sequencing control than the semicolon.

We need a further connective before we can see the full superiority of the algorithm over the eye�witness account, viz. a repetitive connective.

Suppose that we want to express that "peeling the potatoes" is in itself a process that deals with one potato at a time and that, correspondingly, our primitive action is named "peel a next potato". If the number of potatoes to be peeled is a fixed constant, say always 25, then we can replace "peel the potatoes" by 25 times "peel the next potato", separated from each other by in toto 24 semicolons. But we now assume that the number of potatoes to be peeled may differ from one day to the next; yet we want to recognize in each peeling session the same pattern of behaviour. We suppose the housewife capable of looking into the pan and judging whether the amount of peeled potatoes is sufficient.

If we know a priori that in the worst case (i.e. many guests and vary small potatoes) she will never have to peel more than 500 potatoes we can give a general algorithm describing the actual peeling by repeating in the text of our algorithm 500 times (separated by in toto 499 semicolons) the.conditional compound: "if number of peeled potatoes is insufficient do peel a next potato" .

Several objections can be made against this solution. There is the practical objection that it would reduce the construction of algorithms to doing lines. Further- more we had to make the fundamental assumption that we knew in advance a maximum number. Often it is very hard to give such an upper bound a priori and if it can be given, such an upper bound is usually many times larger than the average value. And if in actual fact 25 potatoes have to be peeled, the 26th inspection "number of peeled potatoes is insufficient" �i.e. the first one to deliver the result "false"- gives fresh information, the following 474 inspections (which are prescribed by the algorithm as suggested) give no new information. Once the housewife has established that the number of peeled potatoes is no longer insufficient, she should not be forced to look into the pan another 474 times in order to convince herself!

In order to meet these objections, we introduce a repetitive connective which, again for historical reasons, is written in two parts "while ... do". Using this connective we can write the algorithm: "fetch the basket from the cellar; fetch the pan from the cupboard; if skirt is light-coloured do put on an apron; while number of peeled potatoes is insufficient do peel a next potato; return the basket to the cellar" .

The process corresponding to "while inspection do action" consists of one or more executions of the conditional compound "if inspection do action", viz. up to including the first time that the inspection gives the result "false".

We can also describe the semantics of the repetitive connective in terms of the conditional one recursively: "while inspection do action" is semantically equivalent with "if inspection do begin action; while inspection do action end" . Here the symbols "begin" and "end" are used as opening and closing bracket respectively; they are a syntactical device to indicate to indicate that the conditional connective connects the inspection (from the first line) to the whole of the second line; the value delivered by the first inspection decides whether what is described on the second line (from begin until end) will be done in its entirety or will be skipped in its entirety. [Illegible]

As a final exercise I shall give the algorithm describing the pattern of behaviour of a housewife who -for some obscure reason- is so conditioned that she can only peel an even number of potatoes for the evening dinner: "fetch the basket from the cellar; Fetch the pan from the cupboard; if skirt is light-coloured do put on an apron; while number of peeled potatoes is insufficient do begin peel a next potato; peel a next potato end; return the basket to the cellar". This example is included to show that the same set of primitive actions allows different patterns of behaviour.

The notion of an algorithm is a very powerful one, for a single algorithm "extracts" what a possibly large number of different happenings may have in common. And it does not do so by "abstraction", i.e. by ignoring the detailed differences as would become apparent in the different eye-witness accounts, no, it can describe the single pattern of behaviour to exactly the same degree of detail (i.e. in terms of the same primitive actions). The possibly large number of different corresponding happenings is generated by the different ways of sequencing as might be controlled by the conditional, repetitive (and similar, see later) connectives. Note. In the above I have approached the idea of an algorithm starting my considerations from the class of happenings in which we wanted to discern the same pattern of behaviour. This led besides the semicolon as connective in the text of the algorithm to other connectives such as the conditional connective "if...do" and the repetitive connective "while...do". It is not unusual that the relation between algorithm and computations is approached from the side of the algorithm; such an approach leads already in a very early stage to syntactical considerations as a result of which the connectives are introduced in a somewhat different terminology. Instead of "if inspection do action� people write "if condition do statement".

The part of the text denoted by "if condition do" is then described as "a conditional clause", which is regarded as a prefix that is attached to the "statement". The statement prefixed by the conditional clause can be called "a conditional statement". Similarly, in "while condition do statement" , "while condition do" is called "a repetitive clause" and the statement is called "the repeatable statement". This terminology is so widely used that -in spite of its syntactical origin- I shall not refrain from using it whenever I see fit to do so.

On the one hand we have the algorithm, a finite text, a static, timeless concept; on the other hand we have the corresponding happenings that may be evoked by it, dynamic concepts, happenings evolving in time. The intimate relation between the two -to which we refer by the term "sequencing"- lies at the heart of the algorithmic notion. (It is to this intimate relation to which I refer whenever I stress that the programmer's true activity is "the design of classes of computations.) The notion of an algorithm is admittedly a very powerful one; before going on, however, I shall allow myself a little detour in order to indicate what "price" we have paid for its introduction.

We have stated that we restrict ourselves to happenings taking place in a finite period of time. Whenever an algorithm is followed, a happening is taking place, eventually as a time-succession of primitive actions. It is only realistic to postulate that each primitive action will take a finite period of time, unequal to zero: no action will take place "infinitely fast". This implies that we confine our attention to happenings that are taking place as a time-succession of a finite number of primitive actions.

And now we are beginning to see the price: it is very easy to write down a text that looks like an algorithm but that is not an algorithm in our sense of the word, because the effeort to follow it turns out to be a never ending task, e.g. "while skirt is light-coloured do peel a next potato" . When we assume that the peeling of a next potato does not influence the colour of the skirt, we have just two cases: either the skirt is not light-coloured and the only action taking place is the inspection establishing this fact, or the skirt is light�coloured and will remain so and what the pattern suggests to describe is the peeling of an infinite number of next potatoes. This is usually called "an improper algorithm".

The question, whether a text that looks like an algorithm, is indeed a proper algorithm or not, is far from trivial. As a matter of fact Alan M.Turing has proved that we cannot write an algorithm capable of inspecting any text and establishing whether it is a proper algorithm or not.

The assumption of the existence of such an algorithm leeds to a contradiction which will be sketched below. Suppose that we have such an algorithm, an inspection "proper(L)" which delivers the result true when the text named L is a proper algorithm and the result false when it is improper.

Consider now the following text, named L L: "while proper(L) do whistle once" (in which "whistle once" is assumed to be an available primitive). If we start to follow this algorithm, how many times will be whistled? The assumption that "proper(L)" delivers the result true will cause the algorithm to be improper and vice verse! The conclusion is that no algorithm for the inspection "proper" can exist. (Marvin Minsky concludes in "Computation, Finite and Infinite Machines", Prentice Hall 1967 a formal treatment of this proof with the sentence "We have only the deepest sympathy for those readers who have not encountered this type of simple yet mind- boggling argument before.")

The moral of this story is that it is an intrinsic part of the duty of everyone who professes to compose algorithms, to supply a proof that his text indeed represents a proper algorithm.

Our next fundamental notion is a machine (or "a computer"). A machine is a mechanism capable of causing actions to take place following a pattern of behaviour as can be described by algorithms expressed in terms of a repertoire of primitive actions that belong to this machine.

Above, we have given two algorithms for peeling potatoes, one for a natural number of potatoes and one for only even numbers of potatoes. Both algorithms have been expressed in the same repertoire of primitive actions. They were introduced in the realm of "observing happenings", the one could describe the pattern of behaviour of my left-hand neighbour, the other the one of my rightchand neighbour. Suppose now that my own wife 1) is also capable of performing those primitive actions 2) will accept from me algorithms expressed in these primitives and will follow such en algorithm obediently. Then I can make her peel either as my left-hand neighbour or as my rightrhend neighbour, depending on the algorithm I have supplied to her. Then she is an example of a machine.

A mechanism that can only do one thing (such as one of the most widely-spread automate, the toilet flusher) is not called a machine. Essential for us is the associated repertoire of actions, the ability to accept patterns of behaviour end to behave accordingly.

Machines are mechanical algorithm followers. The fact that in the last decennia increasingly powerful machines have become available to mankind is directly responsible for the increased importance of and interest in algorithms and their composition. Note. It is a trivial matter to compose an algorithm for the fastest machine in the world, a proper algorithm in the theoretical sense of the word but somewhat impractical, as it would take the machine a million years to carry the corresponding process to completion. The claim that "the machine is capable of causing the process to take place" is then somewhat subject to doubt: in actual fact in cannot. In what follows we shalln't be bothered by the distinction between "theoretically possible" and "practically feasible". Not because we are impractical, on the contrary! The point is that in the mean time computers are so powerful that the class of practically feasible computations is by now sufficiently large �to put it mildly!- to make machines very useful and intriguing pieces of equipment, fully worthy of our attention.

We call an algorithm intended to control the behaviour of a machine, a program. In other words, we reserve the name program for those algorithms that are intended for mechanical execution. In the general notion of algorithm we have only required that the repertoire should be "well-understood", without bothering how this understanding is established: if a composer indicates "Andante" (= "going") for a composition in three�four time, he may do so, because, remarkably enough, we may expect this indication to be somehow meaningful for the player. In the case of a machine, the situation is drastically different for a machine is a finite piece of equipment which by its very construction has associated with it a finite, very well defined repertoire and whenevr it is fed with a program it shall behave exactly as prescribed.

The fact that machines are fully obedient slaves has caused complaints from many beginning programmers. Their obedience, they felt, makes programming cruelly difficult, for a trivial mistake in the program is sure to lead to entirely unintended behaviour. The programmer's inability to appeal to "common sense of the machine" has been experienced as one of its major shortcomings. The more experienced programmer learns to appreciate its servile, strict obedience: thanks to it we can instruct it to do something "uncommon"! And this is something you cannot do with a servant who "rounds off" his instructions towards the nearest probable interpretation.

In the preceding paragraphs I have introduced programming as an important activity because now we have machines that can be controlled by programs and for which we have to compose programs when we want to use them, when we want to convert them into the tool solving our problem. But this is not the whole story. A computer is a many-sided thing. For its manufacturer it is primarily a product that he can (hopefully) produce and sell with profit. For many insitutional buyersthe computer is probably primarily a status symbol. For many users it is either a source of endless worries or, as the case may be, a highly useful tool. In University surroundings, the view of the computer as a tool to be used tends to be the predominant one. And there is no denying it: in their capacity of tools the computers are changing the face of the earth (and of the moon as well!). Yet I am comvinced that we underestimate the computer's significance if we confine our appreciation of it to the aspects mentioned. They may cause shocks to the basis of our society, but I believe that in the longer run these will turn out to be but ripples on the surface of our culture. I expect a much more profound influence from the advent of the modern computer and that will in its quality of a gigantic intellectual challenge, unprecedented in the history of mankind.

The computer as piece of equipment presents us with an entirely new combination of simplicity and power, which makes the programming task a unique challenge. When the electronic engineers have done their job properly, they present to the programmer a mathematically trivial piece of equipment. Its instruction code (its "repertoire") can be described perfectly well on a modest number of pages, everything is finite and discrete, there is just no place for mathematically conceptually difficult mathematical notions, such as continuity, infinity, limits, irrational numbers and whatnots. The mathematical basis of programming is just very, very simple, so simple that programming should be easy: it should be aasy to conceive programs, it should be easy to convince oneself that a program is correct and that the machine working under control of it will indeed produce the desired result. From its basic simplicity one derives the intuitive feeling that it should be a trivial matter to keep the happening evoked by one's programs firmly within one's intellectual grip.

But its basic simplicity is only one side of the coin: the other side presents the extreme power (both as regards capacity and speed) of currently available computers. As a result of its extreme power, both the amount of information playing a role in the computations as well as the number of operations performed in the course of a computation, escape our unaided imagination by several orders of magnitude. Due to the limited size of our skull we are absolutely unable to visualize to any appreciable degree of detail what we are going to set in motion and programming thereby becomes an activity facing us with conceptual problems that have risen far, far above the original level of triviality.

It is the possibility to consider realistically effective solutions of any degree of sophistication, combined with our complete intellectual grip on what we are considering, which will deeply influence our ways of thinking and our appreciation of our own thought processes. It has no precedent, for whenever in the past we were faced with something powerful (a storm or an army) we never had effective control over it. (This, for a long time, used to be the definition of "powerful", viz. that we were "powerless" in the face of it!)

Proqramminq Languages and their Implementation. The activity of composing programs is called "programming". In the preceding section we have introduced programs as algorithms intended to control the behaviour of machines and by virtue of the actual existence of such machines, programming is a very practical activity. It is one of the youngest branches of applied mathematics (in the broad sense of the word, i.e. not confined to mathematical physics or numerical analysis), it is as important as the applications in question, it is practical in the sense that it is the programmer's intention that a machine will actually display the behaviour as prescribed by the algorithm. For that reason a conscious programmer should respect the limitations of the (finite) machine. Alternative programs causing a machine to establish the same net result and therefore in that respect equivalent, may differ greatly in what is usually called "efficiency", in the demands they make upon the machine's resources. For many years, efficiency has been used as the sole yard-stick along which to compare the relative quality of alternative programs for the same task. In the mean time programming has turned out to be so difficult, that other quality aspects have gained relative importance, such as the ease with which we can understand a program, can convince ourselves of its correctness or can modify it, etc. Yet, efficiency concerns cannot be ignored and in order to give the reader some feeling for the nature of the limitations he should respect, we shall give in this section an overall view of computing machines and the way in which the execute programs.

In this little monograph we shall confine our attention to sequential algorithms, i.e. algorithms describing what actions should happen in succession, one after the other. Such algorithms have a property for which they have been blamed (and not entirely without justification), viz. that they are often"overspecific" as regards the order in which things have to happen. If two actions, say "A" and "B" have to be dome both, a purely sequential algorithm will prescribe either "A; B" or "B; A" viz. action A in time followed by action B or the other way round. It will not express that the order is immaterial and possibly more serious, it will not express that the two actions are so "non-interfering" with each other that they may take place concurrently, or -to use the jargon- may be done in parallel.

For various reasons I decided to restrict my attention to purely sequential programs. The most obvious reason is to be found in the structure of the machines that are currently available or can be expected to become available in the next years. One or two decades ago, machines used to be purely sequential. In the mean time we have got equipment allowing for a limited amount of parallelism (dual processor machines, independent communication channels etc.) but such pieces of equipment are at best an aggregate of a small number of individual sequential components, In such machines the potential parallelism of activities is exploited by standard control programs (so-called "operating systems"), while the individual user still works in a strictly sequential environment. And it is to the individual user that this little monograph addresses itself.

With the advent of what is called "large scale integration" (being a term from the computer field, its acronym "LSI" is better known!) it seems to become technically feasible to build machines more like "clouds of arithmetic units" with information processing activities going on simultaneously all over the place, for shorter periods of time even undependently of each other. Programming for such machines will pose completely different trade-off problems: one will be willing to invest potentially useful computing activity before its actual usefulness has been established, all for the sake of speeding up the whole computation. But although I know that such machines may be coming, I shall not touch these problems for the following reasons. First, as far as general purpose applications are concerned, I have my doubts about the effectiveness with which such forms of parallelism can ever be exploited. Second -and that is the most important consideration- parallel programming is an order of magnitude more difficult than sequential programming. (This statement will be doubted but I have enough experience in multiprogramming to feel myself entitled to say so. The point is that with parallelism a great variety of happenings may take place under control of the same program(s). On account of undefined speed ratios a set of parallel programs is written for a partly non-deterministic machine and special care is required to ensure that, on a higher level of abstraction, its total behaviour can again be regarded as uniquely determined by the program(s).) Third, I am not over-impressed by the complaints that sequential programs specify a more stringent time-succession than logically necessary: I have often the somewhat uneasy feeling that these complaints find their origin in the mathematical tradition of the pre-computer age. In classical mathematics the notion of an algorithm has been neglected; mind you, I am not blaming the previous mathematicians for this, because before the actual existence of automatic computers, algorithms were hardly a relevant subject. But we should not close our eyes to the fact that the course of history has caused mathematics to be more tuned to timeless problems, to static relations, to functional dependence. (The existence of classical mechanics does not contradict this observation: renaming the independent variable in the differential equations "k", say, instead of the usual "t" does not influence the mathematics involved.) Some of the efforts to remove the overspecification of the time-succession -they rely heavily on functional dependence- strike me as tackling the programming problem with classical concepts that have been developed for other purposes. So much for my decision to restrict my considerations to sequential machines.

To get some feeling for the demands made upon the modern automatic computer, let us focus our attention for a moment upon an average sizeable computation, for instance the computation of (a good approximation of) the inverse of a given matrix of, say, 100 by 100 elements. Such a job has two markedly quantitative aspects: a) a vast amount of numbers is involved: posing the problem implies the specification of 10.000 numbers, the answer is also given by 10.000 numbers (each of which is, in general, a function of all 10.000 elements of the given matrix) b) a vast amount of computation has to be done+ if it is done by elimination, the number of operations (i.e. multiplications and additions) is of the order of magnitude of 1.000.000.

The construction of machines able to cope (reliably!) with these two very different aspects of "multitude" is one of the greater triumphs of electronics. It has been achieved by applying the old and well-known principle "Divide and Rule.". In modern computers one can distinguish two vital components, each of which has the specific task to cope with one of the forms of multitude.

a) the store (called "memory" in American); this is the component able to receive, store and return vast amounts of information; its primary function is to be large, to be able to contain very much information b) the arithmetic unit or processor; this is the component in which the actual work -adding, subtracting, multiplying, comparing, chosing etc.- is done; its primary function is to be very fast so that it may do very much in a limited period of time.

It is not the function of the arithmetic unit to be large in the sense that it should contain large amounts of information. On the contrary: while nearly all the information, relevant for the computation at large, lies "sleeping" in the store, at any moment of time only the tiny fraction actually involved in the information processing activity, is found (copied) in the arithmetic unit, which is only capable of dealing with a few numbers at a time, say the two numbers to be added and the sum formed by the act of addition. Whenever two numbers (in store) are to be added, they are transported from the store to the arithmetic unit, where the sum will be formed; once formed the sum will either be kept in the arithmetic unit for immediate further processing or it will be sent back to store for later processing. Microscopicly, the store acts as the icebox in which all information is kept which is not involved in the current activity of the arithmetic unit. If small letters indicate variables in store and R indicates a register in the arithmetic unit, the computation "x := (a + b)*(c + d)" might be evoked by the following sequence of instructions: R:= a; R:= R + b; t:= R; R:= c; R:= R + d; R:= t * R; x = R

The first instruction fetches the value of a from store into the register R, the next one increases (the contents of) R by the value of b (from store). At this stage one of the two factors to be multiplied has been computed. Before the multiplication can take place, the second factor has to have been computed as well; in e machine with a single register R for arithmetic resulte, this second addition implies again the use of the register R. In order to make this register available for this purpose, the third instruction sends the value of the first factor -a so-called "intermediate result"- back to store, assigning it to a variable hare named "t": the first sum in sent back to store for later usage. The fourth and the fifth instruction compute the second factor the value of which is left in R, ready for multiplication by the temporarily sored value called "t". The last instruction stores the product, now formed in R, so that it can be retrieved under the name "x" for later usage.

The above example illustrates many things. It shows how "x:= (a + b)*(c + d)�" which on one level of interest can be regarded as a single action, on closer inspection turns out to be a sequential process taking place as a time-succession of seven more primitive sub-actions ("program steps"). It also shows that at any moment of time only a tiny portion of the algorithm is in active control of what actually happens+ while the first or the second addition are performed, the fact that the two sums will have to be multiplied is still "dormant". (If the total action would have been "x:= (a + b)/(c + d)" the only modification necessary would have been the replacement of the sixth instruction by "R:= t / R" , the first five instructions would have been insensitive to this change. That is what I menat by "dormant".)

It also demonstrates that, just as at any moment of time, only a tiny fraction of the num?erical information is involved in actual processing, also only a tine fraction of the program exercises control, viz. the instruction currently executed.

It also demonstrates that it is no good just to divide the machine into two components, store and arithmetic unit, one must also provide for a (dense) information traffic between the two: this is provided for by what connects the two together, the so-called "selection"".

We have said that the store should be able to strore information, it must, for instance, be able to store "numbers", e.g. the intermediate result called "t". Obviously, these numbers cannot be kept in store like balls in an urn; when the instruction "R:= t * R" has to be executed, the store must return not just any number, but quite definitely it must return the value sent to it two instructions before. For that reason the numbers in store are not arranged as balls in an urn, on the contrary! Store is arranged as a number of so-called "storage cells", each capable of holding the value of one number at a time. Each storage cell is identified by its so-called "address", each time contact with the store is required -either to receive or to return information- this request is accompanied by a statement of the address of the storage cell involved. If the store is to receive information -this is called "writing into store"- the value to be stored and the address of the storage location involved (plus a "write request") are sent to store and selection respectively; as a result of the writing operation the original contents of the storage cell, which gets lost, are replaced by the new value. If the store is to return information -this is called "reading from store"- the address of the storage cell involved (plus a "read request") is sent to the selection; as a result the contents of the storage cell are returned from store (and kept in the storage cell as well for later reading if desired). As far as destruction, reception and reproduction of the information contained in a storage cell are concerned, the situation shows great analogy to a tape in a tape recorder. You can use the tape to record as many pieces of music as you want, but only one at the same time: whenever you record a new piece of music on an old tape, its previous contents are wiped out; the piece of music currently recorded, however, can be played back as many times as you wish. (To make the analogy a true one, we must restrict ourselves to pieces of music of equal duration, just matched to the length of the tape, matched to its (finite) information capacity.)

Storage cells can store information by virtue of the fact that they can be in a finite number of distinct states. In practically all computers they are composed from elementary components, each of which can be in one of two possible states. (The most common form is a little ring of ferromagnetic material that will be circularly magnetized in one of the two possible directions.) One such component can be in 2 different states (say "North" and "South"), two such components can be together in 4 different total states ("North-North", "North-South", "South-North" and "South- South"), N such components together can be in 2N mutually different states. The number of elementary components associated with each storage cell is a characteristic constant of the machine's store and is called "the word length". If the word length is 32, the number of different possible total states per word is 2³², i.e. slightly over 4*1O⁹; the arithmetic unit will associate with each state a numerical value, in terms of these numerical values a storage cell can then hold, for instance, any integer value ranging from (roughly) -2*1O⁹ to +2*1O⁹.

The finite capacity of the storage cell is something the user must be aware of: it is matched to the abilities of the arithmetic unit, i.e. if the latter deals with integer values it is geared to operations up to a certain maximum value, if it deals with (approximations of) real numbers, it is geared to dealing with them in a certain precision, maximum absolute value and precision respectively being chosen such that the numerical values to be distinguished between can be stored in one (or possibly two successive) storage cells. If greater integers or reals in higher precision have to be manipulated, special measures have to be taken which will be more expensive.

In the mean time we have explained enough about the general machine structure to mention two aspects of the "costs" involved in the execution of a program. One of them is computation time. We have seen that the arithmetic unit performs one operation after the other, and the more operations a program prescribes, the longer the total amount of time the arithmetic unit will have to spend to carry the compu- tation to completion. The other one is storage usage. If a thousand values have to be computed in order to be added together, we may compare the following two algorithms The first one first computes all thousand values and stores them, after which they are added, the second algorithm immediately adds each number to the partial sum as soon as it has been computed. With regard to storage usage the first algorithm is more demanding: at some stage of the computation it requires a sufficient amount of store to hold all thousand values, an amount of store which in the second algorithm remains available For other (possibly more useful) purposes.

So much for the finite capacity of each storage cell and the fact that a store contains only a finite number of such cells. Let us return to their addresses: a while ago we have hinted that each storage cell is identified by an "address" and that each reference to store takes place under control of the address of the storage cell concerned, but up till now we have not been very explicit about what an address really is. Well, this is very simple: the storage cells are numbered: O, 1, 2, 3, 4, 5, ...... up to M-1 if the store comprises M different storage cells (M between 16.000 and 1.000.000 being typical figures), and the ordinal number of each storage cell is used as "its address" (like houses in a street!). This implies that the storage cells have a natural order, viz. the order of increasing address. Given the address of a storage cell, the address of the next storage cell can be computed by adding 1 to the given address of the preceding one.

This natural oredring of storage cells is heavily exploited. If a vector, i.e. a sequence of numbers a₀, al, ... , an has to be stored, its elements can be stored in successive storage cells. If the address of the element a₀ is known, the address of element ai can than be computed, viz. by adding (the value of) i to the address of the element a₀.

The natural order of the storage cells is also exploited in the program representation. Mind you, we have postulated that a machine could "accept" a program and that, once the program had been accepted, the machine could execute the program (i.e. cause the happening as prescribed by the program to take place). In other words, when the machine is executing the program, this program -i.e."the information describing how to behave"- must be somewhere in the machine! Where? Well, in the store, the store being specifically the machine component able to hold information. In other words, the store is used for two different purposes: it holds the numerical information to be manipulated, but it also holds - in some other part of it- the program, i.e. the information describing what manipulations have to be performed.

To sketch briefly how this can be done, we return to our previous example where "x:= (3 + b)*(c + d)" was decomposed into the sequence of seven instructions denoted by "R:= a; R:= R + b; t:= R; R:= C; R:= R + d; R:= t * R; x:= R" and the question is: by means of what conventions do we represent the above information in a store capable of holding numbers? This is achieved by a two-stage convention, one for representing single instructions and one for representing a sequence.

The first convention is to chose for each instruction a unique number code. In the above notation we have denoted variables (or: the addresses of the storage cells associated with the variables and containing their current value) with small letters (a, b, c, d, t and x); but addresses are numbers and that component therefore is already numerical. Using "s" for "any address", we see that in the above example, we can distinguish instructions of four different types: 1) R:= s 2) R:= R + s 3) R:= s * R 4) s:= R The second part of the convention associates with each type of instruction a number (e.g. the numbers 1, 2, 3 and 4 to the types shown above; it should be mentioned that in actual machines the number of instruction types is considerably larger than 4). By concatenating the digits describing the instruction type number with those giving the address we have a number code for each possible instruction and we assume that the word length of the storage cell is sufficient to contain such a number. The first convention as just described, reduces the problem of storing a sequence of instructions to storing a sequence of numbers. Now the second convention is that the sequence as such is represented by storing these number in successive storage cells, i.e. storage cells with successive addresses. And this completes (roughly) the trick.

(Note: This is by no means the only way to represent programs inside the machine's store; in so-called "stack machines" other conventions are chosen. The above elaboration is only shown by way of example, demonstrating the possibility.)

The dual role of the store -storage of instructions and storage of variables� implies another way in which a program can be expensive to execute: if the program text is vary long, by that very fact the program text will make a heavy demand on storage capacity. If we have two alternative programs for the same job, one requiring 5O00 instructions to describe it and the other requiring 10000 instructions to describe it, then -all other things being equal- the first alternative will be cheaper.

The above concludes our bird's eye view of the so-called hardware machine, i.e. the physical piece of electronic equipment as it is delivered by the manufacturer: a machine that can accept and then execute programs written as long sequences of instructions from an instruction repertoire that is specific for this particular machine (and its copies). Until the late fifties programmers indeed produced their programs as long sequences of such instructions, but when machines became faster and when more came on the market, the shortcomings of this way of working became more and more apparent.

Because the programmer expressed his program in terms of the instruction repertoire of that particular machine, he was faced to tailor his program to that machine. He needed a thorough and ready knowledge of all the details of the instruction repertoire of that machine -which for the more intricate machines was no mean task- and worse: once his program was written, it could only be executed by that particular machine. Exchange of programs between institutes equipped with different machines was impossible; furthermore, whenever an institute replaced its old machine by a new and different one, all programs for the old machine became obsolete. From that point of view it was clear that tailoring one's programs so closely to the idiosyncrasies of a specific piece of hardware was not a very wise investment of the intellectual energy of one's programmers.

But even without the problem of transferring programs from one hardware machine to another, this way of programming, expressing programs as a monotonous stream of machine instructions, showed great drawbacks. One serious drawback was that this close contact between programmer and physical machine structure did not only enable the programmer to lard his program with all sorts of coding tricks, it actually invited him to do so. For many a programmer this temptation became irresistible, there even has been a time-when it was generally believed that one of the most vital assets of a virtuoso programmer was that he be "puzzle-minded", and it was only slowly recognized that a clear and systematic mind was more essential! When "tricky programming� was en vogue, programming was not only very expensive -it took too much time- it also turned out to be too difficult to get a program correct. Looking backwards, the period of tricky programming now strikes us as a generation of programmers walking on a tight-rope, in full confidence because they were unaware of the abysmal depth beneath it! The modern competent programmer is more humble and avoids clever tricks like the plague.

It was not only the preponderance of coding tricks that made programming "in machine code" as it is called nowadays, too difficult and too risky.

Firstly, a program in machine code contains very little redundance and as a result it is very sensitive to even small writing errors -errors of the level of "spelling mistakes" or "printing errors".

Secondly, the programmer who thinks in terms of variables has to denote these variables in his program text by the addressee of the storage cells dedicated (by him) to hold their values. As a reault the programmer has the burden of storage layout and all the clerical work implied by this.

Thirdly -and this is the major reason- machine code is an improper vehicle to represent "structure": it is just a single, monotonous sequence of machine instructions, incapble of expressing in a direct and useful form the structure of the algorithm. In what follows it will become abundantly clear that when we wish to compose programs in a reliable fashion, we can only do so by structuring the happenings we intend to evoke and are in urgent need of a descriptive vehicle such that in the program text itself the structure of the happenings -i.e. of the computations� can be adequately reflected.

The above shortcomings led to the design of so-called "(higher level) programming languages". A programming language can be regarded as the machine code for a fictitious, idealized machine. Whereas the old machine codes were tailored to the needs of the hardware �i.e. the equipment electronic engineers could make- programming languages are more tailored to the intellectual needs and conceptual difficulties of the programmer who has to design the computations

The problem now is that on the one hand we have the hardware machine A, that can be built but for which we don't like to program because it is too cumbersome, on the other hand we have "dreamed up" the fictitious machine B, for which we would love to program but which the engineers cannot build. How do we bridge that gap?

The gap is bridged by "software": given machine A, we can make, once and for all, a program (in the machine code for machine A) which prescribes to machine A the pattern of behaviour it should follow if it is to simulate machine B. Such a program is called "software for machine A". Given hardware A, loaded with this software, we have a mechanism �partly "hard", partly "soft"- that is able to execute programs written for the fictitious machine B.

Usually this combination of hard- and software processes such a program in two stages. In the first stage (the "translation stage") the program written in the programming language B is subjected to a translation process. In this process a storage layout is decided, the necessary bookkeeping is carried out and an equivalent program -but now expressed in machine code A� is produced. In the second stage (the "execution stage") the output of the first one is interpreted by machine A as a program and the intended computation is evoked.

The standard software that goes with the machine shields the user off from idiosyncrasies of the specific machine; apart from that it invokes -behind the user's back, so to say- standard ways of dealing with the tougher properties of the hardware, such as the possible parallellism (i.e. concurrence in time) of computation proper and information transfers from and to peripheral devices and multilevel stores. Up till now we have described the hardware as if all storage cells were equally well accessible for the arithmetic unit. In practice this is seldom the case, two storage levels being quite common: primary store {ferrite cores usually) and secondary store (magnetic drums usually). The cells in primary store are the only ones that are directly and immediately accessible for the arithmetic unit; the informtaion in secondary store (which in capacity is an order of magnitude larger than primary store) is not directly accessible for the arithmetic unit, but the possibility of bulk transfers between primary and secondary store is available instead. In such machines, the software may move the information around between the two stores, all the time keeping track of where everything is to be found at any moment and trying to keep in primary store all "currently relevant" information. (This is called "the implementation of a virtual store.

We have mentioned the concept of the virtual store because it is related to an efficiency aspect over which the programmer has some control and in regard to which the programmer therefore has some responsibility. This is called "vagrancy". A program has a small degree of vagrance whenever for larger periods of time accesses are confined to a small, dense subset of the total amount of information; in that case the hope is justified that during that period of time, this dense subset will be kept in primary store and that therefore the computation can go on at full speed. In computations with high vagrancy, the probability of information needed being in secondary store is much larger and the transport facilities between the storage levels then tend to become the bottle-neck. Therefore, if possible, high vagrancy should be avoided.

Variables and relations between their values.

When introducing the basic notions we have said that different happenings could take place following the same pattern of behaviour. And as the happening. is fully determined by the confrontation of the pattern of behaviour with the initial state, it follows that the same pattern of behaviour can only evoke different happenings at different occasions when at these different occasions the initial states differ from each other. In this section we shall show how so-called variables are used for the description of the (initial and final) states. We find the typical use of variables when the same pattern of behaviour is followed repeatedly, i.e. when sequencing is repetitively controlled.

We begin with a very simple program: given two positive integer values A and B, a program has to be made that will compute (i.e. can cause a conputer to compute) the Greatest Common Divisor of A and B. Let us use the notation GCD(A, B) for that value.

(Remark. We have restricted ourselves to positive numbers in order to make life somewhat easier. Zero is divisible by any positive integer d (for 0 = 0 * d), and there would be no objection, with B > 0, to GCD(0, B) = B .

But admitting zero as argument is asking for trouble, because GCD(0, 0) is clearly undefined! In order to avoid these complications, we restrict our- selves to positive arguments.)

For the sake of argument we request an algorithm in which no arithmetic operations other than addition and subtraction will be used. How do we find such an algorithm?

Well, there seem in this case two ways to attack the problem. The first one is more or less a direct application of the definition. One could construct a table of divisors of A (including 1) and a table of divisors of B [also including 1); es both A and B are finite and different from zero, both tables contain only a finite number of numbers. From these two tables of divisors one can construct a third table of common divisors, i.e. containing all the numbers occurring in both of them. This third table is non-empty (because it contains the number 1) and it is finite (because it cannot be longer than any of the original tables). From this non-empty, finite table we can select the greatest number and that will, by virtue of the way in which it has been found be the Greatest Common Divisor.

We could do it along the lines just sketched (or at least use it as a source of inspiration). In the current example, however, there is a second way of attack because the GCD is a well-known mathematical function, well-known meaning that a number of its properties are known. If we can think of so may of its properties that they define the GCD -i.e. that the GCD is the only function satisfying them- we might try to determine GCD(A, B) by exploiting these properties. What properties can we think of? 1) GCD(a, b) = GCD(b, a) 2) GCD(a, b) = GCD(a + b, b) = GCD(a, a + b) 3.1) if a > b: GCD(a, b) = GCD(a - b, b) = GCD(a, a - b) 3.2) if a = b: GCD(a, b) = a = b 3.3) if a < b: GCD(a, b) = GCD(a, b - a) = GCD(b - a, b) (We can think of other properties such as 4) for n≥0 GCD(an, bn) = GCD(a, b)n 5) for c>0 GCD(c * a, c * b) = c * GCD(a, b) but they look less promising as they involve multiplication and we have to restrict ourselves to the arithmetic operations of addition and subtraction.)

The first property states that GCD is a symmetric function. The second one states that the GCD of two numbers is equal to the GCD of one of them and the sum, while the third property states this for the difference. Because we want to restrict ourselves to positive numbers, we have dealt with the cases a < b and a > b separately. The case a = b, however, is very special: it is the only case in which the value of the GCD is given directly!

Relations 2, 3.1 and 3.} tell us that the GCD of a pair of numbers is equal to the GCD of another pair of numbers. This suggests that we use the "current state" to fix such a number pair; the algorithm can then try to change these numbers in such a way that firstly: the GCD remains constant secondly: until eventually the two numbers are equal and rule 3.2 can be applied.

With the second requirement in mind, rule 2 does not look to promising: given two positive numbers, one of them can never be equal to their sum. On the other hand, given two (different!) positive numbers, one of them, viz. the. smallest, can be equal to their difference. This suggests that from 3.1 and 3.3 we use: 3.1' if a > b: GCD(a, b) = GCD(a - b, b) 3.3' if a < b: GCD(a, b) = GED(a, b - a) .

Now the moment has come to consider our first version of the program: program 1: begin integer a, b, gcd; a:= A; b:= B; while a ≠ b do if a > b then a:= a - b else b:= b - a; gcd:= a; print(A); print(B); print(gcd) end

(In this program we have used the well-known alternative connective "if...then...else". The construction "if inspection then action1 else action2" causes one of the two actions, either action 1 or action 2 to take place. If the inspection delivers the value true, action1 will take place (and action2 will be skipped) if the inspection delivers the value false (action1 will be skipped and) action2 will take place. We can describe the conditional connective in terms of it:

"if inspection do action" is equivalent with "if inspection then action else nothing".)

When we try to understand this program we should bear the following in mind: | While the typical use of variables manifests itself with the | program loop, the way to understand such a program implies | looking for the relations between their values which remain | invariant during the repetition. In this example the invariant relation P is P: a > 0 and b > 0 and GCD(a, b) = GCD(A, B) .

The relation P holds after initialization (for the a = A and b = B; from A > 0 and B > 0, relation P then follows).

The repeatable statement will only be executed under the additional condition a ≠ b; i.e. either a < b or a > b. If a > b, then the new value of a, viz. a - b, will again be positive and GCD(a, b) will remain unchanged on account of 3.1'; if a < b, then the new value of b will again be positive and GCD(a, b) will remain unchanged on account of 3.3'. The invariance of relation P is therefore established.

When the loop terminates, a = b is guaranteed to hold, GCD(A, B) = GCD(a, b) = GCD(a, a) and on account of 3.2 the assignment "gcd:= a" will establish the net effect "gcd:= GCD(A, B)".

To complete the proof we must demonstrate that the repetition will indeed terminate. Whenever the repeatable statement is executed the largest of the two (different!) values is decreased by the value of the other which is positive; as a result max(a, b)T0> max(a, b)T1 We also know that before the repetition max(a, b) = max(A, B) is finite, from the invariance of relation P (a > 0 and b > 0) we conclude that max(a, b) > 0 will continue to hold. All values being integer, the maximum number of times the repeatable statement can be executed must be less than max(A, B) and therefore the repetition must terminate after a finite number of repetitions. And this completes the proof.

Once we have this program, it is not difficult to think of others. Reading program 1 we observe that each subtraction is preceded in time by two test, first a = b and then a > b; this seems somewhat wasteful as the truth of a > b already implies the truth of a ≠ b. What happens in time is that a number of times a will be decreased by b, then b will be decreased a number of times by a, and so on. A program in which (in general) the number of tests will be smaller is

program 2: begin integer a, b, gcd; a:= A; b:= B; while a ≠ b do begin while a > b do a:= a - b; while b > a do b:= b - a end; gcd:= a; Print(A); print(B); print(gcd) end Exercise Prove the correctness of program 2. Exercise Rewrite program 2 such that the outer repeatable statement contains only one loop instead of two.Prove its correctness.

Before going on, it is desirable to give a more formal description of the kind of theorems which we use. (In the following I shall make use of a formalism introduced by C.A.R.Hoare.)

Let P, P1, P2, .... stand for predicates stating a relation between values of variables. Let S, S1, S2, ... stand for pieces of program text, in general affecting values of variables, i.e. changing the current state. Let B, B1, B2, ... stand for either predicates stating a relation between values of variables or for pieces of program text evaluating such a predicate, i.a, delivering one of the values true of false without further affecting values of variables, i.e. without changing the current state.

Then P1{S}P2

means: "the truth of P1 immediately prior to the execution of S implies the truth of P2 immediately after that execution of S". In terms of this formalism we write down the following theorems. (Some readers would prefer to call some of them rather "axioms", but at present I don't particularly care about that difference.) Theorem 1: Given: P1{S1}P2 P2{S2}P3 Conclusion: P1{S1;S2}P3

(This theorem gives the semantic consequences of the semicolon as connective.)

Theorem 2: Given: B{S}nonB Conclusion: true{if B do S}nonB

(Here "true" is the condition which is satisfied per definition, i.e. the conclusion that after the execution of the conditional statement "nonB" will hold, is independent of any assumptions about the initial state.)

Theorem 3: Given: (P and B) {S} P Conclusion: P {if B do S} P

Theorem 4: Given: (P1 and B) {S1}P2 (P1 and non B) {S2}P2 Conclusion: P1{if B then S1 else S2} P2

Theorem 5: Given: (P and B {S} P Conclusion: P {while B do S} (P and non B) Remark: This theorem only applies to the case that the repetition terminates, otherwise it is void.

Theorem 5 is one of the most useful theorems when dealing with loops. The appropriate reasoning mechanism to deal in detail with loops is mathematical induction, but often the use of Theorem 5 -which itself can only be proved by mathematical induction- avoids a direct use of mathematical induction.

We used Theorem 5 when proving the correctness of program 1. Here was P: a > 0 and b > 0 and GCD(a, b) = GCD(A, B) and B: a ≠ b .

We draw attention to the fact that we could not show "P {S} P" but only "(P and B){S} P": for a and b to remain positive it was necessary to know that initially they were different. (How is this with program 2?) We also draw attention to the fact that after termination when we wished to show that a = GCD(A, B) we did not only use the mild conclusion "P {while B do 5} P" but the strong conclusion "P {while B do S}(P and non B)": we needed the knowledge "a = b" in order to justify the application of 3.2. With respect to termintation one often uses a somewhat stronger theorem, the formulation of which falls outside the strict Hoare formalism:

Theorem 6: Given: (P and B){S} P Conclusion: in P {while B do S} will (P and B) hold immediately after each execution of the repeatable statement which is not the the last one. This theorem usually plays a role when deriving a contradiction from the assumption that the loop will not terminate.

* * *

There is an alternative form of repetition control which might be represented by "repeat S until B" (other authors write "do S until B"); it is semantically equivalent to "S; while non B do S" . (Instead of describing its semantics in terms of the other repetitive connective, we could also have given a recursive definition in terms of itself, viz. "S; if non B do repeat S until B" .)

The differences with the while-clause are 1) the termination condition has been inverted 2) the repeatable statement is executed at least once.

Sometimes the repeat-clause comes in really handy and gains the text in clarity when it is used. It should be used with great precaution, a precaution which is shown by the pertinent

Theorem 7: Given: P1 {S} P2 (P2 and non B){S} P2 Conclusion: P1 {repeat S until B}(P2 and B) Remark: This theorem only applies to the case that the repetition terminates, otherwise it is void.

The greater complexity of the assumptions about B and S which have to be verfied, reflect the additional care required in the use of the repeat-clause.

Exercise. We know give three tentative alternative programs (3, 4 and 5) for the computation of GCD(A, H). Discover which of them are correct and which are faulty by trying to prove their correctness. If the program is incorrect, construct an A,B-pair for which it fails.

program 3: begin integer a, b, gcd; a:= A; b:= B; repeat if a > b then a:= a - b; else b:= b - a until a=b; gcd:= a; Print(A); print(B); print(gcd) end

rogram 4: begin integer a, b, gcd; a:= A; b:= B; repeat while a > b do a:= a - b; while b > a do b:= b - a until a=b; gcd:= a; Print(A); print(B); print(gcd) end

program 5: begin integer a, b, gcd, x; a:= A; b:= B; while a ≠ b do begin if a < b do begin x := a; a := b; b := x end repeat a := a.b until a ≤ b end gcd:= a; Print(A); print(B); print(gcd) end (Note. If any of the above programs is correct, its occurrence in this exercise is not to be interpreted as a recommendation of its style!)

Exercise. Prove that the following program will print in addition to the greatest common divisor of A end B the smallest common multiple of A and B (being defined as their product divided by the greatest common divisor).

begin integer a, b, c, d, gcd, scm; a:= A; b:= B; c:= B; d:= O; while a ≠ b do begin while a > b do begin a:= a - b; d:= d + c end; while b > a do begin b:= b - a; c:= c + d end end; gcd:= a; scm:= c + d; print(A); print(B); print(gcd); print(scm) end

Hint. Follow the value of the expression a * c + b * d. (Courtesy Software Sciences Holdings Limited, London)

* * *

For a meaningful loop controlled by a while-clause we can make the following further observations. Let us consider the loop "while B do S".

Our first observation is that the execution of the repeatable statement must change the state. Suppose that it does not. If then the repeatable statement is executed once, the predicate B (that was true prior to its execution) will still be true after its execution so that the statement S will be executed still another time; then the argument can be repeated and the net result is that the repetition will not terminate. The only termination is when B is false to begin with: then the statement S will be executed zero times. This we don't call "a meaningful loop".

So, execution of statement S changes the state: let us call "s" that part of the total state that may be changed by the execution of statement S. Here "s" can be regarded as the aggregate of variables whose values can be affected by the execution of statement S. Then our seond observation is that (one or more variables of) s must be involved in the predicate B. If not, a single execution of the repeatable statement would imply infinitely many (by the same argument as used in our previous observation). Treating "s" as a generalized variable, we can express this explicitly by rewriting the loop, using two functions of the generalized argument s: "while B(s) do s:= S(s)" .

This is the basic form of every repetition which is controlled by a while-clause. Reading it, it is obvious that its behaviour is undefined when the initial value of s is completely undefined. In terms of programming this leads to our third observation: | Every repetition controlled by a while-clause requires a proper | initialization of the variables involved. (Although obvious, this rule is mentioned explicitly, because I have seen many programmers forgetting to initialize properly. The rule is so rigid that such an omission is not a mistake but a blunder.)

Let the initial state be denoted by s₀ and let the state immediately after the i�th execution of the repeatable statement be denoted by si ; let the loop terminate after the k-th execution of the repeatable statement. Then the following theorems are true.

Theorem 8: Given s₀, the remaining successive values of s are given by the recurrence relation si = S(s i-1) for 0 < i ≤ k.

Theorem 9: In the sequence s₀, s₁, ... , sk, no two values (with different subscripts) are equal.

Theorem 10: B(si) for all i satisfying 0 ≤ i < k and non B(sk)

Theorem 8 is fairly obvious. It is mentioned, however, because it shows that a repetition is an adequate tool for the evaluation of a recurrence relation

Theorem 9 is mentioned because it is so obviously correct (although I see no use for it).

Theorem 10 -also called "The Linear Search Theorem"-which is also fairly obvious, is a very important one, comparable in importance to Theorem 5. It does not only assert that after termination the state sk will be such that non B is valid, it asserts that in all previous states si with i < k (if any) B did hold. This theorem is used in many searching algorithms looking for the smallest number for which a predicate B is false: by inspecting the numbers in the order of increasing magnitude, the smallest becomes the first found. Theorem 10 tells us that in that case a loop controlled by a while-clause is a proper vehicle. (It is not restricted to looking for e smallest number, it can be applied to any (somehow) ordered set of values of some sort.)

Remark. We have called the last three theorems "obvious". This is not meant to imply that giving a reasonably formal proof for them is trivial. I did it, but the resulting proofs were surprisingly cumbersome and boring.

Finally. in Theorems 2, 3 and 5 we always have assumptions including the truth of B prior to the execution of S. Clearly we are not interested in the net effect of the execution of S after an initial state in which B is false. As a matter of fact, with such initial states the net effect of an S will often be undefined. (A similar remark can be made regarding Theorem 4.) In other words: our statements S regarded as operators are often not defined on the domain of all possible states, they are "partial operators" and the predicates occurring in the clauses ensure that they will not be evoked inappropriately. This observation should temper our hope of increasing computation speed by introducing more parallellism.

Programs corresponding to recurrence relations. Theorem 8 mentions successive states connected by a recurrence relation. The meaning of this theorem is twofold: it can be used to prove assertions about a given program, but also -and this, I think, is more important- it suggests us, when faced with the task of making a program, the use of a while-clause in the case of a problem that in its mathematical formulation presents itself as the evaluation of a recurrence relation. We are going to illustrate this by a number of examples.

Consider the sequence of pairs ai, ci given by for i = 0 a₀ = 1 (1) c₀ = 1 - b , with 0 < b < 2 (i.e. abs(c₀) < 1) for i > 0 ai =(1 + ci-1)* ai-1 (2) ci = ci-1 . Then lim ai = 1/b i → ∞

Exercise. Prove the last formula. (This has nothing to do with programming, it is secondary school algebra. The clue of the proof is to be found in the relation 1 1 + ci-1 --------- = ---------- .) 1 - ci-1 1 - ci

It is requested to use this recurrence relation to approximate the value of 1/b; obviously we cannot compute infinitely many elements of the sequence a₀, a₁, a₂, ... but we can accept ak as e sufficiently close (how close?) approximation of 1/b when ck is less than a given, small, positive tolerance named "eps". (This example is of historical interest; it is taken from the subroutine library for EDSAC 1, the world's first stored program controlled automatic computer. The order code of this computer did not comprise a divide instruction and one of the methods used with this computer to compute quotients was based on the above recurrence relation.) -

Theorem 8 talks about "a part, s, of the state space" and the loop while B(s) do s:= S(s) and asserts that after the initial state s₀ the states si after the i-th execution of the repeatable statement will satisfy si = S(si-1) (3)

Our recurrence relations (2) are exactly of the form (3) if we identify the state si with the value pair ai, ci. That is, we have to introduce, to span the part s of the state space, two variables, for the purpose of this discussion called A and C, and we shall denote their values after the i-th execution of the repeatable statement by Ai and Ci respectively. We associate the state si (as given by the values Ai and Ci) with the value pair ai, ci by the relations Ai = ai (4) Ci = ci .

(Mind you: in the left hand sides the subscript "i" means "the value of the variable after the i�th execution of the repeatable statement", in the right hand sides the subscript "i" refers to the recurrent sequences as given by (1) and (2). It would have been usual to call the two variables "a" and "c" instead of "A" and "C", i.e. not to distinguish between the quantities defined in the mathematical formulation on the one hand and the associated variables in the program on the other hand. As this association is the very subject of this discussion, it would have been fatal not to distinguish between them.)

Within the scope of a declaration "real A, C" it is now a straightforward task to write the piece of program: "A:= 1; C:= 1 - b; while abs(C) > eps do +-------------------+ begin A:=(1 + C)* A; | A / (1-C) = 1 / b | C := C * C +-------------------+ end" .

The first line has to create the proper state s₀ and does so in accordance with (4) and (1), the repeatable statement has the form, symbolically denoted by "s:= S(s)" -see the Note below- in accordance with (4) and (2), and the condition guarantees that after termination (Ak=) A = ak will hold with the proper value of k.

Exercise. Prove that the loop terminates. Note. The symbolic assignment "s:= S(s)" has the form of two assignments A:= (1 + C)* A; C:= C * C; . With the initial condition A = ai-1, C = ci-1 the First assignment is equivalent to A:= (1 + ci-1)*ai-1 and after the first, but before the second assignment we have �on account of (2)- A = ai, C = ci-1 . Only after the second assignment we have the complete pair A = ai, C = ci .

Thanks to the explicit occurrence of the subscripts the order of the two relations composing (2) is immaterial, this in contrast to the two assignment statements composing the repeatable statement, whose order is vital!

Exercise. In the same EDSAC subroutine library the next scheme is used. Consider the sequence of pairs ai, ci , given by for i = 0 a₀ = b c₀ =1- b with 0 < b < 2 (i.e. abs(c0) <1) for i > 0 ai = (1 + .5 * ci-1)* ai-1 ci = c²i-1 *(.75 + .25 * ci-1) then lim ai= b.5 i → ∞

Prove the last Formula and make a program using it for the approximation of the square root. The clue of the proof is to be found in the relation (1 - ci-1)-.5 = (1 + .5 * Ci-1) * (1 - ci)-.5 . Prove also the termintation of the repetition in the program made.

Exercise. In the same EDSAC subroutine library the next schema is used. Consider the sequence of triples inci, si, xi given by for i = 0 inc₀ = log 2 s₀ = 0 xi = arg (with 1 ≤ arg < 2) for i > O for x²i-1 < 2 inci = .5 * inci-1 si = si-1 xi = x²i-1 for x²i-1 ≥ 2 inci = .5 * inci-1 si = si-1 + .5 * inci-1 xi = .5 * x²i-1 . then lim si = log(arg) i → ∞

Prove this relation and make a program using it to approximate the logarithm of a value arg in the interval stated. (In this program "log 2" may be regarded as a known constant which, in fact, determines the base of the logarithm.)

The clue of the proof can be found in the invariance of the relation log(arg) = si + inci * log(xi) / log 2 .

Our next example is very simple; it is so traditional that we could call it standard. (No self-respecting programming course omits it, it is often the very first example of a loop; Peter Naur uses it in his article "Proof of algorithms by general snapshots", 1966, BIT, 6, pp 310-316.) Given a sequence of values a[1], a[2], a[3], , a[N] (with ≥ 1) and a variable called "max". Make a piece of program assigning to the variable named "max" the maximum value occurring in the sequence. (As N ≥ 1, the sequence is not empty and therefore the task makes sense; it is not required that any two values in the sequence differ from each other, the maximum value sought may occur more than once in the sequence.) If he welcomes the experience the reader is invited to try to make this piece of program himself before reading on.

How do we define the maximum value occurring in a sequence of length N for general N ≥ 1? If we call "maximumk" the maximum value occurring among the first k elements a[1], ... , a[k] 1) the ansewer sought is maximumN 2) the values maximumk are given for k = 1 by the base: maximum₁ = a[1] (5) -appealing to the knowledge that the maximum element in a sequence of length 1 must be the only element occurring in the sequence for k > 1 by the recurrence relation: maximumk = MAX(maximumk-1, a[k]) (6) �assuming the knowledge of the function MAX of two arguments.

The recurrence relation (6) presents us with an additional difficulty because it is not of the form si = S(si-1) because -via "a[k]"- the value k occurs at the right hand side not exclusively in the subscript "k-1". To overcome this we use a trick that might be called a method. If we call nk the k�th natural number, then nk = k; the numbers nk the obvious recurrence relation nk = 1 + nk-1 We can now rewrite the definition for the sequence of values maximumk in the form of a definition for the pairs (nk, maximumk): for k = 1 n₁ = 1 (7) maximum₁ = a[1] for k > 1 nk = 1 + nk-1 (8) maximumk = MAX(maximumk-1, a[1 + nk-1]) and now the recurrence relations are of the form s, = S(si-1), the only -trivial� difference being that in Theorem 8 we started with i = 0 and here with k = 1. The trick we called a method shows that we need a second (integer) variable; call it "m". Our state si will associate (with k = i + 1) maxi = maximumk mi = nk .

The piece of program now becomes: max:= a[1]; m:= 1; while m < N do begin m := m + 1; max:= MAX(max, a[m]) end . Again the order of the two assignment statements is essential.

We have given the above piece of reasoning and the explicit reference to the recurrence relation of Theorem 8 because it shows a mechanism leading the the conclusion that the part s of the state space on which the repetition operates needs to comprise an additional variable. Even a moderately trained programmer draws this conclusion "intuitively" and from now onwards I shall assume my reader equipped with that intuition. Then -and only then!- there is e much shorter path of reasoning that leads to the program we found. It does not consider �"statically" so to speak- the sequence of values s₀, s₁,... in the sense that it bothers about the values of the subscript i in si. It appeals directly to Theorems 5 and 6 and works in terms of assertions valid (before or after) any execution of the repeatable statement. The price to be paid for this is the duty to prove termination separately.

Given the base k = 1 maximum₁ = a[1] and the step 1 < k ≤ N maximumk = MAX(maximumk-1 , a[k]) the programmer "intuitively" introduces two variables which he calls "maximum" and "k" for short and the relation to be kept invariant is P: 1 < k ≤ N and maximum = maximumk . (Here any use of "maximum" and "k" stands for the current value of the variable thus named, while "maximumk" stands for the value as given by the recurrence relation. This double use of the same names is tricky but programmers do it. I too.)

The program then consists oF two parts: establishing relation P in accordance with the base and repeatedly increasing k under invariance of relation P, i.e. in accordance with the step. The initialization "maximum:= a[1]; k:=1" establishes P (with k = 1), the repetition "while k < N do begin k:= k + 1; maximum:= MAX(maximum, a[k]) end " causes the repeatable statement to be executed under the combined relation "B and P" i.e. k < N and 1 ≤ k ≤ N and maximum = maximumk which reduces to 1 ≤ k < N and maximum = maximumk (9)

In order to show that the execution of the repeatable statement under the initial condition (9) leaves relation P valid it is desirable to distinguish between the values before and after its execution; now it would be confusing to do so with subscripts (why?), therefore we distinguish the values after execution by primes.

Initially we have relation (9); after the assignment k:= k + 1 we have the relation k' = k + 1 and from the first part of (9), i.e. 1 ≤ k < N, follows 2 ≤ k� ≤ N, which implies . 1 ≤ k' ≤ N . (10) The second assignment now becomes effectively maximum:= MAX(maximumk, a[k']), resulting in the relation maximum� = maximumk, .

Relations (10) and (11) combine to a replica of P, but now for the primed quantities.

Termination follows from the fact that each execution of the repeatable statement involves an effective increase of the integer values variable k. After termination we have, according to Theorem 5, P and non B, i.e. 1 ≤ k ≤ N and maximum = maximumk and non k < N ; from the first and the last term we conclude k = N and then from the middle part maximum = maximumk which concludes the proof.

Exercise. Make a program effectively assigning "prod:= X * Y" with integer X and Y, satisfying X ≥ O, Y ≥ O a) using only addition and subtraction b) using in addition the boolean function "odd(x)", doubling and halving of a number. (The so�called Egyptian multiplication.)

Exercise. Make a program effectively assigning "rem:= REM(X,Y)" with integer X and Y, X ≥ O, Y > O, where the function REM(X,Y) is the remainder after division of X by Y a) using only addition and subtraction b) using in addition doubling and halving of a number. Modify both programs such thatm in addition" "quot:= QUOT(X,Y)" will effectively take place. (The so-called Chinese division.)

We conclude this section by an example of the (standard) circumstance in which a recurrence relation should not be translated blindly into a loop. Given two sequences of values x[1], x[2], ... , x[N] and y[1], y[2], ... , y[N] with N ≤ 0 ; make a program assigning to the voolean variable named "eq" the value true if x[i] = y[i] for all i satisfying 1 ≤ i ≤ N and the value false if in that range a value of i exists such that x[i] ≠ y[i]. (The sequences may be empty, in that case "eq" should get the value true.)

How do we define equality of sequences of length N for general N? Again by means of a recurrence relation.

Let eqi mean "no difference has been observed among the first i pairs"; then the sequence of values eqi is given by for i = 0 eq₀ = true for i > O eqi = eqi-1 and x[i] = y[i] The net effect of the program to be made should be eq:= eqN . A blind translation into initialization followed by repetition would lead to eq:= true; i:= 0; while i < N do begin i:= i + 1; eq:= (eq and x[i] = y[i]) end .

Although the above program is correct, the following program, besides being equally correct, is on the average much more efficient: eq:= true; i:= O; while i < N and eq do begin i:= i + 1; eq:= (x[i] = y[i]) end because it terminates the repetition as soon as a difference has been found.

Exercise. Prove the correctness of the second program.

A first example of step-wise program composition. The little examples dealt with so far are not representative for the programs that have to be made: they are several orders of magnitude too small. A trained programmer "sees" this at a glance, he can think about them without pencil and paper. They are of the size of a paragraph, while we have to deal with programs of the size of pages, chapters or books and eventually -to quote A.Perlis- with programs that no longer fit into a single programmer's skull! The composition of such very large programs falls outside the scope of this little monograph, but the very least thing we can do is to show the reader how to organize his thoughts when composing, say, page-size programs. If in the following the reader thinks that I am too careful, he should bear the chapter-size programs in mind. (If he is still inconvinced he should study a one-page program by a messy programmer: he will then discover that even a single page has room enough for a disgusting and intellectually unhealthy amount of unmastered complexity!)

Here we go. Consider sequences composed of 1's, 2's and 3's which contain only pairs of different adjoining non�empty subsequences. Examples of good sequences are 1 12 12312 3212321 . Examples of bad sequences are 11 12523131 32132132132 .

In all probability the list of good sequences is infinite. I tell you that there is as least one good sequence of length 1OO (i.e. consisting of 1OO digits) and it is asked to make a program generating in alphabetic order the beginning of this list up to and including the first sequence of length 100. (Alphabetic order under the convention that the 1 precedes the 2 and the 2 precedes the 3; the criterion can be translated into a numerical one by putting a decimal point in front of the sequence and then interpreting the sequence as a decimal fraction. With that convention alphabetic order is the order of increasing magnitude.)

I have used this example extensively in oral examinations. After some initial skirmishes, most students discovered for themselves 1) that a wrong sequence could never be made into a good one by extending it, i.e. all good sequences are either a one-digit sequence of a one-digit extension of a good sequence 2) if sequence B is a good one-digit extension of sequence A, sequence A precedes sequence B in the alphabetic order, i.e. a good sequence is followed by all its possible extensions 3) the alphabetic order requires that the good sequence A will first be followed by the extensions starting with a 1 (if any), than by those starting with a 2 (if any) and then by those starting with a 3 (if any).

These observations lead to the following rule: a good sequence should be printed and be extended with a 1 as a next trial sequence; from a bad sequence terminal 3's (if any) should be removed and the final digit (now ≠ 3) should be increased by 1, giving the next trial sequence.

The beginning of the list to be generated is 1 12 121 1213 12131 121312 1213121 1213123 ....... by searching the following list of trial sequences (omitting the ones marked by ≠) 1 ≠ 11 12 121 ≠ 1211 ≠ 1212 1213 12131 ≠ 121311 121312 1213121 ≠ 12131211 ≠ 12131212 ≠ 12131213 ≠ 1213122 1213123 .......

Many of them suggested a program of the following structure.

program 1: SET SEQUENCE TD ONE AND LENGTH TO ONE; repeat if GOOD then begin PRINT; EXTEND WITH ONE end else ADJUST until length > 100 in which the primitive "EXTEND WITH ONE" extends the given sequence with a 1 and the primitive "ADJUST" increases the last digit by 1 after removal of terminal 3's if any. (For the operation "ADJUST" to be defined it is necessary that after removal of terminal 3's the remaining sequence won't be empty; this follows from the fact that the list to be produced is known to contain a sequence of length = 100)

To a program along the lines sketched, a number of objections can be made. One objection is that at the beginning of the execution of the repeatable statement its length will be ≤ 100 and furthermore we know that the operation "ADJUST" will never increase its length; nevertheless each adjustment is followed in time by a test on the length and the first objection is therefore that these tests are superfluous. A more severe objection is to be found in the tortuous reasoning required to establish that the end condition is OK. Instead of stopping when for the first time a solution of length 100 has been printed, it will stop when the first trial sequence of length > 100 has been generated. It is clear that the above program will never produce a solution larger than 100 because such a long trial sequence will never be subjected to the test "GOOD". To show, however, that it will stop after the production of the first solution of length = 100 is much harder.

A much nicer program is based upon the observation that we can regard the empty sequence as a virtual solution which does not need to be printed.

program 2: SET SEQUENCE EMPTY AND LENGTH TO ZERO; repeat EXTEND WITH ONE; while not GOOD do ADJUST; PRINT until length = 100 .

The objections raised are no longer valid. The true reason, however, why the above program is so much more attractive, is to be found in the observation that we can mentally combine the first two statements of the repeatable statement into a single one. The above version is a refinement of the more abstract

program 3: SET SEQUENCE EMPTY AND LENGTH TO ZERO; repeat TRANSFORM SEQUENCE INTO NEXT SOLUTION; PRINT until length = 100.

(Note. In programs 1, 2 and 3 the (outer) repetition could also have been controlled by a while-clause.)

This is much more preferable. Observe that here, in program 3, we have a level of description from which the trial sequences have disappeared! It is a level of description which can be understood in terms of solutions only. By distinguishing, i.e. by mentally isolating the operator "TRANSFORM SEQUENCE INTO NEXT SOLUTION" and postponing its refinement, we have separated the task of formulating the correct criterion for termination from how the transition from one solution to the next will be performed via a number of trial sequences which may be rejected. Remembering the limited size of the programmer's skull, this separation is a vital achievement, as it enables us to deal with one thing at a time.

To show that all this is not just idle playing with words we shall proceed from program 3 as our starting point, refining from there onwards. By way of surprise we shall arrive at a refinement differing from program 2, again without essentially changing the algorithm. (Although I had used this example extensively in examinations, the next version only occurred to me when writing this very text! This is just to show, that such abstract programs are vital stepping stones in our process of constructive reasoning!)

To find this refinement we do a step backwards, asking ourselves what enables us the transition from program 1 to program 2. It was the introduction of the empty sequence as "virtual solution". In program 1, the first solution was given, the others were generated, in program 2 and 3, all solutions to be printed are generated by the same operator "TRANSFORM SEQUENCE INTO NEXT SOLUTION".

When refining this operator the trial sequences have to be generated and in program 2 we find that the criterion "GOOD" has to be applied to trial sequences generated in two different ways, either by "EXTEND WITH ONE" or by "ADJUST". Can we clean up our refinement by insisting that all trial sequences to be tested are generated by the same operator? Yes we can by slightly changing the extension operator and slightly generalizing the operator "ADJUST", as in the following refinement.

TRANSFORM SEQUENCE INTO NEXT SOLUTION: EXTEND WITH ZERO; repeat ADJUST until GOOD .

Here "GOOD" stands for a rather complicated function; an alternative form uses the boolean variable "good" and leaves us with the task of refining the operator "SET GOOD".

TRANSFORM SEQUENCE INTO NEXT SOLUTION: boolean good; EXTEND WITH ZERO; repeat ADJUST; SET GOOD until good . (Note- In the above refinement the repetition is not to be controlled by a while-clause, Why?)

Now the time has come to make e decision on the representation of "sequence". It has a property "length", now satisfying the inequalities O ≤ length ≤ 1OO and is an ordered sequence of length digits. The appropriate vehicle for representing this sequence is (part of) a linear array of integer variables. We suggest to declare an integer array d[1:100] and that at any moment the sequence will be represented by d[1], d[2], ... , d[length] .

We draw attention to the fact that this is a well-motivated decision. An alternative representation would have been d[101 - length], d[102 - length], , d[100] but with the latter convention all operations changing the length of the sequence would imply moving the values upwards or downwards, whereas with the the suggested representation, the values being kept can "stay where they are". When the chosen convention is made to apply to all sequences manipulated (i.e. to solutions as well as to trial sequences) the following four refinements are fairly obvious. (As far as they are concerned, the chosen representation is certainly adequate.)

SET SEQUENCE EMPTY AND LENGTH TD ZERO: length:= O EXTEND WITH ZERO: length:= length + 1; d[length]:= O ADJUST: while d[length] = 3 do length:= length � 1; d[length]:= d[length] + 1 PRINT: i:= O; repeat i:= i + 1; printdigit(d[i]) until i = length; newline

where we have assumed the availability of the primitives "printdigit" and "newline" for the transition to the beginning of the next line of output. The only refinement which still can cause headaches is the operator "SET GOOD".

To investigate an arbitrary sequence is indeed a gruesome task, but it becomes much easier if we exploit the circumstance that the only sequences subjected to the test are trial sequences and each trial sequence is a one-digit extension of an (earlier) good sequence. As a result it can only violate the condition if its terminal element is included in one of the subsequencas, i.e. it has to be rejectd as bad if there exists an m (satisfying O < 2 * m ≤ length) such that the pair of adjoining "msequences" d[length - 2*m + 1] ... d[length - m] and d[length - m + 1] ... d[length] are equal. Assuming the availability of the operator needed to compare the msequences of this pair (for arbitrary, given m) our first refinement of "SET EDDD" is

SET GOOD: integer m; good:= true; m:=1; while 2 * m ≤ length and good do begin GIVE GOOD THE MEANING THAT THE HSEQUENEES DIFFER; m:= m + 1 end

or (probably) better

SET GOOD: integer m, mbound; good:= true; m:= 1; mbound:= length div 2; while m ≤ mbound and good do begin GIVE GOOD THE MEANING THAT THE MSEQUENCE5 DIFFER; m:=m+1 end

Here the operator div is the integer divide, rounding the quotient to the nearest integer towards zero. The double condition for continuing the repetition expresses that the investigation can be stopped as soon as an equal pair has been found, as this is sufficient to establish its being bad. We have seen this construction at the end of the previous section, see above.

Question. An alternative form would have been integer m; good:= true; m:= length div 2; while m >0 and good do begin GIVE GOOD THE MEANING THAT THE MSEQUENCES DIFFER m:= m - 1 end . Why do we propose to do the investigation in the order of increasing m?

Finally we refine the comparison of two msequences GIVE GOOD THE MEANING THAT THE MSEQUENCES DIFFER: integer firstend, k; firstend:= length - m; k:= 0; repeat good:= (d[firstend - k] ,≠ d[length - k]); k:= k + 1 until k = m or good again (see above) expressing that the comparison of two msequences can be terminated as soon as their difference somewhere has been established.

Collecting the declarations and inserting the refinements -keeping their names as labels for explicative purposes. we arrive at the complete program as shown below. The succesive levels of detail have been indicated by systematic use of indentation.

Exercise. Given a linear array of 36 positions, make a program generating all ways (if any) in which these positions can be filled with zeros and ones (one digit per position) such that the 32 quintuples of five adjoining positions present the 32 different patterns of five binary digits, restricting ourselves to sequences starting with five zeros. C.Ligtmans has shown that any such solution must end with four zeros. His argument is as follows. Each solution must start with OOOOO1... �because the pattern 00000 may only occur once. Somewhere in the sequence the pattern 10000 must occur once; as this pattern can only be followed by a O or a 1, its "following"quintuple must be either OOOOO or 00001, presented already by the first two quintuples. As a result the pattern 10000 cannot occur in the interior of the linear sequence and therefore it must be the rightmost pattern. From Ligtmans' observation it follows that we can close the ring, making the last four zeros overlap with the four initial ones. The 32 different patterns are then arranged in a cycle of 32 positions. The patterns have to be generated in alphabetic order.

Discussion and some hints. I take for granted that, given a sequence of 36 binary digits the boolean function stating whether this sequence represents a solution is computable and that we could write an algorithm computing it. In principle we could write a program generating all 36-digit sequences with five leading zeros in alphabetic order and subjecting all these sequences to the test just mentioned, thereby selecting those satisfying the test. This gives a very unrealistic program and we shall not pursue it; we only remark that generating the trial sequences in alphabetic order will ensure that the solutions, when found, will be found in alphabetic order as well.

The program to be made could be regarded as a derivation from the ridiculous one sketched above, viz. by the introduction of some significant short�cuts. At present we shall not stress this relation any further.

begin integer array d[1:100]; boolean good; integer length, i, m, unbound, k, firstend; SET SEQUENCE EMPTY AND LENGTH TO ZERO: length:=0; repeat TRANSFORM SEQUENCE INTO NEXT SOLUTION: EXTEND WITH ZERO: length:= length + 1; d[length];= 0; repeat ADJUST: while d[length] = 3 do length:= length - 1; d[length]:= d[length] + 1; SET GOOD: good:= true; m:= 1; mbound:= length div 2; while m ≤ mbound and good do begin GIVE GOOD THE MEANING THAT THE MSEQUENCES DIFFER: firstend:=length - m; k:=0; repeat good:= (d[firstend - k] ≠ d[1ength - k]); k := k + 1 until k = m or good; m:= m + 1 end until good; PRINT: i:= 0; repeat i:= i + 1; printdigit(d[i]) until i = length; newline until length = 100 end Instead of generating all 36-digit sequences and selecting from this set, we aim at generating only a much smaller set which is guaranteed to contain all solutions. Let us define as "length of a sequence" the number of quintuples it contains (i.e. length = number of digits - 4). Let us call a sequence "acceptable" if no two different quintuples in it present the same digit pattern. With these definitions the solutions are a subset of the set of acceptable sequences, viz, those with length = 32.

We do not know whether there are any solutions at all but we do know that the set of acceptable sequences is nonrempty (e.g. "OOOOO"); we do not have a ready-made criterion to recognize "the last solution" when we encounter it, in our set of acceptable sequences, however, we can designate a virtual last one (viz. "OOOO1"); when that one is encountered we know that all acceptable sequences with five leading zeros have been scanned and that no further solutions will be found.

Summarizing, we know of the set of acceptable sequences 1) it is non-empty and finite 2) we know a first member ("00000") 3) we know a virtual last member ("00001") 4) we can transform an acceptable sequence into the next acceptable sequence 5) solutions are all acceptable sequences (excluding the virtual one) satisfying the Further condition length = 32. 6) no extension of a sequence that is not acceptable will be acceptable.

It is this latter property which makes this problem mathematicaaly speaking very much similar to the previous one.

Hint. The test for acceptability can be speeded up considerably by tabulating which quintuples are to be found in the sequence.

Remark. This problem is difficult and it will take you hours to produce a beautiful program. But these hours will be extremely well-spent.

The shortest spanning subtree of a graph.

I have chosen the following example for a variety of reasons. Firstly, although the final program is rather short, the solution is far from trivial. Secondly, our true subject matter is rather "structure" than straightforward numerical material and as a result the decisions taken to represent the information (using numerical values) are more manifest. Finally it presents us with a type of decisions of strategy which are typical.

Two points can be connected by one point-to-point connection, three points can be connected with each other by two point-to-point connections, in general N points can be fully interconnected by N-1 point-to-point connections. Such a set of interconnections is called a "tree", the point-to-point connections that constitute the tree are called "its branches". Cayley has been the first to prove that the number of possible trees between N points equals NN_2.

We now assume that for each possible branch the length has been given. Defining the length of a tree as the sum of the length of its branches, we can ask for the shortest tree between those N points. (For the time being we assume that the given lengths are such that the shortest tree is unique. From our analysis it will follow that no two branches of equal length is a sufficient condition for this assumption.)

Note. The points don't need to lie in a Euclidean plane, the given distances don't need to satisfy the triangle inequality.

An apparently straightforward solution would generate all trees between the N points, compute their lengths and select the shortest one, but Cayley�s theorem shows that that would become very expensive as N increases. The following theorem enables us to find the shortest tree with considerably less work. Given a subtree of the shortest tree, then the shortest branch that can be found between one of the points touched by this tree and one of the points not touched by this subtree will be part of the shortest tree between all N points.

This theorem is easily proved. Colour the branches of the subtree and all points connected by it red; colour all the remaining points blue and colour all branches leading from a red point to a blue one violet. The theorem asserts that the shortest violet branch is part of the shortest tree as well. Call this shortest violet branch V and assume that it is not part of the shortest tree T; we shall then construct a tree T� which is shorter than T, thus arriving at a contradiction. Add to the tree T the violet branch V; in the resulting graph the violet branch V must be contained in a closed loop. As this violet branch connects a red point with a blue one, it is clear that, going around the loop we must find at least one other violet branch in this loop. Call this V� and remove V�. The resulting graph has again N-1 branches, it interconnects all N points (we have removed a branch from e loop) and therefore it is a tree connecting all N points. Call it T�. From T� = T + V - V� follows: length(T') = length(T) + length(V) - length(V') . As V was the shortest violet branch, we have length(V) < length(V'), so that length(T') < length(T) i.e. the tree T cannot have been the shortest one.

The above theorem tells us that a red subtree of the shortest tree T can be extended with a point and the branch leading to it, viz. the shortest violet branch and the blue point it leads to can be coloured red. As a result, if we can find a red subtree to start with, we can let it grow with a branch at a time. But it is very easy to start with a red subtree, viz. the red subtree consisting of e single point (any point will do) and no branches. Starting from that subtree we can let it grow to the sortest tree T in N-1 steps,,each step adding a new red branch and a new red point to it. We can represent the framework of this algorithm as follows:

COLOUR ONE POINT RED AND THE REMEINING ONES BLUE; while NUMBER OF RED POINTS < N do begin SELECT SHORTEST VIOLET BRANCH; COLOUR IT AND ITS BLUE ENDPOINT RED end .

As it stands, the main task will be "SELECT SHORTEST VIOLET BRANCH", because the number of violet branches may be quite large, viz. k *(N - k) where k = NUMBER OF RED POINTS. If "SELECT SHORTEST VIOLET BRANCH" were an isolated operation, there is not much that could be done about it; in the above program, however, the operation has to be performed N-1 times in succession and the successive sets of violet branches are strongly related: they are the branches between red and blue points and each time only one point changes its colour. We would like to exploit this with the aim of reducing the set of branches from which each time the shortest branch should be selected: we are looking for a useful subset of the violet branches. We still don't know if such a really useful subset exists, but let us assume for the moment that it can be found and let us call it the "ultraviolet" ones. If such a set exists (each time) it is only helpful provided that we have a cheap way of constructing this subset and our only hope is to be found in the past history of the computation, for instance the set of ultraviolet branches used the preceding time. This suggest a program of the following structure:

COLOUR ONE POINT RED AND THE REMAINING ONES BLUE; CONSTRUCT THE SET OF ULTRAVIOLET BRANCHES; while NUMBER OF RED POINTS < N do begin SELECT SHORTEST ULTRAVIOLET BRANCH; COLOUR IT AND ITS BLUE ENDPOINT RED; ADJUST THE SET OF ULTRAVIOLET BRANCHES end where the set of ultraviolet branches should be defined in such a way that 1) it is guaranteed to contain the shortest violet branch 2) the set of ultraviolet branches is in general much smaller than the set of the just violet ones 3) the operation "ADJUST THE SET OF ULTRAVIOLET BRANCHES" is cheap -otherwise the profit we are trying to gain is lost.

Can we find such a definition of the concept "ultraviolet"? Well, for lack of further knowledge I can only suggest that we try.

Considering that the set of violet branches leading from the k red points to the N-k blue ones has k *(N-k) members and observing criterion 1, two obvious possible subsets present themselves immediately: 1) Make for each red point the shortest violet branch ending in it ultraviolet. In this case the set of ultraviolet branches has k members. 2) Make for each blue point the shortest violet branch ending in it ultraviolet In this case the set of ultraviolet branches has N-k members.

Our aim is to keep the ultraviolet subset small, but from their size we won't get a clue: with the first choice the sizes will run from 1 through N-1, with the second choice it will be the other way round. So, if there is any chance of deciding we must find it int the price of the operator "ADJUST THE SET DF ULTRAVIOLET BRANCHES".

Without trying the various adjustments of the ultraviolet sets, there is one observation which suggests a preference for the second choice. In the first choice k ultraviolet branches may lead from the red tree to the same blue point; then we know a priori that at most one of them will be coloured red, while with the second choice each blue point is connected in exactly one way to the red tree (the sum of the number of red and ultraviolet branches is then constantly = N-1) and it is possible that all ultraviolet branches at a certain moment will eventually be coloured red -in which case the adjustment operator was empty but for the removal of the one made red. Therefore, let us try the second choice for the criterion ultraviolet. (The initial value of this set are the N-1 branches leading from the one red point to the remaining N-1 blue ones, so that presents no problem.)

Consider now that we have a red subtree R and that from the corresponding set of ultraviolet branches (according to the second choice -I shall no longer repeat that qualification) the shortest branch leading to the blue point P and the blue point P have been coloured red. The number of ultraviolet branches has been decreased by 1 as it should. Are they the good ones? For each blue point they represent the shortest connection to the red tree R, they should represent the shortest possible connection to the new red tree R + P. But this is for each blue point B a simple comparison: if the branch PB is shorter than the ultraviolet branch connecting B to R the latter is to be replaced by the branch PB -its colour is washed away and PB is made ultraviolet instead- otherwise it is maintained, as the growth of the red tree R with the point P did not provide a shorter way of connecting B with the red tree. As a result the adjustment operator -which has to deal with N-k blue points- is in price a linear function of N and K (and not quadratic as k *(N-k)) and the introduction of this concept of ultraviolet is indeed giving us the gain we were hoping for.

Exercise. Convince yourself that the rejected choice of the concept "ultraviolet" is not so helpful.

Let us try to represent our algorithm in its current stage of refinement:

COLOUR ONE POINT RED AND THE REMAININE ONES BLUE; CONSTRUCT THE SET OF ULTRAVIOLET BRANCHES; while NUMBER OF RED POINTS < N do begin SELECT SHORTEST ULTRAVIOLET BRANCH AND CALL ITS BLUE ENDPOINT P; COLOUR IT AND POINT P RED; ADJUST FOR EACH BLUE POINT B BY COMPARING WITH THE BRANCH BP end .

By now the time has come to bother about the representation of the information involved. We assume that N points being numbered from 1 through N, we assume the length of the branches being given by a two-dimensional array real array distance[1:N, 1:N] , such that for 1 ≤ i,j ≤ N distance[i,j] = distance[j,i] = length of branch connecting the points i and j.

The answer asked is a tree of N�1 branches, each branch being identified by the numbers of its endpoints; the answer is an (unordered) set of (unordered) pairs of numbers. We can represent them by two arrays integer array from, to[I:N-1] where for each h satisfying 1 ≤ h ≤ N-1 the pair "from[h], to[h]" gives (the numbers of) the endpoints of the h-th branch. In our final solution the branches will be numbered (by h), the only order that makes sense is the order in which they have been coloured red. The observation made earlier that the total number of branches (red and ultraviolet together) to be manipulated remains constant suggests that we store them in the same array:

if k = NUMBER OF RED POINTS from[h], to[h] will be red for 1 ≤ h < k from[h], to[h] will be ultraviolet for k ≤ h < N. The ultraviolet branches will be represented leading from a red point to a blue one. The array "length" has been introduced in order to reduce the number of subscriptions to be carried out: length[h] = distance[from[h], to[h]] will hold (and will be restored immediately when temporarily invalid).

Point N is chosen as the initial point to be coloured red. SELECT SHORTEST ULTRAVIOLET BRANCH is a straightforward search for a minimum value (see above) COLOUR IT AND POINT P RED is done by an interchange in the three arrays (if necessary), followed by an increase of k. In ADJUST FOR EACH BLUE POINT B BY COMPARING WITH THE BRANCH BP, h scans the violet branches, to[h] will scann the blue points and len is used to store the length of branch BP. The final program is as follows: begin integer array from, to [1:N-1]; real array length [1:N-1]; real len, minlen; integer k, h, minh, p; COLOUR ONE POINT RED AND THE REMAINING ONES BLUE: k:=1; CONSTRUCT THE SET OF ULTRAVIOLET BRANCHES: h:= 1; while h < N do begin from[h]:= N; to[h]:= h; 1ength[h]:= distance[N,h]; h:= h + 1 end; while k < N do begin SELECT SHORTEST ULTRAVIOLET BRANCH AND CALL ITS BLUE ENDPOINT P: minh:= k; minlen:= length[k]; h:= k + 1; while h < N do begin len:= length[h]; if len < minlen do begin minlen:= len; minh:= h end; h:=h+1 p:= to[minh]; COLOUR IT AND POINT P RED: if k ≠ minh do begin h:= from[k]; from[k]:= from[minh]; from[minh]:=h; h:= to[k]; to[k]:= to[minh]; to[minh]:= h; len := length[k]; length[k]:= length[minh]; length[minh]:= len end; k:= k + 1; ADJUST FOR EACH BLUE POINT B BY COMPARING WITH THE BRANCH BP: h:= k; while h < N do begin len:= distance[p, to[h]]; if len < length[h] do begin length[h]:= len; from[h]:= p end; h:= h +1; end; h:= 1; while h < N do begin print(from[h]); print(to[h]); newline; h := h + 1 end end

Exercise.

Let distance[i,j] be the distance from point i to point j in that direction. As we may have one-way traffic, the relation distance[i,j] ≠ distance[j,i] is then permissible. Make a program finding in the graph the shortest path leading from point I to point J. This is a difficult exercise, therefore it is worth trying!

The towers of Hanoi.

Given three pegs, numbered 1, 2 and 3 and a set of N disks (N ≥ 1] of decreasing diameter and a hole in their centre. At the beginning the N disks are all on peg nr.1 in order of decreasing diameter, i.e. the largest disk is at the bottom, the smallest is at the top side of the first peg. It is requested to move this tower from the first peg to the third one in a number of "moves", where a "move" is moving one disk from the top of a peg to the top of another peg with the restriction that never a larger disk may be placed on top of a smaller one. Hereby the second peg may be used as auxiliary "store" for pegs which are "in the way".

Now, if we can solve this game for any two pegs for N = N0, we can also solve it for N = N0+1. Call movetower(m, A, B, C) the set of moves that transports a tower of m disks from peg A (if necessary via peg B) to peg C. The individual moves are of the form movedisk(A, B) .

The set of moves movetower(N₀+ 1, A, H, C) is the same as that of the successive moves of movetower(N₀, A, C , H) movedisk(A, C) movetower(N₀, B, A, E) . In words: first a tower of N₀ disks is moved from A to B, using C as auxiliary peg, then the N₀ + 1st disk is moved directly from A to C and finally the tower of N₀, that has been placed temporarily on peg B is moved to its final destination C, using A as auxiliary peg. As the tower consists of the N₀ smallest disks, the presence of larger disks will not cause violation of the condition of decreasing disk diameter. Moving a one-disk tower (N₀ = 1) presents no difficulty and as a result the puzzle has been solved. The question posed to us, however, is to make a program generating the diskmoves in the order in which they successively have to take place.

Note. It is not realistic to require the execution of this program for large values of N because the total number of moves required = 2N - 1.

The fact that a move with N > 1 is decomposed into three "smaller" moves, suggests that we keep a list of moves to be done. If the first one to be done is simple, we do it, otherwise we replace it by its decomposition and reconsider our obligations. In both cases, when we have a list of k moves, only the first to be done needs consideration and while we process it, the remaining K-1 moves remain as standing obligations. This suggests that we introduce

movek, movek-1, ....., move₂, move 1 to be done in the order of decreasing subscript, in the order from left to right. If movek is simple, it is done, leaving movek'=k-1,......, move₂, move₀ (indicating with k' the new value of k, the length of the list of obligations) otherwise movek is replaced by three others, leaving movek'=k+2 movek'-1=k+1 , movek'-2=k , movek'-3=k-1 ,.....move₂ move₁ .

In both transformations the lower (i.a. later) k-1 moves have been unaffected.

A move is given by four parameters, say n = number of disks in the tower to be moved from = number of source peg via = number of auxiliary peg to = number of destination peg.

We can store these moves in four arrays integer array n, from, via, to [1; 2*N�1]. (Verify that the list of obligations is never longer than 2*N-1 moves.)

begin integer k; integer array n, from, via, to [1:2*N-1]; n[1]:= N; from[1]:=1; via[1]:= 2; to[1]:= 3; k=1; repeat if n[k]=1 then begin movedisk(from[k], to[k]); k:= k - 1 end else begin n[k+2]:= n[k] - 1; from[k+2]:=from[k]; via[k+2]:= to[k]; to[k+2]:= via[k]; n[k+1]:= 1; from[k+1]:= from[k]; to[k+1]:= to[k]; n[k]:= n[k+2]; from[k]:= to[k+2]; via[k]:= from[k+2]; to[k]:= via[k+2]; k:= k+2 end until k = O end

The non-simple move (with N > 1), given in tabular form by n= from= via = to = k: N A B C is to be replaced by the triple n' = from� = via� = to� = k'- 2 = k: N-1 B A C k'-1 = k+2: 1 A (B) C k' = k+2: N-1 A C B in which the top line replaces the original one, while the next two lines are new. (In the middle line the element "via" has been put between brackets, as it is immaterial; the program leaves that value unaffected.)

Remark. In the program we have not described the details ov the operation "movedisk(A, B)". If it prints the number pair A,B, the solution will be printed; if the machine is coupled to a mechanical hand which really moves pegs, the machine will play the game!

The reader is strongly invited to follow the above program himself for small value of N (say: 4) so that he sees how the value of k goes up and down.

The reader is also invited to check carefully the "shunting" of the values N(-1), A, B and C when a non-simple move is decomposed into three simpler ones. This check is a painful process, so painful that everyone who has done it, will only be too willing to admit that the above program is rather ugly. The above program has been included with the aim of making him more appreciative of the elegance of the so-called "recursive solution" which now follows. begin procedure movetower(integer value m, A, B, C); begin if m = 1 then movedisk(A, C) else begin movetower(m-1, A, C, B); movedisk(A, C) movetower(m-1, B, A, C) end end movetower(N, 1, 2, 3) end

It introduces en operator named "movetower" with four (integer valued) parameters, moving a tower of length "m" from "A" via "B" to "C". In terms if this operator the final program collapses into a single statement as given in the last line, viz. "movetower (N, 1, 2, 3)". All that is given in front of it (lines 2 to 8) describes this operator in terms of a little program, little, because the operator is allowed to invoke itself. The definition of the operator �the so-called "procedure body"- follows completely our original analysis of the game (see above). Recursive procedures -i.e. procedures that are allowed to invoke themselves- are such a powerful tool in programming that we shell give some more examples of them.

Remark. Some of the more old-fashioned programming languages do not cater for recursion. Programming courses based on such programming languages often contain many exercises which are only difficult because the recursive solution is denied to the student.

The problem of the eight Queens.

It is requested to make a program generating all configurations of eight queens on a chess board of 8 * 8 fields, such that no queen can take any of the others. This means that in the configurations sought no two queens may be on the same row, on the same column or an the same diagonal.

We don't have an operator generating all these configurations, this operator is exactly what we have to make. Now the (very general!) way to attack such a problem is as follows. Call the set of configurations to be generated A; look for a greater set E of configurations with the following properties 1) set A is a subset of set B; 2) given an element of set B, it is not too difficult to decide whether it belongs to set A as well; 3) we can make an operator generating the elements of set B.

with the aid of the generator (3) for the elements of set B, the elements of set B can then be generated in turn, they will be subjected to the decision criterion (2) which decides whether they have to be skipped or handed over, thus generating elements of set A. Thanks to (1) this algorithm will produce all elements of set A.

Three remarks are in order. 1) If the whole approach makes sense, set B is not identical to set A and as it must contain set A as a (true) subset, it must be larger. Nevertheless, it is advised to choose it "as small as possible": the more elements it has, the more elements of it have to be rejected on account of the decision criterion (2). 2) We should look for a decision criterion that is cheap to apply, at least the discovery that an element of B does not belong to A should (on the average) be cheap. 3) The assumption is that the generation of the elements of set B is easier than a direct generation of the elements of set A. If, nevertheless, the generation of the elements of set B still presents difficulties we repeat our pattern of thinking, re-apply the trick and look for a still larger set C of configurations that contain B as subset, etc.

Above we have sketched a very general approach, applicable to may, very different problems. Faced with a particular problem, i.e. faced with a specific set A, the problem of course is, what to select for our set B.

In a moment of optimism one could think that this is an easy matter, as we might consider the following technique. We list all the mutually independent conditions that our elements of set A must satisfy and omit one of them. Sometimes this works but as a general technique this is too naive; if we want to see its shortcomings, we only need to apply it blindly to the problem of the eight queens. We can characterize our solutions by the conditions: 1) there are 8 queens on the board 2) no two of the queens can take one another.

Omitting either of them gives for the set B the alternatives B1: all configurations with N queens on the board such that no two queens can take one another B2: all configurations of 8 queens on the board. But both sets are so ludicrously huge that they lead to utterly impractical algorithms. We have to be smarter. How?

Well, at this stage of our considerations, being slightly "at a loss" we are not so much concerned with the efficiency of our final program but rather with the efficiency of our own thought processes! So, if we decide to make a list of the properties of solutions, in the hope of finding a useful clue, this is a rather undirected search, we should not invest too much mental energy in such a search, that is: for a start we should restrict ourselves to their obvious properties. Let us go ahead. a) No row may contain more than one queen, 8 queens are to be placed and the chess board has exactly 8 rows. As a result we conclude that each row will contain exactly one queen. b) Similarly we conclude that each column will contain exactly one queen. c) There are fifteen "upward" diagonals, each of them containing at most one queen, i.e. 8 uoward diagonals contain exactly one queen and 7 upward diagonals are empty. d) Similarly we conclude that 8 downward diagonals are occupied by one queen and 7 are empty. e) Given any non-empty configuration of queens such that no two of them can take one another, removal of any of these queens will result in a configuration sharing that property.

Now the last one is a very important property: in our earlier terminology it tells us something about any non-empty configuration from set B1. Conversely it tells us that each non-empty configuration from B1 can be generated (in N different ways!) by extending a configuration from B1 with N-1 queens by another queen. We have rejected B1 because it was too large, but maybe we can find a suitable subset of it, such that each non-empty configuration of the subset is a one-queen extension of only one other configuration from the subset. This "extension property" suggests that we are willing to consider configurations with less than 8 queens and that we would like to form new configurations by adding a queen to an existing configuration - a relatively simple operation presumably. Well, this draws our attention immediately to the generation of the elements of the (still mysterious) set B. For instance: in what order? And this again raises a question to which, as yet, we have not paid the slightest attention: in what order are we to generate the solutions, i.e. the elements of set A? Can we make a reasonable suggestion in the hope of deriving a clue from it?

Prior to that we should ask ourselves: how do we characterize solutions once we have them? To characterize a solution we must give the positions of 8 queens. The queens themselves are unordered, but the rows and the columns are not: we may assume them to be numbered from O through 7. Thanks to property a), which tells us that each row contains exactly one queen, we can order the queens according to the number of the row they occupy. Then each configuration of B queens can be given by the value of the integer array X[O:7], where x[i] = the number of the column occupied by the queen in the i-th row.

Each solution is then "an 8-digit word" (x[O]...x[7]) and the only sensible order in which to generate these words that I can think of is the alphabetic order. (Note. As a consequence we open the way to algorithms in which rows and columns are treated differently. At first sight this is surprising, because the original problem is completely symmetrical in rows and columns. We should be glad: to consider asymmetric algorithms is exactly what the above considerations have taught us!)

Returning to the alphabetic order: now we are approaching familiar grounds. If the elements of set A are to be generated in alphabetic order and then have to be generated by selecting them from a larger set B, then the standard technique is generating the elements of set B in alphabetic order as well and to produce the elements of the subset in the order in which they occur in set B.

First we have to generate all solutions with x[0] = 0, then all with x[0] = 1 etc.; the solutions with x[0] = 0 have to be generated first those with x[1] = 0 (if any), then those with x[1] = 1 (if any), than those with x[1] = 2 (if any) etc. In other words: the queen of row 0 is placed in column 0 -say: the field in the top left corner- and remains there until all elements of A (and B) with queen 0 in that position have been generated and only then is she moved one filed to the right to the next column. For each position of queen 0, queen 1 will walk from left to right in row 1 -skipping the fields that are covered by queen O-; for each combined position of the first two queens, queen 2 walks along row 2 from left to right, skipping all fields covered by the preceding queens, etc.

But now we have found set B! It is indeed a subset of B1: set B consists of | all configurations with one queen in each of the first N rows, such that | no two queens can take one another.

Having established our choice for the set B, we find ourselves immediately faced with the task of generating its elements in alphabetic order. We could try to do this via an operator "GENERATE NEXT ELEMENT DF B" with a program of the form INITIALIZE EMPTY BOARD; repeat EENERATE NEXT ELEMENT DF B; if N = 8 do PRINT CONFIGURATION until B exhausted but this is not too attractive for the following two reasons.

Firstly, we don't have a ready-made criterion to recognize the last element of B when we meet it and in all probability we have to generalize the operator "GENERATE NEXT ELEMENT'DF B" in such a way that it will produce the indication "B EXHAUSTED" -for instance in the form of the empty board� when it is applied to the last "true" element of B. Secondly, it is not too obvious how to make the operator "GENERATE NEXT ELEMENT DF B": the number of queens on the board may remain constant, it may increase and it may decrease.

So that is not too attractive. What can we do about it? As long as we regard the sequence of configurations from set B as a single sequence, not subdivided into a succession of subsequences, the corresponding program structure will be e single loop as in the program just sketched. If we are looking for an alternative program structure, we must therefore ask ourselves: "How can we group the sequence of configurations from set B into a succession of subsequences7"

Realizing that the sequence of configurations from set B have to be generated in alphabetic order and thinking of the main subdivision in a dictionary �viz. by first letter- the first grouping is obvious: by position of queen 0.

Generating all elements of set B -for the moment we forget about the printing of the elements that belong to the subset A as well- the presents itself in the first instance es

h:= O; repeat SET QUEEN ON FIELD H; GENERATE ALL CONFIGURATIONS WITH QUEEN O FIXED; REMOVE QUEEN; h:= h + 1 until h = 8, where the operations SET QUEEN and REMOVE QUEEN pertain to row zero, i.e. the first free row or the last occupied row respectively.

But now the question repeats itself: how do we group all configurations with queen O fixed? We have already given the answer: in order of increasing column position of queen 1, i.e.

h1:= O; repeat if FIELD H1 FREE do begin SET QUEEN on FIELD H1; GENERATE ALL CONFIGURATIUNS WITH FIRST 2 QUEENS FIXED; REMOVE QUEEN end; h1:= hl + 1 until h1 = 8 where, again, FIELD FREE and SET QUEEN pertain to the first free row and REMOVE QUEEN pertains to the last occupied row.

For "GENERATE ALL FIELDS WITH FIRST 2 QUEENS FIXED" we could write a similar piece of program and so on: inserting them inside each other would result into a correct program with some eight nested loops, but they would all be very, very similar. To do so has two disadvantages: 1) it takes a cumbersome amount of writing 2) it gives a program solving the problem for a chess board of 8 * 8 fields, but to solve the same puzzle for a board of, say, 10 * 10 fileds would require a new (still longer) program. We would like to avoid this by exploiting the similarity of the loops.

The we have to answer two questions 1) can we make the loops exactly identical? 2) can we profit from their similarity?

The two exceptional cycles are the outermost one and the innermost one. The outermost one is different because it does not test, whether the next field is free. There is however no objection to inserting this test: as it is only applied when the board is empty it is guaranteed to give the value true we can give the outermost cycle the same form by inserting the conditional clause if FIELD H FREE do.

The innermost cycle is exceptional in the sense that as soon as 8 queens have been placed on the board, there is no point in generating all configurations with those queens fixed, because we have a full board. Instead the configuration has to be printed, because we have found an element of set B that is also an element of set A. We can map the innermost cycle and the embracing seven ones upon each other by replacing the line "GENERATE" by if BOARD FULL then PRINT CONFIGURATION else GENERATE ALL CONFIGURATIONS EXTENDING THE CURRENT

By now the only difference between the eight cycles is that each cycle has to have "its private h". By the time that we have reached this stage, we can give an affirmative answer to the second question. The sequencing through the eight nested loops can be provoked with the aid of a recursive procedure "generate" say which describes the cycle once. Using it, the program itself collapses into "INITIALIZE EMPTY BOARD; generate" while "generate" is defined recursively as follows:

procedure generate; begin integer h; h:= O; repeat if FIELD H FREE do begin SET QUEEN ON FIELD H; if BOARD FULL then PRINT CONFIGURATION else generate; REMOVE QUEEN end; h:=h+1 until h=8 end .

Each activation of "generate" will introduce its private local variable h, this catering for h, h1, h2, ..... that we would need when writing 8 nested loops inside each other. FIELD H FREE and SET QUEEN UN FIELD H again refer to the first free row, the operation REMOVE QUEEN to the last occupied one.

Our program �although correct to this level of detail - is not yet complete i.e. it has not been refined up to the standard degree of detail that is required by our programming language. In our next refinement we should decide upon the conventions according to which we represent the configurations on the board. We have already decided more or lees that we shall use the integer array x[O:7] giving in order the column numbers occupied by the queens. We need a separate convention to represent the number of queens on the board. Let us introduce integer n, such that

n = the number of queens on the board and for 0 ≤ i < n: x[i] = the number of the column occupied by the queen in the i-th row.

The array x and the scalar n are together sufficient to fix any configuration of the set B and those will be the only ones on the chess board. As a result we have no logical need for more variables; yet we shall introduce a few more because from a practical point of view we can make good use of them. The problem is that with only the above material the analysis whether a given field in the next free row is unciverd is rather painful and time�consuming. Here we can look for e standard technique, called "trading storage space versus computation time". The pattern of this technique is as follows.

In its most simple form we are faced with a computation that regularly needs the value of "FUN(arg)" where "FUN" is a given, computable function defined on the current value of one or more stored variables, collectively called "arg". In version 1 of a program only the value of arg is stored and the value of FUN(arg) is computed whenever needed. In version 2, an additional variable, "fun" say, is introduced whose sole purpose is to record the value of "FUN(arg)" corresponding to the current value of "arg".

Where version 1 has arg:=... (i.e. assignment to erg) version 2 will have (effectively) arg:=...; fun:= FUN{arg) , thereby maintaining the validity of the relation fun = FUN(arg) .

As a result of the validity of this relation, wherever version 1 calls for the evaluation of FUN(arg), version 2 will call for the current value of the variable "fun".

The introduction of such redundant additional tabulated material is one of the programmer's most powerful ways to improve the efficiency of a program. Of course we need our ingenuity for its invention!

Quite often the situation is not as simple as that and we come now to the second reason for introducing such a variable "fun". Often it is very unattractive to compute FUN(arg) from scratch for arbitrary values of arg while it is much easier to compute how the value of FUN(arg) changes when the value of arg is changed. In that case the adjustment of the value of "fun" is more intimately linked with the nature of the functional dependence and the history of the variable "arg" than is suggested by - arg:=...; fun:= FUN(arg) .

After this interlude on program optimization via trading storage space versus computation time, we return to our eight queens. The role of "arg" is played by the configuration on the board, but this value is not changed wildly, oh no, the only thing we do with it is adding or removing a queen. And we are looking for additional tables that will assist us in the decision whether a field is free, tables such that they can be kept up to date easily when a queen is added to or removed from the configuration.

How? Well, we might think about a boolean array of 8 * 8, indicating for each field whether it is free or not. If we do this for the full board, adding a queen implies dealing with 29 fields, removing a queen, however, is then a painful process because it does not follo that all fields no longer covered by her are indeed free: they might be covered by other queens. There is a remedy for this, viz. associating with each field not a boolean variable but an integer counter, counting the number of queens covering the field. Adding a queen means increasing 29 counters by 1, removing a queen means decreasing 29 counters by 1 and a field is free when its counter is zero. We could do it that way, but the question is whether this is not overdoing it: 29 adjustments is quite a lot.

Each field, in the freedom of which we are interested, covers a row (which is free by defenition, so we need not bother about that), covers one of 8 columns (one which still should be empty), covers one of the 15 upward diagonals (one which should be empty) and one of the 15 downward diagonals(one which should be empty). This suggests that we should keep track of 1) the columns that are free 2) the upward diagonals that are free 3) the downward diagonals that are free.

As each column or diagonal is covered only once we don't need a counter for each, a boolean is sufficient. For the columns we introduce a boolean array col[O;7] where "col[i]" means that the i-th column is still free.

How do we identify the diagonals? Well, along an upward diagonal the difference between row number and column number is constant, along a downward diagonal their sum. As a result difference and sum respectively are the easiest index by which to distinguish the diagonals and we introduce therefore boolean array up[-7:+7], down [0:14] to keep track of which diagonals are free.

The question whether field[n,h] is free becomes col[h] and up[n-h] and down[n+h] , setting and removing a queen both imply adjustment of three booleans, one in each array.

Without the tabulated material, REMOVE QUEEN would only consist of "n:= n � 1", now we would like to know her column number as well, i.e. we replace it by REMOVE QUEEN FROM FIELD H". In the final program, the variable "k" is introduced for general counting purposes, statements and expressions are labelled for explicative purposes.

begin integer n,k; integer array x[O:7]; boolean array col[0:7], up[-7:+7], down[O;14]; procedure generate; begin integer h; h := 0; repeat if FIELD H FREE: (co1[h] and up[n-h] and down[n+h:) do begin SET QUEEN ON FIELD H: x[n]:= h; co1[h]:= false; up[n-h]:= false; down[n+h]:= false; n := n + 1; if BOARD FULL: (n = 8) then begin PRINT CONFIGURATION: k:= 0; repeat print(x[k]); k:= k + 1 until k = 8; newline end else generate; REMOVE QUEEN FROM FIELD H: n:= n - 1; doun[n + h]:= true; up[n-h]:= true; col[h]:= true end; h:= h + 1 until h = 8 end INITIALIZE EMPTY BOARD: n:= 0; k:= 0; repeat col[k]:= true; k:= k + 1 until k = 8; k:= 0; repeat up[k-7]:= true; down[k]:=true; k +1 until k =15; generate end

This completes the treatment of our problem; the program, incidentally, generates 92 configurations.

By way of conclusion I would'like to make up the bill: the final solution is not very important (at least not more important than the problem of the eight queens). The importance of this section is to be found in the methods on which our final program relies and the way in which we have found them.

1) The final algorithm mebodies a very general technique, so general that it has a wellrestablished name: it is called "backtracking". The configurations of set B can be thought of as placed at the nodes of a hierarchical tree, each node containing configuration C supporting the subtree with all the nodes with configurations that have C as a true sub-configuration. At the root of the tree we have the empty configuration (from which 8 different branches emanate), at each next level we find configurations with one queen more and at the top nodes (the leaves) we find the 92 solutions. The backtracking algorithm generates and scans the nodes of this tree in a systematic manner. I recommend the reader to become thoroughly familiar with the idea of backtracking, because its can be applied when faced with a great number of at first sight very different problems. (It is only when you recognize that they all ask for a solution by means of back- tracking that the problems become boringly similar to each other.)

2) If the only thing the student learns from this section is his becoming familiar with backtracking, he has learned something, but it was my intention to teach him more: we showed all considerations which together can lead to the discovery of our method, this time to backtracking. But it is my firm conviction that, when faced with a different problem to be solved by a different method, the latter may be discovered by a very similar analysis of ends and means.

3) The finla program contained a recursive procedure. But backtracking is by no means the only algorithmic pattern that is conveniently coded with the aid of recursion. The main point was the collection of considerations leading to the discovery that in this case recursion was an appropriate tool.

4) The major part of our analysis has been carried out before we had decided how (and how redundantly) a configuration would be represented inside the machine. It is true that such considerations only bear fruit when, finally, a convenient representation for configurations can be found. Yet it is essential not to bother about the representation before that becomes crucial. There is a tendency among programmers to decide the (detailed) representation conventions first and then to think about the algorithm in terms of this specific representation but that is putting the cart before the horse. It implies that any later revision of the representation convention implies that all thinking about the algorithm has to be redone; it fails to give due recognition to the fact that the only point in manipulating (such groups of) variables is that they stand for something else, configurations in our case.

5) The trading of storage space versus computation time is more than a trick that is useful in this particular program. It is exemplar for many of the choices a producing programmer has to take; he will work more consciously and more reliably when he recognizes them as such. Exercise. Write two programs generating for N > 0 all N! permutation of the numbers 1 through N, one with and one without recursion, and establish for both programs their correctness.

Exercise. For ) < N < M generate all integer solutions of the equations in c[1] through c[N] such that 1) c[1] > 0 2) c[i]>c[i-1]for 1 < i ≤ N 3) c[1]+...+c[N] = M .

Again, write two programs, one without and one with recursion and establish their correctness.

Exercise. Write a program solvong the problem of the linear array of 36 positions but now using recursion.

A rearranging routine.

The following example has been inspired by work of C.A.R.Hoare (Algorithm 64, C.A.C.M.).

The original problem was to rearrange the values of the elements of a given array A[1:N] and a given value of f (1 ≤ f ≤ N) such that after rearrangement for 1≤k < f A[k]≤A[f] for f As a result of this rearrangement A[f] equals the f-th value in order of non�decreasing magnitude. We call the array rearranged satisfying (1) "split around f"; we call the final value of A[f] "the splitting value". When the array has been split it is divided into two halves, the one half -the "leftchand" half, say� containing the "small" values and the other half �the "right-hand" half, say- containing the large elements, with the splitting value sandwiched in between. The overall function oF the algorithm is to move small values to the left and large values to the right. The difficulty is that for given f the final value of A[f], i.e. our criterion "small/large", is unknown to start with.

Hoare's invention is the following. Select some� rather arbitrary criterion "small/large"; by moving small elements to the left and large elements to the right, a split will be established somewhere, around some position s. If s happens to turn out = f, the original problem is solved. The kernel of Hoare's invention is the obseryation that in the other cases the original problem can be reduced to the same problem, but now applied to one of the halves, viz. to the left-hand half if f lies to the left of the split and to the right-hand half is f lies to the right of the split. Note. An alternative approach would be to sort the array completely: after that A[r] will equal the f�th value in the order of non-decreasing magnitude. But this can be expected to be rather expensive, for then we have established relations (1) for all values of f. As a matter of fact we will arrive at a rearranging routine which itself can be used for complete sorting, on account of the fact that, when a split around s has been established, A[s] has the value it is going to have in the completely sorted array, and that -because all elements to the left of it are ≤ A[s] and those to the right of it are ≥ A[s]- completely sorting it could now be performed by sorting thereafter the two parts independently.

We now focus our attention on the rearranging routine which is to cause a split in the array section A[m] ... A[n] with 1 ≤ m ≤ n ≤ N .

When we try to make such a routine we are immediately faced with the choice of our criterion "small/large". One of the ways is to select an arbitrary element from the section, to call all elements larger than it "large", all elements smaller than it "small" and all elements equal to it either "large" or "small", just what is most convenient (in the final arrangement they may occur everywhere, either at the split or at either of its two sides). Let us therefore postpone the choice in this discussion for a moment, as there is a chance that we can use our Freedom to some advantage.

We are going to select one of the values in the array as the "splitting value"; having chosen this value, its final position - i.e. the position of the split" is unknown before the algorithm starts; it is defined when the algorithm has been executed, in other words it is determined by the evolution of the computation. This suggests that we build up the collection of the small values, starting at the left-hand end, and that of the large values at the right-hand and,and continue doing so until the two collections meet somewhere in the middle. To be more precise, we introduce two pointers, "i" and "j" say, whose initial values will be "m" and "n" respectively,and rearrange values in such a fashion that, when we call the splitting value V, we ensure that A[k] ≤ V for m ≤ k < i and A[k] ≥ V for j < k ≤ n .

Having chosen the splitting value, the algorithm will have the duty of building up the collections of small and large values repectively from the outside inwards. The algorithm can start scanning, at the left-hand end say, until a large element is encountered. If this occurs this value has to be removed from the collection of small values, i.e. it has to be added to the colletion of large elements. It is, as a matter of fact, the first element whose highness the algorithm has established: as we have decided to build up the collections from the outside inwards, this "large" value has to be assigned to A[n]. As we would like this postion in the array to be "free" -i.e. available to receive this first large value- the original value of A[n] can be taken out of the array and can be chosen as the splitting value V.

That is, we initialize i = m and j = n and "take out" A[n] -by assigning it to the variable V- thereby initializing the situation where scanning starts at element A[i], while "j" points to the "hole� just made. When the upward scan (under control of increasing "i") finds a large element, i.e. when for the first time A[i] > V, this value is placed in the hole, now leaving the hole in the place pointed-to by "i". From then onwards a downward scan (under control of decreasing "j") can operate until a small element has been encountered which will be placed in the hole at position "i", leaving the hole in the place pointed to by "j". Such upward and downward scans have to succeed each other alternately until i = j, i.e. until both point to the hole at the position around which the split has been effectuated. Finally the hole receives the value V which had been taken out at the beginning.

The above sketch gives an informal description of the essential features of the algorithm, it by no means settles the structure of the sequential program that will embody it.

I have tried a program in which the core consists of the program part for the upward scan followed by the program part for the downward scan. The first part consists of a loop with "i:= i + 1" in the repeatable statement] the second part consists of a loop with "j:= j - 1" in the repeatable statement. The two parts together then form the repeatable statement of an outer loop. This program became very ugly and messy, the reason being that termination may occur either because the upward scan or because the downward scan is on the verge of scanning the hole. The reasoning needed to establish that the program did properly terminate became tortuous.

On account of that experience I have tried the alternative approach, one loop in which a single execution of the repeatable statement decreases the difference "j - i" -i.e. the length of the unscannad array section- by 1, by doing a step of the appropriate scan.

The decision to control the steps of both scans by the same repeatable statement calls for the introduction of another variable; as we have to distinguish between only two cases,a boolean variable suffices, "up" say, with the meaning: up = true means: the algorithm is in the state of upward scanning and j points to the hole up = false means: the algorithm is in the state of downward scanning and i points to the hole. The initialization has to be extended with the assignment "up := true"; after the initialization the program continues with while i < j do perform the appropriate step" . In the course_of the action "perform the appropriate step", the value of "up" has to change its value whenever the hole is filled and the scanning direction has to reverse. Without any further detours I arrived at the following procedure:

inteqer procedure split(real array a, integer value m, n); begin integer i, j; real V; boolean up; i:= m; j:= n; V:= a[j]; up:= true; while ido begin if up then if a[i] > V do begin a[j]:= a[i]; up:= false end else if V > a[j] do begin a[i]:= a[j]; up:= true end; if up then i:= i + 1 else = j - 1 end a[j]:= V; split:= j end

In its applications we shall only call the procedure "split" with m < n; as it stands it also caters for the case m = n.

Exercise. Show that in a version of split that only needs to cater for m < n, its internal repetition could have been controlled by a repeat until clause as well.

Note. At the price of a larger number of subscriptions to be performed, the text of the procedure can be shortened by not introducing the separate variable V, but by storing this value "in the hole" i.B. V = if up then a[j] else a[i] . As a result the splitting value zigzags to its final position. With the above convention the tests "a[i] > V" and "V > a[j]" both become "a[i] > a[j]", the assignments "a[j]:= a[i]" and "a[i]:= a[j]" both become the interchange "W:= a[i]; a[i]== a[j]: a[j]:= W" and the assignments "up:: false" and "up:= true" can both be represented by "up;= non up" . The above observations allow us to condense the procedure text into inteqer procedure split(real array a, integer value m, n); begin integer i, j; real W; boolean up; i:= m; j:= n; V:= a[j]; up:= true; while i < j do begin if a[i] > a[j] do begin W:= a[i]; a[i]:= a[j]; a[j]:= W; up:= non up end if up then i:= i + 1 else = j - 1 end split:= j end

We now return to our original problem: given an array A[1:N] and a value f (1 ≤ f ≤ N), rearrange the elements in such a way that for 1 ≤ i < f A[i] ≤ A[f] and for f The idea is to apply the operator "split" first to the original array from 1 through N. The operator establishes the split somewhere, position s say. If the position of the split coincides with f (F = s), we have reached our goal, otherwise the operator "split" is applied to one of the halves, viz. to the left-hand half when f < s and to the right-hand half when f > s etc.

For this purpose we introduce variables p and q, satisfying 1 ≤ p ≤ f ≤ q ≤ N such that A[p] .... A[q] will be the section of the array to which the split will be applied, as this section is certain to contain the (future) value of A[f].

If the split is found to the right of f (i.e. f < s) the operator has to be applied to the left-hand half, i.e. q has to be reset to s - 1 and p can be left unchanged. In the case f > s, p has to be reset to s + 1 and q can be left unchanged. We thus arrive at the routine integer p, q, s; p:= 1; q:= N; repeat s:= split(A, p, q); if f < s do q := s-1; if f > s do p := s + 1 untilf = s. (Note. In the case N = 1 this routine will call split with m = n.)

We may wish to improve upon this program: it is rather superfluous to call the operator "split" with p = q: if the section consists of a single element no (significant) rearrangement can take place: the split will be "around its single element and both halves will be empty. The relation p < q gives us therefore another necessary criterion for continuation, and we can look to see whether we can make it the sole criterion for continuation. Because we want to stick to p ≤ f ≤ q, the termination via the luck of hitting f with the split, i.a. f = s; has to generate p = f = q. The following program would achieve that result. integer p, q, s; p:= 1 q := N; while p < q do begin s:= split(A, p, q); if f = s then begin p:= f; q:= f end else if f < s then q:= s-1 else p := s+1 end

From the above program text it is obvious that th operator "split" will only be applied to sections of the array containing at least two elements.

A more intricate use of the operator "split" is in complete sorting of the array, observing that after application of the operator "split" at least one element (viz. A[s]) has reached its final destination, while all other elements, although not necessarily in their final position, will be in the correct half, so that complete sorting then consists of sorting both halves independently.

The naive approach is a recursive

procedure sort(real array a, inteqer value p, q); begin integer s; s:= split(a, p, q) if p < s - 1 do sort(a, p, s-1); if s + 1 < q do sort(a,s + 1, q) end such that the call sort (A, 1, N) will sort the entire array. Again it has been exploited that sorting an array section is only a necessary operation if the section contains at least two elements. (The routine "sort" may be called with a section of only one element,but will not generate such calls itself.)

We have called the above procedure naive and we have done so for the following reasons. The operator "split" may divide the section offered to it into two very unequal parts -e.g. when originally the rightmost element had a near maximum value�; as a result the maximum dynamic depth of recursive cells may grow proportionally to N, the length of the array section. As recursive calls require an amount of storage space proportional to the dynamic depth, the given program may turn out to be prohibitively demanding in its storage requirements. This would lead to the conclusion that recursioe sorting is impractical, but for the fact that a slight rearrangement of the procedure "sort" ensures that the maximum dynamic depth will not exceed logSUB>2 N. In view of the existence of such a sorting procedure we call the previous one "naive".

We can guarantee that a sorting routine will not generate a dynamic depth exceeding log₂ N, if whenever it has called "split", it will only prescribe a recursive call on itself for the sorting of the smallest of the two halves. (In the case that the two halves are of equal length, the choice is immaterial.) Applying "sort" recursively to the smallest half only will leave the other half unsorted, but this can be remedied by repeatedly applying this only half�effective sorting effort to the still unsorted section. In the body of "sort", two integers "pu" and "qu" are introduced, pointing to the left- and right-hand end of the still unsorted section. procedure sort(real array a, integer value p, Q); begin integer s, pu, qu; pu := p; qu := q; while pu > qu do begin s:= split(a, pu, qu) if qu - s < s - pu then begin if s + 1 < qu do sort(a, s-1, qu); qu;= s - 1 end else begin if pu < s - 1 do sort(a,pu, s-1); pu:= s + 1 end end end

Again, sort may be called with,section of a single element, but will not generate such calls itself.

Exercise.Prove that termination of the loop is guaranteed to take place with pu = qu. Note. If, to start with, the elements of array A are ordered according to non- decreasing magnitude, excessive depth of recursive calls has been prevented,but the algorithm remains time�consuming (proportional to N ² ). This has given rise to refinements of the procedure "split": instead of blindly taking the right-most element of the array section as splitting value, some sort of small search for a probably better approximation of the median value can be inserted at the be- ginning of "split": this element can be interchanged with the rightmost element and thereafter split can continue as described.

Transcribed by Martin van der Burgt

EWD288

Concern for Correctness as a Guiding Principle for Program Composition.

A State of the Art Report, at least when written by me, is always a mixture of fact and fiction. It is mainly fact but, in a genuine effort to be up-to-date, I cannot refrain from some extrapolation into the future, and a certain amount of wishful thinking on my side is bound to leave its traces. Let it be so.

Let me start with a well-established fact: by and large the programming community displays a very ambivalent attitude towards the problem of program correctness. A major part of the average programmer's activity is devoted to debugging, and from this observation we may conclude that the correctness of his programs —or should we say: their patent incorrectness?— is for him a matter of considerable concern. I claim that a programmer has only done a decent job when his program is flawless and not when his program is functioning properly only most of the time. But I have had plenty of opportunity to observe that this suggestion is repulsive to many professional programmers: they object to it violently! Apparently, many programmers derive the major part of their intellectual satisfaction and professional excitement from not quite understanding what they are doing. In this streamlined age, one of our most under-nourished psychological needs is the craving for Black Magic, and apparently the automatic computer can satisfy this need for the professional software engineers, who are secretly enthralled by the gigantic risks they take in their daring irresponsibility. They revel in the puzzles posed by the task of debugging. They defend —by appealing to all sorts of supposed Laws of Nature— the right of existence of their program bugs, because they are so attached to them: without the bugs, they feel, programming would no longer be what is used to be! (In the latter feeling I think —if I may say so— that they are quite correct.)

All this becomes the more surprising when we contrast it with a mathematical technique that is justly famous for its efficiency and its high (and generally accepted!) convincing power, viz. killing a conjecture by means of a single counter-example. Everyone accepts the strength of that killer, but when a program fails, believe it or not, its author will defend himself by explaining that it was only (!) a very, very special case where it went wrong!

In other words, compared with what it should (and what it could!) be, the average programmer's professional standard is shockingly low. Mind you, I am just observing (and making a value judgement!), I am not blaming the average programmer, for he has to work under rather unfortunate circumstances.

Firstly, as a rule he is not free in the choice of his programming tools and the most widely used programming languages are rather inadequate vehicles: when FORTAN has been called an infantile disorder, PL/1 must be called a fatal disease and for COBOL I have no words..... In the case of programming languages I am very much interested in their influence upon the thinking habits of their users: particularly in the case of what is becoming known as "the pure FORTRAN environment" the strength of its intellectually degrading influence is, as a rule, grossly underestimated. Yet thousands and thousands of programmers still have to live (and die?) in it.

Secondly —and as I would like to avoid a lawsuit for libel, I shall refrain from mentioning any manufacturer's name, but I trust my readers to be able to supply what I have omitted— language implementations and the operating systems supporting them have grown into baroque monstrosities with most curious and —worse!— changing properties. And when programmers have to erect their "computational edifices" on such shaky foundations, it is hardly amazing that they regard full confidence in the correctness of one's program as a ridiculous presumption. In the old days one of the most fundamental properties of automatic computers was that by means of one's program one could keep complete control over what was going to happen. This property was, and still is, essential for the computer's usefulness: many modern computing systems, I am sorry to say, don't have this property anymore, and from adequate tools they have become depressing burdens. The proliferation of error-loaded and therefore unreliable software has done endless harm in the minds of those who tried to use it: one does not gain automatically from experience and the struggle with "the third generation" offers, alas, an example of how the wrong experience may easily corrupt the soundness of one's judgement.

If the sorry state of affairs described above were a complete picture, it would indeed be most depressing, and we might wonder whether we had not better look for a suitable branch on the nearest tree. Thank goodness, the picture is not complete, there are already on our side of our intellectual horizon the first solid glimmers of hope; it is to those glimmers of hope that the remaining part of this contribution is devoted. For me, the Conference on Software Engineering, sponsored by the NATO Science Committee and held at Garmisch in October 1968, has been a turning-point: it was the first time I witnessed a group of experts —all of them so high in their local hierarchies that they could afford to be honest— unanimously admitted that a software crisis did indeed exist. This struck me as very important, because before its existence was admitted it was vain to hope that something could be done about it.

When we wish to raise the confidence level of our designs the first question to ask is: "On what can we base our confidence?". This question has been explored; well, programmed computers may be amazing pieces of equipment, but as it turned out, many times more amazing are the flimsy grounds on which we have been willing to believe that their output was the output we wanted!

A program can be regarded as an (abstract) mechanism embodying as such the design of all computations that can possibly be evoked by it. How do we convince ourselves that this design is correct, i.e. that all these computations will display the desired properties? A naive answer to this question is "Well, try them all.", but this answer is too naive, because even for a simple program on the fastest machine such an experiment is apt to take millions of years. So, exhaustive testing is absolutely out of the question. As a result, testing by random sampling is hopelessly inadequate as well, because even the most vigorous exercising possible will only cover a truly negligible fraction of the possible number of cases, and whole classes of in some sense critical cases can —and will!— be missed: only the most obvious blunders will show up. The first moral of this story is that program testing can be used very efficiently to show the presence of bugs, but never to show their absence.

But as long as we regard the mechanism as a black box, testing is the only thing we can do. The unescapable conclusion is that we cannot afford to regard the mechanism as a black box, i.e. we have to take its internal structure into account. One studies its internal structure and on account of this analysis one convinces oneself that if such and such cases work "all others must work as well". That is, the internal structure is exploited to reduce the number of still necessary test cases, for all others (the vast, vast majority) one relies on reasoning. In spite of the fact that many, many programmers have dimly suspected that the solution can only be found in this direction, they seldom make more than a half-hearted attempt at it, the snag being that the amount of reasoning needed often becomes excessive.

Yet this function of the mechanism's internal structure opens a new and promising way to attack the reliability problem. Once we have seen that the required confidence level can only be reached by virtue of the structure of the program, that the extent to which program correctness can be established is not purely a function of its external specifications and behaviour, but depends critically upon its internal structure, we can invert the question and ask ourselves "What forms of program structuring can we find, what elements of programming style and what forms of discipline, all to raise the confidence level of our final product?".

So, instead of trying to devise methods for establishing the correctness of arbitrary, given programs, we are now looking for the subclass of "intellectually manageable programs", which can be understood and for which we can justify without excessive amounts of reasoning our belief in their proper operation under all circumstances. This is done in order to reduce the number of test cases needed; in the case of programs —i.e. abstract mechanisms— there are now strong indications that this approach can be so effective that the number of test cases needed is eventually reduced to zero, i.e. that the correctness can be shown a priori.

If the amount of reasoning needed is to be kept tolerably low, it is absolutely necessary that the number of cases between which we have to distinguish (in our reasoning!) combine additively, rather than multiplicatively. This implies that in program composition we must exploit our power of abstraction and our ability to introduce useful concepts as effectively as is done in any other branch of mathematics. (And what is more, we have to exploit these powers very consciously, firstly, because of the lack of tradition in programming, but secondly because programming is a highly creative activity in which we aim at constructing things of an eventual degree of sophistication much higher than the average mathematical theory.)

In answer to the above challenge, two developments are taking place. The first is an investigation as to what structural properties make a program "intellectually manageable"; the second is a search for a methodology for constructing such intellectually manageable programs.

With regard to desirable program structure, one or two very clear conclusions have been reached. When programming, one should constantly bear in mind that although the program text is the last thing that leaves the programmer's hands, the true subject matter of his trade consists of the possible computations that may be evoked by his program, the "making" of which computations he delegates to the machine. When we say, sloppily, that a program is OK, we mean that the corresponding computations satisfy the requirements. In other words, we should regard programmer's activity not so much as "producing programs", but rather as "designing a large class of computations". (From this point of view measuring a programmer's productivity by the number of lines of code produced per month is as ridiculous as measuring a composer's productivity by the number of notes scribbled on his score!) The obligation to keep our intellectual grip on what may happen in time, while the static program text is the last thing we can lay our hands upon, the obligation to understand the computations as they evolve in time via the tangible program text, yields an urgent plea to keep the sequencing rules, i.e. the mapping between the progress through the program text and the progress through the computations, as straightforward as possible. In sequential programming one can —and should— do this by abstaining from the goto statement and by performing all sequencing control by conditional, alternative, selective and repetitive clauses and the subroutine mechanisms. In view of our obligation to bridge mentally the conceptual gap between the static program text and the dynamic computations, the goto statement must be exposed as one of the combinatorial complexity generators we have been looking for.

While the above conclusion deals with avoiding unnecessary complexity, the next ones deal with the exploitation of our powers of abstraction for the purpose of mastering the inherent complexity. They deal with operational abstraction and representational abstraction.

Operational abstraction is well-known; in program texts it is reflected by subroutines or by indentation. It is the kind of encapsulation that we find applied in the structure of any mathematical theory: whenever a piece of mathematical reasoning appeals to a theorem, the only thing that matters on that level is what the theorem asserts, and on that level it is equally immaterial how the theorem has been proved (elsewhere, i.e. on another level). We can and should apply the same principle in program structuring, where it is rewarding to separate for each program component clearly "what it does" and "how it works". With the exception of the recursive routine, the level on which a component is used on account of what it does is always distinct from the level which is concerned with how it works. Our vision becomes unnecessarily blurred when we mix the two levels and try to understand the whole happening on the same, homogeneous semantic level; one has then destroyed a useful structure.

A specific application of the above sketched operational abstraction is the following. Whenever a program component is composed by means of a sequencing clause, encapsule it and find a description of its net effect in which the fact that it contains such a clause is no longer apparent. For instance, give to

"if x < 0 then x := -x"

the description "replace x by its absolute value", a description which is equally applicable to both cases. And if you don't have a ready-made function (such as the absolute value) at your disposal in terms of which to describe the net effect of such a compound component, invent this function and be sure that its properties are mathematically nice and also the ones you want. If you cannot find such a function, don't ignore that warning, for then you are on the verge of messing things up! (To give a hardware anology: when programming in machine code one can invoke the add-instruction but in doing so, it is on that level of interest immaterial whether the hardware invoked has a serial or parallel adder.)

Representational abstraction is concerned with compound data structures, which are ultimately represented by aggregates of variables of more primitive types. The level on which only the collection of possible values of a compound data structure matter is quite distinct from the level which is concerned with the question of how these composite values can be represented by aggregates of values of simpler types. One of the most common sources of program errors seems to be that an operation on a variable is inadvertently coded in terms of components of a specific representation. (E.g. in a binary machine one might be tempted to rephrase the question "is this integer even?" by "is the least-significiant digit of this integer equal to zero?" forgetting that this translation is not valid when negative numbers are represented by 1's-complements.)

With the subroutine we have the two sides of the operational coin, viz. "What does it do for you" versus "How does it do it"; with abstract data types we have the two sides of the representational coin, viz. "What values can it take" versus "How are these values represented". Most current programming languages cater the subroutine mechanism reasonably well for the operational abstraction; their facilities for representational abstraction, if any, are less convincing. The possibility of having representational abstraction reflected in the program code as well seems, however, to be equally essential.

The final subject to be touched upon is a methodology for constructing such "intellectually manageable" programs. Without the framework of this contribution, I can only touch upon it, because it is very intimately linked with the much larger and more general field of heuristics: "What are for the human mind the most effective ways of finding solutions to problems?". To my amazement —apparently I am a very naive person— I find even reasonably creative mathematicians rather unwilling to face this question: the mere suggestion that some sort of helpful answer to that question could be given at all has a tendency to strike them as sacrilegious. (Again I suspect that the mystery in which the act of creation is also kept enwrapped so tenaciously, satifies one of our deeper, otherwise under-nourished psychological needs.) In the restricted field of programming, such a methodology has a much better chance of survival, firstly because, by sheer necessity, programmers have to be more conscious of methodological aspects, secondly because they are often faced with (huge) problems for which the possible existence of a solution, however, is pretty obvious.

My thesis is, that a helpful programming methodology should be closely tied to correctness concerns. I am perfectly willing to admit that I myself may be the most complete victim of my own propaganda, but that will not prevent me from preaching my gospel, which is as follows. When correctness concerns come as an afterthought and correctness proofs have to be given once the program is already completed, the programmer can indeed expect severe troubles. If, however, he adheres to the discipline to produce the correctness proofs as he programs along, he will produce program and proof with less effort than programming alone would have taken.

The framework of this contribution does not allow the inclusion of a worked-out example. Instead I shall try to sketch how the hand-in-hand construction of a program and its correctness proof guides the programming process.

I found what I regard as the quintessence of this methodology in the summer of 1968, when my attitude towards flowcharts changed radically. Up till that moment, I had regarded a flowchart as something incomplete, as a plan, as a (half-pictorial, but that is not essential) representation of my intentions, something that as a description would only make sense if all further details, down to the bottom, had indeed been supplied. But it was then that I saw that such a sketch of a program still to be made, could be regarded as an abstract version of the final program, or even, that it could be regarded as "the program", be it for a —in all probability hypothetical— machine with the proper repertoire of primitive actions operating on variables of the proper types. If such a machine were available, the "rough sketch" would solve the problem; usually it is not available, and actions and data types assumed have to be further detailed in the next levels of refinement. It is the function of these next levels to build the machine that has been assumed to be available at the top level, i.e. at the highest level of abstraction. This most abstract version is now no longer a draft of the final program, it is an essential part of the total program; its correctness is independent of the lower level refinements and can be established beforehand. To give this correctness proof before proceding with the lower level refinements serves many purposes. It establishes the correctness of the top level. Fine, but what is more important is that we do this by applying well-established theorems applicable to well-known sequencing clauses, and as a result it becomes most natural to avoid clever constructions like the plague. But the most important consequence is that the proof for one level ensures that the interface between itself and the lower levels has been given completely, as far as is relevant for that level; and also, by fixing in the interface only what the correctness proof really needs, the interface can be kept free from overspecification.

Finally, a word or two about a wide-spread superstition, viz. that correctness proofs can only be given if you know exactly what your program has to do, that in real life it is often not completely known what the program has to do and that, therefore, in real life correctness proofs are impractical. The fallacy in this argument is to be found in the confusion between "exact" and "complete": although the program requirements may still be "incomplete", a certain number of broad characteristics will be "exactly" known. The abstract program can see to it that these broad specifications are exactly met, while more detailed aspects of the problem specification are catered for in the lower levels. In the step-wise approach it is suggested that even in the case of a well-defined task, certain aspects of the given problem statement are ignored at the beginning. This means that the programmer does not regard the given task as an isolated thing to be done, but is invited to view the task as a member of a whole family; he is invited to make the suitable generalizations of the given problem statement. By successively adding more detail in the lower levels he eventually pins his program down to a solution for the given problem.

July 1970
prof.dr.Edsger W.Dijkstra
Department of Mathematics
Technological University
EINDHOVEN, the Netherlands

Transcribed by Hallgrimur H. Gunnarsson.
revised Thu, 8 Jul 2010

2 juni 1970 | EWD288a

Recensie voor het tijdschrift “Informatie”

Logica en model van Doede Nauta, W. de Haan, Bussum, 1970 (uit de serie “Het modelbegrip in de wetenschappen” onder redactie van Kees Bertels en Doede Nauta, waarin eerder verschenen “Inleiding tot het modelbegrip” van Bertels en Nauta).

Het boek is gedrukt op tamelijk dik papier (2.5 om voor nog geen 300 bladzijden) en, zoals voor romans niet ongebruikelijk, aan de openslaande kant zo gesneden, dat in het profiel de afzonderlijke katernen duidelijk voelbaar zijn, waardoor iets er in naslaan nodeloos onhandig gaat. Voor het overige is de afwerking van uitgeverszijde keurig, mits men niet valt over verschillende representaties van het cijfer “1” �zelfs op eenzelfde regel!— en de afwezigheid van onderscheid tussen de representatie van het cijfer “0” en die van de kleine “o”.

Over het gebruik dat de auteur van de gedrukte text als medium gemaakt heeft, is Uw recensent niet onverdeeld verrukt. Enerzijds is van de typographische mogelijkheden als vet en cursief kwistig gebruik gemaakt (waarbij Uw recensent het gebruik van cursieve druk als nogal hinderlijk ervoer, omdat hij niet ontdekt heeft, welke functie hieraan toegekend moest worden), anderzijds komt men zonder enige (bijv. typographische) waarschuwing passages tegen als “....., dan moet U een grammaticaal volgebouwde zin zijn.”, wat misleidend veel weg heeft van een (zij het wat vreemde) conclusie ten aanzien van de lezer! De auteur schrijft zelf even later “Zoals reeds opgemerkt zullen we de notatie-met-aanhalingstekens niet consequent volhouden.”; of de lezer met deze inconsequentie —die overigens bij logici merkwaardigerwijze niet ongebruikelijk is— gediend is, waagt Uw recensent te betwijfelen. Het is als programmeren zonder onderscheid te maken tussen “het adres A” en “de inhoud van de geheugencel met adres A”, in het naieve vertrouwen, dat de “intelligente machine” iedere keer wel weten zal, wat er bedoeld is!

Over de woordkeus van de schrijver wil Uw recensent geen oordeel vellen, want dit kan locaal geaccepteerd jargon zijn (”instantie” als kennelijke vertaling van het Engelse “instance” in de betekenis van “voorbeeld” of “specimen” was bijv. nieuw voor hem), de zinsbouw roept hier en daar wel vraagtekens op: ala wij lezen “Daarom zullen we in dit boek logische axiomastelsels vaak identificeren met de logische talen ‘T0’ die ze constitueren”, rijst wel de vraag, wie nu wie constitueren!

De welwillendheid, waarmee Uw recensent dit boek ter hand nam, heeft zich zonder veel moeite kunnen handhaven, totdat op pg. 67 haar een klap werd toegebracht, waarvan zij zich niet meer heeft kunnen herstellen. Na referentie naar de moeilijkheden, die de Grieken ondervonden bij de inpassing van het onmeetbare getal in hun denkraam, vervolgt de auteur vrolijk (teruggrijpend naar de iets eerder geintroduceerde decimale breuk): “Nu men een algebraisch representatiesysteem voor de onmeetbare getallen heeft gevonden —namelijk de oneindig voortlopende aperiodieke decimaalontwikkeling— is er echter geen enkele reden meer om deze getallen te discrimineren ten opzichte van andere getallen: ze zijn in geen enkel opzicht 'mysterieuzer' dan negatieve getallen of breuken, die eerst ook representatiedrempels moesten overwinnen.” Hoe de schrijver, die toch weten moet dat nÚch hij, nÚch iemand anders de decimaalontwikkeling gebruiken kan voor de representatie van een onmeetbaar getal, deze representatiedrempel zo luchthartig wegwuift (om niet te zeggen “zo lichtvoetig neemt”) is Uw recensent een volslagen raadsel. Vanaf dit punt ontrolt het boek zich verder als “a self-inflicted pain”, culminerend in een index, waarin “model” onderverdeeld in 21 subhoofdjes (alphabetisch van en met het “abstract model” tot en met het “tegenmodel”) is opgenomen. En passant lijkt het boek de zoveelste bevestiging van de vrees, dat het centraal stellen van de verzamelingenleer, wat zovele vernieuwers van het wiskunde-onderwijs als heilsboodschap brengen, bij nader inzien neerkomt op pretentieus boerenbedrog.

Kortom, het boek was niet voor Uw recensent geschreven; hij vraagt zich wel af, voor wie dan wel.

Prof.dr. E.W. Dijkstra

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD292

to professor C.A.R.Hoare
Department of Computer Science
The Queen's University of Belfast
BELFAST BT7 1NN
Northern Ireland

Monday 31 August 1970

Dear Tony,

May I ask you a few things? My first question is very simple: I should like a new copy of "FIND", the paper you sent to the members of WG2.3, because I lost mine —someone borrowed mine— before I had paid all attention to it that it deserves.

My second question is more demanding: I should like to have your comments on the following thoughts. I ask this to you because on the subjects dealt with I consider you to be the world's expert. (Yet I hesitate as my question might be very demanding: I cannot predict how much re-adjustment from your side is required to follow my considerations. In all probability I use the usual words —such as "value" and "reference" in a slightly different meaning!)

I associate with a variable the following things:

it may have a name —"x" say— so that a program may refer to it

it will have a finite life-time, during which it will have a unique identity

it will be "of a type", i.e. associated with it will be a collection of possible values

at any moment during its life-time it will have one of the values of its type ("any moment" with respect to a sufficiently coarse grain of time, in which "changing its value" is an instantaneous operation)

given the identity of a variable, its value is uniquely defined; as many variables may have equal values, given its value, its identity is in general not uniquely defined

if "x" is the name of a variable, in program texts "ref x" will stand for its identity, "x" will stand for its value with two exceptions, viz.,

when preceded by "ref"

when standing at the left of an assignment operator

besides the reference prefix we have the evaluation operator "val". Its function is given by

val ref x = val (ref x) = x .

Exception 6b) is introduced for compatibility reasons mainly. It allows us to write in the usual way

x := x + 1

instead of the more cumbersome

ref x:= x ;

if I wanted to do this with the assignment procedure "assign" I would have to write

assign(ref x, x+ 1).

If "y = ref x" then "val y = x", so I could write also

val y:= x + 1            or            assign(y, x + 1) .

The assignment operator does two things: it assigns a new variable to a variable (with an identity, i.e. for which we need its identity), it also destroys its old value. Exception 6b) tells us that our notation convention is to write down the indication of the value destroyed, the value replaced:

"x:= x + 1" is read:

"the value of x is replaced by its value plus one". If the left hand side starts with val, the reference in question is found by omitting "val", otherwise by prefixing it with "ref". (At the beginning I was very unhappy about this convention, after some time I found that it makes sense: you mention "old" and "new" value.)

If y is a value of type "reference" its type comprises the type of val y

Given three variables a, b and c, compare the two programs

1) printing the maximum value.

var max: real

if a > b then max:= a else max:= b;
if c > max do max:= c;
print(max)

2) changing the sign of the maximum value

var max: ref real;
if a > b then max:= ref a else max:= ref b;
if c > max do max:= ref c;
val max:= - val max

With the above two examples I have made my first point, viz. to find a clean interface expressing when evaluations have to take place, when I operate on values, when on identities. Any well-motivated suggestion about syntactic sugar (for the declaration for instance) is welcome.

The next point deals with types and type control. When declaring a variable its type should be given either

var prime: boolean

i.e. naming a type, or

var prime: (true, false)

i.e. enumerating its possible values.

The latter arrangement suggests to write

type bintree:

     (tree1,

     tree2(number: real, left:bintree, right:bintree))

Here we introduce a type called "bintree" with two mutually exclusive values, either "tree1", which is used to denote the empty tree, or "tree2" which is a node comprising three variables called "number" (of type "real"), "left" and "right" both of type "bintree". Upon assignment of the value tree2, three suitable values should be supplied as actual parameters.

We can now write the boolean procedure "in" testing whether a given value is in a tree or not and adding it to the tree when it is not.

boolean procedure in(T: ref bintree, num: val real)
            case val T of
           (= tree1: {in:= false; val T:= tree2(num, tree1, tree1)}
           = tree2: {case number(val T ) of
                      (= num: {in:= true}.
                      > num: {in:= in(ref left(val T ), num)}.
                      < num: {in:= in(ref right(val T ), num)})).

or, if you prefer a non-recursive procedure

boolean procedure in(T: ref bintree, num: val real)
begin var curtree ref bintree:= T ; (this is an initializing declaration.)
         var found: boolean:= false;
         var diff: real;
         while val curtree = tree2 and non found do
         begin diff:= number(val curtree) - num;
                  if diff = 0 then found:= true
                                 else
                     curtree:= if diff > 0 then ref left(val curtree)
                                              else ref right(val curtree)
         end;
         if non found do val curtree:= tree2(num, tree1, tree1);
         in := found
end

To use the type and the procedure one can declare

var TREE: bintree:= tree1; in(ref TREE, 3.25) .

A complication arises when we want to write a procedure removing the minimum element from a tree. In the heading we want to describe that initially it should be a non-empty tree; as a result of the call, however, it could become empty. I suggest as heading

real procedure minmove(T: ref tree2 - bintree)

telling that initially the actual parameter is restricted to the subtype "tree2" while eventually it may be of the general type bintree. A non-recursive version then is (after the above heading)

begin var curtree: ref bintree:= T;
         var leftree: ref bintree:= ref left(val T );
         while val leftree = tree2 do
                  begin curtree:= leftree; leftree:= ref left(val leftree) end;
         minmove:= number(val curtree); val curtree:= right(val curtree)
end

(note: the heading of "in" could be:

boolean procedure in(T: ref bintree - tree2, num: val real) )

In all this I am aiming at an interface such that a translator can do all type checking. I have a strong feeling that if this cannot be done, one has the wrong concept of type! To ease this analysis I am willing to add syntactic sugar (in the form of the type-controlled case clause or the type-controlled while clause.) I hope that a translator can check that the call of "minmove(ref TREE)" will only occur with TREE = tree2.

I know that you have paid much attention to such questions in an earlier stage of your life; it is only now that I am beginning to become ripe for such questions and would value your comments very much. Yours are fine shoulders to stand upon!

Thank you for the handwritten letter with the sketch of a proof for the transposition algorithm. I am glad that you enjoyed the algorithm. Some fifteen years ago I was introduced to Christopher Strachey by Aad van Wijngaarden at some conference. Aad and I entered a restaurant and Christopher was sitting alone at a table. Aad asked whether we could join him and we were introduced. Christopher posed the problem and within five minutes —this was a time when I was still a bright boy!— I produced the solution. Some months ago the problem was posed to me again, I recognized the problem but had forgotten my solution; this second time it took me ten minutes to reconstruct it. this just shows what age does to you! My grapevine tells me that you have shown the algorithm both to Brian Randell and Niklaus Wirth. Small world we live in!

Returning for a last time to the main subject of this letter: I am looking for a program representation from which it is at any moment obvious which values are defined (and how) and which are not. The two mutually exclusive forms of the value of a variable of type bintree are suggested by the analogy of the recursive procedure which must contain a condition call upon itself. The node which is either empty or "a set of fields" is the spatial analogue of "if B do S" which, when executed, takes one of two mutually exclusive forms, either empty or S.

Shall I have the privilege of your answer to my questions?

Yours ever

Edsger

                          prof.dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Thu, 8 Jul 2010

EWD295

Reisverslag van bezoek aan het Seminar on the Teaching of Programming at University Level.

De vier hoofdsprekers waren (involgorde van optreden) ondergetekende (4 uur), Knuth, Iverson en Parlis (alle 3 uur). Deze optredens waren allemaal te lang, te vermoeiend, zowel voor de spreker als voor het gehoor en een van de dingen, die ik me van dit seminar zal blijven herinneren is, dat dit geen goed arrangement is. (Ieder van ons begon met twee uur ononderbroken!) De organisatoren lieten aan de sprekers het organiseren van discussies over; ook dit was niet gelukkig.

Mijn verhaal “The Art of Programming” liep redelijk, op een paar inzinkingen na; en ik heb te weinig expliciet ruimte voor discussie gelaten. Ik had in het begin wel gezegd, dat ik interrupties op prijs stelde, maar dat bleek onvoldoende. (Zo verging het de anderen ook.)

Don Knuth viel me wat tegen; ik weet nu echt, dat ik zijn encyclopaedie niet hoef te bestuderen. Die heet “The Art of Programming”, de titel van zijn lezing was “The Analysis of Algorithms” en dat is een veel adequatere titel. Hij heeft de instelling van een non-toegepast wiskundige: computing science is voor hem voornamelijk een onuitputbare bron voor zijn puzzletjes. Het is heel merkwaardig, misschien is het erg Amerikaans: eerst geven ze computing science de meest vulgaire motivering (minimizing resource usage), en vervolgens keren ze zich er met enige walging van af “to do the really interesting problems”. Zo vind je Don Knuth trots de variantie bepalen van het aantal gegenereerde carries bij een optelling in het b-tallig stelsel, terwijl het enige belangrijke is de lengte van de maximale carry-trein!

Iverson was walgelijk, dit was een “slick commercial” over APL. Het weerzinwekkendst vond ik zijn grofheid jegens zijn publiek. Als het zijn bedoeling is geweest om APL te verkopen, dan is hij hierdoor niet geslaagd: het publiek accepteerde hem niet. Ik kan het ontwerp geen consistentie ontzeggen (zal dat ook niet doen), wat op het eerste gezicht alleen maar ad-hoccery lijkt, blijkt meestal op een of andere manier overwogen. Het heeft mijn indruk bevestigd dat de invloed van APL op zijn gebruikers funest is: it is a giant bag of tricks! En inplaats van dat het de neiging programmeren te zien als puzzlen bestrijdt, moedigt het gereedschap deze opvatting aan. Ik dacht —en geloof dit nog— dat programmeren in de eerste plaats een conceptuele uitdaging is en zie niet, hoe APL in dit opzicht een stap vooruit is. Het treft mij zelfs als een stap achteruit.

Perlis was bijzonder aanhoorbaar. Zijn inleiding vond ik erg verhelderend, waarin hij betoogde, dat “programma correctheid” niet los gezien kon worden van wat het programma doen moest, daardoor onverblekelijk verbonden was met ons theoretisch inzicht in de toepassing! De intellectuele uitdaging, die het bestaan van computers inhoudt, wordt daarmee tot de behoefte aan fatsoenlijke theorieen, over activiteiten, die we tot nog toe intuitief, op zijn Jan-Boere-Fluitjes of niet deden. Het overtuigendst vond ik de beschrijving van het eerste college (hij beschreef er drie), waarin hij “from top to bottom” de relatie mens -> algorithme -> taal -> machine -> mens beschreef. Eerst programmeren in een hogere programmeertaal en dan, naarmate de verwerking van de algorithmen gedetaileerder behandeld wordt, de taal van zijn franje ontdoen. In zijn tweede college vergeleek hij verschillende programmeertalen, in het derde besprak hij kwaliteitsaspecten van programmeertalen. Het streven was nobel, maar dit laatste vond ik minder overtuigend, te meer, doordat hij zich kennelijk nogal gebonden achtte aan wat er was.

Twee sprekers (elk van een Engels software house) hebben de praktijk van het programmeren in de industriele omgeving op hun eigen manier belicht. d'Agapeyeff streek het gehoor erg tegen de haren door te betogen, dat hij aan de computer scientists zoals ze van de universiteit kwamen, zo weinig had. Hij stelde daar zijn eigen, interne opleidingsprogramma tegenover; de algemene reactie was, dat het een voortreffelijke taakverdeling was, dat hij zijn eigen mensen dat dan maar moest leren, dat dit soort opleiding onmogelijk, op de weg van de universiteiten kon liggen. De vraag werd zelfs gesteld, of hij voor dit soort werk wel “graduates” nodig had. Door zijn overdrijving kwam deze discussie niet goed op gang. Jackson liet zien, wat in zijn bedrijf gebeurde; dit was een warm pleidooi voor structurering, dat bij het publiek beter in de smaak viel. (Wat natuurlijk ook aan het publiek lag!)

J.Aron (Federal Systems Division, IBM) hield een verhaal in de terminologie van de manager. Mensen, die dit nooit hadden gehoord of niet wilden horen, werden er erg boos over. Ik persoonlijk heb een zwak voor deze man, ik heb me niet geergerd en er zelfs wat van geleerd: FSD probeert om van de “Chinese Army Approach” af te komen. Of ze daarin succes zullen boeken, lijkt erg de vraag, aangezien de behoefte aan the Chinese Army voor een niet gering gedeelte gedicteerd wordt door de barokheid van het gereedschap. Het was boeiend te horen, dat ze er van af wilden, tot een jaar geleden konden ze ons met reden omkleed aantonen, dat the Chinese Army de enige mogelijk was!

Wat de “gemiddelde” deelnemer van dit seminar heeft opgestoken, in welke richting zijn denken gestimuleerd is, vermag ik niet te taxeren, het is voor mijzelf zelfs erg de vraag, of, en zo ja, hoe, ik er als een wijzer mens vandaan ben gekomen. Een aantal mensen hebben op de laatste middag samenvattingen van hun indruk gegeven (van der Sluis, Hoare, Wirth, Samelson en Michaelson). Zelfs als ik er van af trek, dat ze daar stonden in een positie die er om vraagt om vriendelijke dingen te zeggen, leek het toch, of ik het er niet zo slecht van af gebracht had. Mij viel op, dat ik unaniem als “artist” geclassificeerd werd; ik vraag me wel af, wat ze er mee doen en wat ik daar mee doe! Het concept van “Structured Programming” slaat erg aan, het lijkt voor mij noodzakelijk om in deze stijl nu eens iets groots aan te pakken, maar ik ben daar wel bang voor. Er moeten dan een heleboel detailbeslissingen genomen worden en tot nog toe heb ik voornamelijk aangetoond, dat deze allemaal onverwacht veel zorg vergen.

Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 08-Jan-2012

EWD298

Informatica als wiskundige discipline.

In het volgende is mijn visie op het vak “informatica” neergelegd, een visie die sterk medebepalend is zowel voor mijn opvattingen over gewenste onderwijsactiviteiten als over mijn opvattingen over gewenste researchactiviteiten.

Het is een werkterrein dat actueel geworden is door de komst van machtige rekenmachines en een ontwakende technologie om machines te maken die opgebouwd zullen zijn uit een hoeveelheid actieve elementen die een orde van grootte hoger ligt dan wat wij nu gewend zijn. De gebieden, die ik kortheidshalve aanduid as “machinegebruik” en “machineontwerp” werpen enorme problemen op, die met “schaalvergroting” passend gekarakteriseerd zijn, mits wij ons steeds voor ogen houden dat deze schaalvergroting onvoorstelbaar groot is en wij ons tevens realiseren, dat wanneer twee dingen in een of ander opzicht een factor verschillen, dit verschil, naarmate de factor groter wordt, minder als gradueel en meer als essentieel verschil ervaren wordt.

De nuchtere observatie is dat wij in het afgelopen decennium al met een dusdanige schaalvergroting te maken hebben gehad, dat zowel machineontwerp als machinegebruik ons met een uitdaging hebben geconfronteerd, waartegen onze huidige intellectuele vermogens nauwelijks of zelfs niet meer opgewassen zijn. De problemen om een ontwerp, hetzij hardware, hetzij software, vrij van logische fouten te krijgen, begint formidabel te worden, reeds nu manifesteert zich een duidelijke discrepantie tussen wat wij in elkaar kunnen denken en wat van ons gevraagd (en daardoor door ons geprobeerd) wordt in elkaar te denken. Men hoeft de huidige ontwikkeling maar met een half oog gade te slaan om ervan overtuigd te raken, dat deze discrepantie alleen maar heel veel schrijnender zal worden. Daarom acht ik het de hoofdtaak van het vak informatica als geestelijke discipline om alle zeilen bij te zetten opdat wij beter opgewassen raken tegen deze intellectuele uitdaging.

Hoe wij ooit de conceptuele klaarheid kunnen bereiken in wat zonder die klaarheid een onbeheerste chaos wordt, zou onvoorstelbaar zijn, ware het niet, dat er een eeuwenoude traditie bestaat van mensen, die zich als hoodtaak gesteld hebben in een bepaald gebied door een passend gebruik van hun abstractievermogen juist de grootst mogelijke klaarheid te bereiken. Deze mensen heten sinds eeuwen “wiskundigen” en het is daarom dat ik de informatica slechts zien kan als een nieuwe tak der wiskunde, met de nadruk op “nieuw” en op “wiskunde”. Het werk van de informaticus is het beheerst ontwerpen van “mechanismen”. Als iemand zegt “dat is nauwelijks wiskunde”, dan bedoelt hij daarmee, dat een groot gedeelte van de thans en vogue zijnde “bags of tricks” slechts beperkt hier bruikbaar zijn, dan bedoelt hij, dat traditioneel wiskundigen zich maar zijdelings met de studie van “mechanismen” hebben beziggehouden. Dat is waar, maar ik kan me niet anders voorstellen, dan dat deze traditie in het verleden gegroeid is omdat in dat verleden deze problemen zo weinig actueel waren; ik zie niet in waarom dat zo zou moeten blijven, sterker ik vind dat het riet zo hoort te blijven en als het aan mij ligt zal het ook niet zo blijven. Wie zegt “informatica is nauwelijks wiskunde” zegt voor mijn gevoel —en daar kan ik het dan wel mee eens zijn— “het is niet een van de traditionele takken der wiskunde”. Zoveel over de nadruk op het woordje “nieuw”. De nadruk op het woord “wiskunde“ komt omdat ik de wijze van werken van de competente informaticus ervaar als de wijze waarop de wiskundige werkt: er worden dezelfde eisen gesteld aan zijn vermogen tot abstractie en tot conceptvorming, aan rigot en elegance en —last but not least— het onderwerp is in wezen het abstracte mechanisme. Ik heb hier niemand minder dan Marvin Minsky aan mijn zijde —als je een beroemd man met instemming kunt citeren, vecht je zijn autoriteit niet aan!— die bij de bespreking van de relatie tussen (hardware) machine en manual ergens betoogt dat het manual niet een (eventueel onjuiste) beschrijving van de gegeven machine is, maar dat het manual de conceptuele machine beschrijft in termen waarvan de gebruiker denkt, terwijl de geassocieerde machine niet anders is dan een (naar wij hopen acceptabele) implementatie van deze conceptuele machine.

transcribed by Bart Vreugdenhil
revised 29-Nov-2011

03xx

300: Exit “The Programming Laboratory”

301: Over de bewijsbaartheid van programmacorrectheid

302: Design considerations in more detail

303: On the reliability of programs

306: Over het gewicht van een informatica-opleiding

307: (over een voorgestelde configuratie van een P1400 en vier P880’s)

308: Reisverslag bezoek van E.W.Dijkstra aan IFIP W.G.2.3 te Warwick, Engeland

309: (over een voorgestelde configuratie van een P1400 en vier P880’s)

310: Hierarchical ordering of sequential processes

311: [Review of] Bauer, Goos: “Informatik, Erster Teil” Heidelberger Taschenbuecher, Band 80 Springer Verlag, 1971

312: Verslag van reis van E.W.Dijkstra naar Noord Amerika

316: A short introduction to the art of programming

316A: Reisverslag van Edsger W.Dijkstra aan Summer School Marktoberdorf, juli 1971

317: On a methodology of design

319: A class of allocation strategies inducing bounded delays only

325: Poging tot plaatsbepaling van de Informatica

330: [Book review of: Bauer-Goos, Informatik, Zweiter Teil]

338: Parallelism in multi-record transactions (with C.S.Scholten)

340: The humble programmer

341: [Toespraak over de noodzaak van programmeermethodologie]

343: Reisverslag betreffende het bezoek aan de USA van 14 tot 30 mei 1972 door E.W.Dijkstra

345: Ter zake van wiskundige modelvorming

348: Verslag van de reis van E.W.Dijkstra naar Boston, 12–18 augustus 1972

349: Ontwikkelingsplan Informatica

351: Verslag bezoek Engeland 30 augustus – 9 september 1972

353: Elementen ener afstudeerrichting in de informatica

356: Advanced Course on Computer Systems Architecture (Grenoble, December 1972)

361: Programming as a discipline of mathematical nature

362: Bezoek van E.W.Dijkstra aan l’Alpe d’Huez, 8–15 december 1972

363: Reisverslag E.W.Dijkstra: Open house on semantics, Aarhus, 7–18 jan. 1973

364: Weledelgestrenge Heer, Ingenieur Swinkels

365: A parabel

366: Waarom ik niet gewoon hoogleraar wil blijven

368: Verslag van bezoek aan Washington, maart 1973

374: The analysis of multiprogrammed systems of unspecified degree of parallellism

375: A non algebraic example of a constructive correctness proof

376: Finding the maximum strong components in a directed graph

379: On a connection pattern between 2**N elements

384: Betrouwbaarheid van programma's

385: Trip report E.W.Dijkstra Summer School Munich, July 25 to August 4, 1973

386: The solution to a cyclic relaxation problem

387: Trip report IBM Seminar “Communication and Computers”, Newcastle, Sept. 1973

389: Trip report I.U.C.C. Colloquium, Canterbury, 18th–21st Sept. 1973

391: Self-stabilization in spite of distributed control

392: Self-stabilization with four-state machines

393: On representational abstraction

395: Trip report E.W.Dijkstra IFIP Working Group W.G.2.3 “On Programming Methodology”, 21st–26th October 1973, Blanchland, England

396: Self-stabilization with three-state machines

397: Self-stabilizing systems with distributed control

398: Sequencing primitives revisited

399: An immediate sequel to EWD398: “Sequencing primitives revisited”

EWD300

Exit "The Programming Laboratory".

Een negatieve uitslag.

Het doel van het project, dat sinds een jaar is overwogen, was om studenten in een ideale —dwz. passend geidaliseerde— omgeving metterdaad op allerlei niveau relevante ervaring op te laten doen op het gebied van software engineering. Aangezien wij het voor de competente software engineer een belangrijke ervaring achtten in een groot complex systeem zijn bijdrage als integererend bestanddeel te leveren, vonden we het scheppen van de werkisituatie waarin de toekomstige software engineer zullks kan (be)eofenen wenselijk. Wij hoopten ten bate van onze studenten bovengenoemd doel te bereiken door met hen een groot complex systeem netjes op te bouwen

Enkele specifieke doelstellingen stonden hierbij voorop.

1) In weerwil van de uiteindelijke complexiteit moest het systeem "kenbaar" en "beschrijfbaar" blijven, een eis waaraan gangbare systemen, gemeten naar de norm die we ons inmiddels hebben aangemeten, tamelijk tot schromelijk tekortschieten. Wij stelden ons voor door een stringent volgehouden gelaagde structuur met zeer zorgvuldig gekozen interfaces dit ideaal te bereiken. Aan de eis, dat neiuwe studenten zich op grond van de inmiddels bestaande documentatie zich snel op een bepaald niveau zouden kunnen inwerken, wilden wij de voortdurende prikkel tot de hiervoor vereiste zelfdiscipline ontlenen.

2) De eis dat studenten op allerlei niveau van het systeem moesten kunnen meerwerken en experimenteren, impliceerde dat "modulaire opbouw" veel meer dan een loze kreet moest zijn. Sterker, dorrdat "modulariteit" een van de belangrijkste doelstellingen zou zijn, verwachtten we, dat het systeem niet onaanzienlijk van gangbare, bestaande systemen zou afwijken.

3) Misschien haast nog meer dan het uiteindelijke systeem zou de wijze, waarop het moest worden opgebouwd en zou kunnen worden gewijzigd, in het centrum van de belangstelling staan, Het kan niet anders of dit moest ons inzicht in de automatiseringsmogelijkheden bij software productie aanzienlijk verdiepen; het is voor deze automatisering waar we mettertijd een belangrijk werkterrein voor het systeem zagen liggen.

4) In de openingszin hebben wij het scheppen van een "passend geidealiseerde" omgeving genoemd. Wij stelden ons voor dat wij ons de wrijheid zouden voorbehouden royaler met geheugen en rekentijd om te springen dan tot op heden gebruikelijk is. Enerzijds zouden wij hiertoe gedwongen zijn door gebrek aan mankracht, die ons immers verbiedt het onderste uit de kan te willen halen, willen we überhaupt van de grond komen. Anderzijds mocheten we, in het licht van het feit dat hardware in prijs steeds daalt, verwachten, dat hiermee op modernere wijzen van computergebruik geanticipeerd zou worden.

Op grond van de ervaringen van afgelopen jaar meen ik tot de conclusie te komen, dat ik met dit project te hoog en vooral te groot gegrepen heb. Een en ander klemt des te meer omdat de vrijheid ruimer dan gebruikelijk met geheugen om te springer een thans toch nog forse inverstering noodzakelijk zou maken.

In het afgelopen jaar is de poging om vorm aan het project te geven, hoewel niet helemaal zonder succes, onvoldoende opgeschoten. Hierbij hebben oorzaken van naar wij hopen voorbijgaande aard een rol gespeeld —de onrust of ik naar Stanford zou gaan en mijn gezondheid, om er een paar te noemen—; dat ik een paar maanden gegeven heb aan de voorbereiding van het college "Inleiding tot de Kunst van het Programmeren" is een voorbeeld vab interferentie van naar ik vermoed minder vergankelijke aard: dit college staat nu op poten, maar volgende jaren is er wel weer wat anders. Hoofdoorzaak is echter geweest, dat het project vooralsnog te moeilijk bleek.

In de afgelopen jaren is wel steeds duidelijker uit de verf gekomen hoe "een mooi systeem" er uit ziet, maar met een kwaliteitsnorm alleen los je nog geen problemen op. Hoewel ik er nog steeds van overtuigd ben, dat een systeem zoals ons voor ogen zweefde. "Mooi" bouwbaar is, raak ik er tegelijkertijd steeds meer van overtuigd, dat wij dit met de beperkte mankracht en slecht garandeerbare continuiteit niet op poten zullen krijgen in de periode van een jaar of wat, die mij ook voor de ogen zweefde.

Op het gebied van processor allocation is —in het afstudeerwerk van Bomhoff en Feijen— duidelijk vooruitgang geboekt. Op het gebied van virtual storage implemetation is, hoewel we er veel aandacht aan besteed hebben, duidelijk nauwelijks vooruitgang geboekt, we hebben "de passende idealisering" vooralsnog niet kunnen vinden. Dit heeft enige maanden aan mijn gemoedsrust gevroten, ik acht het moment gekomen om te erkennen, dat ik dat zelfs in twee vloeken en twee zuchten niet kan en uit deze erkenning mijn consequenties te trekken.

Ware het alleen de virtual storage implementation geweest, dan hat ik daar nog overheen kunnen stappen, dan had ik, zij het iets minder mooi, zij het iets minder overtuigend verdedigbaar, door kunnen gaan. Dat hebben we tentatief ook geprobeerd, maar toen begonnen zich niewe problemen af te tekenen, waarvan ik in eerste instantie verwacht, dat we er even machteloos tegenover zullen staan.

Er is een op het eerste gezicht nog betrekkelijk geisoleerd probleem, nl. welke rol dient men aan expliciet meegegeven parameters versus globalen toe te kennen. Ze zijn beiden op allerlei manieren implementeerbaar, dat is het probleem niet. Het probleem is, dat we niet over de criteria beschikken, op grond waarvan we overtuigend kunnen kiezen; als we het ene zouden doen en het andere niet zouden laten, zouden we een mechanisme geschapen hebben zonder te weten hoe we het gebruiken moesten. En bij het zoeken naar keuzecriteria hebben we moeten erkennen nog geen vaste grond onder de voeten gevonden te hebben.

Een minder geisoleerd probleem, dat begint op te doemen is het gebrekkige inzicht in automatiseringsmogelijkehden. Er bestaan bv. nauwelijks enigszins fundamentele artikelen over de mogelijkehden en beperkingen van bootstrapping. Nu was het de bedoeling van het programing laboratory project om zulke inzichten te winnen. Het wordt evenwel duidelijk dat het welslagen van het project critiek ervan af zal hangen of zulke inzichten inderdaad gewonnen worden. In het afgelopen jaar hebben we diepte van onze onkunde gepeild; op grond van deze peiling durf ik het project in zijn oorsrponkelijke reikwijdte niet meer aan.

Als de voortekenen niet bedriegen —dat hoop ik vurig en die hoop lijkt nu gerechtvaardigd— zal de volgende grote machine voor het rekencentrum met kop en schouders boven alle thans aan de markt zijnde alternatieven uitsteken. Ik besef, dat deze machine er in de eerste plaats zal zijn voor productiedoeleinden en dat de eis van continuiteit in de productie deze machine niet er beschikking zal stellen van het soort software experimenten, waartoe ik de mogelijkheden had willen scheppen. In dat opzicht is hij geen vervanging; hij maakt, als hij komt, een "programming laboratory" iets minder urgent: als gebruikers kunnen onze studenten in elk geval wel met een complex gezond systeem kennismaken. En als we mettertijd wel een programming laboratory creeren, is de noodzaak dat het "groot" is, daardoor —gelukkig!— kleiner.

Op grond van de genomen beslissing zal ik de bakens wat verzetten, hernieuwd analyseren, waar beter inzicht het meeste nodig is, pogen dit inzicht te verkrijgen in de hoop dat ik later wel een verantwoord voorstel kan doen. Ik hoop het project wat kleiner te kunnen krijgen en toch voldoende interessant te kunnen houden; tegelijkertijd hoop ik dat de alom aangekondigde projsdaling daadwerkelijk doorzet, zodat een research machine niet zo duur hoeft te zijn, want dat zou wel erg prettig zijn: hoe goekoper hij is, des te meer vrijheid ik zal hebben.

transcribed by Pascal Bourguignon
revised Fri, 18 Feb 2011

EWD301

Over de bewijsbaarheid van programmacorrectheid.

1)     Omdat "Verdeel en Heers" in eerste instantie het enige principe is, waarmee we iets groots aankunnen, zal een programma naarmate het groter is uit meer componenten opgebouwd moeten worden. Willen we voor het totale programma een zeker betrouwbaarheidsniveau bereiken, dan dient het betrouwbaarheidsniveau van de individuele programmacomponenten hoger te zijn naarmate het aantal componenten groter is.

2)     Testen van programma's kan een zeer overtuigende methode zijn om de aanwezigheid van fouten aan te tonen, maar is hopeloos inadequaat om hun afwezigheid aan te tonen. De enige mogelijkheid die ons rest is de correctheid van het programma te bewijzen.

3)     Aangezien de (bv. intellectuele) inspanning nodig voor de bewijsvoering critisch afhangt van de structuur van het programma, dient de programmeur zijn programma zo te structureren, dat bewijsvoering nog wel mogelijk is. Ik ga er hierbij van uit dat programma's behalve voor de machine uitvoerbaar voor de mens leesbaar moeten zijn. In het bijzonder dient de programmeur er voor te waken, dat het aantal gevallen, dat onderscheiden moet worden, additief en vooral niet mul- tiplicatief combineert.

4)     In dit licht dient het gebruik van de goto-statement ten sterkste afgeraden te worden: de goto-statement is als combinatorische complexiteitsgenerator ontmaskerd.

5)     De (bekende) sequentieringsclausules belichamen een aspect van programmeringsdiscipline, waardoor bewijsvoering profiteren kan van de postulaten van C.A.R.Hoare. Van het gebruik van deze postulaten zal een voorbeeld gegeven worden. Aan de hand hiervan zal het begrip "operationele abstractie" als middel ter beknotting van de hoeveelheid bewijswerk worden toegelicht.

6)     Aan de hand van een volgend voorbeeld zal het begrip "representationele abstractie" worden toegelicht. Ook dit dient ter beknotting van de hoeveelheid bewijswerk.

7)     Betoogd zal worden dat wij om de correctheid van programma's bewijsbaar te houden, programma's moeten leren zien niet als op zichzelf staande objecten, maar als leden van een familie aanverwante programma's: aequivalente programma's kunnen zich hier presenteren als alternatieve verfijningen van eenzelfde abstract programma.

8)     Tenslotte zal de hoop uitgesproken (en naar vermogen gerechtvaardigd worden) dat de bewijslast geen taakverzwaring voor de programmeur hoeft in te houden. Integendeel: als hij de bewijsvoering hand in hand met het programma laat groeien lijkt hij een waardevol r�chtsnoer bij de opbouw van zijn programma gevonden te hebben.

Edsger W.Dijkstra

EWD 302

Design considerations in more detail.

Preceding sections—in particular "A first example of step-wise program composition." have evoked the criticism that I have oversimplified the design process almost to the extent of dishonesty; I don't think this criticism fully unjustified and to remedy the situation I shall treat two examples in greater detail. The first example is my own invention; I have tried it out in a few oral examinations and finally I have used it at the end of my course "An Introduction into the Art of Programming" in the classroom. I posed the problem to an audience of fifty students and together, with me as leader of the discussion, they solved the problem in 90 minutes.

We consider a character set consisting of letters, a space(sp) and a point(pnt). Words consist of one or more, but at most twenty letters. An input text consists of one or more words, separated from each other by one or more spaces and terminated by zero or more spaces followed by a point. With the character valued function RNC (Read Next Character) the input text should be read from and including the first letter of the first words up to and including the terminating point. An output text has to be produced using the primitive PNC(x) (i.e. Print Next Character) with a character valued parameter. If the function of the program were to copy the text, the following program would do (assuming character valued variables at our disposal)

char x;
repeat x:=RNC; PNC(x) until x = pnt  .

In this example, however, the text is to be subjected to the following transformation:

in the output text, successive words have to be separated by a single space

 in the output text, the last word has to be followed by a single point

when we number the words 0, 1, 2, 3, ... in the order from left to right (i.e. in which they are scanned by repeated evaluation of RNC), the words with an even ordinal number have to be copied, while the letters of the words with an odd ordinal number have to be printed in the reverse order.

For instance (using "˽" to represent a space) the input text

"this˽˽˽is˽˽a˽silly˽˽program˽˽."

has to be transformed into

"this˽si˽a˽yllis˽program."  .

My reader is cordially invited to try this program himself, before reading on and to record his considerations so as to enable himself to compare them with the sequel. (It should take an experienced programmer much less than 90 minutes!)

The unknown length of the non-empty input text suggested a program of the structure

prelude;
repeat something until ready;
coda

but immediately this question turned up: "With how much do we deal during a single execution of "something?" Four suggestions turned up:

a single character of the input text

a single character of the output text

a word (of both texts)

two successive words (of both texts)

The first two suggestions were rejected very quickly and without much explicit motiviation, although —or because?— it is not too difficult to provide it. (The first one is unattractive because the amount of output that can be produced on account of the next character of the input text varies wildly; for the second suggestion a similar objection holds. Apart from that, a program with a loop in a loop is in general cleaner: this suggests to look for the larger portions.) The audience rejected the fourth suggestion on account of the remark that the terminating point could come equally well after an even number of words as after an odd number of words. To make the selection of the third suggestion explicit, we wrote on the blackboard:

prelude;
repeat process next word until point read;
coda

Everyone was satisfied in as far as this program expresses neatly that the output words are dealt with in exactly the same order as the corresponding input words are read, but it does not express that half of the words are to be printed in reverse order. When this was pointed out to them, they quickly introduced a state variable for the purpose. A first suggestion was to count the number of words processed and to make the processing dependent on the odd/evenness of this count, but a minor hesitation from my side was enough for the discovery that a boolean variable would meet the situation. It was decided that the "prelude" should include

forward := true;

while in "process next word" the printing in the order dependent on the current value of "forward" should be followed by

forward := ¬ forward

For me it was very gratifying to see that they introduced the variable forward before bothering about the details of word separation, which then became their next worry. It took them more time to realize that a further refinement of "process next word" required exact specification of which characters of the input text were going to be read and which characters of the output text were going to be printed at each execution of the repeatable statement. In fact, I had to pose the question to them and, after having done so, I asked them in which of the two texts the grouping presented itself most naturally. They selected the output text and chose the following grouping (indicating separation with a vertical bar):

|this˽|si˽|a˽|yllis˽|program.|

i.e. in units of a word followed by a proper terminator. I then asked for the corresponding grouping of the input characters. When their attention had been brought to the terminators, they suggested (from right to left!) the following separation of the input characters:

|this˽˽˽i|s˽˽a|˽s|illy˽˽p|rogram˽˽.|

as soon as one of them had remarked that the program could only "know" that an output word should be followed by a space after having "seen" the first letter of the next input word. I then remained silent, leaving them gazing at their grouping of the symbols until one of them discovered that the exceptional grouping of the characters of the first input word was inelegant, that the grouping should be

t|his˽˽˽i|s˽˽a|˽s|illy˽˽p|rogram˽˽.|

i.e. that the first character of the first word should be read in the prelude. Another variable was introduced and we arrived at

boolean forward; char x;
forward := true; x := RNC;
repeat process next word;
    forward := ¬ forward
until x = pnt

in which the second line represents the prelude; in the meantime it had been decided that the coda could be empty.

The above stage had been reached after the first 45 minutes and we had our interval for coffee. Personally I felt that the problem had been solved, that from now onwards it was just a matter of routine; as it turned out, my audience was not practised enough and it took another 45 minutes to complete the program.

Unanimously, they decided to introduce a

char array c[1:20]

to store the letters of the word. (No one discovered that reading the letters and printing them in the reverse order could be done by a recursive routine!) Essentially, four things have to be done: the letters of the word have to be read, the letters of the word have to be printed, enough has to be read to decide which terminator is to be printed, and the terminator has to be printed. I did not list these four actions, I did not ask for an explicit decision on how to group and/or combine them. The audience decided that first all reading should be done and thereafter all printing. (From their side this was hardly a conscious decision.)

Trying to refine the reading and the printing process they hit an unsuspected barrier: they were —at least for me: surprisingly— slow in discovering that they still had to define an interface between reading and printing through which to transmit the word to be processed, no matter how obvious this interface was. It took a long time before anyone formulated that c[i] should equal the i-th character of the word when read from left to right. Perhaps half of the audience was wondering what all the fuss was about, but it took an equally long time to discover that the length of the word needed some form of representation as well. No one suggested to do this by storing a terminator, they introduced a separate integer l, counting the number of letters of the word. They decided that the first word "this" should be represented by

c[1] = "t", c[2] = "h", c[3] = "i", c[4] = "s" and i = 4 .

They still had difficulty in arriving at the reading cycle and it was only when I had said repeatedly "so we have decided that l is going to represent the number of letter[sic] of the word stored in the array" that they arrived for the beginning of the reading process at

l := 0;
repeat l := l + 1; c[l]:= x; x:= RNC until x = sp or x = pnt .

(In the first draft "or x = pnt" was missing, but this was remedied quickly.) Once this was on the blackboard they completed the reading process without much hesitation:

while x = sp do x:= RNC

When we turned our attention to the printing process, they were more productive. Clearly the reading process had shown them the purpose of the interface and suggestions came from various sides. I had never described the dilemma to them (see EWD249 – 31), whether to code an alternative clause selecting between two repetitions or a repetitive clause repeating an alternative statement. I was waiting for the dilemma to turn up, it came and I showed it to them. Then I had a surprise, for one of the students sugggested to map the two loops on each other with the aid of more variables. We introduced three integers, k, inc, term and the printing of the letters became

if forward then begin k:= 0; inc:= +1; term:= l end
                else begin k:= l + 1; inc:= –1; term:= 1 end;
repeat k:= k + inc; PNC(c[k]) until k = term

followed by

if x = pnt then PNC(pnt) else PNC(sp).

Thus we arrived at the following program

boolean forward; char x; char array c[1:20]; integer l, k, inc, term;
forward:= true; x:= RNC;
repeat l:= 0;
    repeat l:= l + 1; c[l]:= x; x:= RNC until x = sp ∨ x = pnt;
    while x = sp do x:= RNC;
    if forward then begin k:= 0; inc:= +1; term:= l end
                    else begin k:= l + 1; inc:= –1; term:= 1 end;
    repeat k:= k + inc; PNC(c[k]) until k = term;
    if x = pnt then PNC(pnt) else PNC(sp);
    forward:= ¬ forward
until x = pnt     .

This section has not been included because the problem tackled in it is very exciting. On the contrary, I feel tempted to remark that the problem is perhaps too trivial to act as a good testing ground for an orderly approach to the problem of program composition. This section has been included because it contains a true eye-witness account of what happened in the classroom. It should be interpreted as a partial answer to the question that is often posed to me, viz. to what extent I can teach programming style. (I have never used the "Notes on Structured Programming" —mainly addressed to myself and perhaps to my colleagues— in teaching. The classroom experiment described in this section took place at the end of a course entitled "Introduction to the Art of Programming", for which separate lecture notes —with exercises and all that— were written. As of the moment of writing the students that followed this course have still to pass their examination, it is for me still an open question how successful I have been. They liked the course, I have heard that they described my programs as "logical poems", so I have the best of hopes.)

The problem of the eight queens.

This last section is adapted from my lecture notes "Introduction into the Art of Programming". I owe the example —as many other good ones— to Niklaus Wirth. This last section is added for two reasons.

Firstly, it is a second effort to do more justice to the process of invention. (As a matter of fact I start where the student is not familiar with the concept of backtracking and aim at discovering it as I go along.)

Secondly, and that is more important, it deals with recursion as a programming technique. In preceding sections (particularly in "On a program model") I have reviewed the subroutine concept; there it emerged as an embodiment of what I have also called "operational abstraction". In the relation between main program and subroutine we can distinguish quite clearly two different semantic levels. On the level of the main program the subroutine represents a primitive action; on that level it is used on account of "what it does for us" and on that same level it is irrelevant "how it works". On the level of the subroutine body we are concerned with how it works but can —and should— abstract from how it is used. This clear separation of the two semantic levels "what it does" and "how it works" is denied to the designer of a recursive procedure. As a result of this circumstance the design of a recursive routine requires a different mental skill, justifying the inclusion of the current section in this manuscript. The recursive procedure has to be understood and conceived as a single semantic level: as such it is more like a sequencing device, comparable to the repetitive clauses.

It is requested to make a program generating all configurations of eight queens on a chess-board of 8*8 squares such that no queen can take any of the others. This means that in the configurations sought, no two queens may be on the same row, on the same column or on the same diagonal.

We don't have an operator generating all these configurations, this operator is precisely what we have to make. Now there is a very general way (cf. "On grouping and sequencing") of tackling such a problem which is as follows.

Call the set of configurations to be generated: set A. Look for a set B of configurations with the following properties:

set A is a subset of set B

given an element of set B it is not too difficult to decide whether it belongs to set A as well

we can make an operator generating all elements of set B.

With the aid of the generator (3) for the elements of set B, all elements of set B can then be generated in turn; they will be subjected to the decision criterion (2) which decides whether they have to be skipped or handed over, thus generating elements of set A. Thanks to (1) this algorithm will produce all elements of set A.

Three remarks are in order.

If the whole approach is to make sense, set B is not identical to set A, and as it must contain set A as a (true) subset, it must be larger than set A. For reasons of efficiency, however, it is advised to choose set B "as small as possible": the more elements it has, the more elements of it have to be skipped on account of the decision criterion (2).

We should look for a decision criterion that is cheap to apply, at least the discovery that an element of B does not belong to A should (on the average) be cheap. Also this is dictated by efficiency considerations, as we may expect set B to be an order of magnitude larger than set A, i.e. the majority of the elements of B will have to be rejected.

The assumption is that the generation of the elements of set B is easier than a direct generation of the elements of set A. If, nevertheless, the generation of the elements of set B still presents difficulties, we can repeat our pattern of thinking, re-apply the trick and look for a still larger set C of configurations that contains B as a subset etc. (And, as the careful reader will observe, we shall do so in the course of this example.)

Above we have sketched a very general approach, applicable to many, very different problems. Faced with a particular problem, i.e. faced with a specific set A, the problem of course is what to select for our set B.

In a moment of optimism one could think that this is an easy matter, as we might consider the following technique. We list all the mutually independent conditions that our elements of set A must satisfy and omit one of them. Sometimes this works but as a general technique it is too naive: its shortcomings become apparent when we apply it blindly to the problem of the eight queens. We can characterize our solutions by the two conditions

there are 8 queens on the board

no two of the queens can take each other.

Omitting either of them gives for set B the alternatives:

B₁: all configurations with N queens on the board such that no two queens can take each other

B₂: all configurations of 8 queens on the board.

But both sets are so ludicrously huge that they lead to utterly impractical algorithms. So we have to be smarter. The burning question is: "How?".

Well, at this stage of our considerations, being slightly at a loss, we are not so much concerned with the efficiency of our final program as with the efficiency of our own thought processes! So, if we decide to make a list of properties of solutions, in the hope of finding a useful clue, this is a rather undirected search and therefore we should not invest too much mental energy in such a search, that is: for a start we should restrict ourselves to their obvious properties.

(I gave the puzzle as a sobering exercise to one of the staff members of the Department of Mathematics at my University, because he expressed the opinion that programming was easy. He violated the above rule and, being, apart from a pure, perhaps also a poor mathematician, he started to look for interesting, non-obvious properties. He conjectured that if the chessboard were divided in four squares of 4*4 fields, each square should contain two queens, and then he started to prove this conjecture without having convinced himself that he could make good use of it. He still has not solved the problem and, as far as I know, has not yet discovered that his conjecture is false.)

Well, let us go ahead and let us list the obvious properties we can think of.

No row may contain more than one queen, 8 queens are to be placed and the chessboard has exactly 8 rows. As a result we conclude that each row will contain precisely one queen.

Similarly we conclude that each column will contain precisely one queen.

There are 15 "upward" diagonals, each of them containing at most one queen, i.e. 8 upward diagonals contain precisely one queen and 7 upward diagonals are empty.

Similarly we conclude that 8 downward diagonals contain precisely one queen and 7 are empty.

Given any non-empty configuraion of queens such that no two of them can take each other, removal of any one of these queens will result in a configuration sharing that property.

Now the last property is very important. (To be quite honest: here I feel unable to buffer the shock of invention!) In our earlier terminology it tells us something about any non-empty configuration from set B₁. If we start with a solution (which is an 8-queen configuration from set B₁) and take away any one queen we get a 7-queen configuration from set B₁; taking away a next queen will leave again a configuration from set B₁ and we can repeat this process until the chessboard is empty. We could have taken a motion picture of this process: playing it back backwards it would show how, starting from an empty board, via configurations from set B₁ that solution can be built up by placing one queen at a time. (Whether the trick of the motion picture played backwards is of any assistance for my readers is not for me to judge; I only mention it because I know that such devices help me.) When making the picture, any solution could be reduced to the empty board in many ways, in exactly the same number of ways —while playing it backwards— each solution can be built up. Can we exploit this freedom? We have rejected set B₁ because it is too large, but maybe we can find a suitable subset of it, such that each non-empty configuration of the subset is a one-queen extension of only one other configuration of the subset. The "extension property" suggests that we are willing to consider configurations with less than 8 queens on the board and that we would like to form new configurations by adding a queen to an existing configuration —a relatively simple operation presumably. Well, this draws our attention immediately to the generation of the elements of the (still mysterious) set B. For instance, in what order? And this again raises a question to which, as yet, we have not paid the slightest attention: in what order are we to generate the solutions, i.e. the elements of set A? Can we make a reasonable suggestion in the hope of deriving a clue from it? (In my experience such a question about order is usually very illuminating. It is not only that we have to make a sequential program that by definition will generate the solutions in some order, so that the decision about the order will have to be taken at some stage of the game. The decision about the order usually provides the clue to the proof that the program will generate all solutions and each solution only once.)

Prior to that we should ask ourselves: how do we characterize solutions once we have them? To characterize a solution we must give the positions of 8 queens. The queens themselves are unordered, but the rows and the columns are not: we may assume them to be numbered from 0 to 7. Thanks to property a) which tells us that each row contains precisely one queen, we can order the queens according to the number of the row they occupy. Then each configuration of 8 queens can be given by the value of the integer array x[0:7], where

x[i] = the number of the column occupied by the queen in the i-th row.

Each solution is then an "8–digit word" (x[0]...x[7]) and the only sensible order in which to generate these words that I can think of is the alphabetical order.

(Note. As a consequence we open the way to algorithms in which rows and columns are treated differently, while the original problem was symmetrical in rows and columns! To consider asymmetric algorithms is precisely what the above considerations have taught us!)

Returning to the alphabetical order: now we are approaching familiar ground. If the elements of set A are to be generated in alphabetical order and they have to be generated by selection from a larger set B, then the standard technique is to generate the elements of set B in alphabetical order as well and to produce the elements of the subset in the order in which they occur in set B.

First we have to generate all solutions with x[0] = 0 (if any), then those with x[0] = 1 (if any) etc.; of the solutions with x[0] fixed, those with x[1] = 0 (if any) have to be generated first, followed by those with x[1] = 1 (if any) etc. In other words, the queen of row 0 is placed in column 0 —say the square in the bottom left corner— and remains there until all elements of A (and B) with queen 0 in that position have been generated and only then is she moved one square to the right to the next column. For each position of queen 0, queen 1 will walk from left to right in row 1 —skipping the squares that are covered by queen 0—; for each combined position of the first two queens, queen 2 walks along row 2 from left to right, skipping all squares covered by the preceding queens, etc.

But now we have found set B! It is indeed a subset of B₁, set B consists of all configurations with more than one queen in each of the first N rows, such that no two queens can take each other.

The criterion for deciding whether an element of B belongs to A as well is that N = 8.

Having established our choice for set B, we find ourselves faced with the task of generating its elements in alphabetical order. We could try to do this via an operator "GENERATE NEXT ELEMENT OF B" with a program of the form

INITIALIZE EMPTY BOARD;
repeat GENERATE NEXT ELEMENT OF B;
    if N = 8 then PRINT CONFIGURATION
until B EXHAUSTED.

(Here we have used the fact that the empty board belongs to B, but not to A, and is not B's only element. We have made no assumptions about the existence of solutions.)

But for two reasons a program of the above structure is less attractive. Firstly, we don't have a ready-made criterion to recognize the last element of B when we meet it and in all probability we have to generalize the operator "GENERATE NEXT ELEMENT OF B" in such a way that it will produce the indication "B EXHAUSTED" when it is applied to the last "true" element of B. Secondly, it is not too obvious how to make the operator "GENERATE NEXT ELEMENT OF B": the number of queens on the board may remain constant, it may decrease and it may increase.

So it is not too attractive. What can we do about it? As long as we regard the sequence of configurations of set B as a single, monotonous sequence, not subdivided into a succession of subsequences, the corresponding program structure will be a single loop as in the program just sketched. If we are looking for an alternative program structure, we must therefore ask ourselves "How can we group the sequence of configurations from set B into a succession of subsequences?".

Realizing that the sequence of configurations from set B have to be generated in alphabetical order and thinking about the main subdivision in a dictionary —viz. by first letter— the first grouping is obvious: by position of queen 0.

Generating all elements of B —for the moment we forget about the printing of these configurations that belong to set A as well— then presents itself as

INITIALIZE EMPTY BOARD;
h:= 0;
repeat SET QUEEN ON SQUARE[0,h];
    GENERATE ALL CONFIGURATIONS WITH QUEEN 0 FIXED;
    REMOVE QUEEN FROM SQUARE[0,h];
    h:= h + 1;
until h = 8.

But now the question repeats itself: how do we group all configurations with queen 0 fixed? We have already given the answer: in order of increasing column number of queen 1, i.e.

h1:= 0;
repeat if SQUARE[1,h1] FREE do
    begin SET QUEEN ON SQUARE[1,h1];
        GENERATE ALL CONFIGURATIONS WITH FIRST 2 QUEENS FIXED;
        REMOVE QUEEN FROM SQUARE[1,h1];
    end;
    h1:= h1 + 1
until h1 = 8.

For "GENERATE ALL CONFIGURATIONS WITH FIRST 2 QUEENS FIXED" we could write a similar piece of program and so on: inserting them inside each other would result in a correct program with eight nested loops, but they would all be very, very similar. To do so has two disadvantages:

it takes a cumbersome amount of writing

it gives a program solving the problem for a chessboard of 8*8 squares, but to solve the same puzzle for a board of, say, 10*10 squares would require a new, still longer program.

We are looking for a way in which all the loops can be executed under control of the same program text. Can we make the test of the loops identical? Can we exploit their identity?

Well, to start with, we observe that the outermost and innermost loops are exceptional.

The outermost loop is exceptional in that it does not test whether square[0,h] is free because we know it is free. But because we know it is free, there is no harm in inserting the conditional clause

if SQUARE[0,h] FREE do

and this gives the outermost loop the same pattern as the next six loops.

The innermost loop is exceptional in the sense that as soon as 8 queens have been placed on the board, there is no point in generating all configurations with those queens fixed, because we have a full board. Instead the configuration should be printed, because we have found an element of set B that is also an element of set A. We can map the innermost cycle and the embracing seven upon each other by replacing the line "GENERATE" by

if BOARD FULL then PRINT CONFIGURATION
                       else GENERATE ALL CONFIGURATIONS
                              EXTENDING THE CURRENT ONE.

For this purpose we introduce a global variable, n say, counting the number of queens currently on the board. The test "BOARD FULL" becomes "n = 8" and the operations on squares can then have n as first subscript.

By now the only difference between the eight cycles is that each has "its private h". By the time we have reached this stage we can give an affirmative answer to the question whether we can exploit the identity of the loops. The sequencing through the eight nested loops can be invoked with the aid of a recursive procedure, generate say, which describes the cycle once. Using it, the program itself collapses into

INITIALIZE EMPTY BOARD; n:= 0;
generate;

while generate is recursively defined as follows:

procedure generate;
begin integer h;
    h:= 0;
    repeat if SQUARE[n, h] FREE do
        begin SET QUEEN ON SQUARE [n, h]; n:= n + 1;
            if n = 8 then PRINT CONFIGURATION
                else generate;
            n:= n – 1; REMOVE QUEEN FROM SQUARE[n, h]
        end;
        h:= h + 1
    until h = 8
end

Each activation of "generate" will introduce its private local variable h, thus catering for h, h₁, ..., h₈ that we would need when writing eight nested loops.

Our program —although correct to this level of detail— is not yet complete, i.e. it has not been refined up to the standard degree of detail that is required by our programming language. In out[sic] next refinement we should decide upon the conventions according to which we represent the configurations on the board. We have already decided more or less that we shall use the

integer array x[0:7]

giving in order the column numbers occupied by the queens, and also that

integer n

should be used to represent the number of queens on the board. More precisely

n = the number of queens on the board
x[i] for 0 ≤ i < n = the number of the column occupied by
                              the queen in the i–th row.

The array x and the scalar n are together sufficient to fix any configuration of the set B and those will be the only ones on the chessboard. As a result we have no logical need for more variables; yet we shall introduce a few more, because from a practical point of view we can make good use of them. The problem is that with only the above material the (frequent) analysis whether a given square in the next free row is uncovered is rather painful and time-consuming. It is here that we look for the standard technique as described in the seciton "On trading storage space for computation speed" (EWD249 - 53). The role of the stored argument is here played by the configuration of queens on the board, but this value is not changing wildly, oh no, the only thing we do is adding or removing a queen. And we are looking for additional tables (whose contents are a function of the current configuration) such that they will assist us in deciding whether a square is free and also such that they can be updated easily when a queen is added to or removed from a configuration.

How? Well, we might think of a boolean array of 8×8, indicating for each square whether it is free or not. If we do this for the full board, adding a queen might imply dealing with 28 squares, removing a queen, however, is then a painful process, because it does not follow that all squares no longer covered by her are indeed free: they might be covered by one or more of the other queens that remain in the configuration. There is a (again standard) remedy for this, viz. associating with each square not a boolean variable, but an integer counter, counting the number of queens covering the square. Adding a queen then means increasing up to 28 counters by 1, removing a queen means decreasing them by 1 and a square is free when its associated counter equals zero. We could do it that way, but the question is whether this is overdoing it: 28 adjustments is indeed quite a heavy overhead on setting or removing a queen.

Each square in the freedom of which we are interested covers a row (which is free by definition, so we need not bother about that), covers one of the 8 columns (which still must be empty), covers one of the 15 upward diagonals (which must still be empty) and one of the 15 downward diagonals (which must still be empty). This suggests that we should keep track of

the columns that are free

the upward diagonals that are free

the downward diagonals that are free

As each column or diagonal is covered only once we don't need a counter for each, a boolean variable is sufficient. The columns are readily identified by their column number and for the columns we introduce

boolean array col[0:7]

where "col[i]" means that the i-th column is still free.

How do we identify the diagonals? Well, along an upward diagonal the difference between row number and column number is constant, along a downward diagonal their sum. As a result, difference and sum respectively are the easiest index by which to distinguish the diagonals and we introduce therefore

boolean array up[–7:+7], down[0:14] ,

to keep track of which diagonals are free.

The question whether square[n, h] is free becomes

col[h] ∧ up[n – h] ∧ down[n + h] ,

setting and removing a queen both imply the adjustment of three booleans, one in each array.

In the final program the variable k is introduced for general counting purposes, statements and expressions are labeled (in capital letters). Note that we have merged two levels of description, what were statements and functions on the upper level, now appear as explanatory labels.

With the final program we come to the end of the last section. We have attempted to show the pattern of reasoning by which one could discover backtracking as a technique, and also the pattern of reasoning by which one could discover a recursive procedure describing it. The most important moral of this section is perhaps that all that analysis and synthesis could be carried out before we had decided how (and how redundantly) a configuration would be represented inside the machine. It is true that such considerations only bear fruit when eventually a convenient representation for configurations can be found. Yet the mental isolation of a level of abstraction in which we allow ourselves not to bother about it seems cruical.

Finally I would like to thank the reader that has followed me up till here for his patience.

begin integer n, k; integer array x[0:7]; boolean array col[0:7], up[–7:+7], down[0:14];
   procedure generate;
   begin integer h;
      h:= 0;
      repeat if SQUARE[n,h] FREE: (col[h] ∧ up[n – h] ∧ down[n + h]) do
         begin SET QUEEN ON SQUARE[n,h]:
            x[n]:= h; col[h]:= false; up[n – h]:= false; down[n + h]:= false; n:= n + 1;
            if BOARD FULL: (n = 8) then
            begin PRINT CONFIGURATION:
               k:= 0; repeat print(x[k]); k:= k + 1 until k = 8; newline
            end
            else generate;
            n:= n – 1; REMOVE QUEEN FROM SQUARE[n,h]:
               down[n + h]:= true; up[n – h]:= true; col[h]:= true
         end;
         h:= h + 1
      until h = 8
   end;
   INITIALIZE EMPTY BOARD:
      n:= 0;
      k:= 0; repeat col[k]:= true; k:= k + 1 until k = 8;
      k:= 0; repeat up[k – 7]:= true; down[k]:= true; k:= k + 1 until k = 15;
   generate
end

Transcription by David J. Brantley,
latest revision Tue, 18 Dec 2007.

EWD303

On the reliability of programs.

All speakers of the lecture series have received very strict instructions as how to arrange their speech; as a result I expect all speeches to be similar to each other. Mine will not differ, I adhere to the instructions. They told us: first tell what you are going to say, then say it and finally summarize what you have said.

My story consists of four points.

I shall argue that our programs should be correct

I shall argue that debugging is an inadequate means for achieving that goal and that we must prove the correctness of programs

I shall argue that we must tailor our programs to the proof requirements

I shall argue that programming will become more and more an activity of mathematical nature.

The starting point of my considerations is to be found at the "software failure". A few years ago the wide-spread existence of this regrettable phenomenon was established beyond doubt; as far as my information tells me, the software failure is still there as vigorous as ever and its effects are sufficiently alarming to justify our concern and attention. What, however, is it?

Depending on the specific instance of failure one chooses, it can be described in many ways. One of the most common forms starts with an exciting project, but as it proceeds, deadlines are violated and what started as a fascinating thriller slowly turns into a drama, to be played by an ever increasing number of actors, the majority of which know perhaps their own part but have certainly lost their grasp on the meaning of the performance as a whole. At last the curtain falls, only because it is too late, but not because anything has really been completed, for the final piece of software is still full of bugs and will remain so for the rest of its days. There are other forms, but they all have in common, that it turns out to be very, very difficult to get the whole program working with an acceptable degree of reliability.

When we try to explain the present as the natural outcome of the recent past, we get a better understanding of what has happened. In the past ten, fifteen years, the power of commonly available computers has increased by a factor of a thousand. The ambition of society to apply these wonderful pieces of equipment has grown in proportion and the poor programmer, with his duties in this field of tension between equipment and goals, finds his task exploded in size, scope and sophistication. And the poor programmer just has not caught up. Looking backwards we must conclude that the difficulty of the tasks ahead have been grossly underestimated in the past. Extrapolations concerning the number and power of computers to be installed have been made, but society's preparation for this oncoming wave of machinery has been the call for more and more programmers, rather than for more capable ones, who derive their greater capability from a better understanding of the nature of the programming task.

It is alarming to see how little the average programmer's attitude towards his work has changed. The reason is twofold: many programmers have been attracted towards the profession a long time ago, and among them many did not have the intellectual growth potential needed to keep up with the changing profession. Besides that I am afraid that in many organizations young people are attracted as programmers, who are selected on account of obsolete aptitude tests; I still often hear that a successful programmer should be "puzzle-minded" whereas I have the feeling that a clear and systematic mind is more essential. A modern, competent programmer should not be puzzle-minded, he should not revel in tricks, he should be humble and avoid clever solutions like the plague. In the period under discussion higher level programming languages have been accepted as general programming tools and they have been hailed as a tremendous step forward. OK, but is it sufficient? Higher level programming languages enable us perhaps to cope with a factor of 10 in scope but not with a factor of 1000. In the old days, programs of more than one or two thousand assembly code instructions were horrors, but in the mean time higher level programmers produce --admittedly-- large programs of exactly the same degree of unreadability and unreliability, in which the role of old machine-code tricks has been taken over by cunning higher level language tricks. Truly, I cannot see the difference... The conclusion is that, in spite of the factor thousand in scope, present day programming tries to solve its problems with the same old methods. And therefore, if we want to improve matters, we should make it our serious business to minimize the usage of what is now by far our scarcest resource, viz. brainpower. The burning question is "Can we get a better understanding of the nature of the programming task, so that by virtue of this understanding, programming becomes an order of magnitude easier, so that our ability to compose reliable programs is increased by a similar order of magnitude?".

The fact that program reliability becomes a key issue is not only shown by the evidence around us, it is also quite easy to see why. A very large program is, by necessity, composed of a large number, say N, individual components and the fact that N is large implies that the individual program components must be produced with a very high confidence level. If for each individual component the probability of being right equals p, for the whole program the probability P of being right will satisfy

P ≤ pN

and if we want P to differ appreciably from zero, p must be very close to one, because N is so large. And we shall never be able to exploit the power of computers unless we can cope with the case of very large N.

A common approach to get a program correct is called "debugging" and when the most patent bugs have been found and removed one tries to raise the confidence level further by subjecting the program to numerous test cases. From the failures around us we can derive ample evidence that this approach is inadequate. To remedy the situation it has been suggested that what we really need are "automatic test case generators" by which the pieces of program to be validated can be exercised still more extensively. But will this really help? I don't think so.

When faced with a mechanism --be it hardware or software-- one can ask oneself "How can I convince myself of its being correct?" As long as we regard the mechanism as a black box, the only thing we can do is subject it to all possible inputs and check whether it produces the correct outputs. But for the kind of mechanisms we are considering this is absolutely out of the question. I have a pet example to demonstrate this. At my University we have a machine and one should for instance like to know, whether the fixed point multiplication instruction works properly. The machine has a rather short word length of 27 bits, as a result there are only 2⁵⁴ different fixed point multiplications possible. So, why not try them all? With 2¹⁴ multiplications per second, 2⁵⁴ multiplications = 2⁴⁰ sec = 10¹² sec. = 10⁷ days = 30.000 years! It takes 30.000 years to have all possible multiplications performed just once. One of the consequences of this number is that in the whole life time of the machine, the number of fixed point multiplications actually performed by our machine is a truly negligible fraction of the set of possible multiplications. From a simple-minded point of view we are only interested in the correct execution of the tiny set of multiplication the machine is actually called to perform. But because in programming we think not in terms of numerical values but in terms of variables, we have abstracted from the values actually processed by the arithmetic unit and we are only allowed to make this abstraction when the multiplier would do any multiplication correctly. I make this point because it is often not realised that the at first sight extreme and ridiculous reliability requirements imposed by us on the hardware is a direct consequence of the fact that without it we could not afford this vital abstraction. Another consequence of the number of 30.000 years that sampling testing is hopelessly inadequate to convince ourselves of the correctness even of a simple piece of equipment as a multiplier: whole classes of in some sense critical cases can and will be missed! All this applies a fortiori to programs that claim to cope with many more cases and take more time for each single execution. The first moral of the story is that program testing can be used very effectively to show the presence of bugs but never to show their absence.

But as long as we regard the mechanism as a black box, testing is the only thing we can do. The conclusion is that we cannot afford to regard the mechanism as a black box, i.e. we have to take its internal structure into account. One studies its internal structure and on account of this analysis one convinces onself that if such and such cases work "all others must work as well." That is, the internal structure is exploited to reduce the number of still necessary testcases, for all the other ones (the vast majority) one tries to convince onself by reasoning, the only problem being that the amount of reasoning often becomes excessive, with the sad result that bugs remain.

The function of the mechanism's internal structure opens a new way to attack the reliability problem. Once we have seen that the confidence level can only be reached by virtue of the structure of the mechanism, that the extent to which the program correctness is not purely a function of its external specifications and behaviour, but depends critically upon its internal structure, then we can invert the question and ask ourselves "What forms of program structuring can we find, what elements of programming style and what forms of discipline, all for the benefit of the confidence level of the final product?".

Instead of trying to devise methods to establish the correctness of arbitrary, given programs, we are now looking for the subclass of what I would like to call "intellectually manageable programs", which can be understood and for which we can justify our belief in their proper operation under all circumstances without excessive amounts of reasoning. This is done in order to reduce the number of testcases needed; in the case of software I see no reason at all why this approach could not be so effective that the number of testcases is eventually reduced to zero, i.e. that correctness can be shown a priori. Already now, debugging strikes me as putting the cart before the horse: instead of looking for more elaborate debugging aids, I would rather try to identify and remove the more productive bug-generators!

In short, I suggest that the programmer should continue to understand what he is doing, that his growing product remains firmly within his intellectual grip. It is my sad experience that this suggestion is repulsive to the average experienced programmer, who clearly derives a major part of his professional excitement from not quite understanding what he is doing. In this streamlined age, one of our most undernourished psychological needs is the craving for Black Magic and apparently the automatic computer can satisfy this need for the professional software engineer, who is secretly enthralled by the gigantic risks he takes in his daring irresponsibility. For his frustrations I have no remedy......

We return to our question "Can the programmer arrange his activity in such a way that his growing product remains firmly in his intellectual grip, that he continues to understand what he is doing?" Well, let me state my firm belief: yes, he can, it is possible to increase our programming ability by an order of magnitude. And as a corrolary: there is no other way, for when the programmer loses his intellectual grip on his product, he will never get the program in such a state that we can rely upon it. I will now try to convey the quintessence of the considerations upon which this confidence is founded. The reliable design of a highly sophisticated program is anyway a difficult task and we could place our question in a much broader perspective and ask ourselves "How does the human mind invent something very intricate, how does the human mind think difficult thoughts?" Fascinating as those general questions are, I shall not touch upon them. I shall restrict myself to the more limited field of programming, because already in the programming field we can distinguish five elements of mental discipline, each of which is a great help in keeping our programs understandable. In order to be able to talk about them, I must name them, I have called them sequencing discipline, operational abstraction, representational abstraction, configurational abstraction and textual encapsulation. In order to avoid false hopes: all these elements are known, all higher level programming languages cater more or less successfully for some of them. It is just that by making these elements of discipline more explicit, that we can exploit them more consciously and that we can get more of a yardstick along which to compare the respective qualities of different programming languages.

The sequencing discipline first. We should be very well aware of the fact that although the written program is the final product that leaves the programmer's hand, the true subject matter of his trade is formed by the possible computations --the making of which he leaves to the machine-- that may be evoked by his program. Whenever we make a statement about the correctness of a program it is a statement about the corresponding computations that may be evoked by it. The subject matter is dynamic, it is the happening in time, while the last thing we can lay our hands on is the static program text. It is on account of the latter that we must be able to make assertions about the former. It is therefore essential to bridge the conceptual gap between the static program text and the dynamic computations evolving in time as effectively as possible. In order to do this I cannot recommend too heartily to abolish the goto statement and to restrict oneself for sequencing purposes to the conventional conditional clauses, alternative clauses, repetitional clauses and recursion. The goto statement has been identified as one of the combinatorial bug generators we have been looking for. I draw attention to the fact that recursion is grouped under the class "sequencing discipline", I will return to this in a moment when we have mentioned operational abstraction.

Operational abstraction is embodied in most programming languages by the subroutine mechanism. It is an explicit recognition of the fact that a total net effect can be effectuated as the cumulative effect of a sequence of subactions and that this can be done by virtue of what these subactions do for us, as distinct from how these subactions work. In a main program calling subroutines we have a level of discourse in which we can --and should-- regard the subroutines as available primitives whose net effect is known and it is in terms of this knowledge that we can and must understand the main program. At that level of abstraction it should be of no concern how the subroutines work, that is only relevant on another, more detailed semantic level. The mixing of two such levels is one of the most common sources of program bugs. For the sake of completeness I mention that operational abstraction can also be recognized when the sequencing clauses are used, viz. in the relation between the whole construction and the statement controlled by the clause; in the latter case it is customary to represent the difference of level by indentation. And it is now clear, why recursion is treated as a sequencing discipline: in the definition of a recursive operator the level which describes how the operator works coincides with a level in which the operator is used and as a result we cannot distinguish the two different semantic levels.

Operational abstraction deals with the actions occurring in the computation and we have the two sides of the coin "What they do" versus "How they work". With respect to information stored inside the machine we have a similar coin with two sides. The only thing a computer can do for us is to manipulate but the only reason for manipulating symbols is that they stand for something else. Conceptually the program manipulates rather abstract objects, while in fact it does so in terms of a particular representation for them. It is a very common occurrence that alternative programs for the same job can be viewed as different refinements of the same algorithm, the same as long as the algorithm is expressed in terms of rather abstract values, only differing in the particular representations chosen to distinguish between these values. This is called representational abstraction; by virtue of it it is often possible that alternative programs for the same job --or as the case may be: programs for similar jobs-- can share a large part of their correctness proofs. I have the feeling that representational abstraction is one of the most powerful techniques for understanding programs. Also, it seems a bit neglected. I do not know of any programming language --although it may exist-- that caters for it in a convincing way. Records as structured data types do not answer its needs. With record we can introduce composite data types, OK, but the record structure chosen permeates the program using them. Also, much attention has been paid to the problem of proving formally the correctness of a program, but as far as I have seen these formal proofs, they were always tied down to the particular representation chosen in this program, because the formal proof did operate in terms of the primitive data elements. As a result changing the representation would require a completely new formal proof. It is this observation that may indicate the limits of applicability of highly formalized proof techniques. I have now mentioned two forms of abstraction; the inverse processes, viz. choosing an algorithm for an action or choosing a representation for a variable is called "refinement", and so we have operational refinement and representational refinement. We should mention that representational refinement is always accompanied by operational refinement. On the abstract level we have the unanalysed variables with actions operating upon them: when a particular representation is chosen, our original actions have to be translated in terms of algorithms operating on the components of the chosen representation.

The fourth is configurational abstraction. To a given machine we can add a standard library of subroutines. If we do so, we have in a sense rebuilt our machine, we have extended its instruction repertoire. But layers of standard software can rebuild a given machine so much more drastically that a separate name seems appropriate and I have chosen "configurational abstraction" for that purpose. I am referring to the functions of an operating system that can rebuild a single processor installation into a multiple processor installation, that can rebuild a hierarchy of storage levels into a virtual store etc. Ideally, this rebuilding of a given hardware configuration into a virtual machine serves a double purpose. Firstly it enables us to map different configurations into the same virtual machine, thereby providing a step towards program portability; secondly the virtual machine should be much more attractive to use than the original machines. To my great regret I get the impression that the second requirement is often overlooked, at least not met.

Finally we have textual encapsulation. If we consider any program of a sizeable complexity, this program should not be regarded as an object all by itself but as a member of a class of neighbouring programs, alternative programs for either the same or similar jobs. It is becoming recognized more and more that it is highly desirable that the transformation of a program into another one of the family should only affect well isolated portions of the program text and should not require adjustments scattered all through the program text. This is one of the main aspects of modularity. For some program changes this goal is very hard to achieve but the objective is so clear now that I expect it to become easier in the future. We may either invent programming languages more suited to this flexibility requirement or we shall devise more elaborate means of exploiting automatic equipment for the composition of program texts.

With the above I touched on five, what I called "elements of a programming discipline", all of them ways by which we can increase the understandability of programs. They have to do with the ease with which we can understand what a program is doing, they have to do with the feasibility of correctness proofs. It is to the pattern of such proofs that we now turn our attention.

Let me first relate them to patterns of proof for single sequential programs, because the proving techniques for sequential programs seem to be better understood than those for a bunch of parallel programs. If we have a program consisting of a sequence of statements to be executed in the order in which they are given the proving technique is fairly well understood. If the net effect of the execution of the constituent statements is given, the net effect of their successive execution can be established straightforwardly by what I have called "Enumerative reasoning", our main concern being that the amount of reasoning needed for each step does not get excessive. It is my impression that the amount of reasoning needed can be reduced when we can group subsequences into compound statements, the net effect of which allows a compact formulation. This is generally true: any sizeable piece of program, or even a complete program package, is only a useful tool that can be used in a reliable fashion, provided that the documentation pertinent for the user is much shorter than the program text. If any machine or system requires a very thick manual, its usefulness becomes for that very circumstance subject to doubt!

Returning to the correctness proof: the compact formulation of the net effect of compound statements often requires the introduction of a new terminology and it is not unusual that this terminology is provided for by the mechanism of representational abstraction. So much for a piece of program text without any sequencing clauses. In the case of conditional clauses, alternative clauses, case constructions and repetitive clauses, the whole construction should be repeated as a single compound and its net effect should be formulated in such a way that it is no longer transparent that, internally, the construction is controlled by such a clause. In particular: if it is controlled by an alternative clause, the description of its net effect should be applicable regardless of which of the two paths is taken, if it is controlled by a repetitive clause, the description of its net effect should be applicable to all possible numbers of repetitions. This is because in the context in which these constructions occur, they occur on account of what they do for us and not on account of how they work. This is an application of operational abstraction possible thanks to our strict sequencing disciplines. We should make this operational abstraction very explicitly and very consciously: without it the number of cases to be distinguished between in our reasoning has a tendency to grow exponentially with the program text.

The conditional, the alternative and the case construction themselves can be understood by enumerative reasoning, the construction with the repetitive clause, however, requires a special pattern of reasoning for its understanding because it must cover all possible numbers of repetitions. Basically, mathematical induction is our only mental tool adequate for the purpose --and in the case of understanding a recursive subroutine mathematical induction is often applied explicitly-- but in the case of loops the understanding can be speeded up by resorting to one or two theorems, thereby avoiding an explicit appeal to mathematical induction. They are invariance theorems. If it can be shown that a single execution of the repeatable statement will leave a relation between the values of some variables invariant --and this itself can be established by enumerative reasoning-- and if furthermore it can be shown that this same relation is valid before entering the loop, then the said relation will also hold after termination of the repetition. This turns out to be a very powerful theorem.

I have mentioned the exploitation of invariant relations explicitly because it appears to be one of our more powerful tools when we wish to make assertions about the harmonious co-operation of a bunch of parallel programs. In a number of cases the harmonious co-operation between a number of parallel programs could be established by showing the invariance of a relation. In this relation two sorts of quantities occur, on the one hand variables, common to the programs, and on the other hand variables that are a function of the state of progress of the individual processes. The analysis of the requirements of such a proof, again, is very illuminating. Suppose that we want to establish the invariance of such a relation. As long as the variables occurring in the relation remain untouched, their values remain unchanged and the validity of the relation remains invariant. We therefore focus our attention upon all operators occurring in the totality of the bunch of parallel programs, that may influence the value of one or more of the variables concerned. Let their number be M. If all these operators leave the relation invariant, the relation will be invariant. This requires a study of M cases. But be careful! We are studying the net effect of a bunch of parallel programs, so in principle it is insufficient to establish the invariance of the relation under the execution of all possible combinations, i.e. 2M(-1) cases. Here again we are faced with exponential growth of the number of cases to be distinguished between in our reasoning. As a result it makes all the difference in the world, whether one has primitives at one's disposal by means of which mutual exclusion in time can be guaranteed. And I am not sure whether all designers of multiprocessor machines, of programming languages for process control etc. have paid enough attention to this observation.

Our knowledge of how to prove the correctness of programs is far from complete but it is growing. It will have an increasing influence on the programs that are going to be produced. It is irrealistic, however, to expect all potential benefits from this approach before quite a lot of cleaning up of programming languages has been established. That such forms of cleaning up are perfectly possible has been shown by professor Niklaus Wirth from Zurich who has designed the programming language PASCAL. I quote from his introduction "The desire for a new language for the purpose of teaching programming is due to my deep dissatisfaction with the presently used major languages whose features and constructs too often cannot be explained logically and convincingly and which too often represent an insult to minds trained in systematic reasoning. Along with this dissatisfaction goes my conviction that the language in which the student is taught to express his ideas profoundly influences his habits of thought and invention, and that the disorder governing these languages directly imposes itself onto the programming style of the students. I am inclined to think that the lack of discipline and structure in professional programming style is the major reason for the appalling lack of reliability of practially all larger software products." End of quotation. We shall never learn to write good and convincing programs in FORTRAN --a programming tool which, indeed, was a great step forward when it was conceived some fifteen years ago but which, by now, should be regarded as a lower level language, as a low grade coding device. This programming tool, and the thinking habits induced by it, have grown hopelessly inadequate. As a teacher it is my job to help programmers in clearing up their own thinking. Often this is a highly rewarding activity, equally delightful and instructive for both parties. But when talking to the produce as grown in what is getting known as "the pure FORTRAN environment", I am usually baffled, for unsuspected depths of misunderstanding open themselves before my very eyes. It is well knoown that we don't gain automatically from experience, on the contrary, that the wrong experience may easily corrupt the soundness of our judgement. In the case of FORTRAN, it is my impression that its intellectually degrading influence is not commonly recognized, that too few people realize that the sooner we can forget that it ever existed, the better, as it is now too inadequate, too difficult and therefore too expensive and too risky to use.

Ladies and gentlemen, let me come to my final conclusions. Automatic computers are with us for twenty years and in that period of time they have proved to be extremely flexible and powerful tools, the usage of which seems to be changing the face of the earth (and the moon, for that matter!) In spite of their tremendous influence on nearly every activity whenever they are called to assist, it is my considered opinion that we underestimate the computer's significance for our culture as long as we only view them in their capacity of tools that can be used. In the long run that may turn out to be a mere ripple on the surface of our culture. They have taught us much more: they have taught us that programming any non-trivial performance is really very difficult and I expect a much more profound influence from the advent of the automatic computer in its capacity of a formidable intellectual challenge which is unequalled in the history of mankind. This opinion is meant as a very practical remark, for it means that unless the scope of this challenge is realized, unless we admit that the tasks ahead are so difficult that even the best of tools and methods will be hardly sufficient, the software failure will remain with us. We may continue to think that programming is not essentially difficult, that it can be done by accurate morons, provided you have enough of them, but then we continue to fool ourselves and no one can do so for a long time unpunished.

Finally, let me summarize as instructed. Reliability concerns force us to restrict ourselves to intellectually manageable programs. This faces us with the questions "But how do we manage complex structure intellectually? What mental aids do we have, what patterns of thought are efficient? What are the intrinsic limitations of the human mind that we had better respect?" Without knowledge and experience, such questions would be very hard to answer, but luckily enough, our culture harbours with a tradition of centuries an intellectual discipline whose main purpose it is to apply efficient structuring to otherwise intellectually unmanageable complexity. This discipline is called "Mathematics". If we take the existence of the impressive body of Mathematics as the experimental evidence for the opinion that for the human mind the mathematical method is, indeed, the most effective way to come to grips with complexity, we have no choice any longer: we should reshape our field of programming in such a way that their methods of understanding become equally applicable, for there are no other means.

Thank you.

Transcribed by David J. Brantley.
Last modified Mon, 27 Jun 2005.

EWD306

Over het gewicht van een informatica-opleiding.

Bij (niet geheel los van elkaar staande) besprekingen zijn bij herhaling vijf vakken als “typische informaticavakken” naar voren gekomen. Kortheidshalve duid ik ze aan met
1)     programmeren
2)     informatiebeheer
3)     compilerbouw
4)     operating systems
5)     vergelijkende taalstudie.

Het kost mij bijzonder veel moeite, deze als “kernvakken”, als nucleus van een academische opleiding te zien, omdat ik aan zo’n nucleus een dubbele eis wil stellen: enerzijds wil je, dat de vakken practisch relevant zijn, anderzijds wil je dat ze theoretisch op een zo solide basis staan, dat ze een behoorlijke mate van duurzaamheid hebben dan wel methodologisch een zo rijke inhoud hebben, dat ze door hun algemeenheid een gevarieerd (en daardoor naar je hoopt: blijvend) toepassingsgebied hebben. Waar staan in dit opzicht deze vakken?

1)     Programmeren scoort wat practische relevantie betreft hoog. Er is enige relevante theorie en in de vier jaar dat ik het gegeven heb is een methodologie begonnen zich af te tekenen. Dit vak is tot een zodanige graad van wasdom gekomen, dat ik het in een academisch curriculum niet misplaatst vind. Het is vooralsnog een “klein” vak.

2)     lnformatiebeheer scoort wat practische relevantie betreft hoog. Als we ook beveiliging tegen informatieverlies er in betrekken, wordt het bovendien erg moeilijk. De soliede theoretische basis en duidelijke methodologische elementen wachten, dacht ik, nog op hun ontwikkeling. (Met o.a. de hoop hierop is Lunbeck aangetrokken.)

3)     Compilerbouw scoort qua relevantie veel minder hoog. Het feit dat alle programmeren in hogere programmeertalen gebeurt, geeft compilerbouw nog geen centrale positie: dit wel een centrale positie geven is nu dezelfde denkfout, die mensen tien jaar geleden gemaakt hebben toen ze electrotechniek een centrale plaats gaven. Qua theoretische fundering scoort compilerbouw hoog (zelfs hoger dan nodig) waar het “parsing” betreft, maar deze theoretische fundering betreft een erg specifiek aspect. Verder is “compiling a data processing job like any other”. (Voor taalelementen en overeenkomstige structuur van object code, evaluatie van instructiesets etc. verwijs ik naar 5.)

4)     Operating systems scoort qua relevantie (op het ogenblik nog?) iets hoger omdat zij zo’n diepgaande invloed hebben op de macroscopische bruikbaarheidsaspecten van computersystemen. De theoretisch fundering is pover. Het is illustratief voor hoe mensen worstelen met een amorf probleem met teveel haken en ogen, dat wel. Verder is het “a programming job like any other”.

5)     Vergelijkende taalstudie zou een discussie moeten zijn van taalelementen —parameters, pointers, records, types etc.— en hun operationele consequenties —zowel van de kant van de gebruiker als van de kant van de implementator. Dit is wat de taalontwerper zou moeten weten: hoogst relevant maar als “body of ordered knowledge” helaas nog non-existent.

De moraal is, dat er op deze manier bezien, eigenlijk nog niet zo heel veel is. Welke consequenties verbinden wij hieraan voor een curriculum? Ik zie vier mogelijkheden.

A)     Men laat de practische relevantie als criterium vallen en vult het curriculum met wat ik collectief als “automatentheorie” aanduid. Dit geeft aanleiding tot een zuiver wiskundige opleiding, naar traditioneel academisch vooroordeel alleszins respectabel maar onverenigbaar met ons streven naar bruikbaarheid. (Mag ik dit “de Utrechtse school” noemen?)

B)     Men laat de gezonde theoretisch basis en methodologische inhoud, kortom de duurzaamheid als criterium varen. Dit geeft aanleiding tot een hogere beroepsopleiding die zijn duurzaamheid niet ontleent aan innerlijke qualiteiten, maar aan de traagheid van de wereld om ons heen, die in de wurggreep van een te haastig in elkaar gestampt verleden volhardt in het gebruik van obsolete technieken. (Mag ik dit “de compatibiliteitsscholing” noemen?)

C)     Men kan niet kiezen tussen A en B en neemt daarom half-om-half. Dit in de onverantwoorde hoop dat, als we zelf de synthese niet kunnen bereiken, onze studenten dit wel zullen kunnen. (Mag ik dit “de tweeslachtige opleiding” noemen?)

D)     We gaan in wezen door op de ingeslagen weg van “accentsverschuiving” in onze opleiding voor wiskundig ingenieur, maar waken ervoor daarmee significant verder te gaan dan de beperkte “state of the art” rechtvaardigt. (En mag ik dit “de bescheiden opleiding” noemen?)

Dat ik een zekere voorkeur voor mogelijkheid D koester, kan voor de lezer die mijn woordgebruik geobserveerd heeft geen verrassing meer zijn. De reden is, dat D mij treft als het enige eerlijke voorstel, omdat A, B en C eraan voorbij gaan, dat het vak eigenlijk (nog?) heel klein is: ze treffen me als de onwaarachtige lading, waarmee men een voortijdig fier gehesen vlag probeert te dekken, elk is op zijn manier daarom een soort van bedrog. De kans, dat we op A terecht komen, lijkt me, gezien de constellatie van de onderafdeling, heel klein. Het gevaar, dat we op B of C (vooral B) terecht komen acht ik echter levensgroot aanwezig, omdat B op de bekende circumstantiele gronden zo voor de hand liggend lijkt.

De redenering, waarom je, als je D wilt, B moet doen, loopt ongeveer alsvolgt.

1)     Om D te kunnen doen heb je knappe studenten nodig.
2)     Om knappe studenten te krijgen moet je ze kunnen selecteren uit een grotere groep.
3)     Om een grotere groep aan te trekken, moet je de informatica een zo duidelijk gezicht geven, dat ze als vliegen op de honing afkomen.
4)     Het merendeel van deze studenten moet je op de praktijk voorbereiden, dus geef die dan B.
5)     Als die enkele knappe niet van de praktijk op de hoogte is, krijgt hij later in het bedrijfsleven geen poot aan de grond, dus geef die knappe in elk geval ook B.
6)     Ach, laat D dan maar varen, want (naar keuze)
          6a) de goede student komt er toch wel
          6b) het bedrijsleven weet toch geen raad met goede mensen.

En ergens langs de lijn ben je vergeten, dat opleiding B op de keper
beschouwd bedrog was.

16 maart 1971 | prof.dr.Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 29-Nov-2011

EWD307

De architectuur van de machines van de derde generatie, die geconcipieerd is in het begin van de zestiger jaren, is heel bewust toegespitst -met behulp van simulatie van bestaande, representatief geachte programmapakketten, met stochastische modellen en statistische criteria als bv. de "Gibson mix"- op de belasting van de machine, zoals men zich die toen voorstelde. (Als altijd is daarbij ongetwijfeld aanwezige toekomstvisie gecompenseerd door het feit, dat alle statistische materiaal uit het verleden stamde.) Om deze architectuur te begrijpen moeten we daarom trachten het beeld van de machinebelasting, dat toen prevaleerde, in grote trekken te reconstrueren.

Het belangrijkste kenmerk van die periode is in terugblik, dat de zogenaamde "hogere programmeertalen" in het hele veld van automatische informatieverwerking pas aarzelend burgerrecht verkregen. FORTRAN begon toen voor technisch-wetenschappelijke berekeningen redelijk erkenning te krijgen (hoewel vele professionelen het toen nog beschouwden als een tweederangs hulpmiddel voor hen "die niet echt konden programmeren), ALGOL 60 was slechts een hoofdzakelijk Europese, academische hobby en in de administratieve sector, waar toen al de grootste markt gezien werd, was van erkenning van COBOL nog nauwelijks sprake en was "assembly code" nog veruit het voornaamste programmeergereedschap. Zoals wij in het volgende zullen zien, heeft de toenmalig beperkte rol van hogere programmeertalen op allerlei aspecten een diepgaande invloed gehad.

Daarnaast is de architectuur van de machines van de derde generatie in tweeerlei opzicht een reactie op ervaringen opgedaan met machines van de tweede generatie. Dat waren machines met random access geheugens van zeer beperkte omvang, aangevuld met magnetische banden als massa-geheugen, configuraties die door de beperkte toegankelijkheid van de informatie op de magnetische banden steeds moeilijker hanteerbaar werden. Enerzijds is de derde generatie hierop een duidelijke reactie: de maximaal toelaatbare omvang van kerngeheugens is drastisch vergroot en de magnetische schijven hebben als massa-geheugens hun intrede gedaan. (Dit waren schijven met bewegende arm: hoewel "randam" toegankelijkheid hierbij nog een stuk lager ligt dan bij trommels of dan bij schijven met vaste koppen, is het vergeleken bij magnetische banden alleszinds fair deze als "random access" geheugens te beschouwen.) Anderzijds zijn de machines van de derde generatie duidelijk beinvloed door het programma-aanbod, zoals zich dit bij de tweede generatie heeft ontwikkeld, in het bijzonder met betrekking tot sorteren. Wij doelen hier op de uitgebreide kanaalfuncties zoals "scatter read/write", die ten duidelijkste geintroduceerd zijn om sorteerwerk op magnetische banden te versnellen, er wellicht aan voorbijgaand, dat de behoefte aan sorteren met de vervanging van banden door schijven aanmerkelijk is afgenomen. (De barokheid van deze kanaalfuncties lijkt echter mede-verantwoordelijk voor de complexiteit, die de operating systems voor de machines van de derde generatie heeft aangenomen.)

Wij keren terug tot de directe gevolgen, die de toen nog onderschikte positie van hogere programmeertalen gehad heeft.
1)     Het vermogen nieuwe programma's te creeeren is hierdoor sterk onderschat: men heeft zich de belasting voorgesteld als opgebouwd uit minder verschillende programma's die ieder voor zich langer zouden lopen.
2)     In het licht van deze verwachting heeft men gekozen voor een wijze van programmaverwerking, waarin meer geoptimaliseerd is op maximale "throughput" dan op minimale "turn around time".
3)     In het licht van deze verwachting is in operating systems veel aandacht geschonken aan "program scheduling": als het om weinig, grote programma's gaat is de tijd besteed aan program scheduling (vanwege het gering aantal) beperkt in omvang en (vanwege de grootte van de individuele programma's) hopelijk welbesteed. (Daar kwam bij, dat program scheduling, dat bij de tweede generatie vanwege de behandeling van magnetische bandeenheden zoveel had opgeleverd, een nog onverwelkte aureool had.)
4)     In het licht van deze verwachting is de neiging ontstaan grote "initiele kosten" bij programmaverwerking wat makkelijk door procentuele verkorting van de eigenlijke rekentijd te rechtvaardigen.
5)     Een microscopisch gevolg van de bereidheid bij programmaverwerking grote initiele kosten op te brengen ten bate van de snellere verwerking is te vinden in de structuur van de rekenorganen, die om der snelheids wil met een groot aantal, in de programmatekst expliciet benoemde rekenregisters zijn uitgerust. Dit echter vraagt om grotere initiele kosten bij het vertaalproces, dat nu de additionele plicht van "register allocation" heeft, wat de vertaaltijd vergroot.
6)     Een tweede microscopisch gevolg van de bereidheid bij programmaverwerking grote initiele kosten op te brengen ten bate van snellere verwerking is te vinden in de betrekkelijk directe adressering van het geheugen, die geleid heeft tot de noodzaak van "linkage editing". Dit probleem ontstaat doordat procedures (hetzij eigen, voorvertaalde procedures, hetzij procedures uit de bibliotheek) in objectcode geformuleerd diene te worden op een wijze, die bepaald wordt door het programma waarvan ze dit keer deel uit maken. Een en ander is noch des te ernstiger, omdat men niet aan de indruk kan ontkomen, dat de kosten die aan "linkage editing" verbonden zijn, aanvankelijk ernstig onderschat lijken.
7)     De genoemde microscopische aspecten -groot aantal rekenregisters en betrekkelijk directe adressering van het geheugen- hebben niet alleen de macroscopische gevolgen ten aanzien van de initiele (tijd)kosten gehad. Door het grote aantal expliciet benoemde rekenregisters is het mechanisme van de zg. "gesloten subroutine" belast met een zodanige "overhead" (ontstaan door red- en herstelplichten van registerinhouden) dat de gesloten subroutine in discrediet is geraakt ten gunste van de zg. "macro facility", die de neigin heeft �de lengte van de programmatekst in object code te verlengen. Daarnaast heeft ieder programma van elke bibliotheekprocedure die het gebruikt een eigen, door linkage editing aan hem aangepaste, versie. Ook dit heeft geleid tot veeleisendheid ten aanzien van geheugengebruik. Ten gevolge van beide factoren moeten machines van de derde generatie, willen ze enigszins redelijk functioneren, met grote kerngeheugens uitgerust worden (in elk geval aanmerkelijke groter dan aanvankelijk voorzien; naar verluid is deze ontwikkeling de fabrikanten niet onwelgevallig geweest).

Tekenend is tenslotte, dat vertalers en operating systems as regel niet in een hogere programmeertaal geschreven zijn maar in assembly code, een keuze die onveranderlijk door de fabrikant gemotiveerd is met de uitspraak, dat anders deze "harde software" onvoldoende efficient zou zijn!

De aard van machinegebruik is in de afgelopen tien jaar echter geenszinds constant gebleven. De belangrijkste ontwikkelingen zijn de volgende.
1)     Hogere programmeertalen hebben, zelfs bij machines die voor hun verwerking maar matig geschikt zijn, burgerrecht verkregen. Er zijn allerlei installaties waarvoor veel geprogrammeerd wordt, maar geen programma meer in assembly code.
2)     Tengevolge hiervan heeft het programmaaanbod zich verschoven naar meer (soms ook kleinere) programma's
3)     Tengevolge hiervan is de waardering voor korte "turn around time" en bij werk met terminals "short response time" aanzienlijk toegenomen.
4)     Tengevolge hiervan zijn de hoge initiele kosten bij programmaverwerking steeds moeilijker te accepteren.
5)     Tengevolge hiervan is het steeds noodzakelijker, dat de installatie voor de programmeur "soepel in de hand ligt". Als een installatie een gebruiker met "overlast" confronteert, doet hij dat nu in veelvoud, hoe meer mensen voor een machine programmeren, des te essentieler is het, dat dit met een minimum aan haken en ogen gepaard gaat.
6)     Multiprogrammering heeft als middel ter verhoging van de toegankelijkheid van de machine zijn waarde onomstotelijk bewezen.
7)     De realistische implementeerbaarheid van "virtual stores", waarin de gebruiker zich niet hoeft te bekommeren over de hoeveelheid voor hem beschikbaar primair geheugen (en waarin deze hoeveelheid door het systeem aan de omstandigheden wordt aangepast) is voor een grote klasse van problemen onomstotelijk aangetoond.
8)     Dat het concept van het "virtual store" de gebruiker een hoop overlast bespaart is eveneens onomstotelijk aangetoond.
9)     De implementatie van virtual stores heeft een halt toegeroepen aan de ontwikkeling van allerlei (standaard-)programma's in een veelvoud van versie's -gerangschikt naar opklimmende behoefte aan primair geheugen; hiermee is een van de schadelijke groeifactoren effectief bestreden.

Op het Rekencentrum van de THE is deze ontwikkeling, waarin we een essentieel aspect van de dienstverlening zien, voorzien, toegejuicht en tot grote tevredenheid alom daadwerkelijk bevorderd. Het is in dit licht moeilijk om de aanschaf van apparatuur te rechtvaardigen, die ons zou dwingen in dezen de klok een kleine tien jaar terug te zetten.

*                   *

*

Voorgesteld is een configuratie van een P1400 met daaromheen 4 P880's as satelietcomputers. De P1400 is qua conceptie een machine van de derde generatie, om deze als centrale machine van de configuratie op te stellen is daarom niet aantrekkelijk. De P88o is qua opzet iets moderner: het rekenorgaan is bv. met veel minder expliciet benoemde rekenregisters uitgerust. De wijze, waarop het geheugen geadresseerd wordt is echter nog heel klassiek, wat blijkt uit de wijze, waarop de gebruiker nog met "overlays" te maken heeft. De netto indruk van de P880 is, dat er wel voorzieningen zijn ten bate van het aspect van "processor sharing" zoals dit bij multiprogrammering optreedt, dat de rolverdeling van primair geheugen echter nog zo star is, dat de P880 moeilijk onder "general purpose" omstandigheden is in te schakelen.

In het voorstel zitten drie aspecten:
1)     verhogen van de rekencapiciteit door 4 identieke "kleine" computers (voor "kleine" programma's)
2)     verhoging van de rekencapaciteit door toevoeging van een grotere machine (voor "grotere" programma's)
3)     koppeling van dit vijftal

ad 1) Verhoging van de rekencapaciteit door een aantal identieke computers baadt niet. Hiermee bestrijdt je nl. alleen maar overbezetting, maar niet configurationele tekortkomingen, die ons nu de pas naar ambitieuzere computertoepassingen afsneiden. Hoe tevreden we ook over de X8 Zijn, het rekencentrum zou door bv. 4 X8-en onvoldoende geholpen zijn: je kan dan wel meer opgaven van hetzelfde allooi aan, maar niet de opgaven die je nu "zelfs in het weekend" niet aankunt. Het is een beetje alsof je vier ovens tot 250 graden krijgt inplaats van 1 oven tot 1000 graden.

ad 2) Aan het bovenstaande wordt gesuggereerd tegemoet te komen door toevoeging van een grotere machine. Het onderhavige voorstel is moeilijk verdedigbaar omdat de P1400 qua capaciteit wat te weinig van de P880 verschilt, het is absoluut onverdedigbaar omdat de P880 en de P1400 incompatibel zijn. Niet alleen, dat dit zou betekenen dat de gebruiker twee ALGOL systemen zou moeten kennen, het betekent ook, dat hij voor elk programma afhankelijk van de "grootte" van het programma zou moeten kiezen. Dit gaat er van uit, dat de "grootte" een constante programmaeigenschap is, quod non: een toekomstig "groot" programma geeft in zijn testphase tot vele "kleine" runs aanleiding. Verder zou een "klein" programma op de grote machine kunnen moeten draaien vanwege aldaar beschikbare faciliteiten als een procedurebibliotheek.

ad 3) De vermeende voordelen van koppeling zijn mysterieus. Koppeling is in twee omstandigheden duidelijk verdedigbaar:
a) Indien een uiterste aan "beschikbaarheid" geeist wordt (zeg bij "air traffic control"). In zo'n geval koppel je twee identieke machines, die als ze beiden werken identiek hetzelfde doen om ook je vitale informatiebestanden in duplo te hebben. De koppeling dient dan om in geval van tijdelijke uitschakeling van de ene na afloop die weer in staat te stellen de draad op te pakken.
b) Indien een randapparaat of een toepassing zo urgente real time verplichtingen of een zo intensief informatieverkeer met zich meebrengt, dat dit een stuk "dedicated equipment" rechtvaardig - denk aan het drijven van een visual display.

Maar geen van beide rechtvaardigingen zijn in het onderhavige voorstel van toepassing. Het is absoluut misleidend om de zaak voor te stellen, alsof we er door koppeling "een grote installatie" van maken: het blijven vijf kleine machines elk met hun zeer beperkte capaciteit, daarenboven belast met de koppelingssoftware, die bv. zeker niet in staat zal zijn een door de P880 begonnen berekening "omdat die te groot wordt" door de P1400 te laten overnemen. Kortom bet tegendeel van een installatie die lekker in de hand ligt.

Edsger W.Dijkstra

transcribed by Hans Terlouw
revised Wed, 23 Dec 2009

EWD308 - 0

Reisverslag bezoek van E.W.Dijkstra aan IFIP W.G.2.3 te Warwick, Engeland.

De plaats van de handeling is Warwick University, een instelling waarvan (ter bestrijding van de kwalificatie "red brick university"?) alle gebouwen van buiten met een witte W.C. tegel zijn betegeld. Naderhand bleek dit een grapje van de architect: alle gebouwen zijn nu omheind door een rustieke houten palisadering en borden "Danger, falling tiles", en bij alle in-en-uitgangen zijn houten poortjes....

Met waarnemers meegeteld waren er ruim twintig man; de financieel moeilijkere situatie was duidelijk merkbaar aan de geringe opkomst van de Amerikanen: twee stuks hadden de overtocht gemaakt, een derde was dit jaar in Engeland.

Het peil van de voordrachten en de daarop volgende discussies was bijna altijd bijzonder hoog; daarbij sloten ze over het algemeen goed aan bij mijn eigen interessegebied, zodat ik geen spijt heb er naar toegeweest te zijn.

Maandagmorgen heeft Hoare uit Belfast een door hem genomen experiment beschreven. Het experiment bestond uit de beschrijving van een in tweerlei opzicht ingewikkeld programma, gemaakt door een vrien[d] van hem. Het ging over het maken van "school time tables". Zo'n programma is in tweelerlei opzicht ingewikkeld: ten eerste is de probleemstelling vaag en rommelig en de algorithme beïnvloed door heuristische overwegingen (van dubieuze effecitiviteit), ten tweede was het "tightly coded", omdat het aan de rand van de capaciteit van de betrokken machine lag. Naast een illustratie van zijn eigen ideeën was het —en dat maakte het voor mij zo boeiend— een bevestiging van veel ideeën uit mijn "Notes on Structured Programming", maar dan toegepast op een probleem dat een orde van grootte rommeliger en groter is dan de voorbeeldjes, waarmee ik doorgaans speel. Enerzijds was dit voor mij erg bemoedigend, anderzijds betekent het, dat als ik ooit een voorbeeld wil vinden, waarin deze ideeën niet van toepassing zijn, ik waarschijnlijk nog een orde van grootte groter moet proberen. Een beanstigende gedachte! Het eerste gedeelte van de morgen werd een beetje bedorven, doordat men in het begin niet goed doorhad, waar hij naar toe wilde waardoor de discussie een paar keer afgleed in het specifieke probleem van roostermaken.

Maandagmiddag heeft Lehman (IBM, Yorktown Heights) het woord gevoerd. Hij had twee heel verschillende onderwerpen. Het eerste was een relativerende bespiegeling over correctheidsbewijzen, het tweede een bespiegeling over enige kwantitatieve aspecten van de geschiedenis van OS360, waaruit bleek dat, terwijl het aantal modulen lineair groeit (als functie van het afleveringsnummer), de fractie modulen, die per wijziging niet constant blijven, exponentieel groeit! Dit proces eindigt in de nabije toekomst, als het summum van onhanteerbaarheid bereikt is. Wat dan?

Dinsdagmorgen sprak Ross (eertijds MIT, nu Softech) over een programmsmodel, dat aan AED-0 ten grondslag ligt. Hij was duidelijker dan ooit, ook overtuigender dan ooit, hoewel hij mijn reserve jegens AED —in weerwil van de onmiskenbare successen— niet heeft weggenomen. Ze reduceren programmeren tot het herhaald spelen van het zelfde soort spelletjes en hun succes moet geweten worden aan de omstandigheid dat ze dit soort spelletjes inmiddels heel goed kennen en zo zich beperken tot die opgaven, die zich tot dit soort spelletjes lenen. Ik noem het met nadruk "spelletjes" omdat het toch een riskant gepuzzle is. Zijn ruimtelijk/tijdelijk vorstellingsvermogen is verbluffend: als normale wiskundigen "een tekening" als communicatiemiddel accepteren, dan accepteert Ross een film. Dat hij niet praten kan zonder borden in hoog tempo met veranderende plaatjes vol te schilderen, is natuurlijk beangstigend. Deze omstandigheid

EWD308 - 1

draagt niet weinig bij tot de onleesbaarheid van zijn geschriften. Hij is als mens bijzonder boeiend, hij is onmiskenbaar een virtuoos en met de kwalificatie "een van der Poel op hoog niveau" zou ik hem te kort doen.

Dinsdagmiddag sprak Dahl (Oslo) naar aanleiding van de implementatie van SIMULA 67. Hij werd naar mijn smaak erg priegelig, hij is door syntactische zorgen gehypnotiseerd. Na anderhalf uur sliep het publiek. Hij denkt erg in termen van mechaniekjes en voor iemand, die zich interesseert in de "overdraagbaarheid" van dit soort bespiegelingen was het nog wel boeiend, zij het op een andere manier, dan de spreker bedoelde. Na de koffiepauze, toen we geen vast programma hadden, liep het heel onverwacht maar wel leuk. Ik vroeg de opinie van de vergaderde mensen over de drie wijzen van "data structuring": ALGOL68, PASCAL en iets waarover ik zelf overweeg te gaan denken. De reactie's waren bijzonder bemoedigend, het was voor mij een duidelijke aansporing op de ingeslagen weg voort te gaan. We hadden Paul (München), die als chairman van W.G.2.1 q.q. aanwezig mag zijn, onder ons gezelschap; zijn working group worstelt moedelos door aan ALGOL 68. "I triggered all his frustrations" en we hebben erg gelachen. Belangrijk was, dat Strachey (Oxford) op grond van wat ik had aangeroerd aanbood om de volgende dag, als er nog tijd was, te praten over het werk, dat Dana Scott bij hem gedaan had.

Woensdagmorgen was door de eerste helft aan huishoudelijke zaken gewijd, daarna sprak Strachey. Het was een soort lezing, dat ik van niemand zou accepteren behalve van Strachey; ik was erg dankbaar, het is het soort werk, waarin ik mij nooit storten zal, want op die manier ben ik lang niet knap genoeg, ik laat het graag aan in dit opzicht beter geëquipeerde hoofden over. Tegelijkertijd ben ik erg blij, dat het gedaan wordt, eindelijk een zuiver wiskundige die op een vruchtbaarder idee komt dan het classificeren van gecastreerde Turingmachines!

En daarme was de bijeenkomst gesloten; iedereen betreeurde[sic], dat het niet, zoals oorspronkelijk bedoeld, een dag langer had geduurd, maar Warwick University bleek vanwege de Pasen helemaal dicht te gaan.

Voor ongedwongen gesprekken 's avonds was de faciliteit niet helemaal voldoende, het was te lawaaiïg in de grote common room. Ik heb een leuk gesprek gehad met Hoare, die een stuk geschreven had, dat erg in de lijn lag van het afstudeerwerk van Bomhof en Feijen. Aan zijn stuk kleefde precies dezelfde beperking, die ik inmiddels ook aan het stuk van B. en F. ontdekt had: we zagen gelijktijdig, hoe deze beperking moest worden weggenomen. Dit gebeurde op een van de eerste avonden en rechtvaardigde opzichzelf de hele tocht al in mijn ogen. Ten gevolge hiervan weet ik, wat ik in deze zomer in München ga vertellen.

Verder heb ik met een heleboel mensen over een heleboel dingen gepraat, wel genoeg geslapen en niet teveel gedronken.

E.W.Dijkstra

Transcribed by David J. Brantley
Last revision Thu, 19 Feb 2004.

EWD309

Het idee is zo simpel. Je hebt kleine programma's en grotere programma's. Plaats daarom een configuratie van wat kleine machines en een grotere, dan kunnen de kleinere programma's op de kleine en de groter programma's op de grotere machine. Simple comme Bonjour!

Bij nadere beschouwing blijkt het echter een drogreden, want het is bij rekenmachines niet waar, dat vele kleintjes een grote maken. Het zou het leven voor gebruikers een stuk ingewikkelder maken, zelfs als de machines compatibel zouden zijn (wat in het onderhavige voorstel niet eens het geval is, maar daarover later).

Een gewetensvol programmeur houdt rekening met de beperkingen van de machine, die zijn programma moet uitvoeren. (De gemaakte opmerkinge, dat lang niet alle programmeurs in dit opzicht altijd zo gewetensvol zijn is irrelevant: je intensiefste gebruikers worden het heus wel en we hebben het over hen, niet over de beginnertjes die ook eens een broddellapje mogen breien.) Het voorstel zou om te beginnen impliceren, dat de gebruiker de macroscopische karakteristieken van twee verschillende machines moet kennen. Hinderlijk.
Nog hinderlijker is, dat de gebruiker moet kiezen, welke machine het programa moet uitvoeren. Vaak moet die keuze gemaakt worden voordat het programma gemaakt is omdat de keuze de structuur van het te maken programma zal beinvloeden. Dit betekent dat een programmeur moet uitmaken, wanneer een programma "klein" en wanneer "groot" is. Het werd voorgesteld of rekentijd hiervoor de maatstaf was. Dat is al niet aantrekkelijk, want afhankelijk van invoergegevens kan hetzelfde programma dan soms klein en soms groot zijn. Een ander aspect is benodigde werkruimte, maar ook dit kan voor het zelfde programma van run tot run verschillen. Tenslotte is er nog zoiets als lengte van de programmatekst. Gebruikers zouden zich bv. misschien wel moeten realiseren hoe lang de teksten van bibliotheekprocedures zijn! Maar het allerhinderlijkste is, dat deze verschillende maatstaven best tegen elkaar in kunnen wijzen, wat de gebruiker zou confronteren met het soort conflicten, die wij hem nu juist zo graag wilden besparen.

Totzover opmerkingen, die (enigszins) betrekking hebben op het programmabestand zoals zich dat tot op heden heeft ontwikkeld. Bij de keuze van een volgende machine hebben wij echter meer verantwoordelijkheden: de machine moet de wijze van werken, waar wij naar streven, bevorderen. Willen meer geavanceerde of in enigerlei opzicht meer gestroomlijnde machinetoepassingen van de grond komen, dan kan dit niet door ieder programma iedere keer weer van begin tot eind opnieuw uit te drukken op hetzelfde standaardniveau van een vaste programmeertaal. Middelen hiertoe zijn de opbouw van grote procedurebibliotheken en (special purpose) language processors. Het gebruik hiervan heeft ongetwijfeld tot gevolg dat meer programma's —in elk geval qua tekstlengte— groot worden. Dit is een gewenste ontwikkeling; door de voorgestelde configuratie van "vele kleintjes die niet een grote maken" zou hij echter tegengewerkt worden. (Tot overmaat van ramp kunnen we hierbij nog aantekenen, dat alle machines uit de configuratie als voorgesteld, met linkage editing werken, waardoor programmalengte een extra penalty veroorzaakt,)

Tenslotte zijn de machines niet compatibel, zo incompatibel, dat zelfs de ALGOL-systemen moeten verschillen. De hoop, dat deze verschillen door software realistisch gemaskeerd zouden kunnen worden, moet als illusoir gekenschetst worden. Zonder dit incompatibiliteitsdefect is de voorgestelde multi-machine-configuratie al hoogst onaantrekkelijk, met dit defect volstrekt onacceptabel.

15 april 1971 | prof.dr.Edsger W.Dijkstra

transcribed by Hans Terlouw
revised Sat, 9 Jan 2010

EWD310

Hierarchical Ordering of Sequential Processes

by Prof.dr. Edsger W. Dijkstra

The processing unit of a working computer performs in a short period of time a sequence of millions of instructions and as far as the processing unit is concerned this sequence is extremely monotonous: it just performs instructions one after the other. And if we dare to interpret the output, if we dare to regard the whole happening as "meaningful", we do so because we have mentally grouped sequences of instructions in such a way that we can distinguish a structure in the whole happening. Similar considerations apply to the store: high speed stores contain typically millions of bits stored in a monotonous sequence of consecutively numbered but otherwise equivalent storage locations. And again, if we dare to attach a meaning to such a vast amount of bits, we can only do so by grouping them in such a way that we can distinguish some sort of structure in the vast amount of information. In both cases the structure is our invention and not an inherent property of the equipment: with respect to the structure mentioned the equipment itself is absolutely neutral. It might even be argued that this "neutrality" is vital for its flexibility. On the other hand, it then follows that it is the programmer's obligation to structure "what is happening where" in a useful way. It is with this obligation that we shall concern ourselves. And it is in view of this obligation that we intend to start with a rather machine-bound, historical introduction: this gives us the unordered environment in which we have to create order, to invent structure adequate for our purposes.

In the very old days, machines were strictly sequential, they were controlled by what was called "a program" but could be called very adequately "a sequential program". Characteristic for such machines is that when the same program is executed twice —with the same input data, if any— both times the same sequence of actions will be evoked. In particular: transport of information to or from peripherals was performed as a program-controlled activity of the central processor.

With the advent of higher electronic speeds the discrepancy in speed between the central processor on the one hand and the peripheral devices on the other became more pronounced. As a resulttherecame for instance a strong economic pressure to arrange matters in such a way that two or more peripherals could be running simultaneously.

In the old arrangement one could write a program reading information from a paper tape, say at a maximum speed of 50 char/sec. In that case the progress through that piece of program would be synchronized with the actual movement of the paper tape through the reader. Similarly one could write a program punching a paper tape, say at a maximum speed of 30 char/sec. To have both peripherals running simultaneously and also closely to their maximum speed would require a tricky piece of program specifically designed for this mix of activities. This was clearly too unattractive and other technical solutions have been found. Channels were invented; a channel is a piece of hardware dedicated to the task of regulating the information traffic between the store and the peripheral to which it is attached, and doing this synchronized to the natural speed of the peripheral device, thus doing away with the implicit mutual synchronization of the peripheral devices that would be caused if both were controlled by the same sequential program execution.

The introduction of channels created two problems, a microscopic and a macroscopic one. The microscopic problem has to do with access to the store. In the old arrangement only the central processor required access to the store and when the central processor required access to the store it could get it. In the new arrangement, with the channels added —channels that can be regarded as "special purpose processors"— a number of processors can be competing with each other as regards access to the store because such accesses from different processors very often exclude eachother in time (for technical or logical reasons). This microscopic problem has been solved by the invention of the "switch", granting the competing processors access to the store according to some priority rule. Usually the channels have a lower traffic density and a higher priority than the central processor: the processor works at full speed until a channel requests access to the store, an arrangement which is called "cycle stealing". We draw attention to the fact that the unit of information in which this interleaving takes place —usually "a word"— is somewhat arbitrary; in a few moments we shall encounter a similar arbitrariness.

The macroscopic problem has to do with the coordination of central processor activity and channel activity. The central processor issues a command to a channel and from that moment onwards, two activities are going on simultaneously and —macroscopically speaking— independent of eachother: the central processor goes on computing and the channel transports information. How does the central processor discover, when the execution of the channel command has been completed? The answer to this has been the "interrupted". Upon completion of a channel command the channel sets an interrupt flip-flop; at the earliest convenient moment (but never sooner that after completion of the current instruction), the central processor interrupts the execution of the current program (in such a neat way that the interrupted computation can be resumed at a later moment as if nothing has happened) and starts executing an interrupt program instead, under control of which all now appropriate actions will be taken. From the point of view of the central processor it interleaves the various program executions, the unit of interleaving being —similarly arbitrarily— "the instruction".

The above scheme can be recognized in all larger, modern computers that I ever studied. It has been embellished in many directions but we don't need to consider those embellishments now. We go immediately to the next questions: given a piece of equipment constructed along the lines just sketched, what are the problems when we try to use it and in what direction should we look for their solution?

What are the problems? Well the main point is that from the point of view of program control such a piece of equipment must be regarded as a non-deterministic machine. Measured in a grain of time appropriate for the description of the activity of the central processing unit —clockpulse or instruction execution time— the time taken by a peripheral transport must be regarded as undefined. If completion of such a peripheral is signalled to the central processor by means of an interrupt, this means that we must regard the moment when the interrupt will take place (or more precisely: the point of progress where the computation will be interrupted) as unpredictable. The problem is that in spite of this indeterminacy of the basic hardware, we must make a more or less deterministic automaton out of this equipment: from the outside world the machine will be confronted with a well-defined computational task and it has to produce a well-defined result in a microscopically unpredictable way!

Let me give a simple example to explain what I mean by "a more or less deterministic automaton". Suppose that offering a program to the machine consists of loading a pack of cards into a card reader (and pushing some button on the reader in order to signal that it has been loaded). Suppose now that we have a machine with two readers and that we want to load it with two programs, A and B, and that we can do this by loading both card readers and pressing both buttons. We assume that the two card readers are not mutually synchronized, i.e. we regard both speeds as unpredictable. To what extent will the total configuration be a deterministic automaton? It will be fully deterministic in the sense that eventually it will produce both output A and output B. If these outputs are to be produced by the same printer, they will be produced in some order and the system may be such that the order in which the respective outputs appear on the printer does depend on the relative speeds of the two readers. As far as the operator is concerned, who has to take the output from the printer and to dispatch it to the customers, the installation is non-deterministic: what he has to do depends on the unpredictable speed ratio of the two readers, which may cause output A to precede or to follow output B. For both cases the operator has his instructions such that in both cases all output is dispatched to the proper customer. The "computation centre" —i.e. installation and operator together— are deterministic. We can regard the operator's activity as an outer layer, "wrapping up the installation", shielding from the outside world a level of interior indeterminacy.

Now, even if the operator is aware of not having a fully deterministic machine, we should recognize that he has only to deal with two cases —output A before output B or the other way round— while the number of possible sequences of occurrences at cycle time level is quite fantastic. In other words, by far the major part of the "shielding of indeterminacy" is done by the installation itself. We call the resulting installation "more or less deterministic" because as the case may be, a few degrees of limited freedom —here one boolean degree of freedom— may be left unpredictable.

We have called the operator's activity "an outer layer", shielding a level of indeterminacy, and of course we did so on purpose. At the other end we may distinguish an inner layer, viz. in the channel signalling (via an interrupt signal) that the next card has been read: it tells the central processor that the next card image is available in core, regardless which storage cycles have been stolen to get it there. The terms "inner layer" and "outer layer" have been chosen in order to suggest that in the total organization we shall be able to distinguish many layers in between. But an important remark is immediately appropriate: I assume that with the card read command an area in core has been designated to receive this card image: the remark that the interrupt signalled the completed transfer of the card image irrespective of which cycles had been stolen to transport its constituents is only true, provided that no other access to the designated core area took place in the period of time ranging from the moment the command was given up to the moment that the completion was signalled! Obvious but vital.

It draws our attention to an element of structure that must be displayed by the remaining programs if we wish to make the total organization insensitive to the exact identity of the cycles stolen by the channel. And from the above it is clear that this insensitivity must be one of our dearest goals. And on next levels (of software) we shall have to invent similar elements of structure, making the total organization insensitive (or "as insensitive as possible") to the exact moment when interrupts are honoured. Again it is clear that this must be one of our dearest goals. And on a next level we must make our organization insensitive (or "as insensitive as pos-sible") to the exact number of cards put into the readers for program A and B, and so on . . . . . This "layered insensitivity" is, in two words, our grand plan.

I have used the term "layer" on purpose, because it has seemed to pro-vide an attractive terminology in terms of which to talk about operating systems and their total task. We can regard an operating system as the basic software that "rebuilds" a given piece of hardware into a (hopefully) more attractive machine. An operating system can then be regarded as a sequence of layers, built on top of eachother and each of them implementing a given "improvement". Before going on, let me digress for a moment and let me try to explain why I consider such an approach of ordered layers a fruitful one.

There is an alternative approach, which I would like to call the approach via unordered modules. There one makes a long list of all the functions of the operating system to be performed, for each function a module is programmed and finally all these modules are glued together in the fervent hope that they will cooperate correctly and will not interfere disastrously with each other's activity. It is such an approach which has given rise to the assumed law of nature, that complexity grows as the square of the number of program components, i..e. of the number of "functions".

In the layered approach we start at the bottom side with a given hardware machine A0, we add our bottom layer of software rebuilding A0 into the slightly more attractive machine A1 , for which the next layer of software is programmed rebuilding it into the still more attractive machine A2, etc. As the machines in the sequence A0 , A1 , A2, ... get more and more attractive, adding a further layer gets easier and easier. This is in sharp contrast to the approach via unordered modules, where adding new functions seems to get progressively worse!

So much in favour of a layered approach in general. When one wishes to design an operating system, however, one is immediately faced with the burning question, which "improvement" is the most suitable candidate to be implemented in the bottom layer.

For the purpose of this discussion I will choose a very modest bottom layer. I do so for two reasons. Firstly, it is a choice with which for historical reasons I myself am most familiar. Secondly, as a bottom layer it is very modest and neutral, so neutral in fact that it provides us with a mental platform from where we can discuss various alternatives for the structure of what is going to be built on top of it. As a bottom layer it seems close to the choice of minimal commitment. The fact that this bottom layer is chosen as a starting point for our discussion is by no means to be interpreted as the suggestion that this is the best possible choice: on the contrary, one of the later purposes of this discussion is the consideration of alternatives.

With the hardware taking care of the cycle stealing we felt that the software's first responsibility was to take care of the interrupts, or, to put it a little more strongly, to do away with the interrupt, to abstract from its existence. (Besides all rational arguments this decision was also inspired by fear based on the earlier experience that, due to the irreproducibility of the interrupt moments, a program bug could present itself misleadingly like an incidental machine malfunctioning.) What does it mean "to do away with the interrupt"? Well, without interrupt the central processor continues the execution of the current sequential process while it is the function of the interrupt to make the central processor available for the continuation of another sequential process. We would not need interrupt signals if each sequential process had its own dedicated processor. And here the function of the bottom layer emerged: to create a virtual machine, able to execute a number of sequential programs in parallel as if each sequential program had its own private processor. The bottom layer has to abstract of the existence of the interrupt or, what amounts to the same thing, it has to abstract from the identity of the single hardware processor. If this abstraction is carried out rigorously it implies that everything built on top of this bottom layer will be equally applicable to a multiprocessor installation, provided that all processors are logically equivalent (i.e. have the same access to main memory etc.). The remaining part of the operating system and user programs together then emerges as a set of harmoniously cooperating sequential processes.

The fact that these sequential processes out of the family have to cooperate harmoniously implies that they must have the means of doing so, in particular, they must be able to communicate with eachother and they must be able to synchronize their activities with respect to eachother. For reasons which, in retrospect, are not very convincing, we have separated these two obligations. The argument was that we wished to keep the bottom layer as modest as possible, giving it only the duty of processor allocation; in particular it would leave the "neutral, monotonous memory" as it stood, it would not rebuild that part of the machine and immediately above the bottom layer the processes could communicate with eachother via the still available, commonly accessible memory.

The mutual synchronization, however, is a point of concern. Closely, related to this is the question: given the bottom layer, what will be known about the speed ratios with which the different sequential processes progress? Again we have made the most modest assumption we could think of, viz. that they would proceed with speed ratios, unknown but for the fact that the speed ratios would differ from zero. I.e. each process (when logically allowed to proceed see below) is guaranteed to proceed with some unknown, but finite speed. In actual fact we can say more about the way in which the bottom layer grants processor time to the various candidates: it does it "fairly" in the sense that in the long run a number of identical processes will proceed at the same macroscopic speed. But we don't tell, how "long" this run is and the said fairness has hardly a logical function.

This assumption about the relative speeds is a very "thin" one, but as such it has great advantages. From the point of view of the bottom layer, we remark that it is easy to implement: to prevent a running program to monopolize the processor an interrupting clock is all that is necessary. From the point of view of the structure built on top of it is also extremely attractive: the absence of any knowledge about speed ratios forces the designer to code all synchronization measures explicitly. When he has done so he has made a system that is very robust in more than one sense.

Firstly he has made a system that will continue to operate correctly when an actual change in speed ratios is caused, and this may happen in a variety of ways. The actual strategy for processor allocation as implemented by the bottom layer, may be changed. In a multiprocessor installation the number of active processors may change. A peripheral may temporarily work with speed zero, e.g. when it requires operator attention. In our case the original line printer was actually replaced by a faster model. But under all those changes the system will continue to operate correctly (although perhaps not optimally, but that is quite another matter).

Secondly —and we shall return to this in greater detail— the system is robust thanks to the relative simplicity of the arguments that can convince us of its proper operation. Nothing being guaranteed about speed ratios means that in our understanding of the structure built on top of the bottom layer we have to rely on discrete reasoning and there will be no place for analog arguments, for other purposes than overall justification of chosen strategies. I trust that the strength of this remark will become apparent as we proceed.

Let us now focus our attention upon the synchronization. Here a key problem is the so-called "mutual exclusion problem". Given a number of cyclic processes of the form

cycle begin entry;

            critical section;

            exit;

            remainder of cycle

      end

program "entry" and "exit" in such a way that at any moment at most one of the processes is engaged in its critical section. The solution must satisfy the following requirements:

a) The solution must be symmetrical between the processes; as a result we are not allowed to introduce a static priority.

b) Nothing may be assumed about the ratio of the finite speeds of the processes; we may not even assume their speeds to be constant in time.

c) If any of the processes is stopped somewhere in "remainder of cycle", this is not allowed to lead to potential blocking of any of the others.

d) If more than one process is about to enter its critical section, it must be impossible to devise for them such finite speeds, that the decision to determine which of them will enter its critical section first is postponed until eternity. In other words, constructions in which "After you"-"After you"-blocking, although improbable, is still possible, are not to be regarded as valid solutions.

I called the mutual exclusion problem "a key problem". We have met something similar in the situation of programs A and B producing their output in one of the two possible orders via the same printer: obviously those two printing processes have to exclude each other mutually in time. But this is a mutual exclusion on a rather macroscopic scale and in all probability it is not acceptable that the decision to grant the printer to either one of the two activities will be taken on decount of the requirement of mutual exclusion alone: in all probability considerations of efficiency or of smoothness of service require a more sophisticated printer granting strategy. The explanation why mutual exclusion must be regarded as a key problem must be found at the microscopic end of the scale. The switch granting access to store on word basis provides a built in mutual exclusion, but only on a small, fixed and rather arbitrary scale. The same applies to the single processor installation which can honour interrupts in between single instructions: this is a rather arbitrary grain of activity. The problem arises when more complicated operations on common data have to take place. Suppose that we want to count the number of times something has happened in a family of parallel processes. Each time such an occurrence has taken place, the program could try to count it via

n:= n+1

If in actual fact such a statement is coded by three instructions

R:= n;

R:= R+1;

n:= R

then one of the increases may get lost when two such sequences are executed, interleaved on single instruction basis. The desire to compound such (and more complicated) operators on common variables is equivalent to the desire to have more explicit control over the degree of interleaving than provided by the neutral, standard hardware. This more explicit control is provided by a solution to the mutual exclusion problem.

We still have to solve it. Our solution depends critically on the communication facilities available between the individual processes and the common store. We can assume that the only mutual exclusion provided by the hardware is to exclude a write instruction or a read instruction, writing or reading a single word. Under that assumption the problem has been solved for two processes by T.J. Dekker in the early sixties. It has been solved by me for N processes in 1965 (C.A.C.M., 1965, Vol. 8, nr. 9, pag. 569). The solution for two processes was complicated, the solution for N processes was terribly complicated. (The program pieces for "enter" and "exit" are quite small, but they are by far the most difficult pieces of program I ever made. The solution is only of historical interest.)

It has been suggested that the problem could be solved when the individual processes had at their disposal an indivisible "add to store"which would leave the value thus created in one of the private process registers as well, so that this value is available for inspection if so desired. Indicating this indivisible operation with braces the suggested form of the parallel programs was:

cycle begin while {x:= x+l } ≠ 1

               do {x:= x-1};

            critical section;

            {x:= x-1};

            remainder of cycle

end

where the "add to store" operation is performed on the common variable "x" which is initialized with the value zero before the parallel programs are started.

As far as a single process is concerned the cumulative Δx as effected by this process since its start is =0 or =1; in particular, when a process is in its critical section, its cumulative Δx = 1. As a result we conclude that at any moment when N processes are in their critical section simultaneously, x≥N will hold.

A necessary and sufficient condition for entering a critical section is that this process effectuates for x the transition from 0 to 1. As long as one process is engaged in its critical section (N = 1 ), x>1 will hold. This excludes the possibility of the transition from 0 to 1 taking place and therefore no other process can enter its critical section. We conclude that mutual exclusion is indeed guaranteed. Yet the solution must be rejected: it is not difficult to see that even with two processes (after at least one succesful execution of a critical section) "After you"-"After you" blocking may occur (with the value of x oscillating between 1 and 2).

A correct solution exists when we assume the existence of an indivisible operation "swap" which causes a common variable (x) and a private variable (loc) to exchange their values. With initially x = 0 the structure of the parallel programs is:

begin integer loc; loc:= 1;

      cycle begin repeat swap (x, loc)

                  until loc = 0;

                  critical section;

                  swap (x, loc);

                  remainder of cycle

            end

end

The invariant relation is that of the N+1 variables (i.e. the N loc's and the single x) always exactly one will be =0, the others being =1. A process is in its critical section if and only if its own loc =0, as a result at. most one process can be engaged in its critical section. When none of the processes is in its critical section, x = 0 and "After you"-"After you" blocking is impossible. So this is a correct solution.

In a multiprogramming environment, however, the correct solutions referred to or shown have a great drawback: the program section called "enter" contains a loop in which the process will cycle when it cannot enter its critical section. This so-called "busy form of waiting" is expensive in termsof processing power, because in a multiprogramming environment (with more parallel processes than processing units) there is a fair chance that there will be a more productive way of spending processing power than giving it to a process that, to all intents and purposes, could go to sleep for the time being.

If we want to do away with the busy form of waiting we need some sort of synchronizing primitives by means of which we can indicate those program points where —depending on the circumstances— a process may be put to sleep. Similarly we must be able to indicate that potential sleepers may have to be woken up. What form of primitives?

Suppose that process 1 is in its critical section and that process 2 will be the next one to enter it. Now there are two possible cases.

a) process 1 will have done "exit" before process 2 has tried to "enter"; in that case no sleeping occurs

b) process 2 tries to "enter" before process 1 has done "exit"; in that case process 2 has to go sleep temporarily until is woken up as a side-effect of the "exit" done by process 1.

When both occurrences have taken place, i.e. when process 2 has succesfully entered its critical section it is no longer material whether we had case a) or case b). In that sense we are looking for primitives (for "enter" and "exit") that are commutative. What are the simplest commutative operations on common variables that we can think of? The simplest operation is inversion of a common boolean, but that is too simple for our purpose: then we have only one operation at our disposal and lack the possibility of distinguishing between "enter" and "exit". The next simplest commutative operations are addition to (and subtraction from) a common integer. Furthermore we observe that "enter" and "exit" have to compensate eachother: if only the first process passes its critical section the common state before its "enter" equals the common state after its "exit" as far as the mutual exclusion is concerned. The simplest set of operations we can think of are increasing and decreasing a common variable by 1 and we introduce the special synchronizing primitives

P(s) : s : = s-1

and

V(S) : s : = s+1

special in the sense that they are "indivisible" operations: if a number of P- and V-operations on the same common variable are performed "simultaneously" the net effect of them is as if the increases and decreases are done "in some order".

Now we are very close to a solution: we have still to decide how we wish to characterize that a process may go to sleep. We can do this by making the P- and V-operations operate not on just a common variable, but on a special purpose integer variable, a so-called semaphore, whose value is by definition non-negative; i.e. s≥0.

With that restriction, the V-operation can always be performed: unsynchronized execution of the P-operation, however, could violate it.

We therefore postulate that whenever a process initiates a P-operation on a semaphore whose current value equals zero, the process in question will go to sleep until (another) process has performed a V-operation on that very same semaphore. A little bit more precise: if a semaphore value equals zero, one or more processes may be blocked by it, eager to perform a P- operation on it. If a V-operation is performed on a semaphore blocking a number of processes, one of them is woken up, i.e. will perform its now admissible P-operation and proceed. The choice of this latter process is such that no process will be blocked indefinitely long. A way to implement this is to decide that no two processes will initiate the blocking P-operation simultaneously and that they will be treated on the basis "first come, first served" (but it needs not be done that way, see below).

With the aid of these two primitives the mutual exclusion problem is solved very easily. We introduce a semaphore "mutex" say, with the initial value

mutex = 1,

after which the parallel processes controlled by the program

cycle begin P(mutex);

            critical section;

            V(mutex);

            remainder of cycle

      end

are started.

Before proceeding with the discussion I would like to insert a remark. In languages specifically designed for process control I have met two other primitives, called "wait" and "cause", operating on an "event variable", which is a (possibly empty) queue of waiting processes. Whenever a process executes a "wait" it attaches itself to the queue until the next "cause" for the same event, which empties the queue and signals to all processes in the queue that they should proceed. Experience has shown that such primitives are very hard to use. The reason for this is quite simple: a "wait" in one process and a "cause" in another are non-commutative operations, their net effect depends on the order in which they take place and at the level where we need the synchronizing primitives we must assume that we have not yet effective control over this ordering. The limited usefulness of such "wait" and "cause" primitives could have been deduced a priori.

As a next interlude I am going to prove the correctness of our solution. One may ask "Why bother about such a proof, for the solution is obviously correct". Well, in due time we shall have to prove the correctness of the implementation of more sophisticated rules of synchronization and the proof structure of this simple case may then act as a source of inspiration.

With each process "j" we introduce a state variable "Cj", characterizing the progress of the process.

Cj = 0 | process j is in the "remainder of cycle"
Cj = 1 | process j is in its "critical section".

While process j performs (i.e., "completes") the operation P(mutex)j the translation Cj=0 → Cj=1 takes place, when it performs the operation V(mutex)j the transition Cj=1 → Cj=0 takes place. (Note that the Cj are not variables occurring in the program, they are more like functions defined on the current value of the order counters.) In terms of the Cj the number of processes engaged in its critical section equals

(Σj : 1 ≤ j ≤ N : Cj )    NOTE

In order to prove that this number will be at most =1, we follow the life history of the quantity

K   =  mutex + (Σj : 1 ≤ j ≤ N : Cj )

The quantity K will remain constant as long as its constituents are constant: the only operations changing its constituents are the 2N mutually exclusive primitive actions P(mutex)i and V(mutex)i (for 1 ≤ i ≤ N) .

We have as a result of

P(mutex)i : ΔK = Δmutex + Δ(Σj : 1 ≤ j ≤ N : Cj )

                       = Δmutex + ΔCi

                       = +1 -1 = 0

and similarly, as a result of

V(mutex)i : ΔK = Δmutex + ΔCi

                       = +1 -1 = 0

As these 2N operations are the only ones affecting K's constituents, we conclude that K is constant, in particular, that it is constantly equal to its initial value,

K = 1 + (Σj : 1 ≤ j ≤ N : 0) = 1

As a result

(Σj : 1 ≤ j ≤ N : Cj ) = 1 - mutex .

Because mutex is a semaphore, we have

0 ≤ mutex

and from the last two relations we conclude

(Σj : 1 ≤ j ≤ N : Cj ) ≤ 1

Because this sum is the sum of non-negative terms we know

0 ≤ (Σj : 1 ≤ j ≤ N : Cj )

Combining this with

mutex = 1 - (Σj : 1 ≤ j ≤ N : Cj ).

We conclude

mutex ≤ 1.

i.e. mutex is a so-called "binary semaphore", only taking on the values 0 and 1.

Finally we observe that no process will be kept out of its critical section without justification: if all processes are outside their critical sections, all Cj 's are =0 and therefore mutex is =1, thereby allowing the first process that wants to enter its critical section to do so.

For later reference we summarize the structure of this proof. A central role is played by an invariant relation among common variables (here only the semaphore) and "progress variables" (here the Cj 's). Its invariance is proved by observing the net effect of the (mutually exclusive) operators operating on its constituents, without any further assumptions about their mutual synchronization, about which we can then make assertions on account of the established invariance. In the sequel we shall see that this pattern of proof is very generally applicable.

Before proceeding with more complicated examples of synchronization we must make a little detour and make a connection with earlier observations. When a process is engaged in its critical section, a great number of other processes may go to sleep. When the first one leaves its critical section, it is undefined which'of the sleepers is woken up, the only requirement being that no single process is kept sleeping indefinitely long. (This latter assumption we have to make when, later, we wish to prove assertions about the finite progress of individual processes.) In this sense our "family of sequential processes" is still a mechanism of an undeterministic nature, but the degree of undeterminacy is a mild one compared with the original hardware, in which an interrupt could occur between any pair of instructions: the only indeterminacy left is the relative order of much larger units of action, viz. the critical sections. In this respect the bottom layer of our operating system achieves a step towards our goal of "layered insensitivity".

It is in this connection that I should like to make another remark of quantitative nature. The choice of the process to be woken up is left undefined because it is assumed that it does not matter, i.e. we assume the system load to be such that the total period of time that any of the processes will be engaged in its critical section will be a negligible fraction of real time, in other words, nearly always mutex = 1 will hold. It is for that reason that such a neutral policy for waking up a sleeper is permissible. This is no longer true for our macroscopic concerns regarding so-called 'resource allocation". In the case of a number of programs producing their output via the same printer, these printing actions have to exclude each other mutually in time, but it is no longer true that the total time spent in printing will be a negligible fraction of real time! On the contrary: in a well-balanced system the printer will be used with a duty cycle close to 100 percent! In order to achieve this —and to satisfy other, perhaps conflicting design requirements— such a neutral policy which is adequate for granting entrance into critical sections will certainly be inadequate for granting a scarce resource like a printer. For the implementation of a less neutral granting policy we shall use the critical sections, entrance to which is granted on a neutral basis. (For an example of a more elaborate synchronization implemented with the aid of critical sections we refer to the Problem of the Dining Philosophers to be treated later.) This is the counterpart of the "layered insensitivity": going upwards in levels we gain more and more control over the microscopic indeterminacy, but simultaneously macroscopic strategic concerns begin to enter the picture: it seems vital that the bottom layer with its microscopic concerns does not bother itself with such macroscopic considerations. This observation seems to apply to all well-designed systems: I would call it a principle if I had a better formulation for it.

We now turn to a slightly more complicated example, viz. a bunch of producers and a bunch of consumers, coupled to each other via an unbounded buffer. In this example all producers are regarded as equivalent to each other and all consumers are regarded as equivalent to each other. Under these assumptions —which are not very realistic— the semaphores provide us with a ready-made solution.

In the commonly accessible universe we have

a) a buffer, initialized empty

b) a semaphore "mutex", initialized =1; this semaphore caters for the mutual exclusion of operations changing buffer contents

c) a semaphore "numqueuepor"; this gives (a lower bound of) the number of portions queueing in the buffer.

Then a producer may have the form

cycle begin produce next portion;

            P(mutex);

            add portion produced to buffer;

            V (numqueuepor);

            V(mutex)

      end

with consumers of the following structure

cycle begin P(numqueuepor);

            P(mutex) ;

            take portion from buffer;

            V(mutex);

            consume portion taken

      end

Note 1: The order of the V-operations in the producer is immaterial, the order of the P-operations in the consumer is absolutely essential.

Note 2: The assumption is that the operations "produce next portion" and "consume portion taken" are the slow, timeconsuming operations —possible in synchronism with other equipment— for which parallelism is of interest, while the actions "add portion produced to buffer" and "take portion from buffer" are very fast "clerical" operations.

In the above program the semaphore "numqueuepor" is a so-called "general semaphore", i.e. a semaphore whose possible values are not restricted to 0 and 1. We shall now give an alternative program, using only binary semaphores.

In the commonly accessible universe we have

a) a buffer and an integer "n" counting the number of portions in the buffer. The buffer is initializedempty (incl. n:= 0)

b) a semaphore "mutex" initialized =1; this semaphore caters for the mutual exclusion of the operations changing the buffer contents, the value of "n" and the inspection of "n".

c) a semaphore "consal" initialized =0; if this semaphore is =1, a next consumption is allowed.

Then a producer may have the form

cycle begin produce next portion;

            P (mutex);

            add portion to buffer

              (incl. n:=n+l);

            if n=1 do V(consa1);

            V(mutex)

      end

with consumers of the following structure

cycle begin P(consa1);

            P(mutex);

            take portion from the buffer

              (incl. n:=n-1);

            if n > o - do V(consa1);

            V(mutex) ;

            consume portion taken

      end

Although it is not too hard to convince ourselves "by inspection" —whatever that may mean— that the above bunch of programs work properly, it is illuminating to give a somewhat more formal treatment of their cooperation. (I am now used to calling such a more formal treatment of their cooperation 'a correctness proof", although I did not formalize the requirements that such a piece of reasoning should satisfy in order to be a "valid proof".)

The proof consists of two steps. The first step uses our earlier result, viz. that the P(mutex) and V(mutex) establish mutual exclusion of the critical sections. (Inside these critical sections we find no P-operations, as a result they cannot give rise to deadlock situations.) This observation allows us to regard the critical sections as indivisible operations and to confine our attention to the state of the system at the discrete moments with mutex =1 (i.e., no one engaged in its critical section).

In the second step we define three mutually exclusive states for the whole system and shall show that whenever the system is started in one of these states, it will remain within these states. For the purpose of state description we introduce a function defined on the progress of the consumers, viz.

K = | the number of consumers that have performed "P(consa1)" but have not yet entered the following critical section.

Now we can introduce our three states

S1 : n=0 and K=0 and consal=0

S2 : n>0 and K=0 and consal=1

S3 : n>0 and K=1 and consal=0

Three operations; (viz. P(consa1) and the two critical sections) operate on the constituents of these boolean expressions; for each state we investigate all three.

S1 : (initial state)

P(consal) : impossible (on account of consal=0)

critical producer section  : transition to S2

critical consumer section : impossible (on account of K=0)

S2 :

P(consal) : transition to S3

critical producer section  : transition to S2

critical consumer section : impossible (on account of K=0)

S3 :

P(consal) : impossible (on account of consal=0)

critical producer section  : transition to S3

critical consumer section : transition to S1 or S2

This concludes the second step, showing the invariance of

S1 or S2 or S3

(from which we conclude N≥0 and consal≤1)

A few remarks, however, are in order, for we have cheated slightly. Let us repair our cheating first and then give our further comments. In our second step we have investigated the isolated effect of either P(consa1) or the critical producer section or the critical consumer section. For the critical sections this is all right for they exclude eachother mutually in time; the operation P(consal), however, can take place during a critical section, and we did not pay any attention to such coincidence. We can save the situation by observing that in the case of coincidence the net effect is equal to the execution of the critical section immediately followed by P(consa1). This is really a messy patching up of a piece of reasoning that was intended to be clean. Now our further comments.

1) The proof shows why the mutual exclusion problem is worthy, of the name "a key problem". Thanks to the mutual exclusion of critical sections we only need to consider the net effect of each single, isolated section. If these sections were not critical, i.e. could take place in arbitrary interleaving, we would have to consider the net effect of one section, the net effect of two sections together, of three sections together, of four etc.! With N cooperating processes the number of cases to be investigated would grow like 2N (i.e. the powerset!). This is one of the strongest examples showing how the amount of intellectual effort needed for a correctness proof may depend critically on structural aspects of the program, here the aspect of mutual exclusion. It is this observation that is meant to justify the inclusion of the above proof in this text.

2) The proof is complicated considerably by the fact that P(consa1) is an operation sequentially separate from the following critical section: this caused the messy patching up of our piece of reasoning, it called for the introduction of the function "K". If the conditional entrance of critical sections is going to be a standard feature of the system, a more direct way of expressing this would be essential. A minimal departure of the current formation would be the introduction of the parallel P-operation, allowing us to combine the two P-operations of the consumer into

P(consa1, mutex)

3) For the sake of completeness we mention that in the THE multiprogramming system, where we used general semaphores to control synchronization along information streams, each information stream had at any moment in time at most one consumer attached to it. As a result a general semaphore could block at most one process and when a V-operation was performed on it there was never the problem which process should be woken up. The absence of the possibility that more than one process is blocked by a general semaphore is not surprising: it is the semaphore "consal" that may be equal to zero for a long period of time; as a result it is not to be expected that it is irrelevant which of the processes will be woken up when a V-operation is performed on it. In the design phase of the THE multiprogramming system the parallel P-operation has been considered but finally it has not been implemented because we felt that it contained the built-in solution to an irrealistic problem. But it would have simplified proof procedures.

We now turn to the problem of the Five Dining Philosophers. The life of a philosopher consists of an alternation of thinking and eating:

cycle begin think;

            eat

      end

Five philosophers, numbered from 0 through 4 are living in a house where the table laid for them, each philosopher having his own place at the table:

Their only problem —besides those of philosophy— is that the dish served is a very difficult kind of spaghetti, that has to be eaten with two forks. There are two forks next to each plate, so that presents no difficulty: as a consequence, however, no two neighbours may be eating simultaneously.

A very naive solution associates with each fork a binary semaphore with the initial value =1 (indicating that the fork is free) and, naming in each philosopher these semaphores in a local terminology, we could think the following solution for the philosopher's life adequate

cycle begin think;

            P(1eft hand fork);

            P(right hand fork);

            eat;

            V(1eft hand fork);

            V(right hand fork)

      end

But this solution —although it guarantees that no two neighbours are eating simultaneously— must be rejected because it contains the danger of the deadly embrace. When all five philosophers get hungry simultaneously, each will grab his left hand fork and from that moment onwards the group is stuck. This could be overcome by the introduction of the parallel P-operat- ion, combining the two P-operations into the single

P(1eft hand fork, right hand fork).

For the time being we assume the parallel P-operation denied to us —later we shall reject the solution using it on other grounds— and we shall show how (using only single P-operations and binary semaphores) we can derive our solution in a reasonably controlled manner.

In order to be able to give a formal description of our restriction, we associate with each philosopher a state variable, "C" say, where

C[i] = 0 means: philosopher i is thinking

C[i] = 2 means: philosopher i is eating.

In accordance with their first act, all C's will be initialized =0. In terms of the C's we can state that it is disallowed

(∃i : : C[i] = 2 and C[i+1 mod 5 ] = 2), | (1)

in words: no philosopher may be eating while his left hand neighbour is eating as well. From this formula it follows that for a C the transition from 2 to 0 can never cause violation of the restriction (1 ), while the transition from 0 to 2 can. Therefore we introduce for the last transition an intermediate state

C[i] = 1 means: philosopher i is hungry

Now each philosopher will go cyclically through the states 0, 1, 2, 0 ...... The next question to ask is: when has the (dangerous) transition from 1 to 2 to take place for philosopher K? Well, three conditions have to be satisfied

1) C[K]= 1, i.e. he himself must be hungry

2) C[(K+1) mod 5] ≠ 2, because otherwise

C[K]:=2 would cause violation of (1) for i=K

3) C[(K-1) mod 5] ≠ 2, because otherwise

C[K]:=2 would cause violation of (1) for i=(K-1) mod 5

As a result we have to see to it that the state

(∃K : : C[(K-1) mod 5] ≠ 2 and C[K] = 1 and C[(K+1) mod 5] ≠ 2 ) | (2)

is unstable: whenever it occurs, it has to be resolved by assigning C[K]:= 2 and sending philosopher K to the table.

In a similar analysis we ask: which transitions in the life of philosopher w can cause the unstable situation and for which values of K?

1) when C[w]:= 1 is executed, instability may be created for K = w

2) when C[w]:= 0 —i.e. when C[w] loses the value 2— instability may be created for K = (w+1) mod 5 and for K = (w-1) mod 5.

In words: when philosopher w gets hungry, the test whether he himself should be sent to the table is appropriate, when he leaves the table the test should be done for both his neighbours.

In the universe we assume declared

1) the semaphore mutex, initially = 1

2) the integer array C[O:4], with initially all element = 0

3) the semaphore array prisem [0:4] with initially all elements = 0

4) procedure test (integer value K);

    if C[(K-1) mod 5] ≠ 2 and C[K]= 1
        and C[(K+1) mod 5] ≠ 2 do

          begin C[K]:= 2; V(prisem[K]) end;

(This procedure, which resolves unstability for K when present, will only be called from within a critical section).

In this universe the life of philosopher w can now be coded

cycle begin think;

            P (mutex);

               C[w]:= 1; test (w) ;

            V(mutex);

            P(prisem[w]); eat

            P(mutex);

               C[w]:= 0; test [(w+l) mod 5];

               test [(w-1) mod 5];

            V(mutex)

      end

And this concludes the solution I was aiming at. I have shown it, together with the way in which it was derived, for the following reasons.

1) The arrangement with the private semaphore for each process and the common semaphore for mutual exclusion in order to allow for unambiguous inspection and modification of common state variables is typical for the way in which in the THE multiprogramming system all synchronization restrictions have been implemented that were more complicated than straightforward mutual exclusion or synchronization along an information stream (the latter synchronization has been implemented directly with the aid of a general semaphore).

2) The solution (inclusive the need for the introduction of the intermediate state called "hungry") has been derived by means of a formal analysis of the synchronization restriction. It is exemplar for the way in which the flows of mutual obligations for waking up have been derived in the design phase of the THE multiprogramming system. It is this analysis that I have called "A constructive approach to the problem of program correctness".

With respect to this particular solution I would like to make some further remarks.

Firstly the solution as presented is free from the danger of deadlock, as it should be. Yet it is highly improbable that a solution like this can be accepted because it contains possibility of a particular philosopher being starved to death by a conspiration of his two neighbours. This can be overcome by more sophisticated rules (introducing besides the state "hungry" also the state "very hungry"); this requires a more complicated analysis but by and large it follows the same pattern as the derivation shown. This was another reason not to introduce the parallel P-operation: for the solution with the parallel P-operation we did not see an automatic way of avoiding the danger of individual starvation.

Secondly we could have made a more crude solution: the procedure "test" has a parameter indicating for which philosopher the test has to be done; also in the critical sections we call the procedure "test" precisely for those philosophers for whom there is a chance that they should be woken up and for no others. This is very refined: we could have made a test procedure without parameter that would simply test for any K if there was an unstability to be removed. But the problem could have been posed for 9 or 25 philosophers and the larger the number of philosophers, the more prohibitive the overhead of the crude solution would get.

Thirdly, I have stated that we "derived our solution in a reasonably controlled manner": although the formal analysis has been carried out almost mechanically, I would not like to suggest that it should be done automatically, because in real life, whether we like it or not, the situation can be more complicated.

We consider two classes of processes, class A and class B, sharing the same resource from a large pool. (The situation occurred in the THE multiprogramming system with the total pool of pages in the system.) Suppose now that processes from class A ask and return items from this pool at high frequency, while those from class B do so at low frequency only. In that case it is highly unattractive to pose upon the highly frequent item releases of class A the (possibly) considerable overhead involved in the analysis of whether it is necessary to wake up one or more blocked processes. This high-frequency overhead was avoided by delegating the waking-up obligation to (some) processes of class B and by guaranteeing that at least one of these processes would be active when the boundary of the resource restriction was in danger of being approached. In other words, in order to reduce system overhead we removed the highly frequent inspection whether processes had to be woken up at the price of increasing the "reaction time" there where an ultra short "response" was not required. The taking of such decisions seems a basic responsibility of the system designer and I don't see how they could be taken automatically.

The above concludes my discussion of the chosen bottom layer. In the final part of this paper I would like to discuss briefly an alternative solution.

The chosen bottom layer implements a family of sequential processes plus a few synchronizing primitives, the remaining part of the system, to be composed on top of it, will exist of a set of harmoniously cooperating sequential processes. The interface is characterized by a number of features

a) the bottom layer treats all sequential processes on the same footing

b) the sequential processes communicate to each other via commonly accessible variables

c) critical sections ensure the unambiguous interpretation and modification of these common variables.

One or two objections can be raised to this organisation; they center around the observation that each sequential process can be in one of two mutually exclusive, radically different states: either the process is inside its critical section or it is not. Inside its critical section it is allowed to access the comnon variables, outside it is not. In actual fact this difference does not only pertain to accessibility of information, it has also a bearing on processor allocation as implemented in the bottom layer. Given a process without hurry it is permissible to take the processor away from it for longer periods of time, but it is unattractive to do so in the middle of a critical section: if a process is stopped within a critical section it blocks for the other processes themechanismneeded for their cooperation and the remaining processes are bound to come to a grinding halt. In the THE multiprogramming system this has been overcome by giving processes two colours —red or white— by making each process red while it is in a critical section and by never granting the processor to a white process if a red one is logically allowed to proceed.

Furthermore there is the aspect of reproducibility. To an individual user, offering a strictly sequential program to the system, we should like to present a strictly deterministic automation. In the system a number of sequential processes are dedicated to the processing of user programs, they act as slots into which a user program can be inserted; whenever the user program refers to a shared resource the translator effectively inserts —via a subroutine call— the critical section required for this cooperation. As a result, what happens in this slot is perfectly reproducible as long as the sequential process remains outside critical sections. But if we wish to charge our user and also insist that the charge be reproducible, we can only charge him for the activity of the slot outside critical sections! What happens inside the critical sections is situation dependent system overhead: it does not really "belong" to the activity of the process in which the critical section occurs.

Finally, we know how to interpret the evolution of a sequential process as a path through "its" state space as is spanned by "its" variables. But for this interpretation to be valid, it is necessary that all variables "belong" uniquely to one sequential process.

It is this collection of observationsthat was an incentive to redo some of our thinking about sequential processes and to reorder the total activity taking place in the system. Instead of N sequential processes cooperating in critical sections via common variables, we take out the critical sections and combine them into a N+1st process, called "a secretary"; the remaining N processes are called "directors". Instead of N equivalent processes, we now have N directors served by a common secretary. (We have used the metaphor of directors and a common secretary because in the director-secretary relation in real-life organisation its also unclear who is the master and who is the slave!)

What used to be critical sections in the N processes are in the directors "calls upon the secretary".

The relation between a set of directors and their common secretary shows great resemblance to the relation between a set of mutually independent programs and a common library. What is regarded as a single, unanalysed action on the level of a director, is a finite sequential process on the level of the secretary, similar to the relation between main program and subroutines.

But there is also a difference. In the case of a common library of re- entrant procedures, the library does not need to have a private state space: whenever a library procedure is called its local state space can be embedded (for the duration of the call) in the (extendable) state space of the calling program.

A secretary, however, has her own private state space, comprising all 'common variables". One of the main reasons to introduce the concept of "a secretary" is that now we have identified a process to which the "common variables" belong: they belong to the common secretary.

To stress the specific nature of a secretary, I call her "a semi-sequential process". A fully sequential process consists of a number of actions to be performed one after the other in an order determined by the evolution of this process. A secretary is a bunch of actions —"operators in her state space"— to be performed one after the other, but in an undefined order, i.e. depending on the calls of her directors.

A secretary presents itself primarily as a bunch of non-reentrant routines with a common state space. But as far as the activity of the main program is concerned there is a difference between the routine of a secretary and a normal subroutine. During normal subroutine call we can regard the main program "asleep", while the return from the subroutine "wakes" the main program again. When a director calls a secretary —for instance when a philosopher wishes to notify the secretary that now he is hungry— the secretary may decide to keep him asleep, a decision that implies that she should wake him up in one of her later activities. As a result the identity of the calling program cannot remain anonymous as in the case of the normal subroutine. The secretary must have variables of the type "process identity" whenever she is called the identity of the calling process is handed over in an implicit in-put parameter, when she signals a release —analogous to the return of the normal subroutine— she will supply the identity of the process to be woken up.

In real time a director can be in three possible states with respect to his secretaries.

a) "active", i.e. his progress is allowed

b) "calling", i.e. he has tried to initiate a call on a secretary, but the call could not be honoured, e.g. because the secretary was busy with another call

c) "sleeping", i.e. a call has been honoured but the secretary's activity in which he will be released has not ended.

The state "calling" has hardly any logical significance: it would not occur if the director was stopped just before the call that could not be honoured.

With respect to her directors a secretary can be

a) "busy", i.e. engaged in one of her (finite) algorithms

b) "idle", i.e. ready to honour a next call from one of her directors.

Note that a secretary may be simultaneously busy with respect to her directors and calling or sleeping with respect to one of her subsecretaries.

In two respects, the above scheme asks for embellishments. Firstly, a secretary may be in such a state that certain calls on her service are inconvenient. With each call we can associate a masking bit, stating whether with respect to that call she is "responding" or "deaf". A secretary managing an unbounded buffer could be deaf for the consumer's call when her buffer is empty. Here we have another reason why a director may be in the state "calling": besides being busy the secretary could be deaf for the call concerned. For the reasons stated I have my doubts as to whether this embellishment is very useful, but I mention it because it seems more useful than similar embellishments that have been suggested, e.g. making a secretary responding to an enumerated list of directors. The secretary has to see to it that certain constraints will not be violated, i.e. she may be in such a state that she can not allow certain of her possible actions to take place. This has nothing to do with the identity of the director calling for such an action.

A more vital embellishment is parameter passing: in general a director will like to send a message to his secretary when calling her —a producing director will wish to hand over the portion to be buffered; in general a director will require an answer back from his secretary when she has released his call— a consuming director will wish to receive the portion to be unbuffered.

Note that this message passing system is much more modest than various mail box systems that have been suggested in which processes can send mes- sages (and proceed!) to other processes. In such systems elaborate message queues can be built up. Such systems suffer from two possible drawbacks. Firstly, implementation reasons are apt to impose upper limits to lengths of message queues: "message queue full" may be another reason to delay a process and to show the absence of the danger of deadly embraces may prove to be very difficult. Secondly, and that seems worse, with the queueing messages we have reintroduced state information that cannot be associated with an individual process.

From an esthetic point of view the relation director-secretary is very pleasing because it allows secretaries to act as directors with respect to subsecretaries. This places our processes in a hierarchy which avoids deadly embraces as far as mutual exclusion is concerned in exactly the same way in which mutual exclusion semaphores would need to be ordered in the case of nested critical sections. Whether, however, actual systems can be built up with a meaningful hierarchy of secretaries of reasonable depth —say larger than two— remains to be seen. That is why I called this point of view "esthetically pleasing".

Finally: I can only view a well-structured system as a hierarchy of layers and in the design process the interface between these layers has to be designed and decided upon each time. I am not so much bothered by designer's willingness and ability to propose such interfaces, I am seriously bothered by the lack of commonly accepted yardsticks along which to compare and evaluate such proposals. My "playing" with a bottom layer should therefore not be regarded as a definite proposal for yet another interface, it was meant to illustrate a way of thinking

Acknowledgement is due to my former students J. and W.H.J. Feyen and to Professor C.A.R. Hoare from the Queen's University of Belfast.

transcribed by Ham Richards

last revision Sun, 10 Feb 2008

EWD 311

Bauer, Goos: "Informatik, Erster Teil" Heidelberger Taschenb�cher, Band 80
Springer Verlag, 1971.

In view of the central position this book is expected to occupy in the German computer science curricula at University level, the book is by definition important and therefore it deserves a review judging the book from as many different points of view as we can think of. Another consequence of the book's importance, however, is that, no matter from which point of view the book is judged, we must choose very high standards.

The book contains four chapters, the first one (56 pages) on "Information and Message", the second (81 pages) on "Fundamental Concepts of Programming", the third one (37 pages) on "Machine Oriented Programming Languages" and the fourth one (30 pages) on "Switching Networks".

The first chapter "Information and Message" covers a broad spectrum of subjects, ranging from optical illusions, via digital messages, codes and Shannon's information theory to message processing and information processing. It shows a great erudition and is very readable. The authors must be complemented for the way in which they compressed so much information into only a quarter of the whole booklet and I have no doubts that the inclusion of much of it is fully justified by the level of ignorance of the average freshman for which the book is intended, but your reviewer found it difficult to justify the inclusion of all of it: he wonders why full tables of German phonemes, the Flexowriter code, the ISO 7-bit code, Morse code, the International Flag Code and bigram and trigram frequencies in German text have all been included. He definitely objects to the inclusion of a map of the human brain, showing the localisation of its different functions: this information is vital for the brain surgeons, but absolutely irrelevant for the person who tries to use his own brain, an irrelevance that your reviewer regards as one of the key messages of computer science.

The last section — in particular subsection 1.7.2 "The interpretation of message processing" — is not too satisfactory. As an interpretation associates with each message "an information", it presents an interpretation as a mapping of a set of messages on to "a set of information". A set of messages is called redundant when the interpretation associates the same information — i.e. the same element of the set called "the set of information" — with different messages — i.e. different elements of the set called "the set of messages". So far as good, but as a conceptual basis for the next chapter — but perhaps it is the next chapter that is to be blamed for this — it is extremely shaky. I will return to this in a moment.

The second chapter "Fundamental Concepts of Programming" leans heavily on the programming language ALGOL 68. As this programming language has been greeted with highly mixed feelings, the decision to use its conceptual framework in such a basic text can only be regarded as a political decision (which may have most undesirable consequences). The decision astonishes your reviewer and he can only conclude that someone has played his political cards extremely well. As an introduction to the conceptual framework of ALGOL 68 the second chapter seems as clear as the subject matter permits. Equating the message with ALGOL 68's "internal object" ("possessed" by the external object in question) it suddenly turns out that when different messages have the same information associated with them, the external objects possess not the same internal object, but "different instances" of that same internal object, and this is not a mere playing with words, because when a few pages later the reference is introduced, it turns out to refer to a specific instance of the internal object!

The first seven sections (64 pages) of the second chapter deal with various aspects (and mannerisms!) of ALGOL 68, its last section (17 pages), called "Remarks on the Practice of Programming", contains some well-motivated remarks on program documentation, followed by an extremely terse treatment of a number of well-chosen examples. When we realize that programming is a human activity, the second chapter suddenly strikes us as presenting a rather one-sided view of the subject. Hardly any attention is paid to the process of program composition, nor to any of the techniques available for providing assertions about the computations evoked by a program. The authors don't seem to feel that, besides controlling and guiding his creative abilities, increasing the confidence in the correctness of his program, is one of the most difficult aspects of the programmer's task. In short, your reviewer is rather disappointed by the second chapter, both for what it gives and for what it omits.

The third chapter arrives at a description of the structure of machine code programs — and eventually machines — via a top-down analysis of the task that is presented by the mechanical execution of a program written in a higher level programming language. The worked out examples of various way of evaluating expressions are somewhat laborious to follow, but it is hard to see how this could have been avoided. The chapter is very well understandable and the attention given by the authors to the possibility [of] parallel computing gives the chapter a very special flavour.

The fourth chapter, on "Switching Networks" is concise and well-written. It gives a short introduction to Boolean algebra, it introduces the common switching elements and makes some networks out of them. The diagrams are of an outstanding quality and are therefore a pleasure to study. Its shortness is one of its virtues: to your reviewer's taste it pays exactly the right amount of attention to the subject.

With the technical get-up of the book, Springer-Verlag did an excellent job, the only possible complaint being that a rather small fount has been used.

May, 1971 | Edsger W. Dijkstra Technological University Eindhoven, The Netherlands

transcribed by Corrado Cantelmi
revised Fri, 2 May 2008

EWD312

Verslag van reis van E.W.Dijkstra naar Noord Amerika

Deze reis onderscheidde zich van al mijn vorige bezoeken aan Noord Amerika doordat ik door mijn beminde Ria vergezeld werd, wat het op allerlei manieren wel vermoeiender maakte. Ik had daardoor een uitgebreider sociaal programma, moest mijn aandacht meer verdelen en bleef al die tijd geregeld Nederlands spreken, zodat ik af en toe met het Engels moeite had. Daar staat natuurlijk een heleboel tegenover. Ik heb een heleboel dingen gedaan, die ik anders nooit gedaan zou hebben (zoals een bezoek aan de Niagara Falls), er wordt een ander soort hartelijkheid aan je besteed, die je weer een nieuwe kijk op de Amerikaanse samenleving geeft en tenslotte was het een afdoende middel tegen de heimwee, waar ik anders nogal last van pleeg te hebben.

Ik heb erg hadr[sic] moeten werken: van de tien werkdagen, die ik er doorgebracht heb, heb ik met uitzondering van de tweede donderdag altijd gesproken, de eerste vier dagen zelf drie uur per dag. Dat het voor mijn gevoel althans op de beide vrijdagen wat mislukte, wijt ik dan ook voornamelijk aan vermoeidheid. Wij kwamen op een vrijdag aan, het daaropvolgende weekend hebben wij doorgebracht met ons aanpassen aan de verzette klok en het bekijken van Washington, dat met uitzondering van een oase in de onmiddellijke nabijheid van alle monumenten en regeringsgebouwen wel helemaal in een zwart getto ontaard is. Verveloos en beangstigend. Maar de vlam bij het graf van Kennedy brandt nog... Onze gastheer was in al zijn hartelijkheid de slechtste chauffeur, waaran we sinds jaren zijn blootgesteld en we slaakten een (beleefdelijk onderdrukte) zucht van verlichting, toen we ongeschonden in Maryland terugkeerden.

In [M]aryland gaven David Gries en ik een Summer Institute on Compilers and Operating Systems; David dee[sic] de compilers, ik de operating systems. We hadden een gevarieerd gehoor van een man of zeventig, dat qua opleiding en ervaring van een hoger kaliber was, dan we verwachtten: de helft had meer dan vier jaar ervaring, er waren iets van twintig PhD's. Het was een bijzonder prettig gehoor om toe te spreken (gelukkig!) en van alle kanten hebben we te horgen gekregen, dat dit Summer Institute een groot succes was. David Gries had het qua onderwerp iets moeilijker dan ik, omdat zijn verhaal zich twaalf uur lang op hetzelfde niveau bewoog, terwijk ik er iets meer variatie in kon brengen en naar een climax kon toewerken. Toen Yaohan Chu ons om opmerkingen vroeg, hebben we wel gezegd, dat hij door maar twee sprekers te engageren wel een groot risico had genomen. Het liep deze keer goed af, maar de verantwoordelijkheid drukte wel een beetje zwaar. Chu heeft mij bij herhaling verzekerd, dat ik vast voor een volgende keer weer uitgenodigd zal worden, maar of ik dat aan aanneem, staat te bezien, in weerwil van het feit, dat ik echt geloof, goed werk geleverd te hebben.

De Universiteit van Maryland trof mij als een triest en bloedarm opleidingsinstituut. Elke dag vertelde wel iemand me (vol trots, dat was het ergste!) dat ze wel 35.000 studenten hadden. Maar wat ze leerden... Het ademde de sfeer, zoals ik me die van de Leids Onderwijs Instellingen voorstel. (Het semester was net afgelopen, we zagen allerlei "Graduation" plechtigheiden in gang, compleet met cap-and-gown, zoals we die van de affiches van de LOI zo goed kennen. De campus was vol onwennige familie.) De campus zelf is een volslagen rotzooi, behalve dat alle gebouwen in dezelfde, lelijke stijl zijn opgetrokken: rode baksteen met kleine raampjes en bij de ingang vier Griekse zuilen, die een fries ondersteuenen om ook dit gebouw de allure van een tempel der wetenschap te geven. Daartussen een ongeordende verzameling van slecht onderhouden grasvelden en slecht onderhouden parkeerplaatsen. (Van de 35.000 sudenten[sic] leven er 12.000 op de campus, de rest reist op en neer in auto's, waar veel oud roest bij is.) De Department of Computer Science had 17 faculty members, vanwie ik niemand kende, zelfs niet bij naam; en ze hebben 300 graduate students, voor het merendeel werkstudenten, die er heel lang over doen geloof ik. Het Summer Institute werd gehouden in het Center of Adult Education, op een hoek van de campus. Als faciliteit was dit heel geschikt, het laat zich het beste beschrijven als een hotel met voldoende conferentiezalen. We hadden er een voortreffelijke hotelkamer, op de laatste dag moesten we onze koffers een beetje vroeg pakken, omdat het Summer Instituteruimte[sic] moest maken voor de Miss Maryland verkiezingen! Toen we weggingen zeiden Ria en ik tegen elkaar "Dat was dan Maryland" en hebben er geen moment aandacht meer aan geschonken.

We gingen op donderdagavond naar New York, waar we gast waren van dr.M.M.Lehman van IBM, Yorktown Heights, waar ik vrijdag de eerste slechte voordacht van de trip gehouden heb. Misschien hebben ze dat niet gemerkt, ze hebben het me in elk geval niet nagedragen: de lunch daarna was heel geanimeerd, het was een lunch voor VIP's en ik werd uitgenodigd in Yorktown Heights te komen ("Any period ranging from a few weeks to a year.") met de bedoeling dat ik me zou wijden aan heuristiek; het is wederom onwaarschijnlijk, dat ik deze uitnodiging zal aannemen, maar ik vond hem wel leuk, omdat het toont, dat mijn pogingen me een beetje los te maken van compilers en operating systems met enig succes bekroond lijkt te worden. 's Middags een boeiend onderhoud met Don Fraser -die ik niet kende- over het doceren van programeren. Fraser vertelde me een heleboel (wat ik grotendeels weer vergeten ben) over algorithmen met betrekking tot graphen, de man had een verfrissende kijk op wat we nu met machines kunnen en horen te doen. Daarna een onderhoud met Jim King, die helemaal uit het gebied van correstheidsbewijzen[sic] weg is en simulatiemodellen voor systemen ontwikkelt; maar toen was ik ook wat moe. Vrijdagavond met mijn gastheer mee naar de synagoge, zo compleet met petje op het hoofd, dat ik niet van een echte Jood te onderscheiden was: er wordt gevraagd "of ik de vader van Esther Steiner was"! Zaterdag hebben we een orhtodoxe Sabbath gevierd, en zondagmorgen vertrokken we via de Niagara Falls naar Toronto, waar we 's avonds aankwamen.

Toronto was weer hard werken. Ik heb vier voordrachten gehouden, steeds 's middags van twee tot vier voor een gehoor van een man of zeventig. Timing was moeilijker, omdat ik gedeeltelijk preekte tot de bekeerden; de zaal gaf veel respons en daardoor was aanpassing van mijn verhalen niet te moeiljik. Ik heb de verhalen van Maryland dunnetjes overgedaan. Daarnaast heb ik veel gepraat met de mensen die verantwoordelijk waren voor "a project named SUE". De eerste ochtend heb ik hun documentatie bestudeerd, die zo goed was, dat ik vrij snel "in the picture" was. Ze hadden me een dun verhaaltje van tevoren toegestuurd; ik was op grond daarvan onder de indruk van de professionele aanpak van hun planning. Bij nader inzien bleek die indruk wat overdreven: hun schattingen over hoe groot het systeem zou worden en hoe lang de constructie zou duren, waren uit de lucht gegrepen. Dit project betreft een operating system voor de 360. Het hele bezoek heeft mij er -ten overvloede!- nog een van overtuigd, wat een rotmachine dat is. De verhalen van David Gries over compiler constructie brachten duidelijk aan het licht wat een ellende "code generation" voor die opdrachtcode is, in Toronto waren ze met handen en voeten gebonden aan de interrupt ogranisatie van deze machine. Ik werd daar herinnerd aan de uitspraak van Barton "A hardened piece of junk propagates all through the system." en of het de groep in Toronto zat[sic] lukken iets overtuigends te maken, staat nog helemaal te bezien. Ze waren er zelf ook nog niet zo zeker van. Enige cocktail parties gaven wel inzicht in het Canadese academische leven. Levendiger dan in Maryland. Ten aanzien van de onhanteerbaarheid van hedendaagse computer systemen zijn twee heel verschillende reacties mogelijk. De ene reactie zou ik willen beschrijven als "verfijning van onze quantitatieve beheersingstechnieken". Dit is erg in de mode. Mensen ontwerpen allerlei (al of niet stochasitsche[sic]) modellen in de hoop hieraan, hetzij door simulatie, hetzij door analytische methodes, voorspellingen over gedrag te kunnen ontlenen. Dit brengt met zich mee, dat deze modellen aan de praktijk getoetst moeten worden, wat een ontwikkeling van meting aan bestaande systemen ten gevolge heeft gehad. Er zijn zelfs stemmen, die betogen, dat computer science pas wolwassen zal zijn, wanneer het zich in deze zin ontwikkeld heeft tot experimentele wetenschap. Deze ontwikkeling voert op het ogenblik ongetwijfeld de boventoon, zeker in Amerika. Mijn eigen reactie op de onhanteerbaarheid is tegengesteld: ik wil liever onderzoeken, waardoor deze systemen zo onhanteerbaar zijn geworden, om mij vervolgens te beperken tot de intellectueel hanteerbare (in het vertrouwen, dat deze verzameling voldoende gevuld is). Deze vorm van complexiteitsanalyse, herleiding tot (in principe vaak vermijdbare) oorzaken is in Amerika, waar men de machines veel meer beschouwt als onveranderlijk gegeven, nauweljiks bekend. Het was geloof ik in hoofdzaak daardoor, dat ik mijn gehoor nogal boeide. Omdat haast niemand dit doet, geloof ik, dat ik nog maar een tijdje op de ingeslagen weg zal doorgaan, al zit er het gevaar in, dat er erg "weinig" overblijft om de rest van een mensenleven mee te vullen.

23 juni 1971 Edsger W.Dijkstra

transcribed by David J. Brantley
revision Sat, 29 May 2004

EWD316

EWD316: A Short Introduction to the Art of Programming

by

prof.dr.Edsger W.Dijkstra

August 1971

Contents

0. Contents

1. Preface

2. Some Fundamental Notions

3. Programming Languages and their Implementation

4. Variables and relations between their values

5. Programs corresponding to recurrence relations

6. A first example of step-wise program composition

7. The shortest spanning subtree of a graph

8. The towers of Hanoi

9. The problem of eight queens

10. A rearranging routine

1. Preface

The market is already so heavily overloaded with introductory texts on computers and computer programming that one must have rather specific reasons to justify the investment of one's time and energy in the writing of yet another "Short Introduction to the Art of Programming". The sole fact that one likes to write is, in itself, an insufficient justification. Before undertaking such a task I should therefore ask myself "Why am I going to do it?" and also "What do I expect to be the distinguishing features of this little monograph?".

There is a simple, practical reason. At my University I give, mainly for future Mathematical Engineers, an introduction to the art of programming and my students would welcome some supporting material. Besides that, without some form of lecture notes, my colleagues have very little idea of what I am really trying to teach! The contents of this course show signs of settling down —I have now given it three times— and therefore this seems the appropriate moment to produce a document that can serve as lecture notes.

These are purely local circumstances and as far as they are concerned, a normal set of lecture notes —in Dutch, say— would do. The fact that I have not chosen this form means that I am aiming at a larger audience. Such an act is always somewhat presumptuous and the usual author's trick to save the image of his modesty is to say that from various sides he has been urged to produce his manuscript —a trick that I could apply in this case without lying. But I don't think that I shall resort to that trick because I really believe that a larger audience than just my students can benefit from it, or even enjoy it.

The fact is that over the last years I have addressed myself to the question of whether it was conceivable to increase our programming ability by an order of magnitude and what techniques (mental, organizational or mechanical) should then be applied in the process of program composition. Personally, I felt these investigations very rewarding: I gained a much deeper understanding of the nature of the difficulty of the programming task, I became much more conscious about my "programming style", which improved considerably, and found myself, when programming, in much better control of what I was doing than I had ever been before. Needless to say, my teaching was heavily influenced by these experiences.

The purpose of this little monograph is to assist the programming reader in cleaning up his own thinking, to transmit to him some mental disciplines by sticking to which he can avoid making his job unnecessarily difficult. It is born out of dissatisfaction with the usual kind of programming course, which now strikes me as like the type of driving lessons in which one is taught how to handle a car instead of how to use a car to reach one's destination. This monograph is intended as a complement to such courses; I shall try to present programming —to quote Niklaus Wirth— "as a discipline on its own merits, as a methodology of constructive reasoning applicable to any problem capable of algorithmic solution".

I expect the distinguishing feature of this little monograph to be its incompleteness, incompleteness in many, many respects.

It will not be self-contained in the sense that I assume my readers somewhat familiar with a decent higher level programming language. (This assumption is a direct consequence of the local circumstance that my students have had a modest prior exposure to the cleaner aspects of ALGOL 60.)

For those readers who identify the programmer's competence with a thorough knowledge of the idiosyncrasies of one or more of the baroque tools into which modern programming languages and systems have degenerated, the book will also be very incomplete, because I won't describe any programming language —not even the one I use— to any degree of detail. I shall use some sort of programming language, as "a communication language" say, not for the communication of algorithms, but for the communication of ways of thinking, as a vehicle for programming style.

In yet another respect, this little monograph will be very incomplete. As said above, I shall try to present programming "as a discipline on its own merits, as a methodology of constructive reasoning applicable to any problem capable of algorithmic solution". At present, such a methodology does not yet exist in the full sense of the word, only elements of it have become apparent, others are just lurking behind our mental horizon. This of course, is not very satisfactory, but it is a true reflection of the current, still rather poor state of the art. It is a consolation that no piece of scholarship ever reaches the state of perfection and I tell myself that the conviction that there is more to come is no justification for witholding what we have got.

It will also be incomplete as a result of the choice of the examples and the choice of the considerations. By necessity, the examples will be "small" programs, while the need for a discipline becomes really vital in the case of "large" programs. Dealing with small examples in an ad-hoc fashion gives the student not the slightest clue as to how to keep the construction of a large program under his intellectual control. Illustrating how we can avoid unmastered complexity, I hope to deal with small examples in such a fashion, that methodological extrapolation to larger tasks is feasible. The selection of considerations is also kept to a strict minimum: we restrict ourselves to programming for purely sequential machines and when we consider a trade-off question, we shall usually present this in the form of a trade-off between computation time versus store requirements. In this respect the document may strike the reader as very strongly dated, perhaps even out-dated by the time it appears in print. If so, I hope that I can justify my defense, which is that such a reader has failed to read between the lines: it is not so much the particular trade-off question chosen that matters, as the fact that problem has been approached in such a fashion that we have made a conceptual framework in which such specific trade-off questions can be postponed until the appropriate moment. The only thing I can do at this stage is to urge my readers to read between the lines as much as possible. (If one tries to transmit ideas or methods, one can talk about them but that alone is insufficient: one must show examples illustrating them. When lecturing, it is my sad experience that after having dealt with a specific example, I find the attention of half my audience completely usurped by this example: they have forgotten that the example was only brought to their attention to illustrate something more general. This is a sad experience and no amount of prior warning that this misunderstanding is bound to happen if they are not careful, has ever enabled me to avoid it!) To put it in another way: it is my purpose to transmit the importance of good taste and style in programming, the specific elements of style presented serve only to illustrate what benefits can be derived from "style" in general. In this respect I feel akin to the teacher of composition at a conservatory: he does not teach his pupils how to compose a particular symphony, he must help his pupils to find their own style and must explain to them what is implied by this. (It has been this analogy that made me talk about "The Art of Programming".)

There is a further class of potential readers that will find this subject matter very incompletely dealt with, viz. those who identify the programmer's task with writing programs in, say, FORTRAN or PL/1. One of my implicit morals will be that such programming languages, each in their own way, are vehicles inadequate to guide our thoughts. If FORTRAN has been called an infantile disorder, PL/1 must be classified as a fatal disease.

Although I would love to do it, it is impossible to give a true acknowledgement, listing all persons whose relevant influence on my thinking I gratefully remember or should remember. With my apologies to all persons unmentioned I would like to make a few exceptions and list in alphabetical order: my mother mrs.B.C.Dijkstra-Kluyver, R.W.Floyd, C.A.R.Hoare, P.Naur, B.Randell, D.T.Ross, N.Wirth and M.Woodger. None of the persons listed, however, should in any way be held responsible for the views expressed (with the possible exception of my mother who is in some sense responsible for my existence).

I am deeply indebted to my sister-in-law, mrs.E.L.Dijkstra-Tucker for her willingness to correct my use of English in yet another manuscript and to W.H.J.Feijen for the great care with which he has screened the text for typing errors.

Back to top

Next chapter: 2. Some Fundamental Notions

transcribed by Bert Put
revised Mon, 1 Sep 2008

EWD316a

Reisverslag van Edsger W. Dijkstra aan Summer School Marktoberdorf, juli 1971.

De alles overheersende indruk van de International Summer School on Program Structures and fundamental Concepts of Programming is “vermoeiend”: elke werkdag strekte zich uit van 8.20 in de ochtend tot 18.15 in de late middag. Ter ontspanning hebben we een dag een excursie door de Beierse Alpen gehad, die zo mogelijk nog afmattender was! Onze reis (samen met Bomhoff en Feijen in de auto van de laatste) was zowel heen als terug heel voorspoedig, statistisch gezien zelfs onwaarschijnlijk voorspoedig. We vertrokken op een zondagmorgen om vijf uur uit Eindhoven en waren in het begin van de middag in Marktoberdorf. Voor het weekend van de terugreis hoorden we zo alarmerende voorspellingen over de “Urlaubswelle” op de autobanen, dat we vrijdagavond om kwart voor elf haastig zijn vertrokken; om kwart voor zeven zaterdagmorgen stand Bomhoff op zijn stoep in Leende. We hebben die nacht wel ettelijke ongelukken en onvoorstelbaar lange files gezien, maar de files stonden gelukkig voor ons in de tegengestelde richting. Ik heb wel het gevoel, dat we door het oog van de naald gekropen zijn en of ik het nog een keer aandurf, staat erg te bezien.

Zoals al even aangeduid was het gedeelte “ontspanning” even overladen als de summer school zelf. Op de tweede avond was er een Beierse avond, gekarakteriseerd door literglazen bier, de zaterdag werd in beslag genomen door een excursie naar München, waar de deelnemers langs ik weet niet hoeveel musea gesleurd zijn. Beide evenementen heb ik om mijn zwakke lichaam te sparen overgeslagen. Ik ben wel meegeweest naar de excursie door de Beierse Alpen: twee kerken, twee kastelen en een klooster. De kastelen waren gebouwd door Ludwig de tweede van Beieren, die kennelijk knettergek is geweest; nochtans toonden de Beieren deze kastelen met een onbegrijpelijke trots. Het kasteel Neuschwanstein kan ik iedereen, die zich superieur wil voelen, van ganserharte aanbevelen. Het is een hele klim, maar boven op de berg vind je dan wel iets unieks van lelijkheid, elke kamer gewijd aan een opera van Wagner!

Nou de Summer School zelf. Er waren ongeveer tachtig deelnemers uit pakweg vijftien landen. Voor de Italianen en de Fransen was de taalbarriere —de officiele taal van de Summer School was Engels— kennelijk bijna niet te nemen: zij hakten bij hun landgenoten bij elkaar en het was als spreker erg moeilijk om enige terugkoppeling tot stand te brengen. Zelfs de Duitsers, die over het algemeen geen moeilijkheden hadden om de verhalen te volgen, mengden zich maar heel schroomvallig in de discussies. Het resultaat is, dat ik nog geen duidelijk idee heb van het peil van de deelnemers, ik denk dat het een vrij gemengd stel was. Gemiddeld wel met vrij wat ervaring, maar sommigen uitgesproken theoretisch, sommigen uitgesproken practisch gericht. Van de sprekers stal C.A.R.Hoare uit Belfast ongetwijfeld de show: hij trad elke morgen na het ontbijt op. (Hij had gevraagd “vroeg” te mogen spreken: in plaats van in het begin van de Summer School sprak hij aan het begin van elke dag!) Hij sprak over axiomatisering van in programmering gangbare begrippen. Het leuke was, dat hij dit niet alleen koppelde aan bewijsvoering van de correctheid van programma’s, maar ook aan elementen van programmeertalen. Het was verder louterend te observeren, dat hij met veel reserve sprak over de beperktheid van zijn onderwerp: hij liet duidelijk merken, dat in allerlei gevallen het leveren van een formeel correctheidsbewijs hem niet reeel voorkwam. Zo’n beetje in de trant van “je moet een correctheidsbewijs kunnen leveren, indien je daartoe uitgedaagd wordt, maar het is niet iets om aldoor te doen.”.

N.Wirth uit Zürich sprak de eerste week acht uur over zijn schepping, de programmeertaal Pascal. Het was jammer, dat hij zich een beetje in de hoek liet drukken, van waaruit hij deze programmeertaal moest verdedigen, zodat hij betrekkelijk veel over de programmeertaal Pascal zelf gesproken heeft en veel minder over zijn implementatieervaring. Dat laatste was jammer, want hij heeft daarmee een bijzonder mooi stuk werk geleverd, daarmee mijn indruk bevestigend, dat hij een van Europa’s meest competente programmeurs is. De Pascal-vertaler is eerst in Pascal geschreven, daarna voor zover nodig voor zijn eigen vertaling met de hand in een paar weken tijd “vertaald” in iets voorradigs: twee weken, nadat ze voor het eerst toegang tot de machine hadden gehad, vertaalde de Pascalvertaler zichzelf! Hoare gebruikte nu hun Pascalvertaler voor een bootstrap voor de ICL-machine in Belfast en was ongelofelijk enthousiast. Omdat hier metterdaad bewezen is, dat bootstrapping een reele techniek is, had ik over die ervaring wel meer willen horen. Maar we weten het in elk geval.

De status van Pascal werd niet alleen ondersteund door Hoare’s axiomatiseringspogingen —Hoare heeft in het ontwerp van Pascal een aanzienlijke hand gehad— maar ook, doordat Per Brinch Hansen zich ervan bediende om operating system principles in te beschrijven. Brinch Hansen is afgelopen jaar, gedeeltelijk samen met Nico Habermann, bezig geweest aan een boek over “Operating System Principles” en nam in zijn verhalen deze tekst door. De tekst was wel aardig, maar werd niet prettig gebracht. Als spreker is hij een beetje monotoon, hij voelde zich bovendien niet op zijn gemak: het zat hem kennelijk niet lekker, dat hij zoveel aan mij had moeten ontlenen en kreeg daardoor, op zoek naar een eigen positie, iets querolanterigs. Op een avond in het hotel is dat tot een heel nare uitbarsting gekomen; ik heb geprobeerd, dit zoveel mogelijk langs me te laten afglijden, maar dat lukte niet. Ik heb daarna die nacht nauwelijks geslapen en was de volgende dag, toen ik spreken moest, dan ook niet zo erg op dreef.

De grote Alan J.Perlis vond ik slecht. Hij spreekt met ontzettend veel gemak. Om niet te zeggen bluf; zijn grapjes zijn altijd het meest zorgvuldig voorbereide gedeelte van zijn voordracht en het is een genoegen om naar hem te luisteren, zolang je niet critisch luistert naar wat hij zegt. Tot zijn ongeluk deed een fractie van het gehoor hetlaatste wel, in de discussies is het het vuur nogal na aan de schenen gelegd en hoewel hij ogenschijnlijk er ongeschonden uitkwam, was dat niet zo. Zijn eigenlijke onderwerp was LCC, een conversational language, die in Carnegie-Mellon ontwikkeld is. Maar dit was bijzonder moeilijk te verdedigen in dit gehoor, het ging lijnrecht in tegen de ideeen over programma structurering, zoals die door Wirth, Hoare en mij gepreekt werden. Verder viel hij om de andere lezing terug in APL, waartoe hij onlangs bekeerd was en ook hier faalde zijn overtuigingskracht. Ik heb hem nooit zo onzeker meegemaakt; misschien had het er mee te maken, dat hij Carnegie-Mellon had verlaten en een week tevoren naar Yale University was overgestapt om daar (in een omgeving beroemd voor zijn “humanities”) een nieuw leven te beginnen. Hij maakte professioneel niet een gelukkige indruk.

John Reynolds is me enorm meegevallen. De eerste week sprak hij erg ongeinteresseerd over “Gedanken”, een eigen taalexperiment, waarop hij zelf is uitgekeken. Het is een experiment, waarvan mij de zin nooit helemaal duidelijk is geworden, ook nu nog niet. De tweede week heeft hij besteed aan een globale indruk van het werk van Dana Scott. Hoewel ik lang niet genoeg van lattice Theory afwist, om dit helemaal te kunnen volgen, dacht ik wel een indruk gekregen te hebben van de aard en pretentie van dit werk. Als ik een keer niets te doen heb, zal ik me er in verdiepen, hoewel het ten duidelijkste niet “my cup of tea” is. Daarenboven waren zijn voordrachten de tweede week voortreffelijk voorbereid; hij heeft zich in mijn ogen aardig gerehabiliteerd.

Rudolf Bayer was voor mij practisch nieuw, ik had hem een keer ontmoet (bleek), maar was dat vergeten. Hij hield een serie voordrachten over “balanced trees”. Dit was helemaal niet diepzinnig, maar lijkt van groot practisch nut. Het was een genoegen om naar hem te luisteren, zowel omdat hij iets nieuws behandelde, als omdat ook hij het keurig presenteerde. Hij etaleerde misschien niet zoveel “visie”, maar rapporteerde keurig over een leuk en degelijk stuk werk. Het was erg verfrissend en ik van blij hem gehoord te hebben.

Ole-Johan Dahl uit Oslo hield als gast twee voordrachten, iedere keer was dit de zevende voordracht van de dag. Als hij nou een begaafd spreker was geweest, had hij deze handicap misschien overwonnen, nu ben ik bang dat hij het grootste gedeelte van zijn publiek niet bereikt heeft. Ik had hem hier al eens eerder over gehoord, het ging over recursieve co-routines. Het was wel een leuk verhaal, maar hij is moeilijk te volgen. Hij denkt op virtuoze manier in kleine gadgets, tot zijn verdediging moet gezegd worden, dat hij zijn uiterste best doet, er systeem in te brengen, Ik kon niet aan de indruk ontkomen, dat zijn omgeving pressie op hem uitoefent zijn verhaal “academically respectable” te presenteren, hoe inadequaat die plaatselijk heersende normen ook zijn mogen, kortom de bekende tragedie.

Zelf moest ik vier keer optreden, op de eerste vrijdag een uur en op de laatste drie dagen elk een uur. Het ogenblik was heel prettig, na de “morning refreshments”. Doordat sommige sprekers —vooral Brinch Hansen— mij nogal wat gras voor de voeten wegmaaiden, was ik in het begin erg bang niet genoeg stof te hebben, waardoor ik de eerste keer mij zelf veel te omstandig inleidde; ik was bovendien erg zenuwachtig. Later bleek, dat ik een heleboel moest overslaan, dat ik ruimschoots genoeg stof had voorbereid; ik was toen ook veel minder zenuwachtig. De tweede keer ging goed, de derde door de slechte nacht ervoor veel minder, de laatste keer ging dacht ik heel goed. De titel van mijn manuscript was “Hierarchical Ordering of Sequential Processes”, Hoare heeft gevraagd of hij het mocht opnemen in de publicatie van de geschriften ter gelegenheid van het Symposium on Operating System Techniques, dat begin september in Belfast gehouden wordt, Bauer vroeg of hij het mocht publiceren in Acta Informatica. (Dat laatste verzoek heeft minder te betekenen: Acta Informatica is een nieuw tijdschrift, dat nog op zoek is naar een gezicht.)

Laat mij nu proberen mijn totaal indruk van de Summer School samen te vatten. Als ik een enkel woord zoek, dat de stemming zo veel mogelijk dekt, dan kom ik op het woord “consolidatie”: dat geldt voor Reynolds (Scott) ten aanzien van grondslagen, dat geldt voor Hoare ten aanzien van elementen van programmeertalen, dat geldt voor Wirth ten aanzien van implementatie, ten aanzien van Brinch Hansen ten aanzien van operating systems, ten aanzien van mijn bijdrage ten aanzien van parallel programmeren, ten aanzien van Bayer met betrekking tot information retrieval, alleen Perlis valt daar een beetje buiten. Ik heb het gevoel, dat dit naar voren komen van de term “consolidatie” inderdaad direct verband houdt met de status van het tot wasdom komende vak en niet alleen een gevolg is van mijn persoonlijke stemming van dit ogenblik. Het feit dat de titel van deze Summer School o.a. “Fundamental Concepts of Programming” bevatte, is hier misschien niet vreemd aan, anderzijds is deze titelkeuze natuurlijk ook wel tekenend. Tekenend is ook, dat Fortran, Cobol, PL1 en Algol 68 nauwelijks ter sprake zijn geweest!

Persoonlijk heeft mij nog iets anders getroffen, misschien omdat ik na Perlis de oudste spreker was. Onder vakgenoten van de tweede generatie was een zekere wrok bespeurbaar jegens “the inner circle”, die het vak heeft afgeroomd (en naam heeft gemaakt!) toen het vak nog makkelijk en door zijn nieuwheid opwindend was. Zij vinden het erg moeilijk om “gevestigd” te worden. Dit geldt niet alleen voor de jongens die aan de Amerikaanse carrieredruk hebben blootgestaan, ik merkte dit ook bij onbesmette Europeanen. Jonge Duitse collegae hadden hier het minste last van: de opblazing van het curricum informatica vult hun hele dag en nog meer, ze hebben geen tijd om zich zorgen te maken over hun positie, ze werken zich gewoon kapot.

2 augustus 1971 | Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 08-Jan-2012

EWD317

On a methodology of design.

On an occasion like this it is very tempting to look backwards, to play the modern historian, to give a survey of what has happened over the last 25 years and to interpret this history in terms of trends and the like. This is so tempting that I shall try to resist the temptation. Instead, I would like to pose a question and to speculate about its answer. The question is roughly "Can we expect a methodology of design to emerge in, say, the next ten years?"

Let me first explain why I pose this question in my capacity as a programmer. There is a very primitive conception of the programmer's task, in which the programs produced by him are regarded as his final product. It is that conception which has led to the erroneous idea that a programmer's productivity can be measured meaningfully in terms of number of lines of code produced per month, a yardstick which when accepted, is guaranteed to promote the production of insipid code. A sounder attitude regards as the programmer's final product the class of computations that may be evoked by his program: the quality of his program will depend among many other things on the effectiveness with which these computations will establish their desired net effect. In this point of view a programmer designs a class of computations, a class of happenings in time and the program itself then emerges as a kind of generic description of these happenings, as the mechanism that evokes them. I regard programming as one of the more creative branches of applied mathematics and the view of a program as an abstract mechanism makes it perfectly clear that designing will play an essential role in the activity of programming. Conversely, the view of a program as an abstract mechanism suggests us that a good understanding of the programming activity will teach us something relevant about the design process in general. In actual fact this hope is one of the major reasons for my being interested in the task of programming for digital automata, digital automata who confront us with a unique combination of basic simplicity and ultimate sophistication. On the one hand programming is very, very simple; on the other hand processing units are now so fast and stores are now so huge that what can be built on top of this simple basis has outgrown its original level of triviality by several orders of magnitude. And it is this fascinating contrast that seems to make programming the proving ground par excellence for anyone interested in the design process of non-trivial mechanisms.

It is this combination of basic simplicity and ultimate sophistication which presents the programming task as a unique and rather formidable intellectual challenge, I consider it as a great gain that by now scope and size of that challenge have been recognized. Looking backwards we can only regret that in the past the difficulty of the programming task has been so grossly underestimated and that apparently we first needed the so-called "software failure" to drive home the message that in any non-trivial programming task it tends to be very difficult to keep one's construction intellectually manageable.

As soon as programming emerges as a battle against unmastered complexity, it is quite natural that one turns to that mental discipline whose main purpose has been since centuries to apply effective structuring to otherwise unmastered complexity. That mental discipline is more or less familiar to all of us, it is called Mathematics. If we take the existence of the impressive body of Mathematics as the experimental evidence for the opinion that for the human mind the mathematical method is indeed the most effective way to come to grips with complexity, we have no choice any longer: we should reshape our field of programming in such a way that the mathematician's methods become equally applicable to our programming problems, for there are no other means. It is my personal hope and expectation that in the years to come programming will become more and more an activity of mathematical nature. I am tempted to add that a development in that direction can already be observed, but I refrain from doing so: such a statement has too much the flavour of wishful thinking and besides that, such a statement could easily be an overestimation of the relative importance of the rather limited part of the field that lies within my mental horizon.

I have used vague terms like "the mathematician's method" and "an activity of mathematical nature"; I did so on purpose and let me try to explain why.

In one meaning of the word we identify mathematics with the body of mathematical knowledge, with the subject matter dealt with in mathematical theses, articles appearing in mathematical journals etc. I am not ashamed of admitting that most of it never passes my eyes; I also have a feeling that most of it —although of course one never knows— is hardly of any relevance for the programming task. If we identify Mathematics with the subject matter with which mathematicians have occupied themselves over the last centuries, it is indeed hard to see how mathematics could be highly relevant to the art of programming. In view of the programming problems facing us now, we can only regretfully observe that preceding generations of mathematicians have neglected a now important field. There is of course no point in blaming our fathers and grandfathers for this neglect. In their time, prior to the advent of the actual computing equipment, there was very little incentive: for lack of machines programming was no problem.

In a second meaning of the word, we identify Mathematics with a human activity, with patterns of reasoning, with methods of exploiting our powers of abstraction, with traditions of mixing rigour with vagueness, with ways of finding solutions. It is in this second meaning that I judge mathematics as highly relevant for the programming task.

It is perhaps worth noting that, at least at present, the second interpretation of mathematics does not seem to be the predominant one at the Universities. In the academic curricula the fruits of research are transmitted very explicitly, how one does do research, however, is taught only very implicitly, at most as a kind of by-product. We teach solutions, we teach hardly how to solve. At first sight this is amazing, taking into account that one of the assumptions underlying the University is that we can educate researchers! But there are explanations.

One observation is that many mathematicians of the current generation —in Euler's time it may have been different— seem to worry very little about problems of methodology, stronger they resist it and are shocked by the mere suggestion that, say, a methodology of mathematical invention could exist. Although we profess to be yearning for knowledge, insight and understanding, we are fascinated by the unknown and many a creative mathematician is fascinated by his own inventive ability thanks to the fact that he does not know how he invents. He enjoys his share in the spark of genius, untarnished by any understanding of the inventive process. We just like mysteries.

Secondly, with the growth of mathematical literature, particularly the publications of the type "Lemma, Proof, Lemma, Proof etc." mathematics has very much acquired the image of a "hard" science. It is regarded by many as the prototype of a "hard" science. But the result is that the mathematician tends to feel himself superior, that he looks disdainfully down upon all the "soft" sciences surrounding him. As a result a serious research effort into discovery and development of a methodology of mathematical invention would have a hard fight for academic respectability. And we all know that the pressures for academic respectability are very strong. It takes a respectable scientist, supported by fame, to embark upon it. Polya did it with his "Mathematics and the Art of Plausible Reasoning" and I admire his courage.

The final reason why we teach so little about problem solving, however, is that we knew so little about it, that we did not know how to do it. But I honestly believe that in the last fifteen years the scenery has changed. Polya has written the book I mentioned, Koestler has written a book of 600 pages called "The Act of Creation", Simon delivers at the IFIP Congress 1971 a talk on "The Theory of Problem Solving", just to mention a few examples. And there is a fair chance that this development will influence our teaching of mathematics. I think it will.

After this digression we return to our original question, can we expect a methodology of design to emerge? In designing one designs a "thing" that does "something". Over the last decades the most complicated things designed to do something have been programs; on account of their abstract nature we can regard programs as the "purest" mechanisms we can think of and if we can find some sort of question to the specific question "What about a programming methodology?", that answer seems relevant with respect to our original question.

It is my impression that there is a point in discussing programming methodology separate from problem solving as it is treated usually. Most of the literature about problem solving that I have seen deals with how to hit an unexpected but simple solution —simple of course once you have found it. In the case of programming this simplicity of the final solution is very often an illusion: programs, even the best programs we can think of for a given task, are often essentially very large and complicated. And by structure they are more akin to complete mathematical theories than to an ingenious solution to some sort of combinatorial puzzle. In other words, programming tasks seem to be of a different size.

From a programming methodology we require two main things. It should assist us in making better programs —i.e. we have desires regarding the final product— it should also assist us in the process of composition of the design —i.e. even if we have established what kind of programs we should like to design, we would like to discover ways leading to such a design. As it is hard to talk about strategies that might assist you in reaching your goal without having a clear picture of the goal itself, we shall deal with the first question first: what kind of programs should we like to make? If we talk about "better programs", what standards do we apply in judging their quality?

I have raised this question urgently and repeatedly in the first half of the sixties but at that time it turned out to be impossible to reach even the illusion of a consensus of opinion and the question was discarded by the attitude that it was all a matter of taste. The common experience of the next five years has certainly changed the situation. This common experience with large and vital programs was very often disastrously bad, and as a result of this sobering experience more and more people agree that requirement number one is not only that a program should be correct, but that its correctness can be established beyond reasonable doubts. An analysis of the possible ways for increasing the confidence level of programs has shown that for that purpose, program testing must be regarded as insufficient: program testing can be used very effectively to show the presence of bugs, but never to show their absence. Proving program correctness remained as the only sufficiently powerful alternative. And here I don't necessarily mean "formal proofs": I regard axiomatics as the accountancy of mathematics, or to use another metaphor: a formal treatment relates to my power of understanding as a legal document to my sense of justice.

The concern about correctness proofs had an immediate consequence. If proofs get longer and longer they lose their convincing power very, very quickly. It also emerged that the length of a correctness proof could depend critically upon the structure of the program concerned and with this observation a legitimate objective of program structuring emerged, viz. to shorten the length of the proofs required to establish the confidence in the program's correctness. Such considerations gave rise to a computing science folklore for which I am partly responsible; it centers around key-words such as "hierarchical design" and "levels of abstraction".

The programs should be "correct", but that is certainly not the whole story. Correctness proofs belong to "hard" science —and the more formal the proofs, the harder the science. Considerations about the relation between program structure and proof length are already at the outskirts of hard science. Softer still is the equally vital requirement that the program, the mechanism in general, be adequate, that it be a sufficiently realistic implementation of the model we have in mind. Let me explain this with a simple example. In ALGOL 60 the integer variable is a key concept: whenever it is manipulated it stands for an integer value, but in understanding a program, you don't care about its specific value, you have abstracted from it. Caring about its actual value is something you leave to the arithmetic unit, you yourself understand the program in terms of variables and relations between their values, whatever these values may be. In order not to complicate matters we restrict ourselves to applications where integer values remain quite naturally within the range that might be imposed by the implementation. Suppose now that our machine has a very funny adder, funny in the sense that each integer addition takes one microsecond except when the sum formed happens to be a prime multiple of 7, in which case the addition takes a full millisecond. How do you program for a machine like that? You might prefer to ignore this awkward property of the adder, but if you do so I can change the machine, slowing down the exceptional additions by another factor of thousand, and if necessary I do so repeatedly. Comes the moment that you can no longer afford to ignore this awkward property: by that time you feel obliged to organize your computations in such a way that the exceptional additions are avoided as much as possible. Then you are in trouble, for a vital abstraction, viz. that of an integer variable that stands for an integer value but you don't care which, is denied to you. And when a vital abstraction is denied to a user, I call the implementation inadequate.

The requirement of adequacy has a direct bearing on our hierarchical designs, more precisely on the number of levels we can expect to be distinguishable in such a design. Mind you, I am all in favour of hierarchical systems, we have hierarchical systems all around us. We understand a country in terms of towns, towns in terms of streets, streets in terms of buildings, buildings in terms of floors and walls, floors and walls in terms of bricks, bricks in terms of molecules, molecules in terms of atoms, atoms in terms of electrons and nuclei, nuclei in terms of what-have-you etc. It is a pattern you find all over the complete spectrum ranging from science to children's behaviour. At each next level, however, we describe phenomena of a next order of magnitude. In the example given it is a spatial order of magnitude, in the case of mechanisms where we want to understand what happens, we find ourselves faced with happenings to be understood in different grains of time. It seems characteristic of an adequate design that when we go from one level to the next, the appropriate grain of time will increase by an order of magnitude. If this impression is correct, our adequacy requirement imposes an upper bound on the number of levels admissible in our hierarchy, even if we start at the bottom at nanosecond level. Then we must conclude that, although essential, hierarchical levelling cannot be the only pattern according to which "Divide and Rule" is to be applied.

Now the design process itself. Many of its aspects can better be treated by greater experts in the field than myself; let me confine myself to what I have found lacking in the literature. On the one hand you find authors writing about problem solving: they stress psychological conditioning in order to hit the unexpected solution and search strategies. Their descriptions of the inventive process seem honest, their guidelines seem relevant, but they confine themselves to small size problems. On the other hand I have met people trying to organize large scale design projects. They were mostly Americans and talked with the self-assurance that we tend to connect with competence. I am perfectly willing to admit that once or twice I have been taken in by their eloquence, but never for long and I have come to the conclusion that the organization expert, although potentially useful, will not provide the final answer. A few things have struck me very forcibly. Firstly they persist in thinking in exactly two dimensions —this must have something to do with the two-dimensional paper on which they draw their organization charts. Secondly, they are obsessed by reducing the elapse time; this gives them the opportunity to introduce their dear tools such as PERT diagrams, base-lines etc. but I am much more interested in the designs we don't know how to achieve even if we are not in such a great hurry. Thirdly, they have such preset notions about documentation standards and the holy rules of the game —such as design reviews— that the whole design efforts loses the ring of reality and degenerates into a complicated parlour game. But the fourth thing is probably the worst: apparently they do not know the essential difference between "vague" and "abstract" where it is the function of abstraction to create a level of discourse where one can then be absolutely precise!

Let me now give you what I regard as my expectations. I leave it to you to decide whether you prefer to regard them as my hopes.

Our insight in the effectiveness of patterns of reasoning when applied to the task of understanding why mechanisms work correctly and adequately, has been growing considerably in the recent past and I expect it to grow still further.

Our insight in the design process will also increase. In particular I expect that more recognition will be given to the circumstance that designing something large and sophisticated takes a long time. As a result we must take the intermediate stages of the design into consideration and must be clear about their status in relation to each other and to the complete design. I expect a clearer insight in the abstractions involved in postponing a commitment.

From a better understanding of the relation between the final design and its intermediate stages I expect a body of knowledge that will enable us to judge the adequacy of descriptive tools such as programming languages.

In the course of the design process we are envisaging a final product: how well it behaves will ultimately only be known by the time the design is completed and the mechanism is actually used. By its very nature the design process makes heavy demands on our predictive powers. In connection with that I expect two things to happen. On the one hand our predictive techniques will be refined: at present, for instance, the outcome of simulation studies tends to be the source of heated arguments and it appears that we can simulate but lack the proper discipline that tells us what weight to attach to these simulations. Refinement of predictive techniques is one thing, the other thing I expect is that we shall learn how to reduce the need for them. In the design process it is not unusual that some sort of performance measure is dependent in a complicated and only partially known way on a design parameter whose value has to be chosen. There are two usual approaches to this problem and they seem to be equally disastrous. One of them is to give a group the duty to discover the best value of the parameter. As they don't know how to do this, any answer they produce will fail to be convincing and as a rule this approach leads to heated arguments and an overall paralysis of the design process. The other approach leaves the parameter free, so that the user can set it, suited to his own needs. Here the designer has shirked his responsibilities and leaves to the user that part of his task that he could not do himself: this second approach is disastrous because often the user is equally unable to fix the parameter in a sensible way. Both approaches being equally unattractive I expect the competent designer to become more alert when the problem of the parameter with unknown optimum value presents itself. The most efficient way to solve a problem is still to run away from it if you can, and one can try to restructure a design in such a way that the parameter in question loses its significance. In individual applications the performance might be less than optimal but this can be easily outweighed by greater adequacy over a wider range of applications and the easier justification of the remaining decisions. This is an example of the impact of the requirement of "designability" upon the final product.

This was a very rough sketch of a few of my expectations of an emerging methodology of design. I am not going to refine in this talk the picture any further for part of my expectation is that further refinement will require the next ten years. But by that time I expect a body of teachable knowledge that can be justly called "a methodology of design". Other authors are less modest in their expectation: Herbert A. Simon argues in his little booklet "The Sciences of the Artificial", which I can recommend warmly, that what he dares to call "a science of design" is already emerging. He may very well be right; personally I feel that I lack the wide experience needed to judge his prophecies.

I would like to end with a final remark in order not to raise false hopes. The remark is that a methodology is very fine but in isolation empty. We expect a true methodology of design to be relevant for a wide class of very different design activities. The counterpart of its generality is by necessity that it can only have a moderate influence on each specific design activity, i.e. we must expect each specific design activity to be heavily influenced by the peculiarities of the problem to be solved. And that is where knowledge about and deep understanding of the specific problem enters the picture. Yet a methodology, although absolutely insufficient in itself, may be of great value. It should give as the delimitation of our human abilities, it could very well result in a modest list of "don't" rules that we must obey and can only transgress at our own peril.

transcribed by Jose Alejandro Ruiz Delgado
revised Sun, 31 Aug 2008

EWD319

A class of allocation strategies inducing bounded delays only.

by Edsger W.Dijkstra

We consider a finite set of persons, say numbered from 1 through M, whose never ending life consists of an alternation of eating and thinking, i.e. (in the first instance) they all behave according to the program

cycle  | begin  | eat; think
| end. |

The persons are living in parallel and their common accomodations are such that not all combinations of simultaneous eaters are permitted. As a result: when a person has finished thinking, some inspection has to take place in order to decide whether he can (and shall) be granted access to the table or not. Similarly, when a person leaves the table, some inspection has to take place in order to discover whether on account of the changed occupancy of the table one or more hungry persons could (and should) be admitted to the table. This situation is reflected by writing their program

cycle 
begin 
ENTRY;
eat;
EXIT;
think

| end |

with the understanding that
1)     all inspection processes “ENTRY” and “EXIT” take only a finite period of time and exclude each other in time. (As a result of the postulated mutual exclusion of the inspections “ENTRY” and “EXIT”, a “local delay” of person i, wanting to invoke such an inspection, may be needed. We postulate that such a “local delay” will only last a finite period of time —the requests for these inspections could be dealt with on the basis of “first come, first served”— and we shall not mention these local delays any further, because they are now irrelevant for the remainder of our considerations.)
2)     as a result of such an inspection the person invoking it may be put to sleep (i.e. prevented, for the time being, from proceeding with his life as prescribed by the program).
3)     as a result of such an inspection, one or more sleeping persons may be woken up (i.e. induced to proceed with their life as described by the program).

We restrict ourselves to such exclusion rules for simultaneous eaters
that

condition 1: | if V is a permissible set of simultaneous eaters, so is any subset of V
condition 2: | each person occurs in at least one permissible set of simultaneous eaters. (Note: if a person occurs in exactly one permissible set of simultaneous eaters, this set contains —on account of condition 1— only himself and no one else.)

From condition 1 it follows that there is no restriction on the set of simultaneous thinkers; as a result the inspection EXIT will never have the consequence that the person invoking it will be put to sleep. As a result, persons can only be sleeping on account of having invoked the inspection ENTRY and the act of admitting person i to the table can be associated with the waking up of person i. (A little bit more precise: if during the inspection ENTRY as invoked by person i the decision to admit him to the table is not taken, he is put to sleep, otherwise he is allowed to proceed. If in any other inspection the decision to admit person i to the table is taken (person i must be sleeping and) person i will be woken up.)

Furthermore we restrict ourselves to the case that

condition 3:
for each person the action “eat” will take a finite period of
time (larger than some positive lower bound and smaller than
some finite upper bound); this in contrast to the action “think”
that may take an infinite period of time.

In the simplest strategy no inspection will leave a person sleeping whose admittance to the table is allowed as far as the occupancy of the table is concerned. Alas, such a strategy may have the so-called “danger of individual starvation”, i.e. although all individual eating actions take only a finite period of time, a person may be kept hungry for the rest of his days. (The classical configuration showing this phenomenon is the Problem of the Dining Quintuple. Here five places are arranged cyclically around a round table and each of five persons has his own place at the table. The restriction is that no two neighbours may be eating simultaneously. The rule will then be that every person is admitted to the table as soon as he is hungry and none of his two neighbours is eating. In this particular example this rule leaves no choice, i.e. when I leave the table the decisions whether my lefthand neighbour and my righthand neighbour have to be admitted to the table are independent of each other. In this example my two neighbours can starve me to death, viz. when my eating lefthand neighbour never leaves the table before my righthand neighbour is eating and vice versa. If the remaining two persons remain thinking, access to the table will never be denied to my neighbours and with me hungry the process can continue for ever.) The moral of the story is that if we are looking for strategies without the danger of individual starvation, we must in general be willing to consider allocation strategies in which hungry persons will be denied access to the table in spite of the circumstance that the occupancy of the table is such that they could be admitted to the table without causing violation of the given simultaneity restrictions. Our interest in strategies without the danger of individual starvation was roused by the sobering experience that quite a few intuitive efforts to exorcize this danger led to algorithms that turned out to be quite ineffective because they could lead to deadlock situations. The remaining part of this paper deals with a general characterization of strategies that do not contain the danger of individual starvation. We shall restrict ourselves to strategies where the decision to admit persons to the table will be taken for one person at a time; from our analysis it will follow that then our characterization can be given independent of the specific simultaneity restrictions (provided of course they satisfy our stated conditions 1 and 2).

We start by proving a theorem, in which we consider the following (possible) properties of a strategy.

property A: | the existence of at least one sleeping person implies at least one person who is eating or leaving the table
property B: | for any person i it can be guaranteed that during a period of his hungryness the decision to admit someone else to the table will not be taken more than Ni times, where Ni is a given, finite upper bound for person i.

Our theorem asserts that when conditions 1, 2 and 3 are fulfilled, properties A and B are the necessary and sufficient conditions for any strategy in order not to contain the danger of individual starvation.

The necessity of property A follows from the inadmissibility of the situation in which one or more persons are sleeping while all remaining ones (if any) are thinking. The thinking one may go on thinking for ever, as a result no new inspections will be evoked and the sleeping ones remain hungry for an infinite period of time.

We say that the danger of individual starvation is absent when the hungryness of any person will never last longer than a given, finite period of time. The minimum time taken by the act of eating imposes an upper bound on the personal frequency with which any given person can be admitted to the table; the total number of persons is M and therefore there is an upper bound on the total frequency with which someone is admitted to the table. Therefore the number of admissions during a period of hungryness of person i must always be less than a fixed, finite value: property B is necessary in the sense that a set of fixed, finite Ni’s exists such that it is satisfied.

Next we show that the conditions are sufficient. When person i becomes hungry —by invoking ENTRY— we have to show that his hungryness will only last a finite period of time. If in the course of that very inspection he is admitted to the table, it is true (for inspections take only a finite period of time), otherwise he goes to sleep. At the end of that inspection at least one person is eating (on account of property A)! From the fact that the action “eat” takes only a finite period of time, the persons now eating will have finished doing so and will have left the table within a finite period of time. From this and property A it follows that within a finite period of time a new person will have been admitted to the table. The assumption that person i remains hungry for ever implies that the lucky person must have been someone else, i.e. within a finite period of time the number of times it has been decided during hungryness of person i that someone else is admitted to the table is increased by one. Then the argument can be repeated and within a finite period of time the number of times someone else is admitted to the table would exceed Ni, contrary to our property B. Therefore person i will not remain hungry for ever.

Having established that properties A and B are necessary and sufficient for the absence of the danger of individual starvation, we are now in a position to characterize all strategies satisfying them with a priori given bounds Ni. For this purpose we associate with each hungry person a counter called “ac” (short for “allowance count”). Whenever person i becomes hungry, his ac is added to the set of ac’s with the initial value= Ni; whenever it is decided that a person is admitted to the table, his ac is taken away from the set of ac’s and all remaining ac’s are decreased by 1. Property B is guaranteed to hold when no ac becomes negative.

We call the set of ac’s “safe” when for all k ≥ 0 holds that at most k ac’s have a value < k. Note that also the empty set is safe. (Another formulation of safety is that it must be possible to order the ac’s, if present, in such a fashion that the first ac ≥ 0, the second ac ≥ 1, the third ac ≥ 2, etc.) Such a safe set has four important properties.

Property 1. No safe set contains a negative element (substitute k = 0 in the first definition).

Property 2. If removal of an element from the set is accompanied by a decrease by one of the remaining elements, each non-empty safe set contains at least one element that can be removed such that the remaining set is again safe: for this purpose it is sufficient —although one has often greater freedom— to choose one of the smallest values.

Property 3. Removal of any non-negative element from an unsafe set (again accompanied by a decrease by 1 of the remaining elements) will leave an unsafe set. If the set contains a negative element to start with, that one will not be removed and the remaining set remains unsafe; if the unsafe set contains no negative elements there must exist a positive k such that more than k elements have a value less than k: if the element removed is among them we are left with more than k–1 (≥ 0) elements with a value less than k–1, otherwise with even more than k elements with such a value.

Property 4. Addition of a new element will never make an unsafe set into a safe one.

Because the empty set is safe again, properties 3 and 4 tell us that an unsafe set of ac’s is bound to lead to negative ac’s before it is empty. Therefore safety of the set of ac’s must be maintained if we wish to guarantee property B. This imposes a lower bound on the initial values of the ac’s, i.e. the Ni. With M processes, at most M–1 will be sleeping (property A), if we impose

Ni ≥ M – 2

we can guarantee that, given a safe set of ac’s, the addition of a new ac will never lead to unsafety.

We can now characterize all strategies satisfying properties A and B. We call a person “admissible” if the followingthree conditions all hold
1)     he must be hungry
2)     his addition to the set V of eating persons would not cause violation of the simultaneity restrictions
3)     his removal from the set of hungry persons would leave a safe set of ac’s. We now characterize all strategies enjoying our (necessary and sufficient) properties A and B in terms of a general permission and a specific obligation.

Each inspection ENTRY or EXIT has the general permission to decide (zero or more times) to admit an admissible person to the table. However, inspections that would violate property A in the case of zero admissions have the specific obligation to admit at least one person to the table. They are the ENTRY while there are no eating persons and the EXIT in which a person is the last to leave the table while there are sleeping persons. In both cases conditions 1 and 2 and property 2 of safe sets guarantee the existence of at least one admissible person.

It is clear that any such strategy will satisfy properties A and B, it is also clear that any other strategy will have to be rejected: if the general permission is violated, an erroneous admission to the table takes place or we end up with either deadlock or violation of property B, if the specific obligation is not fulfilled property A is violated. In this sense we have characterized all strategies satisfying properties A and B.

Concluding Remarks.

For a very specific reason the result obtained seems significant. When one is making an operating system one is faced with “absolute requirements” (of a rather logical nature) on the one hand and “desires” (not necessarily all compatible with each other) on the other. In the early design phase of the THE Multiprogramming System we had the hope that all allocation strategies could be factored in the sense that first we could produce the code that would ensure non-violation of the absolute requirements, in which then all sorts of strategic routines could be plugged in, the idea being that a change of strategic routines could influence the desirability of the systems behaviour but could never lead to violation of the absolute requirements. In the later design stages we have not been able to reach that goal: we turned up with allocation strategies for which we could prove that the absolute requirements would never be violated, but each new proposed strategy required a new proof of this fact. The origin of this failure was our unability at that time to give a constructive characterization of all possible strategies that were guaranteed to meet our absolute requirements. This paper shows that —at least in the case of the chosen absolute requirements— such a characterization can be given in terms of permissions and obligations and in such a way that it has been proved that the obligation can always be fulfilled. The question under which other circumstances such characterizations can be given is now open for investigation.

Acknowledgements.

The author wishes to express his great indebtness to A.Martin and W.H.J. Feijen, for it is due to their persistence, in a common effort to clear up our thinking about starvation, that I was guided towards the approach described in this paper.

transcribed by Bart Vreugdenhil
revised 30-Nov-2011

EWD325

Poging tot plaatsbepaling van de Informatica.

Het doel van dit geschrift is in eerste instantie om voor mijzelf tot klaarheid te komen ten aanzien van de wetenschappelijke positie en pretentie van de Informatica —hoewel natuurlijk een ieder, die mijn conclusies delen wil, van harte welkom is—, omdat ik deze klaarheid als noodzakelijk ervaar, voordat ik zinvol over bv. een curriculum kan denken. Allerlei zakelijke en politieke overwegingen —aan de THE gegroeide situatie, verwachte kwaliteit van studenten, etc.— wil ik pas in tweede instantie in de beschouwing betrekken en vallen dan ook buiten het bestek van dit geschrift.

“A computer is a many-sided thing” en op grond van deze onontkoombare observatie komen geregeld voorstellen naar voren voor wat ik “een cocktailopleiding” zou willen noemen: een mengsel van bestaande ingredienten (electrotechniek, wiskunde, economie, organisatieleer, etc., etc.), waarvan men hoopt, dat het smakelijk is en, mits in voldoende mate genuttigd, aanleiding zal geven tot de gewenste wetenschappelijke feeststemming. Voor mijn gevoel ontstaat een dergelijk voorstel altijd “faute de mieux”, dwz. doordat men voor de Informatica niet een specifiek eigen werkterrein met zijn eigen spelregels ontwaart, maw. doordat men niet het gevoel heeft, dat Informatica als een voldoend isoleerbare discipline bestaat. De bedoeling van dit geschrift is, om te onderzoeken in hoeverre een isoleerbare discipline, die ik dan gemakshalve “informatica” noem, onderscheidbaar is. Ter vermijding van misverstand, het gaat hier om isoleerbaarheid op grond van intrinsieke eigenschappen van diverse werkterreinen en niet om politieke isoleerbaarheid: ons gereedschap is dan ook niet de interdisciplinaire enquete, maar een zorgvuldige analyse.

Laat mij met een historisch overzichtje beginnen. Hoewel in het aanzwengelen van de programmeerbare rekenautomaat de wiskundige von Neumann een spectaculair aandeel heeft gehad, hoewel de eerste werkende —nou ja!— machine, waarin het programma in het geheugen opgeslagen was, de EDSAC, ontwikkeld is in the Mathematical Laboratory, hoewel in Nederland het Mathematisch Centrum snel volgde, waren de technische problemen om binnen de begrenzingen van budget en technologie een werkend apparaat te maken in de beginperiode allesoverheersend. (Dit wordt nog weerspiegeld in de toen gekozen naam van de professionele genootschappen zoals ACM, BCS en NRMG!) Van de technische wetenschappen, die hier in het geding geweest zijn, heeft de electronica in antwoord op de hem gestelde uitdagingen de stormachtigste ontwikkeling doorgemaakt en tevens de meest spectaculaire resultaten geboekt en de associatie van Computer (!) Science met electrotechniek vindt dan ook zijn wortels in die eerste periode.

De relatie met de wiskunde is natuurlijk ook heel oud —zeker als we door de logica gemakshalve bij de wiskunde onder te brengen, Turing in de weegschaal leggen— maar “dunner”. De numerieke wiskunde speelde in het gebruik een vrij vooraanstaande rol, omdat dit de voornaamste discipline was, die reeds over een arsenaal informatieverwerkende algorithmen beschikte; omgekeerd was de komst van de rekenautomaat, waarbij efficiencynormen zo anders lagen dan bij de tafelmachine, voor de numerieke wiskunde een enorme stimulans om naar nieuwe methoden te zoeken, een stimulans die, als ik goed ben ingelicht, dan ook tot een duidelijke opbloei van de numerieke wiskunde aanleiding heeft gegeven. Wanneer ik desondanks de relatie met de wiskunde veel “dunner” noem, dan is dat ten eerste omdat de rest van de wiskundige wereld (die nog steeds aarzelde of numerieke wiskunde een legitiem, een onecht of een aangenomen kind van de Regina Scientiarum was) door deze ontwikkeling niet zo beroerd werd, ten tweede omdat behoudens het motiveren van de behoefte aan snellere en grotere apparatuur de numerieke methoden zelf weinig invloed op machinestructuur gehad hebben.

In de volgende fase, die met de komst van de UNIVAC is ingezet, komt de rekenautomaat als commercieel serieproduct op de markt. Van dit moment af is de ontwikkeling zo stormachtig en zo veelzijdig, dat ik veel vluchtiger te werk moet gaan en elke hoop op volledigheid moet laten varen. Als ooit duidelijk wordt dat “A computer is a many-sided thing.” maar al te waar is, is het in dit stadium van de ontwikkeling.

Ten eerste ontwikkelt de computer zich tot een marktproduct, een ontwikkeling waarmee fabelachtige investeringen gemoeid zijn: terwijl deze ontwikkeling sommige fabrikanten opstuwt tot giganten, ervaren vele anderen het als een (te) moeilijk product, te moeilijk om te maken, te moeilijk om te verkopen of beide. Ik noem dit commerciele aspect, omdat het, direct of indirect, het denken van een heleboel mensen vaak ernstiger beinvloed heeft, dan zij lijken te beseffen. De hoge prijs van deze machines heeft in het begin van de zestiger jaren tot een bijzonder eenzijdige opvatting over het idee “efficiency” aanleiding gegeven en krachtige residuen van die eenzijdigheid vindt men nog steeds. De computer is ook een product, dat tot een heel speciale verkoopstechniek geleid heeft en zelfs de verkoopskreten hebben de neiging ons denken ernstig te beinvloeden. (Vele gebruikers en kringen, die een computer moeten uitzoeken, hebben oprecht het idee, dat “compatibiliteit” een heel groot goed is. Historisch gezien is het in elk geval een sales-gimmick en hoeveel mensen nemen de moeite om de potentiele vruchten van de compatibiliteit zorgvuldig af te wegen tegen de onmiskenbare lasten?)

Het is de periode van de opbloei van de administratieve toepassingen, die, hoewel “administreren” in allerlei opzichten een stuk ingewikkelder is dan wetenschappelijke toepassingen, zich in hoofdzaak buiten de universitaire gezichtskring voltrekt; sommigen zullen haasten hier aan toe te voegen “met alle gevolgen van dien”. Wanneer Euwe, zelf geen specialist op het gebied van rekenmachines, door een aantal Nederlandse economische hogescholen aangetrokken wordt, om de informatica te doceren zal hij zich beperken tot management aspecten, er van uitgaand, dat zijn studenten het eigenlijke werk aan lagere krachten kunnen overlaten. Van de opmars van de rekenautomaat in de administratieve wereld moet men in retrospectie opmerken, dat hij iets geforceerds gehad heeft: het gebruik heeft jaren lang in het teken gestaan van de vraag hoe men zich zo goed mogelijk met magnetische banden behelpt, ook in die gevallen waar dit duidelijk een ontoereikend medium was. Dan toch maar!

Het is ook de periode geweest —en we zijn tegenwoordig wel eens geneigd dit te vergeten— waarin machines behalve een orde van grootte sneller en groter een orde van grootte betrouwbaarder werden. Die grotere betrouwbaarheid heeft een enorme invloed gehad, omdat nu veel geraffineerdere methoden van machinegebruik mogelijk werden en het aanvankelijke niveau van trivialiteit ontstegen werd. De komst van hogere programmeertalen is hiervan het duidelijkste symptoom. Dit heeft in tweeerlei opzicht de wiskundige bemoeienis met rekenmachines versterkt. Met de komst van ALGOL 60, en speciaal het gebruik van BNF ter definitie van een syntaxis, werd het probleem van compilerbouw in een zodanige vorm gepresenteerd, dat althans gedeelten daarvan zich voor wiskundige behandeling leenden, terwijl dankzij hogere programmeertalen het programma zelf als wiskundig object dat bestudeerd zou kunnen worden, zich aandiende.

Met de komst van hogere programmeertalen hebben zich allerlei kringen van gebruikers ontwikkeld, waarvan vooral “the bubble chamber boys”, die dankzij de prijs van hun overige apparatuur met veel volume konden schreeuwen, zich aan allerlei universiteiten tot krachtige pressiegroepen ontwikkeld. Het feit, dat zij zo ongans veel rekentijd konden verstoken, wettigt natuurlijk de vraag of hun experimentele techniek niet voor enige herziening in aanmerking komt, maar deze vraag is niet erg populair.

Volledigheidshalve noem ik de toepassing van rekenmachines in instrumentatie en overige besturingsproblemen. Het is wederom de grotere betrouwbaarheid van de hardware, die dit mogelijk maakt. Op het denken van de computer scientist heeft deze ontwikkeling niet zo erg veel invloed gehad. Dit is gedeeltelijk te wijten aan het feit, dat het hier toepassingen van vaak kleinere machines betrof. De belangrijkste oorzaak is ongetwijfeld, dat mensen met “real time toepassingen” meer dan de meeste andere machinegebruikers aan het gebruik van machinecode hebben vastgehouden. Je hoort vaak de stringentheid van de real time verplichtingen als verklaring en rechtvaardiging van deze terughoudendheid om van hogere programmeertalen gebruik te maken. Ik geloof, dat het fairder is om de afwezigheid van gezonde synchronisatieprimitiva in allerlei hogere programmeertalen gezien moet worden als symptoom van relatief onbegrip van de hele synchronisatieopgave en dat het dit onbegrip is, dat in iedere speciale opgave maakt, dan men zo vaak weer naar een ad hoc oplossing zoekt.

Naast de bloei van de programmeertalen wordt het afgelopen decennium door twee ontwikkelingen gekarakteriseerd, LSI (Large Scale Integration) en de moeilijkheden bij de bouw van operating systems. LSI is in eerste instantie een fabricagetechniek voor circuitry, waarvan de belofte is, dat rekeneenheden vele malen goedkoper gemaakt zullen kunnen worden, dan nu het geval is. LSI is nu al vijf jaar bezig, deze belofte in te lassen en het gaat niet zo hard, als ons destijds is voorgespiegeld. Hiervoor zijn allerlei technische problemen verantwoordelijk (precisie bij de fabricagetechniek, warmteontwikkeling etc.); qualiteitscontrole wordt, alsof het al niet genoeg is, ook een levensgroot probleem. Als deze technische problemen eenmaal opgelost zijn, blijft er nog een aanzienlijk probleem over: hoe concipieren we een rekenproces met “distributed activity”? Het is weer een duidelijk gebied, waar concurrentie een ontwikkeling lijkt te forceren. De ontwikkeling van operating systems is ontstellend tegengevallen en dit heeft tot ten minste drie “lines of thought” aanleiding gegeven. Ten eerste, dat de bouw van iets ingewikkeld als een operating system een enorme intellectuele uitdaging inhoudt, en dat je inzicht in de veelzijdigheid van de probleemstelling voor dat je aan het operating system begint geleid moet hebben tot een grote mate van conceptuele klaarheid, zonder welke het project gedoemd is in de chaos te verzinken. Ten tweede, de opvatting dat operating systems qualitate qua zo ingewikkeld en in hun gedrag zo onvoorstelbaar moeten zijn, dat we hier “experimentele computer science” moeten bedrijven, dwz. van het gebeuren een model moeten maken en vervolgens, als in elke andere natuurwetenschap, door meting dit model moeten verifieren. Ten derde, dat, omdat we nu weten dat een echt moeilijk programma alleen maar gemaakt kan worden door een leger van een paar duizend programmeurs, de hoofdopgave van programmeren een kwestie van organisatie techniek is.

Ten leste moet ik een veranderende instelling tegenover programmafouten vermelden. Vijf jaar geleden was het niet ongebruikelijk om in vertrekken, waar geprogrammeerd werd, een klein wandbordje aan te treffen met de tekst (onder een sprekend plaatje) “This is a program bug; be kind to the little animal, it gives you job security.” Voor de relatie tussen software house en “gevangen klant” was dit inderdaad het geval: het software house maakte een product, dat goed genoeg was, opdat de klant er mee ging werken en afhankelijk van werd, anderzijds was het product van een zodanige kwaliteit, dat het product constant onderhoud vergde en dit onderhoud alleen door de oorspronkelijke leverancier gedaan kon worden. Maar het tij is aan het keren. Een van de oorzaken is ongetwijfeld het geaccumuleerde ongenoegen van aldus gevangen klanten. Een tweede oorzaak is te vinden in de weliswaar schuchtere, maar met veel succes bekroonde pogingen om correctheid van programma’s te bewijzen. Een derde oorzaak is een professioneel gevoel van “uneasiness”, nl. de overweging dat wanneer (en dit gebeurt!) systemen een steeds belangrijkere plaats in onze samenleving gaan innemen, er binnen afzienbare tijd natuurlijk eens een keer een ramp gebeurt (en er zijn mensen, die zeggen, dat dat al gebeurd is!), waarvan de oorzaak onder andere herleid kan worden tot een profane programmafout. Deze vrees ligt ten grondslag aan de bezorgdheid van bv. de BCS om te komen tot “professional rules of conduct”; bij een recent congres in Amerika zijn er stemmen opgegaan om de Amerikaanse overheid te bewegen geen software producten zonder correctheidsbewijs te accepteren. Hoopvol als deze geluiden enerzijds zijn, ze zijn ook beangstigend: het zou voor de zoveelste keer de aanleiding voor een geforceerde ontwikkeling kunnen zijn (compleet met alle vormen van “overselling”.)

Nou, dit is, waar we zowat staan. “A computer is a many-sided thing” en afhankelijk van de kant, waartegen we aankijken, kunnen we computer science beschouwen als

a)    een verlengstuk van de electrotechniek

b)    een verlengstuk van de numerieke wiskunde

c)    een verlengstuk van bedrijfskunde

d)    als een verlengstuk van instrumentatie

e)    als een verlengstuk van systems theory

f)    als een verlengstuk van de wiskunde.

g)    etc.

Het is duidelijk, dat de enige manier om met dit soort bespiegelingen iets te kunnen aanvangen het nader analyseren van de vage kreet “verlengstuk” zal zijn. Ik wil daarom proberen de aard van de interface tussen de informatica enerzijds en aangrenzende gebieden anderzijds iets nader te beschrijven. Het idee, dat hier achter ligt is dat de levensvatbaarheid van een “isoleerbare” discipline sterk beinvloed wordt door de mate van isoleerbaarheid, en, indien de isoleerbaarheid mogelijk is, ook door de noodzaak tot isolering, een noodzaak die zou kunnen ontstaan als de geestelijke disciplines aan beide zijden van de interface heel verschillend zijn. Andere criteria ten aanzien van levensvatbaarheid, die ik bedenken kan, hebben te maken met omvang: een in principe isoleerbaar vak kan “te klein”, in die zin, dat het heel gewoon is, dat iemand uit een aanverwant gebied “het er wel even bij doet”, het kan qua werkterrein te arm zijn. Hoe we al deze dingen precies zouden moeten wegen, weet natuurlijk geen kip, maar dat ontheft mij voor mijn gevoel niet van de plicht te proberen hier enig gevoel voor te ontwikkelen en te beschrijven.

Om te beginnen de interface tussen informatica en electrotechniek. Ik zie hier drie, voor mijn gevoel vrij duidelijk gescheiden aspecten. Ten eerste de historisch oudste, nl. als leverancier van de technologie, die de fabricage van computers mogelijk gemaakt heeft, een fabricage waardoor de problematiek van de informatica actueel is geworden. Deze interface, waarin de electrotechniek zich in de informatica doet gelden via de existentie van machines, is het medium voor een wederzijds zeer zwakke koppeling: in het overgrote gedeelte van de informatica is het volslagen irrelevant dat machines via hoofdzakelijk electronische technieken gerealiseerd worden, in dat gedeelte van de electrotechniek dat zich bezig houdt met de constructie van circuitry doet het er wederom heel weinig toe, waarvoor de te maken hardware uiteindelijk ingezet wordt.

Het tweede aspect van je interface tussen de electrotechniek en de informatica wordt gegeven door de omstandigheid dat ontwerp van een niet-triviaal stuk hardware, annex mogelijke automatisering van hetzij stadia van het productieproces, hetzij bewaking van correctheid, up to date houden van documentatie etc. een enerzijds zo complexe zaak is, terwijl men anderzijds het gevoeld heeft, dat veel van de (vaak discrete) informatie zich wel voor automatiesche verwerkingsprocedures zou lenen. Hierdoor wordt “het electronisch ontwerpen” mogelijkerwijs een vruchtbaar werkterrein voor de informaticus. We signaleren dit aspect van de interface, maar laten voorlopig de educatieve consequenties hiervan in het midden: men kan proberen in deze toepassingsmogelijkheid van de informatica te voorzien door “informatica” een basisvak (een basisbijvak) van de toekomstige electronisch ontwerper te laten zijn, dan wel stukken electrotechniek en leer van de automatisering als potentieel bijvak op te voeren voor de afstuderende informaticus, die aan ziet komen, dat hij zich op dit toepassingsgebied wil gaan inzetten.

Het derde aspect van de interface tussen de electrotechniek en de informatica wordt geleverd door de opgave van “functionele specificatie van een nieuw hardware ontwerp”. Zodra we veronderstellen, dat de functionele specificatie niet door commerciele overwegingen volledig gedicteerd worden, maar technische overwegingen ook een rol mogen spelen, dan krijg je bij deze specificatietaak heel duidelijk twee aspecten: de vraag van de informaticus “kan ik zo’n machine gebruiken?” en de vraag van de electrotechnicus “kan ik zo’n machine maken”. Weer is, door de bank genomen, de interactie zwak, in die zin, dat het grootste gedeelte van de informatici (althans op het ogenblik) niet met deze vraag tot functionele specificatie van een stuk hardware worden uitgenodigd (sterker: in een heleboel organisaties wordt dit denken zelfs helemaal niet aangemoedigd!), terwijl bij de ontwerper van circuitry de aard van zijn werk weinig door de functionele specificatie wordt beinvloed. Een en ander neemt natuurlijk niet weg dat voor een goed verdedigbaar ontwerp een goed samenspel tussen beide disciplines vereist is.

Wat heeft dit alles te maken met onderlinge isoleerbaarheid? Het eerste aspect, als dat het enige was, maakt een perfecte isoleerbaarheid mogelijk, de informaticus werkt in de wereld waarin de idealisering van de discretisering voltooid is, de electrotechnicus leeft in de wereld waarin met in zijn ogen wezenlijk analoge middelen deze discretisatie gesimuleerd moet worden. De andere twee aspecten van de interface hebben duidelijk een interdisciplinair karakter. Bij de vraag of we een dergelijk werkterrein liever bij (beoefenaren) van de ene, dan wel de andere discipline willen onderbrengen, moet je de vraag beantwoorden, welke aspecten van de asymmetrie je in het geding wilt brengen. Ik dacht, dat “relatieve beheersing van het eigen vak” hierin een belangrijke rol moest spelen in die zin, dat de grensactiviteit hoofdzakelijk ligge op het gebied van de man, die relatief zijn vak het slechtste beheerst: de ander kan zijn kant van het contract nl. zo duidelijk formuleren. In het geval van design automation ten bate van het electronisch ontwerpen zou ik me voor kunnen stellen, dat het soort informatietechnische problemen op betrekkelijk standaard manieren kan worden opgelost, terwijl de vraag “hoever komen we met onze automatisering?” a priori veel onduidelijker is. Van een project voor design automation voor het electronisch ontwerpen verwacht ik eerder baanbrekend werk van de electrotechnicus, dan van de informaticus. Mijn neiging zou daarom zijn, deze activiteit voornamelijk te zien als een electrotechnische aangelegenheid? waarin, als informatici er aan meewerken, de informatici niet de leidende rol zouden mogen hebben. Bij de taak van de functionele specificatie van een hardware machine zou het wel eens precies andersom kunnen liggen: de hardware man, die inmiddels zijn beperkingen zo goed kent, zou een gegeven ontwerp wel eens veel sneller op maakbaarheid kunnen taxeren, dan dat de software man het ontwerp op bruikbaarheid taxeren kan. In mijn neiging het hoofdaccent van de ontwerpverantwoordelijkheid zo mogelijk te leggen bij de relatief meest incompetente discipline (daar kan je je immers de hardste builen vallen!), zou ik bij het ontwerp van de functionele specificatie bij mijn huidige taxering van de relatieve competenties de hoofdverantwoordelijkheid bij de informatica-kant willen leggen. Technieken ter verantwoorde evaluatie van de bruikbaarheid van voorgestelde hardware configuraties is duidelijk een onderontwikkeld gebied van de informatica. Pas als de informatica die heeft en aan de electrotechnicus kunnen doceren, is machineontwerp van uit de kant van de informatica een delegeerbare activiteit.

Wij vervolgen onze beschouwingen en komen nu toe aan de interface tussen de informatica en de numerieke wiskunde. Na aanvankelijk als practisch enige leverancier van algorithmen gefungeerd te hebben, is in de latere jaren de rol van de numericus wat op de achtergrond geraakt. Een belangrijke bijdrage heeft de numerieke wiskunde daarna nog gehad door met redenen omkleed fatsoenlijkheidsnormen voor drijvende arithmetiek op te stellen. (Dat de numerici hierbij vaak roependen in de woestijn waren, kunnen we betreuren, ik beschouw hun bijdrage in dezen desalniettemin als “belangrijk” omdat ze, zij het op een gedetailleerd punt, een qualiteitscriterium hebben aangedragen, waaraan een machineontwerp getoetst kan worden.) Als machines, waarin een hoge mate van parallelle rekenactiviteit plaats kan vinden, reëel worden, zou gedurende een aantal jaren de interferentie tussen machinebouw en —gebruik enerzijds, en de numerieke analyse anderzijds heviger kunnen worden. Het is niet ondenkbaar dat weer de numerieke wiskunde de discipline is, die een tijd lang als voornaamste leverancier van (nu parallelle) algorithmen op zal treden; en het is evenzeer denkbaar, dat de numerieke wiskunde van zijn kant hier een grote stimulans zal ondervinden. Ik kan het niet goed bekijken: als we de ILIAC IV als mogelijk symptoom van deze ontwikkeling beschouwen, dan wijst dat stuk recente geschiedenis niet sterk in die richting, maar je kan nooit weten. Duidelijk is, dat er allerlei machinetoepassingen zijn, waarbij een goede kennis van de bestaande numerieke wiskunde een vereiste is. Wanneer ik de numerieke wiskunde niet als een “must” voor de informaticus taxeer, dan is dat ingegeven door de volgende overwegingen. Ten eerste heeft zich er een ruim en gevarieerd toepassingsgebied van rekenautomaten ontwikkeld, waar de simulatie van het continuum helemaal geen rol speelt, anderzijds is “the body of knowledge”, die zich onder de naam numerieke wiskunde heeft ontwikkeld, inmiddels zo omvangrijk (en hecht technisch verknoopt met een paar andere takken van de wiskunde), dat het absoluut irreeel is, om van elke informaticus te eisen, dat hij een all round numericus en passant er bij is. Ik neem op quantitatieve gronden aan, dat we ons er bij neer moeten leggen, als de doorsnee informaticus enig benul van de numerieke wiskunde heeft (genoeg om te weten, wanneer hij een numericus in de arm moet nemen), terwijl je omgekeerd hoopt dat de man, die echt moeilijk numeriek werk doet, voldoende benul van de informatica heeft, om doorgaans verantwoord machines te gebruiken (en, op zijn beurt, als de situatie zich voordoet, niet schroomt om een informaticus in de arm te nemen, als de organisatorische moeilijkheden hem bijvoorbeeld uit de hand lijken te lopen).

De interface tussen informatica en bedrijfskunde is een stuk ingewikkelder. Ik kan zeker vier raakvlakken bedenken. Het eerste raakvlak is betrekkelijk economisch en is het raakvlak met de computerindustrie, die de computer (hopelijk met winst) als product op de markt wil brengen; als men aan dit aspect veel gewicht toe wil kennen, zou men tot de stellingname kunnen komen, dat de “realistische” informaticus zich dan wel niet hoeft te beperken tot de bestaande apparatuur, maar bijvoorbeeld wel tot de “verkoopbare”... De drie andere raakvlakken betreffen meer de organisatieleer. Ten eerste fungeert elk gemaakt systeem als onderdeel van een grotere organisatie. Voor de wetenschappelijke gebruiker, die een programma voor zichzelf maakt omdat hij een differentiaalvergelijking opgelost zou willen hebben, is die “omvattende organisatie” niet zo groot en niet zo onoverzicbtelijk; voor hem althans. Het aantal dusdanige gebruikers is ontzettend groot en het is een gevarieerd stel, zo gevarieerd, dat je nauwelijks van de centrale informatica kunt verwachten, dat die een overzicht heeft van hoe het gebruik van automatische rekenapparatuur de wijze van werken in al die verschillende disciplines zal beinvloeden. Je kunt daarom alleen maar hopen, dat die gevarieerde gebruikers zelf, ieder voor zich, er langzamerhand achter komen, wat het fenomeen “computer” mogelijk voor hun eigen vakbeoefening te betekenen heeft. Zodra een computer een essentieel onderdeel gaat worden in een grotere organisatie —en dit mag een universitair rekencentrum zijn, dat “gerund” moet worden, het mag een stuk automatische informatieverwerking in een ziekenhuis zijn (voor mijn part inclusief patientenbewaking en bewaking van de apotheek!) of voorraadbeheer en planning van een fabriek— dan wordt de interactie tussen systeem en omvattende organisatie ontegenzeggelijk veel inniger. Ten tweede vertoond elk groot programma —en een operating system is hiervan misschien wel het duidelijkste voorbeeld— zelf de structuur van een organisatie (en wordt in overeenstemming daarmee dan ook vaak beschreven en begrepen in een terminologie, die aan de organisatieleer ontleend is). Ten derde is het maken van een groot programma een bezigheid, die zich in elk geval over een flinke periode uitstrekt, gedurende welke periode er heel vaak een aantal mensen bij betrokken zijn: kortom, het maken van programma’s heeft zelf duidelijk organisatorische aspecten. Gelukkig ligt in deze laatste twee gevallen de wijze van interactie tussen informatica en organisatieleer wat duidelijker, ik heb nl. sterk de indruk, dat er in dezen slechts sprake is, resp. hoort te zijn, van èèn-richtingverkeer. Dat een groot programma zelf een organisatie is, is voor de programmeur vanzelfsprekend, maar hij heeft daarbij weinig van de gevestigde organisatieleer te leren, die zich zelden of nooit kan veroorloven allerlei sociale randcondities niet in de beschouwing te betrekken en het resultaat lijkt te zijn, dat het omgekeerd voor de organisatiedeskundige interessanter is, om eens een groot operating system te bestuderen, dat hem confronteert met een complexe organisatie “in reincultuur”. Wat de organisatie van de programmeerarbeid betreft moeten we opmerken, dat de software afdelingen, die zijn opgezet volgens de geldende regels en normen van de organisatieleer, om het voorzichtig uit te drukken, niet zo erg succesvol zijn geweest; het klakkeloos uit andere productieprocessen overnemen van een aparte groep die verantwoordelijk is voor “quality control”, bv. heeft tot absurde en onmogelijke taakverdeling geleid. Ik geloof, dat we veilig stellen kunnen, dat het abstracte product “software” met al zijn interne logische verknopingen een heel ander product is dan wasmachinemotoren en dat de manier, waarop men het constructieproces van software moet organiseren meer bepaald dient te worden door de specifieke eigenschappen van software in het algemeen en het onderhavige product in het bijzonder, dan op zo anderssoortige omstandigheden gefundeerde standaard organisatorische opvattingen. Voor de software engineer beperkt de interactie zich in eerste instantie tot het feit, dat hij leren moet, dat hij zich in zijn latere leven geen inadequaat organisatiepatroon moet laten opdringen, de organisatiedeskundige zou er heel veel van kunnen leren, als hij er zich eens zorgvuldig in verdiepte, hoe een succesvol team een software project klaart; misschien dat hij dan het wezenlijke verschil tussen abstractheid en vaagheid leert apprecieren. Het samenspel tussen “systeem” en omvattende organisatie blijft een teer punt. Ik zou me kunnen voorstellen, dat men de vraag “Hoe beinvloede automatiseringsmogelijkheden een organisatie?” in zijn algemeenheid aan organisatiedeskundigen (wie en wat dat ook moge zijn) moet over laten, terwijl de omgekeerde vraag “Hoe kies, resp. dimensioneer ik een installatie, gegeven de omstandigheden, waaronder hij zal moeten werken?” —een vraag, waarmee bv. de directie van ons rekencentrum heel duidelijk mee geconfronteerd wordt— wel tot het terrein van de Informatica rekent.

Toen ik de instrumentatie opschreef, was ik in eerste instantie getempteerd om “de experimentele natuurkunde” op te schrijven, er van onder de indruk hoe in sommige universiteiten het rekenbedrijf geterroriseerd wordt door “the bubble chamber boys”, die zich als grootste klant de grootste zeggenschap in keuze aanmatigen, een keuze die louter en alleen bepaald wordt door het verlangen compatible te zijn met hun Amerikaanse vriendjes. Iedereen begrijpt, waar dat op uitmondt. Ik zou tegenover die physici willen opmerken, dat het feit dat zij zo ongans veel machinetijd verstoken —en voor het claimen van die tijd chanteren ze de maatschappij met de hoge prijs van hun overige apparatuur!— wel eens een indicatie zou kunnen zijn dat er aan hun experimenteertechniek iets schort. Wat betreft de overige “instrumentatie”, ik denk dan aan allerlei min-of-meer real time toepassingen, zoals het bewaken van processen en patienten, het verzamelen van stromen meetgegevens in een experimentele opstelling en wat onder de verzamelnaam “message switching” bekend staat (inclusief netwerken). Het lijkt mij buiten kijf, dat dit gebied tot de informatica gerekend moet worden: in alle gevallen, die ik hier bedacht heb, zijn de uitwendig opgelegde specificaties vrij goed formuleerbaar (medische kennis is echt niet nodig); en dat, omdat je nu veel sneller reageren kunt, andere indicaties medisch belangrijk kunnen worden, wel, dat is iets, dat je een medicus nu nog wel kunt uitleggen.

Systems theory heb ik er maar bij geschreven om der wille van de volledigheid. Ik moet hier bekennen, dat ik er niet zo heel veel van af weet. Ik sta er dan ook met gemengde gevoelens tegenover. Ik heb, ruwweg drie ervaringen. De eerste is al weer een hele tijd geleden: toen hield systems theory zich nadrukkelijk bezig met systemen, waarvan het gedrag door lineaire differentieelvergelijkingen (door wat anders!) beschreven werd; afgezien van enige stabiliteitsbespiegelingen heb ik er toen niet veel relevant uit kunnen halen. Het tweede contact was hoopgevender: dat was toen ik het verhaal van de “allowance counts” aan Hautus kon slijten en wat ik over het bijhouden van de geschiedenis bedacht had, in de besturingstheorie een gevestigde methode bleek te zijn. Dat is dan een ogenblik, waarin je een mogelijke kruisverbinding proeft. Mijn laatste contact was met een boek van drie Amerikanen van Oost-Europese origine (zoiets als “Mesarovic” et.al.) van Case Western Reserve University, waar sinds tien jaar een instituut voor systems study bestaat. Het boek gaat over hierarchische systemen, het meest opvallende is, dat in hun inleiding, waarin ze drie begrippen “hierarchie” willen uitleggen, deze drie begrippen niet erg duidelijk over het voetlicht komen. De rest van het boek lijkt een moeizaam wiskundig apparaat, waar weer allerlei lineariteitsveronderstellingen om de hoek komen kijken. Ik heb sterk de indruk, dat voordat dit relevant is, er nog wel een paar dingen moeten gebeuren: ten eerste mag er wiskundig nog wel wat verfraaid worden, ten tweede mogen er nog wel een paar Koestlers komen, om de quintessence er uit te distilleren.

De relatie met de rest van de wiskunde is natuurlijk iets, waarover we, uit hoofde van de positie, waarin we ons bevinden, iets explicieter kunnen en moeten zijn. (Omdat ik de numerieke wiskunde al heb aangestipt, laat ik die nu verder buiten beschouwing.)

Om te beginnen is er een heel duidelijke verbinding met wat hetzij “logica”, hetzij grondslagenonderzoek genoemd wordt. Je denkt hier in de eerste plaats aan Turing, Post etc.; enige bekendheid hiermee hoort m.i. ongetwijfeld tot gewenste geestelijke bagage van de informaticus: het is een respectabel stuk wiskunde en komt, zij het niet frequent, af en toe heel significant om de hoek kijken. (Ik denk aan het artikel van Floyd, waarin hij van een algemene klasse BNF-grammatica’s aantoont, dat de aan-of afwezigheid van de mogelijkheid tot syntactische dubbelzinnigheden niet decideerbaar is. Sindsdien is meer naar voren gekomen, dat de grammatica van een programmeertaal uit het oogpunt van “human engineering” nog wel aan heel wat stringentere eisen moet voldoen, waardoor de studie van dergelijke “pathologische” grammatica’s wel wat aan betekenis heeft ingeboet. Het zij zo, hier ligt desalnietemin voor mij een relevant stuk theorie.) De terugkoppeling vindt ook andersom plaats, nl. zodat wiskundigen zich gaan afvragen, welk gedeelte van hun “symbol manipulation” zij aan een automaat kunnen delegeren en met welke pretentie. Hier kom je direct tegen het grondslagenonderzoek aan, resp. de tak van dienst, die elders “artificial intelligence” genoemd wordt. Automath is duidelijk een symptoom van deze interactie. Het komt mij voor, dat in dit soort projecten de informatica hoofdzakelijk “toeleverende partij” is totdat het project heel groots wordt: dan kan het het karakter van “a highly unusual application” krijgen, met alle repercussies van dien. Het is het vermelden waard, dat dit soort machinegebonden projecten sinds de inventie van LISP niet erg veel nieuwe invloed op de informatica gehad heeft!

Het afgelopen decennium heeft sterk in het teken van de hogere programmeertaal gestaan. Men is begonnen met allerlei syntactische verkenningen en het daarvoor benodigde wiskundige apparaat (en naar mijn smaak: meer dan dat) is ontwikkeld. De volgende stap is geweest de poging om semantische definitie van programmeertalen te formaliseren; het werk van de Weense groep mag hier niet onvermeld blijven. Terwijl dit werk in principe als heel belangrijk getaxeerd moet worden, kunnen we alleen maar betreuren, dat deze ontwikkeling aan de formalisering van PL/I is opgehangen. Een andere tak van activiteit is ontsproten aan het werk van Dana Scott. Dit lijkt me conceptueel veel eleganter, mijn kennis van lattices is beslist onvoldoende om het allemaal naar waarde te kunnen schatten. Bij wat ze dan uiteindelijk bereikt hebben, heb ik een licht gevoel van teleurstelling helaas niet kunnen onderdrukken.

De bezorgdheid om “correctheid” treft mij als de jongste ontwikkeling. Er zijn hier twee hoofdstromingen: de ene betreft de ontwikkeling van formele bewijstechnieken, de andere betreft de programmastructurering, zodat de bewijsvoering vergemakkelijkt wordt. Hoewel ieder, die zich met dit soort werk bezighoudt, wel duidelijk in een van beide kampen pleegt te zitten, lijkt het me duidelijk, dat deze twee ontwikkelingen hand in hand horen te gaan. (En ook doen.)

Ik verwacht —maar dat heb ik al vaker gezegd— de belangrijkste interactie tussen de informatica en de rest van de wiskunde meer op het “quo modo” dan het “quod”. Als ik zie, hoeveel moeite ik met allerlei wiskundige teksten kan hebben, louter en alleen omdat ze zo slordig geschreven zijn en de spelregels, volgens welke zo gelezen moeten worden, zo vaag zijn —deze moeilijkheid mijnerzijds is natuurlijk een “déformation de métier”—, dan denk ik vaak, “ik wou, dat de auteur iets intensiever met de informatica geconfronteerd geweest was”; omgekeerd kan ik allerlei programmeursgeschriften tegenkomen, waarvan ik dan denk “ik wou, dat de man zich een beetje meer als wiskundige tegenover zijn problematiek opstelde”.

Ik wou het overzicht van het contact met de randgebieden hier eigenlijk maar bij laten en proberen of ik, geinspireerd door deze verkenningen, het voor de informatica specifieke werkterrein, de specifieke geestelijke discipline en de wetenschappelijke pretentie isoleren kan. Nogmaals: de vraag in hoeverre we op grond van de locale omstandigheden in een curriculum recht kunnen doen wedervaren aan dit beeld van de informatica, is een vraag, die ik slechts in tweede instantie —en niet in dit stuk!— wil bekijken.

Laat mij nu trachten het typisch eigene van de informatica te vinden. Ik wil hier vooropstellen dat ik denk aan de informatica in de omgeving van een technische hogeschool. In universitaire omgeving zou men nl. een minder constructieve opvatting van informatica kunnen huldigen en bv. het soort informaticus willen opleiden die vervolgens zijn sporen verdient in een team van medici etc., dat een studie maakt van de informatieverwerking door het menselijk oog en de daarachtergelegen hersenen. Hoe legitiem dergelijk onderzoek ook kan zijn, ik wilde de taakstelling van de informatica in het raam van een technische hogeschool niet daarnaar uitstrekken.

Dan focusseert de informatica zich voor mij op het beheerst ontwerpen van complexe mechanismen die in voorspelbare mate beantwoorden aan een zorgvuldig gekozen doel. En als je nou zegt “maar er worden toch veel meer “systemen”, “mechanismen” ontworpen, die aan een of ander doel moeten beantwoorden? Hoe kan je hier iets specifieks voor de informatica uit destilleren?”, dan zou ik het volgende willen antwoorden.

Het veld van de informatica is in dit opzicht iets aparts, omdat ik geen ander gebied weet, waarin de te ontwerpen mechanismen enerzijds zo ongelofelijk ingewikkeld kunnen zijn —dit is een onmiddellijk gevolg van de macht van tegenwoordige rekenapparatuur— terwijl anderzijds de praemissen, op grond waarvan het mechanisme zou moeten werken, zo simpel en expliciet bekend zijn, zodat volledige intellectuele beheersing, die niet alleen nodig is, ook mogelijk is. Het is de enorme spanwijdte tussen de eenvoud van de basis en de sophistication van het uiteindelijke product, dat voor mij het unieke kenmerk van de informatica is. Het is een onmiddellijk gevolg van de aanwezigheid van machinerie, die zo ongeveer een millioen stuurbare instructies per seconde uitvoert. En het is daarom, dat ik de taakstelling van de informatica zie als een intellectuele uitdaging zonder precedent in de geschiedenis van onze cultuur.

Hier komt nog een heel bijzonder facet bij: het is een werkterrein waarin, meer naar het mij voorkomt dan in allerlei andere disciplines, elke routineactiviteit “op de schopstoel zit”: zodra in de uitoefening van de informatica iets een duidelijke routineactiviteit begint te worden, bestaat er een goede kans, dat het geautomatiseerd wordt. Dit hebben we in het verleden al een paar keer gezien —de “codeur” bestaat eigenlijk nauwelijks meer, het is in elk geval geen baan met houvast— en de aard van het vak maakt, dat we dit in de toekomst ook nog wel eens mogen verwachten. De onbestendigheid van routinetaken is een van de facetten, die mij huiverig maakt om mensen van onvoldoende niveau in de informatica te trekken: de uitvlucht is dan altijd “je hebt mensen van allerlei niveau nodig”, maar in de informatica kon wel eens een vacuum ontstaan tussen de echte top en de echte onderlaag (van ik zou bijna zeggen “operateursniveau”).

Terug naar de intellectuele uitdaging, dat is een prettig houvast (vind ik tenminste). Het betekent, dat alle onmisbare kennis en vaardigheid om tegen deze uitdaging zo goed mogelijk opgewassen te zijn, een wezenlijk onderdeel van de informatica uitmaakt. Wat zijn die vaardigheden, wat is die kennis? Hier bemerk ik, dat ik me in een merkwaardige hoek gemanoeuvreerd heb in die zin, dat ik nu nauwelijks meer met kennis kan komen aandragen, waar ik zelf niet redelijk in thuis ben, noch met vaardigheden, die ik niet redelijk beheers. Staat een beetje gek!

Kennis van machines is essentieel, althans van hun functionele specificatie. Zo als ik me voortreffelijk een informaticus kan voorstellen, die niets van de electronica afweet, kan ik als ik een beetje mijn best doe, me ook wel een informaticus voorstellen, die eigenlijk nog nooit een machinecode gezien heeft. Ik zou dit niet toejuichen, maar voorstellen kan ik het me wel.

Ik zou het daarom niet toejuichen, omdat ik over bestaande machines nog niet zo enthousiast ben en de informaticus gaarne als gesprekspartner zag op zoek naar betere machines. Ik kan het vervolgens niet toejuichen, omdat de bestaande alternatieven (abstracte machines in de vorm van een programmeertaal) nu ook niet zo ideaal zijn en ik de informaticus desgewenst in staat zou willen achten een betere taal te ontwerpen en te implementeren. Functionele specificaties van bestaande machines —althans in grote lijnen— behoort kennelijk tot zijn geestelijke bagage. (Nou, dat is fijn, want we zullen moeite genoeg hebben om in de informatica genoeg relevante, doceerbare “kennis” onder te brengen.) Je kunt hier weer twee kanten uitgaan: ik kan me de informaticus voorstellen, die een groot aantal machines kent, liever heb ik de informaticus, die de gangbare aspecten van machines —met hun motivering, hun voors en hun tegens— kent.

Kennelijk is een zekere kennis van de logica en vertrouwdheid met bewijstechnieken een hoeksteen. Ook hier moet relevante, doceerbare kennis te vinden zijn.

Vertrouwdheid met automatiseringstechnieken —hier valt zeker onder het maken van vertalers, assemblers en dergelijk soort spul— is dacht ik ook een vereiste: de informaticus moet zijn eigen “tools of his trade” kunnen maken. Bootstrapping, hetzij op een machine, hetzij van een machine naar een ander, is ook zo’n artikel. Ik wil hiermee niet gezegd hebben, dat je nu zonder meer als informaticus specialist op het gebied van taalimplementatie moet zijn. Ik heb in Maryland een serie voordrachten van David Gries over compiler constructie bijgewoond, maar wat mij daarvan in hoofdzaak is bijgebleven is, dat de complicerende oorzaken heel vaak gezocht moeten worden in, hetzij een ongelukkig gekozen taal (en dat geldt dan niet alleen voor FORTRAN, we weten inmiddels dat ALGOL 60 een iets andere syntax zou kunnen hebben, waardoor het parsing problem een stuk makkelijker zou zijn geweest), hetzij een ingelukkige object machine. Wat dacht ik tot de gewenste bagage van een informaticus behoort is enige vertrouwdheid met de structuur van vertalers en daarbij —zonder dat is de kennis me niets waard— een inzicht in hoe de vertalertaak van de structuur van source en object language afhangt, opdat hij, als hij de keuze heeft, de vertalertaak minimaliseert. (Software is a necessary evil!) Je kunt ook je op het standpunt stellen, dat je studenten zoveel van vertalen van gangbare talen voor gangbare machines moeten weten, dat ze pasklaar in een industrieel vertalerteam kunnen worden ingeschakeld: dat beschouw ik dan als hoger beroepsonderwijs, die kennis kan ik niet tot de kern van de informatica rekenen. In de bovengeschetste critische (bah, modewoord) zin wel, want hij moet desgewenst zijn eigen gereedschap kunnen maken. Op het hier geschetste gebied is ongetwijfeld relevante en doceerbare kennis te selecteren, ik denk hierbij aan Niklaus Wirth die dit aspect van de informatica voor mijn gevoel als geen ander beheerst, speciaal wat betreft de implementatiekant. Op deze kennis kan voor een gedeelte het vermogen berusten om een hardware ontwerp op zijn bruikbaarheid te toetsen, om een voorgestelde taal op zijn implementeerbaarheid te toetsen. (Maar hier heb ik het al over een vermogen, niet meer over kennis.)

Een volgend man, die ik nu onmiddellijk noemen moet is Hoare. Wat wij aan hem danken is de signalering dat de intellectuele beheersbaarheid van programma’s (en hun implementeerbaarheid: Hoare claimt, dat de twee vaak hand in hand gaan) critisch kan afhangen van bepaalde linguistische constructies bv. de preciese structuur van het parametermechanisme. Als je een taal ontwerpt, moet de taal je de combinatorische vrijheden geven die je denkt nodig te hebben: als het jasje te wijd is, en je ook een heleboel andere dingen kunt, kan je in het schip van de onbeheersbaarheid terechtkomen. De alertheid, dat enerzijds elke informaticus de hem gestelde taak moet generaliseren, maar dat hij anderzijds angstig bewaken moet, dat zijn generalisatie intellectueel hanteerbaar blijft, lijkt me een vitaal onderdeel van de informatica. Ook hieruit is wel relevante en doceerbare stof te destilleren, maar hoe je dat moet doen is niet zo een twee drie duidelijk. Dit kon wel eens een gebied zijn, waar je een hoop bereiken kunt met “negatieve voorbeelden”, dwz, de confrontatie met een aantal pitfalls, gewoon laten zien, hoe je je in de nesten kunt werken. (Ik doe dit bij het begin van het college Operating Systems, waar ik sequentiele processen met gebrekkige methoden ogenschijnlijk goed laat samenwerken. Dat werkt didactisch heel goed, de kennis van een aantal van dergelijke pitfalls is waarschijnlijk ook wel een essentieel onderdeel van de informatica.)

Het college Operating Systems, zoals dit bezig is in te klinken, lijkt me ook onmisbare kennis, in die zin, dat ik tegenwoordig me geen competent informaticus kan voorstellen, die van zijn leven alleen maar sequentiele processen heeft gezien op hun eentje, en nooit de samenwerking tussen een aantal van hen. De dan optredende problematiek is moeilijk en onverwacht genoeg om niet te kunnen zeggen “als iemand dat tegen het lijf loopt, bedenkt hij het wel even”. Een tweede aspect is, dat door een overzicht te geven van een simpel operating system, de student enerzijds een idee heeft van de structuur van het gereedschap, dat hij aan het gebruiken is en anderzijds met wat nieuwe aspecten geconfronteerd wordt, waaraan hij de adequaatheid van een hardware ontwerp kan proberen te toetsen. Een encyclopaedisch overzicht van een of meer gangbare operating systems voor een of meer gangbare machines lijkt mij wederom volledig misplaatst in een academisch curriculum. Hier moet dezelfde bescheidenheid betracht worden als bij de compilers. (Kennis van de structuur van operating systems is voor een gebruiker van een operating system misschien nog wel essentieler als de kennis van een compiler voor de gebruiker van een hogere programmeertaal: de compiler plaatst de gebruiker niet voor zulke vreemde verrassingen als bv. een virtual store...)

Ik geloof niet, dat alle aspecten van “complexiteit” met het bovenstaande aan de orde gekomen zijn, ik denk aan de expliciete exploitatie van ons abstractievermogen, zoals ik dat in de kunst van het programmeren probeer te preken. Ik dacht, dat dat een essentieel aspect van de informatica was en dat ik met dat college zo niet een spijker, dan toch wel een spijkertje op de kop heb geslagen. Zowel studenten als leraren uit het hoger beroepsonderwijs hebben zich zeer gunstig over dit college uitgelaten, maar ze reageren verschillend. De leraren uit het hoger beroepsonderwijs zijn er op grond van dit college over het algemeen van overtuigd, dat “programmeren moeilijker is, dan men denkt”, maar bovendien, dat, hoewel ik vrijelijk over de kunst van het programmeren praat, het daarmee nog niet in zwarte kunst hoeft te ontaarden en zij begrijpen, dat dit college, met zijn kleine sommetjes, maar een eerste aanzetje is. Studenten hebben de neiging het vak programmeren met sommetjes van deze omvang te identificeren en neigen, mede door de begrijpelijkheid van het college, het vak te onderschatten. Sinds dit college in dictaatvorm is uitgereikt, neemt het aantal zich bij mij meldende afstudeerders ernstig toe. Als dit het gevolg is van een maatschappelijke onzekerheid en men het gevoel heeft, dat men als computer expert nog makkelijker zijn brood zal verdienen —wat ik betwijfel, daar de automatisering een heel kwetsbaar gebied is gebleken, waarin nu een aantal statusprojecten onbarmhartig gedumpt worden—, dan zou Lunbeck deze toevloed ook moeten merken. Ik ben, op grond van bij studenten gepeilde motivering een beetje bang, dat de keuze maar al te vaak een gevolg is van het “succes” van dit college. Ik ben mij er pijnlijk van bewust, dat het vermogen projecten van een orde of twee, drie groter aan te pakken, een essentieel aspect van de informatica is, plus alle denk— en organisatietechnieken om tegen deze schaalvergroting opgewassen te zijn. Het is juist deze schaalvergroting van de problemen, die zo typisch is voor de moderne informatica. Hoe men dit aspect in een curriculum zou moeten recht doen wedervaren is mij een volslagen raadsel.

Ik wil nu twee punten noemen, die mij ernstige zorgen baren.

Het ene punt betreft de effectiviteit van algorithmen. Vele wegen leiden naar Rome en om een bepaald probleem op te lossen, zal men doorgaans de keuze hebben tussen allerlei verschillende algorithmen. Wie is de beste? Ik zie drie verschillende dingen gebeuren. Volgen wij het spoor van Knuth, dan komen wij tot de conclusie, dat afschattingstechnieken, en in het bijzonder allerlei vormen van asymptotiek tot de kern van de wetenschappelijke bagage van de informaticus gerekend moeten worden: hij dient dit stuk wiskunde te beheersen om te kunnen voorspellen, hoe goed zijn overwogen product is. Ik plaats hierbij grote vraagtekens, en wel ten eerste omdat het soort wiskundige technieken, dankzij welke deze afschattingen soms mogelijk zijn, erg probleemgebonden lijken en moeilijk daarom tot de kern van de informatica gerekend kunnen worden, ten tweede omdat de statistische verdeling van de invoer, die het programma zal krijgen toegediend, veelal niet bekend is. De tweede techniek, die van toepassing is, als je het programma inderdaad intensief gebruiken wilt, is “proberen”. Het geeft informatica een flavour van een experiment als wetenschap, niet zozeer omdat de programmeur niet weet wat hij gedaan heeft, maar niet weet, wat het programma zal moeten doen. Met de kanttekening, dat die experimentele flavour mij niet aantrekt, teken ik aan, dat het in onderhavige gevallen waarschijnlijk vaak het enig verdedigbare gedrag is. Dit betekent, dat de programmeur zijn programma inderdaad beschouwen moet als lidmaat van een familie naburige programma’s, we zitten meteen met het probleem van het afbeelden van programma’s op elkaar etc., en het zinvol uitvoeren van deze experimenten, beheerst en tegen een aanvaardbare prijs en aanvaardbaar risico is zeker een van de kernopgaven van de informatica. De derde consequentie is, dat het eigenlijk onmogelijk is om een verdedigbare algorithme te publiceren als de populatie van gevallen niet bekend is; we zien dan ook gepubliceerde algorithmen, die hun rechtvaardiging vinden in hun statistisch gedrag ten opzichte van een heel willekeurig samengestelde verzameling proefgevallen. Ik beschouw dit als een degeneratieverschijnsel.

Er is een tweede ding, dat mij nog veel meer zorgen baart. Ik ben nu ettelijke malen tegengekomen —en zodra je bij bestandsorganisatie, wat je moet, er rekening mee gaat houden, dat er wel eens informatie verloren zou kunnen gaan, krijg je het daar ongetwijfeld ook— dat je pas een fatsoenlijk programma kunt maken, mits je een behoorlijke theorie over de mogelijk plaatsvindende gebeurtenissen hebt geconstrueerd, kortom het soort programma, waarin je hopeloos in de mist komt als je er naief aan begint. Dit verschijnsel kennen we allemaal. We moeten dus tot de onontkoombare conclusie komen, dat het tot de typische en essentiele vaardigheden van de competente informaticus behoort, dat hij een dergelijke noodzaak voor een theorie tijdig signaleert. Kan iemand deze ongrijpbare vaardigheid vatten?

In het voorafgaande heb ik me met zorg van specifieke machinetoepassingen onthouden. In principe moeten we natuurlijk ook zeggen, dat als je daaraan begint, het hek van de dam is. Ik vraag me soms af, of we een uitzondering moeten maken voor, zeg maar, administratieve machinetoepassingen. Het is een kwestie van Mohammed en de berg. Het staat vast, dat de meeste machines administratief op een of andere manier worden ingezet, het staat ook vast, dat de mensen, die dit proberen, door de bank genomen met grote moeilijkheden zitten. Het staat voor mij althans ook vast, dat zo hun problemen oplosbaar zijn, deze redding van een meer mathematische aanpak zal moeten komen. Het probleem is, dat de meeste wiskundigen dit nog niet weten —en het zou daarom misschien makkelijker op zijn te zetten in een apart Department of Computing Sciences dan onder de vleugelen van een afdeling wiskunde—, en dat ook de meeste administratieve machinegebruikers dit nog niet weten. (Sommigen lijken mijn opvatting over de rol van de wiskunde in dezen te delen.)

Vanwege Mohammed en die verdomde berg zou je, als een groep ter zake kundige wiskundigen deze nood zien en vertrouwen hebben in hun vermogen hier te helpen, kunnen argumenteren, dat hier voor deze wiskundigen een duidelijke taak is weggelegd. Omgekeerd moet je vermoeden, dat als deze wiskundigen dit gedaan hebben, zij makkelijker aan de administrateurs de relevante opvoeding kunnen overdragen, dan dat de administrateur zijn problemen aan de wiskundige zal kunnen uitleggen. Mijn voorlopige gevoel is dat er ruimte is voor een onderzoek met een sterk wiskundige inslag, dat echter, eenmaal op gang, primair opleiding van derden (c.q. wiskundigen, die een heel speciaal toepassingsgebied in willen) tot gevolg zal kunnen hebben.

Ik heb vanmiddag vijfeneenhalf kantje getikt, ik word wat moe en heb de indruk, dat dit stuk nu langzamerhand lang genoeg is; ik wil de eerstvolgende ciro-vergadering liever niet nog meer uitstellen en het daarom hierbij voorlopig laten.

18 april 1972 | prof.dr.Edsger W.Dijkstra

Voor mij concentreert het vak Informatica zich op het beheerst ontwerpen van systemen, die met welgekozen middelen een welgekozen doel moeten realiseren. Ik heb hier tweemaal het woord “welgekozen” en niet het woord “gesteld” gebruikt om tot uiting te brengen

1)    dat het niet louter de taak van de informaticus is bestaande —eventueel zelfs: hem opgedrongen— apparatuur te gebruiken, maar dat evaluatie van eventuele apparatuur, de adequaatheidsanalyse, niet alleen tot zijn competentie, maar zelfs tot zijn plicht behoort;

2)    dat de ervaring geleerd heeft, dat het zelden verstandig is om het “gestelde” doel zonder discussie te aanvaarden en dat het tenminste de plicht van de informaticus is, om zijn “opdrachtgever” te confronteren met “naburige” doelstellingen, die qua realiseerbaarheid wel eens heel anders zouden kunnen liggen.

Met “ontwerpen” bedoel ik zowel de conceptie van de rekenprocessen als de productie van de bij behorende algorithmen. Met “beheerst” heb ik willen aanduiden, dat conceptie en productie zo ordelijk zijn verlopen en zo handbaar zijn gedocumenteerd, dat de auteur kan instaan voor de qualiteit van zijn product. En hierbij kan qualiteit zich op een heleboel manieren manifesteren, zoals

1)    correctheid

2)    aanpasbaarheid

3)    overzichtelijkheid

4)    voorspelbaarheid in de quantitatieve aspecten van gedrag

5)    robustheid t.a.v. mogelijke component malfunctioning

6)    efficiency.

Dit gekozen hebbende, dienen we alle relevante technieken, kennis en theorieen te bedenken. Ik wil proberen, die die specifiek zijn voor de informatica en niet direct in een ander vak zijn onder te brengen, eerst te noemen.

1)    de techniek van het programmeren met bewuste exploitatie van alle toepasbare abstractiepatronen, de vaardigheid van interfacebewaking

2)    de theorie van correctheidsbewijzen

3)    de kennis van representatietechnieken

4)    de technieken van automatisering van codetransformaties (compilers, assemblers etc.)

5)    de kennis van machineeigenschappen, die genoemde transformaties actueel maken

6)    de theorieen, die aan dergelijke transformaties ten grondslag liggen.

7)    de kennis van notatietechnieken

8)    de theorie die vertelt, waarop de bruikbaarheid van notatietechnieken berust. (of die theorie al bestaat, doet nu niet zo terzake)

9)    de vaardigheid te detecteren wanneer er een model gevormd moet worden waarvoor een theorie ontwikkeld kan worden en zulks vervolgens op adequate wijze te realiseren

10)   de vaardigheid “deelplannen” op adequaatheid en realiseerbaarheid te taxeren

11)   organisatietechniek voorzover relevant voor eigen ontwerp- en ontwikkelingswerk. (Ik noem dit als “specifiek voor de informatica” omdat de algemene organisatieleer bij de software ontwikkeling ’t er lelijk bij heeft laten zitten.)

12)   wat anderen bij doorlezing van dit stuk nog bedenken

Wat hebben de rondom de informatica liggende disciplines hier te leveren? Laat ik met de wiskunde beginnen. Grondslagen, logica, “moderne methoden”, een stuk algebra (bv. lattice theory), stochastisch en asymptotisch benul en voorzover we dat onder de wiskunde willen rekenen, perfect taalgebruik. Besturingstheorie mag er ook wel bij, ik weet niet precies, of dat niet onder “systems theory” valt; verder kan ik, bij gebrek aan kennis, over systems theory niet zoveel zeggen.

transcribed by Bart Vreugdenhil
revised 08-Jan-2012

EWD 330

Bauer - Goos, Informatik, Zweiter Teil

The second volume of the introductory survey of computing science has appeared within a remarkably short period of time after the publication of the first volume, that contained the first four chapters.

The second volume starts with the fifth chapter. This chapter (48 pages) is devoted to dynamic storage allocation and restricts itself —very wisely at this stage— to a single level store. The main part of this chapter deals with the accomodation of variables with nicely nested life times, it explains the stack, the concept of blockheight and the notion of a display; it does so by showing a specific implementation of these concepts in rather great detail. Your reviewer is not quite happy with this way of presentation: the amount of detail makes the chapter quite hard to read and to my taste it is insufficiently stressed that the implementation shown is just one out of many possibilities. Finally the problem of garbage collection —a poor term for which I think the German translation "Speicherbereinigung" a great improvement— is dealt with in only the last seven pages. In view of the comparatively meagre treatment of the allocation problems when life times are no longer nicely nested, one could have the feeling that in this respect the fifth chapter is somewhat unbalanced.

The sixth chapter (56 pages) tries to do the impossible: to give a concise and elegant treatment of a number of very extensive and sometimes very messy subjects. It starts with a dense but adequate survey of all sorts of peripheral equipment and storage media (8 pages). Channels, I/O commands and interrupts are introduced in the next 4 (!) pages; it is the reader's first confrontation with parallelism and a form of non-determinism in the sense that interrupts occur at unpredictable and irreproducible moments. After having told that this could lead to irreproducible results, the authors think it sufficient to remark "Derartige Schwierigkeiten lassen sich durch korrektes Programmieren vermeiden." Although the first half of this section mentions the possibility of a multi-processor configuration, its second half —introducing the interrupt— has clearly been written with a single processor in mind. Is the previous section misleading, the next section "Functional Characterization of the I/O Processes" (17 pages) is just obscure. It does not state the problems to be solved nor the goals aimed at and the result is a long enumeration of definitions (in the style of "We can do this, we can introduce that...") while on the whole it fails to explain their purpose. The text is not always too carefully written: "die Angabe der ersten nicht mehr geschrieben Zeichens" (pg.57) reminds me of the classical advertisement for self-checking tape equipment with the claim "No undetected error has ever been found.". The final part of this section introduces so-called "formats" at great length. I have always been quite happy without them and until someone has convinced me of the contrary, I shall continue to regard the introduction of formats in programming languages as a mistake, as an ad hoc concept that has done more to obscure than to clarify. The authors have included the concept unchallenged. The section "Functional Characterization of the I/O Processes" leans heavily on the baroque apparatus of ALGOL68, a circumstance that could be responsible for its unsatisfying nature. The next section (6 pages) deals with Data Management; it makes the reader encounter the usual terminology but leaves him with a vague picture of a rather elusive subject. The final section (20 pages) of the sixth chapter deals with Operating Systems. It explains multiprogramming in a very satisfactory way. The very condensed treatment of synchronization problems ends with an example of such a twisted nature that I would never recommend it, but has the merit of mentioning the prevention of deadlock as a difficult problem. The section on main storage management is quite clear and has the merit to point out that in a widely used type of machine (guess which!) the accessibility of the base registers prevents refined management of main store. It mentions different systems and system goals (batch processing, time sharing etc.). The final two pages on compilers, loaders, assemblers and linkage editors are not enough: the underlying assumptions or prior decisions that call for this organisation are left undiscussed.

The seventh chapter "Automata and Formal Languages" (45 pages) is of quite a different nature: in contrast to the previous chapter it is full of script capital letters, so beloved by the Mathematician. Besides that the chapter contains 35 pictures and the authors deserve a compliment of their exploitation of graphical means for the purpose of explanation. The pictures range from transition diagrams for finite state machines to parsing trees. It gives a clear example of a syntactic ambiguity, classifies context-free grammars and discusses the parsing problem in a quite attractive way.

The eighth chapter "Syntactical and Semantical Definition of Algorithmic Languages" (30 pages) has outstanding features. For three different algorithmic languages it shows a facsimile of a page of its defining report. It has a short section on axiomatic definition of semantics in relation to the possibility of giving correctness proofs for programs. It contains the remark, that it is practically impossible to establish with the aid of test runs the absence of program bugs; in spite of the overwhelming importance of this observation, the remark, however, is placed in a footnote. After mentioning syntax directed compilers, a few algorithmic languages are compared.

An appendix of fifteen pages gives a survey of the history of automatic computing that is a pleasure to read. Personally I think it very valuable that such a historical survey is included in a book that will be placed in the hands of many students.

Reviewing the two volumes as a whole, we can state without reservation that it gives a fair survey of the field of computing science. The price paid for this encyclopedic aim is twofold. Firstly, many areas of the field could not be covered, they could be touched only. Secondly, the book faithfully mirrors the characteristic lack of coherence between all sorts of computer connected mental activities, but for this incoherence not the book, but the still immature science of computing should be blamed.

Eindhoven, March 1972 | prof.dr.Edsger W.Dijkstra         

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD338

Copyright Notice

The following manuscript

EWD 338: Parallelism in multi-record transactions (with C.S.Scholten)

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 15–21 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

Parallellism in multi-record transactions.

by E.W.Dijkstra and E.S.Scholten

We consider a data base comprising a great number of individual records and transactions to be carried out on this data base. Each transaction is a finite computation, involving a number of these records: the computation to be carried out �and even the identity of the records involved— will in general be dependent on the initial state of the data base when the transaction is initiated. When the data base grows, the following conflict emerges: on the one hand one may expect the number of transactions to be carried out to grow as well, on the other hand the growing data base will make individual record selection a more and more painful process, slowing down the individual transaction executions. Comes the moment that the stream of transactions, carried out one after the other, no longer fits in real time. To solve this real time problem we must be willing to carry out a number of transactions in parallel. This paper is devoted to the logical problems that then emerge.

The purpose of this paper is twofold: firstly to isolate (and to solve to a certain extent) the logical problems involved and secondly, to demonstrate the viability of our top-down approach in problem solving. This means that those readers that are unfamiliar with the top-down approach but are familiar with a number of these logical problems, must be patient. If they find us ignoring a number of practical considerations in the beginning, they should read on quietly: there is a fair chance that they will be taken into account in due time.

The first model.

In the purely sequential execution of the transactions, we can execute the transactions in the (supposedly unique) order in which they are requested and at any moment in time there is at most one transaction under execution. In our first model, we still assume that the requests for transactions reach the system in a unique order and with a speed regulated by the system in such a way that the system can cope with the requests. We admit, however, that at any moment in time the number of transactions currently under execution may be larger than one, although not exceeding some given finite upper bound. The execution of a transaction extends from the moment that the system has acknowledged the request for the transaction until the moment that the system has completed the transaction.

In the purely sequential execution, the system’s net reaction to a number of transaction requests may depend on the order in which the transactions are requested. In the case of parallellism we do not require that the system’s net reaction is identical to that of the sequential system when faced with the stream of requests in the order in which the parallel system has acknowledged these requests. We do require, however, that it is possible to order the requests in such a way that the net reaction of the sequential system faced with the requests in that order will be identical to the reaction of the parallel system. (In many cases, viz. when we have two mutually non-interfering transactions, this order need not be unique.)

Our parallel system has three main obligations; it has to prevent 1) undesired interference, 2) deadlock and 3) individual starvation.

ad 1.

We assume each transaction identified only for the period of its execution. Let T[i] be a transaction currently under execution, let M[i] be the set of records manipulated up till now by T[i]. This implies that during the execution of T[i], the set M[i] can never decrease, until transaction T[i] is terminated and M[i] ceases to exist. We can guarantee the absence of undesirable interference when at any moment in time

i ≠ j ⇒ M[i] ∩ M[j] = ∅ | 1)

i.e. for two different transactions the intersection of the corresponding sets M is empty.

ad 2.

If a and b are two different records and for i ≠ j we have at a given moment a ∈ M[i] and b ∈ M[j] then we will find ourselves in trouble when the progress of T[i] requires record b to be added to M[i] and also the progress of T[j] requires record a to be added to M[j], for then there is no way in which T[i] or T[j] can progress without violating condition 1. This is called “deadlock”. If we insist on the absence of the danger of deadlock —and we do— the above observation tells us that without any further knowledge about the future requirements of the transactions, parallellism is impossible. We therefore associate with each transaction T[i] a set F[i] of records, containing all the records that may possibly be added to M[i]. (Note that this definition implies M[i] ∩ F[i] = ∅.)

When the current transactions can be renumbered such that

i < j ⇒ F[i] ∩ M[j] = ∅ | 2)

the danger of deadlock is absent, for then T[0] can be carried to completion and after that the new T[0] etc. We call the situation “safe” when besides relation 1 the current transactions can be renumbered such that relation 2 holds. We shall keep the system in a safe state. From the above we can conclude that decrease of the set F[i] —as a result of progress of T[i]— will leave a safe situation safe; it furthermore follows that such a decrease is something to be encouraged, because as long as F[0] = the universe, all M[j] with j > 0 must be empty, i.e. parallellism is not possible.

When we start each transaction with its F equal to the universe and insist that T[i] can only add a record to M[i] by transferring it from F[i], then this is the only transition that might violate condition 1 or the safety, i.e. this is the only place where it might be necessary to hold up the further execution of the transaction, “to put the transaction to sleep.” The “counter-occurrences,” on account of which a sleeping transaction could be woken up again are when another processing transaction decreases its own F explicitly or terminates.

In the above we have assumed that for each transaction, F would start equal to the universe and would only decrease. Because this set is so huge, one could think that it could be profitable to divide the execution of a transaction into two successive phases, a first phase in which F is still allowed to grow and a second phase in which this is no longer permissible. But as far as the avoidance of deadlock is concerned, such a transaction is equivalent to one with F equal to the universe during the first phase, decreasing F to the stated amount upon the transition from the first to the second phase.

ad 3.

Our system has to allocate records to transitions. When the allocation strategy is such that each request of a F → M transition is honoured as soon as this is compatible with the simultaneity restriction 1 and the safety condition, it is well-known that the execution of an acknowledged transaction may be postponed indefinitely long. If we have

M[1] = {a} | F[1] = {c}
M[2] = {b} | F[2] = {c}
M[3] = ∅ | F[3] = {a, b, c}

and suppose that T[3] would like to transfer record c to M[3], then it cannot do so because otherwise the deadlock danger woul be introduced with respect to both T[1] and T[2]. In the case of an infinite supply of transactions of type 1 and type 2, T[3] could be kept asleep forever. This phenomenon is called individual starvation and as a rule it is considered to be undesirable.

A crude way to exorcize the danger of individual starvation is the following: As soon as a transaction is put to sleep, a fixed upper limit is imposed upon the number of transactions that may be initiated during that nap. We are not going to look for a more refined technique now, for there are other reasons why we consider our first model as too crude, and in our second model we shall depart from it.

The second model.

Our main complaint about the first model is that a record once in set M[i] remains in set M[i] until the transaction has run to completion. We would like to be able to express that a transaction is such that a manipulated record is no longer essential for the correct progress of the transaction. We therefore split M[i] into two disjoint sets A[i] and P[i], i.e. the records that are still active and the records that have been processed. A record in set P[i] has arrived there from set F[i] via set A[i] and will remain there until termination of T[i].

Obviously

i ≠ j ⇒ A[i] ∩ A[j] = ∅

is a necessary condition, but this is no longer sufficient to guarantee that the net reaction of the parallel system is identical to the reaction of a sequential system after proper ordering of the requests, for it would not exclude

A[i] ∩ P[j] ≠ ∅ and A[j] ∩ P[i] ≠ ∅ .

The first condition expresses that in the sequential ordering T[i] should follow T[j] and the second condition requires it to be the other way round. The situation is even worse, because if P[i] ∩ P[j] ≠ ∅, apparently, the order in which the shared record has been processed has been decided in the past, and this order is no longer expressed in the population of the various sets, but in general it is still relevant.

In our second model, the virtual order for the pair T[i], T[j] is irrevocably decided as far as their interference with the data base is concerned, as soon as for the first time holds

A[i] ∩ P[j] ≠ ∅ or A[j] ∩ P[i] ≠ ∅ .

Therefore we associate with each pair an antisymmetric function V(i,j) = −V(j,i); when the pair is created —i.e. when the second transaction starts to be under execution— V(i,j) is initialized with the value 0. During its life time it may remain constant, it may change its value once to either +1 or −1, where

V(i,j) = +1

means that in the virtual order T[i] has to precede T[j].

We now have the following invariant relations

i ≠ j ⇒ A[i] ∩ A[j] = ∅ | 3)
A[j] ∩ P[i] ≠ ∅ ⇒ V(i,j) = +1 | 4)
V(i,j) = +1 ⇒ A[i] ∩ P[j] = ∅ | 5)
P[i] ∩ P[j] ≠ ∅ ⇒ V(i,j) ≠ ∅ | 6)

and deadlock is prevented, provided that we can renumber the transactions currently under execution in such a way that

i < j ⇒ {F[i] ∩ (A[j] ∪ P[j]) = ∅ and V(i,j) ≥ 0} | 7)

for then T[0] can be carried to completion without violation to the decided virtual order.

The second model shows great similarity to the first one. Again, the only point where it might be necessary to put a transaction to sleep is where it would like to transfer a record from set F to set A. The points of progress in one transaction that could result in the situation that sleeping transactions could be woken up are (as before) explicit F-decrease and termination, but in addition to those two the transition from A to P. The problem of individual starvation can be dealt with in the same crude fashion as in the first model and for the time being we shall leave it at that.

The third model.

The second model is appropriate when each transaction modifies all its active records. But that seems a rather exceptional situation and in our third model we would like to exploit that simultaneous inspection of a current record value by a number of parallel transactions is an absolutely innocent operation. For that reason we split all sets into two: F into FR and FW, A into AR and AW and P into PR and PW. Here AR are the “read only records”, while records in set AW may also be modified. Initially the transaction starts with FW equal to the universe and the other five sets empty. Permissible transfers of a record are: from FW to FR and AW, from FR to AR, from AW to PW and from AR to PR.

Now formulae 3) through 7) can be modified systematically by changing

X[i] ∩ Y[J]

into

(XW[i] ∩ YW[j]) ∪ (XW[i] ∩ YR[j]) ∪ (XR[i] ∩ YW[j])

i.e. from the four cross-products only the three in which writing is possibly involved, but not the fourth, the RR combination.

After this sytematic change we have formulae 3′) through 7′), describing a model in which records shared for inspection only do not impose any mutual exclusion or virtual ordering. The only difference between the third and the second model is that in one transaction the transfer of a record from FW to FR could have the side-effect of waking up a sleeping transaction.

Note. If a transaction upon inspection of a record in set AW (because it might have to modify it) discovers that it can leave the record unchanged, we can, if we so desire, admit the transfer of this record from set AW to set AR. In that case also this transition could have the side-effect that another sleeping transaction can now be woken up.

Avoiding the danger of individual starvation.

In view of the formal relationship between the second and the third model it suffices to discuss the starvation problem in terms of the simpler formalism of the second model.

By the time, however, that we are going to tackle the starvation problem seriously, we should bear in mind that up till now we have assumed that the only reason for preventing progress of a transaction would be that otherwise relations 3 or 7 would be violated. In a general system one must assume that there will be other reasons as well: By the time that we bring into the picture that most of the records will be in secondary store most of the time, reduction of the traffic density between primary and secondary store might become a worthy goal and we can envisage a system trying to collect transactions involving the same records. The system can try to do so by postponing transactions, but also that strategic postponement must be void of the starvation danger.

With each transaction T[i] currently under execution we can associate an so-called “allowance counter” ac[i] and its value will be equal to the maximum number of other transactions allowed to run to completion before T[i] will run to completion. This implies that upon termination of a transaction all ac’s associated with the remaining transactions will be decreased by 1. We now superimpose upon our original safety condition that the transaction can be renumbered in such a fashion that besides relation 7 also

i ≤ ac[i] | 8)

holds.

In that case T[0] can run to completion; its termination will decrease the remaining ac’s by 1; simultaneously the remaining transactions will shift down over one place (i.e. the old T[1] becomes the new T[0]) and as a result relation 8 will continue to hold.

Inside a transaction we have now three types of points where the system may decide to put a transaction to sleep:

request for record transfer from F to A

request for potential strategic postponement

request to terminate.

Whenever a transaction makes such a request that can be honoured without violating conditions 3, 7 and 8, the system is in general free to refuse the request and to put the transaction to sleep. That would admit the possibility of a completely sleeping system and no real time guarantee could be given, even if a maximum execution time for a transaction is known. We therefore impose the requirement that when the set of current transactions is non-empty, at least one transaction must be non-sleeping.

When a transaction is initiated and its ac is introduced its initial value must be sufticiently high to guarantee 8; the number of transactions currently under execution will certainly be sufficient. The higher the initial value of the ac’s, the greater the system’s freedom in shuffling with the transaction order, but the weaker any real time guarantee about possible delays.

Finally in the above parallel system the order in which the transactions are terminated is a possible order for the transaction stream processed by the purely sequential system that should show the same net reaction.

ACM Turing Lecture 1972 | EWD340

The Humble Programmer
by
Edsger W. Dijkstra

As a result of a long sequence of coincidences I entered the programming profession officially on the first spring morning of 1952 and as far as I have been able to trace, I was the first Dutchman to do so in my country. In retrospect the most amazing thing was the slowness with which, at least in my part of the world, the programming profession emerged, a slowness which is now hard to believe. But I am grateful for two vivid recollections from that period that establish that slowness beyond any doubt.

After having programmed for some three years, I had a discussion with A. van Wijngaarden, who was then my boss at the Mathematical Centre in Amsterdam, a discussion for which I shall remain grateful to him as long as I live. The point was that I was supposed to study theoretical physics at the University of Leiden simultaneously, and as I found the two activities harder and harder to combine, I had to make up my mind, either to stop programming and become a real, respectable theoretical physicist, or to carry my study of physics to a formal completion only, with a minimum of effort, and to become....., yes what? A programmer? But was that a respectable profession? For after all, what was programming? Where was the sound body of knowledge that could support it as an intellectually respectable discipline? I remember quite vividly how I envied my hardware colleagues, who, when asked about their professional competence, could at least point out that they knew everything about vacuum tubes, amplifiers and the rest, whereas I felt that, when faced with that question, I would stand empty-handed. Full of misgivings I knocked on van Wijngaarden’s office door, asking him whether I could “speak to him for a moment”; when I left his office a number of hours later, I was another person. For after having listened to my problems patiently, he agreed that up till that moment there was not much of a programming discipline, but then he went on to explain quietly that automatic computers were here to stay, that we were just at the beginning and could not I be one of the persons called to make programming a respectable discipline in the years to come? This was a turning point in my life and I completed my study of physics formally as quickly as I could. One moral of the above story is, of course, that we must be very careful when we give advice to younger people; sometimes they follow it!

Another two years later, in 1957, I married and Dutch marriage rites require you to state your profession and I stated that I was a programmer. But the municipal authorities of the town of Amsterdam did not accept it on the grounds that there was no such profession. And, believe it or not, but under the heading “profession” my marriage act shows the ridiculous entry “theoretical physicist”!

So much for the slowness with which I saw the programming profession emerge in my own country. Since then I have seen more of the world, and it is my general impression that in other countries, apart from a possible shift of dates, the growth pattern has been very much the same.

Let me try to capture the situation in those old days in a little bit more detail, in the hope of getting a better understanding of the situation today. While we pursue our analysis, we shall see how many common misunderstandings about the true nature of the programming task can be traced back to that now distant past.

The first automatic electronic computers were all unique, single-copy machines and they were all to be found in an environment with the exciting flavour of an experimental laboratory. Once the vision of the automatic computer was there, its realisation was a tremendous challenge to the electronic technology then available, and one thing is certain: we cannot deny the courage of the groups that decided to try and build such a fantastic piece of equipment. For fantastic pieces of equipment they were: in retrospect one can only wonder that those first machines worked at all, at least sometimes. The overwhelming problem was to get and keep the machine in working order. The preoccupation with the physical aspects of automatic computing is still reflected in the names of the older scientific societies in the field, such as the Association for Computing Machinery or the British Computer Society, names in which explicit reference is made to the physical equipment.

What about the poor programmer? Well, to tell the honest truth: he was hardly noticed. For one thing, the first machines were so bulky that you could hardly move them and besides that, they required such extensive maintenance that it was quite natural that the place where people tried to use the machine was the same laboratory where the machine had been developed. Secondly, his somewhat invisible work was without any glamour: you could show the machine to visitors and that was several orders of magnitude more spectacular than some sheets of coding. But most important of all, the programmer himself had a very modest view of his own work: his work derived all its significance from the existence of that wonderful machine. Because that was a unique machine, he knew only too well that his programs had only local significance and also, because it was patently obvious that this machine would have a limited lifetime, he knew that very little of his work would have a lasting value. Finally, there is yet another circumstance that had a profound influence on the programmer’s attitude to his work: on the one hand, besides being unreliable, his machine was usually too slow and its memory was usually too small, i.e. he was faced with a pinching shoe, while on the other hand its usually somewhat queer order code would cater for the most unexpected constructions. And in those days many a clever programmer derived an immense intellectual satisfaction from the cunning tricks by means of which he contrived to squeeze the impossible into the constraints of his equipment.

Two opinions about programming date from those days. I mention them now, I shall return to them later. The one opinion was that a really competent programmer should be puzzle-minded and very fond of clever tricks; the other opinion was that programming was nothing more than optimizing the efficiency of the computational process, in one direction or the other.

The latter opinion was the result of the frequent circumstance that, indeed, the available equipment was a painfully pinching shoe, and in those days one often encountered the naive expectation that, once more powerful machines were available, programming would no longer be a problem, for then the struggle to push the machine to its limits would no longer be necessary and that was all what programming was about, wasn’t it? But in the next decades something completely different happened: more powerful machines became available, not just an order of magnitude more powerful, even several orders of magnitude more powerful. But instead of finding ourselves in the state of eternal bliss of all programming problems solved, we found ourselves up to our necks in the software crisis! How come?

There is a minor cause: in one or two respects modern machinery is basically more difficult to handle than the old machinery. Firstly, we have got the I/O interrupts, occurring at unpredictable and irreproducible moments; compared with the old sequential machine that pretended to be a fully deterministic automaton, this has been a dramatic change and many a systems programmer’s grey hair bears witness to the fact that we should not talk lightly about the logical problems created by that feature. Secondly, we have got machines equipped with multi-level stores, presenting us problems of management strategy that, in spite of the extensive literature on the subject, still remain rather elusive. So much for the added complication due to structural changes of the actual machines.

But I called this a minor cause; the major cause is... that the machines have become several orders of magnitude more powerful! To put it quite bluntly: as long as there were no machines, programming was no problem at all; when we had a few weak computers, programming became a mild problem, and now we have gigantic computers, programming had become an equally gigantic problem. In this sense the electronic industry has not solved a single problem, it has only created them, it has created the problem of using its products. To put it in another way: as the power of available machines grew by a factor of more than a thousand, society’s ambition to apply these machines grew in proportion, and it was the poor programmer who found his job in this exploded field of tension between ends and means. The increased power of the hardware, together with the perhaps even more dramatic increase in its reliability, made solutions feasible that the programmer had not dared to dream about a few years before. And now, a few years later, he had to dream about them and, even worse, he had to transform such dreams into reality! Is it a wonder that we found ourselves in a software crisis? No, certainly not, and as you may guess, it was even predicted well in advance; but the trouble with minor prophets, of course, is that it is only five years later that you really know that they had been right.

Then, in the mid-sixties, something terrible happened: the computers of the so-called third generation made their appearance. The official literature tells us that their price/performance ratio has been one of the major design objectives. But if you take as “performance” the duty cycle of the machine’s various components, little will prevent you from ending up with a design in which the major part of your performance goal is reached by internal housekeeping activities of doubtful necessity. And if your definition of price is the price to be paid for the hardware, little will prevent you from ending up with a design that is terribly hard to program for: for instance the order code might be such as to enforce, either upon the programmer or upon the system, early binding decisions presenting conflicts that really cannot be resolved. And to a large extent these unpleasant possibilities seem to have become reality.

When these machines were announced and their functional specifications became known, quite a few among us must have become quite miserable; at least I was. It was only reasonable to expect that such machines would flood the computing community, and it was therefore all the more important that their design should be as sound as possible. But the design embodied such serious flaws that I felt that with a single stroke the progress of computing science had been retarded by at least ten years: it was then that I had the blackest week in the whole of my professional life. Perhaps the most saddening thing now is that, even after all those years of frustrating experience, still so many people honestly believe that some law of nature tells us that machines have to be that way. They silence their doubts by observing how many of these machines have been sold, and derive from that observation the false sense of security that, after all, the design cannot have been that bad. But upon closer inspection, that line of defense has the same convincing strength as the argument that cigarette smoking must be healthy because so many people do it.

It is in this connection that I regret that it is not customary for scientific journals in the computing area to publish reviews of newly announced computers in much the same way as we review scientific publications: to review machines would be at least as important. And here I have a confession to make: in the early sixties I wrote such a review with the intention of submitting it to the CACM, but in spite of the fact that the few colleagues to whom the text was sent for their advice, urged me all to do so, I did not dare to do it, fearing that the difficulties either for myself or for the editorial board would prove to be too great. This suppression was an act of cowardice on my side for which I blame myself more and more. The difficulties I foresaw were a consequence of the absence of generally accepted criteria, and although I was convinced of the validity of the criteria I had chosen to apply, I feared that my review would be refused or discarded as “a matter of personal taste”. I still think that such reviews would be extremely useful and I am longing to see them appear, for their accepted appearance would be a sure sign of maturity of the computing community.

The reason that I have paid the above attention to the hardware scene is because I have the feeling that one of the most important aspects of any computing tool is its influence on the thinking habits of those that try to use it, and because I have reasons to believe that that influence is many times stronger than is commonly assumed. Let us now switch our attention to the software scene.

Here the diversity has been so large that I must confine myself to a few stepping stones. I am painfully aware of the arbitrariness of my choice and I beg you not to draw any conclusions with regard to my appreciation of the many efforts that will remain unmentioned.

In the beginning there was the EDSAC in Cambridge, England, and I think it quite impressive that right from the start the notion of a subroutine library played a central role in the design of that machine and of the way in which it should be used. It is now nearly 25 years later and the computing scene has changed dramatically, but the notion of basic software is still with us, and the notion of the closed subroutine is still one of the key concepts in programming. We should recognise the closed subroutines as one of the greatest software inventions; it has survived three generations of computers and it will survive a few more, because it caters for the implementation of one of our basic patterns of abstraction. Regrettably enough, its importance has been underestimated in the design of the third generation computers, in which the great number of explicitly named registers of the arithmetic unit implies a large overhead on the subroutine mechanism. But even that did not kill the concept of the subroutine, and we can only pray that the mutation won’t prove to be hereditary.

The second major development on the software scene that I would like to mention is the birth of FORTRAN. At that time this was a project of great temerity and the people responsible for it deserve our great admiration. It would be absolutely unfair to blame them for shortcomings that only became apparent after a decade or so of extensive usage: groups with a successful look-ahead of ten years are quite rare! In retrospect we must rate FORTRAN as a successful coding technique, but with very few effective aids to conception, aids which are now so urgently needed that time has come to consider it out of date. The sooner we can forget that FORTRAN has ever existed, the better, for as a vehicle of thought it is no longer adequate: it wastes our brainpower, is too risky and therefore too expensive to use. FORTRAN’s tragic fate has been its wide acceptance, mentally chaining thousands and thousands of programmers to our past mistakes. I pray daily that more of my fellow-programmers may find the means of freeing themselves from the curse of compatibility.

The third project I would not like to leave unmentioned is LISP, a fascinating enterprise of a completely different nature. With a few very basic principles at its foundation, it has shown a remarkable stability. Besides that, LISP has been the carrier for a considerable number of in a sense our most sophisticated computer applications. LISP has jokingly been described as “the most intelligent way to misuse a computer”. I think that description a great compliment because it transmits the full flavour of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.

The fourth project to be mentioned is ALGOL 60. While up to the present day FORTRAN programmers still tend to understand their programming language in terms of the specific implementation they are working with —hence the prevalence of octal and hexadecimal dumps—, while the definition of LISP is still a curious mixture of what the language means and how the mechanism works, the famous Report on the Algorithmic Language ALGOL 60 is the fruit of a genuine effort to carry abstraction a vital step further and to define a programming language in an implementation-independent way. One could argue that in this respect its authors have been so successful that they have created serious doubts as to whether it could be implemented at all! The report gloriously demonstrated the power of the formal method BNF, now fairly known as Backus-Naur-Form, and the power of carefully phrased English, a least when used by someone as brilliant as Peter Naur. I think that it is fair to say that only very few documents as short as this have had an equally profound influence on the computing community. The ease with which in later years the names ALGOL and ALGOL-like have been used, as an unprotected trade mark, to lend some of its glory to a number of sometimes hardly related younger projects, is a somewhat shocking compliment to its standing. The strength of BNF as a defining device is responsible for what I regard as one of the weaknesses of the language: an over-elaborate and not too systematic syntax could now be crammed into the confines of very few pages. With a device as powerful as BNF, the Report on the Algorithmic Language ALGOL 60 should have been much shorter. Besides that I am getting very doubtful about ALGOL 60’s parameter mechanism: it allows the programmer so much combinatorial freedom, that its confident use requires a strong discipline from the programmer. Besides expensive to implement it seems dangerous to use.

Finally, although the subject is not a pleasant one, I must mention PL/1, a programming language for which the defining documentation is of a frightening size and complexity. Using PL/1 must be like flying a plane with 7000 buttons, switches and handles to manipulate in the cockpit. I absolutely fail to see how we can keep our growing programs firmly within our intellectual grip when by its sheer baroqueness the programming language —our basic tool, mind you!— already escapes our intellectual control. And if I have to describe the influence PL/1 can have on its users, the closest metaphor that comes to my mind is that of a drug. I remember from a symposium on higher level programming language a lecture given in defense of PL/1 by a man who described himself as one of its devoted users. But within a one-hour lecture in praise of PL/1. he managed to ask for the addition of about fifty new “features”, little supposing that the main source of his problems could very well be that it contained already far too many “features”. The speaker displayed all the depressing symptoms of addiction, reduced as he was to the state of mental stagnation in which he could only ask for more, more, more... When FORTRAN has been called an infantile disorder, full PL/1, with its growth characteristics of a dangerous tumor, could turn out to be a fatal disease.

So much for the past. But there is no point in making mistakes unless thereafter we are able to learn from them. As a matter of fact, I think that we have learned so much, that within a few years programming can be an activity vastly different from what it has been up till now, so different that we had better prepare ourselves for the shock. Let me sketch for you one of the possible futures. At first sight, this vision of programming in perhaps already the near future may strike you as utterly fantastic. Let me therefore also add the considerations that might lead one to the conclusion that this vision could be a very real possibility.

The vision is that, well before the seventies have run to completion, we shall be able to design and implement the kind of systems that are now straining our programming ability, at the expense of only a few percent in man-years of what they cost us now, and that besides that, these systems will be virtually free of bugs. These two improvements go hand in hand. In the latter respect software seems to be different from many other products, where as a rule a higher quality implies a higher price. Those who want really reliable software will discover that they must find means of avoiding the majority of bugs to start with, and as a result the programming process will become cheaper. If you want more effective programmers, you will discover that they should not waste their time debugging, they should not introduce the bugs to start with. In other words: both goals point to the same change.

Such a drastic change in such a short period of time would be a revolution, and to all persons that base their expectations for the future on smooth extrapolation of the recent past —appealing to some unwritten laws of social and cultural inertia— the chance that this drastic change will take place must seem negligible. But we all know that sometimes revolutions do take place! And what are the chances for this one?

There seem to be three major conditions that must be fulfilled. The world at large must recognize the need for the change; secondly the economic need for it must be sufficiently strong; and, thirdly, the change must be technically feasible. Let me discuss these three conditions in the above order.

With respect to the recognition of the need for greater reliability of software, I expect no disagreement anymore. Only a few years ago this was different: to talk about a software crisis was blasphemy. The turning point was the Conference on Software Engineering in Garmisch, October 1968, a conference that created a sensation as there occurred the first open admission of the software crisis. And by now it is generally recognized that the design of any large sophisticated system is going to be a very difficult job, and whenever one meets people responsible for such undertakings, one finds them very much concerned about the reliability issue, and rightly so. In short, our first condition seems to be satisfied.

Now for the economic need. Nowadays one often encounters the opinion that in the sixties programming has been an overpaid profession, and that in the coming years programmer salaries may be expected to go down. Usually this opinion is expressed in connection with the recession, but it could be a symptom of something different and quite healthy, viz. that perhaps the programmers of the past decade have not done so good a job as they should have done. Society is getting dissatisfied with the performance of programmers and of their products. But there is another factor of much greater weight. In the present situation it is quite usual that for a specific system, the price to be paid for the development of the software is of the same order of magnitude as the price of the hardware needed, and society more or less accepts that. But hardware manufacturers tell us that in the next decade hardware prices can be expected to drop with a factor of ten. If software development were to continue to be the same clumsy and expensive process as it is now, things would get completely out of balance. You cannot expect society to accept this, and therefore we must learn to program an order of magnitude more effectively. To put it in another way: as long as machines were the largest item on the budget, the programming profession could get away with its clumsy techniques, but that umbrella will fold rapidly. In short, also our second condition seems to be satisfied.

And now the third condition: is it technically feasible? I think it might and I shall give you six arguments in support of that opinion.

A study of program structure had revealed that programs —even alternative programs for the same task and with the same mathematical content— can differ tremendously in their intellectual manageability. A number of rules have been discovered, violation of which will either seriously impair or totally destroy the intellectual manageability of the program. These rules are of two kinds. Those of the first kind are easily imposed mechanically, viz. by a suitably chosen programming language. Examples are the exclusion of goto-statements and of procedures with more than one output parameter. For those of the second kind I at least —but that may be due to lack of competence on my side— see no way of imposing them mechanically, as it seems to need some sort of automatic theorem prover for which I have no existence proof. Therefore, for the time being and perhaps forever, the rules of the second kind present themselves as elements of discipline required from the programmer. Some of the rules I have in mind are so clear that they can be taught and that there never needs to be an argument as to whether a given program violates them or not. Examples are the requirements that no loop should be written down without providing a proof for termination nor without stating the relation whose invariance will not be destroyed by the execution of the repeatable statement.

I now suggest that we confine ourselves to the design and implementation of intellectually manageable programs. If someone fears that this restriction is so severe that we cannot live with it, I can reassure him: the class of intellectually manageable programs is still sufficiently rich to contain many very realistic programs for any problem capable of algorithmic solution. We must not forget that it is not our business to make programs, it is our business to design classes of computations that will display a desired behaviour. The suggestion of confining ourselves to intellectually manageable programs is the basis for the first two of my announced six arguments.

Argument one is that, as the programmer only needs to consider intellectually manageable programs, the alternatives he is choosing between are much, much easier to cope with.

Argument two is that, as soon as we have decided to restrict ourselves to the subset of the intellectually manageable programs, we have achieved, once and for all, a drastic reduction of the solution space to be considered. And this argument is distinct from argument one.

Argument three is based on the constructive approach to the problem of program correctness. Today a usual technique is to make a program and then to test it. But: program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence. The only effective way to raise the confidence level of a program significantly is to give a convincing proof of its correctness. But one should not first make the program and then prove its correctness, because then the requirement of providing the proof would only increase the poor programmer’s burden. On the contrary: the programmer should let correctness proof and program grow hand in hand. Argument three is essentially based on the following observation. If one first asks oneself what the structure of a convincing proof would be and, having found this, then constructs a program satisfying this proof’s requirements, then these correctness concerns turn out to be a very effective heuristic guidance. By definition this approach is only applicable when we restrict ourselves to intellectually manageable programs, but it provides us with effective means for finding a satisfactory one among these.

Argument four has to do with the way in which the amount of intellectual effort needed to design a program depends on the program length. It has been suggested that there is some kind of law of nature telling us that the amount of intellectual effort needed grows with the square of program length. But, thank goodness, no one has been able to prove this law. And this is because it need not be true. We all know that the only mental tool by means of which a very finite piece of reasoning can cover a myriad cases is called “abstraction”; as a result the effective exploitation of his powers of abstraction must be regarded as one of the most vital activities of a competent programmer. In this connection it might be worth-while to point out that the purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise. Of course I have tried to find a fundamental cause that would prevent our abstraction mechanisms from being sufficiently effective. But no matter how hard I tried, I did not find such a cause. As a result I tend to the assumption —up till now not disproved by experience— that by suitable application of our powers of abstraction, the intellectual effort needed to conceive or to understand a program need not grow more than proportional to program length. But a by-product of these investigations may be of much greater practical significance, and is, in fact, the basis of my fourth argument. The by-product was the identification of a number of patterns of abstraction that play a vital role in the whole process of composing programs. Enough is now known about these patterns of abstraction that you could devote a lecture to about each of them. What the familiarity and conscious knowledge of these patterns of abstraction imply dawned upon me when I realized that, had they been common knowledge fifteen years ago, the step from BNF to syntax-directed compilers, for instance, could have taken a few minutes instead of a few years. Therefore I present our recent knowledge of vital abstraction patterns as the fourth argument.

Now for the fifth argument. It has to do with the influence of the tool we are trying to use upon our own thinking habits. I observe a cultural tradition, which in all probability has its roots in the Renaissance, to ignore this influence, to regard the human mind as the supreme and autonomous master of its artefacts. But if I start to analyse the thinking habits of myself and of my fellow human beings, I come, whether I like it or not, to a completely different conclusion, viz. that the tools we are trying to use and the language or notation we are using to express or record our thoughts, are the major factors determining what we can think or express at all! The analysis of the influence that programming languages have on the thinking habits of its users, and the recognition that, by now, brainpower is by far our scarcest resource, they together give us a new collection of yardsticks for comparing the relative merits of various programming languages. The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague. In the case of a well-known conversational programming language I have been told from various sides that as soon as a programming community is equipped with a terminal for it, a specific phenomenon occurs that even has a well-established name: it is called “the one-liners”. It takes one of two different forms: one programmer places a one-line program on the desk of another and either he proudly tells what it does and adds the question “Can you code this in less symbols?” —as if this were of any conceptual relevance!— or he just asks “Guess what it does!”. From this observation we must conclude that this language as a tool is an open invitation for clever tricks; and while exactly this may be the explanation for some of its appeal, viz. to those who like to show how clever they are, I am sorry, but I must regard this as one of the most damning things that can be said about a programming language. Another lesson we should have learned from the recent past is that the development of “richer” or “more powerful” programming languages was a mistake in the sense that these baroque monstrosities, these conglomerations of idiosyncrasies, are really unmanageable, both mechanically and mentally. I see a great future for very systematic and very modest programming languages. When I say “modest”, I mean that, for instance, not only ALGOL 60’s “for clause”, but even FORTRAN’s “DO loop” may find themselves thrown out as being too baroque. I have run a a little programming experiment with really experienced volunteers, but something quite unintended and quite unexpected turned up. None of my volunteers found the obvious and most elegant solution. Upon closer analysis this turned out to have a common source: their notion of repetition was so tightly connected to the idea of an associated controlled variable to be stepped up, that they were mentally blocked from seeing the obvious. Their solutions were less efficient, needlessly hard to understand, and it took them a very long time to find them. It was a revealing, but also shocking experience for me. Finally, in one respect one hopes that tomorrow’s programming languages will differ greatly from what we are used to now: to a much greater extent than hitherto they should invite us to reflect in the structure of what we write down all abstractions needed to cope conceptually with the complexity of what we are designing. So much for the greater adequacy of our future tools, which was the basis of the fifth argument.

As an aside I would like to insert a warning to those who identify the difficulty of the programming task with the struggle against the inadequacies of our current tools, because they might conclude that, once our tools will be much more adequate, programming will no longer be a problem. Programming will remain very difficult, because once we have freed ourselves from the circumstantial cumbersomeness, we will find ourselves free to tackle the problems that are now well beyond our programming capacity.

You can quarrel with my sixth argument, for it is not so easy to collect experimental evidence for its support, a fact that will not prevent me from believing in its validity. Up till now I have not mentioned the word “hierarchy”, but I think that it is fair to say that this is a key concept for all systems embodying a nicely factored solution. I could even go one step further and make an article of faith out of it, viz. that the only problems we can really solve in a satisfactory manner are those that finally admit a nicely factored solution. At first sight this view of human limitations may strike you as a rather depressing view of our predicament, but I don’t feel it that way, on the contrary! The best way to learn to live with our limitations is to know them. By the time that we are sufficiently modest to try factored solutions only, because the other efforts escape our intellectual grip, we shall do our utmost best to avoid all those interfaces impairing our ability to factor the system in a helpful way. And I cannot but expect that this will repeatedly lead to the discovery that an initially untractable problem can be factored after all. Anyone who has seen how the majority of the troubles of the compiling phase called “code generation” can be tracked down to funny properties of the order code, will know a simple example of the kind of things I have in mind. The wider applicability of nicely factored solutions is my sixth and last argument for the technical feasibility of the revolution that might take place in the current decade.

In principle I leave it to you to decide for yourself how much weight you are going to give to my considerations, knowing only too well that I can force no one else to share my beliefs. As each serious revolution, it will provoke violent opposition and one can ask oneself where to expect the conservative forces trying to counteract such a development. I don’t expect them primarily in big business, not even in the computer business; I expect them rather in the educational institutions that provide today’s training and in those conservative groups of computer users that think their old programs so important that they don’t think it worth-while to rewrite and improve them. In this connection it is sad to observe that on many a university campus the choice of the central computing facility has too often been determined by the demands of a few established but expensive applications with a disregard of the question how many thousands of “small users” that are willing to write their own programs were going to suffer from this choice. Too often, for instance, high-energy physics seems to have blackmailed the scientific community with the price of its remaining experimental equipment. The easiest answer, of course, is a flat denial of the technical feasibility, but I am afraid that you need pretty strong arguments for that. No reassurance, alas, can be obtained from the remark that the intellectual ceiling of today’s average programmer will prevent the revolution from taking place: with others programming so much more effectively, he is liable to be edged out of the picture anyway.

There may also be political impediments. Even if we know how to educate tomorrow’s professional programmer, it is not certain that the society we are living in will allow us to do so. The first effect of teaching a methodology —rather than disseminating knowledge— is that of enhancing the capacities of the already capable, thus magnifying the difference in intelligence. In a society in which the educational system is used as an instrument for the establishment of a homogenized culture, in which the cream is prevented from rising to the top, the education of competent programmers could be politically impalatable.

Let me conclude. Automatic computers have now been with us for a quarter of a century. They have had a great impact on our society in their capacity of tools, but in that capacity their influence will be but a ripple on the surface of our culture, compared with the much more profound influence they will have in their capacity of intellectual challenge without precedent in the cultural history of mankind. Hierarchical systems seem to have the property that something considered as an undivided entity on one level, is considered as a composite object on the next lower level of greater detail; as a result the natural grain of space or time that is applicable at each level decreases by an order of magnitude when we shift our attention from one level to the next lower one. We understand walls in terms of bricks, bricks in terms of crystals, crystals in terms of molecules etc. As a result the number of levels that can be distinguished meaningfully in a hierarchical system is kind of proportional to the logarithm of the ratio between the largest and the smallest grain, and therefore, unless this ratio is very large, we cannot expect many levels. In computer programming our basic building block has an associated time grain of less than a microsecond, but our program may take hours of computation time. I do not know of any other technology covering a ratio of 10¹⁰ or more: the computer, by virtue of its fantastic speed, seems to be the first to provide us with an environment where highly hierarchical artefacts are both possible and necessary. This challenge, viz. the confrontation with the programming task, is so unique that this novel experience can teach us a lot about ourselves. It should deepen our understanding of the processes of design and creation, it should give us better control over the task of organizing our thoughts. If it did not do so, to my taste we should not deserve the computer at all!

It has already taught us a few lessons, and the one I have chosen to stress in this talk is the following. We shall do a much better programming job, provided that we approach the task with a full appreciation of its tremendous difficulty, provided that we stick to modest and elegant programming languages, provided that we respect the intrinsic limitations of the human mind and approach the task as Very Humble Programmers.

transcribed by
revised 05-Feb-2013

EWD341

Ik zal U van een papiertje toespreken, niet omdat ik dat liever doe, integendeel zelfs, maar opdat er na afloop geen verschil van mening hoeft te bestaan over wat ik gezegd heb.

Aan onze vriend Posthumus danken we het beeld, dat onderzoek en onderwijs voor de wetenschap zijn als schering en inslag van eenzelfde weefsel, waaraan onlangs de opmerking is toegevoegd dat als men ze scheidt, er ook slechts poetskatoen zal overblijven. Het is mij een voorrecht in heel kort bestek te mogen proberen U duidelijk te maken, wat dit voor de informatica inhoudt.

Het is wel bekend, dat electronische rekenmachines duur zijn, het is zelfs zo bekend , dat deze wetenschap dreigt ons kostenbeeld ernstig te vertekenen. De feitelijke uitvoering van de programma’s mag door hun beslag op rekentijd dan duur zijn, de ontwikkelingskosten om deze programma’s te maken is in het algemeen vele malen hoger. En het is onder andere om deze louter economische reden al, dat op de informatica de dure plicht rust te proberen om hierin een drastische verbetering te brengen, om programmeurs te kweken, die in hun beroepsuitoefening een orde van grootte effectiever zijn, dan wij tegenwoordig gewend zijn. Die grotere effectieviteit kan zich manifesteren in hun vermogen programma’s te maken, die onder verstoking van minder rekentijd dezelfde resultaten bereiken, veel belangrijker is dat ze leren een orde van groote effectiever met hun eigen “brainpower” om te springen, want het is in hun manuren, dat de grote kosten gaan zitten.

Nu is een paar jaar geleden in een grote organisatie min of meer bij toeval aan het licht gekomen, dat de individuele effectieviteit van programmeurs, die door hun management nota bene als zo ongeveer gelijkwaardig beschouwd werden, bij nadere beschouwing onderling zo ongeveer een factor 20 uit elkaar bleek te liggen. Deze schokkende ontdekking was een sterke prikkel om te proberen achter de oorzaak van dit enorme effectiviteitsverschil te komen, dit met het uiteindelijke doel te komen tot een doceerbare methodologie waarmee deze enorme effectiviteitswinst kan worden binnengehaald.

Voor onze samenleving is het, voorzover die afhankelijk is van het succes waarmee automatische rekenmachines worden ingezet, van eminent belang, dat deze winst wordt binnengehaald, en hier is meer in het geding dan louter de prijs van programmaontwikkeling, uitgedrukt in manuren. In een moment van optimisme zou men een project, dat door omvang en complexiteit een groep van 10 man vele malen teboven gaat, als de nodige fondsen ter beschikking zijn kunnen proberente bemannen met zeg 200 man. Dit is geprobeerd maar de pogingen om de schaalvergroting in de programmeringsproblematiek op te vangen door er alsmaar meer mensen bij in te schakelen, zijn falikant mislukt, nog helemaal los van het feit, dat deze aanpak een beetje onbetaalbaar begon te worden: in weerwil van de beste organisatorische maatregelen worden bij een dergelijke taakverdeling de onderlinge communicatiemoeilijkheden nl. onoverkoombaar. Bij de dan noodzakelijke informatieuitwisseling beginnen zich dezelfde congestieverschijnselen voor te doen als bij het autoverkeer in een grote stad. De moraal van deze, achteraf begrijpelijke, mislukkingen is, dat in plaats van de groepen tot onhanteerbare grootte te laten groeien, liever de effectiviteit van de individuele programmeurs genoemde orde van grootte opgekrikt zou moeten worden. Vandaar de levendige belangstelling voor een methodologie, die dat zou verwezenlijken, maar de brandende vraag is natuurlijk geweest of wij mochten hopen, dat een dergelijke methodologie ontwikkeld zou kunnen worden.

De aanvankelijke skepsis heeft gelukkig een aantal beoefenaren van de informatica er niet van weerhouden naar een dergelijke methodologie te zoeken en hun werk lijkt met meer succes bekroond te worden dan we aanvankelijk misschien mochten hopen. Het zoeken naar en beproeven van een dergelijke methodologie is bij lange na nog niet voltooid maar een aantal elementen beginnen zich met meer en meer overtuigingskracht af te tekenen. Voor de effectieviteitswinst bij het programmeerproces die dankzij een beter inzicht hierin nu haalbaar is, taxeer ik vergeleken bij hoe thans geprogrammeerd wordt een factor van tenminste 5, voor de toekomst acht ik een factor 30 of hoger geenszins onmogelijk. Op een gegeven moment laat het verschil in competentie zich natuurlijk niet meer in een factor uitdrukken, want dan krijg je te maken met het verschil tussen iets wel kunnen en iets niet kunnen, ongeacht hoeveel tijd je ervoor zou krijgen.

Het gaat hier om een uitgesproken Europese ontwikkeling, die in de Verenigde Staten uit de aard der zaak met belangstelling gevolgd wordt en sommigen heel wel aanspreekt, hoewel het niet een-twee-drie duidelijk is hoe men in het Amerikaanse werkklimaat de vruchten hiervan ten volle zou moeten plukken, een moeilijkheid die wel dezelfde oorzaak zal hebben als het feit dat in Amerika niet een analoge ontwikkeling zelfstandig, helemaal onafhankelijk van Europa, heeft plaatsgevonden. De voornaamste oorzaak van dit Amerikaanse achterblijven lijkt me de daar prevalerende neiging om aan kwantitatieve argumenten het primaat te geven, waardoor te vaak voortijdige kwantificering in de hand gewerkt wordt en vitale imponderabilia tussen walen schip komen. Vanuit technisch oogpunt bekeken lijken de toekomstmogelijk- heden voor de Europese software-industrie dan ook heel gunstig, maar we zullen dan wel de moed moeten opbrengen om niet slaafs te volgen en niet vandaag uit Amerika te importeren, wat daar gister al als vergissing ont- maskerd is.

Een ervaring van dit onderzoek wil ik niet onvermeld laten en die is, dat de invloed van een stuk gereedschap op de mens, die probeert dit stuk gereedschap te gebruiken, vele malen sterker is dan doorgaans wordt aangenomen. En waar het gereedschap in dit geval bestaat uit programmeertalen, moet je constateren dat wanneer aan een programmeertaal maar voldoende bezwaren kleven, zijn gebruikers voor het concipieren van hele klassen van mogelijke oplossingen mentaal volledig geblokkeerd worden; en in het gebruik is een dergelijke programmeertaal veel en veel te duur: na onevenredig veel denktijd komt de programmeur met een onbeholpen programma. Ik ben hier zó van onder de indruk, dat ik me ernstig afvraag of het moreel verantwoord is mensen af te richten op het gebruik van in het bijzonder FORTRAN, COBOL en PL/1, omdat zo’n opleiding meer lijkt op misleiding: wie dit doet bezondigt zich mijns inziens aan geestelijke misvorming, begaat onrecht jegens de slachtoffers en berokkent schade aan het vaderland. Je dwingt deze mensen tot net zo iets onbeholpens als met potlood en papier vermenigvuldigen en delen, maar dan in Romeinse cijfers.

Tenslotte —en ook deze laatste opmerking heeft met onderwijs te maken— de ontwikkeling van een methodologie is een steriele bezigheid, wanneer die methodologie niet overdraagbaar is en de enige overtuigende manier, die ik ken om deze overdraagbaarheid te testen is ... de overdracht te proberen! En hier zijn we terug bij de verwevenheid van onderzoek en onderwijs, waarmee ik begonnen ben. Het betekent dat de docent , opdat wat hij vertelt de moeite van het aanhoren waard blijft, de ondelegeerbare plicht tot onderzoek heeft, maar ook dat de student naast spons tevens wetsteen moet zijn. Mogen beide partijen tegen beide facetten van hun taak zijn opgewassen.

transcribed by Bart Vreugdenhil
revised 26-Dec-2011

EWD343

Reisverslag betreffende het bezoek aan de USA van 14 tot 30 mei 1972 door E.W.Dijkstra.

De ondertitel van dit verslag zou kunnen luiden “Met een verkoudheid op reis”: op de avond van mijn vertrek had ik geen stem meer en lukte het me nog net, om een dosis antibiotica mee te nemen, die vier dagen later in Atlantic City (voor grof geld: je kan in Amerika beter niet ziek zijn) is vernieuwd. Ik ben de hele tocht koortsig geweest. Op de rest van de tocht heb ik mijn menu met aspirine en vitamine C aangevuld. (De oude dame in de drug store in New York, waar ik de vitamine C kocht, heeft haar best gedaan om me ook vitamine E te laten kopen; ze wist niet te melden, waartegen het zou moeten helpen, maar wel, dat het tegenwoordig enorm in trek was. Ik heb aan de verleiding weten te weerstaan.)

Sinds de dood van de spoortrein is het vliegtuig eigenlijk het enige alternatief, maar je zit te wachten tot het moment, dat ook die organisatie in elkaar stuikt. In Chicago heb ik een keer bijna mijn aansluiting gemist, omdat ik van de vervolgvlucht wel het codenummer wist, maar niemand me kon vertellen, welke maatschappij de vluchten met vluchtnummer “ZW...” begon. Voor wie ooit nog een keer liever niet op O’Hare Airport verdwalen wil, het is “Air Wisconsin” en je moet je melden bij een barak in een uithoek van het vliegveld. Een andere keer stuurde ze mijn bagage met het verkeerde vliegtuig weg. Op de laatste dag, toen ik me bij Sabena meldde voor de vlucht New York – Brussel, bleek de Sabena, in weerwil van reservering en bevestiging mijn naam helemaal niet te kennen en werd ik in eerste instantie als “stand by” geboekt. Gelukkig was ik zo vroeg, dat een half uur later het voorafgaande vliegtuig van de Sabena naar Brussel vertrok, waarin in de eerste klas nog een plaats open was en daar ben ik toen ingezet. Dat had twee voordelen: ten eerste reisde ik aanmerkelijk geriefelijker over de oceaan, dan anders het geval zou zijn, ten tweede kon ik —in de vele uren, die ik in Brussel moest doorbrengen— constateren, dat mijn oorspronkelijke vliegtuig zoveel vertraging had, dat ik alleen dankzij deze omzetting de aansluiting naar Eindhoven niet miste. Verder is vliegen met een verstopte buis van Eustachius of daaromtrent een hoogst onaangename ervaring.

Ik zal mijn zwerftocht niet op de voet volgen, ik ben bang dat dat dit verslag te lang zou maken. Ik heb gesproken in New York University (The Bronx), op de Spring Joint Computer Conference te Atlantic City, bij de Bell Labs (Murray Hill), Courant Institute, IBM Systems Research Institute, New York City (twee maal, ’s morgens twee en een half uur, en ’s middags om vijf uur: die tweede lezing was de enige, die niet naar mijn zin ging, ik was waarschijnlijk uitgeteld), Carnegie-Mellon University, Purdue University en Cornell University. Op die ene uitzondering na zijn alle voordrachten heel goed gegaan, ook de laatste, die ik nooit eerder gehouden had en door de laatste drie universiteiten van mijn lijstje was uitgekozen. Van alle gehoren, die ik heb toegesproken, vond ik die in Bell Lab’s en die in Carnegie-Mellon het prettigste.

In NYU, the Bronx, was de stemming nogal “gloomy”, want twee weken tevoren was aangekondigd, dat de school gesloten zou worden en de campus verkocht zou worden: ze werden geacht nog een jaar door te draaien. Hoe ze zich dat voorstelden, was niet helemaal duidelijk, want er hing al erg de stemming van “sauve qui peut”. Mijn gastheer was bijzonder bitter hierover en bracht een en ander onverbloemd in verband met het stijgende anti-intellectualisme in de Verenigde Staten, een anti-intellectualisme, waarvan vooral de technologie het eerste slachtoffer van is.

Op de avond van die eerste maandag ben ik de gast geweest van IBM, waar ik het avondmaal genuttigd heb in het gezelschap van vier mensen, waarvan eentje mij wilde laten zien aan de overige drie, die heel hoge functies in het concern bekleden. Het onderhoud viel me wat tegen, doordat Evans, (president of the Systems Development Division) de conversatie erg beheerste en tevens erg weinig speels was. Hij was “bazig” en erg weinig flexibel. (Door de overigen werd hij me beschreven als “biased”). Dit was jammer, persoonlijk zou ik het veel leuker gevonden hebben, als de andere twee iets meer van zich hadden laten horen. Zonder de aanwezigheid van Evans zouden ze dit waarschijnlijk wel gedaan hebben. Ik denk, dat ik een van beiden, die heel levendige glimoogjes had en oprecht geintrigeerd was, nog wel eens een brief schrijf. Laat op de avond ging ik met een heel klein vliegtuigje naar Atlantic City.

De SJCC was een kermis, waar totaal 12.000 mensen in betrokken waren. Atlantic City is verschrikkelijk, een soort mengsel van Brighton en Knokke, maar dan in het groot. Vergane glorie, aangekleed met aangevroten pluche. Ik heb het er heel gezellig gehad, doordat ik vrijwat bekenden ontmoette; zonder hen zou ik me geloof ik, vrij verloren gevoeld hebben. Ik heb er niet veel nieuwe mensen leren kennen. Zohar Manna gaf een goed voordracht over het werk van Dana Scott, Dana zelf gaf er een slechte over. Er was een hardnekkig gerucht, dat Dana Scott Princeton zal verlaten en naar Oxford gaat (dat betekent dan: naar Christopher Strachey). Ik heb veel geleerd van een gesprek tussen een aantal directeuren van bekende software houses in de USA; het was op een cocktail party, waar de heren geen blad voor de mond namen. Het voor mij meest opvallende in dat gesprek was, dat ze eigenlijk maar een zorg hadden: het op betaalbare wijze ontsluiten van nieuwe markten. Dat de feitelijke productie van software nog heel gebrekkig gaat, bleek uit alles, maar het bleek ook, dat hen dat niet deerde. Daar komt nog bij, dat via het onderhoudscontract van hun product, juist door zijn gebreken, een sterke klantenbindende werking uitgaat.

De openingstoespraak van de SJCC was een grof schandaal. Hij werd uitgesproken door Learson, Chairman of the Board van IBM. Het was een goedkope commercial voor de release van OS/360, die eind 1973 van de band moet komen. Een heleboel Amerikanen waren ook verontwaardigd. Voor mij was het meest opvallende, dat hij in zijn hele verhaal over de vooruitgang van computing science zich volledig tot IBM beperkte en de universiteiten geen enkele keer genoemd werden, zelfs niet terloops... Ik heb daar later iets meer van begrepen. De volgende morgen hadden we de grote toespraak van de Chairman van AFIPS, Uncapher van de Rand Corporation. Ook dat was een heel merkwaardig verhaal in zoverre het louter en alleen ging over de bedreigde monopoliepositie van Amerika op de internationale markt en het de primaire functie van de computing industry bleek te zijn om deze monopoliepositie te handhaven. Ik heb met meer genoegen geluisterd naar de luncheon address van Andrei Ershov uit Novosibirsk, hoewel ik niet al zijn inzichten deelde.

Na deze kermis was Bell Labs een verademing. Ik heb een paar uur zitten praten met Sandy Fraser, oorspronkelijk uit Cambridge, die met hetzelfde soort problemen bezig is, waar C.S.Scholten af en toe met mij over praat, een omstandigheid dankzij welke ik in elk geval als sparring partner kon optreden. Een en ander heeft mijn indruk versterkt, dat het model van signaalverwerking, zoals dat in de tegenwoordig gangbare automatentheorie gehanteerd wordt zijn langste tijd gehad zou moeten hebben. Er begint een grote behoefte te komen aan een model, dat enerzijds mathematisch hanteerbaar is en anderzijds recht doet toekomen aan de eindige lichtsnelheid en Heisenberg. Het zal wel een soort analogon van de statistische mechanica moeten worden, een soort “relativistische statistische informatica”? Het is hard nodig... Aan de lunch verbaasde Hamming me doordat hij nauwelijks wilde weten van beinvloeding van je denken door het gereedschap, dat je gebruikt. Maar misschien zat hij me alleen maar een beetje te stangen....... Bij het echtpaar MacWilliams heb ik een vredig weekend doorgebracht: ik zat mijn laatste lezing voor te bereiden, terwijl mijn gastheer vogeltjes voerde. Zondag een picnic party in de tuin, waar ik het genoegen had, Vyssotski te ontmoeten: ik had zijn naam een aantal malen met respect horen noemen, ik begrijp nu waarom.

In het Courant Institute werd ik wat gedeprimeerd door de uitgebreide maatregelen ter beveiliging van have en goed: zelfs boven in het gebouw had iedereen, ook als hij op zijn kamer was, de kamerdeur op slot. Ik werd daar ingepast in een symposium, dat daar georganiseerd was om mij op de eerste dag en Ershov op de tweede dag ten tonele te voeren, maar het symposium viel me wat tegen; ik was daar niet alleen in.

Dinsdagavond verliet ik Manhattan in de bus naar La Guardia Airport; dat ritje duurt zowat een half uur, de man naast mij heeft de hele rit elke 15 seconden vol overtuiging “Bullshit!” tegen zichzelf zitten zeggen. Ik werd ’s avonds door Nico Habermann opgehaald, die een uiterst gelukkige indruk maakte. Hoogtepunten in Carnegie-Mellon waren mijn gesprekken met Wulf, die probeerde 16(!) PDP 11’s aan een groot geheugen te koppelen en een gesprek met Newell en Simon over “problem solving”. Newell had ik wel eens eerder ontmoet, Simon kende ik alleen uit zijn geschriften. Een gevolg van dit gesprek is in elk geval, dat ik beter begrijp, wat ik de laatste jaren probeer te doen, me beter bewust ben van een van de beperkingen die ik me heb opgelegd. Deze zelfbeperking mag de toepasbaarheid inkrimpen (maar daar maak ik me nog niet zoveel zorgen over), de kans op succes is daardoor veel groter. Als zodanig was het gesprek erg inspirerend.

Naar Purdue ging ik uit beleefdheid jegens Saul Rosen. Mijn feitelijke gastheer was Rudolf Bayer, die op het punt stond een gewoon hoogleraarschap in München te aanvaarden en de hemel op zijn blote knietjes dankte, dat hij Purdue vaarwel kon zeggen. Ik kon het me wel voorstellen. Ik heb nog nooit zoveel “junk” aan elkaar gekoppeld gezien, een CDC6500 met drie (!) IBM 7094’s concentrators van een of andere soort en nog wat meer van dat spul. Mijn gastheer moest mij de deugden van het terminal system laten zien. Het was weer de bekende flop, zij het, dat nu na een vol uur het programma’tje inderdaad draaide. Een en ander heeft me gesterkt in de opinie dat hengsten op een on line toetsenbord een van de duurste manieren is om je tijd te verknoeien. A desolate place.

Cornell University was veel leuker; ik was daar de persoonlijke gast van David Gries, met wie ik verleden jaar in Maryland een Summer School gerund heb. Het verhaal ging daar weer heel goed; gelukkig maar, want er waren nog al wat mensen van vrij ver speciaal voor overgekomen en dat schept wel verplichtingen. Maar het lukte allemaal. Er was daar een aantal mensen met wat tegenwoordig “complexity theory” heet bezig. Dat vak is veel te moeilijk voor mij om er zelf iets zinnigs in te doen, maar het soort resultaten dat nu bereikt wordt is belangwekkend genoeg om notitie van te nemen. Het lijkt een van de meer belovende manieren, waarop een aantal welgefundeerde methodes uit de klassieke wiskunde een daadwerkelijke bijdrage tot computing science kunnen geven. Ik signaleer in dezen de naam van Robert (?) Constable. De indruk, die ik van het huidige “head of the department”, die Hartmanis heeft opgevolgd, kreeg, was maar heel matig, want er deden zich teveel sociale complicaties voor. Het bleek, dat hij zich ernstig gepasseerd voelde dat de associate professor Gries, die nog niet eens tenure had, zich had aangemeten iemand als mij zomaar uit te nodigen en bij zich te logeren te hebben. Dat paste helemaal niet in zijn waardenschaal! Dat was allemaal een beetje lachwekkend.

Het geheel was een ervaring van uitersten. Enerzijds heb ik de vaste overtuiging gekregen, dat er over een paar jaar door meer mensen heel anders over de programmeeropgave gedacht zal worden dan thans gebruikelijk. In een hierop toegespitst experiment is als redelijk haalbare kwaliteitseis naar voren gekomen, dat een programmeur al testend 1 fout per maand mag ontdekken, wat geresulteerd heeft in een eindproduct, dat toen nog 1 fout per 2 manjaar investering bleek te bevatten. Deze getallen klinken nu volslagen ongeloofwaardig voor de meeste mensen, voor mij niet. En eigenlijk ben ik professioneel heel opgewonden, hetzelfde soort opwinding dat door ons heen ging, toen we de eerste machines kregen: in zekere zin krijgen we straks “de eerste programma’s” en ik ben er vurig van overtuigd, dat een groot stuk van de oorspronkelijke belofte in de komende jaren eindelijk zal worden ingelost. In dat licht is het op zijn zachtst gezegd deprimerend om te zien, hoevelen zich bij de status quo als iets onvermijdbaars hebben neergelegd.

Ik heb verder de hand kunnen leggen op wijze woorden van Ershav en Zemanek.

1 juni 1972 | prof.dr.Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 18-Sep-2014

EWD345

Ter zake van wiskundige modelvorming.

Ik hoor over plannen om een speciaal college, responsie-college of practicum of zo te wijden aan "wiskundige modelvorming". Ik weet niet goed, wa t anderen hierbij voor de geest zweeft en heb daarom geprobeerd te bedenken wat ik zelf me er bij zou kunnen voorstellen en wat de bedoeling ervan zou moeten zijn. Ik zie twee alternatieven en mijn vraag is "Is een van deze beide bedoeld of denkt men aan iets heel anders?"

In de eerste opzet zou de bedoeling zijn om het vakkenpakket dat wij thans doceren en waarvan wij tot onze droefnis moeten constateren, dat het niet al te best overkomt, te ondersteunen door studenten te dwingen het geleerde te gebruiken, operationeel te maken, in het bijzonder bij een gegeven probleem door "modelvorming" de omstandigheden te laten scheppen waarin de gedoceerde wiskundige technieken toegepast kunnen worden. Onwillekeurig denk je ook aan het veel gehoorde woord "motivatie". Bij deze opzet heb ik een paar vragen en een kanttekening. De eerste vraag is "Gebeurt dit dan al niet in de colleges en practica die de betrokken vakken behandelen?". Als het antwoord op deze vraag ontkennend is, zou je tot de conclusie kunnen komen, dat dan die colleges en practica voor herziening in aanmerking komen; de vraag "Waarom zouden we dit in een speciaal ding "modelvorming" genaamd onderbrengen?" dient dan in elk geval beantwoord te worden. Als het antwoord op de eerste vraag bevestigend is en in de respectievelijke colleges en practica wel voldoende aandacht aan de modelvorming besteed wordt, dan is de opmerking, dat het kennelijk toch niet zo erg aanslaat en wordt de vraag, die beantwoord moet worden "Wat doet ons verwachten dat een speciaal modelvormingskader in dezen meer effectief is?" De kanttekening, die ik bij de eerste opzet maken wil, is dat een dergelijke activiteit, die er op gericht is onze studenten metterdaad meer te doordringen van de bruikbaarheid van de gedoceerde vakken, niet van reclameaspecten vrij te pleiten is. Ik zie in het bijzonder het gevaar van propagering van de bewustzijnsvernauwing dat de toepasbaarheid van wiskundige methode beperkt zou zijn tot de toepassing van de specifieke technieken en vakken, die wij doceren.

In de tweede opzet zou de nadruk er op komen te vallen, dat modelvorming een intellectuele activiteit is; zorg om de effectiviteit van ons denkproces, methodologie van inventiviteit etc. zouden daar dan centraal in komen te staan. Het zou daarmee een kader zijn voor betrekkelijk algemene bespiegelingen, die niet duidelijk als zodanig bij een van de andere vakken ondergebracht zou kunnen worden, respectievelijk daarover verdeeld zou kunnen worden. Ik acht het geenszins uitgesloten dat, wanneer dit met zorg en smaak wordt opgezet, zulks leidt tot een educatieve activiteit die op ideële gronden bijzonder goed te verdedigen is. Helaas zie ik ook grote moeilijkheden. Het kan heel blikverruimend werken, vooral als de gekozen problemen –ik neem nl. aan, dat dit grotendeels in de vorm van "case studies" zal moeten gebeuren– juist niet te nauw aansluiten bij een heleboel, dat we doceren. In zoverre het de betrekkelijkheid van grote gedeelten van ons curriculum aan het licht zou kunnen brengen betwijfel ik, of er wel zo'n stimulerende invloed van zal uitgaan. Men versta mijn goed: persoonlijk ben ik van deze betrekkelijkheid van grote gedeelten van ons curriculum overtuigd, maar dat is in mijn ogen geen diskwalificatie en ik zou de laatste willen zijn om op grond daarvan haastig te concluderen "Hupsakee, gooi die vakken er dan maar uit." Maar "bruikbaarheid" —of om de wat vieze term te gebruiken, die tegenwoordig zo gepouseerd wordt: "maatschappelijke relevantie"— is op het ogenblik zo overtrokken, dat een sterker nadruk vestigen op deze betrekkelijkheid alleen maar aanleiding kan geven tot psychische conflicten, zo niet bij studenten, dan wel bij docenten. Vandaar mijn reserve bij de tweede opzet.

Of had iemand anders een derde opzet voor ogen?

14 juni 1972

transcribed by F. Koenders
revised Thu, 13 Nov 2008

EWD348

Verslag van de reis van E.W.Dijkstra naar Boston, 12 – 18 augustus 1972.

Ik ben, hoewel het Annual Symposium van de ACM pas op maandag begon, al op zaterdag naar Boston gereisd, mijzelf een extra zondag gunnend om van de reis te bekomen en aan de klokverschuiving te wennen. Toen ik zaterdagavond in het Boston - Sheraton Hotel —dat ik iedereen warm kan afraden— aankwam, verwachte ik daarom nog niet veel bekenden te ontmoeten. Wie schetsts mijn verbazing toen ik in de lobby meteen recht in de armen liep van Elliott Organick, thans hoogleraar in Salt Lake City, die drie jaar geleden, toen ik een maand bij MIT geweest ben, op een wijze die boven alle lof verheven was als mijn bewaarengel heeft gefunctioneerd! Hij viel direct in zijn rol terug en een half uur later zaten we een hapje te eten, samen met de vrouw van wijlen Forsythe, die hier was om een posthume onderscheiding voor haar man in ontvangst te nemen. Vrijdagmorgen, op de dag van mijn vertrek, heb ik met Elliott samen nog ontbeten, het was erg gezelllig hen terug te zien. Het gevlieg ging goed, behalve dat op de terug reis vijf kwartier overstaptijd op Heathrow Airport wel genoeg voor mij, maar niet genoeg voor mijn koffer bleek, zodat ik op Schiphol nog twee-en-een-half uur gewacht heb op de volgende vlucht van BEA uit London.

Het Sheraton Hotel in Boston —waarschijnlijk niet verschillend van andere Sheraton Hotels— is een verschrikkelijke instelling. Het ergste is waarschijn- lijk dat een of andere onverlaat bedacht heeft, dat plastic een prettige be- kleding voor stoelen is. Het absorbeert evenwel niets en dat wordt in het klimaat van Boston in de zomer erg plakkerig.... Toen ik me bij de receptie gemeld had en was ingeschreven, wilde ik mijn kamernummer weten, maar ik kreeg dat niet te horen “The bellman will tell you.” Ik ging vervolgens naar de safe, om daar wat geld en mijn ticket achter slot te laten bewaren. In die tijd was mijn naam door de bellman afgeroepen, wat ik niet gehoord heb, maar een arabier, die hierin zijn naam meende te horen, wel, zodat die naar mijn kamer gebracht werd. Toen ik enige minuten later mijn sleutel loskreeg en op eigen kracht naar mijn kamer ging en deze opende, lag de arabier grotendeels ontkleed op bed en een beeldschoon jongetje (dito) probeerde de televisie aan te zetten. Je mompelt dan maar excuses. Hun “Arabian Night” —de gentleman kwam uit Beiroet— is elders voortgezet en na een minuut of tien kon ik mijn kamer betrekken. Toen ik dit verhaal daarna aan Elliott vertelde, gaf die als commentaar, dat hij altijd de bellman zijn kamer liet openmaken: als er iemand overhoop geschoten moest worden, dan had hij liever, dat dat de bellman was! Mijn enige troost was, dat ook de Amerikanen het hotel veel te duur vonden: ze rebelleerden bijna.

The Annual Sympsium, waar 1500 mensen aan deelnamen, was extra feestelijk, omdat tevens het 25-jarig bestaan van de ACM gevierd werd. Ik mocht de Turing Lecture aan het einde van de openingszitting op maandagmorgen houden voor een gehoor van ongeveer 900 mensen. Het verhaal is bijzonder goed ontvangen. Terwijl ik het verhaal afstak merkte ik al dat het goed viel, want ik kreeg een stuk of vijf open doekjes (op onverwachte plaatsen ), de volgedne dagen hebben een heleboel mensen me er over aangesproken. Na enige uren schoot iemand van de organisatie mij aan, of ze de tekst mochten vermenigvuldigen, omdat er zoveel aanvragen voor waren. Dit is niet door gegaan, want de Editorial Board van de Journal van de ACM gaf geen toestemming. Tenslotte hebben ze mij gevraagd, of ik er geen bezwaar tegen had, wanneer het in de Communications van de ACM gepubliceerd zou worden, omdat die een veel grotere oplage hebben dan de Journal. Ik heb mijn toestemming gegeven en ik weet niet hoe het is afgelopen.

Dinsdagavond was het Silver Anniversary Dinner, waarvoor ik, omdat het als “gala” was aangekondigd, mijn smoking had meegenomen: kan je het weer eens gebruiken: ik was de enige! Hier waren de nog in leven zijnde oprichters (zeven van de negen) van de ACM te bezichtigen. Teen Wegstein van het NBS hoorde, dat ik de meesten van hen niet kende, heeft hij mij aan een paar voorgesteld en toen heb ik het pijnlijkste ogenblik van de hele week gehad. Wegstein stevende, met de bedoeling me voor te stellen, af op John Mauchly (van Eckert en Mauchly van de ENlAC) en zei “Hello John, how are you?”, waarop Mauchly antwoordde “I have no money.” en toen kregen we het hele verhaal. hoe hij jaren geleden voor zichzelf begonnen was, dacht dat hij pensioen had, maar toen de zaak verleden jaar over de kop ging , bleek dat niet zo te zijn. En zijn zoon had een software-house, dat eveneens de laatste adem had uitgeblazen. Dat is dan de oude dag van de grote John Mauchly; ik heb heel beteuterd staan kijken en de rest van die avond eigenlijk geen plezier meer kunnen hebben.

Omdat erg veel mensen me aangesproken hebben, heb ik van het eigenlijke programma een heleboel gemist. Wat ik wel meegemaakt heb, smaakte over het algemeen niet naar meer en het algemene oordeel was niet gunstig. Het was verdeeld over de ruim 25 “Special Interest Groups” van de ACM, de “SIG’s”. Ik wist, dat deze bestonden, hoe ze functioneerden had ik nooit zo van dichtbij gezien. De SIG’s werden bezongen als de ruggegraat van de ACM, maar nu ik het van dichtbij gezien heb, hoeft het voor mij niet. De conferentie als geheel maakte een erg versnipperde indruk, en de opgesplitste zittingen zelf waren vaak bekrompen, je kreeg erg de indruk van een collecite kleine coterietjes. De enige “onverdeelde” zitting naast de opening was de “Research Session”, die ik grotendeels heb bijgewoond. Hier spreken de mensen, die het in de komende jaren voor het zeggen zouden hebben. Schorz van IBM, Weil van Honeywell, Fredkin van MIT, Cheetham van Harvard, Danning van Purdeu en Roberts van ARPA. Ik —en hier stond ik niet in alleen— vond dit heel triest. “Cheaper to make and easier to use” was het vaandel, waaronder ze zich allen geschaard hadden. Wat er op het ogenblik voornamelijk aan schortte was dat “ the man with the little grocery store around the corner” zijn adminis- tratie niet kon automatiseren! Zowel van industriele als van academische kant stond alles erg in het teken van “de gewone man”: je zou bijna vergeten dat een computer nog steeds iets heel bijzonders is! Je merkt aan alles, dat de politieke druk op het ogenblik erg sterk is, dat de technici zich bedreigd voelen en hun beste beentje voorzetten om te laten merken, dat ze vooral geen elite zijn.

De politiek van ARPA, die een groot gedeelte van het geld controleert, speelt ook een belangrijke rol. Een complicatie is, dat deze politiek erg wispelturig is, zodat velen zich genoodzaakt voelen een groot gedeelte van hun “wetenschappelijke intuitie” in te zetten, om tijdig aan te voelen, wat volgend jaar bij ARPA lekker zal vallen, resp. hun invloed aanwenden om de mode in hun richting te buigen. Allemaal niet zo leuk. Time sharing en graphics zijn “out”, networks als onderwerp is tanende. Natural language systems doen het beter.

Twee ontwikkelingen, die mij belangrijk voorkomen, kwamen wel via de ACM-kanalen aan het licht, ten eerste het werk van Zohar Manna, die de fixpoint theory, zoals deze door Dana Scott en Christopher Strachey is ontwikkeld, gebruikt heeft om, indien je daar behoefte aan hebt, de postulaten van Floyd en Hoare te bewijzen: hier zie je heel duidelijk dat vrij verschillend geaerd werk op het gebied van programmacorrectheid aan het convergeren is. Dit is bijzonder bemoedigend en ik verwacht, dat we in de komende jaren het belang hiervan zullen merken. Ten tweede het werk van Minsky en Papert over opvoeding van kleine kinderen: hun afdeling “pubpiciteit” is zo goed ontwikkeld, dat je als Europeean geneigd bent om achterdochtig te worden, maar in dit geval geloof ik ten onrechte. Ten minste Minsky is in elk geval heel knap.

De donderdag heb ik gebruikt om contact te leggen met was via de “officiele kanalen” niet aan het licht komt: ’s morgens ben ik bij Anatole Holt geweest, ’s middags bij Douglas Ross. Het bezoek bij Holt was zo boeiend, dat hoewel hij kersvers terugwas uit Peking, China niet ter sprake is geweest. Deze man werkt vrij intensief samen met Carl Adam Petri uit Bonn. De bedoeling van dit werk is om tot een model van informatieverwerking en communicatie te komen, dat epistorologisch verantwoord is: door zijn operationele definitie van “gelijktijdigheid” is het duidelijk door de relativiteitstheorie beinvloed. Uit deze studie is het model van het “Petri-net” gekomen, waarover met de nodige combinatoriek en graphentheorie een heleboel fascinerende dingen te bewijzen blijken te zijn. Het meest fascinerende resultaat is ongetwijfeld dat de nodige en voldoende voorwaarde opdat een Petri-net een globale eigenschap bezit (globaal zowel in ruimte als tijd) in zuivere locale criteria kon worden uitgedrukt. Het zou mij helemaal niet verbazen, wanneer dit werk van fundamentele betekenis zou blijken te zijn, wanneer we mogelijkheden (en de grenzen daarvan) van koppeling van onderling asynchrone machines willen onderzoeken. (Het is allang duidelijk, dat de op de telefonie geente instelling van de “data communications engineer” hier het verlossende woord niet zal spreken.)

’s Middags en ’s avonds ben ik bij Douglas Ross geweest: ’s middags heeft hij me wat laten zien van het werk, dat ze deden naar aanleiding van de computer- gestuurde fabriek, waar de computer enerzijds stuursignalen zendt, anderzijds via sensors observeert, wat er gebeurt. De logische moeilijkheden komen, wanneer de sensor gegevens niet aangeven, wat zou moeten en de beste gok gemaakt moet worden, wat er misgegaan is. Dit was het eerste voorbeeld van grootscheepse “closed loop control”, dat ik ooit gezien heb en de manier, waarop zij zich voorstelden de onwaarschijnlijk strenge betrouwbaarheidseis te bevredigen, heeft grote indruk op me gemaakt (al kan ik me de details niet meer herinneren.) ’s Avonds heb ik hem over een paar ideeen van mij gepolst; dat was erg vermoeiend, want ik had nog nooit zo erg geprobeerd ze precies te formuleren. Het ging erover, dat je bij een groot systeem niet alleen zorgen moet, dat de totale bewijslast als het systeem groeit niet uit de hand loopt (quantitatief, bedoel ik), maar dat je het systeem zo moet kunnen beschrijven, dat de bewijslast “uniform” over de tekst verdeeld is, in het DK-jargon: dat het bewijs even modulair is als de tekst. Ik meende een paar consequenties van deze eis gevonden te hebben, hij bleek er nooit zo over gedacht te hebben, maar in de loop van de avond ging hij helemaal met mij mee en gesterkt ging ik huiswaerts.

De volgende dag ben ik bij project MAC op MIT geweest: dit trof mij helaas als een doodgebloede zaak. De Artificial Intelligence Group had zich van project MAC losgemaakt en daar gebeurt nog genoeg!—, wat er over was, was nog een beetje aan het nakaarten over MULTICS en hun nieuwe research richting vond ik niet overtuigend: het haakte bij de heersende mode aan, in plaats van dat ze de toon aangaven.

Ik vond het hele bezoek eigenlijk een beetje angstig, toen ik me het vol- gende realiseerde: ik rangschik Barton, Holt en Ross onder de grootste en origineelste computer scientists van de USA. Met uitzondering van Barton, die als consultant van Burroughs weerklank vindt, hebben deze drie zich helemaal afgekeerd eigenlijk van de “computing science establishment” zoals zich dat weerspiegelt in de universiteiten, de ACM en de computer industrie. Zij publiceren niet meer in de periodieken van de ACM, houden er ook geen voordrachten meer, het is, alsof ze iets hebben opgegeven. Hun namen zijn bekend, men weet globaal, waar ze mee bezig zijn, als je laat vallen, dat je hen rangschikt onder de grootsten, spreekt niemand je tegen, dat wat ze doen wel eens schokkend zou kunnen zijn wordt beaamd en vervolgens worden deze mensen gemakshalve genegeerd. Angstig.

PS: Een SIGPRO “Special Interest Group on Programming” bestaat niet. Gek he?

21 augustus 1972 | Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 01-Dec-2011

EWD349

Ontwikkelingsplan Informatica.

De Commissie observeert alom een sterke neiging om Informatica nadrukkelijk te beschouwen als een interdisciplinaire wetenschap, een neiging, die het voorspelbare gevolg is van de in vele disciplines heersende opvatting, dat de computer een veelbelovend, ja onmisbaar stuk gereedschap voor het betrokken vakgebied is of zal worden. Zonder de potentiele bruikbaarheid van de computer op velerlei vakgebied ook maar een ogenblik in twijfel te willen trekken, tekent de Commissie hierbij aan:

1)     dat de verbreding van de opvatting, dat men in zijn vakgebied niet meer “up to date” is, tenzij men ook van de computer gebruik maakt, een epidemisch verschijnsel lijkt te zijn: men steekt elkaar aan! Het verschijnsel vraagt om de karakterisering “Joining the bandwagon of the Computer Age”.

2)     dat de computerindustrie, op zoek naar nieuwe markten, de universele bruikbaarheid als te van zelfsprekend en te makkelijk heeft voorgesteld. In het bijzonder is de voorstelling van zaken dat “het inschakelen van de (bij voorkeur: “onze”) computer het einde van Uw problemen zal zijn” op zijn zachtst gezegd misleidend: veelal beginnen de moeilijkheden dan eerst goed.

3)     dat zij, die van het interdisciplinaire karakter overtuigd zijn, zulks vaak zijn doordat zij onbekend zijn met het hart van Informatica, nl. die technieken en hun theoretische fundering, die aan elke computertoepassing ten grondslag liggen en daardoor applicatie-onafhankelijk beschouwd kunnen en moeten worden. Vaak zijn zij zelfs van het bestaan van dit hart en zijn groeipotentieel tot een cohaerente methodologie niet op de hoogte en het is deze onbekendheid, die hen dwingt de informatica niet een eigen plaats te geven, maar er plaats voor te zoeken, verspreid over de applicatiegebieden.

4)     dat op goede gronden verwacht mag worden, dat de huidige ontwikkeling, die programmeren maakt tot een activiteit van uitgesproken wiskundige signatuur, het komende decennium zich zo versneld zal voortzetten, dat anno 1980 de huidige tradities van machinegebruik volledig achterhaald zullen zijn. Op grond van deze overtuiging acht de Commissie “computer education”, die de mathematische inslag van de informatica niet centraal stelt of zelfs verdoezelt, uit den boze.

5)     dat de Commissie dan ook een groot vraagteken plaatst bij de gretigheid waarmee allerlei takken van wetenschap zich storten in de “computerizing” van delen van hun vakgebied: met alle respect voor de oprechte bedoeling de vruchten van het fenomeen computer ten bate van de wetenschap te plukken, is het gevaar levensgroot aanwezig, dat men over tien jaar zit opgezadeld met een volslagen verouderd systeem. De bittere ervaring heeft geleerd, dat wanneer investering in en afhankelijkheid van een dergelijk systeem maar groot genoeg zijn, men onverbiddelijk aan de vergissingen uit het verleden vastgekluisterd blijft. Een toekomst, waarin hele vakgebieden gedegenereerd zijn tot de kunst hoe te leven met de beperkingen van een aantal door traditie en verbreiding tot standaard verheven “program packages” is een maar al te reeel schrikbeeld.

Gezien het bovenstaande verwacht de Commissie, dat ten aanzien van die disciplines, waar Informatica als bijvak vanwege de potentiele bruikbaarheid van de computer in een opleiding niet zou misstaan, eer remmend dan stimulerend moet worden opgetreden: zowel bij de ontwikkeling als bij de verbreiding van Informatica als wetenschappelijke discipline en toepasbare methodologie dient voorop te staan dat verstandig en verantwoord computergebruik, zodra het het niveau van de trivialiteiten voldoende ontstegen is —en met de capaciteit van tegenwoordige rekenapparatuur is dat al heel gauw het geval— intrinsiek heel moeilijk is. “There is no royal road to Mathematics.” en programmeren, een tak van de toegepaste wiskunde die hoge eisen stelt aan een spectrum dat loops van accuratesse tot conceptuele creativiteit, is daarop geen uitzondering, integendeel!

Voorts observeert de Commissie de neiging om de 1968 ACM Curriculum Proposals als uitgangspunt, ja haast als standaard te nemen. De Commissie wil hierbij het volgende aantekenen.

1 )     In alle algemeenheid moet worden opgemerkt, dat “imitatie” de neiging heeft tot een tweederangsproduct te leiden. Op het gebied van hardware heeft de Europese computerindustrie zulks getoond, het lijkt ongewenst, wanneer op het gebied van software de Europese universiteiten dit gaan herhalen.

2)     Het ACM-voorstel in indertijd ten duidelijkste afgestemd op de toen in de USA heersende problematiek, toen in allerlei negorijen opleidingen dreigden te starten. Het doel was om een zekere homogeniteit te bereiken; in menig op- zicht is het een minimum-programma, aangekleed met stukken op korte termijn gerichte beroepsopleiding. Als zodanig lijkt het veel te bevatten, dat weinig aansluit bij de beste tradities van het Europese universitaire onderwijs. Voorts is de Amerikaanse toestand met vooral die in Nederland slecht vergelijkbaar, omdat in de Verenigde Staten een weinig sterke traditie van toegepaste wiskunde is.

3)     Er is, met als voornaamste componenten vooraanstaande computerindustrieen, vooraanstaande universiteiten, de ACM en ARPA (Advanced Research Projects Agency of the Department of Defense), in de USA een gevaarlijk conservatief en door inteelt bedreigd computer establishment aan het ontstaan, waar innovatie (zeker al een jaar of tien) met kracht (en niet altijd even fraaie middelen) wordt tegengewerkt. Het is alarmerend om te zien, hoe een aantal boeiende ontwikkelingen in de officiele media nauwelijks aan het licht komen en de facto op de “underground press” zijn aangewezen. De publicaties van de ACM, evenals de proceedings van de grote Computer Conferences zijn niet meer representatief; dit geldt ook voor menig universitair curriculum.

Voor de informatica aan de THE verwacht de Commissie op grond van de ontwikkeling van de laatste jaren en zich steeds duidelijker aftekenende behoeften een ontwikkeling in de hieronder geschetste richting.

In verband met toenemende betrouwbaarheidseisen zullen correctheidsbewijzen een belangrijkere rol gaan spelen. Dit zal zich uiten door
1)     verdere ontwikkeling van bewijstechnieken, zowel voor sequentiele systemen als voor systemen met intern parallellisme
2)     verdere ontwikkeling van technieken voor interface-keuze, zodat de bewijsplicht niet explodeert
3)     verdere ontwikkeling van de methodologie, waarin de analyse van de behoefte van een correctheidsbewijs als heuristisch hulpmiddel bij ontwerp kan worden geexploiteerd.

Naast het “correctheidsbewijs” ais middel tot betrouwbaarheidsverhoging zal “automatisering” een rol gaan spelen: met name mag van de toekomstige software engineer verwacht worden, dat hij, meer dan zijn collega van vandaag, zijn eigen “gereedschap” zal ontwikkelen, dwz. zowel ontwerpen als maken. Het ontwerpen van doelgerichte programmeertalen bv. zal van kunst meer kunde worden, evenals het toepassen van technieken als “bootstrapping” e.d.

Tenslotte constateert de Commissie, nog steeds in het kader van de betrouwbaarheidseis, maar nu betrokken op systemen, die grote hoeveelheden informatie beheren en/of 24 uur per dag beschikbaar moeten zijn, dat de technieken om systemen als geheel resistent te maken tegen “partial equipment malfunctioning” tot op heden nog niet veel meer zijn dan een collectie maatregelen ad hoc. Het ontbreken van een tegelijkertijd realistisch en tevens mathematisch hanteerbaar model wordt een steeds schrijnender tekort.

Naast het logische aspect van de correctheid zal het practische aspect van voorspelbaarheid van systeemgedrag in kwantitatief opzicht een belangrijke rol spelen. Met een groeiend inzicht in grenzen en mogelijkheden van een voornamelijk analytische behandeling verwacht de Commissie dat bij deze problematiek de rol van simulatietechnieken aan relatief belang zal afnemen; parallel daaraan zal het belang van uitgesproken hierarchische systemen toenemen.

Voorts vestigt de Commissie de aandacht op de zich ontwikkelende complexiteitstheorie. Terwijl het fundamentele werk van Turing en Post een jaar of dertig als basis heeft gediend ter afbakening van het mechanisch principieel onmogelijke, heeft het werk van Winograd de stoot gegeven tot kwantificering van de graad van doerlijkheid van “in principe mogelijke” opgaven. Bruikbaarheid van deze theorie begint zich pas schuchter af te tekenen; bovendien doet de theorie een beroep op een aanmerkelijk bredere wiskundige kennis dan waarover de informatici vandaag plegen te beschikken. Het ligt daarom voor de hand dit vak voorhande niet specifiek bij de informatica onder te brengen, maar bij de meer algemene wiskunde. De ontwikkeling dient echter voldoende nauwlettend gevolgd te worden om desgewenst het curriculum voor de informaticus tijdig aan te kunnen passen.

transcribed by Bart Vreugdenhil
revised 01-Dec-2011

EWD351

Verslag bezoek Engeland 30 augustus – 9 september 1972.

Ik leef in vele werelden. Wanneer ik in Eindhoven over ontwerpmethodologie etc. praat, bespeur ik een duidelijke scepsis in de trant van “Voor ontwikkeling (in tegenstelling tot onderzoek), voor routineaangelegenheden zoals programmeren kan zoiets misschien wel bestaan, daar waar originaliteit enwiskundige inventie in het geding zijn, kan het nooit veel helpen.” Donderdag 30 augustus 1972 heb ik ’s middags een lezing gehouden in het IBM Laboratorium te Hursley, waarin ik een aantal programmatjes “op mijn manier” ontwikkeld heb. Mijn gehoor was uiterst gemend: achter in de zaal zaten de programmeurs (in de ruimste zin des woords), voorin zaten de managers. In de discussie bleek, dat de managers erg teleurgesteld waren .... omdat ik nog zoveel ruimte liet voor originaliteit en inventiviteit! (Het publiek achter in de zaal vond de voordracht heel leuk!) Mijn samenvatting van de situatie is “Managers regard software design primarily as a management problem because they cannot manage it.” Ik voel me getempteerd om een satyre te schrijven over “Mathematics, Inc.”, een organisatie, die een contract heeft afgesloten om in het voorjaar van 1975 een bewijs van Goldbach’s Conjecture te leveren!

In Hursley troffen me verder een paar dingen. Ten eerste zijn alle bordjes “THINK” verdwenen en vervangen door aansporingen “to keep IBM confidential matters secret”. In de vele gesprekken, die ik heb gehad, was dit een keer erg hinderlijk. Het was verder een wat deprimerende zaak: meer dan vijftig procent van hun manpower is inmiddels opgeslokt door wat ze als “maintenance” aanduiden, ze vinden dit om begrijpelijke redenen heel hinderlijk en alarmerend, ik bespeurde absoluut geen research ten aanzien van de vraag, hoe dit te voorkomen zou zijn. Dergelijk onderzoek valt kennelijk buiten hun taakstelling. De bekrompenheid van deze taakstelling leidt wel tot heel moeilijke situaties: ik heb een tijd lang zitten praten met een man, die verantwoordelijk was voor zoiets als “product validation”, wat als je het logisch analyseert, een volslagen onmogelijke taak is. Je zit wel in een naar schip als je een taak hebt, waarvan je kunt aantonen, dat niet alleen jij hem niet kan, maar dat niemand hem kan en toch geen kans ziet je managers ervan te overtuigen, dat de interne taakverdeling fundamenteel verkeerd is. Het was een slimme jongen en ik had erg met hem te doen. Verder trof ik er de zoveelste groep aan, die bezig was om een rigoureuze definitie van PL/I te geven; ook deze groep had het gevoel op een dood spoor gezet te zijn omdat ze iets moesten doen op een manier, waarvan ze inmiddels overtuigd waren, dat de manier fundamenteel tekort schoot. En dan maar do en alsof...

Na mijn bezoek aan Hursley vertrok ik naar Newcastle, waar onder auspicieen van de Universiteit en op kosten van IBM een seminarium gehouden werd over “Computer applications in business.” Ik ben daar naar toegegaan met de bedoeling om veel te leren, ik heb er ook wel veel geleerd, misschien niet altijd wat ik hoopte te leren. De officiele sprekers vielen uiteen in twee categorieen: ten eerste twee Amerikaanse hoogleraren, die een undergraduate en een graduate program presenteerden. In weerwil van het feit, dat het graduate program gepresenteerd werd door iemand als Ashenhurst, waren deze presentaties nogal weinig overtuigend. Ashenhurst hield het hoofd boven water, door ook zelf er nogal relativerend over te spreken, de man van het undergraduate program ging gewoon af. Het had heel weinig met computing science te maken, het was op zijn best “vocational management training”.

Prof.M.M.Lehman —nu Imperial College— ging in de discussie een keer op een van zijn stokpaarden zitten, nl. dat het grote bezwaar van het Amerikaanse onderwijssysteem is, dat het de neiging heeft om voor de volle honderd procent “knowledge oriented” te zijn; de opmerking was volkomen terecht, een beter bewijs voor zijn stelling had hij niet kunnen vinden. De veel gehoorde opmerking “dat door de snelle vooruitgang van de wetenschap onze kennis zo snel verouderd” vraagt om een tegeninterpretatie, nl. dat teveel ten duidelijkste valotiel spul ten onrechte voor “wetenschap” wordt aangezien.

Voorts was het geheel een duidelijk symptoom van de in de USA heel geprononceerde anti-intellectuele beweging: als je wilt een volgende greep naar de macht van de soft sciences. Het was al den donder gedragswetenschappen, sociologie, psychologie en economie. Het is natuurlijk allemaal best dat iemand, die zich met automatisering of modelvorming in het bedrijsleven wil gaan bezighouden, daar iets van af weet, maar een en ander ging zover, dat eigenlijk ontkend werd dat er doorgaans ook nog een technisch probleem competent opgelost moet worden. Deze beide heren hebben elk drie uur gesproken, ze werden nogal in het defensief gedrongen.

Dan was er een drietal andere sprekers (van Dupont, ICI en Barclay’s Bank), die heel andere verhalen hielden, nl. een verslag gaven van hoe in hun bedrijf de werkzaamheden door de komst van de rekenmachine beinvloed waren. Deze verhalen hadden in elk geval het voordeel, dat ze “waar” schenen; de drie sprekers waren alledrie hoog in hun eigen hierarchie. De man van Barclay’s bank faalde op het publiek een goede indruk te maken; hij had helemaal de instelling van “Ik verwacht van afgestudeerden van de universiteiten, dat ze zonder inwerkperiode onze problemen met de bestaande apparatuur kunnen oplossen.” en de vraag, wat deze afgestudeerden over vijf en over tien jaar zouden doen, regardeerde hem niet. Een mengsel van kortzichtigheid en cynisme, dat onverkoopbaar bleek. (Uit de discussie kwam duidelijk naar voren, dat de meesten ook zonder dit verhaal al de indruk hadden, dat uitgerekend het Engelse bankwezen wel heel erg aan zijn tradities zit vastgekluisterd.) De verhalen van Dupont en ICI gingen over de veranderde planning-procedures; de man van Dupont, Andersen, heeft de conferentie gedragen, het was een genot om naar hem te luisteren; Youle van ICI sprak ook bijzonder eerlijk en was daarom de moeite waard, zij het dat ik hem wel wat verontrustend vond in zijn diepgeworteld wantrouwen tegen de “academicians”. Het had teveel de flavour van “wij jongens van de praktijk”; ik ken die geluiden uit Nederland natuurlijk ook, maar het trof mij een beetje ouderwets en achterhaald en het zou best kunnen zijn, dat in dit opzicht Engeland een paar jaar op Nederland achterloopt.

Dave Parnas van Carnegie-Mellon heeft ook drie voordrachten gehouden, de eerste was goed, de tweede een beetje langdradig en de derde was in wezen over een nog lang niet rijp onderwerp. Ik wist niet anders dan dat hij na het seminarium naar Nederland zou komen en had al half-en-half georganiseerd, dat hij ook een voordracht aan de TH zou houden; het was een opluchting te horen, dat hij direct naar Amerika terugmoest en dat daarom zijn hele bezoek aan Nederland niet doorging. Als hij dit verhaal hier gehouden zou hebben, zou ik me nogal in verlegenheid gebracht voelen.

Het seminarium werd afgesloten met de verplichte IBM-spreker. Onze landgenoot prof.dr.A.A.Verrijn Stuart, die ik bij deze gelegenheid voor het eerst ontmoet heb, onderscheidde zich door na deze voordracht als enige uit het gehoor ook nog een duit in het zakje te doen en een soort credo weg te geven, dat zich weinig onderscheidde van het verhaal van de spreker bij wie hij aansloot. Wolbers was er ook.

| prof.dr.Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 01-Dec-2011

CIRO 8.6
EWD353

Elementen ener afstudeerrichting in de informatica.

In de ciro is diepgaand gediscussieerd over de vraag welke stof niet zou misstaan in het curriculum van een wiskundig ingenieur die zich tot "software engineer" zou willen ontwikkelen. Wij zijn uiteindelijk terecht gekomen bij acht "verplichte vakken" —verplicht in de dubbele zin, dat elke toekomstige software engineer ze redelijk zou moeten beheersen en wij ze regelmatig zouden moeten geven— en zes "keuzevakken"; dit laatste zestal is niet uitputtend en ook minder definitief, het is meer bedoeld als aanduiding van het soort dingen, die b.v. voor een caput-college in aanmerking zou komen.

Wij geven de verplichte vakken hieronder in een min of meer chronologische volgorde.

1. Inleiding tot de Kunst van het Programmeren (2 * 2 semesteruur).

Dit zij een college met een sterk methodologische inslag, waarin kennisoverdracht een vrij ondergeschikte rol speelt. De nodige semantiek wordt intuitief gepresenteerd, de zorg om correctheid fungeert voornamelijk als richtsnoer bij het proces van programmaontwerp. In zijn huidige vorm beslaat dit college 1 * 2 semesteruur; de voortzetting dient meer aandacht te schenken aan het gebruik van representationele abstractie en de studenten indien mogelijk met omvanrijkere programmeeropgaven te confronteren.

2. Toegepaste logica (2 * 2 semesteruur).

De bedoeling van dit college is om de student vertrouwd te maken met een aantal formele technieken van standing, welke onmisbaar zijn als men het vak op een solidere basis wil bedrijven. Het eerste semester is inmiddels geconsolideerd en bestrijkt twee hoofdgebieden, ten eerste formele systemen en ten tweede de beslisbaarheidsproblematiek. Het tweede semester is nog niet zover geconsolideerd; het college heeft bestreken de eindige automaat, generatieve grammatica's, ambiguiteit en herkenning met al of niet eindige automaten. De verwachting bestaat dat in dit laatste gedeelte een accentverschuiving van Chomsky naar Church zal plaatsvinden.

3. Inbeddingsproblematiek (1 * 2 semesteruur).

Dit zij een college met een veel meer encyclopaedische inslag, waarin de adresseringsproblematiek en technieken om deze problematiek op te lossen centraal staan. Onderwerpen als onafhankelijke vertaling, segmentering, linking, gemeenschappelijke bibliotheek, stacks, displays, co-routines e.d. dienen hier aan de orde te komen. Deze stof wordt thans gedeeltelijk gedekt door het huidige college Informatica I en het college Operating Systems. De bedoeling van dit college is om een gedeelte van de kennis en de begrippen aan te dragen om een computer systeem op zijn adequaatheid te taxeren. Dit college moet nog worden opgezet, het zal heel moeilijk zijn de stof op het vereiste niveau en voldoende samenhangend te presenteren.

4. Representatietechnieken (1 * 2 semesteruur).

De bedoeling van dit college is om de studenten vertrouwd te maken met de diverse technieken van afbeelding van abstracte informatiestructuren (strings, matrices, lijsten, grafen, meer-dimensionale objecten, naamlijsten e.d.) op geheugenstructuren, zoals linked lists, hash-coding etc. Deze stof wordt thans gedeeltelijk bestreken door de colleges Informatica II en III. Omdat dit college Representatietechnieken tamelijk enceclopaedisch gedacht is, lijkt bij nader inzien de kans op overlapping met de voorzetting van de Inleiding tot de Kunst van het Programmeren aanmerkelijk kleiner dan we aanvankelijk even dachten. Het zal wederom heel moeilijk zijn de stof op het vereiste niveau en voldoende samenhangend te presenteren.

5. Syntactische Technieken (1 * 2 semesteruur).

De bedoeling van dit college is om de student te leren zijn talen zo te ontwerpen, dat diverse aspecten van de mechanische tekstverwerking (parsing, generating, "back-on-the-rails", type-checking) gemakkelijk mogelijk worden. De terugkoppeling op taalontwerp zij het hoofdmotief van dit college. Het is nadrukkelijk de bedoeling de uitgebreide catalogus van bestaande parsing technieken (meestal voor talen, die nooit ontworpen hadden moeten worden) met dit college buiten de deur te houden. Dit college zal geheel nieuw moeten worden opgezet, over de beschikbare kwaliteit van dit college maken wij ons niet de meeste zorgen, het is evenwel denkbaar, dat de stof zich laat reduceren, zodat het voor 2 semesteruur wat te weinig wordt.

6. Axiomatisering van Semantiek (1 * 2 semesteruur).

De bedoeling van dit college is
1)     studenten vertrouwd te maken met axiomatische definitie van de semantiek van programmeertalen (ten gunste van mechanistische)
2)     allerlei bruikbare stellingen —die in de Inleiding tot de Kunst van het Programmeren intuitief ten tonele gevoerd zijn— nu rigoreus af te leiden
3)     waar mogelijk de consequenties van het voorafgaande ten aanzien van taalontwerp te trekken.

Vergeleken met wat we nu doen is dit een helemaal nieuw college, maar we verwachten, dat er over een a twee jaar voldoende stof voor is.

7. Informatiebeheer (1 * 2 semesteruur).

De bedoeling is de studenten vertrouwd te maken met de moeilijkheden, die bij het bespelen van grote gegevensbestanden optreden en met de methoden die worden toegepast om aan deze moeilijkheden het hoofd te bieden. Wij zouden erg graag zien, dat in dit kader aan "error recovery" op een meer systematische manier aandacht zou worden geschonken, dan wij tot op heden kunnen. Wij verwachten helaas niet, dat aan deze vrome wens binnen een jaar voldaan kan worden. Dit college beschouwen wij als de continuering, resp. ontwikkeling van het huidige college Informatica II.

8. Parallellisme (1 * 2 semesteruur).

Dit college beschouwen wij als de continuering, resp. ontwikkeling van het huidige college Operating Systems. Doordat een gedeelte van de thans descriptieve functie van dit college door het college "Inbeddingsproblematiek" wordt overgenomen, wordt er ruimte geschapen voor de behandeling van een ruimere categorie synchronisatieproblemen, b.v. tussen via boodschappen communicerende machines.

Als onderwerpen voor keuze colleges zijn genoemd LISP, SNOBOL, Petri netten, Complexity Theory, Ontwerpmethodologie, Bootstrapping en Informatietheorie.

2 october 1972 | prof.dr.Edsger W. Dijkstra

transcribed by F. Koenders
revised Thu, 13 Nov 2008

EWD356

Advanced Course on Computer Systems Architecture. (Grenoble, December 1972)

Summary of the talks on “Programming Methodology” by Edsgar W.Dijkstra.

The talks will deal with five main subjects:

1)  On the Necessity of Correctness Proofs.

2)  On the Mathematical Structure of Correctness Proofs.

3)  On the Feasibility of Correctness Proofs.

4)  On the Impact of Correctness Concerns on System Structure.

5)  On the lmpact of Correctness Concerns on the Process of Program Composition.

Ad 1. This is a very short section the moral of which can be summed up by the observation that program testing can be a very effective means for demonstrating the presence of bugs, but is a hopelessly inadequate method for showing their absence. As a result, correctness proofs remain as the only alternative by means of which we can hope to reach the required confidence level.

Ad 2. For sequential programs an axiomatic definition of semantics will be proposed that can serve as a mathematical basis for correctness proofs. For the most practical tool, this experience will be carried over to co-operating sequential processes, with “mutual exclusion” as the logical corner stone. The problems of deadlock and of individual starvation are introduced as the parallel programming analogue of the termination problem.

Ad 3. When “in principle” correctness proofs can be given, we still have the obligation to arrange matters in such a way that they can also be given in practice. This is no trivial obligation, because without special precautions, the necessary amount of manipulation —be it formal or informal, be it mechanized or done by hand— required for the correctness proofs will explode for all but the most simple systems. Abstraction will be presented as a method for arranging our thoughts in such a manner that the practical feasibility of correctness proofs is not unnecessarily impaired. It will become apparent that the purpose of abstraction is not to be vague, but to create a new semantic level at which we can be absolutely precise. It will also become apparent that, if the method is to be practical at all, the system write-up should reflect the abstractions in terms of which we can continue to understand what we are designing.

Ad 4. The abstractions introduced serve to understand the possible behaviour of the system and therefore we must require that they admit a sufficiently truthful implementation. By way of illustration it will be shown how certain hardware features impair the achievable truthfulness to such an extent that we may question whether equipment with such properties admits intelligent use at all. Apart from truthfulness of the implementation we require a form of robustness, excluding the situation in which the data, on which individual basic assertions about system behaviour rely, are scattered all through the system. By way of illustration, hardware features violating this second requirement will also be given.

Ad 5. The one impact of correctness concerns on the process of program composition is that our basic software has to satisfy requirements analogous to the ones that in the previous section we imposed upon hardware. Besides that we shall show some of the formal techniques by means of which the process of program composition can he aided very effectively, formal techniques that allow us to derive from the requirements a program satisfying the correctness proof (salvo errore et omissione) automatically.

EWD 361

Programming as a discipline of mathematical nature

by Edsger W. Dijkstra

In this article I intend to present programming as a mathematical activity without undertaking the arduous task of supplying a definition of "mathematics" pleasing all mathematicians, nor of defining "programming" in a way that is palatable to all programmers.

With respect to mathematics I believe, however, that most of us can heartily agree upon the following characteristics of most mathematical work:

Compared with other fields of intellectual activity, mathematical assertions tend to be unusually precise.

Mathematical assertions tend to be general in the sense that they are aplicable to a large (often infinite) class of instances.

Mathematics embodies a discipline of reasoning allowing such assertions to be made with an unusually high confidence level.

The mathematical method derives its power from the combination of all these characteristics; conversely, when an intellectual activity displays these three characteristics to a strong degree, I fell justified in calling it "an activity of mathematical nature", independent of the question whether its subject matter is familiar to most mathematicians. In other words, I grant the predicate "mathematical nature" rather on the "quo modo" than on the "quod".

A programmer designs algorithms, intended for mechanical execution, intended to control existing or conceivable computer equipment. These -usually electronic- devices derive their power from two basic characteristics. Firstly, the amount of information they can store and the amount of processing they can perform in a reasonable short time are both large beyond imagination. And as a result, what computers could do for us has outgrown its basic triviality by several orders of magnitude. Secondly, as executors of algorithms, they are reliable and obedient, again beyond imagination: as a rule they indeed behave exactly as instructed.

This obedience makes heavy demand on the accuracy with which the programmer has instructed the machine; if the instructions were to produce non-sense, the machine will produce non-sense. Inexperienced programmers often blame the machinery for its strict obedience, for the impossibility to appeal to the machine's "common sense"; more experienced programmers realize that it is exactly its strict obedience that enables us to use it reliably, to forge it into a sophisticated tool that we would never be able to build if the executor of our algorithm had the uncontrolled freedom to interpret our instructions in "the most plausible way". As a result, the competent programmer does not regard precision and accuracy as mean virtues: he knows that he could not work without them.

His work is also always "general" in the sense that each program is able to evoke as many different computation as we can supply it with different input data. Whenever we make an assertion about a program, it is an assertion about the whole class of possible computations that could be evoked under control of it and "designing an algorithm" is nothing more nor less than "designing a whole class of computations". So the programmer's work also shares the second characteristic.

Finally, what about the confidence level of his work? Well, it should be very high for two reasons. Firstly, a large sophisticated program can only be made by a careful application of the rule "Divide and Conquer" and as such consists of many components, say N; if, however, p is the probability of an individual component being correct, then the probability P of the whole aggregate being correct satisfies something like P ≤ pN. In other words, unless p is indistinguishable from 1, for large N the value P will be indistinguishable from zero! If we cannot design the components sufficiently well, it is vain to hope that their aggregate will work at all. Secondly, its confidence level should be very high if we, as society, would like to rely upon the performance of the algorithm. And we do, when we use machines for air traffic control, banking, patient care in hospitals or earth-quake prediction.

Now honesty compells me to admit that today, on the average, the confidence level reached by the programming profession is not yet what it should be, on the contrary!

From a historical point of view this sorry state of affairs is only too understandable. The tradition of programming is very young and has still many traceable roots in the recent past, when machines were still rather small and programming was not yet such a problem. (Before we had machines, programming was no problem at all!) But in the last ten to fifteen years, the power of available machinery has grown at least with a factor of a thousand, thereby completely changing the scope of the programming profession. But old habits seldom die!

The old technique was to make a program and then to subject it to a number of testcases where the answer was known; and when the testruns produced the correct result, this was taken as a sufficient ground for believing the program to be correct.

But with growing sophistication, this assumption proved more and more to be unjustified until, some five years ago, it surfaced in the form of "the software crisis". One of the first considerations of what was later to emerge as "programming methodology" was this question of the confidence level: "How can we rely on our algorithms?"

An analysis of the situation quite forcibly showed that program testing can be used very convincingly to show the presence of bugs, but never to demonstrate their absence, because the number of cases one can actually try is absolutely negligible compared with the possible number of cases. The only way out was to prove the program to be correct.

The suggestion that the correctness of programs could and should be established by proof was met with a great amount of scepticism. (In the mean time, many older people had already accepted as a Law of nature, that each program is bound to contain bugs!) The skepticism, however, was not without reason.

To start with, it was not clear what form such correctness proofs could have. You cannot build a proof on quicksand, you must have axioms, in this case an axiomatic definition of the semantics of the programming language in which the program has been expressed. It was only after a few efforts that a technique for semantic definition emerged that could serve as a possibly practical staring point for correctness proofs.

When people then tried to give correctness proofs for existing programs, the result of that effort was very disappointing: the proofs were so long, hairy and clumsy, that they failed to convince. And also this disappointment can still be traced in the scepticism of many. But three discoveries have changed the scene since them.

The first discovery was that the amount of formal labour, needed to prove the correctness of a program could depend very heavily on the structure of the program.

The second discovery was that of a few useful theorems about program constructs and thanks to them we no longer need to go all the way back to the axioms all the time.

The most drastic discovery, however, was the last one, that what we then tried, viz. to prove the correctness of a given program, was in a sense putting the cart before the horse. A much more promising approach turned out to be letting correctness proof and program grow hand in hand: with the choice of the structure of the correctness proof one designs a program for which this proof is applicable. The fact that then the correctness concerns turn out to act as an inspiring heuristic guidance is an added benefit.

If I ended this article with the above optimistic note I could create the wrong impression that now the intrinsic difficulties of programming have been solved, but this is not true: the best I can say is that now we have a better insight in the nature of the difficulties of the programming task than a few years before. In my closing paragraphs I hope to convey this nature, at the same time sketching the intellectual demands made upon the competent programmer.

A programmer must be able to express himself extremely well, both in a natural language and in the formal systems. The need for exceptional mastery of a natural language is twofold. Firstly it is not uncommon that e.g. English is the language in which the problem is communicated to him and in which he must describe his interpretation or modification of the problem. This circumstance has been a source of many misunderstandings to the extent that there is a wide-spread belief that e.g. English by its very nature is inadequate for the communication task. I don't believe it (although sloppy English certainly is!), on the contrary: I always have the feeling that our natural language is so intimately tied with what we call understanding that we must be able to use it to express what we have understood. Secondly, we should not close our eyes for the fact that formalization, in a sense, is always "after the fact" and that therefore natural language is an indispensable tool for thinking, in particular when new concepts have to be introduced. And this is what a programmer has to do all the time; he has to introduce new concepts --not occurring in the original problem statement-- in order to be able to find, to describe and to understand his own solution to the problem. For instance, when asked to construct a detector, analysing a string of characters for the occurrence of an instance of the --nicely formally described-- syntactic category "sentence", he may find himself led to the introduction of a completely new syntactic category "proper begin of a sentence", i.e. a string a characters that is admissible as the opening substring of a sentence but not yet a complete sentence itself. After having established that this is indeed a useful concept for the characterization of some intermediate of the computational process, he will proceed by manipulating the given formal syntax in order to derive the formal definition of this new syntactic category. In other words, given the problem, the programmer has to develop (and formulate!) the theory necessary to justify his algorithm. In the course of this work he will often be forced to invent his own formalism.

Such demands, of course, are common to most mathematical work, but there are reasons to suppose that in programming they are more heavy than anywhere else. For besides the need of precision and explicitness, the programmer is faced with a problem of size that seems unique to the programmer profession. When dealing with "mastered complexity", the idea of a hierarchy seems to be a key concept. But the notion of a hierarchy implies that what at one level is regarded as an unanalyzed unit, is regarded as a composite object at the next lower lever of greater detail, for which the appropriate grain (say, of time or space) is an order of magnitude smaller than the corresponding grain appropriate at the next higher level. As a result the number of levels that can meaningfully be distinguished in a hierarchical composition is kind of proportional to the logarithm of the ratio between the largest and the smallest grain. In programming, where the total computation may take an hour, while the smallest time grain is in the order of a microsecond, we have an environment in which this ratio can easily exceed 10⁹ and I know of no other environment in which a single technology has to encompass so wide a span.

It seem to be the circumstance sketched in the above paragraph that gives programming as an intellectual activity some of its unique flavors. The concepts he introduces must be highly effective tools for bringing the necessary amount of reasoning down to an amount of reasoning that can be done. And also the formalism he chooses must be such that his formulae do not explode in length, a regrettable phenomenon that is bound to occur unless the programmer pays conscious care to measures for avoiding that explosion. A final consequence of the hierarchical nature of his artefacts is the competent programmer's agility with which he switches back and forth between various semantic levels, between global and local considerations, between macroscopic and microscopic concerns, an ability that has been described as "a mental zoom lens". This agility is bewildering for those that are unaccustomed to it.

If --and I hope that I am fair-- I confront with this with my impression of "the standard mathematical curriculum" (whatever that may be), I come to the following differences in stress:

In the standard mathematical curriculum the student becomes familiar (sometimes even very familiar!) with a standard collection of mathematical concepts, he is less trained in introducing new concepts himself.

In the standard mathematical curriculum the student becomes familiar (sometimes even very familiar!) with a standard set of notational techniques, he is less trained in inventing his own notation when the need arises.

In the standard mathematical curriculum the student often only sees problems so "small" that they are dealt with a single semantic level. As a result many students see mathematics rather as the art of organizing their symbols on their piece of paper than as the art of organizing their thoughts.

If I have given some of my readers the first germs of the feeling that to an inventive and effective mathematician the field of programming may provide the area par excellence in which to find his challenge and bring his abilities to bear, one of my dearest wishes has been fulfilled.

Eindhoven, Technological University                                  23rd May 1973

transcribed by Jorge Andrés Pérez
revised Thu, 2 Sep 2004

EWD362

Bezoek van E.W.Dijkstra aan l’Alpe d’Huez, 8 – 15 december 1972.

Omdat ik zo kort na Sinterklaas niet over mijn hart verkrijgen kon om van mijn nieuwste kleinood afscheid te nemen, werd ik door Finair en Air Inter door de lucht zuidwaarts vervoerd, terwijl ik Stefan Zweig’s “Die Welt von Gestern” zat te lezen, een boek, waarvan hele passages, afgezien van de kwaliteit van het Duits, voor je gevoel vandaag geschreven zouden kunnen zijn. Het boek is in weerwil van zijn sereniteit nauwelijks geruststellend te noemen, integendeel: zijn beschrijving van de “democratisering” van het onderwijs in Oostenrijk na de eerste wereldoorlog —compleet met slogans uit het leven van vandaag gegrepen— is ronduit alarmerend, vooral wanneer je weet dat in 1932, een vol jaar voor de Putsch, de Duitse universiteiten in meerderheid allang voor Hitler gekozen hadden. Maar het was allemaal daar: de hervorming van het Duits, zowel het geschrevene als het gesprokene, de afschaffing van de bijzin (wat zoals bekend tot een soort heiblokstijl aanleiding geeft), de afschaffing van het “der, die, das”, de unisex-kleding en de oudere hoogleraren, die zich belachelijk maken in een verkrampte poging om al meedoend niet uitgerangeerd te worden. Weinig vermoedde ik, al opstijgend uit Parijs, hoe-snel ik aan deze passages herinnerd zou worden.

Dankzij het feit, dat ik op Schiphol de vorige nacht in hotel Frommer had geslapen, kwam ik op zaterdagmorgen zonder zenuwslopend geren en gedraaf in de Caravelle van Finair, die mij op voorbeeldige wijze naar Paris-Orly vloog. Met zorg had ik een tweetal vluchten uitgezocht, zodat ik in Parijs op hetzelfde vliegveld uit Amsterdam zou aankomen, als waarvan ik naar Grenoble zou vertrekken. Omdat ze me in Amsterdam, waar mijn bagage naar Grenoble was doorgeboekt, geen uitsluitsel konden geven over de vraag, of ik in Parijs nog aandacht aan mijn bagage moest besteden, was dit een van de eerste dingen, die ik in Parijs informeerde. Voor de zekerheid heb ik dit bij een aantal instanties geinformeerd, maar allen zeiden, dat als mijn bagage naar Grenoble was doorgeboekt, dat ik dan er niet naar hoefde om te zien. Wie schetst mijn verbazing (en ergernis, dat garandeer ik je!), toen mijn naam, vijf minuten voordat we aan boord zouden, werd omgeroepen en ik te horen kreeg, dat ik heel snel naar de douane moest rennen, om mijn koffer in te klaren! In mijn eerste poging verdwaalde ik —de instrucites, die ik gekregen had, waren natuurlijk onduidelijk en er stonden ook geen bordjes—; dus rende ik terug naar de balie, vanwaar ik weggestuurd was en heb ik een juffrouw van Air Inter zover gekregen om me naar mijn douanier te brengen. Hijgend, het laatste restje van mijn energie met vloeken verdoend, kwam ik, waarachtig met koffer en al, in het vliegtuig naar Grenoble. Ook aan deze ervaring zou ik, voordat ik heelhuids thuis was, nog eens herinnerd worden.

In het vliegtuig van Parijs naar Grenoble trof ik (zoals ik verwacht had) Brian Randell uit Newcastle en (wat ik niet verwacht had, maar wel had kunnen verwachten, want die man kom je op de meest ongelegen ogenblikken tegen), Helms uit Denemarken; Helms wist te melden, dat prof.L.Bolliet ons niet, zoals hij had toegezegd, zou komen halen, omdat hij op zondag 3 december, de dag voordat de “Advanced Course” zou beginnen, op de piste een been gebroken had: bij een val had een van de skis niet goed losgelaten. Gelukkig was er een taxi, en naarmate de reis naar Alpe d’Huez vorderde, begon ik het eigenlijk steeds prettiger te vinden, dat niet Bolliet, maar een professionele chauffeur ons naar boven loodste: de weg werd steeds steiler, de haarspeldbochten werden werden steeds scherper en tot overmaat van ramp kwamen we in een dichte mist, die het zicht tot enkele meters reduceerde. Met mijn kijker in mijn koffer (“om van de vergezichten te genieten”) begon ik me knap belachelijk te voelen! Maar ziet: enkele meters voor de laatste haarspeldbocht waren we plotseling uit de wolken en reden we door een fascinerend sneeuwlandschap!

De, ik zal maar zeggen, “winterschool” werd juist voor de opening van het seizoen gehouden, het dorpje was grotendeels nog bezig, uit zijn zomerslaap te ontwaken. Er was al wel wat sneeuw, hoewel men zich over de hoeveelheid ernstig zorgen maakte en eigenlijk niet goed zag, hoe men “de kerstdagen door zou moeten komen”. (De vorige keer, dat ik ’s winters in Grenoble geweest ben was in dezelfde tijd van het jaar; toen was het vlak voor de Olympische Winterspelen en toen lagen ze ook over een tekort aan sneeuw in de zenuwen!) De helft van de liften waren operationeel en blijkens Bolliet’s ervaring lag er genoeg sneeuw om een been te breken. Dit was mijn eerste bezoek aan een wintersportplaats; als het aan mij ligt, zal het ook mijn laatste zijn. De hele klont gebouwen tegen de berghelling trof mij in zijn ontoegankelijkheid als een soort derderangs Shangri-La en in het hotel was niet eens een piano. Daarenboven bekwam de plotselinge verplaatsing naar de ijle lucht mij slecht.

Het officiele programma van de winterschool was zwaar: ’s morgens van negen tot half een drie voordrachten van een uur, en laat op de middag (om cursisten de gelegenheid te geven hun been te breken) van vier tot zeven/ half acht weer drie voordrachten. Ik moest drie keer ’s morgens om negen uur spreken, wat over het algemeen een bijzonder prettig ogenblik was. Verder heb ik van de cursus niet zo erg veel voordrachten meegemaakt (over de rest van het programma moeten Rem en Keulers maar berichten), want ik werd ziek. Is het Franse eten altijd al een aanslag op mijn spijsvertering (ik ben traditioneel een willig slachtoffer van “Napoleon’s revenge”), in l’Alpe d’Huez heerste een epidemie, die zelfs Italianen velde! Ik ben een nacht, van middernacht tot vier uur ’s morgens, zo ontzettend beroerd geweest, dat ik eigenlijk nog maar een gebed had “Breng me naar huis en laat me daar sterven.” IJlend zag ik visioenen van Rem en Keulers, als geimproviseerde ziekenbroeders mij tussen zich indragend... Maar na vieren zakte de koorts en om negen uur heb ik —gesterkt door een glas melk, dat er gedurende de lezing in is gebleven— hoewel ik me vanbinnen helemaal geel voelde, mijn voordracht gehouden. Dat ging goed, maar de rest van die dag heb ik wel in bed doorgebracht, en daags daarna was het leven ook nog heel voorzichtig.

Van collegae hoorde ik verhalen uit andere Europese universiteiten, die natuurlijk allemaal met hetzelfde gedonder zitten, vaak waarschijnlijk nog geprononceerder dan wij in Eindhoven. Uit de verhalen, die ik hoorde, werd ik —ik merkte dat bij mijzelf plotseling— emotioneel verplaatst naar een sfeer, die ik beangstigend goed herkende en me herinnerde: de oorlogsjaren! Er heerst heel duidelijk een sfeer van “bezetting” en verhalen, die ik hoorde, kan ik niet anders beschrijven, dan dat wetenschap en cultuur in de illegaliteit onderduiken, om om ’s landswil geprepareerd te zijn, wanneer deze democratiseringsrazernij eenmaal is uitgewoed. Toen ik de opmerking maakte, dat die illegaliteit mij aan de oorlogsjaren deed herinneren, viel Bauer uit M¸nchen me bij met de opmerking, dat hij het recente gedrag van z.g. radicale studenten ook maar al te goed van vroeger kende ... van de S.A. Iedereen uitte zich voorzichtig; het was waarschijnlijk juist deze voorzichtigheid, die een en ander zo onheilspellend maakte.

Wachten tot de razernij is uitgewoed en kijken, wat er dan over is .... Waar een en ander b.v. in Duitsland toe leidt, heb ik in een gesprek met Bauer alleen ontdekt, toen ik er mijn verwondering over uitsprak, dat nog geen Duitse universiteit op het idee is gekomen om C.A.Petri, die per slot van rekening al meer dan tien jaar bekend is als een van Duitsland’s indringendste denkers op het gebied van automatische informatieverwerking, een hoogleraarsplaats aan te bieden. Met alle respect voor Petri werd mij uitgelegd, dat dit in het huidige bestel absoluut onmogelijk was, omdat de machinerie alleen soortgelijke mensen tolereerde, waarover de onderwijs-(en intrigue-)last verdeeld kon worden, en geen ruimte meer toestond voor de wetenschappelijke eenling , hoe begaafd ook. Belangrijker dan wat iemand doet, schijnt te worden “dat hij samenwerkt met anderen”. Ik kon niet nalaten tegenover Bauer op te merken, dat mijn Anglophilie voor een groot gedeelte is terug te voeren op (goedwillende en vaak ietwat vertederde) tolerantie van de Engelse maatschappij jegens de excentricus: ik vind dat een van de bijzonderste eigenschappen van de Engelsen. Bauer was het met me eens, er droevig aan toevoegend, dat tolerantie nu nooit een erg opvallende Duitse deugd geweest was....

Specifiek op het gebied van de informatica is er ook nog wel wat te vertellen. Ten eerste, dat het “International Institute for Software Engineering” er wel niet zal komen. Gode zij dank! Eind 67, begin 68, toen de Duitse regering voor de informatica nog geen cent over had, ja het vakgebied nog niet eens ontdekt had, was er om intern Duitse redenen pressie voor zo’n instituut. Inmiddels is de Duitse regering helemaal omgeslagen, met het gevolg, dat de Duitse universiteiten helemaal geen interesse in een dergelijk instituut meer hebben. Dan zijn de vertragingsacties van Engeland en Nederland (in weerwil van van der Poel) toch ergens goed voor geweest, want anders zaten we misschien met een organisatie opgescheept, waarvoor geen geld, geen mensen en geen doel meer was. Dit was een mooi bericht.

Een in mijn ogen even mooi bericht is het doodbloeden van ALGOL 68, waarvan speciaal in München, dat als loyaal partner is begonnen, zich steeds meer mensen afkeren. Het zou mij niet verbazen, als in Europa die kous binnen een jaar af was; je moet alleen vurig hopen, dat niet allerlei onderontwikkelde landen zich door het IFIP-stempel laten verblinden en dat over vier jaar niet Oeganda het ALGOL 68 rapport in twintig negertalen blijkt te hebben vertaald. Op het zelfde niveau lag het gerucht —ook al eerder gehoord, maar nu met wat meer klem—; dat IBM van de “unbundling” gebruik wilde maken, om zijn onvoorwaardelijke steun aan PL/I zo niet te ontnemen, dan toch wel te temperen. Het ligt voor de hand, want de investering, die er tot nog toe in gegaan is, is buiten proportie, gemeten naar de bruikbaarheid (en daarmee “de gebruiktheid”) van het product. Als ze hier op een (naar hun standaard gemeten!) “nette” manier vanaf kunnen, zullen ze het niet laten.

Verder kan gemeld worden, dat de explosieve groei van het informatica onderwijs, zoals dat in Frankrijk, Duitsland en Italie door de overheid gestimuleerd wordt, het vak dreigt te vermoorden. Bauer is met de tegenaanval begonnen en heeft in München een numerus clausus bereikt, heeft tevens bereikt, dat het aantal universiteiten, dat met informatica zal beginnen, drastisch kleiner is, dan aanvankelijk in veler bedoeling. Grasselli in Pisa is minder gelukkig, hij is in dezelfde situatie als wij en moet ook elke student nemen. Hier is het aantal studenten in de informatica opgelopen tot 1700 en van de opleiding is, voorzover hij iets heeft voorgesteld, niets meer over. Hoe de situatie in Frankrijk is, heb ik beleefdheidshalve niet aan mijn gastheer gevraagd: van Alain Martin hadden we een indruk van Grenoble, die onlangs door enige studenten bevestigd werd. In l’Alpe d’Huez is een hoogleraar uit Parijs opgetreden en dit is zo slecht geweest,dit kunnen andere mensen geloof ik zich helemaal niet voorstellen. Arme studenten! Er worden dikke pagina’s toegevoegd aan de Aanklacht wegens Fraude, die eens zal worden uitgebracht tegen het Europese Hogeronderwijs.

Op de terugreis miste ik in Orly bijna mijn aansluiting, omdat ik ... verkeerde inlichtingen had gekregen, op de verkeerde plaats zat te wachten en uiteindelijk (met de sandalen in hand!) naar de andere kant van het vliegveld moest rennen! Eerlijkheidshalve moet gezegd worden, dat,eenmaal in het vliegtuig gezeten, ik voor het eerst bij zo’n gelegenheid gerookte zalm heb gekregen en de piloot van Air France, toen hij de Caravelle (toch zo’n prettig vlieg tuig!) in Schiphol aan de grond zette, zorgde voor de mooiste landing, die ik ooit heb meegemaakt.

| Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 01-Dec-2011

EWD363

Reisverslag E.W.Dijkstra: Open House on Semantics, Aarhus, 7–18 jan.1973.

Om in januari per vliegtuig —uit de aard der zaak via Kopenhagen— van en naar Aarhus te willen reizen, is vanwege mist altijd een hachelijke zaak, maar zowel heen als terug hebben alle vliegtuigen, waar ik gebruik van maakte, op de minuut gevlogen. Desalnietemin is het altijd weer een hele geruststelling om op het afgesproken ogenblik weer thuis te zijn.

Toen ik voor het "Open House on Semantics" in Aarhus arriveerde, voelde ik me lichtelijk opgelicht, want van het dozijn mensen, van wie Svejgaard me telefonisch had meegedeeld, dat ze ook werden uitgenodigd —en op grond van wier namen ik de uitnodiging had aangenomen— heb ik alleen Peter Naur gezien, en dat dan nog maar voor twee dagen. Ziende, wat voor mensen er dan wel gekomen waren (en wat voor titels ze voor hun voordrachten hadden opgegeven) werd ik wel bevreesd, dat door de bank genomen het gezelschap zich niet erg aan het officiele onderwerp zou kunnen houden, een vrees die bewaarheid werd. De keerzijde van een dergelijke teleurstelling is natuurlijk dat je eens met nieuwe mensen in aanraking komt —doorgaans is dat een teleurstelling, want hoewel ik langzamerhand beter moest weten, zijn mijn verwachtingen eigenlijk altijd te hoog gespannen— en zowaar, dit keer was daar een heel leuke jongen bij, een medewerker van Strachey uit Oxford; dat maakte een hoop goed, en als die er niet geweest was, had ik waarschijnlijk het ogenblik van de terugreis vervroegd. Ten tweede is zo iets natuurlijk een aanleiding om naar een serie voordrachten te gaan luisteren, waar je op eigen initiatief van je leven niet naar toegegaan zou zijn (zoals lezingen over de standaardisering van PL/I of de implementatie van wat ik nog steeds "van Wijngol" noem, maar in de wereld onder de naam ALGOL 68 gebracht wordt; het was een teleurstelling voor mij te ontdekken, dat dit in Cambridge was aangeslagen, maar in Cambridge zijn de laatste jaren wel meer rare dingen gebeurd....)

De enige verdere bekende was Martin Richards, de ontwerper van BCPL; het was best gezellig, die weer te ontmoeten, het is een aardige en knappe jongen, die eerste-klas werk gedaan heeft en wiens Engels een verademing is om naar te luisteren. In de vorige alinea is het al een beetje tussen de regels doorgesiepeld: de grootste indruk, die dit open house op mij gemaakt heeft is ... het enorme verschil in geestelijke klimaat tussen de computing science in Oxford en de computing science in Cambridge. (Het is natuurlijk een beetje gek, dat je naar Jutland moet gaan om dat te ontdekken, het zij zo.) Ik kan hier maar een verklaring voor geven: Oxford heeft Christopher Strachey en Dana Scott en Cambridge heeft ze niet.(En erger misschien: heeft een grijzende Wilkes, wiens aanwezigheid enige frisse wind misschien wel verhindert.) Kortom, ik vond Cambridge een beetje blijven hangen in wat in de eerste helft van de zestiger jaren "issues" waren; er was nog een man uit Cambridge, en ook die maakte de indruk van een "bit-fiddler". Martin Richards is natuurlijk een heel knap en veelzijdig implementator, maar als ze zo doorgaan komt er uit Cambridge voor de komende jaren geen bladzij theorie en naar hun spelletjes, hoe virtuoos ook, wil straks geen hond meer luisteren. Ik vind het voor Cambridge een beetje triest, eigenlijk heeft het de glorie van de EDSAC 1 als een uit de historie overgebleven blok aan het been. Toen TITAN door een IBM 360 werd opgevolgd, was dat natuurlijk al een heel veeg teken.

Ik heb drie keer twee uur gesproken, de eerste keer over de axiomatische methode van Hoare, de tweede keer over de toepassing ervan bij sequentiele programma's en de derde keer over de toepassing ervan bij parallele programmering, althans dat was de bedoeling, maar het vijfde uur was een absoluut debacle: ik had mijn notatie gewijzigd en verstrikte me in de propositional calculus. De eerste vier waren gelukkig heel goed gegaan en ik had in het zesde nog de gelegenheid, iets van de scherven van het voorafgaande uur bijeen te vegen. Ik vond het een bijzonder moeilijk publiek om toe te spreken; ik heb het er met een paar mensen over gehad —wat oudere Denen en een jonge Zwitser, die er nu een paar jaar zat— en men weet het een de recente normenverschuivingen, waarvan ook Denemarken niet verschoond is gebleven. (Ook Denemarken heeft zijn WUB!) Het resultaat was een absoluut passief lijkend publiek, ze applaudiseren niet, ze roepen geen boe, ze stellen geen vragen, ze zitten er als geduldige sponzen bij. Vooral de afwezigheid van vragen en opmerkingen —en dat was niet alleen bij mij zo, daar hadden we allemaal last van— was hoogst hinderlijk; en de verklaring kan niet gezocht worden in gebrek aan beheersing van het Engels, want als je even met ze aan de praat raakte, merkte je dat hun Engels heel voldoende was. Is het een symptoom van "niet opvallen", alles doen wat je buurman doet? Een van de verklaringen die me werd gegeven, was dat we nu allemaal zo "equal" waren, dat een discussie, die deze idylle zou kunnen verstoren, tegen elke prijs vermeden moest worden, als sociaal aanstoogevend incident.

Van de wetenschappelijke activiteiten van Aarhus heb ik niet veel indruk gekregen; door historische omstandigheden zijn ze nogal gericht op hardware onderzoek en ze bouwden minicomputertjes op printed circuits ter groote van een schoolschrift. Daar kan je natuurlijk een heleboel medewerkers mee bezighouden, en zo'n ding testen is natuurlijk opwindend, maar ze hebben me eigenlijk niet kunnen uitleggen waarom ze het nu deden, wat ze ervan hoopten te leren. Ik had erg het gevoel, dat deze activiteit richtinggevende leiding ontbeerde. Mogelijk ging de club nog gebukt onder de afscheiding van het rekencentrum, dat hoewel in het zelfde gebouw, niet tot de universiteit behoort en dat schept toch wel een kloof, niet alleen een kloof van een paar vloeren. Sinds twee jaar werd er service gegeven —althans"probeerde men service te geven"— met een grote CDC-machine, maar het is eigenlijknauwelijks te doen. De kwaliteit van CDC's software is zo abominabel, het systeem is langzamerhand een lappendeken van "patches", er zijn ongeveer twee man constand bezig de stroom van binnenkomende reparaties te realiseren. Ze troosten zich dat het met een IBM nog erger geweest zou zijn. (In de strijd om hier een machine te plaatsen heeft IBM met de bedoeling om een machine van 13 millioen kronen te leveren, een millioen kronen in zijn "campagne" geinvesteerd, waarvan driekwart tunen aan de software om de benchmark van Aarhus er sneller doorheen te krijgen!) En toen ze de CDC-machine bijna een jaar was, hebben ze ontdekt, dat er aan de achterkant bij de bedrading een draad ontbrak, waardoor bij overbelasting van het geheugen soms een woord uit louter nullen afgeleverd werd. Het is natuurlijk heel naar, dat zoiets pas ontdekt wordt als de machine al een tijd in gebruik en door allerlei gebruikers vertrouwd is. Wat doe je als rekeninstituut in zo'n geval? Een rondschrijven aan alle gebruikers lijkt mij het aangewezene; helaas heeft het rekeninstituut besloten te proberen, dit ontbreken van de draad geheim te houden, om voor mij onnaspeurbare redenen. Ik vind het een symptoom van bederf.

De faciliteiten, die de universiteit zijn bewoners en vooral zijn gasten bood, was voortreffelijk. Zowel in het mathematische instituut als in het instituut voor computing science —intern via een trappenhuis verbonden— waren op de bovenste etage kamers en zelfs appartementen, alles met een eigen badkamer, de appartementen geloof ik zelfs met eigen keuken. Op alle gangen waren keukens met ijskasten (met bier er in), en je had het gevoel dat je koffiezetapparaten met een even grote frequentie tegenkwam als telefoontoestellen. Dit alles met leuk, stevig Deens meubilair, en nergens plastic op de zittingen! De lettertang, waarmee je in vrij hard plastic plakband opplakbare teksten drukt, was hier losgelaten op plasticband dat er uitzag als ... fineer in precies dezelfde kleur als het hout waarop ze werden geplakt! Een klein detail, dat me elk ogenblik er aan herinnerde in welk land ik was, mocht ik het voor een ogenblik hebben vergeten!

prof.dr.Edsger W.Dijkstra

transcribed by Hans Terlouw
revised Tue, 15 Dec 2009

EWD 364 - 0

Weledelgestrenge Heer, Ingenieur Swinkels,

Afstuderen is net zoiets als geboren worden en doodgaan; je doet zuk soort dingen maar één keer in je leven en daarom zijn ze een gelukwens waard. Ik feliciteer U dan ook van ganser harte met de behaalde titel van "wiskundig ingenieur", U verleend ter afsluiting van een studietijd in welker laatste gedeelte ik, als officiële afstudeerhoogleraar iets nauwer betrokken ben geweest: aan drs C. Bron, die de feitelijke begeleiding van uw afstudeerwerk gedaan heeft, zijn wij, dacht ik beiden onze dank verschuldigd en ik vertrouw ook uit Uw naam hier deze dank openlijk uit te mogen spreken, temeer daar het de laatste keer was dat hij mij deze dienst bewijzen kan.

U heeft jaren geleden gekozen voor de afstudeerrichting die sindsdien met de naam "informatica" is opgesierd. Toendat die kogel door de kerk was hebben wij een aantal met elkaar over die keuze gesproken. Wat mij in U aantrok was een slordig waarnemer voor "ongeïnterresseerdheid" zou kunnen verslijten; ik meende iets heel anders zien: nl. een ruime belangstelling, een verlangen zich liever breed te oriënteren dan zich voortijdig te totaal te indentificeren met een specialisme, dat voor de rest van een mensenleven wellicht niet genoeg intellectuele speelruimte bieden kan.

EWD 364 - 1

In Uw afstudeerperiode heeft U een implementatie ontworpen en gerealiseerd voor de programmeertaal TRAC, waarbij U, omdat het een conversationele programmeertaal betreft, direct kon voortbouwen op het afstudeerwerk van ir. J.J. van Amstel. Om een afstudeerder aan een redelijk groot project te zetten is altijd een zeker risco, in Uw geval is het risico niet te groot geweest, wij beschouwen Uw werk om een aantal redenen met succes bekroond. Ten eerste, omdat Uw implementatie werkt. Ten tweede omdat Uw implementatie een qua opbouw een heel nette indruk maakt. Maar het derde punt is het belangrijkste: ik geloof dat U een heleboel geleerd hebt. Het was Uw eerste "grote" programma, en daar leer je natuurlijk altijd van, maar U hebt meer geleerd dan onder dergelijke omstandigeheden onvermijdelijk is: U hebt nl. tevens geprobeerd opbouw en overwegingen te documenteren, en in die poging hebt U ervaren, dat zulks verre van triviaal is omdat je je eigen uitdrukkkingsmiddel daarvoor scheppen moet.

De ijver en toewijding waarmee U gewerkt hebt geven mij vertrouwen voor Uw toekomst, waarin de beste wensen U begeleiden.

Ir. Swinkels, nogmaals mijn hartelijke gelukwensen.

Transcribed by Michiel Duvekot.

Last revision: Tue 26 Aug 2003.

EWD365

A Parabel

"Years ago a railway company was erected and one of its directors --probably the commercial bloke-- discovered that the initial investment could be reduced significantly if only fifty percent of the cars would be equipped with a toilet and, therefore, so was decided.

"Shortly after the company had started its operations, however, complaints about toilets came pouring in. An investigation was carried out and showed that the obvious thing had happened: despite its youth the company was already suffering from internal communication problems, for the director's decision on the toilets had not been transmitted to the shunting yard where all cars were treated as equivalent and, as a result, sometimes trains were composed with hardly any toilets at all.

"In order to solve the problem, a bit of information was associated with each car, telling whether it was a car with or without toilet and the shunting yard was instructed to compose trains with the number of cars of both types as equal as possible. It was a complication on the shunting yard but, once it had been solved, the people responsible for the shunting procedures were quite proud that they could manage it.

"When the new shunting procedures had been made effective, however, complaints about the toilets continued to come in. A new investigation was carried out and then it transpired that, although in each train about half of the cars had indeed toilets, sometimes trains were composed with nearly all toilets in one half of the train. In order to remedy the situation, new instructions were issued, telling that cars with and cars without toilets should alternate. This was a more severe complication for the shunting people, but after some initial grumbling, eventually they managed.

"Complaints, however, continued and the reason turned out to be that, as cars with a toilet had a toilet at one of their ends, the distance between two successive toilets in the train could still be nearly three car lengths and for mothers with children in urgent need --and perhaps even luggage piled up in the corridor-- this still could lead to disasters. As a result, the cars with toilets got another bit of information attached to them, making them into directed objects and the new instructions were, that in each train the cars with toilets should have the same orientation. This time the new instructions were received with less than enthusiasm, for the number of turntables was hardly sufficient; to be quite fair to the shunting people we must even admit that according to all reasonable standards, the number of turntables was insufficient and it was only by virtue of the most cunning ingenuity that they could just manage.

"With all toilets equally spaced along the train the company felt confident that now everything was all right, but passengers continued to complain: although no passenger was more than a car length away from the nearest toilet, passengers (in urgent need) did not know in which direction to start their stumbling itinerary along the corridor! To solve the problem, arrows saying "TOILET" were fixed in all corridors, making also the other half of the cars into directed objects that should be properly oriented by the shunting procedures.

"When the new instructions reached the shunting yard, they created an atmosphere ranging from despair to revolt: it just couldn't be done! At that critical moment a man whose name has been forgotten and shall never be traced, made the following observation. If each car with a toilet was coupled, from now until eternity, at its toileted end with a car without a toilet, then, from now onwards, the shunting yard, instead of dealing with N directed cars of two types, could deal with N/2 identical units that to all intents and purposes could be regarded as symmetrical. And this solution solved all shunting problems at the modest price of, firstly, sticking to trains with an even number of cars only --the few additional cars needed for that could be paid out of the initial savings effected by the commercial bloke!-- and, secondly, slightly cheating with regard to the equal spacing of the toilets. But after all, who cares about the last three feet?

"Although at the time that this story took place, mankind was not blessed yet with automatic computers, our anonymous man who found the solution deserved to be called the world's first competent programmer."

I have told this story to different audiences. Programmers as a rule are delighted by it and managers, invariably, get more and more annoyed as the story progresses; true mathematicians, however, fail to see the point.

transcribed by Kevin Hely
revised Mon, 7 Jun 2004

EWD366

Waarom ik niet gewoon hoogleraar wil blijven.

Het volgende is als persoonlijke verantwoording geschreven; de openbaarheid hiervan is ingegeven door de overtuiging, dat ik hiermee de gevoelens van menig collega vertolk.

Toen ik bijkans elf jaar geleden voor het hoogleraarsambt werd aangezocht, heb ik de uitnodiging niet zonder gevoel van opwinding, maar ook met een aanzienlijke hoeveelheid lood in de schoenen aanvaard: in het waardenpatroon waarin ik was opgevoed, werd van een hoogleraar iets bijzonders verwacht. Zo herinner ik me nog, dat ik na mijn oratie wat gechoqueerd was door de velen, die mij feliciteerden in de trant van dat ik het nu "so herrlich weit gebracht" had, terwijl het voor mijn gevoel allemaal nog beginnen moest en ik herinner me bij die gelegenheid in dankbaarheid mijn moeder, die me helemaal niet feliciteerde, maar terzake opmerkte "Nou jong, je ziet maar, dat je het waar maakt!".

lk heb mijn best gedaan en na een inloopperiode mij als een vis in het water gevoeld; helaas moet ik nu constateren, dat het water het water niet meer is. Een symptoom is, dat er nu allerlei hoogleraren worden aangetrokken van wie niet iets bijzonders verwacht wordt door hun omgeving en die voor zichzelf een dergelijke plicht ook nauwelijks erkennen. Dit is triest, maar lijkt met de massificatie van het hoger onderwijs lijkt het onvermijdelijk en dan is het vruchteloos om er over te treuren. Het wordt evenwel alarmerend, wanneer de tekenen er op wijzen dat van een hoogleraar iets bijzonders straks niet eens meer getolereerd zal worden! En helaas wijzen de voortekenen onmiskenbaar in die richting. Het is al een aantal jaren geleden, dat een mijner collegae meende te moeten opmerken, dat er twee soorten hoogleraren waren, enerzijds zij die zich voor de TH opofferden en daardoor aan wetenschappelijke productie niet toekwamen en anderzijds de profiteurs, die hun plichten jegens de TH verzaakten om tot grotere glorie van zichzelf artikelen te kunnen publiceren.

In de democratiseringsgolf, die uiteindelijk in de WUB uitmondde, is wat al tijden sluimerde, aan de oppervlakte gekomen. Antoine de Saint-Exupéry heeft opgemerkt, dat de mensheid met de woorden van gisteren vandaag plannen voor morgen moet maken; in het hoger onderwijs, zoals ik dit aantrof, was dit dilemma levensgroot aanwezig. Het universitaire bedrijf werd begrepen, bestuurd en besproken in termen, idealen en begrippen, die grotendeels stevig geworteld waren in de negentiende eeuw: wij dienden de wetenschap en daarmee basta. En wie nog niet gepromoveerd was, telde nog niet mee, en daarmee basta. En het proefschrift moest een proeve zijn van origineel, zelfstandig wetenschappelijk werk, en daarmee basta. Dat inmiddels door de massificatie van het hoger onderwijs een steeds groter gedeelte van de studentenbevolking noch de gaven, noch de aspiraties had om tot beoefenaar der wetenschap opgeleid te worden, werd zo goed en kwaad als het ging door de mantel der liefde bedekt; om de waardering voor de wetenschappelijk niet productieve maar overigens goede docent tot uiting te brengen, waren geen termen aanwezig en de promotieriten voorzagen niet of nauwelijks in de mogelijkheid, wetenschappelijk werk te honoreren, dat in een groter team dan provendus en promotor tot stand gekomen was. Dat het academisch bedrijf geperst bleef in een stramien van waarden, waarin een zwijgende meerderheid het niet verder brengen kon dan stilzwijgend getolereerde verschoppeling, heeft naar zich denken laat tot onhoudbare spanningen aanleiding gegeven, spanningen, die zich moesten ontladen: de zwijgende meerderheid heeft van zich laten horen. En hoe!

Het verbazingwekkende gemak, waarmee hele senaten destijds over stag zijn gegaan, trof mij in mijn eerste onschuld als een laf zwichten voor studententerreur en ik herinner me te hebben moeten denken aan 't stuurmanschap, dat, om te voorkomen, dat de dijken doorbreken, zelf de dijken tijdig doorsteekt. Bij nader inzien geloof ik, dat hiermee aan de terreur, hoe abject en gevaarlijk ook, teveel eer is gegeven en dat de studententerreur ten hoogste een lont in het kruitvat is geweest: in alle groepen, waarin de hoogleraar niet duidelijk met kop en schouders boven zijn medewerkers uitstak, was voor de medewerkers het recht te mogen meepraten en voor de hoogleraar het vervallen van de plicht te excelleren, een onmiskenbare bevrijding. Ik heb tenminste de stroomversnelling, die zich manifesteerde bij de tot standkoming van de WUB, toen tenslotte het gehele wetenschappelijke corps in slechts een "geleding" werd samengeveegd, niet anders kunnen begrijpen. Het zij zo.

De resulterende toestand is moeizaam, grotesk en deprimerend. Terwijl eens het ideaal was, dat in groepsbeslissingen het oordeel van de terzake meest competente het zwaarste woog, moet nu, om de gelijkheidsidylle niet te verstoren, zorgvuldig verborgen worden, dat de opinie van de een wel eens ordes beter gefundeerd zou kunnen zijn dan die van een ander. Sinds het "Mijn mening is toch net zo goed als de jouwe." tot wet verheven is, is elk openlijk appel op iemands specifieke competentie illegitiem en is elke voorzitter blij, als hij door tactvol gekozen bewoordingen althans aan de oppervlakte maskeren kan, dat een aantal participanten aan de discussie er eigenlijk voor Piet Snot bij zit. Lukt hem dat niet, dan grijpt het grauw naar de macht en wordt mediocriteit tot norm verklaard.

Het vacuum, dat ontstaan is door competentie als beslissingsgrond in de ban te doen, is opgevuld, maar helaas door politieke stellingname, een verschijnsel dat met intolerantie (om niet te zeggen: verloedering) gepaard is gegaan. Het zichtbaarste symptoom �van deze politisering is de pressie, die op een ieder wordt uitgeoefend, om alsmaar partij te kiezen, alsmaar een standpunt in te nemen en overal een mening over te hebben. Voor iemand, wiens opvoeding hem bijgebracht heeft, dat je niet hoort te praten over dingen, waar je geen verstand van hebt, is dat tamelijk weerzinwekkend. Een iets minder duidelijk, maar niet minder schadelijk effect van de politisering is de hieruit voortvloeiende vertroebeling van allerlei discussies: wie op goede gronden een zorgvuldig tot stand gekomen opinie uitspreekt, krijgt onmiddellijk een politiek standpunt in de schoenen geschoven, waarna de discussie in een hopeloze patsituatie is verzand. De goede gronden zouden deze kunnen oplossen, maar hun existentie wordt nu juist ontkend.

Het is niet de intolerantie van de extremisten, waar je het meeste last van hebt: de extremisten zijn bekend en niet erg interessant, ze vormen bovendien een minderheid. Er is een veel grotere groep van nature gezagstrouwe mensen die in onverdachte vaderlandsliefde en grote bezorgdheid oprecht proberen het hoger onderwijs voor totale ineenstorting te behoeden door de nieuwe spelregels, nu die eenmaal de kracht van wet hebben, zo serieus mogelijk in acht te nemen. Het probleem is evenwel dat hun evenwicht zo wankel, hun gemoedsrust zo broos is, dat er voor twijfel geen ruimte meer is: zij worden democraten, die zich uiterst dogmatisch opstellen.

Tot zo ver de WUB: deze betreft eigenlijk louter interne aangegenheden en het is alleen omdat hun gevolgen zo tijdrovend zijn, dat men verleid kan worden, deze als hoofdzaak te beschouwen. Belangrijker zijn de externe aspecten, met name de plaats, die het hoger onderwijs in onze maatschappij krijgt opgedrongen. Het oude ideaal was ontwikkeling en verbreiding der wetenschap, een activiteit waarin studenten betrokken werden, voorzover ze daarvoor in aanmerking kwamen; maar die tijd ligt ver achter ons. Het is duidelijk, dat in de ogen van de regering het opleidingsaspect een relatief veel groter gewicht dient te krijgen. Nu zou ik me daar van ganser harte ten volle aan wijden, als de paar duizend man, die onze collegezalen bevolken, het predicaat "keurbende" verdienden, maar dat is helaas niet het geval, integendeel! De overheid werpt geen dam op tegen de nivellerende stromingen, integendeel, zij stelt kwantiteit boven kwaliteit. Maar het niveau van het onderwijs zakt onherroepelijk met het peil van de gemiddelde student en de definitie "Een hoogleraar is iemand die valse parelen werpt voor echte zwijnen." wint dagelijks aan actualiteit. Tegen de tijd, dat de opleiding zo verwaterd is dat het de grootste moeite gaat kosten te blijven geloven in de bruikbaarheid van je afgestudeerden, wordt het hoog tijd je af te gaan vragen of "massaal hoger onderwijs" niet een contradictio in terminis blijkt te zijn. In de zinvolheid van het experiment "hoger onderwijs voor allen" heb ik mijn geloof verloren: als "democratisering van het hoger onderwijs" dát betekent, ben ik bang, dat het een euphemisme is voor "afschaffing".(iets wat overigens in radicalere kringen openlijk als ideaal beleden wordt).

Tegen de tijd, dat je je als hoogleraar ervan bewust wordt niet te kunnen geloven in de zinvolheid van wat de meerderheid als hoofdtaak van het hoger onderwijs wenst te beschouwen, is natuurlijk wel het moment aangebroken om je af te vragen of je niet beter je biezen kunt pakken. Wanneer je aarzelt, doe je dat om der wille van hen, aan wie goed onderwijs wel besteed zou zijn, die nu tot grote schade van de maatschappij helemaal niet aan hun trekken komen en die wij het onrecht aandoen hen de intellectuele uitdaging te onthouden, die voor hen een eerste levensbehoefte is. Zolang je dergelijke jongens af en toe nog tegen het lijf loopt en je iets voor hen doen kunt, is het hoogleraarsambt nog vol te houden. Het wordt evenwel steeds moeilijker ze te vinden omdat ze ten gevolge van de sterke anti-intellectuele stromingen geneigd zijn (vaak onbewust!) hun licht onder de korenmaat te stellen. (lk heb onlangs na afloop van een mondeling tentamen een student voor het eerst van mijn leven gevraagd, of hij voor zijn gevoel in zijn afdeling aan politieke pressie blootstond, niet omdat hij mij verteld had, dat hij liefst alleen werkte, maar omdat hij zich tegenover mij geexcuseerd had, dat hij liefst alleen werkte!)

Ik zie te weinig van deze jongens (en teveel, die ik liever niet zien wil) om een volle dagtaak te rechtvaardigen en pak dus mijn biezen. Ik doe dit met weemoed: eerlijk gezegd voel ik me door mijn cultuur een beetje in de steek gelaten. Ik heb respect voor hen, die menen te moeten blijven en hoop, dat zij omgekeerd respect kunnen opbrengen voor mijn beslissing.

transcribed by Hans Terlouw
revised Wed, 23 Dec 2009

EWD368

Verslag van bezoek aan Washington, maart 1973

Washington, zondagmorgen, half acht plaatselijke tijd.

Ik schijn de eerste ronde in de slag om de time shift gewonnen te hebben! Na Gisteravond het avondmaal in gezelschap van een half flesje Californische Chablis (!) genuttigd te hebben, ben ik tegen achten mijn bed in getuimeld en de eerste keer, dat ik vanmorgen op mijn horloge keek —ik had toen al een tijdje zo’n beetje liggen denken— was het al na zessen. Ik ben toen zowaar weer ingedoezeld, tot ik om zeven uur —dat zijn natuurlijk wel excessen!— een douche heb genomen en mijn haar heb gewassen. Nu, met schone kleren aan, ligt alle “transport” van de heenreis definitief achter me.

Het arrangement om vast vrijdagavond naar London te vliegen, daar een nacht te slapen, en de volgende morgen de oversteek te maken, kan ik —in weerwil van het feit, dat ik deze keer in London slecht geslapen heb— een ieder aanraden, vooral ’s winters, wanneer die tussenstop je de gelegenheid geeft vast het eerste uur van het tijdsverschil te absorberen. Wie ooit op kosten van een ander een nacht in het Skyline Hotel te Londen kan doorbrengen, moet zich deze unieke ervaring dan niet ontzeggen. De hotelkamer —hoewel met een heel speciale soort Kitsch ingericht— was voortreffelijk, “the little something”, hoewel het geld niet waard, was smakelijk en verder was het hotel van een ongeevenaarde belachelijkheid. De entree, de hal voor de receptie en het aangrenzende gangenwerk waren uitgevoerd in een hoeveelheid marmer, Mussolini waardig, aangrenzend was een wintertuin met weelderige plantengroei, verlicht door fakkels, waarin allerlei zitjes rondom een ongebruikt zwembad, en een strijkje en serveuses in een staat van ontkleding, die de suggestie van de South Pacific compleet moesten maken. We hebben er niet gezeten, maar zijn er wel even doorheen gelopen, omdat het zo onvoorstelbaar gek was. Veel avondkleding en een overmaat aan mannelijk personeel in opzichtige pakken vol gouden tressen, maar zonder duidelijke taak, allemaal uit de aard der zaak van door mij niet nader geanalyseerde zuid-Europese of Aziatische origine. De overmatige aanwezigheid van goedkope gekleurde arbeidskrachten manifesteerde zich de volgende morgen in Heathrow’s International Departure Lounge even beangstigend.

De vlucht van London naar Washington ging met een voor 30 procent bezette PANAM Boeing 747, die luidruchtiger was, dan ik me dit type vliegtuig herinner: communicatie met stewardessen was uitgesproken moeilijk. Het eten was ronduit slecht, het glaasje sherry, dat ik me gegund heb (Harvey’s) voor- treffelijk en doordat ik over drie plaatsen kon beschikken, heb ik vrijwat geslapen, wat na die slechte nacht in London niet onwelkom was.

In Amsterdam had ik in de Tax Free shop een fles Tio Pepe gekocht, die ik in London kon aanbieden aan het echtpaar Woodger, dat mij op het vliegveld kwam ophalen —in de kitscherige hotelkamer hebben we voor het eten even geprobeerd of het echte Tio Pepe was— in Heathrow heb ik, onder het motto “je kunt nooit weten” een fles whiskey gekocht. En ja hoor: dit hotel ligt in het tamelijk droge Virginia, waar geen bars zijn. Het kwam goed uit, want zodoende kon ik dr Stewart van het National Bureau of Standards, die mij gisteren op Dulles International Airport kwam ophalen om mij naar dit hotel te brengen, uit dank een glaasje whiskey aanbieden.

Tenslotte: dit is mijn eerste reis, waarop ik het colbertjasje door een schoudertas heb vervangen. Ik moet zeggen: het bevalt me tot nog toe voortreffelijk en de vaak door vrouwen geuite afgunst treft mij voor alsnog als volstrekt onbegrijpelijk. Wanneer ik mijn tas echt keer kwijtraak, tap ik misschien uit een ander vaatje!

Terug in Nederland, een week later.

Om de draad op te vangen, waar ik hem had laten liggen: ik ben onderweg mijn schoudertas niet kwijtgeraakt en het is me tot op het einde goed bevallen. Sommige mensen kijken wel gek: mijn broer dacht geloof ik, dat ik helemaal een flikker was geworden. Maar we gaan dapper door: het bevalt te goed.

De bijeenkomst in Washinton was georganiseerd door het National Bureau of Standards en de Association of Computing Machinery, met subsidie van de National Science Foundation. Ik voelde me een beetje bedrogen, omdat ik naar Amerika gelokt was ter planning van maatregelen ter verbetering van software ontwikkeling, maar toen het puntje bij het paaltje kwam, bleek een “Handbook for Software Engineering” —in de uitnodiging als mogelijkheid genoemd— het enige doel. Voor de overweging, dat daar nog wel enig onderzoek aan vooraf zou kunnen moeten gaan, was niet veel ruimte meer. De claim was, dat dit handbook “the proven techniques” zou vastleggen, maar het kwam neer op een codificatie van “current practices”, ongeacht of hun ontoereikendheid al bekend was! Ik heb geen weerstand kunnen bieden om het “The Footbook for the Pedestrian Programmer” te noemen, maar dat vond niet iedereen een leuk grapje. Ik zou zeggen: ze zien maar!

Ik heb er natuurlijk wel een hoop geleerd. John Gosden, die ik vaak vluchtig ontmoet had, is uitgebreid aan het woord geweest en ik heb wel een indruk gekregen, hoe hij de softwareontwikkeling voor een heel grote levensverzekering organiseert. Wat hij zei, maakte aanmerkelijk meer indruk dan het gebruikelijke gezever van de “business administration”. Voorts was ik onder de indruk van Harry Larson, een manager in optima forma, die van origine uit de technische wereld kwam, in Houston het mission control centre had opgezet en nu (of all places!) bij Calcomp zat. Leuke, levendige man, die mij aan tafel een keer allerlei verhalen gehouden heeft, hoe hij in een grijs verleden als electrotechnicus met Harry Huskey de SWAC bouwde.

Bob Floyd was er ook. En die viel me eigenlijk nogal tegen. Als je op een rijtje zet, wat die in de zestiger jaren allemaal gedaan heeft, dan hoef je aan zijn kaliber niet te twijfelen. En voor wie dit niet weet, is het, als je even met hem praat, volkomen duidelijk, dat dit een heel spits en snel verstand is. En het was misschien juist daarom, dat ik een beetje teleurgesteld was over het werk, waarmee hij zich de laatste jaren vereenzelvigd heeft, en waar hij duidelijk trots op was. Sinds een aantal jaren doceert hij “elementary programming” aan Stanford studenten van allerlei pluimage. Als je bedenkt, dat hij dit boven het niveau van Basic en Fortran heeft moeten uitheffen, dan heeft hij met de voor educatieve doeleinden ontworpen programmeertaal Chiron groot werk gedaan. Maar als je nu kijkt, waar hij terecht is gekomen, en je vergeet even deze historische achtergrond, dan is het een beetje zielig. Op de eerste dag kreeg ik een exemplaar van zijn collegedictaat, dat de eerste 65 procent van een toekomstig boek is, en voor dat we scheidden, vroeg hij natuurlijk, wat ik er van vond. lk vond het een beetje pijnlijk, want eigenlijk vond ik het nogal lullig. Ik heb me er uit gered, door te zeggen, dat ik uit de tekst niet helemaal kon reconstrueren, voor wat voor studenten dit bedoeld was. Maar dat was een soort smoes. Ben ik even blij, dat ik niet naar Stanford gegaan ben! Als zelfs iemand als Bob Floyd in het kader van de popularisering komt tot een verwatering, zodat het product eigenlijk niet meer door de beugel kan, wat zou er dan met mij gebeurd zijn! Ik vond het triest. Een volbloed voor een mestkar, die vervolgens zo oprecht probeert “to make the best of a bad job”, dat hij voor zijn gemoedsrust de ogen moet sluiten voor de onmogelijkheid van de opgave. Niet dat het dictaat lullig was, dat hij het niet meer zag, dat was het erge....

Ik heb ook een beetje achter de schermen van het Amerikaanse publicatiewezen gekeken. Wat ik daar zag, was nu niet allemaal zo erg verheugend. Bij de besprekingen over het “Handbook” kwam heel duidelijk naar voren, dat het vooral niet te moeilijk gemaakt moest worden, dat je je lezers niet mocht afschrikken etc.; Amerikaanse uitgevers stellen bij een dergelijk project een manager aan, die niet zozeer de administratieve taak heeft, om te zorgen, dat alle bijdragen op tijd komen, nee, die zorgen moet, dat het boek beantwoordt aan de verlangens van het beoogde publiek. Van de ACM, die op het ogenblik in financiele zorgen verkeert, was mij bekend, dat ze als de dood zijn om op de pagina’s van de Communications —hun meest verbreide publicatie— iets op te nemen, dat ook maar een procent van hun lezers zou kunnen afschrikken. Hier komt een soort censuur, een dictatuur van het proletariaat in optima forma! Je ziet aankomen, dat straks in de wetenschappelijke wereld hetzelfde gaat gebeuren, als wat in de letteren al een hele tijd aan de gang is, nl. dat literatuur gemeten gaat worden met de normenschaal van de bestseller. Eng.

De laatste dag ben ik, samen met Bob Floyd op het National Bureau of Standards geweest, waar we beiden min of meer voor de vuist weg —we kenden ons publiek zo weinig, dat we niet erg veel aan voorbereiding konden doen— allebei voor een enorm gehoor een voordracht gehouden hebben onder de titel “High Quality Software”. Dit ging allemaal goed. Bob moest na de lunch meteen weg, ik ben de rest van de middag gebleven, waar nog allerlei mensen me hebben aangeschoten om me even te zeggen, dat ze zo van mijn voordracht genoten hadden. Dat is altijd leuk om te horen. Na enige technische discussies werd ik naar Dulles International Airport gebracht, vanwaar mijn terugreis voorspoedig verliep totdat we in het Europese luchtruim terechtkwamen. Toen in de City of London een paar IRA-bommen ontploften, was ik, ondanks alle vertragingen, al op weg naar Nederland, waar ik de aansluiting van de NLM-vlucht op Eindhoven miste en met de trein naar Eindhoven ging.

Ik heb in Amerika wel gewerkt, het is mij niet gelukt, om EDW367 te voltooien; voorlopig loop ik vast op een bewijs, dat ik niet leveren kan. Maar we geven de moed niet op, want de stelling is ongetwijfeld goed.

maandag 12 maart 1973 | Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 02-Dec-2011

EWD 374

The Analysis of Multiprogrammed Systems of Unspecified Degree of Parallelism.

Multiprogrammed systems have been tackled by considering them as finite state machines with a considerable amount of non-determinacy, reflecting unspecified speed ratios. This is all right as far as it goes (see [1]), but it does not go very far if the reasoning forces us to choose beforehand the number of parallel processes. It is particularly unattractive if the amount of reasoning —or computing if the proof procedure is mechanized— rises steeply with the number of participating processes. The following example shows how even for general “n”, a finite state analysis can suffice, provided that what we call “states” are carefully chosen.

It is the by now classical example of the readers and the writers, where the critical reader activity excludes the critical writer activity and where in addition the critical activity of any one writer excludes the same activity of any other writer. In short, in this example we have an unknown number of participants of two different types.

We have chosen a rather unusual solution, not because we have any reason for favouring it, but in order to show the power of our technique for analysing such systems. The chosen solution is rather sophisticated in granting a rather strong priority to writers and in trying to minimize the execution of synchronizing primitives and tests.

The common state space is controlled by four integer variables ar, aw, br, bw (short for “active or blocked readers or writers”) and three semaphores, called R, W and mutex. Their initial values are

ar = aw = br = bw = R = W = 0     and mutex = 1.

The programs for the readers and the writers —for explanation of the notation see below, after the program texts— are as follows.

READER:
cycle  | non critical reader activity;
|  | P(mutex);
|  | if  | aw = 0 and bw = 0
|  |  | then  | ar plus 1; V(mutex)
|  |  | else  | br plus 1; V(mutex);
| empty  | statement 1;
|  |  |  | P(R);
|  |  |  | br minus 1; ar plus 1;
|  |  |  | if  | br > 0
|  |  |  |  | then  | V(R)
|  |  |  |  | else  | V(mutex)        
|  |  |  | fi
|  | fi;
| critical reader activity;
|  | P(mutex); ar minus 1;
|  | if | ar = 0 and bw > 0
|  |  | then | V(W)
|  |  | else | V(mutex)
|  | fi
elcyc
WRITER:
cycle  | non critical writer activity;
|  | P(mutex);
|  | if  | ar = 0 and aw = 0
|  |  | then  | aw plus 1; V(mutex)
|  |  | else  | bw plus 1; V(mutex);
| empty  | statement 2;
|  |  |  | P(W);
|  |  |  | bw minus 1; aw plus 1; V(mutex)
|  | fi;
| critical writer activity;
|  | P(mutex); aw minus 1;
|  | if  | br > 0
|  |  | then  | V(W)
|  |  | else  | if  | br > 0
|  |  |  |  | then | V(R)
|  |  |  |  | else | V(mutex)
|  |  |  | fi
|  | fi
elcyc

Note 1. As conditional clause we have used

if B then statement list else statement list fi   .

thus doing away with begin’s and end’s; the fi has been written right underneath the corresponding if, the enclosed then and else have been slightly more indented.

Note 2. We have used “ar plus 1” instead of “ar:= ar + 1” etc.

Note 3. The two empty statements have been inserted for the purpose of the discussion that is to follow.

Note 4. Instead of “aw plus 1” the program could have prescribed “aw:= 1” because whenever it is executed, aw = 0 holds initially; similarly “aw minus 1” could have been replaced by “aw:= 0". It is easier not to do so at the start, but to regard this as a possible optimization, permissible when the correctness proof has been given.

Note 5. The P-operation decreases the semaphore concerned by 1, the V-operation increases it by 1; semaphore values are by definition non-negative and therefore the P-operations represent the potential delays. When a V-operation takes place on a semaphore prohibiting at that moment the progress of more than one (other) process, we assume that the blocked processes are served on a FIFO basis (or any weaker assumption excluding the danger of individual starvation at that level.)

We start out considerations by drawing a number of (rather obvious, but vital) conclusions on account of the topology of the programs.

1)   The programs are such that between two successive non-indented statements, control is such that first a P-operation is executed and finally one V-operation. As a result 0 ≤ R + W + mutex ≤ 1, the non-indented ones are the only ones that —as far as the semaphores are concerned— can take place simultaneously, while at most one process can be engaged in the execution of its indented statements: they, together, form a sort of generalized critical section. It means that modification and inspection of the four common variables can take place without the danger of uncontrolled interference by any of the other processes.

2)   The topology of the reader program is such that each critical reader activity is preceded by one execution of “ar plus 1”, after which no further P-operation can postpone its critical activity; moreover each critical activity —which is taken to last until the following P-operation takes place— is then immediately followed by “ar minus 1”. This, together with the initial value of ar and the mutual exclusion of the indented statements, tells us that we are entitled to interpret the value of ar as equal to (or temporarily slightly larger than) the number of critically active readers.

3)   Similarly we can interpret aw as the number of critically active writers (see Note 4 above).

4)   Similarly we can interpret br, the number of blocked readers as the number of readers engaged in “empty statement 1” and bw, the number of blocked writers, as the number of writers in “empty statement 2”. As a consequence, at least one reader can proceed when R = 1, and at least one writer when W = 1.

After the above observation we verify that outside critical sections —i.e. R + W + mutex = 1— will be in one of the states A through E, characterized by the following table.

ar          | ≥ 0 | > 0 | = 0 | ≥ 0 | = 0
aw | = 0 | = 0 | = 1 | = 0 | = 0
br | = 0 | ≥ 0 | ≥ 0 | > 0 | ≥ 0
bw | = 0 | > 0 | ≥ 0 | = 0 | > 0
R | = 0 | = 0 | = 0 | = 1 | = 0
W | = 0 | = 0 | = 0 | = 0 | = 1
mutex | = 1 | = 1 | = 1 | = 0 | = 0
| A | B | C | D | E

It is easily verified that each pair of states —classes of states, if we want to be very precise— has an empty intersection: D and E have nothing in common with any other on account of the semaphore values, among the remaining three, C is the only one with aw = 1 and A and B are distinguished on account of bw = 0 or bw > 0. The system is started in state A, possible transitions are

from |  A  | to A, B or C
from |  B  | to B or E
from |  C  | to A, C, D or E
from |  D  | to A or D
from |  E  | to C .

Furthermore it is now easily checked that the existence of at least one reader or at least one writer ensures that in each state at least one of the transitions is possible, excluding the case of general deadlock. Assuming FIFO (Note 5), the writers are free of the danger of individual starvation; the readers are exposed to this danger, but that is an essential consequence of the strong priority granted to the writers.

15th May 1973

[1] Gilbert, P. and Chandler, W.J. Interference Between Communicating Parallel Processes. Comm. ACM 15, 6 (June 1972), 427–437

transcribed by Corrado Cantelmi
revised 14-Mar-2012

EWD375

A non algebraic example of a constructive correctness proof.

We consider a text built from five types of characters, viz. digits, operators, “(”, “)” and “;”. The text can be read from left to right by means of the primitive move which assigns to the variable named “x” the next character of the text. Initially the value of x is undefined, after the first execution of move, x equals the left-most character of the text. The text has infinite length and it is required to write a recognizer called “sent” that has to establish whether the text starts with a < sent > , given by the following syntax.

< sent > ::= < exp >; |
< exp > ::= < term > {< operator > < term >} |
< term > ::= < digit > {< digit >} | (< exp >)  | (1)

Here { ..... } should be read as “zero or more times the enclosed”. An alternative syntax would have been

< sent > ::= < exp >; |
< exp > ::= {< term >< operator >} < term > |
< term > ::= {< digit >} < digit > | (< exp >) | (2)

We regard (1) and (2) as trivially equivalent.

In order to carry out this investigation, the routine has at its disposal five boolean functions, defined when x has a value, viz. digit(x), operator(x), open(x), close(x) and semi(x), such that always exactly one of the five has the value true.

The result of the investigation has to be recorded in the global boolean named “c” (short for: “correct”). In order to specify more rigorously the net effect to be established by a call on sent, we introduce the following notations.

Let S be the non-empty string of characters read by sent; by definition x then equals the right-most character of S and by S − x we denote the string of characters of S up to and excluding this right-most character.

We now want to express two things: if a < sent > is found, S should equal that sentence; if, however, sent has established that the text does not start with a < sent >, no more characters than are needed for this conclusion should have been read. In view of our later needs, we introduce two new syntactic categories, viz. < pbo sent > and < bo sent >. Here < pbo sent > stands for “proper begin of a sentence but not a complete sentence”, i.e:. a string of characters not forming a sentence all by itself, but that still can be extended to form a correct sentence; < bo sent > , being short for “begin of sentence”, is either a correct sentence all by itself, or allowing extension to a correct sentence. In other words

< bo sent > ::= < pbo sent > | < sent > | (3)

Similarly we introduce:

< bo exp > ::= < pbo exp > | < exp > | (4)
< bo term ::= < pbo term > | < term > | (5)

Note: A < pbo Y > has not been defined as a string that by a non-empty extension can be transformed into a < Y > : it has also been required not to be a < Y > all by itself.

In terms of S and the notion < pbo sent > we now specify the desired net effect of sent by requiring that upon completion

S – x = < pbo sent > and |
S ≠ < pbo sent > and |
c = [ S = < sent > ] | (6)

The first of these terms is required to ensure that not too much has been read, the second guarantees that enough has been read and the final term defines the value of c. Note that specification (5) has been given without taking syntax (1) into account! All proper initial strings of S are of the syntactical category < pbo sent > : the empty string is, and as soon as reading has progressed such that the first two terms are true, reading stops and c will get its proper value.

In order to proceed with (6) in which that syntactic category < pbo sent > occurs, we derive from the first line of (1)

< pbo sent > ::= < bo exp>   | (7)

where < bo exp > comprises all expressions and sequences that can be extended to an expression.

(Note: According to (4) it is not excluded that a proper initial string of an expression by itself is an expression!)

Relation (7), together with the first line of the syntax (1) enables us to rewrite the desired net effect of sent as follows: upon termination of sent we require

S – x = < bo exp > and |
S ≠ < bo exp > and |
c = [ S – x = < exp  | > and semi(x)] | (8)

The second line shows that the concept < bo exp > is related to the complete string S. As a result, when we wish to express sent in terms of a primitive exp, whose analysis has to embody the syntactical rules of an < exp > and that shall read a string E, then E and S should be identical.

In terms of a primitive exp, reading a string E, such that upon termination

E – x = < bo exp > and |
E ≠ < bo exp > and |
c = [ E – x = < exp |  > ] | (9)

the body  

proc sent: exp; c := c and semi(x) corp | (10)

satisfies requirement (8). A formal proof of the correctness of (10) relies on the axiom of assignment only: with post-condition (8) we derive on account of (1) as the post-condition for its call of exp

S – x = < bo exp > and |
S ≠ < bo exp > and |
c and semi(x) = [ S – |  x = < exp > and semi(x)]

which is obviously satisfied by E = S and specification (9). The equality E = S is guaranteed when, prior to its call on exp, sent will not command any move. It does not: it opens with exp.

Now we are left with the duty of constructing a recognizer exp, reading a string E given by the first two lines of (9) and assigning to c the value given by the last line of (9). Because (9) mentions the syntactic category < bo exp >, we had better derive its syntactic definition, now from the second line of the syntax. Syntax (2) is the most convenient and we find —because < operator > is always a single character!—  

< bo exp > ::= {< term >< operator >} < bo term > | (11)

The braces —“zero or more times”— suggest a while loop and therefore we must try to find a convenient invariant, implied by (9). It is certainly necessary to maintain

E – x = < bo exp >

as this takes care of the requirement that not too much will be read. On account of (11) we can then write

               E = {< term >< operator >} T′ |
with              T′ – x = < bo term > | (12)

Equation (11) tells us that the necessary and sufficient condition for E = < bo exp > is in terms of T′, as given by (12),

T′ = < bo term > or T′ = < term >< operator > .

The necessary and sufficient condition for E ≠ < bo exp > is therefore

T′ ≠ < bo term > and T′ ≠ < term >< operator >

or

T′ ≠ < bo term > and non [ T′ – x = < term > and operator(x)]

Furthermore it follows from (12) and the syntax for < exp > that E – x = < exp > (from the third line of (9)) is equivalent to T′ – x = < term >. Therefore we can rewrite (9) as

Q and non [ c and operator(x)] |
with Q:                E – x = < bo exp > and |
T′ – x = < bo term > and |
T′ ≠ < bo term > and |
c = [ T′ – x =< term > ] | (13)

where we have combined in Q all assertions about the total text read by exp. Now the invariance theorem for loops suggests a body for exp of the form

establish Q: |
while c and operator(x) do something without violating Q od |

Analogous to (9) we try a primitive term, such that upon completion the string T read by it and c satisfy

T – x = < bo term > and |
T ≠ < bo exp > and |
c = [ T – x = < term |  >] | (14)

Relations (12), (13) and (14) suggest that we try to prove that

E = {< term >< operator >} | (15)

is a sufficient precondition for term to ensure the postcondition Q. As far as the effect on E of the primitive term is concerned, an execution of term is equivalent to

E := E + T

(where we have used the "+" for concatenation) or

E – x := E + T – x

The post-condition E – x = < bo exp > reduces thanks to the axiom of assignment and (11) to the pre-condition

E + T – x = {< term >< operator >} < bo term > .

Because T – x = < bo term > , (15) is a sufficient precondition, allowing the identification T′ = T, guaranteeing on account of (14) the last three lines of Q as well. Because E = < empty > is a specific instance of (15), the initialization of the loop —i.e. establishing Q to start with— can be done by a single call on term. As repeatable statement term would be acceptable, provided that we can show that

Q and c and operator(x) ⇒ relation (15)

The left-hand implies

E – x = { < term >< operator>} T′ – x and T′ – x = < term > and operator(x)

and therefore (15) holds, but (15) was a sufficient pre-condition for term not to violate Q and we have found the program

proc exp:    term; while c and operator(x) do term od corp .

We are left with the duty to construct a primitive term such that the string T, read by it, and c will satisfy (14) upon completion. In order to construct it, we derive from the third line of syntax (2) the syntactic rule

< bo term > ::= {< digit >} | (< bo exp > | (< exp >) | (16)

and the primary duty of term is to establish a string T such that

T – x = < bo term > and

   T ≠ < bo term >    .

According to the syntax (16) we have three cases

A)      T – x = {< digit >}

In this case x ≠ < digit > on account of the requirement T ≠ < bo term > , and c is to get the value true when T – x ≠ < empty > .

B)            T – x = (< bo exp >

or, with        T = ( E | (17)

we then know that

E – x = < bo exp > and E ≠ < bo exp > . | (18)

But we know also

non [ E – x = < exp > and close(x)] | (19)

because otherwise T = < bo term > (3rd alternative) would have been true. In this case c must get the value false, because from T – x = < term > would follow E – x = < exp ) and this is incompatible with E – x = < bo exp > because via mathematical induction it is easily proved that in an < exp > the number of opening brackets equals the number of closing brackets while in a < bo exp > the number of closing brackets does not exceed the number of opening brackets.

C)      T – x = (< exp >)

In this case, regardless the value of x, T ≠ < bo term > holds and c must get the value true. With

T – x = ( E

—in contrast to (17), covering case B— we have again relation (18) but also

E – x = < exp > and close(x).

But this is exactly the negation of relation (19)! Thus we are led to the following program (with comments inserted between braces)

proc term: | move;
if open(x)
| then | {case B and case C} exp;
if c and close(x)
| then {case C} move
| else {case B} c := false
fi
|  | else | {case A} c := digit(x);
|  |  | while digit(x) do move od
| fi
corp |

*              *
*

Conclusion. The primary purpose of the above exercise was to demonstrate that the applicability of the technique of developing correctness proof and program hand in hand is not confined to simple programs dealing with algebraic relations between integers but can also be applied to non-arithmetic data processing. Some readers might argue that this example rather weakens my point, because the essay is rather long compared to the length of the program. My answer to them is the following:

1) A program need not be long in order to be difficult to conceive and also, unless one has produced absolutely insipid code, a final program is always a a very compact product of one's intellectual labour.

2) We have not made strong assumptions about the reader’s familiarity with the theory of recursively defined syntaxes and therefore have derived explicitly all we needed.

3) Anyone who thinks that he can make reliable programs without a sufficient “theory” about the subject matter of the computations, fools himself.

Finally, although the alert reader will have noticed it, it seems worthwhile to draw attention to the fact, that in all our reasoning in the above exercise we have not given a single example of a sentence, nor of a non-sentence.

Eindhoven, 18th May 1973 | Edsger W.Dijkstra

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-05 .

EWD376

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 376: Finding the maximum strong components in a directed graph

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 22–30 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,

Springer-Verlag, 1982. ISBN O–387–90652–5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited. .

Finding the maximum strong components in a directed graph.

This essay records an exercise in orderly program composition. The record is not completely truthful in the sense that prior to its writing some thinking without pencil and paper was done. As a result, the following text contains a few “surprises” in the sense that suggestions are made without an elaborate heuristic justification. When I noticed myself doing so, some heuristic justification has been added afterwards. The moral of all this is: in case of surprise, please go on reading!

Given a set of nodes and a set of directed arcs leading from a node to a node, it is requested to partition the set of nodes into maximal strong components. A strong component is a set of nodes such that the arcs between them provide a path from any node of the set to any node of the set; a single node is a special case of a strong component: then the path can be empty. A maximal strong component is a strong component to which no nodes can be added.

We shall use the acronym “sa” for a set of arcs, the acronym “sn” for a set of nodes. Our final answer is a partitioning, that is a set of sets of nodes with empty intersections: for that latter object we shall use the acronym “ssn”. Similarly, when the need arises, we shall use the acronym “ssa”�for a set of sets of arcs with empty intersection. (Note added while typing out the manuscript: this need has not arisen.)

Let “sn” be the given set of nodes, let “sa” be the given set of arcs. Let the final value of “ssn” be the desired answer. We then write the desired final relation as

| ssn = MSC(sa) | (1)

where MSC, the set of Maximal Strong Components, is regarded for constant sn as a function of the set of arcs sa.

We want to inspect the arcs one by one (in a suitable order still to be chosen), i.e. we introduce two disjoint subsets of sa, viz. sa1 and sa2, such that

| sa = sa1 + sa2 | (2)

where sa1 comprises the arcs inspected (initially empty, finally = sa) and sa2 the arcs uninspected (initially = sa, finally empty)

Similarly, we want to build up the final value of ssn. We shall do so by maintaining the invariant relation

| ssn + ssn1 = MSC(sa1) | (3)

Here each node of sn will either occur in an element of ssn or in an element of ssn1, but never in both. (Besides that we can, as will be shown later, restrict ourselves to ssn1-values being sets of sets of single nodes.) The following idea was underlying the introduction of ssn1: ssn is a set of maximal strong components, for which -we write an algorithm for a sequential machine!- we may expect to establish one after the other that they will occur as element of the final value of ssn. Our aim is that at any moment in time, ssn will only contain elements of its final value: they are the maximal strong component definitely found. Then we need ssn1 for the remaining nodes.

The initialization corresponding to sa1 = empty is ssn = empty and ssn1 with each node of sn in a separate element of ssn1. When we succeed in establishing

| ssn1 = empty and sa2 = empty | (4)

under invariance of (3), the desired relation (1) has been established, as the second term of (4) implies on account of (2) that sa = sa1.

We have not established yet the relation between the way in which the nodes are divided over ssn and ssn1 on the one hand and the arcs over sa1 and sa2 on the other. We shall maintain the following relations (5) and (6):

| each arc originating in a node of ssn will be in sa1 | (5)
| each arc terminating in a node of ssn1 will be in sa2 . | (6)

Relations (5) and (6) are compatible with the initial situation: because ssn = empty, there will be no arcs originating in a node of ssn and therefore sa1 can be empty (i.e. (5) is not violated) and because ssn1 comprises all nodes, all arcs should be in sa2, in accordance with the initial condition sn2 = sa (i.e. (6) is satisfied).

Relations (5) and (6) are also compatible with the final situation: because then ssn will comprise all nodes, all arcs must be in sa1, in accordance with sa1 = sa (i.e. (5) is satisfied) while (6) is satisfied because then both ssn1 and sa2 will be empty (see (4)).

We observe that, because sa1 and sa2 have an empty intersection, there will be no arcs originating in a node of ssn and terminating in a node of ssn1. On the other hand, an arc originating in a node of ssn1 and terminating in a node of ssn may be either in sa1 or in sa2.

The structure of our program becomes, if we want to apply the fundamental invariance theorem for loops:

| sa1:= empty; sa2:= sa;
| ssn:= empty; ssn1:= “the set of all single node sets”;
| while ssn1 ≠ empty or sa2 ≠ empty do
|  | “transfer arc(s) from sa2 to sa1” and/or
|  | “transfer node(s) from ssn1 to ssn”
|  | under invariance of (3), (5) and (6)
|  |  | od

Relation (5) allows us to simplify the last boolean expression: ssn1 = empty implies that all nodes are in ssn; this implies that all arcs are in sa1, which implies that sa2 = empty. Therefore it can be simplified to

while ssn1 ≠ empty do .

Relations (5) and (6), which may have come as a surprise, have been suggested by

Theorem 1. When the set of nodes are subdivided into two sets nsA and nsB, such that there are no arcs originating in a node of nsA and terminating in a node of nsB, then the set of strong components is unchanged when the arcs (if any) originating in a node of nsB and terminating in a node of nsA are removed and, secondly, no strong component comprises nodes from both sets.

Here the nodes in ssn play the role of those in snA and Theorem 1 tells us that the maximal strong components they will give rise to cannot depend on the arcs still in sa2. Therefore they can only depend on the arcs in sa1 that have already been inspected. As a result each element (i.e. a maximal strong component) of an intermediate value of ssn will be an element of its final value.

In order to detail the repeatable statement we introduce a chain of strong components (a chain of sets of nodes), called “csn”; empty at the beginning and at the end of the repeatable statement. The transfer of a node from ssn1 to ssn will take place in two steps: first the node will be transferred (individually) from ssn1 to csn, at a later stage the node will be transferred (together with all the nodes of the same maximal strong component) from csn to ssn.

The strong components in csn are so by virtue of arcs of sa1 and their chaining is performed by arcs of sa1, more precisely two successive strong components in csn are connected by one arc from sa1 originating in a node of the predecessor and terminating in a node of the successor

|  | (7)

no arc in sa1 will originate at a node of an element of csn and terminate at a node of a preceding element in csn .

|  | (8)

The chain csn has been introduced as a tool for the searching for cycles, an activity that is suggested by

Theorem 2. When a number of strong components can be connected via a cyclic path, they belong to the same maximal strong component.

This theorem suggests that we try to extend the chain at one end: whenever we encounter an arc leading from its end element to a preceding element in the chain, from and including that preceding element up to and including the terminal element can be combined to form the new terminal element. We shall call this operation “combine end elements of csn”; its purpose is to restore the validity of (8).

When the chain csn is non-empty, we investigate whether sa2 contains an arc f having its origin in (one of the nodes of) the terminal element of csn. If such an arc f points to one of the nodes in ssn, it can be ignored (on account of Theorem 1). If such an arc f points to a node in the terminal element of csn, it can be ignored as well �we knew already that the nodes in this terminal element formed a strong component. If such an arc points to (a node in) a preceding element of csn, the end elements of csn are combined. If such an arc leads to a node in ssn1, that node is appended to the chain and will form, all by itself, the new terminal element of csn. In all four cases the arc t is transferred from sa2 to sa1.

If no such arc exists, the terminal element of the chain must be a maximal strong component of the final graph, will be removed from csn and added to ssn, which now grows by one element. This conclusion, again, is justified by Theorem 1. (Note. Here Theorem 1 is applied twice: the terminal node is a maximal strong component because it has no outgoing arcs in the reduced graph that we get by removing all arcs leading back to a node of ssn after it has been established that ssn already contains maximal strong components for the total graph.)

The structure of the repeatable statement -only starting when the chain csn = empty and ssn1 ≠ empty� can be the following:

| transfer an arbitrary element of ssn1 and append it to an
| initially empty chain csn;
| while csn ≠ empty do
|  | if sa2 contains no arc f originating in a node of csn’s terminal
|  |  | element
|  |  | then transfer csn’s terminal element to ssn
|  |  | else transfer such an arc f from sa2 to sa1;
|  |  |  | if f terminates in (a node of) an element of ssn1
|  |  |  |  | then transfer that element from ssn1 by appending it to csn
|  |  |  |  | else if f leads to (a node of) a preceding element of csn
|  |  |  |  |  |  | then combine end elements of csn
|  |  |  |  |  | fi
|  |  |  | fi
|  | fi
| od

We have now to choose a way for representing the information. It is assumed that the nodes are numbered from 1 through N. Because we intend to chain nodes, it is a wise precaution to add “a virtual node” with number 0.

In the representation of our sets of nodes we can exploit the fact that we know that the elements of ssn1 are single node sets. In ssn and csn our elements are strong components, in csn we can number them from +1 upwards, in ssn we can number them from -1 downwards and thus we come to the following representation with an integer array sn[0:N]

sn[i] > 0 means: node i is a member of element sn[i] of csn

sn[i] < 0 means: node i is a member of element sn[i] of ssn

sn[i] = 0 means: node i is (a node of) an element of ssn1

sn[0] = 0 .

In order to scan nodes we introduce for nodes in csn or ssn an integer array pc[1:N], where for node i in one of the two sets of sets

pc[i]= j means: | with respect to node i, node j is the next oldest node in the same set of sets; when j = 0, node i is its oldest node.

In order to be able to trace these pc-chains we introduce two handles:

yc = | the number of the youngest node in csn; when csn = empty, yc = 0
ys = | the number of the youngest node in ssn; when ssn = empty, ys = 0 .

In order to speed up the search for an arbitrary node in ssn1 for the initialization of csn, we introduce the integer k, such that ssn1 contains no nodes with a number < k.

Further we introduce, in order to be able to fix the ordinal number of a new element

ec = | the number of elements in csn
es = | the number of elements in ssn

and, in order to decide whether ssn1 is empty

es1 = | the number of elements in ssn1.

In our program we have to establish whether sa2 contains an arc f originating from the terminal element of csn. We do so by investigating the nodes of the terminal element and on account of the pc-chaining we do so in order of increasing age in csn. Because quite a number of nodes may be a member of the terminal element it seems a bit wasteful in time to start this search always at the youngest node and therefore we introduce

yun = | the number of “the youngest possibly unexhausted node” i.e. sa2 contains no arcs originating in a node of csn younger than nr. yun (if any). Again, in the extreme ease, yun may get the value 0.

Our algorithm presupposes that for each node we can find “its outgoing arcs”. We therefore assume that the arcs are sorted in the order of increasing starting node and that in that order their terminal nodes are listed in the global integer array t[1:number of arcs] while the boundaries are given by the integer array b[0:N], such that b[0]= 0, b[N] = number of arcs and the nodes at which the arcs originating at node i terminate will be t[k], with k ranging

| b[i-1] < k < b[i] .

For the representation of the partitioning sa = sa1 + sa2 we introduce

| integer array c[0:N]

such that all arcs originating in node i and belonging to sa1 will have an ordinal number k satisfying

| b[i�1] < k ≤ c[i]

and those in sa2 a k satisfying

| c[i] < k ≤ < b[i] .

We assume c[0] = 0 for the sake of safety (i.e. sa2 contains no arcs originating from the virtual node).

In the following program the variable ft is used to identify the terminal node of arc f, while the variable h is used for a wild collection of short range purposes. I know that this is a poor style: I too have my weak moments!

begin integer array sn, c [0 : N], pc [1 : N];
|  |  |  |  | integer yc, ys, ec, es, es1, yun, h, ft, k;
|  | {initialize sa1 and sa2}
|  |  |  |  | c[0]:= 0; h:= 0; while h < N do h:= h + 1; c[h]:= b[h-1] od;
|  | {initialize ssn and ssn1}
|  |  |  |  | h := 0; while h ≤ N do sn[h] := 0; h := h +1 od;
|  |  |  |  | ys:= 0; es:= 0; es1:= N; k:= 1;
|  |  |  |  | while es1 > 0
|  |  |  |  | do
|  |  |  | {search for a node k in ssn1}
|  |  |  |  |  |  | while sn[k] ≠ 0 do k:=k+1 od;
|  |  |  | {remove it from ssn1 and initialize csn with node k}
|  |  |  |  |  |  | es1:= es1 - 1; sn[k]:= 1;
|  |  |  |  |  |  | pc[k]:= 0; yc:= k; ec:= 1; yun:= k;
|  |  |  | {note that at this moment node k is oldest and youngest and youngest
|  |  |  |  | possibly unexhausted node of csn}
|  |  |  |  |  |  | while ec > 0
|  |  |  |  |  |  | do
|  |  |  |  |  | {search for the youngest unexhausted node of the terminal element
|  |  |  |  |  |  | of csn}
|  |  |  |  |  |  |  |  | while sn[yun] = ec and c[yun] ≥ b[yun] do yun:= pc[yun] od
|  |  |  |  |  | {this loop will certainly terminate, possibly with yun = 0};
|  |  |  |  |  |  |  |  | if sn[yun] ≠ ec
|  |  |  |  |  |  |  |  |  | then {there is no arc f in sa2 originating in the terminal
|  |  |  |  |  |  |  |  |  |  |  | element nr. ec of csn and therefore this terminal element
|  |  |  |  |  |  |  |  |  |  |  | will be transported to ssn]
|  |  |  |  |  |  |  |  |  |  |  |  |  | es:= es + 1;
|  |  |  |  |  |  |  |  |  |  |  |  |  | while sn[yc] = ec
|  |  |  |  |  |  |  |  |  |  |  |  |  | do sn[yc]:= - es: h:= pc[yc]; pc[yc]:= ys;
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | ys:= yc; yc:= h;
|  |  |  |  |  |  |  |  |  |  |  |  |  | od;
|  |  |  |  |  |  |  |  |  |  |  |  |  | ec:= ec - 1; yun:= yc
|  |  |  |  |  |  |  |  |  | else { c[yun] < b[yun], therefore the next arc originating at
|  |  |  |  |  |  |  |  |  |  |  | node nr. yun will be transferred from sa2 to sa1; this is arc f}
|  |  |  |  |  |  |  |  |  |  |  |  |  | c[yun]:= c[yun] + 1; ft:= t[c[yun]]; h:= sn[ft];
|  |  |  |  |  |  |  |  |  |  | {now ft is the terminal node of arc f and h = sn[ft] to save
|  |  |  |  |  |  |  |  |  |  |  | dynamically a few subscriptions}!
|  |  |  |  |  |  |  |  |  |  |  |  | if h = 0
|  |  |  |  |  |  |  |  |  |  |  |  |  |  | then {node ft has to be removed from ssn1 and to be
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | attached to csn}
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | es1:= es1 - 1; ec:= ec + 1; sn[ft]:= ec;
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | pc[ft]:= yc; yc:= ft; yun:= yc
|  |  |  |  |  |  |  |  |  |  |  |  |  |  | else if 0 < h and h < ec
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | then {ft is a node of the non-terminal element
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | nr. h of csn, with which the younger elements
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | have to be combined}
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | ec:= h
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | {this ends the use of h as h = sn[ft]};
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | h:= yc; while sn[h] > ec
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | do sn[h]:= ec; h:= pc[h]
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | od
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | { note that in combining, pc, yr: and yun can
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | remain unchanged]
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | else {arc f points either to csn’s terminal
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | element or to an element of ssn; in either
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | case it can be ignored}
|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | fi
|  |  |  |  |  |  |  |  |  |  |  |  | fi {the case that arc f existed has been dealt with}
|  |  |  |  |  |  |  | fi {csn’s terminal element has been inspected]
|  |  |  |  | od {csn is again empty}
|  |  | od {ssn1 is empty, the computation has been done};
| {print the results; the maximal strong Components appear numbered in
|  | decreasing order}
|  |  | while es > 0
|  |  | do newline; printtext(“maximal strong component nr.”);
|  |  |  |  |  | printvalue(es); printtext(“consists of the nodes:”);
|  |  |  |  |  | while sn[ys] = - es do printvalue(ys); ys:= pc[ys] od;
|  |  |  |  |  | es:= es -1
|  |  | od
end

Concluding remarks.

In order to avoid the usual misunderstandings it might be a good thing to point out, once again, that the approach that has been illustrated in this exercise does not pretend to be an infallible cure against fallibility We have tried two things: we have tried to develop a program in a way that leads to a higher confidence level than the one that can he reached when the designer “rushes into coding” and we have tried to make the reader share our conviction �strengthened by the above experience!� that the simultaneous development of the correctness proof gives indeed a strong heuristic guidance in the process of shaping the program.

As the reader will have noticed we have not spent a single word of explanation on the repeatable statement of the small innermost loops. I think that this is in accordance with normal mathematical practice: the reasoning has to be broken down in steps so small that they can be made “in confidence” and that a more detailed proof, a more detailed justification could be given when they are challenged, but that that should not be done without compelling reason. We should not waste our time on trivia!

The situation at the innermost loops, where we deal with quite standard coding techniques, is quite different from the situation at the outermost levels where we have to manipulate with concepts and relations cooked up and discovered for the specific purpose of solving this specific problem: it is at the latter level that the greater explicitness seems most urgently needed. Also, it is in that part of the analysis and synthesis that the most heavy demands are made upon the programmer’s ability to express himself effectively.

Finally we draw attention to the fact that we did not need a single example to explain what we were talking about or (even worse!) to discover what the program should do. And this, of course, is as it should have been.

Acknowledgements. We express our gratitude towards J.A.G.M. Kelbosch and J.C. Wortmann for bringing this problem to our attention and thereby presenting the challenge.

30th May 1975                                    Edsger W.Dijkstra

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-07 .

EWD– 379

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On a connection pattern between 2N elements.

We consider M = 2N elements identified by an address running from 0 through M-1. We shall call elements with an even (odd) address "even (odd) elements". In the kind of arrangements we are going to consider, M is constant (e.g. 1024). Each element has the ability of receiving, storing, manipulating and sending information: it is "a little computer".

In order to enable them to exchange information there will be a set of paths, each path leading from an element to (usually) another element. Together the paths form "the connection pattern". We are going to study a specific connection pattern; in most applications that we could think of, the paths will be used for one-way traffic only. (Besides information via the paths, the elements may receive, via other connections, control information for resetting, for synchronization etc.; these additional connections won't be mentioned any further.)

The pattern we are going to study consists of 2M paths. With M1 = M/2, for 0 ≤ k < M1, each element k and each element k+M1 will have two outgoing paths, one to element 2k and one to element 2k+1. As a result each element will also have two incoming paths. (Elements 0 and M-1 have the exceptional property of having an outgoing path leading to itself.)

The fundamental property of this connection pattern is that in N steps it provides a connection from any element A to any element B. To see this we form a 2N-digit number, formed by concatenating the N binary digits of address A with the N binary digits of address B. Over this number we place a window, N bits wide, initially in the left-most position, so that through the window we see the digits of address A. When the window is moved over one position to the right N times, we shall see the digits of address B when the window is in its final position. The numbers seen in the N-1 intermediate positions of the window are now in that order interpreted as the addresses of the elements via which the information will travel from A to B. The proposed connection pattern provides precisely the paths leading from one element to the next (the corresponding value of k is the value of the N-1-bit number formed by the overlapping bits of the two successive N-bit addresses).

Selection in N steps.

We assume that each element stores a value v[j] of an array v[0:M-1]. We regard permuting these values in such a way that for given value of j, v[j] is the contents of element nr. 0 as "selecting v[j]" -element 0 may be the only element connected to the outer world! ".

Denoting with c[i] the contents of element i, we restrict ourselves primarily to the M permutations P[j], such that c[i]= v[i†j] with 0 ≤ j < M where with "†" we denote the "bit-wise exclusive or" ("bit-wise sum modulo 2"). >From the above formula it is clear that in P[j] : c[0] = v[j]. The permutation P[j] can be changed into P[j'] in N steps under control of s = j † j', each step being controlled by the next digit (in order from left to right) of s. If the corresponding digit of s = 0, we command a step "rotate", i.e. elements i from the lower half (i.e. i < M1) send their contents to their even receiver and elements from the upper half (i.e. i ≥ M1) send their contents to their odd receiver. If the corresponding digit of s is = 1, we command the step "rotate and invert", i.e. elements from the lower halt send to their odd receiver and elements from the upper half send to their even receiver. In N steps all the digits of s have been processed, the state P[j] has been changed into P[j'].

Hyperfast Fourier Transform.

With d = exp(2πi/M) we have to compute M-1 b[j] = ∑ a[i] * di*j for 0 ≤ j < M . i=0 Our initial state is c[i] = a[i] for 0 ≤ i < M. For h running from 0 through N-1 we do N times the following step. Each element i sends its contents c[i] to both its receivers, i.e. c[k] and c[k+M1] arrive both at elements 2k and 2k+1. All even receivers perform simultaneously the assignment c[2k]:= c[k] + c[k+M1] while odd receivers perform the assignment c[2k+1]:= (c[k] - c[k+M1])* f(k,h) where f(k,h) = dr and the value of r is formed by forcing the h right-most binary digits of k to zero.

The determination of the constants f(k,h) can be accomplished by extending the contents of each element i with a variable e[i] = f(k,h). They can be initialized for h = 0; after the adjustment of the c-values, the e-values can be adjusted simultaneously by e[2k]:= e[k]² e[2k+1]:= e[k]² i.e. the lower half senders have to broadcast their e-value to both their receivers, who square the received value to form their new value of e.

After these N steps c[i] = b[mir(i)]

where the binary representation of mir(i) consists of the digits of the N-bit binary representation of i, but in the reverse order.

If we want to reduce the traffic along the paths and to do away with the squaring needed to form the new e-value, we can store in each element the N f(k,h)-values: they are constants!

In either case, the Hyperfast Fourier Transform uses the paths of the connection pattern for one-way traffic only.

Autocorrelation coefficients.

After a Fourier Analysis as described above, each element multiplies its c-value by c, its complex conjugate. Then, again in N steps not basicly different from the above, a Fourier Synthesis is performed. The synthesis, however, requires traffic along the paths in opposite direction.

Sorting.

The concatenation of two sequences of length K, sorted in opposite directions, is a "bitone cycle of length 2K". A bitone cycle is a cyclic arrangement of values with only one local maximum and only one local minimum. In contrast to the sorted sequence, the bitone cycle is an undirected object.

A bitone cycle of length 2K is easily split into two bitone cycles of length K with the property that the maximum element of the left(right)hand cycle is at most equal to the minimum element of the right(left)hand cycle. The split is a directed operation.

In order to create an ordered sequence -say "an upward seqoence"- we arrange them into a bitone cycle of length M and perform "an upward split". Thereafter both halves are subjected to an upward sort.

In order to create a bitone cycle of length M the two halves are sorted independently in opposite directions. (Note that, because a bitone cycle is un undirected object, it does not matter whether the lefthand half is sorted into an upward or into a downward sequence!)

The above considerations replace the task of an upward sort of length M by two sorts of length M/2, an upward split followed by two upwards sorts of length M/2. These latter two sorts have already been prepared, because after the split, both halves are bitone cycles!

We can describe the algorithm as follows (comments have been inserted between braces): k:= 0; while k < N do k:= k + 1; {at this moment the sequence consists of 2N-k bitone cycles of length 2k; mark them "up - down - up - down ....." in the order in which they occur} h:= k; while h > 0 do {at this moment the sequence consists ot 2N-h bitone cycles of length 2h ; consecutive bitone cycles with the same marking are groupwise ordered according to the marking} split the bitone cycles of length 2h according to their marking and give the children the marking of the parent; h:= h -1 od od

With our connection pattern this can be implemented with the aid of the operation "rotate" (see above) and the operation "rotate and select". In the latter operation, each element sends its contents to both its receivers, but, depending on the marking of the pair, the even receiver selects the smallest value and the odd receiver selects the largest (upwards), or the other way round (downwards). The program then becomes k:= 0; while k < N do k=: k + 1; h=: N - k; set marking; while h > 0 do rotate; h=: h - 1 od; h:= k; while h > 0 do rotate and select; h:= h - 1 od od

Each receiver(pair) can set its marking "up" when the k-th bit from the right of the binary representation of its ordinal number is = 0 (for the case k = N, this digit is = 0 for all receivers) and "down" if that bit is equal to 1.

From the program it follows that the M elements are sorted in N² steps. Again the connection pattern is used for one-way traffic only.

13th June 1973 Edsger W.Dijkstra

EWD384

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Betrouwbaarheid van programma’s.

Mathematische uitspraken plegen zich door drie eigenschappen te onderscheiden:
a)     ze zijn algemeen in de zin, dat ze op een groot aantal gevallen van toepassing zijn; (men formuleert een eigenschap van “alle niet ontaarde driehoeken”)
b)     ze zijn heel precies; (dit in tegenstelling tot alle uitspraken, die hun algemeenheid aan vaagheid ontlenen)
c)     er bestaat een bewijstraditie, waardoor de kans op onjuistheid van de uitspraak drastisch gereduceerd kan worden; (hierbij tekenen we aan, dat er voor het bereiken van een dergelijk betrouwbaarheidsniveau geen alternatieven bekend zijn).

Zodra wij rekenautomaten aan het werk zetten met de bedoeling aan de uitkomsten consequenties te verbinden, dan zijn wij daartoe slechts gemachtigd voor zover wij ons geloof kunnen rechtvaardigen, dat de geproduceerde uitkomsten inderdaad het antwoord op het door ons gestelde probleem zijn. Een eerste vereiste daartoe in, dat wij ons ervan kunnen overtuigen, dat het programma correct in. Hoe kunnen wij deze overtuiging bereiken?

In de begintijd heeft men dit door “programma testen” geprobeerd te bereiken: men onderwerpt het programma aan een aantal bekende testgevallen, proefberekeningen, waarvan het antwoord bekend is: als in deze testgevallen het juiste resultaat bereikt werd, nam men aan, dat het programma in alle gevallen het correcte resultaat zou produceren. De bittere ervaring heeft geleerd, dat deze laatste aanname ongerechtvaardigd is.

Het punt is, dat de klasse mogelijk bedoelde rekenprocessen, dat onder controle van een niet helemaal triviaal programma zo enorm groot is, dat men met de testgevallen slechts een absoluut verwaarloosbare fractie metterdaad proberen kan en hele subklassen van in een of andere zin “critische gevallen” kan en zal missen. Sterker: de klasse van de mogelijke berekeningen is een klasse van zo sterk gestructureerde objecten, dat als van de 1000 testgevallen er 1 is misgegaan, de verwachting dat ook in de toekomst van de 1000 testgevallen er gemiddeld 1 zal misgaan, helemaal ongerechtvaardigd is: de berekeningen zijn onvoldoende gelijksoortig om hier zinvol statistiek op te kunnen bedrijven. (Dit is iets, wat allelei mensen maar heel moeilijk kunnen geloven.) Om het vereiste betrouwbaarheidsniveau te halen, rest ons slechts een ding: nl. bewijzen, dat het programma correct is.

Om dit te kunnen doen, moet aan drie voorwaarden voldaan zijn:
a)     de vereiste eigenschappen moeten voldoende scherp en hanteerbaar geformuleerd zijn (anders hoeven we over “correctheid” helemaal niet te praten)
b)     er moet een bewijstraditie zijn (inclusief stellingen, axioma’s en beproefde redeneerpatronen)
c)     de voor een correctheidsbewijs benodigde hoeveelheid “manipulatie” moet binnen de grenzen van het mogelijke blijven.

De eerste pogingen om correctheidsbewijzen te leveren, waren niet bemoedigend. In retrospectie is dat ook heel begrijpelijk. Om van een programma de correctheid te bewijzen, zal men een formele definitie van de semantiek van de programmeertaal, waarin het programma is uitgedrukt, moeten hebben en de eerste pogingen, zulke formele definities te geven, hebben, hoewel tot ondubbelzinnige definities -en dat was in die tijd al heel wat!- niet geleid tot axiomastelsels, die zich soepel leenden tot basis van correctheidsbewijzen. In dit opzicht lijken de tijden inmiddels veranderd.

Een tweede oorzaak van de aanvankelijk ontmoedigende ervaringen was gelegen in het feit, dat men zich in zijn optimisme stortte in het leveren van correctheidsbewijzen van programma’s geschreven in toen gangbare programmeertalen, die meestal niet vrij waren van anomalieen, die een zekere barokheid niet ontzegd kon worden en die zeker niet ontworpen waren in een tijd, dat men zich over bewijsbaarheid van correctheid al veel zorgen maakte.

De grootste doorbraak is echter gekomen door de ontdekking, dat de hoeveelheid vereiste manipulatie sterk kon afhangen van de structuur van het programma en dat een van de dingen, die men met structurering van een programma na kon streven juist vermindering van de bewijslast was. Een onmiddellijk gevolg van deze ontdekking is geweest, dat men het correctheidsprobleem constructiever ging benaderen. In plaats van dat men eerst een programma ging schrijven en dan ging proberen om te bewijzen, dat het goed was, gingen mensen correctheidsbewijs en programma hand in hand ontwikkelen: op het moment, dat het correctheidsbewijs vorm kreeg, schreef men een programma, waarop dit correctheidsbewijs van toepassing was. Een extra “benefit” van deze benaderingswijze was, dat op dat moment de correctheids overwegingen zich ontpopten tot een vruchtbaar heuristisch hulpmiddel.

Een van de machtigste hulpmiddelen is de invariantiestelling voor loops van C.A.R.Hoare:

Indien voor de statement S de voorwaarde P and B een voldoende preconditie is om te garanderen dat, mits de uitvoering van S eindigt, aan de post-conditie P dan voldaan zal zijn, dan is voor de statement

| while B do S od

de pre-conditie P voldoende om in geval van beeindiging de post-conditie P and non B te garanderen.

Het belang van deze stelling is daarin gelegen, dat hij zich zeer wel blijkt te lenen voor de constructie van programma’s. Om een bepaalde relatie R te bewerkstelligen, kiest men een P en een B, zodat P and non B de eindrelatie R impliceert. Het programma krijgt dan de algemene vorm

vestig de geldigheid van P;

while B do onder invariantie van P een “stap”

| in de richting van “non B” od .

De stelling is in bijzonder machtig, omdat we ons bij de bewijsvoering er niet over hoeven uit te laten, hoe effectief de stap in de richting “non B” nou wel precies is: zolang we er ons van kunnen overtuigen dat de toestand “non B” in een eindig aantal stappen bereikt zal worden, is dit stuk van het correctheidsbewijs compleet. Doordat de stelling van Hoare zich er niet over uitspreekt, hoevaak de herhaalbare statement herhaald wordt, hebben we hier een stuk gereedschap dat ons in staat stelt programma’s met een deterministisch netto effect te construeren onder gebruikmaking van het semi-deterministische primitivum “een stap in de goede richting”. Het is dit gebruik van semi-deterministische primitiva, dat onder de naam “strategische abstractie” bezig is burgerrecht te verkrijgen.

Bijna alle programma’s, die ik ken, om bij een gegeven puntenwolk in het platte vlak het convex omhulsel te vinden, zijn via strategische abstractie bijvoorbeeld afbeeldbaar op hetzelfde abstracte programma van de volgende vorm, waarin de mogelijke waarden van de variabele “convex omhulsel” het convex omhulsel van een niet lege deelverzameling van de gegeven punten zijn.

| initialiseer het convex omhulsel, zodat het een of meer
| punten omvat;
| while er bestaat een punt buiten het convex omhulsel do
|  | kies een punt buiten het convex omhulsel en noem dat q;
|  | pas het convex omhulsel aan, zodat ook punt q omvat is
| od

In hun uiteindelijke uitwerking kunnen de hierop geente programma’s nog enorm verschillen, bv. doordat ze zich in de keuze van het punt q altijd zullen beperken tot een punt dat op het uiteindelijke contour zal blijken te liggen of zich deze beperking niet opleggen.

Een tweede techniek begint burgerrecht te verkrijgen onder de naam “representationele abstractie”. Hier scheidt men de feitelijk gekozen techniek om in het geheugen verschillende waarden van een (abstracte) variabele te representeren van de voor de bewijsvoering meest conveniente wijze om deze verschillende waarden te karakteriseren, daarmee het correctheidsbewijs in dit opzicht factoriserend. Aan de hand van enige simpele voorbeelden zal een en ander geillustreerd worden.

2 juli 1973                                 prof.dr.Edsger W.Dijkstra

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD 385

Trip report E.W.Dijkstra Summer School Munich, July 25 to August 4, 1973.

Well, actually it was not Munich, but the little town of Marktoberdorf, which meant that upon arrival in Munich we had another two hours of travel to survive and that upon departure we had to leave so early, that I bought a travel alarm clock, just to be on the safe (i.e. "early") side, as I had found the waking service of Hotel Sepp on previous tests unreliable! At both occasions, the international trains were perfect and dead on time, it is for distances of that order of magnitude the most civilized way of travelling through Europe.

This NATO-sponsored Summer School is establishing quite a position in the field. Last time there were about 80 participants, this year they could accommodate 105, but the number of applications had been three times as much! It was a difficult audience: it was large and highly inhomogeneous. I always try to adapt as far as possible my presentations to my audience and for such a mixed audience this is always difficult, but during the first three days I could not even try it, because they were very passive and did not give any feed back. Part of that can be explained by the language barrier —there were participants from 22 different countries, including France— but not all of it. I had to give ten lectures (of 45 minutes each), the last six —i.e. after the weekend— were less of a monologue. I got the impression that eventually I reached practically all of the participants. Wladislav Turski and Alan Perlis had an equal share of the burden.

Turski (Warszawa, Poland) lectured under the title "Morphology of Data." What he tried to do, seemed quite reasonable: he tried to separate "naming conventions" on the one hand from storing on a (addressable) medium on the other hand. But he suffered quite clearly from the pressure of his Polish environment, where pure mathematicians are very much in power and enforce their notational prejudices (probably justified for their own requirements) ruthlessly upon everyone else; I know that Turski has suffered from this pressure and that he has made a conscious effort to undo its harmful effects as much as possible. Having heard his presentation I must come to the conclusion that he has not fully escaped (yet).

Perlis (Yale University, USA) is quite a different person! He is fun to listen to as long as you do not listen too carefully, for as soon as you start doing that, his words dissolve into loose talk, so superficial that after a while it becomes most annoying, his jokes excepted. His presence was valuable in so far he provided the contrast, trying to make his case for "unstructured programming" and his presence has been responsible for a number of discussions and even arguments; but I have the feeling that the level of these discussions could have been higher if someone else had provided that contrast. Brian Randell (who is very good at such things) saved a few discussions.

Niklaus Wirth —who spoke also a little bit on behalf of Tony Hoare— spoke on "An Axiomatic Definition of the Programming Language PASCAL". His presentations were very well prepared and it was a pleasure to listen to him. He gave a striking demonstration of our increased power of annotating and explaining non-trivial programs! It was really impressive. (The demonstration slightly suffered from the fact that the program he showed was not very nice and some in the audience found their thoughts drifting away in the mood of "How should I solve that problem by means of a program?") In other respects he was not convincing: in the design of PASCAL the axiomatic definition has not played a significant role, to give an axiomatic definition was an afterthought. The result shows that and you cannot conceal that.

Personal reasons prevented M.Griffiths from Grenoble to speak as scheduled, but we were lucky in having Per Brinch Hansen (California Institute of Technology) as a substitute. He went through the highlights of his recently published book "Operating System Principles" and he did that much, much better than two years ago, when he covered the same material, but then he was very biased and even aggressive. Now he gave a neat, balanced survey. It is a pity that he has a very monotonous voice; it is really soporific and now I cannot even read one of his publications without hearing it!

Brian Randell gave a two-lecture talk on the PEARL system, and did so very nicely. (He had better, for its author, Bob Snowdon, was sitting in the audience!). The remaining three speakers, I am afraid, failed to get their message across the limelight; in one or two cases there was some doubt whether there was a message...

Having talked about factorization of a solution and having illustrated this by comparing with each other two different types of circuits as you find in clocked machines, I wanted to expose the audience to the design of the mouse that follows a contour, because you can then in a completely different environment meet that same factoring principle (in its full glory, even!). I did not quite know how to stage it: the whole crowd of 105 people seemed too large for active participation. I have announced "an interactive programming session", announced that I had found two "intelligent terminals" —in the form of David Redell and Paul McJones, both from Berkeley— and predicted a successful session because our communication language (viz. English) was "an interpretive language". (I was so cross with Al for all his platitudes; I think that this ridicule was the only time that I showed a temper in public!) It was a very nice session, I had been very lucky in the choice of my "intelligent terminals"!

Compared with earlier Summer Schools there was a change. A greater percentage of the participants seemed to have come with the rather stupid hope, essentially, for a recipe of thinking, or came under the false assumption that "the good programming language" is the end to all your problems! Who has taught them that nonsense? I observed this attitude most markedly among American and the Israeli participants (but as the French have kept their mouth hermetically sealed... who knows?). This false and primitive idea surfaced over and over again; in utter exasperation I have recommended at the beginning of my last lecture "A Guide to Positive Programming" by Norman Vincent Peale...

Another difference was caused by a drastic change (or shift) on the German Academic scene. After neglecting computing science for years, finally, now they have invented the term "Informatik" the German government is backing the subject with all its force and marks: departments of "Informatik" are mushrooming all over the country. And how did they staff them: with what they had, pure mathematicians and automata theorists in particular. I am afraid that the result is a disaster, at least for German Computing Science. German Computing Science is in danger of being taken over either by the mathematicians or by APL; in both cases the result will be very much the same, viz. the end of German Computing Science!

I solved the convergence properties of a tricky cyclic relaxation problem while the others visited mad Ludwig's castle Neuschwanstein. It came out of my search for self-stabilizing systems.

NUENEN, 7th August 1973 | dr.Edsger W.Dijkstra

transcribed by Corrado Cantelmi
revised Fri, 2 May 2008

  EWD 386

The solution to a cyclic relaxation problem.

The problem solved in this note arose in connection with the (just initiated) study of self-stabilizing systems.

Consider a circle and N points numbered from 0 through N-1, placed in an arbitrary order around the circumference. For "the adjustment of point nr. i" we consider the shortest clockwise path along the circumference from its predecessor —i.e. point nr. (i-1) mod N— to its successor —i.e. point nr. (i+1) mod N—; the new position of point nr. i will be halfway (i.e. the middle) of that path. In formula (taking the circumference of the circle as unit) with pred = x[(i-1) mod N] and succ = x[(i+1) mod N]

x[i]:= if pred ≤ succ then (pred+succ)/2 else ((pred+succ+1)/2) mod 1 fi.

If we start doing adjustments, will the system converge on a stable state?

This is not necessarily the case if we do the adjustments simultaneously, i.e. determine all new positions in terms of all the old ones, as is shown by the following examples.

| N = 3 |  |  | | |  | N = 4 |  |
t | 0 | 1 | 2 | | | t | 0 | 1 | 2
x[0] | 0 | 1/2 | 0 | | | x[0] | 0 | 3/4 | 0
x[1] | 2/3 | 1/6 | 2/3 | | | x[1] | 0 | 1/4 | 0
x[2] | 1/3 | 5/6 | 1/3 | | | x[2] | 1/2 | 1/4 | 1/2
|  |  |  | | | x[3] | 1/2 | 3/4 | 1/2

For both odd and even N we have an example that will oscillate with a period 2. If, however, we do the adjustments one at a time in a fair random order (i.e. without permanent neglect of certain points), then the system is bound to converge.

Consider, instead of the N points, the N clockwise paths leading from each point to its successor. After a point adjustment the two paths meeting at that point will both be less than 1/2 and no future adjustment can ever undo that! After adjustments all around the circle each path will be less than 1/2, and from that moment onwards each triangle "i-1, i, i+1" is a clockwise one. The total clockwise path from 0 to 1, from 1 to 2, ....., from N-1 to 0 will go around the circle a fixed number of times, m say (0 ≤ m ≤ N/2). No adjustment can anymore change the value of m, from now onwards we could even do simultaneous adjustments. The final state will satisfy for all i

(x[(i+1) mod N] - x[i]) mod 1 = m/N.

The system converges linearly (imagine successive points connected by spiral springs or rubber bands of equal length).

The above was written under the assumption that along the circumference we had the continuum at our disposal, i.e. that the fractions x, satisfying 0 ≤ x < 1 could be represented in arbitrary precision. Suppose now that we have to represent the fractions x as integer multiples of 1/p (where we may assume the integer p to satisfy p >> N).

The extent to which the system converges seems to depend on how we round off when necessary, i.e. when the clockwise path from predecessor to successor turn out to be an odd multiple of 1/p. If we impose the rule, that rounding will always take place in the same cyclic direction (say "anticlockwise"), then the following will happen.

With m defined as in the continuous case, define q and r by

m*p = q*N + r with 0 ≤ r < N.

Of the paths p[i] leading from x[i] to its successor, (N - r) —the "short" paths— will be of length q/p and r paths —the "long" paths— will be of length (q + 1)/p. If p[i-1] is "long" and p[i] is "short", adjustment of point nr. i —with anticlockwise rounding— will have the effect that the predicates "short" and "long" have interchanged position. The short ones will be travelling anticlockwise through the cycle, simultaneously the longs ones will travel clockwise through the cycle.

The two types of paths travelling in opposite direction through the same cycle makes it clear that if m*p is an integer multiple of N, that then the system will converge to a completely stable situation.

NUENEN, 8th August 1973 | dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Tue, 27 Mar 2007

Copyright Notice

The following manuscript

EWD387: Trip report IBM Seminar �Communication and Computers�, Newcastle, Sept. 1973

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 36–40 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 387

Trip report IBM Seminar "Communication and Computers", Newcastle, Sept. 1973

It was a very mixed affair and I have not yet succeeded in sorting out my feelings completely. Let me try.

There are two completely different views of programming: on the one hand we have the (academic) study about the nature of the intellectual challenge, on the other hand we have programming as it is done and can be done by the hundreds of thousands that are called "programmers" today. These are two completely different subjects and when two groups are talking about them as if it were one subject, unaware of the "twoness", endless confusions arise. I have now witnessed this confusion so many times that it does no more catch me unaware. During this seminar on "Communication and Computers" there was a similar confusion; being less familiar with that one, I only discovered it well after the Seminar had finished.

On the one hand there are the technical and logical problems connected with the organization of the cooperation between two or more computers, so far apart that by definition they are asynchronous. In this field there are enough intriguing and logically very difficult problems to justify a seminar to them. On the other hand the American scene presents us with a few large, powerful bodies: the giant IBM forcing a de facto standard upon the world of computing, "ma Bell" forcing in a very similar fashion a de facto standard upon the world of communication and finally as a third (politically very powerful) party the ARPA network, an achievement that, in spite of all its patent shortcomings, will be a model for many future efforts, if only because it has been such an expensive experiment.

Much of the discussion and the talks was really about the problem how to organize fruitful cooperation —how to organize some sort of merge— between the now separate communication and computer industries, each with their different pasts and tremendous vested interests. But this was done in veiled terms, addressed to an audience of European academic computer scientists! Some misunderstanding —to put it mildly— was only to be expected!

The academic computer scientists were not quite sure whether the problem really concerned them and their educational responsibilities, and I cannot blame them either. From the rostrum the problem was approached from an academic point of view as well, but....! L.Kleinrock of UCLA gave three excellent and inspiring tutorials on "Analytical Techniques for Computer Communication Networks". A highly gifted teacher, so gifted that he made you forget that his dealing with the whole subject was very one-sided! He showed queueing theory at work, unavoidably suggesting that the contribution of mathematics should always have the form of "applying an existing mathematical technique for solving a specific class of problems". The result is not inspiring for mathematicians: on the one hand most of the results can be obtained with the aid of what Kleinrock characteristically described as "baby queueing theory" and that was not too much: quickly one had to turn to simulation! In another respect it was also misleading: his stress on the quantitative aspects of the game —what else can you expect from a queueing theorist?— tended to make the audience believe that the logical problems were either solved or unimportant or nonexistent. (The stress on the quantitative aspects is, of course, a very American attitude: this time it was vigorously enforced by the really gigantic size of the investments made at all sides. We don't really know what to do, but let us minimize our cost/performance ratio nevertheless!) But he was a great lecturer and it was a pleasure to see him at work.

Sandy Fraser, now from Bell Labs, did an excellent job. He was very concerned about bringing communication and computing industries together. (Let the universities think too about sound protocols: now all nets are still "experimental" but what will happen in the next ten years will bind us for the next 200 years.) He was in many ways bound: the fact that Bell and IBM are engaged in a lawsuit of some gigantic proportions required all sorts of statements (from Ewan Page, when he was introduced and from himself when he started). As far as bringing his technical message was concerned, he was also very careful —alarmingly careful, one might say—: he made the impression of arguing that all technical considerations pointed in a direction opposite to the store-and-forward techniques chosen for the ARPA network, but clearly he wished to avoid making all ARPA fans his declared enemies. It is somewhat sickening that an undoubtedly gifted, honest and sensitive scientist like Sandy must so constantly be on his guard. He too is a gifted speaker, very different from Kleinrock, but also and always a pleasure to listen to. Kleinrock and Fraser were the only two speakers that received an applause at the end of their last lecture; and they fully deserved it.

The other two speakers that gave three one-hour lectures, Dr. McKay from IBM, Yorktown Heights and Professor Engelbart, SRI, Menlo Park, were both terrible. McKay spoke undiluted IBMerese for three full hours and I am not going to give any further comments; I only heard the first hour —like many participants— and that was enough (too much). Because I had an urgent letter to write I missed Engelbart's first lecture —it was not really a lecture, he showed a movie— but I attended his next two performances. He was not only terribly bad, he was dangerous as well, not so much on account of the product he was selling —a sophisticated on-line text-editor that could be quite useful— as on account of the way in which he appealed to mankind's lower instincts while selling it. The undisguised appeal to anti-intellectualism and anti-individualism was frightening. He was talking about his "augmented knowledge workshop" and I was constantly reminded of Manny Lehman's vigorous complaint about the American educational system that is extremely "knowledge oriented", failing to do justice to the fact that one of the main objects of education is the insight that makes quite a lot of knowledge superfluous. (Sentences like "the half-life of a fresh university graduate is five years" are only correct if you have crammed the curriculum with volatile knowledge, erroneously presented as stuff worth knowing.) His anti-individualism surfaced when he recommended his gadget as a tool for easing the cooperation between persons and groups possibly miles apart, more or less suggesting that only then you are really "participating": no place for the solitary thinker. (Vide the sound track of the Monsanto movie showing some employees: "No geniuses here: just a bunch of average Americans, working together."!) The two talks I heard were absolutely insipid, he had handed out a paper "An augmented knowledge workshop.": the syntactical ambiguity in the title is characteristic for the level of the rest of the article. As a result of his presentations I have told a few of the participants that I had found, thanks to this seminar, a new software project. "Because in the years to come there will be a crippling shortage of competent programmers, I shall develop a software package, called "The Instruction Interpreter". From the moment of its completion, users do no longer need to program, they just give their instructions to the system." (This is only an edited version of one of the paragraphs of the Engelbart article!) I would have liked to start a discussion with him but I knew that my lack of mastery of the understatement would have made me too rude for English ears if I had spoken. Finally —after a more than two-hour effort in the middle of the night in sorting out his muddle— I decided that he was not worth the trouble. (One of the most offending conclusions I ever came to!)

Besides the four main speakers there were six others who gave one-hour presentations.

On the schedule was mentioned Mr. T.R.M.Longam from IBM International Information Services. He was prevented to come and his place was taken by one of his staff members, whose name I failed to catch. He did not speak IBMerese and gave a clear survey of intent and scope of his organisation. In my memory will stick the tremendous amount of equipment he had in his place: 4 IBM360 model 65, a similar number model 50 plus peripheral gear. From the type of work he described one could not fail to conclude that the arithmetic capabilities of these machines could hardly be expected to get very tired; and presumably they spend an awful lot of time idling or doing internal red tape. But he was a good speaker.

J.McNeil of Logica Limited gave a talk on "Graduates in the Computer Industry: A Consultant's View." It was a talk on a similar topic as covered by Alex d'Agapeyef a few years earlier but McNeil's presentation was more convincing. On the whole he was happy with graduates. He made it quite clear that their ability to write another compiler for a baby language was in his eyes not their most important asset, because the range of their activities was much broader. He complained —and I can well believe that he was fully justified in doing so!— about their crippling inability to use English effectively. In the discussion afterwards no one took up that point; at some stage I felt inclined to do so, but the moment passed. Nice talk.

There were two talks from PTT officials, a management talk by Mr. G.Dale from the English PTT and a technical one by ir.A.Boesveld of the Dutch PTT. The first speaker dealt with international politics, the second one described Stored Program Controlled Telephone Exchanges. As far as the clarity and truthfulness of the picture as given by Boesveld is concerned he did an excellent job; the programming techniques applied seemed to be rather old-fashioned, but my guess is that that is typical for the field. (As a Dutchman it was nice to hear that the Dutch telephone system ranks high in quality and low in tariff among its European fellow systems.) After both talks the audience misbehaved, at least to my standards: the audience started to attack the (his) PTT monopolistic attitudes, misuse of power, failing public relations etc. I understand that it can be quite frustrating to get the PTT's permission to hook an unusual gadget to their lines, but this seminar was not the proper place nor moment to air(?) those frustrations.

Mr.R.Scantlebury from the NPL, Teddington, described the —again experimental!— NPL Data Communication Network. The subject, I gather, was appropriate, it was, however, a little bit too obvious that the speaker had done so before: it was a nice, polished presentation, but the speaker could not get excited about his subject, nor could his audience. I always like to listen to him lecturing, but that is because I like his English.

I used my hour to talk not on my announced subject, but on the many-mosquito elephants in general and the hyperfast fourier transformer in particular. (Patent restrictions prevented me from announcing this subject when I was invited to talk.) My subject fell a little bit outside the scope of the seminar (so did McNeil's) but I felt that this was not too bad in view of the background of the audience. Although I thought that I did a reasonably competent job in explaining it, they found it very difficult to follow and made not the impression of being excited. This amazed me rather, because in my introduction I had told them the various reasons why I had chosen to talk on this subject, among them the fact that elephant design had turned out to present problems that had stretched my mathematical gear, my notational techniques and my conceptual abilities to the limit. But perhaps it was a mistake to present a new intellectual challenge, even to an audience consisting almost exclusively of university professors. (When I showed it —in strict confidence of course!— earlier this year to Peter Naur, at the end of my presentation he looked silently to the blackboard for more than a minute and then exclaimed "Jezus!". My sad guess is that there were too few Peter Naurs in this audience....)

That was the conference. Before it started we had "an evening" at the home of Ewan Page, a sherry party the next afternoon just before dinner, the next afternoon an excursion to Hadrian's wall —with a true archeologist explaining all about one of the excavations: he was an absolute delight!— and the closing banquet on the next evening. So we were kept quite busy!

I wonder whether the seminar as a whole was a success. If you set "instruction" as your goal, then I gather that it was successful: the academic computer scientists have seen stuff from a closely related field that was largely new for them. The "but" of course is, what they are going to do with it. Mostly nothing, I am afraid. Besides that I observed a general "malaise": on the whole technical or scientific excitement was lacking —in spite of Kleinrock's superb lecturing technique!— and the little bit there was damped by the feeling that eventually political considerations would force the "wrong" decision anyhow. In that sense it was not only not exciting, it was even depressing. Is computing science nearing its completion? Is computing practice settling down in a way beyond recovery? Or are, as a result of current circumstances, university professors tired and discouraged?

12th September 1973 | dr.Edsger W.Dijkstra

transcribed by Corrado Cantelmi
revised 28-Sep-2011

  EWD 389

Trip report I.U.C.C.Colloquium, Canterbury, 18th – 21st Sept.1973.

     I left for Canterbury on Tuesday morning after having lectured at the THE for two hours: these lectures had been so exciting (at least for me!) that I was still shivering when the train was well beyond Utrecht. Thanks to elaborate safety measures I was not hijacked, not bombed at either Heathrow, nor at West London Air Terminal, nor at Victoria Station. On that trip I had my only unpleasant surprise when I arrived at Canterbury station and discovered that, contrary to what had been suggested by mail, no one was there to pick me up, while taxis were absent as well. Some one —as it turned out, he was from the University— knew how to get a taxi: around the corner of the station, there was an anonymous wooden box attached to the wall that could be opened and contained a telephone for which you had to pick up the receiver and turn the handle.... I guess it was the kind of equipment that frightened my grandfather.

     The I.U.C.C Computer Science Colloquium was primarily intended for younger staff members of university computation centres. Besides them the audience contained a certain number of —as a rule also young— staff members from computing science departments and people from a number of polytechnics. Its purpose was to upgrade them by providing a forum; the Colloquium was not devoted to a particular theme. The number of older participants was very small (Wilkes from Cambridge, Rogers from Bristol, Michaelson from Edinburgh, Gilles from Glasgow, and a few others, on a total of 300 participants).

     I was one of the three invited speakers and started the Colloquium on Wednesday morning. On Thursday morning Sumner from Manchester spoke in that capacity, on Friday morning captain Grace M.Hopper. (On the schedule she was still announced as "commander" but she had been promoted to captain on I think the 15th of August.) Captain Hopper spoke officially about "Programming Languages"; her real subject was how she had acted as midwife to COBOL and she talked more about t he Pentagon and about the U.S.Navy than about programming. She did so for seven quarters of an hour, it was sometimes funny and I have been told that but for one new joke it was the same talk that she had given in York earlier this year. It was very illuminating: it gives a sheltered academic mind such as mine some glimpses into the organization of power and the power of organization. Sumner spoke officially about the mutual influence between hardware and software design. Perhaps he thought he did in fact as well. He gave —and in view of the youth and limited knowledge and experience of the average participant this may have been a very good thing— a clear exposé of the problems caused by the unpredictable flow of control in pipelined machines, when you wish to keep the flow at maximum density. But the amazing thing was that he considered "jump instructions" as a kind of unpleasant surprise in the machine code string. The way he talked about "programming" struck me as old-fashioned: in Manchester they lead a very isolated life, I am afraid. He could have profited perhaps at this Colloquium from the exposure to others, were it not for the fact that he arrived just before he had to speak and he left immediately afterwards. (So did Grace Hopper as well.) Narrow minded and pragmatic are the best terms, I am afraid, in which to describe the Manchester spiritual climate. It is a pity and it is even somewhat frightening.

     I gave a talk on the influence of correctness concerns on the process of program composition and I stuck to my title (this in contrast to my Newcastle performance a few weeks earlier). Maurice Wilkes did not like my talk at all and said so in private. He felt that I had been "extremely formalistic" and that I had paid too much attention to technical details in the development of my small examples. I was quite depressed when he told me this; I thought that I had done a good job —in view of my recent experiences in the USA I had done it slowly, for I don't like to lose an audience— and usually people find me too abstract (that was the complaint last spring, when I spoke to the staff members of the THE Department of Mathematics.). Thanks to the fact that I stayed another two days I have left the colloquium with quite another impression of how my talk went down: at least with a considerable fraction of the audience extremely well. Many youngsters have come to me to thank me and tell me, how delighted they had been, because now they knew what was meant by proving things about programs etc. I had the opportunity to speak about another hour with Wilkes and he is clearly from a different cultural background. Very pragmatic and grown up in a period where insufficiency of the available theories was rather rule than exception.

     I have not attended all other presentations: there have been parallel sessions (a little bit) and sometimes I played truant, talking with someone else outside the lecture theatre. What was presented was not inspiring; again very pragmatic. Sampling under control of the real time clock values of the instruction counter during program execution and translating these values back into "source code text places" in order to get an idea of where the computer spent its time while executing FORTRAN programs and then using this information for tuning of programs was one of the best examples! Many were worse. In particular the "projects" assigned to students (or groups of students) were very depressing. We must bear in mind, however, in view of the fact that the colloquium was organized by an organization of computation centre directors, what was presented may perhaps may not be regarded as characteristic of British Computing Science today. (Although I have some fears....)

     On the evening of the first full day we had as guest speaker Dr.S.H.Mandil from IBM UK Scientific Centre, Peterlee on "Trends in Data Base Technology". It was an unexpectedly good talk in the sense that it contained hardly any IBMerese. (Well, he was an old pupil of Tony Hoare!) He gave three "models", a hierarchical one, one with chains and one with relations. What, in doing so, he demonstrated most clearly was the insufficiency of the current way of talking and thinking about data bases. Basically it was still the fuzzy jargon of the commercial world, only cleaned up slightly. It is terrible to see people struggling with problems, attacking them in a way that cannot be adequate. And I am afraid that that was the case here as well. Mandil was refreshing compared with the others: he was not purely pragmatic and he did an honest effort to find some applicable theory that for instance could be used to clean up some of the adhoccery. Also, he, however, made upon me a rather isolated impression.

     In general, I would have expected (and justified) more isolation in industrial research units than in academic research units. Universities do have some sort of tradition in communicating: it is even part of their business. But again, perhaps I am naive: most of the academic groups, even those engaged in the educational side of the business, struck me as isolated. And usually this has not a good effect: inbreeding, "not-invented-here" or just a cluster of incompetence, protected by ignorance.

24th September 1973 | dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Mon, 12 Sep 2005

  EWD 391

Self-stabilization in spite of distributed control

by

Edsger W. Dijkstra, BURROUGHS

Abstract: A system of finite state automata can be built in such a way that regardless their initial states, the total system will converge in a finite number of steps towards a synchronization regime.

Key words: self-stabilization, distributed logic, mutual exclusion,
synchronization, co-operation, concurrency.

CR Category: 4.32

Author's address:
Burroughs,
Plataanstraat 5
NUENEN — 4565
the Netherlands

1st October 1973

Self-stabilization in spite of distributed control

A systematic way for finding the algorithm ensuring some desired form of co-operation between a set of loosely coupled sequential processes can in general terms be described as follows: the relation “the system is in a legitimate state” is kept invariant. As a consequence, each intended individual process step that could possibly cause violation of that invariant relation has to be preceded by a test that it won't do so, and depending on the outcome of that test the critical process step is either caused to take place or it —and with it the process of which it is a part— is delayed until a more favourable system state has been reached. With a suitable choice of the set of legitimate states one can indeed introduce the rule that a critical process step will be delayed only as long as its execution would lead to violation of the corresponding invariant relation.

The resulting design is readily implemented if the different sequential processes can be granted mutually exclusive access to a common store in which the current system state is recorded: then a relation between (the values of) the variables in that commonly accessible store is then the core of what we could call “the centralized control”.

A complication arises when there is no such commonly accessible store and “the system state” must be recorded in variables distributed over the various processes, and furthermore the communication facilities are limited in the sense that each process can only exchange information with “its neighbors”, a (possibly small) subset of the total set of processes. (We can view the processes as the nodes of a connected graph in which each of the (sparse) set of edges denotes the neighbor relation.) The complication is that a node's behaviour can only be influenced by that part of the total system state description that is available in that node: local actions taken on account of local information must accomplish a global objective. Such systems (with what is quite aptly called “distributed control”) have been designed, but all such designs I am familiar with are unstable in the sense that, when once in an illegitimate state, they could remain so forever. I call a system “self-stabilizing” when, regardless its initial state, it is guaranteed to arrive at a legitimate state in a finite number of steps. (Whether the property of self-stabilization is interesting either as a start procedure, or for the sake of system robustness or merely as an intriguing problem, is a question that falls out of the scope of this article.)

Unable to decide on theoretical grounds whether non-trivial self-stabilizing system with distributed control could exist at all, I decided to try to design one under the following constraints and objectives.

We consider a system built from N+1 finite state machines numbered from 0 through N. (The state space for the total system is then the Cartesian product of the N+1 individual state spaces of the respective machines.) The machines are arranged in a ring, i.e. for 0 ≤ j < N, machine nr.i has machine nr.i+1 as its righthand neighbour, and machine nr.N has machine nr.0 as its righthand neighbour.

In the middle of the ring stands a demon, each time giving, in “fair random order” one of the machines the command “to adjust itself”. (In “fair random order” means that in each infinite sequence of successive commands issued by the demon, each machine has received the command to adjust itself infinitely often.) Upon “adjustment” a machine goes into a (new) state, which must be a function of its own (old) state and the current states of its (two) neighbours.

Furthermore, as a function of its own state (and possibly of the states of its neighbours) a machine may be “privileged”. The legitimate states are defined as those states in which exactly one machine is privileged and for which all possible successor states are legitimate as well; furthermore it is required that then the privilege will rotate around the ring.

Side remark. I was hoping for an existence proof of self-stabilizing systems with distributed control: a ring is then one of the most natural, simple connection graphs. My choice of legitimate states, viz. requiring convergence towards a solution of the mutual exclusion problem is understandable for historical reasons [1], [2], [3], [4], it is also justified by its central position in the whole field of controlling co-operation between loosely coupled processes. Finally, the choice of the demon was suggested by a recent experience with a cyclic relaxation problem in which “fair random relaxation” would converge to a limit, while simultaneous relaxation could lead to oscillation (EWD386, unpublished). So much for the justification of the problem choice.

Again I beg my intrigued readers to stop reading here and to try to solve the stated problem themselves, for only then they will (slowly!) build up some sympathy with my difficulties: the problem has been with me for many months, while I was oscillating between trying to find a solution and trying to prove the non-existence of a solution. And all the time I had no indication in which of the two directions to aim, nor of the simplicity or complexity of the argument —if any!— that would settle the question

*          *
*

The crucial observation is that, in general, the problem cannot be solved if, in addition, we require our machines to be identical. For if the number of machines is non-prime, our starting situation can have a cyclic symmetry of degree n (2 ≤ n ≤ N/2) and if then the demon —and he is free to do so!— gives his first n commands equally spaced around the ring, the cyclic symmetry will not have been destroyed. If the demon continues with such fair (but nasty) behaviour, we shall never reach the state after which, forever, a single machine will be priviliged. Making not all machines identical can be accomplished in two extreme ways: either by making them all different or by making one exceptional. In view of our obligation to enforce asymmetry, one machine exceptional and all others mutually equal seems the most promising choice.

Secondly, it is not a priori excluded that the net effect of the command “adjust yourself” is nil, viz. that the new state of the machine to which the command was given equals its old state. In the legitimate state we have no particular desire to let the adjustment command have any effect when given to a machine far away from the privileged one. To simplify matters we can look for a solution in which the adjustment command has only effect when directed towards a machine that at that moment is privileged, and the result of whose adjustment will be that it loses its privilege. When now the function “privileged” is chosen such that at least one machine must be privileged, then “dead ends” are excluded a priori: the ring will remain alive, and we can concentrate on the requirement that the system converges to the state from where a single privilege will rotate past all machines.

Thirdly, we may feel tempted to introduce some sort of counters, but because we are confined to finite machines, true counters are excluded and the best we can hope for are counters counting modulo K, where K is some sufficiently large constant (certainly >1). For two counter values modulo K, the maximum or minimum is not defined and we cannot hope to establish progress towards the legitimate state because some “maximum counter value” decreases. Well-defined are equality and a successor function that can be applied a limited number of times without leading to ambiguity. This suggests to define the function “being privileged” in terms of equality of states.

In terms of equality we can define a function “being privileged” such that at least one machine is privileged quite easily when bearing in mind that one machine —let it be machine nr.0— should be exceptional. Let for 1 ≤ i ≤ N machine nr.i be privileged when its state differs from that of machine nr.i-1, i.e. when x[i] ≠ x[i-1]. We choose this —rather than the other way round— because now non-privileged implies x[i]=x[i-1]$ and equality is transitive: in other words, when all machines except machine nr.0 are non-privileged, x[0]=x[N] and when we define this as the condition for machine nr.0 being privileged, our requirement of at least one machine being privileged is therefore met.

Further we had suggested that adjustment would cause the machine in question to lose its privilege. For the normal machines (1 ≤ i ≤ N) we have no freedom anymore: adjustment of machine nr.i means

“if x[i] ≠ x[i-1] then x[i] :=x[i-1] fi”

For the exceptional machine nr.0 I now suggest

“if x[0]=x[N] then x[0] := (x[0]+1) mod K fi”

and it is only here, where a new state has to be generated and that it becomes significant that we consider the machine states x as a counter modulo K.

To start with we remark that when a machine “fires” —if we may use that term for the non-nil adjustment that takes place when the demon gives the command to a privileged machine— it loses its privilege, it may give the privilege to its righthand neighbour and to no one else. Because at least one machine must be privileged, firing of the only privileged machine will always give the only privilege to its righthand neighbour: once in a legitimate state the system will remain in a legitimate state and the privilege will rotate around the ring.

Furthermore, suppose that the exceptional machine is not privileged, i.e. x[0] ≠ x[N], then in a finite number of commands it will become privileged. For let j be the minimum value such that x[j] ≠ x[0]; because j is the minimum value, x[j-1]=x[0] and therefore x[j] ≠ x[j-1], i.e. machine nr.j is privileged. In a finite number of commands the demon will point to it, thus increasing j if j<N or making x[N]=x[0] if j=N, i.e. making the exceptional machine privileged. So the exceptional machine will continue forever to get the opportunity to fire.

Let us now investigate what happens when we start the system in an arbitrary state. When the exceptional machine fires for the first time, we colour its new state blue and all other states white; from then onwards each state created by the exceptional machine or copied from a blue state by a normal machine will be blue as well. If h is the number of times the exceptional machine fires when x[N] is still white, then —because K>1— h will satisfy h ≤ N: after the first firing, the copying process along the chain of normal machines can supply machine nr.N at most with another N-1 further white state, differing in succession.

Without loss of generality we could have chosen initially x[0]=K-1. If k ≥ N, then the first N firings of the exceptional machine have created the blue states from 0 through N-1, and scanning the blue states, starting at the exceptional machine and going to the right, we find a sequence of non-increasing blue x-values. At the next firing of the exceptional machine with x[0]=N-1, also x[N]=N-1 must hold. At that moment, however, x[N] must be blue as well and therefore all states must be =N-1, i.e. the system has arrived in one of its legitimate states. And this completes the proof for self-stabilization provided K ≥ N (and for smaller values of K counter examples kill the assumption of self-stabilization).

*          *
*

So far, so good, but one may object that I have introduced a rather powerful demon that may be very awkward to implement. Can we eliminate that centralized agency, can we replace it by “a distributed demon”?

Each variable x[i] is only inspected and assigned to by machine nr.i and only inspected by its righthand neighbour. We assume each variable x[i] equipped with its own, private two-way switch, excluding simultaneous access by the two neighbours it connects. And for the machines we assume that they will adjust themselves with a finite speed and a finite frequency, instead of waiting for the demon's command. Does it work? Amazingly it does without any further refinements.

Two simultaneous adjustments of non-neighbouring machines have no mutual interference at all. An adjustment by the exceptional machine cannot suffer from simultaneous activity of its lefthand neighbour nr.N, because x[N] is inspected only once per adjustment. But adjustment of a normal machine nr.i, although possibly inspecting x[i-1] twice during a single adjustment, cannot suffer from its lefthand neighbour activity either: if x[i-1] changes its value between the two inspections, the first value differed from x[i]; if the second value differs from x[i] as well, the program behaves as if this value was also offered the first time, if the second value equals x[i], the assignment has no effect and it is as if the adjustment has not taken place at all!

Conclusion. Self-stabilizing systems with distributed control do exist in the sense that local decisions force the system towards satisfying and then maintaining a global requirement. In particular, local mutual exclusion is a sufficient building block for eventually achieving mutual exclusion globally.

References.

[1] Dijkstra, E.W. Solution of a problem in concurrent programming control. Comm. ACM 8, 9 (Sept.1965), 569

[2] Knuth, D.E. Additional comments on a problem in concurrent programming control. Comm. ACM 9, 5 (May 1966), 321–322

[3] de Bruijn, N.G. Additional comments on a problem in concurrent programming control. Comm. ACM 10, 3 (March, 1967)

[4] Eisenberg, M.A. and McGuire, M.R. Further comments on Dijkstra's concurrent control problem. Comm. ACM 15, 11 (Nov. 1972) 999

transcribed by Xiaozhou (Steve) Li
revised Wed, 17 Jan 2007

EWD392

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Self-stabilization with four-state machines.

We consider a sequence of N+1 finite state machines, numbered from 0 through N; two machines are “neighbours” if and only if their ordinal numbers differ by 1.

For each machine one or more “privileges” are defined, i.e. boolean functions of its own state and the state(s) of its neighbour(s). A “move” consists of selecting one of the privileges currently present and bringing the machine enjoying it in a new state that must be a function of its old state, the state(s) of its neighbour(s) and the privilege selected (the latter can only apply in the case of a machine that can enjoy more than one privilege simultaneously).

We call a state of the total system “legitimate” if and only if

1) | exactly one privilege is present and, therefore,exactly one move is possible, and
2) | the execution of the only possible move will again bring the total system in a legitimate state, and
3) | successive moves will cause each privilige to be present with equal frequency.

We are interested in designing a set of machines, privileges and machines, such that, in addition, the system enjoys the property of“selfstabilization”, i.e. regardless the initial state and regardless the privilege selected for the next move, it must always be possible to do a next move and after a finite number of moves the total system must arrive at a legitimate state. It is the requirement of self-stabilization that makes the problem non-trivial.

For each machine nr.i (0 ≤ i ≤ N) we introduce two booleans, called “x[i]” and “up[i]” respectively. In the “bottom machine” up[0] = true holds permanently, in the “top machine” up[N] = false holds permanently, all other booleans are variables. In other words, the top machine and the bottom machine are two-state machines, the so-called “normal machines” (i.e. 0 < i < N) are four-state machines.

For all machines nr.i with 0 < i ≤ N the “privilege from below” is defined as

| x[i] ≠ x[i-1] :

for the normal machines the corresponding move is defined as

| x[i]:= non x[i]; up[i]:= true

but for the top machine —who has up[N] = false permanent1y— the move is reduced to

| x[N]:= non x[N] .

For all machines nr.i with 0 ≤ i < N the “privilege from above” is defines as

| x[i] = x]i+1] and up[i] and non up[i+1] :

for the normal machine the corresponding move is defined as

| up[i]:= false

but for the bottom machine —who has up[0] = true permanently— the move is given by

| x[0]:= non x[0] .

If neither machine nr.0 nor machine nr.1 is to have a privilege, x[1] = x[0] and up[1] = true should hold; if in addition machine nr.2 should also have no privilege, x[2] = x[1] and up[2] = true should hold as well. Repeating the argument we see that the assumption of “no privilege at all” would lead to the conclusion up[N] = true, but as this contradicts the truth we conclude

Theorem 1: There is at least one privilege.

Furthermore we can conclude —the proofs are left to the reader—

Theorem 2: Each move destroys the privilege that allowed it.

Theorem 3: If machine nr.0 has a privilege, machine nr.1 has not a privilege from below; a move by machine nr.0 will give a privilege from below to machine nr.1.

Theorem 4: If machine nr.N has a privilege, machine nr.N-1 has not a privilege from above; a move by machine nr.N may give a privilege from above to machine nr.N-1 (and will certainly do so in the legitimate state on account of Theorems 1 and 2).

Theorem 5: If a normal machine nr.i does a move on account of a privilege from above, it can only affect the privileges held by nr.i and by nr.-1; machine nr.i is sure to lose its privilege from above, a new privilege from above may be created for machine nr.i-1 (and this will certainly happen in the legitimate state on account of Theorems 1 and 2).

Theorem 6: If a normal machine nr.i does a move on account of a privilege from below, it can only affect the privileges held by nr.i and by nr.i+1. There are now two cases to consider:
a) Originally x[i] ≠ x[i+1] : machine nr.i and machine nr.i+1 will both lose their privilege from below, for machine nr.i a new privilege from above may be created;
b) Originally x[i] = x[i+1] : machine nr.i will lose all its privileges and for machine nr.i+1 a new privilege from below will be created (and this will certainly happen in the legitimate state on account of Theorems 1 and 2).

Corrolary 1: If a normal machine nr.i does a move on account of a privilege from below (above) and this privilege is not transferred to machine nr.i+1 (nr.i-1), then the total number of privileges is decreased.
Corrolary 2: No move increases the total number of privileges.
Corrolary 3: A normal machine enjoying both privileges cannot do a move without reducing the total number of privileges.

From the above it follows that in the legitimate state a privilege from below will go upward until the top machine reflects it as a privilege from above, until that again is reflected by the bottom machine as a privilege from below, etc. All our requirements of the legitimate state have been met. Self-stabilization now follows from the corrolaries.

We can ask ourselves: what is the minimum value for k(N), such that after k(N) moves the system must be in a legitimate state? The answer is that k(2) = 2 and for N > 2, k(N) = N²- N + 1. My demonstration for this result is unelegant and the exact value of the bound is not important enough to waste printing space on it.

*              *
*

More important is the question, whether we can eliminate —or rather: distribute— the tacitly assumed demon, who was supposed to see to it that at any moment in time only one move was made. For this purpose we assume that each machine state is equipped with a private switch, guaranteeing that while a machine changes its state, no neighbour can inspect it; the changing or inspecting of a state are regarded as undivided actions. The bottom machine and the top machine can now be regarded as cyclic processes, inspecting if their privilege is present and if so, doing their move, while each normal machine can be regarded as a cyclic process that investigates the presence of its two possible privileges alternatingly and upon finding a privilege will do the corresponding move before investigating the presence of its other privilege.

The analysis is simplified by the fact that inspection for the presence of a privilege implies only one neighbour and —if the privilege is present— the move is then a completely private affair.

If a normal machine nr.i enjoys two privileges, simultaneous execution of the two possible moves would lead to conflicting assignments to up[i] but this conflict is prevented from arising by the postulated sequential nature of the normal machines.

Simultaneous moves by two different non-neighbouring machines cannot interact at all and we are therefore left with the analysis of simultaneous moves by two neighbours.

If machine nr.i observes a privilege from below and machine nr.i+1 a privilege from above, no common states are involved and the net result is as if the moves were done in some order. If machine nr.i observes a privilege from above, machine nr.i+1 can observe no privilege at all and the question of simultaneous moves by nr.i and nr.i+1 does not arise. We are left with the case that machine nr.i and machine nr.i+1 both observe a privilege from below; simultaneous moves would interfere in the sense that upon completion of the moves. machine nr.i+1 would not have lost its privilege from below. As a matter of fact a whole sequence of machines might simultaneously detect the privilege from below and act upon it simultaneously. The net effect, however, is as if the moves of the sequence had been done in order of decreasing ordinal number. As a result, even with the distributed demon, self-stabilization has been achieved.

*              *

*

Finally we observe that any normal machine enjoys in the legitimate state twice as often a privilege as the two end-machines. We can close the ring, merging the two end-machines into a single exceptional machine: this then is a four-state machine like the others and will enjoy a privilege with equal frequency as all the others.

12th October 1973 |   prof.dr.Edsger W.Dijkstra
BURROUGHS |    Research Fellow
Plataanstraat 5 |
NUENEN - 4565 |
The Netherlands |

Errata to EWD391: page EWD391 - 5, 6 lines from below: for “non-decreasing” read “non-increasing” page EWD391 - 6, 10 lines from above: for “.” read “,provided K > N.” page EWD391 - 6, 8 lines from below: for “Solutiong” read “Solution”.

Note. The second erratum —courtesy drs.C.S.Scholten— shows a serious flaw in my reasoning; I should have known better!

| EWD.

Note to readers of EWD392: The reading of this report is made less difficult when you have a set of draughtsmen at hand; while writing it, I used the set of my oldest son.

| EWD.

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD393

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On representational abstraction.

The usual higher level programming languages provide us with the type “integer” allowing us to prescribe “a:= b + c” or to assert “a = b + c”, regardless of the internally chosen interpretation. This is great, for the alternative would have been to regard these variables as bit strings, say; this would have been nasty in two respects: instead of asserting “a = b + c” we would find ourselves forced to write down the equations of the binary adder —which on that level would only add to the confusion—, secondly we would be overspecific, because we would (presumably) not object if our program operating on integers would be executed on a decimal machine! So much for the power of representational abstraction. Its power is so great that we would like to exploit it at higher levels as well. We should, however, be aware of one vital fact, viz. that while the highest level program does not fix a representation for variables of type “integer”, it is fixed somewhere an how, viz. in the implementation: someone has to bother!

The most innocent way of regarding “a type” is as “an attribute of variables of that type”, i.e. as the collection of different possible values a variable of that type can have. (How this collection of different values is defined is another matter: either by enumeration or by some BNF-like recursive technique I guess.)

We should be aware of the fact that this abstract definition of the set of possible values is only one side of the coin: to compare it with the procedure concept —embodying operational abstraction— it is as if we have given an axiomatic definition of the semantics of the call without —as yet— specifying an adequate body.

To do justice to this observation we could talk for the purpose of this discussion about “ an implemented type”i.e. a defined class of values together with a proposal as how to represent these different values. In addition it should contain a proposal for the algorithmic operations on the consituents of the representation in order to “model” the operations on the abstract values.

In the simplest case this proposal associates with each abstract value one or more points in a little state space which is probably regarded as the Cartesian product of smaller —“known”— state spaces. (One in the case of “a unique representation”, more in the case of a “non-unique representation”. Note that not all points in our little Cartesian state space need to correspond to a possible value of the abstract type!) In any case our proposal for representation needs to give the correspondence between abstract values and points in the little state space.

On the above level of vagueness, everything is still OK: we have not said much yet that could contradict itself. Let us, therefore, look for problems. There seems to be a marked difference between operational abstraction and representational abstraction in the following sense. Given a program with procedures the replacement of one procedure body by a semantically equivalent one is a straightforward operation: the choice of the body is only reflected in the “static” program text and in the (volatile!) happening when the program is executed: with modest precautions it is even possible to replace during execution of a program one body by a semantically equivalent one that will be exercised during the second half of the computation.

The choice of representation, however, spreads all through the state space of the computation: to start the execution of a program in binary arithmetic and to switch half-way to decimal arithmetic is certainly not such a trivial operation. One can even start asking oneself, whether one could have both representations simultaneously: could we have simultaneously “binary integers” and “decimal integers”? The fact that there are machines with both binary and decimal arithmetic —at least: machines that are presented as such— seems to make this question meaningful. It is, however, utterly misleading.

There are no such things as “binary integers”, nor “decimal integers”. Both names are misnomers! The integers, according to Kronecker created by the Good Lord and subsequently defined by the axioms of Peano are a concept in which “a number system” has no place, let alone a specific number system. We can have as types (possibly bounded) integers, and/or bitstrings and/or decimalstrings. But neither a string of bits, not a string of decimals can be an integer. We can associate —but this is at least a conceptual transfer function!— with either string an integer value, but in both cases that requires a quite distinct additional convention.

(In this connection it is illuminating that the definition of a programming language like ALGOL 60 does not mention a thing about internal representation of integer variables, this in sharp contrast to most machine manuals that usually start with ... a detailed description of the number representation, the last thing that should be of any importance for the programmer! Instead of operating on integers, one has there to operate on the constituents of a specific representation and that is, of course, one of the reasons why machine code programming is so tricky: you really have to know the tules for representing negative numbers on a binary machine before you can translate the test “even(x)” into an inspection of X’s least significant digit. As an aside: from previous confrontations with COBOL I have retained the impression of an endless conceptual confusion between integers and strings of decimal digits ....)

Similarly there is no “binary arithmetic” nor “decimal arithmetic”: Peano did not mention radix systems in his axioms!

Let us now assume for a moment that we have a binary machine with a number of “decimal operations” as an added facility; how are we going to use it? (Note 1. It will become apparent that such an added facility is to a large extent an added nuisance — as usual?— but we shall investigate its use nevertheless. Note 2. The dual number representation is a rather microscopic example of non-unique representation: for more sophisticated types than integers it becomes more interesting.) In a purely binary machine our higher level code does know nothing about the number representation; in our mixed machine we should stick to that same level of transparency. I.e. if an integer value can be represented by a string of bits or a string of decimals (or possibly both) we should have what on that level is called “a tag”, indicating which is the case. (A proposal could be something on the following lines:
1)     if both operands are available in one kind only and the kinds are equal, produce the result of the same kind
2)     if both operands are available in one kind only and the kinds differ perform concurrently bot transfer functions and then act as
3)     if both operands are available in both kinds, produce concurrently the result of both kinds
4)     if one operand is available in both types, the other one in one kind only. produce a result of the latter kind, etc.

The above is not a serious proposal, it is intended as an example how the implementation could try to choose at any moment the most convenient alternative.)

It could very well be that the programmer knows that for some variables a specific representation is more adequate than another. (This is particularly true when you have variables of the type “set”.) But it is my feeling that such knowledge should be transmitted to the implementation in the form of “a hint”: a parameter of the declaration that introduces the variable. It is then up to the implementer to decide how much attention will be paid to the hint. (In our example: even with hints of the form “integer (dec)” and “integer(bin)” a program executed on the machine with the decimal facilities should be transferrable to a machine without the decimal facilities without any change —the purely binary machine implementation can be expected to ignore hints to do something in a locally impossible way!

One can argue with respect to such a text with hints: “Is the programmer now aware of the representation or is he not?” Well, both of course! He creates the major part of his text as if he could ignore the representation, but he knows full well that if such an abstraction is insufficiently truthful, this full separation of concerns is denied to him and he has to develop a controlled schizophrenia. That is what all programmers sometimes are forced to do: we only try to assist him in controlling his schizophrenia. What we try to achieve is that, although the program is perhaps only realistic when the “hints” are taken into account, yet the program without the “hints” can be regarded as “logically complete”.

*              *
*

For the sequel I take the position that we aim at a strict textual separation between the places where the abstract variable is considered as an unanalyzed whole and where it is considered as a composite object. Note that this is meant to be a drastic decision, for instance damning ALGOL 60 —and many other programming languages— where on the same level one can equally well refer to an array as a whole as to its individual elements, allowing procedure calls such as “P(A, A[i])”, which I would prefer to consider as confusing horrors.

If we take such an attitude, we should pay attention to the following question —even if we do not have complete and completely satisfactory answers to them:
a)     What are exactly the benefits that we hope to derive from such a separation?
b)     What type of interface do we suggest between the two levels?

A clear benefit is presented by the circumstance that —provided that the abstract variable has decent properties— the upper level program can be much clearer to understand and —even formally— easier to prove to be correct. A program operating on complex numbers becomes mystified when you express it in real and imaginary parts! (Most formal proof systems that have been mechanized —King’s “Verifying Compiler” and the like— seem to suffer from the fact that they carry out the proofs in terms of the primitive data types handled: the proofs become very quickly unwieldy.)

A second benefit arises as soon as not all points of the local little state space —built up as the Cartesian product of the state spaces of the components— actually correspond to a value of the abstract variable. In that case there is redundancy, a relation in that little state space must be kept invariant. The textual separation pins the obligation to maintain such an invariance quite explicitly down on that part of the text that manipulates on the individual components. As many program improvements boil down to a trading of storage space for computation time by storing redundant information —that might be absorbed in the representation of an abstract type?—, this second benefit also seems to be important. (It is here where the “unsafeness” of for instance the PASCAL record really begins to hurt!)

As the third benefit I see the possibility to change the representation of an abstract type: in a sense the language “scope rules” will tell you which parts of the program remain unaffected. There is a fourth potential benefit of which I am not quite sure: it might be to far-fetched, but you never know in these days of privacy and security. It is conceivable that we would like to be able to give partial access to information only; and mind you, this will not necessarily be that certain bits are inaccessible and therefore unable to influence the course of the computation: while the “age of a person” might be hidden, you may yet get permission to compare the ages of two persons: the relational operator “older than” might be at your disposal! I think that more convincing examples can be constructed....

Let us now turn to the question b), what type of interface we do suggest between the two levels.

We cannot only define an abstract variable, its layout in store, so to speak, we must define operations and functions as well. In the case that the abstract variable is represented by an enumerated set of variables —such as you can declare at block entry— it has been suggested by C.A.R. Hoare —I cannot give the exact reference, I think it was ACTA INFORMATICA— to write a block with

a) | the declarations of the components needed to represent an instance of the abstract variable, together with their initialization

b) | functions defined on a variable of such a type: the algorithm would then refer to the components of the abstract variable

c) | updaters, i.e. operations modifying the value of the abstract variable.

In the case of, for instance, the complex number, there would be certainly the two functions “re” and “im”. They can be regarded as “characteristic functions” in the sense that if you know these two values you know all there is to know about that complex value. If “z1” and “z2” are then two complex variables, the condition that they have equal values can be written “z1.re = z2.re and z1.im = z2.im”. And for some time I have felt that among the definition of the abstract type there must be enough so as to be able to write a program (on the upper level!) that can determine whether two values of the abstract variable are equal. (As I have just done for the complex numbers.) I am no longer so sure of the reasonableness of the requirement in view of the fourth (potential) benefit. (In the example there is a way of establishing equality of the unaccessible ages, because “A older than B or B older than A” is equivalent with “A.age ≠ B.age”.)

I am beginning to feel now, that “equality of values” is such a fundamental property that we should allow the algorithm establishing the equality of two values to be expressed on the lower level in terms of the values of the composing parts. The syntax suggested by Hoare would make this equality test an asymmetric algorithm, because he presented these lower level algorithms as within an inner block with one instance in the surrounding block. Also the operation “swap(a, b)”, where a and b are variables of the same abstract type that should exchange their values is only very clumsily coded in his suggestion. In other words, Hoare’s suggestion that the lower level algorithms are always executed subordinate to one instance of the abstract variable and will have explicit access to the components of that variable only, seems too restrictive. Up till now I do not have a better proposal.

*              *
*

Finally I draw attention to the fact that the introduction of fancy types may be expected to increase the number of partial functions and operations. With the current sequencing primitives the upper level programme: has to sequence his program explicitly in such a way that none of these functions or operations is invoked outside its domain. For robustness sake, however, the lower level implementation will start checking ... that the operation is not invoked outside its domain. First you give a complicated duty to the upper level programmer, next you check dynamically that the upper level programmer has not violated any of the rules! I mention, just for the record, that my tentative notion of the “guarded command” is intended to present a better interface.

NUENEN - l6th November 1973         prof.dr.Edsger W.Dijkstra

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD395

Trip report E.W.Dijkstra IFIP Working Group W.G.2.3 "On Programing Methodology", 21st - 26th October 1973, Blanchland, England

From sad experience we all know that the hardships of travel are the certain price to be paid for possible pleasures; in this case both terms of the cost/benefit ratio were extremely high.

Basing himself on ample evidence collected in the past Mike Woodger was certain that the train by which the two of us travelled from London to Newcastle would arrive in Newcastle dead on time. It was an "Intercity Train" at least, I even got the vague impression that it was one of the trains with a fancy name as well (could it have been "The Abelonian"?). But all this could not prevent a derailment, as a result of which we arrived in Newcastle at 8.00 p.m. instead of the scheduled 6.27; in Newcastle they had waited for our arrival and somewhere after 9 p.m. we arrived in Blanchland at the Lord Crewe Arms Hotel, just in time for the postponed evening meal.

We left Blanchland in the early afternoon on Friday 26th. With Brian Randell and Gerhard Seegmüller (from Munich) we arrived at the University Computing Laboratory, where Gerhard gave a talk, most of which I could attend, but slightly before he had finished I had to leave in order to catch the six-o'clock flight from Newcastle to Amsterdam: at a quarter to nine I would be landing in Eindhoven. I dislike missing planes, so I arrived in time, only to be faced with the logical problem whether one could catch a cancelled flight. So I was flown to London, from where after two hours in the departure hall, a KLM flight would take me to Rotterdam. But this one was cancelled as well and at half past twelve --courtesy of KLM-- I found myself again alone in a hotel bed. On Saturday morning my take-off was scheduled at 9.35, but this flight was delayed for at least two hours and thanks to the fact that I had hand luggage only, I could switch to one of the last free places of another KLM flight, this time to Amsterdam. This fourth effort to cross the North Sea was successful and in the course of the afternoon my family picked me up at Eindhoven railway station. A three hour trip had taken me almost 21 hours.

The Lord Crewe Arms Hotel in Blanchland is eminently suited for a conference of this type. Blanchland is a very little, very old and rather isolated village --there is a bus connection to civilization once a week or something like that-- with a few hundred inhabitants and a good hotel in the ruins of the old monastery, with a multitude of "mind your step" and "watch your head" --I hurt mine thrice!-- passages. In the last night a blown fuse paralyzed my bedroom heating, with the result that I woke up shivering after what could only be called "a refreshing night". As I said, the hotel was eminently suited for a conference of this type, its monastic atmosphere was only ruined by Mike Woodger's portable radio with news about Nixon and the Middle East. (Exciting of course, but that was exactly the reason why I would have preferred to be without it!)

Our sessions were one and a half hour mostly: four of them on Monday, Wednesday and Thursday, two of them on Tuesday (excursion in the afternoon) and two of them on Friday morning. According to modern student standards, we made long days! And then I am not even counting the discussions in the evening. Personal circumstances made me write during two nights; as a result I was somewhat tired when I came home, but, as will become apparent in the sequel, it was worth it.

Our first session was devoted to the collection of material and the (loose) design of the time table. I offered two subjects, viz. "Self-stabilization and distributed control" and "Sequencing primitives revisited."

The remaining three sessions of the Monday were filled --he was the only speaker filling three slots-- by M.A.Jackson, an independent consultant from London who had undertaken, as an invited guest, to introduce the members of this group to commercial programming. He did a very good job. One of his major activities is to give two-day to five-day courses to COBOL programmers in which he taught them how to apply "structured programming techniques" in a COBOL environment. He did not expose us to such a course, he described his courses. He did an excellent job and his points were well taken. His central theme was that a file could be described grammatically as a regular expression --he made quite clear that while lecturing for the commercial programmers he avoided this term but explained it via pictures, of which he gave examples-- and that a program processing such a file should have a syntactical structure very much similar to that regular expression. In the end he showed the complications that arose when a program had to process two files of not the same structure. He called this "a clash of data structures" and showed how in a COBOL environment one could program around it; this last part was a convincing case in favour of coroutines. His contribution was a very good start; he --Jackson, I mean-- was quite nervous and only got more confidence after the first session.

The next morning we had another guest speaking, dr.R.M.Burstall of the Department of Machine Intelligence and Perception. He filled two slots describing "A system which automatically improves programs". But for the loaded term "improves" in the title he gave a very good talk, describing work done by him and J.Darlington. Their aim was to construct automatically efficient POP-2 programs out of LISP-like programs. One could be nasty and argue that the problem only existed thanks to the fact they started with LISP and was only significant as far as the economics of POP-2 were applicable, he did much more. In particular he showed --quite convincingly-- that equivalence theorems concerned with uninterpreted schemata were too weak a tool; secondly he convinced me (and many others for that matter) that optimization should be done "at the right level": it is easier to exploit the known theorem that the intersection of two sets is a symmetric operation when the primitive "intersection" is still explicitly mentioned than when the operation of constructing the intersection is described by an asymmetric program. The aims of the project he described were clear and modest, he gave --in spite of his tendency to speak very fast and somewhat flippantly-- a good description of it. Also our second day was very successful.

The first slot on the Wednesday morning was filled by Douglas T.Ross with a philosophical paper titled "PLEX: A Natural Philosophy. Its Theory, Language, Method and Model". He was more coherent than he had ever been in my presence although it was still absolutely impossible to take notes, as he never finished a sentence. As he said himself in the opening of his talk "Perhaps the only thing that will become clear is that I am past embarrassment". Well, to say the honest truth: we were embarrassed: later in the week there was a slot called "Feedback on Ross" and none of us was quite sure how to do that. Things improved greatly when his handout was distributed: 10 pages of which the first 8 were quite processible, only after the picture (!) on page 9 was I lost.

Then, after the coffee break, I had to fill a slot. I had decided to speak on "Sequencing primitives revisited". The start of this talk had taken place in Marktoberdorf, when I showed a different way of looking at Euclid's Algorithm during one of the dinners. I knew this was relevant when designing a proper interface catering for representational abstraction. During our --extra long!-- train trip I showed this to Mike Woodger, who after a long time, during which he did not see what I was driving at, suddenly became excited. It was on account of that excitement, that I offered the subject for the conference the next morning. Monday I had a second trial in private with Jackson and Burstall, during which I designed a tentative syntax to be able to show examples. Tuesday evening I could not sleep and found myself preparing my lecture: with the brains burning I left my bed at 2.30 a.m. and wrote for more than an hour. I filled my slot and at the end of it, I was half way. Some immediate rescheduling was done and the first slot of the afternoon was given to me as well; during that second slot I completed my presentation, covering six sub-subjects

Uniform treatment of multi- and uniprogramming

To show the equivalence of deadlock and termination

How to avoid certain forms of sequential overspecification

How to cope with certain forms of non-determinacy

How to retain certain symmetries of the problem statement in the problem solving algorithm

A proper interface element for representational abstraction.

I was quite excited --as a matter of fact I still am-- and convinced my audience, if not by reasoning, then at least by eloquence. The last slot was filled by Gerhard Seegmüller. He was torn to pieces and I am afraid that I was instrumental in doing so. As a director of a large computing centre he wanted to discuss with us a paper with design considerations for a systems programming language. The paper contained superficial descriptions of a few "how's" but none of the "why's". He complained about the fact that the people of this working group did not --although "Programming Methodology" was our subject-- provide him with the answers to his practical questions. It is exactly the strength of this working group that we do not pretend to have an answer if this, in fact, is not true. He is dangerously near the patient for whose illness medical science does not know a cure and who then blames the physicians for their inability to cure him. He then goes to a quack; as a matter of fact; he blamed us for not acting as quacks. All this was later cleared up and he saw that it had been mistaken to bring up this subject in this form with these expectations. He is a very nice man and it must be hard to keep your sanity in his position; I think he does remarkably well.

Thursday was bad. The first two slots were mr.D.J.Pearson from ICL, describing CADES, A Computer Aided Design and Evaluation System. For those who are interested in the way in which ICL has tried to control system design following the Chinese Army Approach, it may have been quite interesting. But it was depressing; of course "structured programming" and "levels" etc. are the terminology used to describe and defend the system, but it was all so terribly wrong. It struck me as first designing a vocabulary --in a loosely hierarchical manner--, then building --again in a hierarchical manner-- sentences from that vocabulary only to discover then that it does not fit: Great! Iterative Design Cycles! The reason for the misfit being, that while introducing the vocabulary they had not written the dictionary defining those terms. Sickening. Besides that, mr.Pearson's English was below any standards. During the second slot he could not keep my attention and I solved a problem mentioned by Burstall, using my new techniques, in an absolutely satisfactory manner.

After lunch, we were addressed by dr.P.Henderson from The Computing Laboratory of Newcastle University, describing how they intended to use a not yet implemented symbolic simulation system during program development. The idea of simulation at this symbolic level was not without attraction, but Henderson shocked his audience by his superficiality: in spite of the fact that he had given this talk now about twelve times during the last three weeks, his notion of "the states of a variable" was still a conceptual mess and his example contained a fundamental flaw. At first sight the Newcastle group may make a very active impression, but they produce noise with a productivity based on lack of standards rather than on insight. Disappointing and depressing.

The last slot on Thursday was filled by Harlan D.Mills from IBM who redid his old piece of the tree systems on the level sets of R. A cute observation disguised as an important theoretical insight, dressed up by all the formalistic pomp and circumstance that could be used to inflate a balloon. The audience gently pricked into the balloon but we are not sure whether he noticed it. He was pathetically keen on impressing us, both at the session and during private conversation --I checked this with a few other members of the group as well--. His performance was technically void but from other points of view quite illuminating. He has some connection with Johns Hopkins University; poor Johns Hopkins...

Last morning's first slot was taken care of by dr J.D.Roberts from Cambridge, a very shy speaker who presented his --massive!-- handout "Semantic Primitives for Secure Parallel Processing". The paper contains too much detail, the presentation, however, was quite nice. His paper, together with the one from Burstall, somewhat restored my confidence in English Computing Science (after the severe shock of the IUCC Symposium last September).

Our last session was "feedback on Ross". This, surprise, surprise, was not embarrassing at all! Ross managed to connect what he had been saying to my last solution of the Burstall problem --which was still on the blackboard--; it was then connected to the notion of critical sections and the conceptual framework of Anatol Holt. It ended quite exciting!

A final remark. EWD391/392 had been handed out and at the first scheduling session I had said that I would be perfectly willing to talk about self-stabilization, but that I would prefer if my audience had read those two documents prior to that. After three days I discovered that they had hardly been looked at. I see a new form of illiteracy emerging. These people can read (in principle at least), but thanks to Xerox, our input channels are getting blocked. We are faced with so much junk, that each time the threshold gets higher.

29th October 1973                           prof.dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Mon, 27 Sep 2004

EWD396

Self-stabilization with three-state machines.

I consider N+1 machines numbered from 0 through N (N > 1). In order to avoid avoidable subscripts in my text, I introduce for each machine nr.i a local terminology
L = state of machine nr.(i–1)mod(N+1), its “lefthand neighbour”
S = state of machine nr.i (S from “self”)
R = state of machine nr.(i+1)mod(N+1), its “righthand neighbour”.

For each machine one or more privileges are defined, i.e. boolean functions of L, S and R. A “move” consists of selecting one of the privileges currently present and bringing the machine enjoying it in a new state, i.e. S:= f (L,S,R), where the function f may depend on the privilege selected in the case of a machine for which more than one privilege has been defined.

We call a state of the total system “legitimate” if and only if
1)     exactly one privilege is present and, therefore, exactly one move is possible, and
2)     the execution of the only possible move will again bring the total system in a legitimate state, and
3)     successive moves will cause each privilege to be present with equal frequency.

We are interested in designing a set of finite state machines, privileges and moves, such that, in addition, the system enjoys the property of “self-stabilization”, i.e. regardless of the initial state and regardless of the privilege selected for the next move, it must always be possible to do a next move and after a finite number of moves the total system must arrive at a legitimate state.

Each machine is a three-state machine, its state being denoted by 0, 1 and 2; in the following “+” and “–”, when referring to machine states, are to be understood as operations, reduced mod 3 .

The machines nr.i with 0 < i < N are called “the normal machines”; they have two privileges:
the privilege   “S + 1 = L” allows the move  “S:= S + 1”  and
the privilege   “S + 1 = R ” allows the move  “S:= S + 1”.

Machine nr.0 —the so-called bottom machine— has one privilege:
the privilege  “S + 1 = R ”   allows the move  “S:= S – 1”.

Machine nr.N —the so-called top machine— has also only one privilege:
the privilege  “L = R and S ≠ L + 1”  allows the move  “S:= L + 1”.

We observe
0)     each move destroys the privilege allowing it
1)     at least one privilege must be present (no privilege among the bottom machine and the normal machines implies that they are all in the same state; if the top machine is not to have its privilege, it must be on account of  S = L + 1, which contradicts the assumption that its normal neighbour had no privilege)
2)     between two successive moves of the top machine, the bottom machine must have moved at least once.

We now consider the N differences between nr.i and nr.i+1 (0 ≤ i < N) and write a “+” between the two of each pair if the lefthand state is one higher than the righthand state, a “–” if the lefthand state is one less than the righthand state and nothing if they are equal. If the normal machine B does a move, we have five possibilities
a)     “A + B   C ” becomes “A   B + C ” (a “+” travelling to the right),
b)     “A   B – C ” becomes “A – B   C ” (a “–” travelling to the left),
c)     “A + B + C ” becomes “A   B – C ” (internal reflection of “+ +”)
d)     “A – B – C ” becomes “A + B   C ” (internal reflection of “– –”)
e)     “A + B – C ” becomes “A   B   C ” (mutual annihilation of “+ –”).
Transitions c), d) and e) reduce the total number of “+” and “–” signs.

A move of the bottom machine requires a “–” to the right of it and changes it in a “+”: it is a true reflection, leaving the number of “+” and “–” signs unchanged. A move of the top machine creates a “–” at the left of it —in doing so it may absorb a “+” in that position—, but on account of observation 2) it cannot do so in a higher frequency than the bottom machine absorbs “–” signs.

In the legitimate states there is only one “+” or “–” sign, travelling in the appropriate direction and being changed —and then reflected— at the ends.

Self-stabilization is now obvious. A move of the bottom machine absorbs a “–” gone to the left and produces in its place a “+” ready to go to the right. How is the bottom machine going to receive its next “–” in the non-legitimate state? Either because the right going “+” meets a pair “– –” (“+ – –” can reduce to “–”) or because it meets another “+” (“+ +” can reduce to “–”) that could have been created by “– –”. In order to stay away permanently from the legitimate state, the top machine would have to create two “–” signs for every single “–” arriving at the bottom machine. But this possibility is denied by our observation that between two successive moves of the top machine, the bottom machine must have moved at least once.

Note. In view of the fact that a three-state machine requires two bits, with which we can have four-state machines, for whom the problem of self-stabilization has already been solved, the result achieved here could very well be totally insignificant. This aspect of minimization of the number of machine states has reached the stage of a problem in pure mathematics and I shall not pursue it any further.

1st November 1973                                              prof.dr.Edsger W.Dijkstra
BURROUGHS                                                     Research Fellow
Plataanstraat 5
NUENEN - 4565
The Netherlands

transcribed by Chrys Alexander Panayiotou
revised 08-Sep-2013

EWD397

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Self-stabilizing systems with distributed control.

by Edsger W.Dijkstra *)

Abstract. In a system with distributed control the local rules of behaviour can guarantee convergence of the system as a whole towards satisfying a global requirement.

Keywords: multiprocessing, networks, self-stabilization, synchonization, mutual exclusion, robustness, starting, error recovery.
CR Category: 4.32

*) Authors address: | BURROUGHS
| Plataanstraat 5
| NUENEN - 4565
| The Netherlands

Self-stabilizing systems with distributed control.

We consider a connected graph in which the majority of the possible edges are missing and with a finite state machine placed at each node; machines placed in directly connected nodes are called each other’s “neighbours”. For each machine one or more so-called “privileges” are defined, i.e. boolean functions of its own state and the states of its neighbours; when such a boolean function is true, we say that the privilege is “present”. If a privilege is present, it can be “selected” and the corresponding “move” is then made, i.e. the machine enjoying the selected privilege is brought into a new state that is a function of its old state and the states of its neighbours; if for such a machine more than one privilege has been defined, that function may also depend on the privilege selected.

Furthermore there is a global criterion, telling whether the system as a whole is in a “legitimate” state. We require that
1)     in each legitimate state one or more privileges will be present, and
2)     in each legitimate state each possible move will bring the system again in a legitimate state, and
3)     each privilege must be present in at least one legitimate state, and
4)     for any pair of legitimate states there exists a sequence of moves transferring the system from the one into the other.

We call the system self-stabilizing if and only if regardless of the initial state and regardless of the privilege selected for the next move, always at least one privilege will be present and the system is guaranteed to find itself in a legitimate state after a finite number of moves. For a long time it has been an open question whether non-trivial (e.g. all states legitimate is considered trivial) self-stabilizing systems could exist. It is not directly obvious whether the local moves can assure convergence towards satisfaction of such a global criterion; the non-determinacy of the privilege selected is an added complication. The question is settled by each of the following three constructs. For brevity’s sake the heuristics that lead me to find them the proofs that they satisfy the requirements have been omitted and —to quote Douglas T.Ross’s comment on an earlier draft— “the appreciation is left as an exercise for the reader”.

In all three solutions I consider N+1 machines, numbered from 0 through N. In order to avoid avoidable subscripts I shall use for machine nr.i:

L: | to refer to the state of its lefthand neighbour, machine nr.(i-1)mod(N+1),
S: | to refer to the state of itself, machine nr.i,
R: | to refer to the state of its righthand neighbour, machine nr.(i+1)mod(N+1).

In other words, we confine ourselves to machines placed in a ring; machine nr.0 will also be called “the bottom machine”, machine nr.N will also be called “the top machine”. For the legitimate states we have chosen those states in which exactly one privilege is present. In describing the designs we shall use the format: “if privilege then corresponding move fi”

Solution with K-state machines (K ≥ N).

Here each machine state is represented by an integer value S, satisfying 0 < S < K. For each machine, one privilege is defined, viz.
for the bottom machine: if L = S then S:= (S + 1)mod K fi
for the other machines: if L ≠ S then S:= L fi .

Solution with four-state machines.

Here each machine state is represented by two booleans xS and upS. For the bottom machine upS = true by definition, for the top machine upS = false by definition: these two machines are therefore only two-state machines. The privileges are defined as follows:
for the bottom machine: if xS = xR and non upR then xS:= non xS fi
for the top machine: if xS ≠ xL then xS:= non XS fi
for the other machines: if xS ≠ xL then xS:= non xS; upS:= true fi; if xS = xR and upS and non upR then upS:= false fi .

The four-state machines may enjoy two privileges. The neighbour relation between bottom and top machine is not exploited; we may merge them into a single machine which is then also a four-state machine for which also two privileges have been defined.

Solution with three-state machines. Here each machine state is represented by an integer value S, satisfying 0 ≤ S <3. The privileges are defined as follows:

for the bottom machine: | if (S + 1)mod 3 = R then S:= (S - 1)mod 3 fi |
for the top machine: | if L = R and (L + 1)mod 3 ≠ S then S:= (L + 1)mod 3 fi |
for the other machines: | if (S + 1)mod 3 = L then S:= L fi; |
| if (S+1)mod 3 = R then S:= R fi | .

Again the machines nr.i with 0 < i < N may enjoy two privileges, the neighbour relation between bottom and top machine has been exploited.

Acknowledgements are due to C.S.Scholten who unmasked an earlier effort as fallacious and since then has found a nice proof for solutions of the first type and to M.Woodger whose fascination by the first two solutions was an incentive to find the third.

NUENEN, 5th November 1973 | prof.dr.Edsger W.Dijkstra |
| Research Fellow |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD398

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Sequencing primitives revisited.

Let “db” equal the number of boys in the common dressing room of a swimming pool; the initial value of db obviously equals zero. Using the operators “inc” and “dec” respectively for increase and decrease by one of their integer argument(s), we can describe the life of a little boy —omitting all further irrelevant details— as the cyclic process

| do inc(db); dec(db) od

where the repeatable statement describes a single usage of the dressing room. And if we have a community of a hundred of such little boys, we have a hundred of such sequential processes.

There is, however, another way of looking at the usage of the dressing room. From the point of view of the dressing room —which can be assumed not to be awfully interested in the identity of the boys using it, there are just two sequential processes

| do inc(db) od and do dec(db) od ,

describing what happens at its entry and at its exit respectively. These two processes, however, have to be synchronized so as to maintain the invariance of

| db ≥ 0

(From the point of view of the dressing room we can even regard the physical boys as a means for implementing this synchronization restriction: they are very similar to the coins in one’s purse!)

As a second example, consider the well-known version of Euclid’s algorithm for the computation of the greatest common divisor GCD(A, B) of two positive numbers, using addition and subtraction only:

| a := A; b := B;
| while a ≠ b do if a > b then a := a - b
|  | else b := b - a fi od
| print(a)

The first line establishes the relation “GCD(A, B) = GCD(a, b)” and both operations “a:= a - b” and “b:= b - a” leave that relation —For such are the properties of the GCD-function— invariant. Furthermore, the first line establishes

| a > 0 and b > 0

and also this relation is kept invariant; the loop terminates when a = b and then, because GCD(a, a) = a , we know the answer.

Also this program, however, admits another interpretation, viz. the two cyclic processes

| do a:= a - b od and do b:=b-a od

have to be synchronized in such a fashion that the relation

P: | a > 0 and b > 0

is kept invariant.

Let us compute the synchronizing conditions that follow from this requirement. Using the notation

| wp(S, P)

for “the weakest precondition such that its truth prior to the execution of S will guarantee that the execution of S will establish the truth of the postcondition P”,then from the axiom of assignment follows

| wp(“a:=a - b”, a>0 and b>0) = (a - b>0 and b>0)
| wp(“b:=b - a”, a>O and b>0) (a>O and b - a>0).

For each of the two statements we have here the necessary and sufficient precondition to establish the truth of the postcondition F. We are, however, only interested in maintaining P, that is, for each of the statements S, we are interested in the additional condition C, such that

| (P and C) ⇒ wp(S, P) .

The computation of C is simple. but I shall explain it slowly, as I can only have heart-felt sympathy with any reader who, through unfamiliarity, gets confused. (Students and staff from Aarhus, Denmark, may remember how, early 1973, I got completely entangled during one of my lectures, when lack of preparation could not be compensated by experience!) One uses the following theorems of propositional calculus

1) | From P ⇒ C2 follows (P and (C1 and C2)) = (P and C1)
2) | From P ⇒ non C2 follows (P and (C1 or C2)) = (P and C1) .

As first form of C, satisfying

| (P and c) ⇒ wp(S, P)

one chooses C equal to wp(S, P) itself and if C is a conjunction, theorem 1 allows us to drop any term that is implied by P and if C is a disjunction, theorem 2 allows us to drop any term whose negation is implied by P. In this example we only need theorem 1 and we arrive at

| (P and a > b) ⇒ wp(“a:= a - b”, P) and
| (P and b > a) ⇒ wp(“b:= b - a”, P) .

And it is now very tempting —so tempting in fact, that I shall do it— to write our program for the greatest common divisor as follows:

| a:= A; b:= B;
| do a > b: a:= a - b,
|  | b > a: b:= b - a od;
| print(a)

We call a construct like “a > b: a2:= a - b” a “guarded command” and for the time being we suggest the following syntax

< guarding head > ::= < boolean expression > : < statement >

< guarded command > ::= < guarding head > { ; < statement > }

where the braces {...} should be read as “followed zero or more times by the enclosed” —in our example above, this is zero times—

< guarded command list > ::= < guarded command > { , < guarded command > }

The guarded command list is a semantically unordered list of guarded commands, separated by commas. (We have sticked to the usual convention to use the comma as separator in a list in which the relative order of the elements separated is semantically irrelevant, the above program could equally well have been written with

| do b > a: b:=b - a,
|  | a.> b: a:= a - b od .)

A guarded command is “executable” when its associated guard —here the boolean expression with which the guarding head starts— considered as a function of the initial state is true.

Basically we propose two constructs with guarded command lists. The first is a possible form of a statement:

< statement > ::= if < guarded command list > fi

If one or more of the guarded commands is executable, the execution of the whole construct consists of the execution of one of the executable guarded commands. If none of the guarded commands in the enclosed list is executable, the program is wrong —and in attempted execution we assume program abortion. Note that there is no point in introducing the default convention that, if none of the n alternatives mentioned in the list is executable, the whole construct reduces to the empty statement. If we wish to provide that alternative, we should add it as the n+1st alternative and write instead of

| if B1: S1, ... Bn: Sn fi

rather

| if B1: S1, ... , Bn: Sn, non(B1 or ... or Bn): Slast fi

where Slast can be the empty statement. For the above we propose —but this can be regarded as syntactic sugar— the abreviation

| if B1: S1, ... , Bn: Sn else Slast fi ,

i.e. we also allow the format

< statement > ::= if < guarded command list > else < guarded command list > fi

If one or more guarded commands from the list are executable, one of them will will be executed, otherwise the statement following “else” .

What used to be written as if B then S1 else S2 fi can now be written

| if B: S1, non B: S2 fi

or, with our last notational extension as

| if B: S1 else S2 fi .

(In doing so, we can imagine ourselves to serve a dual purpose. On the one hand the use of else can be regarded as a hint to the implementation: after the evaluation of B the value of non B is known as well. On the other hand it is an explicit expression (for us!) of the fact that at least one of the alternatives is executable, stronger, that if none of the preceeding ones is executable, the last one is and that, if the last one is executable, it is the only one. In the following it will become apparent that the use of else is often to be avoided.)

Note that what we used to write as

| if B then S fi

should be written now as

| if B: S else fi

and not as

| if B: S fi

because in the old notation the latter would correspond to

| if B then S else ABORT fi .

Secondly we note that in the case that more than one of the guarded commands in the list is executable, we have left undefined which of the ones will be chosen for execution. This is done intentionally; in this respect we are proposing what could be regarded as a non-deterministic machine. On the one hand we have the duty to see to it that this non-determinacy is only introduced “when it does not matter”, on the other hand —and that is at this stage more important— whenever “it does not matter” our notation does not force an arbitrary or premature decision upon us.

The second construct with guarded command lists that we propose is

< statement > ::= do < guarded command list > od

Here we do allow that the alternatives are exhausted. i.e. it is not a fatal error if none of the guarded commands is executable: in the case of exhaustion, the execution of the whole do ... od construct is regarded as completed. The complementary rule, however, is that this is the only way in which the do ... od construct can terminate and that, as long as at least one of the guarded commands is executable, one of the executable ones will be selected for execution. In the case of more than one executable command, it is again undefined which one will be selected, we postulate, however, that then they will be selected in “fair random order”, i.e. we disallow the non-determinacy permanent neglect of a permanently executable guarded command from the list. We have to postulate this, because in the construct

| do B1: S1, B2: S2 od

we would not like to exclude —nor to advocate for that matter!— that both B1 and B2 might be true, while S1 has reduced itself to the empty statement and the “possible” execution of S2 will eventually cause both guards to become false. In that case we cannot allow the non-determinacy to be so bad as to choose the executable first alternative S1 all the time.

Again, if more than one of the guarded commands is executable we have what we can regard as a non-deterministic machine. We have to see to it that whenever we introduce this non-determinacy, “it does not matter”, on the other hand “whenever it does not matter” our notation relieves us from the duty to make an arbitrary choice.

But even in the case of mutually exclusive B’s —i.e. no non-determinacy— the text

| do B1:S1, B2:S2 od

seems to have advantages. In the older notation we would be forced to choose between one of the following versions

1) while(B1 or B2)do
| if B1 then S1 else S2 fi
|  | od

more or less obscuring the fact that S2 will only be executed provided B2 holds initially

2) while(B1 or B2)do
| while B1 do D1 od;
| while B2 do S2 od
|  | od

which is not too bad, but not too nice either —with the possible execption of the first outer repetition. for instance. the first inner loop will always be executed at least once.

3) repeat ready:= true;
|  | while B1 do S1; ready:= false od;
|  | while B2 do S2; ready:= false od
| until ready

Clearly our alternatives are getting nastier and nastier. Besides that, without any further information there is no reason to assume that our new version with the guarded commands would lead to a greater number of evaluations of the boolean expression B1 and B2.

*              *
*

As we have pointed out, in the case of a non-deterministic choice between two or more guarded commands, we must ensure that “the choice does not matter” and before proceeding with more examples, we had better be sufficiently clear about

1) | what we mean by “does not matter” and
2) | how we ensure that fact.

There is a snag about non-determinacy. We recall that we denote by

| wp(S, R)

the weakest precondition such that its truth prior to the execution of S will guarantee that the execution of S will establish the truth of the postcondition P; in particular it guarantees that the execution of S will terminate successfully, which in general could be prevented by either endless looping —e.g. do true: S od— or by abortion —e.g. if false: S fi—. Proper termination is guaranteed if the initial state satisfies wp(S, T), where “T” is used to denote the condition that is satisfied by all states. The most important properties are
1)     For any S. wp(S, F) = F , where “F” is used to denote the condition that no state satisfies. (This is called the “Law of the Excluded Miracle”.)
2)     For any S and any Q and R such that 0 ⇒ R , we have wp(S, Q) ⇒ wp(S, R) . (As a result wp(S, Q) ⇒ wp(S, T) for any Q.)
3)     For any S, Q and R we have (wp(S, Q) and wp(S, R)) = wp(S, Q and R)
4)     For any S, Q and R we have if S is deterministic: (wp(S, Q) or wp(S, R)) = wp(S, Q or R) otherwise only: (wp(S, Q) or wp(S, R)) ⇒ wp(S, Q or R) .

In the fourth relation. the non-determinacy replaces the equality by an implication. If initially wp(S, R) is not true, the truth of R after execution of S is not excluded.

Note. For a given S, wp(S, R) is uniquely defined for any postcondition R, even if S is non-deterministic!

Finally I introduce —inspired by, but possibly deviating from, C.A.R. Hoare— one further notation, viz.

| {P} S {R}

to be read as “P is with respect to S a safe precondition for the postcondition R” and asserting that the truth of P prior to the execution of S is sufficient to guarantee that S cannot terminate without establishing the truth of R. Note that in this assertion we do not guarantee that S will terminate properly, we don’t assert that S will produce the desired result, we only assert that S won’t produce the wrong result. We can relate this assertion to our previous formalism:

| {P} S {R}
| (wp(S, T) and P) ⇒ wp(S, R) .

There are two typical applications of the concept of “a safe precondition”. Firstly, if we can establish a safe precondition and can establish separately that the execution of S will terminate properly, then we have derived a sufficient precondition —not necessarily the weakest one, but often we don’t need that, so why bother? The advantage is that the reasoning establishing the safeness of the precondition now need not be encumbered by arguments establishing proper termination (the latter arguments often being of quite a different nature). Secondly, we may be quite content with the assertion itself as we are often content with programs that either do the job or “give up” —e.g. a compiler refusing a source program, the compilation of which violates some capacity limits—, provided that we can be certain that “giving up” will be exceptional and not disastrous.

For our constructs with guarded commands we can now formulate the following properties.

Let S be “if B1:S1, ... , Bn:Sn fi” and let for 1 ≤ S ≤ n hold: {P and Bi} Si {R}, then we can assert about S: {P} S QR} . Note that S may fail to terminate properly because none of the guards is true, or because the guarded command selected fails to terminate properly.

Let S be “do B1:S1. ... , Bn:Sn od” and let for 1 ≤ S ≤ n hold: {P and Bi} Si {P}; then we can assert: {P} S {P and non(B1 or ... or Bn)}. Note that also this S may fail to terminate properly, but here either because the state with no guard true fails to occur, or because a guarded command selected fails to terminate properly.

Let S be “if B1:S1, ... , Bn,Sn fi” and let for 1 ≤ S ≤ n hold (P and Bi) ⇒ wp(Si, R). then (P and (B1 or ... or Bn))⇒wp(S, R) . Here we assert termination.

To give an example. Let S be

| do y ≠ 1: x:= x + 1,
|  | y ≠ 1: x:= x - 1,
|  | y ≠ 1: y:=1 od

Above we have made explicitly the rule, that a loop of this type terminates. What, however, in the mean time has been done with x is in general undefined. I venture the following assertions about S:

wp(S, x = x0) = (y = 1 and x = x0)

wp(S. y ≠ 1) = F

wp(S, y = 1) = T

and this is all there is to be said about S, we have captured its semantics completely.

Before turning to next examples, I once more return to Euclid’s algorithm

| if A > 0 and B > 0:
|  | a:= A; b:= B;
|  | do a > b: a:= a - b,
|  |  | b > a: b:= b - a
| od
| print(a) fi

(By supplying “A > 0 and B > 0” as a guard for our previous algorithm we have made the condition imposed on the arguments explicit: if they don’t satisfy it, the program as a whole will be aborted.) When we did derive the program we have already used the invariance of

P: | GCD(A, B) = GCD(a, b)and a >0 and b >0 .

The loop theorem just mentioned tells us that upon termination we know also

| non (a > b or b > a)

from which we conclude a = b, with the consequence that “print(a)” indeed produces the desired answer.

Does the loop terminate? Yes, for each execution of a guarded command from the list decreases a + b by at least 1 and therefore, in view of the invariance of P, this can happen only a finite number of times. We see here that “termination” —i.e. all the guards false— is here our goal; when synchronizing cyclic processes such as in an operating system, the situation “all the guards false” is called “a deadly embrace” and there one aims at avoiding this situation, because the show must go on! I hope to have shown the close connection between termination of sequential processes and deadlock in parallel programming.

Let us now try another problem. For N ≥ 0, we are requested to assign to an integer variable “a” such a value that the relation

R: | a² ≤ N and (a+1)²>N

is established. with “a² ≤ N” as our P to be kept invariant during the loop, the program a:= 0; do (a+1)² ≤ N: a:= a + 1 od follows directly. We arrive at a more interesting program when we introduce a local variable (as a means for weakening R) and choose as our relation

P: | a² ≤ N and b²>N

Clearly, (P and a+1 = b) ⇒ R, and therefore our first sketch of the program can be (the first line is only one of the many ways in which P can be established easily)

| a:= 0; b:= N + 1;
| do a+1 ≠ b: “bring a and b closer together
|  | under invariance of P” od .

Let “d” be the amount, by which the difference b - a is going to be decreased. Without loss of generality, we can assume that in the operation “bring a and b closer together under invariance of P” only one of the two variables will be changed each time, because the other one can be adjusted in the (or a) next execution of the repeatable statement.

Under these life-simplifying restrictions the repeatable statement will be somthing of the structure

| d:= ......;
| if ......: a:= a + d,
|  | ......: b:= b - d fi

Let us first find out the guards. The repeatable statement as a whole has to maintain the invariance of P. Let us derive in the usual manner the corresponding weakest preconditions:
wp(“a:= a + d”, P) = ((a + d)² ≤ N and b²>N)
wp(“a:= b - d”, P) = (a² ≤ N and (b - d)²>N)

Now our theorems about the if...fi construct tell us, that we can drop the terms implied by P and our repeatable statement becomes

| d:= .......;
| if (a + d)² ≤ N: a:= a + d,
|  | (b - d)² > N: b:=b - d fi

This, however, would lead to abortion, if both guards were false. That must be excluded, so the negation of the one has to imply the truth of the other: e.g. (a + d)² > N (the negation of the first guard) must imply (b - d)² > N. This implication is ensured if (a + d) ≤ (b - d) , i.e. 2d < b-a . In order to assure termination, d should be positive, but any value of d satisfying 0 <d < (b - a) div 2 will do. The larger the value of d, the faster our program, and my final suggestion for this program is therefore

| a:= 0; b:= N + 1;
| do a+1 ≠ b: d:=(b-a) div 2;
|  | if (a + d)² ≤ N: a:= a + d,
|  |  | (b-d)²>N: b:=b-d fi
| od

(Remark. If 2d < b - a , then both guards may be true and it does not matter which of the two guarded commands is executed. In this example they could even be executed both, but that is not typical.) I think this example a beauty. The assignment to “d” is to ensure that the partial operator if ... fi is not invoked outside its domain, but, working backwards, we can derive what obligation this implies. (In Canterbury, last September, I have shown in essence the derivation of the same algorithm, but that was a clumsy affair, compared with the above!)

(26th November 1973). Since I wrote the previous pages of this report last week, I saw that Don Knuth pointed out in a letter to Tony Hoare, that this use of the comma violates all rules of interpunction: one should not use the comma as major separator between pieces of text that internally may contain the semicolon as minor separator. I agree and in the following text —this whole report is an experiment in notation!— I shall use —inspired by the vertical bar “|” of Peter Naur’s representation of BNF— a fat vertical bar “▯” instead, i.e.

< guarded command list > ::= < guarded command > { ▯ < guarded command > }

The next example I am going to code is known as “The Problem of the Dutch National Flag”. In frontof a row of buckets, numbered from 1 through N, there is a minicomputer. Each bucket contains one pebble and each pebble is either red, or white of blue. The minicomputer can permute the pebbles because it has two controllable mechanical hands. controlled by the instruction “swap(i, j)” (1 ≤ i, j ≤ N): if i = j, this is the empty command, if i ≠ j, the pebbles in buckets nr.i and nr.j respectively are interchanged. Also the machine has a movable eye used to compute the function “look(i)” (1 ≤ i ≤ N) of type colour: its value is the colour of the pebble in bucket nr.i (currently in bucket nr.i. I mean). The minicomputer must be programmed in such a way that it will rearrange the pebbles in the order of the Dutch National Flag, i.e. red, white, blue. There are, however, three constraints.
1) We know nothing about the numbers of red, white or blue pebbles, the program must even work in the case of missing colours
2) It is a minicomputer with such a small store that the program may not make use of internal arrays
3) It is assumed that the evaluation of the function “look” is so timeconsuming that we require that each pebble is “looked at” at most once.

The argument is the following. On account of the last requirement we have somewhere half way the computational process four kinds of pebbles: established red, established white, established blue and uninspected. We have to keep track of which is what, we cannot use an internal array for that purpose, we therefore use also the row of buckets and there contents as a memory element. We can represent then the information with three internal pointers, r, w and b according to the following convention:

for 1 ≤ k < r: | the pebble in bucket nr.k is established red,
for r ≤ k ≤ w: | the pebble in bucket nr.k is uninspected
for w < k ≤ b: | the pebble in bucket nr.k is established white
for b < k ≤ N: | the pebble in bucket nr.k is established blue.

Once we have chosen this general intermediate state, our problem is nearly solved, because both initial state (all pebbles uninspected) and final state (no pebbles uninspected and the remaining ones sorted out) are particular cases of the above described general state. So that one is established and under its invariance the number of uninspected pebbles is decreased one at a time. Inspection of the pebble in bucket nr. w gives on the average less swaps to perform than inspection of the pebble in bucket nr.r and we arrive ultimately at the following program

begin int var r, w, b; colour var v;
| r:=1; w:= N; b:= N;
| do r ≤ w: v:= look(w);
|  | if v = red: swap(r, w); inc(r) ▯
|  |  | v = white: dec(w) ▯
|  |  | v = blue: swap(b, w); dec(b, w)
|  | fi
| od
end

and I prefer the last part over what I used to write down

| if v = red then swap(r, w); inc(r)
|  | else if v = blue then swap(b, w); dec(b) fi;
|  |  | dec(w)
| fi

I know that I am now talking about minute details —some of my readers might already wonder why I bother!— but let us analyse the difference as completely as possible, so that we might learn from it. We have seen that decrementing “w” is part of the reaction in cases white and blue, so we decide to group them together in our first binary cut,where we ask for “v = red”. (I have shown this example in its old version for many audiences and I remember my “justification” more or less going as follows “What the repeatable statement has to do is to decrease the difference w - r, either by increasing r or by decreasing w , etc”. What a waste of words!) In passing we note, that this way of partitioning becomes definitely unattractive, if for some reasons, we may expect a minority of red pebbles, and that is suddenly a quite different sort of consideration! If the pebble is not red, we discover that waht has to be done in the case of a white pebble is really a subset of what has to be done with the blue pebble and as no programmer would think of writing

if v = white then else swap(B, w); dec(b) fi; dec(w)

(you may omit the else but not the then!) we “discover” that we must ask explicitly for a blue pebble. If there happens, quite erroneously, to be a grey pebble as well, it is unconsciously treated as a white one. Then we learn by sad experience, that this is not too good from the point of robustness, so we introduce, as element of the well-trained programmer’s competence, the notion of “defensive programming”.... It just means, that educating him with the existence of “else” as the default case, he is always invited to choose, in a curious mixture of static and dynamic efficiency considerations, which of the cases he is going to treat as the default.... If we assume the availability of a mill with some capacity for concurrency and if the tests can be done concurrently, the whole argument disappears completely. As long as that is not the case, let us at least create a mental platform where we can ignore such details!

If a number of guarded commands from a list have a common tail, we might wish to save writing; we can do so by introducing an abbreviation, which syntactically can be presented as an alternative for the guarding head
< guarding head > ::= [ < guarded command list > ]: < statement >
allowing us to write

| if v = red: swap(r, w); inc(r) ▯
|  | [v = white: ▯
|  | v = blue: swap(b, w); dec(b)]: dec(w)
| fi

but this is now presented not so much as something that has to do with “sequencing control” -decisions and the like- it is just a short-hand notation, an abreviation. (As the different elements of the guarded command list are semantically unordered, we are absolutely free to order them in the case of common tails as we see fit: it is a merging tree.)

*              *
*

The original reason to undertake these experiments was the following observation. Many a program shows the following phenomenon

| while non null(x1) do
|  | begin temp:= tail(x1);.....

(this is taken from an example from R.M.Burstall), where the function “the tail of a list”,i.e. what remains after removal of its first element, is undefined if its argument happens to be an empty list. It is a clear example of a partial function. In a program using such partial functions or operators, it turns out that much of the sequencing control in the upper level, using such functions or operators, is no more than ensuring that the partial operators or functions will not be invoked outside there domain. Now this is kind of silly: it implies that the upper level program has the duty to reflect in its explicitly stated sequencing commands what measures are to be taken in order to prevent invocation outside the domain, while anybody with any experience at all will know that for robustness sake the implementation of a thing like “tail” will start.... by checking that the upper level program satisfies that rule, that the upper level programmer has indeed met his obligations! Since I saw this, it has been hurting me, not so much for reasons of computational (in)efficiency, but perhaps still more for logical reasons: to present from below a partial function or operator does not seem to be a nice interface. I have been looking for a long time, what we should have instead, and the idea of the guarded command seems to come closer to it than anything I have seen before. More precisely, from below we offer so-called “guarded primitives” and syntactically they can be used as guarding heads, i.e. we have the alternative form (I give the old one from page 2 as well)

< guarding head > ::= < boolean expression > : < statement > | < guarded primitive > .

Let me show, how these can be used; I use an example that I owe to W.H.J.Feijen. Let V be a set and let e be a variable of the type of the elements of V. We consider two guarded primitives

sel(V, e): | the guard of this primitive is the initial value of non empty(V); the corresponding action is to select any element from V, to remove it from V and to assign it to the variable a.
sub(V, e): | the guard of this primitive is the initial value of “e in V”; the corresponding action is to remove this element from V.

It is now requested to make a program establishing whether the set B0 is contained in the set A0. We introduce two variable sets, A and B and maintain the invariance of the following relation

| (A0 contains B0) = (A contains B)

(i.e. both sides are either true or false). Now we start massaging the sets A and B, but under invariance of the above relation. when A is empty, the question (A contains B) is easily answered: it is true if and only if B is empty as well. So after initialization we try to“empty” A, which we can do with the guarded primitive “sel”. In order to maintain the invariance any element removed from A has to be removed from B as well, if B contains it. And we are led to the following program

| A:= A0; B:= B0;
| do se1(A, e);do sub(B, e) od od
| answer:= empty(B)

(Remark: We have not exploited the fact that A and B are sets which, by definition, do not contain different elements. The “do sub(B, e) od” would old-fashionedly have been coded as if e in B then sub(B, e) fi: this construct now appears as a special case of a loop, viz. where the repeatable statement never needs to be executed more than once. In our version the program will also work for “collections of values”: it will establish whether any value occurring at least once in B, also occurs at least once in A.)

We are not finished with this example yet: the only possible change of B is that it loses an element: we are not interested in the final value of B. we only want to know of the final value of B is empty or not: as a result, if B becomes empty halfway, then we can stop the repetition, we can “extrapolate” the final value of B. And this suggests the following program

| A:= A0; B:= B0;
| do non empty(B) and sel(A, e); do sub(B, e) od od;
| answer:= empty(B)

where we have used yet another form of guarding head, viz.

< guarding head > ::= < boolean expression > and < guarded primitive > ,

This might seem to be at first sight a little piece of ad-hoccery, it is not. In order that something be evoked, in general we have two conditions: it most be possible to do it —and the guarded primitive presents that as a condition from below— but you must also be interested in doing it, and that is clearly somthing that must be specified by the upper level programmer! Once you have seen this separation of reasons why to do something, classical programs, in which these different conditions are often lumped together in a single boolean expression, can strike you as unnecessarily obscure.

I shall give a final program, doing a merge sort, merging three sets A, B, and C into a fourth one; initially D is empty, finally A, B and C are empty} I assume a guarded command “selmin”, that I have written in the form of a parallel assignment when used. Its guard is non-emptiness of the sets mentioned at the right hand side; its action is to select from each of the sets the minimum value and to assign this vector of values to the vector of variables at the left hand side. The sets are not changed. The operator “move(e, V, W)” transfers -if possible an element with value e from V to W; if there is no such element, it is the empty statement.

| do (a, b, c):= selmin(A, B, C); d:= min(a, b, c);
|  | if a = d: move(a, A, D) ▯
|  |  | b = d: move(b, B, D) ▯
|  |  | c = d: move(c, C, D) fi
| od {comment: now at least one of the three input streams is empty};
| if empty(A): do (b, c):= selmin(B, C); d:= min(b, C);
|  |  |  |  | if b = d: move(b, B, D) ▯ c: = d: move(c, c, D) fi
|  |  |  | od ▯
|  | empty(B): do (a, c):= selmin(A, C); d:= min(a, c);
|  |  |  |  | if a = d: move(a, A, D) ▯ c = d: move(c, C, D) fi
|  |  |  | od ▯
|  | empty(C): do (a, b):= selmin(A, B); d:= min(a, b);
|  |  |  |  | if a = d: move(a, A, D) ▯ b = d: move(b, B, D) fi
|  |  |  | od
| fi {now at least two of the three input streams are empty};
| if empty(A) and empty(B): do (c):= selmin(C); move(c, C, D) od ▯
|  | empty(B) and empty(C): do (a):= selmin(A); move(a, A, D) od ▯
|  | empty(C) and empty(A): do (b):= selmin(B): move(b, B, D) od
| fi {now all the three input streams are empty}

It is in this example quite clearly that the guarded primitive controls repetition, while —some sort of— negation of the guard is used for selection: they express our interest.

Concluding remarks.

I regard what I have sketched as an aspect of a programming language, but it could be “an abstract programming language”. i.e. a programming language for which we don’t have a processor that, without further human intervention, will process our programs with acceptable efficiency. I do not care about that too much, it is a very one-sided view to regard programs as “things to execute automatically”: they are also things to design, to enjoy, to embellish, to talk about and to use as a means of communication, either with yourself or with someone else. About algorithms. It is primarily with the latter aspects in mind; that the above has been written. Very tentatively written, even.

26th November 1973

BURROUGHS |  | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 |  | Research Fellow
NUENEN 4565
The Netherlands

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD399

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

An immediate sequel to EWD398: “Sequencing primitives revisited.”.

I have fixed the semantic definition of the if...fi and of the do...od constructs as introduced in EWD398.

Let “Sif” be: if B1:S1 ▯ ... ▯ Bn:Sn fi ; then wp(Sif, P) = {(E i: 1≤i≤n: Bi) and (1≤i≤n:(Bi and wp(Si, P)) or non Bi)} .

Let “Sdo” be: do B1:S1 ▯ ... ▯ Bn:Sn od ; then wp(Sdo, P) = (E i: 0 ≤i: Hi(Sdo, P)) , where the Hi(Sdo, P) are given by the recurrence relation:

| H₀(Sdo, P) = {P and non (E j: 1≤j≤n: Bi)}
for i >0: | Hi(Sdo, P) = {wp(Sif, Hi-1(Sdo, P)) or Hi-1(Sdo, P)}

Here the “wp(Sif, ...) is the function defined above. The interpretation of Hi(Sdo, P) is ”the weakest precondition such that we can guarantee termination after at most i executions of a guarded command such that then the postcondition P will be satisfied. It is indeed the weakest precondition, if initially wp(Sdo, P) is not satisfied, either non-termination or termination without establishing the truth of P or both are possible. In terms of the Hi an alternative definition of the weakest precondition for the do...od construct could have been —but I prefer to avoid the limit concept—

| wp(Sdo, P) = | lim Hi(Sdo, P)
|  | i → inf

so we had better forget this again.

The decision to postulate —EWD398 - 4, last paragraph— “Fair random selection” so that the construct as described on top of page 5 and in the middle of page 8 is guaranteed to terminate, was a mistake: for such constructs we prefer now not to exclude non-termination. It is just too tricky if the termination —and in particular: the proof of the termination— has to rely on the fair randomness of the selection and we had better restrict ourselves to constructs were each guarded command, when executed, implies a further approaching of the terminal state.

27th November 1973 |  | prof.dr.Edsger W.Dijkstra
Burroughs |  | Research Fellow
Plataanstraat 5
NUENEN - 4565, The Netherlands

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-08 .

04xx

401: The characterization of semantics

404: A trip to France: 13th–20th December 1973

406: A trip to the U.S.A., 5th–25th January 1974

407: Acceptance speech for the AFIPS Harry Goode Memorial Award 1974

408: A time-wise hierarchy imposed upon the use of a two-level store

413: The formal treatment of some small examples.

415: A beautiful proof of a probably useless theorem (with W.H.J.Feijen)

416: On avoiding the infinite

417: On the abolishment of the subscripted variable

418: Guarded commands, non-determinacy and a calculus for the derivation of programs

420: Tripreport E.W.Dijkstra, Luxembourg, 7–12 April 1974

423: Trip report E.W.Dijkstra, W.G.2.3 Meeting “Boldern” 28th April–3rd May 1974

425: Trip report E.W.Dijkstra, USA and Canada, 5th–25th May 1974

426: Self-stabilizing systems in spite of distributed control

427: Speech at the occasion of an anniversary

428: Array variables.

429: A generalization of the Sheffer Stroke for n-valued logic (by C.S.Scholten)

432: [A letter to C.A.R. Hoare, 13 July 1974]

435: Associons: an effort towards accomodating potentially ultra-high concurrency (with W.H.J.Feijen and M.Rem)

439: Associons continued (with W.H.J.Feijen and M.Rem)

440: The problem of the most isolated villages.

442: Inside “Mathematics Inc”

443: A multidisciplinary approach to mathematics

447: On the role of scientific thought

448: Trip report E.W.Dijkstra, Edinburgh and Newcastle, 1–6 September 1974

449: Het curriculum informatica aan de THE

450: Correctness concerns and, among other things, why they are resented

451: Heer, verlos ons van de charlatans!

452: About robustness and the like

453: Finding the maximal strong components in a directed graph.

454: [Letter to Dr. H.Bekic, 8 October 1974]

456: Determinism and recursion versus non-determinism and the transitive closure

458: On non-determinacy being bounded.

459: The pattern matching problem.

462: A time-wise hierarchy imposed upon the use of a two-level store

463: Some questions

464: A new elephant built from mosquitos humming in harmony

465: Monotonic replacement algorithms and their implementation

466: Trip report E.W.Dijkstra, Meeting IFIP W.G.2.3., Munich, 8–14 December 1974

469: Programming methodologies, their objectives and their nature

470: Letter to the referees of EWD418

471: Bij de aanvang van het semester

472: Guarded commands, non-determinacy and formal derivation of programs

473: On the teaching of programming, i.e. on the teaching of thinking

474: Trip report visit ETH Zurich, 3–4 February 1975 by E.W.Dijkstra

475: A letter to my old friend Jonathan

476: Concurrent programming: a preliminary investigation

477: Tweede toespraak tot mijn studenten

478: On one-sided smoothing of event sequences

479: Commentaar op “Structuurplan Informatica (W.O.)” van de ARSI

480: “Craftsman or scientist?”

481: Derde toespraak tot mijn studenten

482: Exercises in making programs robust

483: Vierde toespraak tot mijn studenten

484: Tripreport E.W.Dijkstra, London, 9–10 March 1975

485: Marketing questionnaire “A Discipline of Programming”

486: Vijfde toespraak tot mijn studenten

487: Letter to the Burroughs recipients of the EWD-series

489: Zesde toespraak tot mijn studenten

492: On-the-fly garbage collection: an exercise in multiprocessing

493: [Toespraak tot een afstudeerder]

494: Trip report E.W.Dijkstra 16th April/7th May, U.S.A. and Canada

494a: Zevende toespraak tot mijn studenten

495: Achtste toespraak tot mijn studenten

496A: On-the-fly garbage collection: an exercise in cooperation (preliminary version) (with Leslie Lamport, A.J.Martin, C.S.Scholten, and E.F.M.Steffens)

496B: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, and E.F.M.Steffens)

497: A challenge to memory designers?

498: How do we tell truths that might hurt?

499: [toespraak tot een student bij uitreiking ir-diploma]

EWD401

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 401: The characterization of semantics

is held in copyright by Prentice-Hall International, who have granted
permission to reproduce it here.

The manuscript was published as Chapter 3 of

A Discipline of Programming. Prentice-Hall, 1976.

The characterization of semantics.

We are primarily interested in systems that, when started in an “initial state”, will end up in a “final state” which, as a rule, depends on the choice of the initial state. This is a view that is somewhat different from the idea of the finite state automaton that on the one hand absorbs a stream of input characters and on the other hand produces a stream of output characters: to translate that in our picture we must assume that the value of the input (i.e. the argument) is reflected in the choice of the initial state and that the value of the output (i.e. the answer) is reflected in the final state. Our view relieves us from all sorts of peripheral complications.

Now I assume that the design of such a system is a goal-directed activity, in other words that we want to achieve something with the system. For instance, if we want to make a machine capable of computing the greatest common divisor, we could demand of the final state that it satisfies

| x = GCD(X, Y) | (1)

In the machine we have been envisaging, we shall then also have y = GCD(X, Y) —because the game terminates when x = y ), but that is not part of our requirement when we decide to accept the final value of x as our “answer”.

We call condition (1) the (desired) “post-condition” —“post” because it imposes a condition upon the state in which the system must find itself after its activity. Note, that the post-condition could be satisfied by many of the possible states. In that case we apparently regard each of them as equally satisfactory and there is then no reason to require that the final state is a unique function of the initial state.

In order to use such a system when we want it to produce an answer —say “reach a state satisfying condition (l) for a given set of values of X and Y— we must know the set of corresponding initial states, more precisely: the set of initial states that is guaranteed to result in a final state satisfying (l). If we can bring the system without computational effort into one of these states, we know how to use the system to produce for us the desired answer! To give the example of Euclid’s cardboard game: we can guarantee a final state satisfying the post-condition (1) for any initial state satisfying

| GCD(x, y) = GCD(X, Y) and 0 <x ≤ 500 and 0 <y ≤ 500 | (2).

(The upper limits have been added to do justice to the limited size of the cardboard. If we start with a pair (X, Y) such that GCD(X, Y) = 713, then there exists no pair (X, Y) satisfying (2), i.e. for those values of X and Y condition (2) reduces to F and that means that the machine in question cannot be used to compute the GCD(X. Y) for that pair of values of X and Y.

For many (X, Y)-combinations, many states satisfy (2). In the case that 0 < X ≤ 500 and 0 < Y ≤ 500, the trivial choice is x = X and y = Y: it is a choice that can be made without any evaluation of the GCD-function, even without appealing to the fact that the GCD-function is a symmetric function of its arguments.

The condition that characterizes the set of all initial states that are guaranteed to lead to a final state satisfying a given post-condition is called “the weakest pre-condition corresponding to that post-condition”. (We call it “weakest”, because the weaker a condition, the more states satisfy it and we aim here at characterizing all possible starting points that are certain to lead to one of the desired states.)

If the system (machine, mechanism) is denoted by “S” and the desired post-condition by “R”, then we denote the corresponding weakest pre-condition by

| wp(S, R)

It the initial state satisfies wp(S, R), the mechanism is certain to establish eventually the truth of R. Because wp(S, R) is the weakest precondition, we also know that if the initial state does not satisfy wp(S, R), the mechanism is not certain to establish eventually the truth of R. In the case that S is a deterministic machine —i.e. the final state is uniquely determined by the initial state— it will then fail to do so, in the case that S is a non-deterministic machine, the most we can say is that then it may fail to do so.

As we proceed we shall see that there are a variety of ways in which the mechanism S may fail to reach a final state satisfying the post-condition R. One of the possibilities is that it reaches a final state for which R is false; another possibility is that it does not reach a final state at all, either because the system finds itself engaged in an endless task or because the system has got stuck.

We take the point of view that we know the possible performance of the mechanism S completely if and only if we can derive for any post-condition R the corresponding weakest pre-condition wp(S, R) because then we have captured completely what the mechanism can do for us. In the jargon: it is then that we know its “semantics”.

Two remarks are in order. Firstly, the set of possible post-conditions is in general so huge, that this knowledge in tabular form —in a table with an entry for each R we would find the corresponding wp(S, R)— would be utterly unmanageable, and therefore useless. Therefore the definition of the semantics of the mechanism is always given in another way, viz. in the form of a rule describing how for any given post-condition R the corresponding weakest pre-condition wp(S, R) can be derived. Such a rule —which is fed with the predicate R denoting the post-condition and delivers a predicate wp(S, R) denoting the corresponding weakest pre-condition— is called “a predicate transformer”. When we ask for the definition of the semantics of the mechanism S m what we really ask for is its corresponding predicate transformer.

Secondly, we are often —and I feel tempted to add “thank goodness”— not interested in the complete semantics of a mechanism. This is because it is our intention to use the mechanism S for a specific purpose only, viz. for establishing the truth of a very specific post-condition R for which it has been designed. And even for that specific post-condition R , we are often not interested in the exact form of wp(S, R): often we are content with a stronger condition P for which we can show that

| P => wp(S, R) | (3)

(read: “P implies wp(S, R)”). This means that wherever in the state space P is true, wp(S, R) is true as well: P is a sufficient pre-condition. In terms of sets it means that the set of states characterized by P is a subset of the set of states characterized by wp(S, R) . If for a given P, S and R relation (3) holds this can often be proved without explicit formulation —or if you prefer “computation” or “derivation”— of the predicate wp(S, R). And that is a good thing for except in trivial cases we must expect that the explicit formulation of wp(S, R) will defy at least the size of our sheet of paper, our patience or our (analytical) ingenuity (or any combination of them).

The meaning of wp(S, R) : “the weakest pre-condition for the initial state such that the mechanism S will establish a final state satisfying the post-condition R ” allows us to conclude that, considered as function of the post-condition R, the predicate transformer has a number of properties.

Property 0. For any mechanism S and any post-conditions R and Q, the equality “R = Q” alows us to conclude “wp(S, R) = wp(S, Q)” . In words: if R and Q are two predicates denoting the same post-condition, than the derived predicates wp(S, R) and wp(S, Q) denote the same precondition. One can argue whether it is worth-while to mention explicitly a property that is so obvious: if it did not hold, we had been talking nonsense all the time! I mention Property 0 for the sake of completeness. (I myself have worked for more than a month with predicate transformers without having formulated this property explicitly....)

Property 1. For any mechanism S we have “wp(S, F) = F” . Suppose that this was not true; under that assumption there would be at least one state satisfying wp(S, F) . Take such a state as the initial state for the mechanism S : then, according to our definitio of the weakest pre-condition “the mechanism S will establish a final state satisfying the post-condition F ”, But this is a contradiction for there are by definition no states satisfying F . Property 1 is known under the name of “The Law of the Excluded Miracle”.

Property 2. For any mechanism S and any post-conditions Q and R “Q ⇒ R” allows us to conclude “wp(S, Q) ⇒ wp(S, R)”. Indeed, because any initial state satisfying wp(S, Q) is “such that the mechanism S will establish a final state satisfying the post-condition Q”; on account of “Q ⇒ R” any such final state will satisfy R as well, i.e. any initial state satisfying wp(S, Q) is such that the mechanism will establish a final state satisfying the post-condition R and therefore any initial state satisfying wp(S, Q) will satisfy wp(S, R) as well. Property 2 is called “The property of Monotonicity”.

Property 3. For any mechanism S and any post-conditions Q and R

| (wp(S, Q) and wp(S, R)) = wp(s, Q and R) | (4).

The lefthand side of (4) implies the righthand side because for any initial state satisfying both wp(S, Q) and wp(S, R) we have the combined knowledge that a final state will be established satisfying both Q and R. Also, on account of the Property of Monotonicity we conclude from (Q and R) ⇒ Q that wp(S, Q and R) ⇒ wp(S, Q) ; Similarly we conclude that wp(S, Q and R) ⇒ wp(S, R) and from the last two implications we conclude that the righthand side of (4) implies the lefthand side. Both sides implying eachother, they must be equal and thus Property 3 has been proved.

Property 4. For any mechanism S and any post-condition Q and R

| (wp(S, Q) or wp(S, R)) ⇒ wp(S, Q or R) | (5)

Also this is a direct consequence of the Property of Monotonicity. From Q ⇒ Q or R follows wp(S, Q) ⇒ wp(S, Q or R) ; from R ⇒ Q or R follows wp(S, R) ⇒ wp(S, Q or R). And then, relation (5) follows.

We can make a stronger assertion tor the special case that the mechanism is deterministic. The deterministic machine has the special property that its behaviour —i.e. if a final state will be reached and, if so, which one— is fully determined by the initial state. While in general we can only be sure that the final state will satisfy the post-condition R provided that the initial state satisfies wp(S, R), we know for the deterministic machine S that the final state will satisfy the postcondition R if and only if the initial state satisfies wp(S, R) : this is because every initial state that could lead to a final state satisfying R must lead to that final state satisfying R . In the special case of the deterministic machine the righthand side of (5) implies therefore the lefthand side as well and we have

| (wp(S, R) or wp(S, Q)) = wp(S, R or Q) . | (6)

In this book —and that may turn out to be its distinctive feature— I shall treat non-determinacy as the rule and determinacy as the exception: a deterministic machine will be regarded as a special case of the non-deterministic one, as a mechanism for which Property 4 is given by (6) rather than by the somewhat weaker (5). This decision reflects a drastic change in my own thinking. Back in 1958 I have been one of the firsts to develop the basic software for a machine with an I/O interrupt and the irreproducibility of the behaviour of such a —to all intents and purposes: non-deterministic— machine has been a traumatic experience. When the idea of the I/O interrupt was first suggested I was so terrified at the thought of having to build reliable siftware for such an intractable beast that I have delayed the decision to incorporate the feature for at least three months. And even after I had given in —I had been flattered out of my resistance!— I was highly uncomfartable. When the prototype was becoming king of operational I had my worst fears fully confirmed: a bug in the program could evoke the erratic behaviour so strongly suggestive of an irreproducible machine error. And secondly —and that was in the time that for deterministic machines we still believed in “debugging”— it was right from the start quite obvious that program testing was quite ineffective as a means for rasing the confidence level.

For many years thereafter I have regarded the irreproducibility of the behaviour of the non-deterministic machine as an added complication that should be avoided whenever possible. Interrupts were nothing but a curse inflicted by the hardware engineers upon the poor software makers. Out of this fear of mine the discipline for “harmoniously co-operating sequential processes” has been born. In spite of its success I was still afraid for our solutions —although proved to be correct— seemed ad hoc solutions to the problem of “taming” —that is the way we felt about it!— special forms of non-determinacy. The background of my fear was the absence of a general methodology.

Two circumstances have changed the scene since then. The one is the discovery that, even in the case of fully deterministic machines, program testing is hardly helpful. As I have now said many times and written in many places: program testing can be quite effective for showing the presence of bugs, but is hopelessly inadequate for showing their absence. The other one is the discovery that in the mean time it has emerged that any design discipline must do justice to the fact that the design of a mechanism that is to have a purpose, must be a goal-directed activity. In our special case it means that we can expect our post-condition to tbe the starting point of our design considerations. In a sense we shall be “working backwards”. In doing os we shall find that the implication of relation (5) is the essential part, for the equality of relation (6) we shall have very little use.

Once the mathematical equipment needed for the design of nondeterministic mechanisms achieving a purpose has been developed, the nondeterministic machine is no longer frightening, on the contrary! We shall learn to appreciate it even as a valuable steeping stone in the design of an ultimately fully deterministic mechanism.

*              *
*

Above we have mentioned that the complete evaluation of wp(S, R) is often beyond our interest and/or power and that we are content with a sufficient pre-condition such that P ⇒ wp(S, R) , i.e. that P is a sufficient pre-condition to guarantee that the mechanism S will reach a final state satisfying R .

A closely related but subtly different concept is that of the “safe pre-condition”. We call “P with respect to the mechanism S a safe pre-condition for the post-condition R if an initial state satisfying P guarantees that the mechanism S cannot reach a final state not satisfying R ”. In formula we denote this state of affairs by

| {P} S {R}

Note that the two negations in the end of the definition of the concept of “a safe pre-condition” do not cancel: an initial state satisfies a safe pre-condition either because it will lead to a final state satisfying R or to no state at all (i.e. when the mechanism S fails to terminate properly) or both.

The concept of a safe pre-condition derives its usefulness from the following property. From

| {P} S {R}

follows

| (wp(S, T) and P) :⇒ wp(S, R) | . (7)

Here the term wp(S, T) describes the weakest pre-condition such that S will reach “a final state satisfying T ”, but as each state satisfies T by definition, this reduces to “the weakest pre-condition such that S will reach a final state” or “will terminate properly”. From this observation and the definitions, the above property follows immediately. It tells us that “(wp(S, T) and P)” is a sufficient pre-condition for the establishment of the truth of R

The above relation between safe and sufficient pre-conditions will play a central role in the practice of program composition. The point is that termination is in general a tricky problem, but in deriving a safe pre-condition for the post-condition R we can ignore the termination problem. When establishing the termination we can ignore the post-condition R ! In formula (7) the requirements

1) | that the mechanism will terminate, and
2) | that the final state will satisfy R

have been factored nicely: two different concerns have been separated.

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

  EWD 404

A trip to France: 13th – 20th December 1973.

     The train for Paris left my country at half past seven in the evening: being a nervous traveller, I found the major part of that day ruined. It was about noon, when my suitcase was packed and I had checked for the umptieth time that I had my ticket, my passport, my money and all the papers, when Ria kindly offered to bring me to the University: there at least I was close to the railway station and that would give me the feeling of having started. Her offer was gratefully accepted.

      That restless afternoon in my room at the University I could not work, so I thought, until I came to the discomforting conclusion that I had to rewrite EWD401 "The characterization of semantics" because the way in which I intended to deal with non-deterministic machines —and I do intend to deal with them— would lead to difficulties. Via two local trains I had to go to Rosendaal, where I would catch the Trans Europa Express "Ile de France" to Paris. I did not follow the suggestion of the travel agency —which would give me seven minutes in Rosendaal— but made the trip to Rosendaal half an hour earlier. This meant, of course, more waiting at Rosendaal railway station and if you don't know it, I can tell you: "It is not an exciting railway station!". But when the TEE left for Paris —with me on board!— I had the immense satisfaction of having observed that I would have missed the connection, if I had taken the next train from Eindhoven! Such experiences confirm one's pessimism, one's little faith in travel arrangements.

      The "Ile de France" is in principle an excellent train. I had a reserved seat in one of the dining cars. It so happened that in that car they only served the first meal and I came in so late that I was just unlucky .... So I had to change to another car and finally was served the second meal. The personnel on the train were very impolite and unhelpful; I think the Wagon Lits puts its worst employees on that northern bound train by way of banishment. Later I checked my experiences with Carel Scholten who has taken that train quite regularly: he confirmed them.

      I arrived in Paris "Gare du Nord" a little after eleven and dr.Robinet was there to pick me up and to take me to my hotel. I was very glad that he did so —the Metro terrifies me to such an extent that I would have been forced to take a taxi and in a large, strange town even that is not always pleasant—. In the hotel I was fortunate in that I could leave the arguing at the reception desk to him, because for the first fifteen minutes the other side argued "that they did not know me". Finally they found my name written in a book —the wrong book, apparently— and I got my room on the fourth floor which I reached via squeaking stairs. Before entering my room I looked around to imprint in my mind where to go for the emergency exit, but there was none ... Sleep well. In the room I groped for the lights and in doing so I created a great disturbance in the bath room where suddenly all sorts of bugs were rudely woken up and started to run around. Being on sandals I could kill the ones that had chosen the wall as escape route as well. I knew I was in France, in the heart of France, in the heart of Paris even!

      On Friday and Saturday morning we had meetings of the Program Committee for "1e Colloque sur la Programmation" where two out of every three offered papers had to be rejected. On the whole it was not difficult. A number of definitely wrong decisions have been taken, but somehow I did not suffer from it emotionally: to a large extent it is their symposium and their political game. For that was clear to me very quickly: French science is poisoned by politics. Many played it subtle, Nivat played[?] it crudely but with a persistence and a cruelty that I expect him to become a very powerful and dangerous man when he gets older. Computing science suffers, besides from politics, from their limited mastery of English and, also, from the mathematical establishment: Bourbaki is in power and he never understood a single word of computer science and he never will. The situation is very familiar to me from Turski's description of Poland. (I am aware of the fact that it is a historical tour de force to try to understand the French scientific scene in terms of Polish situations!) The meeting ended with a considerable complication: Arsac had funds from the government for the publication of the proceedings of the symposium on the condition that ... you guessed it right: they would be published in French! The idiots! I did not buy that. Filled more with contempt than with indignation I left Paris from the "Gare de Lyon" at 13.20 with the TEE "Le Mistral", a train that I really can recommend if you have to travel through France. I had smoked trout and pheasant. (Although for us, who have been trained to eat noiselessly, sharing a dinner table with Frenchmen smacking their lips is somewhat distracting. Perhaps I am distracted too easily....)

      At a quarter to eight I was picked up by a really multilingual driver who took me to Alpe d'Huez. The last thirteen kilometers were again a frightening experience: 21 hair-pins and a slippery road. When it became too nerve-wracking I closed my eyes in the hope that the driver did not. At a quarter to nine I arrived and Bolliet —who seems to have made it a rule that he shares both the first and last dinner with each of his speakers— was there to welcome me. I think I first had a glass of sherry.

      That Winter School in Alpe d'Huez is a funny business. I don't exactly know under what constraints it has to be organized. It is given under the auspices of some European Community Treaty: each country has to organize such a thing once a year and the government of the host country has to provide the funds, which, as a rule, they don't do. It is a glorious mess. This was the second time that Bolliet organized such a Winter School, but he has too many local speakers —each of them scheduled for one hour, say—. He should not do so, because they are really no good, but perhaps he has to do so in order not to make enemies. (Some of his American imports I could not admire either. I found a remarkable man, Enslow who was observer on behalf of the American Army —apparently some of the funds came from that organization—, and he observed! His comments on some of his countrymen were less forgiving than mine and that is saying a good deal.)

      In all the three days I heard two exciting lectures from Carel Scholten. It was a very nice survey of what he had done about the axiomatization of synchronization via binary signals. Regrettably he lost a large portion of his audience. Peter Naur, who spoke, like me, three hours, was very disappointing. (Enslow was so furious that he refused to attend Peter's third lecture and he had taken the wisest decision.) The last half of his time was devoted to the article he had published a few years ago in BIT on the eight queens problem, what is generally regarded as a poor article, written with the best of intentions —warning for unwarranted optimism based on simplified views of "structured programming"—, but technically totally beside the point. More disappointing, I guess, was the audience: you are invited to stay a little longer so as to be able to have informal contacts with the participants, but the majority of them talk about skiing, a card game or what they have just read in the paper. Under Carel Scholten's expert guidance I travelled home quite successfully.

25th December 1973 | prof.dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

EWD406

A trip to the U.S.A., 5th – 25th January 1974

The journey to Albuquerque was an ordeal, as usual. I knew no better than that my plane left Schiphol at 11.35 in the morning. My usual pessimism had seen to it that I had left home so early —catering for punctured tyres, train delays, etc., all disasters that did not occur— that I arrived at Schiphol at 6.45 .... just in time to catch my plane that took off at 10.15! I crossed the North Sea hoping that my luggage was with me.

I was at a PANAM flight which after a long stop and a change of planes in London continued to Boston, that is: so I thought. When I studied my ticket I saw that for London-Boston they had booked me on a TWA flight, that left London much earlier. I was somewhat annoyed because I hate missing connections and now I had in London only one hour and 20 minutes, but I was greatly relieved to see that the PANAM plane left Schiphol dead on time. Over London, however, instead of landing, it started to circle, and circle and circle... At least it came to the ground: it took a long time before the passengers could leave the aircraft; in the mean time I had a view on the conveyor belt unloading the suitcases and —needless to say— I failed to see mine.

I caught the TWA flight to Boston. Although I had three seats to myself I did not sleep: the cushions were so bad that lying was too painful. Still reasonably fresh I arrived in Boston where, as I expected, my luggage failed to turn up. Thanks to the changed schedule I had plenty of time in Boston and I started waiting for the PANAM flight to arrive in Boston. And there one of the last suitcases was mine! I shall never know in which plane it crossed the North Sea!

At five O'clock local time I left for Dallas where I had more than an hour to kill before the fourth plane could take me —with one intermediate stop— to Albuquerque. The hour in Dallas I have walked up and down in front of the gate: I was afraid that I would fall asleep if I set down. At 23.15 Albuquerque, more dead than alive. My hosts, Bell and Morrison, were there to pick me up; before I went to bed they revived me with a few whiskeys that were gratefully accepted.

The next day, Sunday, I had the shock of my life. I knew already that the number of participants of the Regional Conference would be unusually large, not the usual 60 but about 175. When I saw the list of participants, I saw that they came from all over the USA —even one from London— and, worse, that quite a few were quite well known. A rather terrifying audience. Secondly I heard that no other speakers had been arranged. As Stoughton Bell put it nicely "Well, I felt that the majority decided to come in order to hear you!" I quickly figured out that the scheduled two hours a day would be insufficient and that the double would be closer to the truth. And so it turned out to be.

I was very afraid, not in the last place because last December in Alpe d'Huez I had been warned that the perfection of some of my programs —and, of course, I have polished them over and over again— is beginning to irritate some of my audience. Add to this the possibility of a culture shock. Secondly I knew —particularly from Marktoberdorf— that in the USA I am so famous that people come with such utterly irrealistic expectations that one is bound to disappoint them. People tend to take your word as the gospel, simple souls think that one has a retail shop in Philosopher's Stones that, by magic, will cure all diseases. (And when over a few years even these simple should will have discovered that there remain a few diseases uncured, the will denounce me as a quack!)

In order to save the situation I used the first half of the morning to display all my misgivings, all my feelings of uncertainty and I warned them for all possible forms of disappointment. And I did not attempt to disguise my vulnerability, as I felt that honesty alone could save me. (Two days later one of the participants told me "On Monday morning I did not understand why you were so apologetic, but now I do.") It worked.

I had decided to start also here each lecture with a quotation, but on Monday afternoon I made an exception and wrote down one of my own puns. After the morning session, which for me ended about 11.15, I went to Stoughton Bell's office where I could rest for a few hours on a couch. Returning to the theater at two o'clock I could not resist telling them that a graffiti in the men's toilet at the Computation Center had taught me that not all computing scientists over here were proud of their president, but that, being a foreigner, I was not quite sure whether I was allowed to write at that sacred spot and that, therefore, I would give my modest contribution on the blackboard, in particular because I felt that U.S. Computing Scientists could help him: "What Nixon needs is a debugging aide." I intentionally hesitated slightly before writing down the last "e" and I had the theatre roaring with laughter. (I had already verified that even in front of the most mixed audience, a cynical joke about Nixon is one of the safest one can make.) The next day I could inform my audience that the graffiti in the gentlemen's toilet mentioned had been removed (all eighteen-and-a-half of them!).

What happened during that one man show of five days is unbelievable and exceeded my wildest hopes. It turned out to be a very inspiring audience, once they had picked up the rules of the game they inspired me to an extent that I have not experienced since a long time and I am perfectly willing to believe the many participants that told me on the last day that this week had been a unique experience. It certainly was for me! The most compact way to indicate it is perhaps to tell what happened on a Thursday. One of the older participants shyly handed me a piece of paper with a quotation from "Sand and Foam" by Kahlil Gibran

"The obvious is that which is never seen until someone expresses it clearly."

I thanked him very much, not only because it is a nice quotation, but also because it was clearly meant as a compliment. In the afternoon I found a sheet of paper on the speaker's desk with two others from the same source

"It takes two of us to discover truth: one to utter it and one to understand it."

"There lies a green field between the scholar and the poet; should the scholar cross it, he becomes a wise man; should the poet cross it, he becomes a prophet."

As about half the audience had to catch planes we ended the official proceedings at Friday morning. (That morning's quotation had been Lord Peter Wimsey's "A quotation saves original thinking.") As those who stayed quite clearly wanted to go on, we also arranged a Friday afternoon session which should be wholly conducted around requests from the floor. A group of conspirators centered around Ralph London wanted to see me solve a problem I had never seen before, so my mouth of a charming lady conspirator —should I say: "conspiratrix"?— the problem and what was expected from was explained to me in such a way that I could not escape. I managed, but not before displaying the detours and dead alleys they had been looking for. (Taking into account how dead-tired I was, I think that I even did not do too badly.) Afterwards they apologized for "undressing me", Unnecessary, for their desire was fully in order. I had vaguely expected something of that sort and took it as a welcome symptom that it actually happened.

And after having been carried for a week on 350 hands, I had to see to it that I should land safely with both feet on the ground again!

Saturday Stoughton Bell drove me via two Pueblos —muddy Indian villages, highly interesting, somehow beautyful and immensely refreshing because I saw children and dogs— and Santa Fe to Los Alamos. On Sunday James Morris showed me the Bandalier National Monument: I found the climb to the caves tiring, but probably I was already older than its early, original inhabitants ever managed to become.

On Monday I was picked up by Mark-B.Wells and introduced to his group. It was then that I collected my main impressions about Los Alamos Scientific Laboratory. Some of the impressions found their explanation during the evening when I read "Los Alamos, 1943 – 1945, The Beginning of a New Era....", a brochure full of nostalgia for the good old days when they could make an atom bomb, but knew at least what to do and why! Next day I lectured —under the title "The formal derivation of a few simple programs" at the general colloquium at LASL.

I have a general impression about the place, and a more specific one about the computing activity. The place has gone sour, that is the only way in which I can describe it. The exodus of brilliancy in 1945, the general uncertainty whether that place would continue to exist now World War II was over, is described quite vividly in the aforementioned brochure: apparently the place nearly died and it is to the credit side of J.Robert Oppenheimer's successor that it stayed alive, at least after a fashion. I do not know whether it is the general unhappiness about all the implications of the existence of atom bombs or the general sickness of high energy physics —there must be a bug in that theory!— which made the place one of the least exciting scientific institutes that I have visited in the last years. It was quite typical that most of the people seemed to welcome the energy crisis and its recognition: this might channel more funds into LASL, for the benefit of the whole (rather fragile) New Mexico economy.

Another example of malaise was that I have met no one who spoke with respect about his superiors. That is truly a bad sign. I tested it during my lecture. After having explained that, as every research director would agree with me, the truly scarce resources are not computing time or budget —"Bit-fiddling is the pass-time for the uneducated."— but worthwhile research projects and good brains, I tentatively added "and another very scarce resource, of course, is, as all their subordinates will agree, good directors of research!" The audience thought this insolent remark funnier than I thought funny: I had verified my impression of sickness on a large sample! The impression of hardly disguised death was moreover confirmed by the insipidness of the lunch conversation —since long a sensitive point with me!— and the often repeated assertion that Los Alamos was the ideal place to work and live ... on account of the scenery and the skiing opportunities!

The computing group seemed in exceptionally bad shape, as if they had forgotten what intellectual excitement really is. They spoke, full of misery that I can so well understand and also —and that is worse!— full of contempt (no matter how justified) about their customers who clung to FORTRAN for dear life. They tried to design a new programming language around the CDC-Star Computer but before telling me what nice things they had thought of, they told how they felt constrained by their customers insisting on obsolete features. I know that in particular high energy physicists are fairly education-resistant as far as computing and programming is concerned, but have they preached their gospel? I know that one has to do it ad nauseam and with great patience —decades, as a matter of fact—; but if one has not done so, can one complain about the lack of education of one's customers? About CDC —apparently the machine had been forced upon them— they spoke with bitterness and in this respect they met some sympathy from my side, for I remember the CDC salesman visiting the THE and recommending the Star Computer as a unique and fascinating challenge for the programming community, as if that was what we had been waiting for! This was some years ago and apparently CDC's software department up till now has failed to pick that gauntlet itself! Morris showed me some of his efforts to design a higher programming language that would control that machine: it was a valiant effort, but too much APL'ish to inspire me. The Star seems a sad mistake. My initial quotation the next day was from the aforementioned brochure "The error probably will stick," but no one asked during the discussion to what error I had been referring.

Shortly after my talk —which started at 8.15 in the morning— I was taken by car back to Albuquerque and from there via Los Angeles to San Diego, where I was joined by Win Feijen: together we should address from Wednesday through the next Wednesday about 18 people from Burroughs. As soon as Wim was with me I felt much better: now I could catch a cold, collapse, etc., I had now a spare speaker. On Friday evening Tony Hoare would join us and he would address the audience directly during the weekend.

Tony's arrival was not without problems: he was due to arrive at 20.40 and we had made the arrangement that he would arrive with an empty stomach and that we would have our evening meal together. Due to fog, San Diego airport was closed and his flight was diverted to somewhere. We had gone to the airport to pick him up but returned without him at 23.15: the hotel did not serve anything anymore. I went to bed, preparing my Saturday morning talk as I felt asleep. Next morning at the breakfast table I encountered Tony, with a beard and a healthy appetite: he had eventually arrived by coach at a quarter past one in the morning! He spoke that morning and that afternoon and did an excellent job. He spoke on Sunday morning as well, but then he appeared tired and in the afternoon I took over again.

My feelings with respect to this group were mixed as the group itself was mixed. There were a number of very sharp and capable ones, there was even one who had kept his sanity and soundness of judgment while having made a (very successful) PL/I compiler. On the other hand there was a man who still "lived" in machine code and —so it transpired on that very last day— did not really know what "a variable" was. OK, to Perlis we owe the remark that having understood what a variable is means that you have understood what programming is about. But yet. We had participants from all over the USA, from different plants; the obvious conclusion is that Burroughs is large enough to show a considerable amount of non-homogeneity.

At first sight out efforts have been very successful. That is, some two or three in the audience must have felt absolutely out of place and (I presume) utterly miserable. But these poor guys were rather silent. A next group enjoyed it, a minority was absolutely delighted and thrilled. Well, if I can give a number of people a fresh appreciation of our wonderful craft —and this for the benefit of all of us!—, if I can show them the way towards unexpected intellectual satisfaction and excitement, I am content: this is a worthy job. (This is what I have been trying to do in Albuquerque as well, and also there I think I was successful with about a quarter of my audience.) But it will take time, before these ideas spread; I have used the analogy, that you cannot show someone three times how to swim and throw him in deep water! You can do it, but the victim will drown and the act is like willful murder. And —not that I had expected otherwise— everybody was very pleased with the way Wim played his craft.

Shortly after the weekend it was decided that the seminar would only take seven days instead of the original eight: people were getting tired. As a result we left San Diego early Wednesday morning by car for Los Angeles, where we went to the Proctor plant. In the afternoon I had a private discussion about technical matters while Wim "addressed the troops". He had been warned that he should not expect an audience of the San Diego calibre, and my impression from him was that the warning was fully justified. (In both places, Albuquerque and San Diego, I have given exercises, "homework": in both places I found that accuracy and a good handwriting is perhaps even rarer than a sharp wit. This to my amazement, I just cannot imagine how you can combine sloppiness with programming. Perhaps they cannot either!)

Wim's last night in San Diego was not a very good one. He had a room on the 15th floor with a beautiful view for which he was envied. During his last night, however, Bob Hope had hired an apartment just above him and B.H. proved to be a noisy guest. This was a great pity for Wim, for the next two nights we should pass in planes.

After a pleasant meal at Don Lyle's home we flew during the night to Boston. (We would announce that flight as a flight to Boston with an intermediate stop in Cleveland, America Airways called it "A non-stop flight to Cleveland with continuing service to Boston.") To our misery we found ourselves close to three noisy couples (Puerto Rican? Mexican?) and since then I know the difference between Man and Beast: speech, non-stop speech....

In Boston we were picked up by professor Joseph Stoy from Oxford and his wife; they took us home with loving care and supplied us with eggs, coffee, milk and two showers. Jack Dennis came for lunch, then we went to MIT, Project MAC, where I gave a talk. It had only been announced a few hours before and it was really out of term time, but even that could not prevent an overflow problem. I had fun and Wim in the mean time collapsed. His eyes were still open but I don't think that he still heard or saw very much. After a cocktail party given by Stoy in our honor —Douglas Ross was there to my pleasant surprise!— we were taken to the airport and shipped home. Our flight back was successful in the sense that both of us have slept about four hours, but we had a stop in London of more than three hours and that was hard: Heathrow Airport is of course a quite interesting and fascinating place, but I don't think that we were still in the mood for it.

Our train brought us to Eindhoven at 15.54 and both our wives were at the railway station to collect us. On the whole of the trip I lost four pounds.....

28th January 1974
Burroughs
Plataanstraat 5
NEUNEN – 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Research Fellow

Transcription by Justin TerAvest.
Revised Mon, 10 Apr 2006.

Copyright Notice

The following manuscript,

EWD 407: Acceptance Speech for the AFIPS Harry Goode Memorial Award 1974

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 47-49 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN: 0�387�90652�5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

EWD 407

Acceptance Speech for the AFIPS Harry Goode Memorial Award 1974

Before focussing on today's occasion, viz. my receiving the AFIPS Harry Goode Memorial Award, I would like to say a few things about awards and getting them in general. You see, it has been argued that the whole system of giving awards and bestowing distinctions is obsolete and that therefore we should stop doing so.

One argument in favour of abolition is that it is so difficult to select the recipient in all fairness, both fairness to those candidates that don't get the award and fairness to its past recipients. The argument is that nearly always one is faced with either too many or too few eligible candidates. I cannot regard this as a valid objection: something cannot be wrong just because it is too difficult to do it well! Besides that, the past history of the Harry Goode Memorial Award has shown the way out of this dilemma: the abundance or lack of suitable candidates has resulted in a shared award in some years and no award at all in other years. That such a wise policy maintains and even enhances the value of the distinction is something of which —as you can guess— I am painfully aware.

A next argument on favour of abolition is that they are superfluous, because one only wants to give them to first rate scientists and they are sufficiently known via their work anyhow. But are they? Well, certainly in some circles, including the selection committee. But a wise committee realizes that such distinctions also act as signposts, as a kind of reading guide for the general public and I would not like to deprive responsible bodies of such means of exerting a hopefully beneficial influence. For the recipient that is aware of this aspect, the whole happening becomes somewhat embarrassing and perhaps even frightening, but that is his problem.

A third objection against the whole award system is that the distribution of fame suffers, by its very nature, from a built-in instability, so why aggravate it? The only thing you do is to make the already famous still more famous! But in all honesty: "What else can you do with a famous man?”— Now serious: underlying this last objection is the doubt as to whether “fame" as an institution in our civilization is a good thing or not. I think it can be a good thing. There are all sorts of things that should be said but will only be noticed when said by someone supported by fame: we may not like this state of affairs, but for the time being it seems a fact of life. Fame creates responsibility at both sides: the famous have the obligation to decide wisely when, where and how to open their mouth, their audience has the complementary responsibility not to accept everything they say unchallenged, just because a famous man has spoken. Trying to abolish fame is trying to shrink from those responsibilities, and I do not think that our civilization should do that.

In short, I am greatly in favour of honours, titles, awards, distinctions, golden medals etc. and you find in me not only an experienced, but also enthusiastic recipient!

So much about awards in general; now about getting them. When such a distinction hits you, and particularly when this happens during one of those agonizing periods of doubt and despair, it can be an encouragement stronger than I can describe it in words, it can revive one to the extent that suddenly one can hear again the angels singing in one’s heart. It can evoke a frightening joy.... And when it happens to you, I must warn you not to be disappointed when you discover that you can share this joy with only very few people: again you will find yourself very lonely....

Let us now switch from the general considerations to this specific occasion. I interpret this granting of the Harry Goode Memorial Award as a symptom of a broadening recognition of the relevance of a cause to which I have devoted more than the last decade of my life, and as such it is very gratifying. I have not been the only one to promote it, but I am willing to accept the point of view that I have been its principal advocate and in that capacity I accept the Award in name of all those colleagues, known or unknown, who have contributed. The cause in case is the conviction that the potentialities of automatic computing equipment will only bear the fruits we hope, provided that we take the challenge of the programming task seriously and provided that we realize that what we are called to design will get so sophisticated, that Elegance is no longer a luxury, but a matter of life and death. It is in this light that we must appreciate the view of programming as a practical exercise in the effective exploitation of one’s powers of abstraction, it is in this light that we must appreciate all current efforts towards raising the level of confidence in the correctness of our programs, the reliability and robustness of our machines, all efforts to discover the intellectual disciplines needed for controlled design.

We are in the midst of an exciting process of clarification, of improvement of our understanding of the true nature of the programming task and its intrinsic difficulties. A few notes of warning, however, are not out of place, because, to my great regret, already now progress is being oversold. Simple souls have been made to believe that we have a retail shop in Philosopher’s Stones that, by magic, will cure all diseases; in a few years time it will, of course, become apparent there are still a few diseases uncured and then the same simple souls will denounce us as quacks. Secondly, as one may expect, programming discipline reflects itself in a coding discipline, but this does not justify the expectation that the problems of programming can be solved by a few measures such as a new, clean programming language or a new management structure or a new mechanical aid! Such measures may assist, certainly, but only provided that we do not overestimate their significance.

I would like to end my brief acceptance speech with a quotation from the English artist William Blake, who lived from 1757 until 1827:

"He who would do good to another must do it in minute particulars
General Good is the plea of scoundrel, hypocrite and flatterer
For Art and Science cannot exist but in minutely organized particulars."

I thank you for your attention.

prof.dr.Edsger W.Dijkstra

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD408

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A time-wise hierarchy imposed upon the use of a two-level store.

Disclaimer. This note describes a way of looking at a class of virtual store implementations; the way seems illuminating and, as a result, virtual store implementations to which it is applicable may be expected to display some sensible characteristics. Not knowing all the —extensive!— literature on the subject. I do not claim any novelty; Denning’s survey article [1] of 1970 does not seem to mention it, not could I find it in the book by Coffman and Denning [2] of 1973 (nor in five other articles on demand paging and multiprogramming that at scanned).

Some simplifying assumptions about the hardware.

In order not to complicate the discussion unduly at the start I shall make a few simplifying assumptions. At the end of our discussion we may reconsider some of them; some are easily weakened, of others, however, we may come to the conclusion that, if our hardware does not allow such idealizations, the scheduling problem will be “complified” seriously, perhaps even beyond our comprehension and controls. In the latter case we don’t need to feel having failed “to cope with the problem”, on the contrary: the identification of a seriously “complifying” factor seems in the light of the present state of affairs a valuable discovery.

As primary store we assume a store as randomly accessible as, say, a core store. As secondary store we assume a device with the characteristics of, say, a drum or a head-per-track disc, such that
1)     place of information in secondary store need not influence decisions to change the contents of primary store
2)     the processor speed is sufficiently slow and/or the cycle time of the primary store is sufficiently small and/or the transfer rate between primary and secondary store is sufficiently low that slowing down of the processor as a result of cycle stealing by the channel (to all intents and purposes) can be ignored.
3)     a dedicated channel for the transport between the storage levels.

Furthermore I assume
4)     demand-paging with fixed-size pages
5)     a single channel for transport between primary and secondary store
6)     a single processor
7)     such a modest amount of processor-status information (registers included!) that the time needed for switching the processor from one process to another can be ignored in view of the upper bound on the frequency this switching has to take place
8)     no page sharing between user programs (for instance possible on account of a common procedure library).

Note 1. The above assumptions are —or at least: were— not unrealistic. All but the last one were satisfied in the case of the THE Multiprogramming - System for the EL-X8. Had we known at that time Simon’s article [3], the following considerations could well have been reflected in the design of that system in which, for instance, thrashing control has now been left to the operator,

Note 2. Usually the channel between the two levels of store is a semi-duplex channel, allowing a transport command either to read from or to write into secondary store. This results in the temptation
a)     to keep track of “unmodified pages” in core store that need not be dumped because the original information is still on the drum, and, even worse
b)     to allow the information which pages are still unmodified, to influence the replacement algorithm.
In the following I assume that this temptation does not exist —in a swapping drum with a full duplex channel it would be absent— or —if such an ideal situation is denied to us— it can be resisted. Our goal is “separation of concerns” and a coupling between the decisions what shall when be where on the one hand and the fact whether a page has been written into on the other seems contrary to that goal. (A milder form of yielding to the temptation is a separation between —constant— program pages which are never dumped and data pages which are always dumped, even if in fact unchanged while residing in core. Still I would prefer hardware that made the distinction pointless, at least in the case of fixed size pages.) The role of the replacement algorithm. We assume a constant number Q of page frames in main store dedicated to a particular program. Upon a so-called “page fault” —i.e. the desire to reference a page that is currently not in main store— the missing page must be brought in from seconday store; parallel to that a page that occupied one of the Q frames has to be dumped. It is the task of the “replacement algorithm” to choose that victim, its goal is to keep the interesting pages in main store. Obviously, for each reasonable strategy, unreferenced pages have a tendency to disappear sooner or later from main store.

Unable to look forward, each replacement algorithm looks backwards, i.e. its reasonableness is justified by the assumption of some sort of continuity and the expectations regarding the near future are based upon the near past. (Very much like the whether prediction for tomorrow “Same whether as today.”) Replacement algorithms differ in the amount of data they collect about past history and the way in which they extrapolate.

A well-known replacement algorithm records about the past history only the identity of the Q pages currently occupying the frames. When a victim has to be chosen, it makes —for lack of further information— a (quasi) random choice. As a replacement algorithm it is not too bad.

Another one is called FIFO: the page that is in main core for the longest period of time is chosen as the victim. As a rule that strategy generates considerably more page faults than the random choice described above.

The best result have been achieved with LRU (Least Recently Used): here the pages in main store are permanently ordered (logically, not physically!) in the order of last reference to them and the one that has not been referenced for the longest period of time is chosen as the victim.

The LRU-algorithm, besides making the impression of being sensible, has a deep advantage: if the same program is re-executed with a larger value of Q, the number of page faults generated by this program shall not be larger. This property of monotonicity makes it very attractive. A disadvantage, however, is that the collection of the information —i.e. the ordering according to last reference— is rather expensive.

A good compromise seems to have been discovered in the so-called “Second Chance Algorithm”. Here only a boolean is associated with each page frame, a boolean which is set to true at each reference to the corresponding page. In the case of a page fault these booleans are scanned in a cyclic order: if the boolean is true, it is set to false and the scanning proceeds to the next one, if the boolean is false, the victim is found. At the next page fault scanning will start at the next boolean. Its ease of implementation and the fact that it is hardly noticeably worse than LRU have given the Second Chance Algorithm a well-deserved popularity. (I have described the Second Chance Algorithm in more detail because I do not know of a publication of it; I would love to give credit where credit is due, but this is one of those delightful small inventions that, by word of mouth, spread like wildfire.)

It is worth noticing that neither LRU, nor the Second Chance Algorithm, although reasonable, are always optimal. On the contrary: in the case of cyclic references to U+1 pages, LRU is as bad as possible, as bad as FIFO. Instead of refining the replacement algorithm it seems in such a case wiser to detect the poor performance and to increase Q. Mind you, I am not advocating a brute force method —I am too much a puritan for that!— but if we have the choice between spending our investment in a neutral facility tilke more core or in the implementation of a very refined replacement strategy, we should realize that there will always be reference patterns for which our refined strategy will fail miserably compared to other strategies. Some more primary store, however, will never do harm and will be useful under a greater variety of loads. Much of the extensive research spent on a great variety of replacement algorithms strikes me as rather ill-directed.

I honestly assume that something simple like Random or the Second Chance Algorithm will do, in spite of the fact that they fo not enjoy the property of monotonicity such as LRU.

A program-wise balance between traffic time and computation time.

Let for a given program T be the total time the transport facilities between the storage levels have been monopolized on behalf of its page faults. Let for that same program C be the total time the processor has been monopolized on behalf of the progress of the corresponding computation. While C is given by the computation to be performed, T depends on the chosen replacement algorithm and the number Q of dedicated page frames, the so-called “window size”. (For the time being we assume that the window size is kept constant over the whole computation.)

When we now chose for each program a window size Q such that each program’s T/C-ratio is about equal to 1, then each program absorbs the same fraction of the two resources “traffic” and “computation” and we can schedule them together as a single shared resource, assigning “priorities” as we please. Under what further assumptions would such system work reasonably well?

To start with, no program can ever utilize more than 50 percent of the combined resource and for full utilization we need therefore at least two programs. With two programs, full machine utilization is only possible provided the two programs generate their page faults with great regularity, for instance: during the first transport one idles and the other proceeds, which generates its page fault as soon as the idler can proceed. Such regularity is more than we can hope for, we must expect that the computaion times between successive page faults will differ. It is also clear what has to be done about it: increase the degree of multiprogramming. I have a gut feeling that with four or five programs simultaneously in the machine (and not too extreme scheduling) most of these irregularities will be absorbed. (The gut feeling is based on an old experiment; for a conservative two-particle system Boltzmann’s distribution —which tells that for any particle at any moment of time the probability of a kinetic energy between U and U+dU is proportional to exp(-U/kT)dU— cannot hold; I simulated a three particle system and the exponential distributions came out beautifully! Admittedly the analogy is not too strong, yet it gives me the feeling that four or five is a reasonable guess; at a later stage we could try some baby-queueing-theory.)

For a given program we can we can plot the TC consumption: while C increases we move a pencil point to the right, while T increases we move a pencil point upwards. On the average our pencil point must rise under an angle of 45 degrees. Type a) is a program with small irregularities. type b) is a program with larger irregularities, type c), however, is a challenge to our assumption that a window size constant all through the computation is indeed a good thing: during the first half, which displays a T/C-ratio

greater than 1, we should like to decrease T, what may be achieved by increasing the window size; in the second half a smaller window size might bring the T/C-ratio closer to 1.

The next refinement, of course, will be to observe the T/C-ratios for the individual programs, decrease the window size when it is too small and increase it when it is too large. Compared with the target page fault frequency for a given program, the frequency of its window size adjustments must be an order of magnitude smaller, because —unless, perhaps, the window size is ridiculous— the whole notion of a window size being adequate or not in view of the resulting T/C-ratio is only meaningful over a longer stretch of T and C consumption. Picture c) indicates that, if T and C are the accumulated consumptions since the last decision to set or keep the window size at its current size, the absolute value |T-C| —i,e. the deviation from the diagonal—exceeding a threshold could be a good indication to reconsider the window size. (Note: if your target T/C-ratio is not 1, but 0.9, than one should take the absolute value |T-0.9C|.)

We may now hope to arrive at a very smoothly working system provided that for each program there is indeed a window size such that its T/C-ratio is close to 1. In the case of a program with highly interleaved references to 4 pages, howeverm a window size = 4 will give a T/C-ratio = 0 and a window size = 3 will give an arbitrarily high T/C-ratio. With window size = 4, we have T = 0 and we shall reconsider after C= threshold; if we then decide upon a window size = 3, then in the extreme case C will drop to zero and the window size is reconsidered when F = threshold, i.e. two such periods together have again a T/C-ration = 1 ! (This is just a joke, not an intended feature. When I saw this, I started laughing. It says something about the stability of the window size adjustment mechanisms at this end of the scale and that is very encourageing. I think that I would keep the window size = 4 for longer periods of time: the window size oscillation with extreme T/C-ratios is not difficult to detect.)

In the case of a program with high vagrancy —a random referencing through 1 000 000 pages and hardly any computing at all— we shall always have a very high T/C-ratio and if the system reacts upon this regrettable state of affairs by increasing and increasing its window size, then the system comes in a silly state that should be avoided. (At this side of the spectrum the window size adjustment mechanism suggested has not that stability.) It would be nice if for each program the system kept a list of the identities of the last so-many dumped pages: from this list we can derive a very good indication whether the most recent computation would have given a smaller T/C-ration with a larger window size. (If I am not mistaken, the guess can be absolutely accurate if the LRU strategy has been used for replacement; Second Chance Algorithm or Random seem to allow a good estimate.) We must be able to detect that increasing the window size is no good, yeah, even that, although the T/C-ratio is too high, a decrease of the window size might not make it worse; in the latter case the window size must tentatively be decreased until oscillation as mentioned above.

Change of window size will change the number of free pages — when the number becomes too large or too small, we may or must decide to change the degree of multiprogramming.

*              *
*

The above has been written for many reasons. To a large extent it was like paying an old debt, repairing an old omission: we should have thought such type of thoughts a decade ago when we were designing the THE Multiprogramming System in which the replacement algorithm was LRU but then applied to the whole of main store. As a result a program with high vagrancy proceeded very slowly and could reside very long in the system. I remember that we have considered for a moment to keep track of which page frames were used by which program but that we have given up to pursue this idea rather quickly, because we had difficulties with the shared library pages. What the difficulties were I don’t remember, for now it seems obvious what to do. If program A requests access to a shared page that happens to be in the window of program B, the number of free pages increases by 1 because the two windos are made to overlap on that page; Both programs keep independently of eachother track of their own usage for the sake their own replacement algorithm. When the first of the two pushes the shared page out of its window the number of free pages decreases by one. When the last owner of the page pushes it out of its window, then the page disappears from main store. The possible gain of page sharing should not be too great, for otherwise the pressure to schedule such as to maximize such coincidences becomes too strong. Such pressure should be resisted, yielding to it would be terrible! (Immediately after I had written down and underlined this sentence, I found in Denning [4] “Allocation policies should tend to run two processes together in time whenever they are sharing information...” etc.!)

A second reason for writing the above down was an effort towards unmuddling my own mind. Last week the Dutch Computer Society NRMG organized a two-day Symposium on Operating Systems. (I spoke, but not at all about strategies; my subject was the mathematical relation between synchronization and sequencing, between deadlock and termination.) It was a depressing symposium: while most speakers wanted to talk about how to design a good operating system, the majority of the audience wanted to hear how to live with a bad one. And that is a different subject.... I was appalled during the discussion by the questions that came from the floor; I got the impression of operating systems that cause the machine’s behaviour to be extremely sensitive to all sorts of workload characteristics, and, even worse, in a hardly predictable way. And I have the feeling that a machine is only useful provided the relevant aspects of its behaviour are reasonably well predictable and, also, as unsensitive to workload characteristics as we can possibly achieve. Such “smoothness” in the systems reactions seems much more important than the utmost efficiency, that justifies all complications that have been introduced. Honesty should even force us to add, that after all, efficiency considerations justify only the efforts and not the result. For from various participants I heard that they would regard a central processor utilization of 75 percent as a great achievement of the operating system! In what crazy world are we living? So I started to think.

The sketched approach —aiming both at smoothness and avoidance of extreme situations— can be viewed as an effort to design with Simon’s “The Architecture of Complexity” in mind. For the proper functioning of a hierarchical organization a necessary condition is that the natural grain for understanding each level grows by an order of magnitude when we go one level up. Here we are trying to understand what happens in time and our grains are therefore grains of time. The minimal time grain is of microseconds: the occurrence is a reference to a word in main store. This is applicable for the description of the happening during C-growth, between page faults. The next time grain is of the order of magnitude of a few centiseconds: at that level the relevant occurrence is the transport generated by a page fault. The next time grain will be of the order of magnitude of a second, viz. when for a program its window size will be reconsidered. The decision to change te degree of multi-programming will be taken with still lower frequency. On account of past experience I judge this as inspiring confidence.

The whole-model gives me a better grasp on what you should say to someone who complains that he cannot keep his processor busy. If he is content with his throughput, you should say “Why bother?” or “What about a slower processor?” (In the early days I have seen, at an English University, where an IBM 7090 could not cope with the load, that this was replaced by an IBM 7094, so that that machine could wait four times as fast on its magnetic tapes!) If he bothers, faster store and transport will always do the job —this is, mathematically, of course the same suggestion as slowing down the processor. Just increasing the store will not help if the real source of the difficulties are the high vagrancy programs, it will help if he can increase his degree of multiprogramming in order to absorb the apparently severe irregularities. (Somehow I cannot expect that these severe irregularities in page fault occurrence can be successfully absorbed by a modest increase of the window size.)

Finally I have understood why I have never been able to see much significance in Denning’s notion of the working set, viz. the set of pages referenced in the last t seconds of computation time: in that notion the intensity of the interleaving of the references is disguised, if not hidden and it is this intensity of interleaving which tells us how much the T/C-ratio might rise. A final word about our simplifying assumptions. One channel and one processor are not essential, nor the absence of page sharing. Assumption 7 is not used explicitly in this note, it is of course essential in the realm of processor scheduling where you want to give the processor to the most urgen job and do not like to make this choice a compromise between the above desire and the desire to minimize the switchings from one to another. The fixed size pages are attractive for the simplicity of the considerations, to figure out how complicated this story would become for variable size pages (in the sense of “quanta of presence in main store”) I just don’t know. I guess that a similar story can be told.

Assumptions 1 and 2 seem pretty essential and so does number 3.

Finally, let there be no misunderstanding about this note: it has no scientific pretensions, nor should it be regarded as a suggestion for new implementations. It has been written for my own clarification and all others that would like to read this note are welcome to do so.

[1] | Denning, Peter J., “Virtual Memory” Computing Surveys Vol.2, No 3 (Sep. 1970) 153 - 189
[2] | Coffman, Jr., Edward G. and Denning, Peter J». “Operating Systems Theory”, Prentice-Hall, Inc., Englewood Cliffs, 1973
[3] | Simon, Herbert A. “The Architecture of Complexity”, reprinted in Simon, Herbert A.“The Sciences of the Artificial” MIT-Press 1968
[4] | Denning, Peter J., “The Working Set Model For Program Behavior” Comm.A.C.M. Vol.11, No 5 (May 1968), 323 - 333

Author’s address: |  | prof.dr.Edsger W.Dijkstra
Burroughs |  | Research Fellow
Plataanstraat 5
NUENEN 4565
The Netherlands

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD413

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

The formal treatment of some small examples.

In this chapter I shall give the formal development of a series of small programs solving simple problems. This chapter should not be interpreted as my suggestion that these programs must or should be developed in such a way: such a suggestion would be somewhat ridiculous. I expect most of my readers to be familiar with most of the examples and, if not, they can probably write down a program, hardly aware of having to think about it.

The development, therefore, is given for quite other reasons. One reason is to make ourselves more familiar with the formalism as far as it has been developed up to now. A second reason is to convince ourselves that, in principle at least, the formalism is able to make explicit and quite rigourous what is often justified with a lot of hand-waving. A third reason is precisely that most of us are so familiar with them that we have forgotten how, a long time ago, we have convinced ourselves of their correctness: in this respect this chapter resembles the beginning lessons in plane geometry that are traditionally devoted to proving the obvious. Fourthly, we may occasionally get a little surprise and discover that a little familiar problem is not so familiar after all. Finally it may shed some light on the feasibility, the difficulties and the possibilities of automatic program composition or mechanical assistance in the programming process. This could be of importance even if we do not have the slightest interest in automatic program composition, for it may give us a better appreciation of the role that our inventive powers may or have to play. In my examples I shall state requirements of the form “for fixed x, y, ... ; this is an abreviation for “for any values X0 , y0, ... a post-condition of the form x = x0 and y = y0 and ... should give rise to a pre-condition implying x = x0 and y = y0 and ”. We shall guarantee this by treating such quantities as “temporary constants”, they will not occur to the left of an assigment statement.

First example. Establish for fixed x and y the relation R(m):

| (m = x or m = y) and m ≥x and m ≥ y .

For general values of x and y the relation m = x can only be established by the assignment m:= x; as a consequence (m = x or m = y) can only be established by activating either m:= x or m:= y. In flow-chart form

The point is that at the entry the good choice must be made so as to guarantee that upon completion R(m) holds. For this purpose we “push the post-condition through the alternatives”:

and we have derived the guards! As

| R(x) = ((x = x or x = y) and x ≥ x and x ≥ y) = (x ≥ y)
and | R(y) = ((y = x or y = y) and y ≥ x and y ≤ y) = (y ≥ x)

we arrive at our solution:

| if x .≥ y → x ▯ y ≥ x → m:= y fi

Because (x ≥ y or y ≥ x) = T , the program will never abort (and in passing we have given an existence proof: for any values x and y there exists an m satisfying R(m) ). Because (x ≥ y and y ≥ x) ≠ F , our program is not necessarily deterministic: if initially x = y , it is undetermined which of the two assignments will be selected for execution; this non-determinacy is fully correct, because we have shown that the choice does not matter.

Note. If the function “max” had been an available primitive, we could have coded m:= max(x, y) because R(max(x, y)) = T (End of note.)

The program we have derived is not very impressive; on the other hand we observe that in the process of deriving the program from our postcondition next to nothing has been left to our invention.

Second example.

For a fixed value of n (n > 0) a function f(i) is given for 0 ≤ i < n . Establish the truth of R:

| 0 ≤ k < n and (A i: 0 ≤ i < n: f(k) ≥ f(i)) .

Because our program must work for any positive value of n it is hard to see how R can be established without a loop; we are therefore looking for a relation P that is easily established to start with and such that eventually (P and non BB) ⇒ R . In search of P we are therefore looking for a relation weaker than R , in other words: we want a generalization of our final state. A standard way of generalizing a relation is the replacement of a constant by a variable —possibly with a restricted range— and here my experience suggests that we replace the constant n by a new variable, j say, and take for P:

| 0 ≤ k < j ≤ n and (A i: 0 ≤ i < j : f(k) ≥ f(i))

where the condition j ≤ n has been added in order to do justice to the finite domain of the function f . Then, with such a generalization, we have trivially

| (P and n = j) ⇒ R .

In order to verify whether this choice of P can be used, we must have an easy way of establishing it to start with. Well, because

| (k = 0 and j = 1) ⇒ P .

we venture the following structure for our program -comments being added between braces

| k, j:= 0, 1 {P has been established};
| do j ≠ n → a step towards j = n under invariance of P od
| {R has been established} .

Again my experience suggests to choose as monotonicly decreasing function t of the current state t = (n - j) , which, indeed, is such that P ⇒ (t ≥0) . In order to ensure this monotonic decrease of t I propose to subject j to an increase by 1 and we can develop

| wp(“j:= j + 1”, P) =
|  | 0 ≤ k < j + 1 ≤ n and (A i:0 ≤ i < j + 1: f(k) ≥ f(i)) =
|  | 0 ≤ k < j + 1 ≤ n and (A i:0 ≤ i < j: f(k) ≥ f(i)) and f(k) ≥ f(j).

The first two terms are implied by P and j ≠ n (for (j≤n and j≠n) ⇒ (j + 1 ≤ n) and this is the reason why we decided to increase j only by 1.) Therefore

| (P and j ≠ n and f(k) ≥ f(j)) ⇒ wp(“j:= j + 1”, P)

and we can take the last condition as guard. The program

| k, j := 0, 1;
| do j ≠ n → if f(k) ≥ f(j) → j:= j + 1 fi od

will indeed give the good answer when it terminates properly. Proper termination, however, is not guaranteed, because the alternative construct might lead to abortion —and it will certainly do so, if k = 0 does not satisfy R . If f(k) ≥ f(j) does not hold, we can make it hold by the assignment k:= j and therefore our next investigation is

| wp(“k, j:=j, j + 1”, P) =
| 0 ≤ j < j + 1 ≤ n and (A i: 0 ≤_i < j + 1: f(j) ≥ f(i)) =
| 0 ≤ j < j + 1 ≤ n and (A i: 0 ≤_i < j: f(j) ≥ f(i)) =

To our great relief we see that

| (P and j ≠ n and f(k) ≤ f(j))⇒ wp(“k, j:= j, j + 1”, P)

and the following program will do the job without the danger of abortion:

| k, j:= 0, 1;
| do j ≠ n → if f(k) ≥ f(j) → j:= j + 1
|  | ▯ f(k) ≤ f(j) → k, j:= j, j + 1 fi od .

A few remarks are in order. The first one is that, as the guards of the alternative construct do not necessarily exclude each other, the program harbours the same kind of internal non-determinacy as the first example. Externally it may display this non-determinacy as well. The function f could be such that the final value of k is not unique: in that case our program can deliver any acceptable value!

The second remark is that having developed a correct program does not mean that we are through with the problem. Programming is as much a mathematical discipline as an engineering discipline, correctness is as much our concern as, say, efficiency. Under the assumption that the computation of a value of the function f for a given argument is a relatively time-consuming operation, a good engineer should observe that in all probability this program will often ask for many re-computations of f(k) for the same value of k . If this is the case the trading of some storage space against some computation time is indicated. The effort to make our program more time-efficient, however, should never be an excuse to make a mess of it. (This is obvious, but I state it explicitly because so much messiness is so often defended by an appeal to efficiency considerations, while upon closer inspection the defense is always unvalid: it must be, for a mess is never defensible.) The orderly technique for trading storage space versus computation time is the introduction of one or more redundant variables, the value of which can be used because some relation is kept invariant. In this example the observation of the possibly frequent re-computation of f(k) for the same value of k suggests the introduction of a further variable, max say, and to extend the invariant relation with the further term

| max = f(k) .

This relation must be established upon initialization of k and be kept invariant —by explicit assignment to max — upon modification of k . We arrive at the following program

| k, j, max := 0, 1, f(0);
| do j ≠ n → if max ≥ f(j) → j:= j + 1
|  | ▯ max ≤ f(j) → k, j, max:= j, j + 1, f(k) fi od

This program is probably much more efficient than our previous version. If it is, a good engineer does not stop here, because he will now observe that for the same value of j he might order a number of times the computation of f(j). It is suggested to introduce a further variable, h say (short For “help”) and to keep

| h = f(j)

invariant. This, however, is a thing that we cannot do on the same global level as with oux previous term: the value j = n is not excluded and for that value f(j) is not necessarily defined. The relation h = f(j) is therefore re-eslablished every time j ≠ n has just been checked; upon completion of the outer guarded command— “just before the od” so to speak— we have h = f(j - 1) but we don’t bother and leave it at that.

| k, j, max:= 0, 1, f(0);
| do j ≠ n → h:= f(j);
|  | if max ≥ h → j:= j + 1
|  | ▯ max ≤ h → k, j, max:= j, j + 1, h fi od

A final remark is not so much concerned with our solution as with our considerations. We have had our mathematical concerns, we have had our engineering concerns and we have accomplished a certain amount of separation between them, now focussing our attention on this aspect and then on that aspect. While such a separation of concerns is absolutely essential when dealing with more complicated problems, I must stress that focussing one’s attention on one aspect does not mean completely ignoring the others. In the more mathematical part of the design activity we should not head for a mathematically correct program that is so badly engineered that it is beyond salvation. Similarly, while “trading” we should not introduce errors through sloppiness, we should do it careful and systematic; also, although the mathematical analysis as such has been completed, we should still understand enough about the problem to judge whether our considered changes are significant improvements.

Note. Prior to my getting used to these formal developments I would always have used “j < n” as the guard for this repetitive construct, a habit I still have to unlearn, for in a case like this, the guard “j ≠ n” is certainly to be preferred. The reason for the preference is twofold. The guard “j ≠ n” allows us to conclude j = n upon termination without an appeal to the invariant relation P and thus simplifies the argument about what the whole construct achieves for us compared with the guard “j < n”. Much more important, however, is that the guard “j ≠ n” makes termination dependent upon (part of) the invariant relation, viz. j ≤ n and is therefore to be preferred for reasons of robustness. If the addition j:= j + 1 would erroneously increase j too much and would establish j > n , then the guard “j < n” would give no alarm, while the guard “j ≠ n” would at least prevent proper termination. Even without taking machine malfunctioning into account, this argument seems valid. Let a sequence x0, x1, x2, ... be given by a value for x0 and for i > 0 by xi= f(xi-1) , where f is some computable function and let us carefully and correctly keep the relation X = xi, invariant. Suppose that we have in a program a monotonicly increasing variable n , such that for some values of n we are interested in xn . Provided n ≠ i , we can always establish X = xn by

| do j ≠ n → i, X:= i+1, f(X) od .

If —due perhaps to a later change in the program with the result that it is no longer guaranteed that n can only increase as the computation proceeds— the relation n ≥ i does not necessarily hold, the above construct would (luckily!) fail to terminate, while the use of

| do j < n → i, X:= i+1, f(X) od

would have failed to establish the relation X = xn. The moral of the story is that, all other things being equal, we should choose our guards as weak as possible. (End of note.)

Third example.

For fixed a (a ≥ 0) and d (d > 0) it is requested to establish

R: | 0 < r < d and (a - r)|d .

(Here the vertical bar “|” is to be read as: “is a multiple of”.) In other words we are requested to compute the smallest non-negative remainder r that is left after division of a by d . In order that the problem be a problem, we have to restrict ourselves to addition and subtraction as the only aritmetic operations. Because the term (a - r)|d is satisfied by r = a, an initialization that —on account of a ≥ 0— also satisfies 0 ≤ r , it is suggested to choose as invariant relation P:

| 0 ≤ r and (a - r)|d .

For the function t , the decrease of which should ensure termination, we choose r itself; because the messaging of r must be such that the relation (a - r)|d is kept invariant, r may only be changed by a multiple of d , for instance d itself. Thus we find ourselves invited to evaluate

| wp(“r:= r - d”, P) and wdec(“r:= r - d”, r) =
|  | 0 ≤ r - d and (a - r + d > 0 .

Because the term d > 0 could have been added to the invariant relation P , only the first term is then not implied; we find the corresponding guard “r ≥ d” and the tentative program:

| if a ≥ 0 and d > 0 →
|  | r:= a;
|  | do r ≥ d → r:= r - d od
| fi .

Upon completion the truth of P and non r ≥ d has been established, a relation that implies R and thus the problem has been solved.

Suppose now, that in addition it would have been required to assign to q such a value that finally we also have

| a = d * q + r

—in other words it is requested to compute the quotient as well— then we can try to add this term to our invariant relation. Because

| (a = d * q + r) ⇒ (a = d *(q + 1)+(r - d))

we are led to the program:

| if a ≥ 0 and d > 0 →
|  | q, r:= 0, a;
|  | do r ≥ d → q, r:= q + 1, r - d od
| fi .

The above programs are, of course, very time-consuming if the quotient is large. Can we speed it up? The obvious way to do that is to decrease r by larger multiples of d . Introducing for this purpose a new variable, dd say, the relation to be established and kept invariant is

| dd|d and dd ≥ d

We can speed up our first program by replacing “r:= r - d” by a possibly repeated decrease of r by dd , while dd , initially = d , is allowed to grow rather rapidly, e.g. by doubling it each time. So we are led to consider the following program

| if a ≥ 0 and d > 0 →
|  | r:= a;
|  | do r≥d →
|  |  | dd:= d;
|  |  | do r≥ dd → r - dd; dd + dd od
|  | od
| fi

The relation 0 ≤ r and (a - r)|d is clearly kept invariant and therefore this program establishes R if it terminates properly, but does it? Of course it does, because the inner loop —that terminates on account of dd > 0 — is only activated with initial states satisfying r ≥ dd and therefore the decrease r:= r - dd is performed at least once for every repetition of the outer loop.

But the above reasoning —although convincing enough!— is a very informal one and because this chapter is called “a formal treatment” we can try to formulate and prove the theorem to which we have appealed intuitively.

With the usual meanings of IF, DO and BB , let P be the relation that is kept invariant, i.e.

| (P and BB) ⇒ wp(IF, P) for all states | (1)

and let furthermore i be an integer function such that for any value of t0 and for all states

| (P and BB and t ≤ t0 + 1) ⇒ wp(IF, t ≤ t0) | (2)

or —in an equivalent formulation—

| (P and BB) ⇒ wdec(IF, t) for all states | (3)

then for any value of t0 and for all states

| (P and BB and wp(DO, T) and t ≤ t0 + 1) ⇒ wp(DO, t ≤ t0) | (4)

or —in an equivalent formulation—

| (P and BB and wp(DO, T) ⇒ wdec(DO, t) . | (5)

In words: if the relation P that is kept invariant guarantees that each selected guarded command causes an effective decrease of t, then the repetitive construct will cause an effective decrease of t if it terminates properly after at least one execution of a guarded command. The theorem is so obvious, that it would be a shame if it were difficult to prove, but luckily it is not. We shall show that from (1) and (2) follows that for any a value t0 and all states

| (P and BB and Hk(T) and t ≤ t0 + 1) ⇒ Hk(t ≤ t0) | (6)

for all k ≥ 0. It holds for k = 0 —because (BB and H₀(T)) = F — and we have to derive from the assumption that (6) holds for k = K , that it holds for k = K + 1 as well.

| (P and BB and HK+1(T) and t ≤ t0 + 1)
|  | ⇒ wp(IF, P) and wp(IF, HK(T)) and wp(IF, t ≤ t0)
|  | ⇒ wp(IF, P and HK/(T) and t ≤ t0)
|  | ⇒ wp(IF, and BB and HK/(T) and t ≤ t0 + 1) or (t ≤ t0 and non BB))
|  | ⇒ wp(IF, HK(t ≤ t0) or H₀(t ≤ t0))
|  | ⇒ wp(IF, HK(t ≤ t0))
|  | ⇒ wp(IF, HK(t ≤ t0) or H₀(t ≤ 0))
|  | ⇒ HK+1(t ≤ t0)

The first implication follows from (1), the definition of HK+1(T) and (2), the equality in the 3rd line is obvious, the implication in the 4th line is derived by taking the conjunction with (BB or non BB) and then weakening both terms, the implication in the 5th line follows from (6) for k = K and the definition of H₀≤t0) and the rest is straightforward. Thus relation (6) has been proved for all k ≥ 0 and from that result (4) and (5) follow immediately.

Exercise. Modify also our second program in such a way that it computes the quotient as well and give a formal correctness proof for your program.

Let us assume next, that there is a small number, 3 say, by which we are allowed to multiply and to divide and that these operations are sufficiently fast so that they are attractive to use. We shall denote the product by “m * 3” —or by “3 * m”— and the quotient by “m / 3”; the latter expression will only be called for evalution provided initially m|3 holds. (We are working with integer numbers, aren’t we?)

Again we try to establish the desired relation R by means of a repetitive construct, for which the invariant relation P is derived by replacing a constant by a variable. Replacing the constant d by the variable dd , whose values will be restricted to d *(a power of 3) we come to the invariant relation P:

| 0 ≤ r < dd and (a - r)|dd and (E i: i ≥ 0: dd = d * 3i)

We shall establish the relation and then try to reach, while keeping it invariant, a state satisfying d = dd . In order to establish it, we need a further repetitive construct: first we establish

| 0 ≤ r < dd and (a - r)|dd and (E i: i ≥ 0: dd = d * 3i)

and then let dd grow until it is large enough and r < dd is satisfied as well. The following program would do:

| if a ≥ 0 and d > 0 →
|  | r, dd = a, d;
|  | do r ≥ dd → dd:= dd * 3 od;
|  | do dd ≠ d → dd:= dd / 3;
|  |  | do r ≥ dd → r:= r - dd od
|  | od
| fi

Exercise. Modify also the above program in such a way that it computes the quotient as well and give a formal correctness proof for your program. This proof has to demonstrate that whenever dd / 3 is computed, originally dd|3 holds. The above program exhibits a quite common characteristic. On the outer level we have two repetitive constructs in succession; when we have two or more repetitive constructs on the same level in succession, the guarded commands of the later ones lend to be more elaborate than those of the earlier ones. (This is known as “Dijkstra’s Law”, which does not always hold.) The reason for this tendency is clear: each repetitive construct adds his “and non BB” to the relation it keeps invariant and that additional relation has to be kept invariant by the next one as well. But for the inner loop, the second one is exactly the inverse of the first one; but it is precisely the function of the added statement do r ≥ dd → r:= r - dd od to restore the potentially destroyed relation r < dd , i.e. the achievement of the first loop.

Fourth example.

For fixed Q1 , Q2 , Q3 and Q4 it is requested to establish R where R is given as R1 and R2 with R1: The sequence of values (q1, q2, q3, q4) is a permutation of the sequence of values (Q1, Q2, Q3, Q4) R2:         q1 ≤ q2 ≤ q3 ≤ q4 .

Taking R1 as relation P to be kept invariant a possible solution is

| q1, q2, q3, q4:= Q1, Q2, Q3. Q4;
| do q1 > q2 → q1, q2:= q2, q1
|  | ▯ q2 > q3 → q2, q3:= q3, q2
|  | ▯ q3 > q4 → q3, q4:= q4, q3
| od

The first assignment obviously establishes P and no guarded command destroys it. Upon termination we have non BB , and that is relation R2. The way in which people convince themselves that it does terminate depends largely on their background: a mathematician might observe that the number of inversions decreases,an operations researcher will interpret it as maximizing q1 + 2*q2 + 3*q3 + 4*q4 and I, as a physicist, just “see” the center of gravity moving in the one direction (to the right, to be quite precise). The program is remarkable in the sense that, whatever we would have chosen for the guards, never would there be the danger of destroying relation P : the guards are in this example a pure consequence of the requirement of termination.

Note. Observe that we could have added other alternatives such as

| q1 > q3 → q1, q3:= q3, q1

as well; they cannot be used to replace one of the given three. (End of note.)

It is a nice example of the kind of clarity that our non-determinacy has made possible to achieve; needless to say, however, that I do not recommend to sort a large number of values in an analogous manner.

Fifth example.

We are requested to design a program approximating a square root, more precisely: for fixed n (n ≥ 0) the program should establish

R: | a² ≤ n and (a + 1)² > n .

One way of weakening this relation is dropping one of the terms of the conjunction, e.g. the last one and focus upon

P: | a² ≤ n

a relation that is obviously satisfied by a 0 , so that the initialization need not bother us. We observe that if the second term is not satisfied this is due to the fact that a is too small and we could therefore consider the statement “a:= a + 1”. Formally we find

| wp(“a:= a + 1”, P) = ((a + 1)² ≤ n) .

Taking this condition as — the only!— guard, we have (P and non BB = R and therefore we are invited to consider the program

| if n ≥ 0 →
|  | a:= 0 {P has been established};
|  | do(a + 1)² ≤ n → a:= a + 1 {P has not been destroyed} od
|  |  | {R has been established}
| fi {R has been established}

all under the assumption that the program terminates, what it does thanks to the fact that the square of a non-negative number is a monotonicly increasing function: we can take for t the function n - a²

This program is not very surprising, it is not very efficient either: for large values of n it could be rather time-consuming. Another way of generalizing R is the introduction of another variable, b say —and again restricting its range— that is to replace part of R, for instance

P: | a² ≤ n and b² > n and 0 ≤ a < b

By the way this has been chosen it has the pleasant property that

| (P and (a + 1 = b)) ⇒ R

Thus we are led to consider a program of the form —from now onwards omitting the if n ≥ → .... fi—

| a, b:= 0, n + 1 {P has been established};
| do a + 1 ≠ b → decrease b - a under invariance of P od
| {R has been established} .

Let each time the guarded command is executed d be the amount by which the difference b - a is decreased. Decreasing this difference can he done by either decreasing b or by increasing a or both. Without loss of generality we can restrict ourselves to such steps in which either a or b is changed, but not both: if a is too small and b is too large and in one step only b is decreased, then a can be increased in a next step. This consideration leads to a program of the following form

| a, b:= 0, n + 1 {P has been established};
| do a + 1 ≠ b →
|  | d:= ... {d has a suitable value and P is still valid};
|  | if ... → a:= a + d {P has not been destroyed}
|  |  | ▯ ... → b:= b - d {P has not been destroyed}
|  | fi {P has not been destroyed}
| od {R has been established}

Now

| wp(“a:= a + d”, P) = ((a + d)² ≤ n and b² > n)

which, because p implies the second term leads to the first one as our first guard; the second guard is derived similarly and our next form is

| a, b:= 0, n + 1
| do a + 1 ≠ b → d:= ...;
|  | if {a + d²) ≤ n → a:= a + d
|  |  | ▯ (b - d²) > n → b:= b - d
|  | fi {P has not been destroyed}
| od {R has been established}

We are still left with a suitable choice for d . Because we have chosen b - a —well: b - a → 1 actually— as our function t , effective decrease implies that d must satisfy d > 0 . Furthermore the following alternative construct may not lead to abortion, i,e, at least one of the guards must be true. That is, the negation of the first: (a + d)² > n must imply the other: (b . d)² > n ; this is guaranteed if

| a + d ≤ b - d
or | 2 * d ≤ b - a .

Besides a lower bound we have also found an upper bound for d . We could choose d : 1 , but the larger d , the faster the program and therefore we propose:

| a, b:= 0, n + 1
| do a + 1 ≠ b → d:= (b - a) div 2;
|  | if {a + d²) ≤ n → a:= a + d
|  |  | ▯ (b - d²) > n → b:= b - d
|  | fi {P has not been destroyed}
| od {R has been established}

where n div 2 is given by n/2 if n|2 and by (n - 1)/2 if (n - 1)|2 .

The use of the operator div suggests that we should look what happens if we impose upon ourselves the restricition that whenever d is computed, b - a should be even. Introducing c = b - e and eliminating the b , we get the invariant relation

P: | a² ≤ n and (c + a)² > n and (E i: i ≥ 0: c = 2i)

and the program (in which the roles of c and d have coincided)

| a, c:= 0, 1;do c² ≤ n → c:= 2 * c od
| do c ≠ 1 → c:= c/2;
|  | if {a + c²) ≤ n → a:= a + c
|  |  | ▯ (a + c²) > n → skip
|  | fi
| od .

Note. This program is very much like the last program for the third example, the computation of the remainder under the assumption that we could multiply and divide by 3 . The alternative construct in our above program could have been replaced by

| do (a + c)² ≤ n → a:= a + c od

If the condition for the remainder 0 ≤ r < d would have been rewritten as r < d and (r + d) ≥ d the similarity would be even more striking. (End of note.)

Under admission of the danger of beating this little example to death, I would like to submit the last version to yet another transformation. We have written the program under the assumption that sqaring a number is among the repertoire of available operations, but suppose it is not and suppose that multiplying and dividing by (small) powers of 2 are the only (semi-)multiplicative operations at our disposal. Then our last program as it stands is no good i.e. it is no good if we assume that the values of the variables as directly manipulated by the machine are to be equated to the values of the variables a and c if this computation were performed “in abstracto”. To put it in another way: we can consider a and c as abstract variables whose values are represented —according to a convention more complicated than just identity— by the values of other variables that are in fact manipulated by the machine. Instead of directly manipulating a and c , we can let the machine manipulate p , q and r , such that

| p = a * c
| q = c²
| r = n - a² .

It is a co-ordinate transformation and to each path through our (a,c)-space corresponds a path through our (p,q,r)-space. Not always the other way round, for the values of p , q and r are not independent: in terms of p , q and r we have redundancy and therefore the potential to trade some storage space against not only computation time but even against the need to square! (The transformation from a point in (a,c)-space to a point in (p,q,r)-space has quite clearly been constructed with that objective in mind.) We can now try to translate all boolean expressions and moves in (a,c)-space into the corresponding boolean expressions and moves in (p,q,r)-space. If this can be done in terms of the there permissible operations, we have been successful. The transformation suggested is indeed adequate and the following program is the result (the variable h has been introduced for a very local optimization):

| p, q, r:=0, 1, n; do q≤ n → q:= q * 4 od
| do q ≠ 1 → q:= q / 4; h:= p + q; p:=p / 2 {h = 2 * p + q};
|  | if r ≥ h → p, r:=p + q, r - h
|  |  | ▯ r < h → skip
|  | fi
| od {p has the value desired for a}

This fifth example has been included because it relates —in an embellished form— a true design history. When the youngest of our two dogs was only a few months old I walked with both of them one evening, preparing my lectures for the next morning, when I would have to address students with only a few weeks exposure to programming, and I wanted a simple problem such that I could “massage” the solutions. During that one hour walk the first, third and fourth program were developed in that order, but for the fact that the correct introduction of h in the last program was something I could only manage with the aid of pencil and paper after I had returned home. The second program, the one manipulating a and b , which here has been presented as a stepping stone to our third solution, was only discovered a few weeks later —be it in a less elegant form then presented here. A second reason for its inclusion is the relation between the third and the fourth program: with respect to the latter one the other one represents our first example of so-called representational abstraction.

Sixth example.

For fixed X (X > 1) and Y (Y ≥ 0) the program should establish

R: | z = XY

under the —obvious— assumption that exponentiation is not among the available repertoire. This problem can be solved with the aid of an “abstract variable” , h say; we shall do it with a loop, for which the invariant relation is

P: | h * z = XY

and our (equally “abstract”) program could be

| h, z:= XY , 1 {P has been established};
| do h ≠ 1 → squeeze h under invariance of P od
| {R has been established}

The last conclusion is justified because (P and h = 1) ⇒ R . The above program will terminate under the assumption that a finite number of applications of the operation “squeeze” will have established h = 1. The problem, of course, is that we are not allowed to represent the value of h by that of a concrete variable directly manipulated by the machine: if we were allowed to do that, we could have assigned the value of XY immediately to z , not bothering about introducing h at all. The trick is that we can introduce two —at this level concrete— variables, x and y say, to represent the current value of h and our first assignment suggests as convention for this representation

| h = xy

The condition “h ≠ 1” then translates into “y ≠ 0” and our next task is to discover an implementable operation “squeeze”. Because the product h * z must remain invariant under squeezing, we should divide h by the same value by which z is multiplied. In view of the way in which h is represented, the current value of x is the most natural candidate. Without any further problems we arrive at the translation of our abstract program

| x, y, z:= X, Y, 1{P has been established};
| do y ≠ 0 → y, z:= y - 1, z * x {P has not been destroyed} od
| {R has been established} .

Looking at this program we realize that the number of times control goes through the loop equals the original value Y and we can ask ourselves whether we can speed things up. Well, the guarded command has now the task to bring y down to zero: without changing the value of h , we can investigate whether we can change the representation of that value, in the hope of decreasing the value of y . We are just going to try to exploit that the concrete representation of a value of h as given by xy is by no means unique. If y is even we can halve y and square x, and this will not change h at all. Just before the squeezing operation we insert the transformation towards the most attractive representation of h and here is the next program:

| x, y, z:= X, Y, 1;
| do y ≠ 0 → do y|2 → x, y:= x * x, y / 2 od;
|  | y, z:= y - 1, z * x
| od {R has been established}

There exists one value that can be halved indefinitely without becoming odd and that is the value 0, in other words: the outer guard ensures that the inner repetition terminates.

I have included this example for various reasons. The discovery that a mere insertion of what on the abstract level acts like an empty statement could change an algorithm invoking a number of operations proportional to Y into one invoking a number of operations only proportional to log(Y) startled me when I made it. This discovery was a direct consequence of my forcing myself to think in terms of a single abstract variable. The exponentiation program I knew was the following:

| x, y, z:= X, Y, 1;
| do y ≠ 0 → if non y|2 → y, z:= y - 1, z * x ▯ y|2 → skip fi
|  | x, y:= x * x, y / 2
| od

This latter program is very well known, it is a program that many of us have discovered independently of each other. Because the last squaring of x when y has reached the value 0 is clearly superfluous, this program has often been cited as supporting the need for what were called “intermediate exits”. in view of our second program I come to the conclusion that this support in weak.

Seventh example,

For a fixed value of n (n ≥ 0) a function f(i) is given for 0 ≤ i < N . Assign to the boolean variable “allsix” the value such that eventually

R: | allsix = (A i: 0 ≤ i < n: f(i) = 6)

holds. (This example shows some similarity to the Second Example of this chapter. Note, however, that in this example, n = 0 is allowed as well. In that case the range for i for the all-quantifier “A” is empty and allsix = true should hold.) Analogous to what we did in the second Example the invariant relation

P: | (allsix = (A i: 0 ≤ i < n: f(i) = 6)) and 0 ≤ j ≤ n

suggests itself, because it is easily established for j = 0 , while (P and i = n) ⇒ R . The only thing to do is to investigate how to increase j under invariance of P . We therefore derive

| wp(“j:=j +1”. P) =
| (allsix = (A i: 0 ≤ i < j + 1: f(i)=6)) and 0 ≤ j + 1 ≤ n .

The last term is implied by P and j ≠ m ; it presents no problem because we had already decided that j ≠ n as a guard is weak enough to conclude R upon termination. The weakest pre-condition that the assignment

| allsix;:= allsix and f(j) = 6

will establish the other term is

| (allsix and f(j) = 6) = (A i: 0 ≤ i < j + 1: f(i) = 6) .

a condition that is implied by P. We thus arrive at the program

| allsix, j:= true, 0;
| do j ≠ n → allsix:= allsix and f(j) = 6;
|  | j:= j + 1
| od

(In the guarded command we have not used the concurrent assignment for no particular reason.)

By the time that we read this program —or perhaps already earlier— we should get the uneasy feeling that as soon as a function value ≠ 6 has been found, there is not much point in going on. And indeed, although (P and j = n) ⇒ R , we could have used the weaker

| (P and (j = n or non allsix)) ⇒ R

leading to the stronger guard “j ≠ n and allsix” and to the program

| allsix, j:= true, 0;
| do j ≠ n and allsix → allsix, j:= f(j) = 6, j + 1 od .

(Note the simplification of the assignment to allsix , a simplification that is justified by the stronger guard.)

Exercise. Give for the same problem the correctness proof for

| if n = 0 → allsix:= true
| ▯ n > 0 → j:= 0;
|  | do j ≠ n - 1 and f(j) = 6 → j:= j + 1 od
|  | allsix:= f(j) = 6
| fi

and also for the still more tricky program (that does away with the need to invoke the function from more than one place in the program)

| j:= 0;
| do j ≠ n cand f(j) = 6 → j:= j + 1 od
| allsix:= j = n

(Here the condition conjunction operator “cand” has been used in order to do justice to the fact that f(n) need not be defined.) The last program is one, that some people like very much.

Eighth example.

Before I can state our next problem, I must first give some definitions and a theorem. Let p = (p₀, p₁, ... , pn-1) be a permutation of n (n > 1) different values pi (0 ≤ i < n), i.e. (i ≠ j) ⇒ (Pi ≠ Pj) . Let q = (q₀, q₁, ... , qn-1) be a different permutation of the same set of n values. By definition “permutation p precedes q in the alphabetic order” if and only if for the minimum value of k such that pk ≠ qk we have pk < qk .

The so-called “alphabetic indexn” of a permutation of n different values is the ordinal number given to it when we number the n! possible permutation arranged in alphabetic order from 0 through n!-1 For instance, for n = 3 and the set of values 2, 4 and 7 we have

| index₃(2, 4, 7) = 0
| index₃(2, 7, 4) = 1
| index₃(4, 2, 7) = 2
| index₃(4, 7, 2) = 3
| index₃(7, 2, 4) = 4
| index₃(7, 4, 2) = 5

Let (p₀� p₁� ... �pn) denote the permutation of the n different values in monotonicly increasing order, i.e. indexn((p₀� p₁� ... �pn)) = 0. (For example (4� 7� 2) = (2, 4, 7) but also (7� 2� 4) = (2, 4, 7) .)

With the above notation we can formulate the following theorem for n > 1:

| indexn(p₀, p₁, ..., pn-1) =
| indexn(p₀,(p₁� p₂� ... �pn-1)) + indexn(p₁, p₂, ..., pn-1)

(e.g. index₃(4, 7, 2) = index₃(4, 2, 7) + index₂(7, 2) = 2 + 1 = 3 .) In words: the indexn of a permutation of n different values is the indexn of the alphabeticaly first one with the same leftmost value increased by the indexn-1 of the permutation of the remaining rightmost n-1 values.
As a corrolary: from

| pn-k < pn-k+1 < ... < pn-1

follows that indexn(p₀, p₁, ... , pn-1 ) is a multiple of k! and vice versa .

After these preliminaries we can describe our problem. We have a row of n positions (n > 1) numbered in the order from left to right from 0 through n-1 ; in each position lies a card with a value written on it such that no two different cards show the same value.

When at any moment ci (0 ≤ i < n) denotes the value on the card in position i , we have initially

| c0 < c₁ < ... < cn-1

(i.e. the cards lie sorted in the order of increasing value). For given value of r (0 ≤ r < n!) we have to rearrange the cards such that in the

R: | indexn(c₀, c₁, ... , cn-1) = r .

the only way in which our mechanism can interfere with the cards is via the execution of the statement

| cardswap(i, j) with 0 ≤ i, j < n

that will interchange the cards in positions i and j if i ≠ j (and will do nothing if i = j).

In order to perform this transformation we must find a class of states —all satisfying a suitable condition P1— such that both initial and final states are specific instances of that class. Introducing a new variable, s say, an obvious candidate for P1 is

| indexn(c₀, c₁, ... , cn-1) = s

as this is easily established initially (viz. by “s:= 0”) and (P1 and s = r) ⇒ R .

Again we ask, whether we can think of restricting the range of s and in view of its initial value we might try

P1: | indexn(c₀, c₁, ... , cn-1) = s and 0 ≤ s ≤ r

which would lead to a program of the form

| s:= 0 {P1 has been established};
| do s ≠ r → {P1 and s < r}
|  | increase s by a suitable amount under
|  | invariance of P1 {P1 still holds}
| od {R has been established}

Our next concern is, what to choose for “a suitable amount”. Because our increase of s must be accompanied by a reaarngement of the cards in order to keep P1 invariant, it seems wise to investigate whether we can find conditions, under which a single cardswap corresponds to a known increase of s . Let for a value of k satisfying 1 ≤ k < n hold

| cn-k < cn-k+1 < ... < cn-1 ;

this assumption is equivalent with the assumption k!|s —read: “k! divides s”—. Let i = n-k-1 , i.e. ci is the value on the card to the immediate left of this sequence. Let furthermore ci < cn-1 and let cj be for j in the range n-k ≤ j < n the minimum value such that ci < cj (i.e. cj is the smallest value to the right of ci exceeding the latter). In that case the operation cardswap(i, j) leaves the rightmost k values in the same monotonic order and our theorem about permutations and their indices tells us that k! is the corresponding increase of s. It also tells us that when besides k!|s we have

| s ≤ r < s + k!

c₀ through cn-k-1 have attained their final value.

I therefore suggest to strengthen our original invariant relation P1 with the additional relation P2 —fixing the function of a new variable k —

P2: | 1 ≤ k ≤ n and k!|s and r < s + k!

which means that the rightmost k cards show still monotonicly increasing values, while the leftmost n-k cards are in their final positions: we have decided upon the “major steps” in which we shall walk towards our destination.

In order to find “the suitable amount” for a major step the machine first determines the largest smaller value of k for which r < s + k! no longer holds — ci with i = n-k-1 is then too small, but to the left of it they are all OK— and then increase s by the minimum multiple of k! needed to make r < s + k! hold again; this is done in “minor steps” of k! at a time, simultaneously increasing c, with cards to the right of it. In the following program we introduce the additional variable kfac , satisfying

P3: | kfac = k!

and for the second inner repetition i and j , such that i = n-k-1 and either j = n or i < j < n and cj > ci and cj-1 < ci .

| s:= 0 {P1 has been established};
| kfac, k: 1, 1 {P3 has been established as well};
| do k ≠ n → kfac, k:= kfac *(k+1), k+1 od
|  |  |  | {P2 has been established as well};
| do s ≠ r → {s < r, i.e, at least one, and therefore
|  |  |  |  | at least two cards have not reached their
|  |  |  |  | final position}
|  |  | do r < s + kfac → kfac, k:= kfac / k, k - 1 od
|  |  |  |  | {P1 and P3 have been kept true, but in P2
|  |  |  |  | the last term is replaced by
|  |  |  |  | s + kfac < r < s + (k + 1)* kfac};
|  |  | i, j:= n - k - 1, n - k;
|  |  | do s + kfac ≤ r → {n - k ≤ j < n}
|  |  |  |  |  | s:= s + kfac; cardswap(i, j); j:= j + 1
|  |  | od {P2 has been restored again: P1 and P2 and P3}
|  | od {R has been established}

Exercise. Convince yourself of the fact that also the following rather similar program would have done the job:

| s:= 0; kfac, k:=1, 1;
| do k ≠ n → kfac, k:= kfac *(k +1), k +1 od;
| od k ≠ 1 →
|  | kfac, k:= kfac / k, k - 1;
|  | i, j:= n - k - 1, n - k;
|  | do s + kfac ≤ r →
|  |  | s:= s + kfac; cardswap(i, j); j:= j +1
|  | od
| od

(Hint: the monotonicly decreasing function t ≥ 0 for the outer repetition is t = r - s + k - 1 .)

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD415

A beautiful proof of a probably useless theorem

by
Edsger W.Dijkstra and W.H.J.Feijen

Let a positive continuous function be defined on the Euclidean plane, such that its integral taken over the whole plane is finite, say = 1. Then there exists a set of rectangular axes such that the four integrals of the function, taken over the four quadrants respectively, are all equal to each other.

For a fixed orientation of the cross we can first move it in a direction perpendicular to one axis, such that eventually the surface integrals taken over the half planes at both sides of that one axis are equal to each other, a state of affairs that is not destroyed by moving thereafter the cross in a direction perpendicular to the other axis until also for that other axis the surface integrals at both sides are equal to each other. Such a so-called "balanced position" always exists and is uniquely determined by the orientation of the cross because the function integrated is positive. In a balanced position the surface integrals taken over opposite quadrants are equal: if they are both ¼ + α, then the other two must each be ¼ - α.

While keeping the relation "the cross is in a balanced position" invariant, the cross is now slowly rotated. The continuously changing value of the surface integral, taken over the quadrant encompassed by two chosen half-axes, that was originally = ¼ + α, must have been at least once = ¼ before we have rotated the cross over more than a right angle, for after a rotation over a right angle the cross has returned to its original balanced position, in which the continuously observed surface integral has the value ¼ - α.

dr.Edsger W.Dijkstra
BURROUGHS
Plataanstraat 5
NUENEN - 4565
The Netherlands
ir.W.H.J.Feijen
Department of Mathematics
Technological University
P.O.Box 513
Eindhoven
The Netherlands

transcribed by Alejandro Ruiz
revised Wed, 12 Nov 2008

EWD416

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On avoiding the infinite.

This chapter should be skipped by most of my readers: it should be skipped by all those that could not care less, it should also be skipped by all dyed-in-the-wool logicians, who probably care too much. Its inclusion is the consequence of a few piercing remarks made by John C. Reynolds in earlier correspondence between him and me. It goes without saying that he is in no way to be held responsible for the following exposition, which, I am sure, is somewhat shaky anyhow.

With respect to modelling what computers can do for us, there are two extremist views.

The one view stresses the fact that computer stores have only a finite capacity and that therefore our machines can be regarded as a finite state automaton. This has as a consequence that if the computation proceeds without terminating , it must return within a finite number of steps in a state in which it has been before. If the machine is fully deterministic, history will from then onwards repeat itself, and the computation will therefore never terminate. If the machine is non-deterministic in the sense as we have introduced non-determinacy —i.e. that in some states there is a choice between a finite number of alternatives— the situation is more complicated. We may have states where the machine will never terminate, we may have states where the machine will certainly terminate and we may have states where the machine may terminate after an a priori unbounded number of steps. In a machine with two boolean variables “stop” and “go on” we can investigate the following program:

| do go on → skip
|  | ▯ non stop → skip
|  | ▯ non stop → stop:= true
| od

If “go on” is true, it will remain so and proper termination is excluded. If “go on” is false, we have to distinguish between two cases: if “stop” is true, termination is ensured, if, however, “stop” is false, the nondeterminacy leaves the choice between the second and the third guarded command open. As long as the third guarded command is not selected, “stop” remains false and the second command may be selected an unbounded number of times: termination is not guaranteed but it remains possible.

The other view stresses that, although the number of states of a modern computer is indeed finite, it is in practice so incredibly large that the remark that the deterministic machine is bound to start cycling is rather irrelevant, because the length of most cycles is such that we could never live long enough to see the machine perform such a cycle. The freedom to forget about the fact that we can only distinguish between a finite number of different states is then immediately exploited by introducing variables of type integer whose range —all whole numbers— is clearly infinite. In our previous examples we have very clearly done so. How does this model, however, relate to what can take place in our admittedly finite computers?

The extremists with the second point of view forget that nobody but the Good Lord could make such a machine —and that up till now He has failed to do so!— and have made it a subject of intensive study, to the extent that they have pondered about what it could do when we would set it in motion from now until eternity. As soon as one starts asking oneself such questions, however, its infinite size is no longer only a luxury but also creates problems, problems we should like to avoid. In this monograph we try to steer a middle course between the Scylla of the finite constraints and the Charybdis of the unfathomed infinite. We shall try to come away with just enough theory for dealing with the behaviour of the unlimited machines only for initial states such that proper termination is guaranteed.

Let us first restrict ourselves to the simpler case that the unlimited machine is fully deterministic. In each initial state activation of our machine will then give rise to a unique happening; if that happening terminates after a finite number of computational steps have taken place, a finite number of integer values have been manipulated and therefore their maximum absolute value had a unique lowest upper bound. We repeat that that lowest upper bound is uniquely determined by the initial state. For that initial state we apparently did not need our unlimited machine! The computation could have been done by a machine of finite size, and even stronger: we —or at least the Good Lord— could decide upon a sufficient size a priori.

The critical step in the above reasoning is that the knowledge of an upper bound for the number of computational steps allows us to conclude an upper bound for the maximum absolute value of integers to be catered for. Let us now consider a non-deterministic machine and the class of of possible happenings that may take place when we activate it in an initial state such that only properly terminating computations can ensue. Each individual computation of that class will only manipulate a finite number of values, but if the class of possible computations is infinite, a maximum abolute value manipulated is no longer necessarily bounded. That would be nasty and we should try to convince ourselves that the form of non-determinacy we have introduced is so mild, that infinity of the class of possible computations when termination is guaranteed, is excluded. Luckily we can, it the if ... fi- and the do ... od-constructs are our only source for non-determinacy. Firstly each guarded command list contains a fixed and finite number of alternatives. Secondly the a priori upper bound on the number of computational steps implies an upper bound on the number of times the non-deterministic choice can be made. From these two considerations it follows that the form of non-determinacy we have introduced is aptly described as “bounded non-determinacy”. As a result also in the case of our bounded non-determinacy, we —or again at least the Good Lord— could for each initial state decide a priori upon a sufficient size of a finite machine that could do the job.

The moral of the story is that a bounded number of computational steps and bounded non-determinacy together imply that the number of possible happenings and the maximum value possibly manipulated are both bounded as well.

The fact that the non-determinacy is bounded is very intimately tied to the guarded commands. For not only do they not introduce unbounded non-determinacy as we have seen, but also in the presence of unbounded non-determinacy —supplied by some other magical means— the semantic definition of the repetitive construct would be subject to doubt, to say the least.

Suppose that we have a non-deterministic primitive

| “set x to any positive value”

and consider now the program

S: | do x > 0 → x:= x - 1
|  ▯ x < 0 → set x to any positive value od

I expect most readers to agree that, no matter what initial value of x , this program will terminate sooner or later with x = 0 . If initially x ≥ 0, then we know a priori the number of steps (viz. the initial value of x ); it initially x < 0, we don’t, but yet we have the feeling that it must terminate because then the second alternative will be chosen and after its successful execution, x will have some positive value that will be brought down to zero in a finite number of steps. As we shall see, the crux can be pinned down to the proviso “after its successful execution”.

Our formalism, however, gives for Hk(T) —the weakest pre-condition such that the construct terminates after at most k steps—:

| Hk(T) = 0 ≤ x ≤ k)

and

| wp(DO, T) = (E k: k ≥ 0: hk(T))
|  | = (E k: k ≥ 0: 0 ≤ x ≤ k)
|  | = (0 ≤ x)

The inability to give for any negative x a priori an upper bound for the number of steps needed is translated into “for negative x termination is not guaranteed”. Have we failed?

That we have not can been seen by considering a possible implementation for set x to any positive value, e.g.

| go on:= true; x:= 1;
| do go on → x:= x + 1
|  | ▯ go on → go on:= false
| od .

This construct will continue to increase x as long as the first alternative is chosen; as soon as the second alternative has been chosen once, it terminates immediately. Upon termination x may indeed be “any positive value” in the sense that we cannot think of a positive value X such that termination with x = X is impossible. However, termination is not guaranteed either! If we substitute our implementation for “set x to any positive value” we get

| do x > 0 → x:= x -1
|  | ▯ x < 0 → go on:= true; x:= 1;
|  |  | do go on → x:= x + 1
|  |  |  | ▯ go on → go on:= false
|  |  | od
| od

Now it is fully correct not to guarantee termination for initial states with x < 0 , but not so much because we cannot say a priori how many steps the outer cycle will take, but because we cannot guarantee termination for the subprocess that would decide upon that number of steps: we cannot guarantee termination for the process that is expected to increase x to an unbounded value! If it is expected to increase x possibly beyond any bound, we must also accept that it will go on for an arbitrarily long time, even forever.

There is still another reason for wanting to avoid unbounded nondeterminacy. The repetitive construct gives rise to a weakest pre-condition of the form

| (E k: k ≥ hk)

where

| for k ≥ 0: Hk ⇒ Hk+1 for all states

(This implication is intuitively clear from our interpretation “... after at most k executions of a guarded command”; formally it is easily proved by mathematical induction.) Such a condition might easily occur as postcondition for another statement, S say, and then we would like that

| wp(S,(E k: k ≥ 0: Hk)) = (E n: n ≥ 0: wp(s, Hn)) . | (1)

For a statement S with unbounded non-determinacy, however, this equality does not necessarily hold, as is shown by the example

| Hk: | 0 ≤ x ≤ k
| S: | set X to any positive value

Relation (1) does hold, however, under the assumption that the non-determinacy of S is bounded. In order to prove (1), we prove that for all states each side of (1) implies the other.

Consider an initial state such that the righthand side of (1) is true, i.e. there exists a value N such that in this initial state

| wp(S, HN)

holds. Because

| HN ⇒ (E k: k ≥ 0: Hk) for all states

we may conclude that

| wp(s, HN) ⇒ wp(S, (E k: k ≥ 0: Hk)) for all states

and therefore in the initial state considered the lefthand side of (1) must be true as well. We have proved that the righthand side of (1) implies the lefthand side of (1) in all states without an appeal on the bound on the non-determinacy; we need this bound to prove the implication the other way round.

Consider an initial state such that

| wp(s, (E k: k ≥ 0: Hk)) ;

for such an initial state we guarantee termination in a bounded set of final states, each of them satisfying

| (E k: k ≥ 0: Hk) ;

because each Hk implies all its successors, for each of these final states there is a minimum value kmin, such that

| (A k: k ≥ kmin: Hk) .

Because the set of possible final states is bounded, the set of kmin-values is bounded and there is a maximum kmin-value, K say. As a result, our initial state satisfies

| wp(S, HK)

and as

| wp(S, HK) ⇒ (E n: n ≥ 0: wp(S, Hn))

the implication has been proved in the other direction as well. Relation (1) has been proved for all states.

As a consequence we can prove —with the usual meanings of EB, IF and DO — that

| (BB and wp(DO, R)) = wp(IF, wp(DO, R))

for wp(IF, wp(DO, R)) = wp(IF, (E k: k ≥ 0: Hk(R)))

| = (E n: n ≥ 0: wp(IF, Hn(R)))

(and because

| H₀(R) ⇒ non BB and for any P we have wp(IF, P) ⇒ BE )
|  | = BB and (E n: n ≥ 0: wp(IF, Hn(R)) or H₀(R))
|  | = BB and (E k: k ≥ 1: Hk(R))
|  | = BB and wp(DO, R) .

In other words, in all initial states such that EB holds

| do b₁ → SL₁ ▯ B₂ ⇒ SL₂ ▯ ... ▯ Bn ⇒ SLn od | (2)

is equivalent to

| if b₁ → SL₁ ▯ B₂ ⇒ SL₂ ▯ ... ▯ Bn ⇒ SLn fi |
| do b₁ → SL₁ ▯ B₂ ⇒ SL₂ ▯ ... ▯ Bn ⇒ SLn od | (3)

In initial states where BB does not hold, program (2) would have acted as “skip”, while program (3) would have acted as “abort”.

I find it somewhat disconcerting that so much has been involved in the formal proof of the partial equivalence of (2) and (3), the more so because this partial equivalence is intuitively so obvious. On the other hand it gives some confidence that it can be done. At the beginning of this chapter I have suggested that the majority of my readers should skip this chapter; at its end I express the hope that the few that have studied it will appreciate its inclusion.

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD417

On the abolishment of the subscripted variable.

(The following is written after discussions with C.Ligtmans, W.H.J.Feijen, M.Rem and C.S.Scholten, while during the first part A.Martin is looking over my shoulder.)

I have been trained to regard an array in the ALGOL 60 sense as a finite set of elementary variables, whose "identifiers" could be "computed". For two reasons this view does not satisfy me anymore and now I prefer to regard an array as a single variable.

The one reason is to be found in my abhorrence for variables whose values are undefined, a state of affairs caused by the simultaneous introduction of all local variables upon block entry, possibly long before they are actually needed. Two would-be remedies have been suggested (and implemented) many times. The one suggestion is to extend the original range with an additional value "undefined" or "nil"; this is the kind of remedy that pure mathematicians tend to invent, but it leads to all sorts of conflicts, exceptions and logical patches. If one decides on a case of bigamy when two different persons have the same spouse, what about two bachelors, married to the same "nobody"? The other suggestion is to allow initialization and, if not specified, by default a normal value will be assigned (say "0" for an integer and "true" for a boolean variable); the one that follows the second suggestion fools himself even worse, because he has even lost himself the possibility of a run-time check for a common programming error. In the case of scalar variables a meaningful initialization is no problem if the variables are only introduced when needed; with a set of adequate sequencing primitives there need be no problem in saving the static scope concept: at each semicolon there need not exist any doubt as to which variables together build up the current state space and the common programming error referred to above can be caught mechanically prior to execution. This solution breaks down, however, in the case of arrays regarded as a large collection of elementary variables.

The second reason is of a combinatorial nature and more fundamental. In ALGOL 60 the compound statement that causes the variables x and y to interchange their values needs an additional variable, h say:

h:= x; x:= y; y:= h

which is cumbersome and ugly compared to the concurrent assignment

x, y:= y, x .

A requirement of the concurrent assignment is of course that the variables on the left-hand side are all different: no one should care to give "x, x:= 1, 2" a meaning (different from "error"). For a long time I hesitated to adopt the concurrent assignment on account of the problems it causes in a case like

a[i], a[j]:= x, y .

Should it be allowed when i ≠ j, but never when i = j? Or is it permissible in the latter case also when x = y? What about

a[i], a[j]:= a[j], a[i] ?

Clearly we are piling one complication upon another. However, I have now come to the conclusion that it is not the concurrent assignment but the notion of the subscripted variable that is to be blamed. In the axiomatic definition of the assignment statement via "substitution for a variable" —as in, I guess, all parts of logic— one cannot afford uncertainty as to whether two variables are "the same" or not.

We can regard a variable of type "integer" as an integer-valued function without arguments —and therefore with a domain consisting of a single anonymous point—,a function that does not change unless explicitly changed (usually by means of an assignment).

Restricting ourselves to the analogon of a one-dimensional array, we can similarly regard a variable of type "integer array" as an integer-valued function with one argument with a domain in the integers —a function, again, that does not change unless explicitly changed.

We now take the view that we shall only admit types such as that an algorithm can establish whether the values of two variables of the same type are equal or not. In the case of integer variables x and y this can be done by the boolean expression x = y, i.e. both functions x and y are evaluated in the only point of their domain and these values are compared.

Given two variables of type "integer array" their values are equal if, as functions, they have the same domain and in each point of the domain they both take the same value. In order to be able to perform these comparisons, we must restrict ourselves to finite domains and it must be possible to extract from the current value of an array variable the currently corresponding domain. For practical purposes we propose to restrict ourselves to domains consisting of consecutive integers.

If "av" is the name of an array variable, I assume a number of functions of its value and operations upon its value defined. They will be denoted by the identifier of the array variable, a dot, and then a reserved name. Unable to make my choice, I have introduced more than the minimum.

Depending on the domain only are the integer functions "av.size", "av.first" and "av.last"; they will always satisfy

av.size ≥ 0 and av.last - av.first = av.size - 1 .

The corresponding domain for the function av(k) is given by

av.first ≤ k ≤ av.last .

The expression "av(k)" —which could be regarded as a special purpose abbreviation for "av.val(k)", a kind of abbreviation one can introduce just once!— is regarded as any other function call with an integer argument transmitted by value: the argument needs only to be defined and within the domain when the evaluation av(k) is actually required.

As stated above, a scalar variable can be regarded as a function (without arguments) that can be changed by assignment. Similarly we need operations to change the value of an array variable. For practical reasons I do not consider "assignment" of an arbitrary value to an array variable as a primitive operation: if the domain is large this can be a very costly operation. I therefore prefer array values being built up sequentially by "slight modifications".

Slight modifications are extending the domain by one, at either the "high" or the "low" end: in both cases av.size is increased by 1. With the extension at the high end av.last is increased by 1, with extension at the low end av.first is decreased by 1. For the argument value added to the domain, a value must be supplied simultaneously, it is really the well-known push-operation and with "x" an expression of the appropriate type we could write "av.hipush(x)" and "av.lopush(x)"; on the intersection of the old and the new domain the value of the function av will be left unaltered. Similarly, with initially av.size > 0 and x a variable of the appropriate type, we can envisage the inverse operations "av.hipop(x)" and "av.lopop(x)".

A further domain changing operation I envisage is a translation, say "av.trans(k)", which increases av.first and av.last both by k and leaves 0 ≤ i < av.size the value of av(av.first + i) unchanged.

The next thing is assignment. Conceptually there is no problem with an assignment of the form av1:= av2, but if that operation is included it should not look so innocent, and something like "av.ass(av2)" is already much better. The kind of assignment I am wiling to write down with ":=" are the ones in which the final size is small because the function values must be enumerated at the right-hand side; I could live with a format of the form

av:= (0: 0, 1, 2, 3)

which defines av.first = 0, av.last = 3, av.size = 4 and av(i) = i for 0 ≤ i < 4. Perhaps even this is already too ambitious and should the right-hand side be restricted to values with size = 0. Note that in this proposal even the empty domain "has a place": first and last are always defined: we need this for the operation hipush and lopush to be defined. The same values that are allowed in the assignment are allowed in the obligatory initialization.

The remaining operations to be discussed are the ones that modify the value of av without changing its domain. An obvious candidate is altering just one of the function values: the analogon of the well-known assignment to the subscripted variable av[k]:= E; in order to avoid confusion I propose a radically different notation for altering just one function value, say "av.alt(k, E)" in order to do justice to our considerations that we change the whole function, a modification that requires two value parameters.

Another operation that I have learned to consider as "fundamental" —whatever that may mean— is "av.swap(i, j)". Both arguments must lie in the current domain; if they are equal, it is the empty operation, otherwise the function values av(i) and av(j) are interchanged.

Note. It is unwise to regard the swap as a special case of a cyclic rotation over one place in a cycle of length n with n = 2. Let us not introduce —with a variable number of parameters!— av.rot(i, j, k) say: first of all no one would be able to remember in which direction the values would be shifted cyclically, secondly the difficulties when not all arguments are different —an awkward test, by the way!— are just terrible. It is the total absence of these difficulties that justifies the view of "swap" as a fundamental primitive.

Finally, what about the declaration, what about our old "subscript bounds"? The implied "bound checking" in av(k), av.alt(k, E) and av.swap(i, j) is of course with respect to the current value of the domain, it is the test av.first ≤ k, i, j ≤ av.last. For reasons of storage reservation we can still think of supplying a lower and an upper bound as part of the declaration; they are no more than a lower bound for av.first and an upper bound for av.last respectively. Alternatively, we could give an upper bound for av.size. I can think of

a)    no bounds given
b)    a lower bound for first
c)    an upper bound for last
d)    the combination of b) and c)
e)    an upper bound for size.

We recognize the unrestricted stacks and the cyclic buffer of limited capacity.

The drastic difference between these bounds and the old array concept of ALGOL 60 is the following (if I understand the ALGOL 60 array and the notion of type correctly). In ALGOL 60 I have always viewed the bounds as a constant attribute of the array, just as constant as "the type of a variable". From that point of view the one-dimensional integer arrays of ALGOL 60 provide for infinity² different "types": viz. as many different types as we can define different bound-pairs.

Here it is proposed that all one-dimensional integer arrays are array variables of exactly the same type, while bounds possibly given in the declaration are regarded as hints to the implementation, hints the implementation may exploit or ignore. They are regarded as more than just a hint, they are also a permission —but not an obligation!— to abort when the domain exceeds the stated limitations. The bounds when stated in the declaration are not an aspect of the value of the array variable.

The above seems clean and sound. I would welcome comments very much, comments on various levels. It may seem clean and sound, yet there may be logical difficulties hidden somewhere that I have not seen; if someone finds one, I would be immensely grateful. Also comments on notations and names would be very welcome. (It took me very long to find something for the name "alt" which was eventually suggested by Feijen; and to say that I am proud of my "hipush" and "lopop" would violate the truth.)

Use of the dot in this way —it is the first time I do it myself— is something with which I have reasonable confidence: it gives us the possibility for the introduction of "restrictedly reserved identifiers". I did not state any scope rules, but the idea is that the fact that av is of type "integer array" makes av.swap identify the operation it should identify. With the dot-notation we can make the post-dot identifiers subordinate to the type of the pre-dot identifier. If av1 is of type integer array, and av2 is of type boolean array, there is yet no "polymorphism" (I think it is called) involved when we compare av1.val(k) and av2.val(k): the one val is an integer function, the other val is a boolean function. Clearer perhaps is the comparison of av1.swap(i, j) and swap(av2, i, j), where according to common interpretation these would be regarded as two calls of the same library procedure. As said, I have a reasonable confidence in this use of the dot-notation, but any warning for its pitfalls is welcome.

Burroughs
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

20th March 1974

transcribed by Tristram Brelstaff
revised Fri, 16 Jul 2010

EWD418

Guarded commands. non-determinacy and a calculus for the derivation of programs.

by Edsger W.Dijkstra *)

*) Author's address: | BURROUGHS
| Plataanstraat 5
| NUENEN – 4565
| The Netherlands.

Abstract. So-called "guarded commands" are introduced as a building block for alternative and repetitive constructs that allow non-deterministic program components for which at least the activity evoked, but possibly even the final state, is not necessarily uniquely determined by the initial state. For the formal derivation of programs expressed in terms of these constructs, a calculus will be shown.

Keywords. programming languages, sequencing primitives, program semantics, programming language semantics, non-determinacy, case-construction. repetition, termination, correctness proof, derivation of programs, programming methodology.

CR-category: 4.20, 4.22.

Guarded commands, non-determinacy and a calculus for the derivation of programs.

1. Introduction.

In section 2, two statements, an alternative construct and a repetitive construct will be introduced, together with an intuitive (mechanistic) definition of their semantics. The basic building block for both of them is the so-called "guarded command", a statement list prefixed by a boolean expression: only when this boolean expression is initially true, is the statement list eligible for execution. The potential non-determinacy allows us to map otherwise (trivially) different programs on the same program text, a circumstance that seems largely responsible for the fact that now programs can be derived in a more systematic manner than before.

In section 3, after a prelude defining the notation, a formal definition of the semantics of the two constructs will be given, together with two theorems for each of the constructs (without proof).

In section 4, it will be shown how upon the above a formal calculus for the derivation of programs can be founded. We would like to stress that we do not present "an algorithm" for the derivation of programs: we have used the term "a calculus" for a formal discipline --a set of rules-- such that, if applied successfully
1 ) it will have derived a correct program
2) it will tell us that we have reached such a goal.
(In choosing the term "calculus" we have been inspired by the "integral calculus" and the "propositional calculus" where we have a very similar situation.)

2. Two statements made from guarded commands.

If the reader accepts "other statements" as indicating, say, assignment statements and procedure calls. we can give the relevant syntax in BNF [2]. In the following we have extended BNF with the convention that the braces "{...}" should be read as: "followed by zero or more instances of the enclosed".

〈 guarded command〉 ::= 〈 guard〉 → 〈 guarded list〉
〈 guard〉 ::= 〈 boolean expression〉
〈 guarded list〉 ::= 〈 statement〉 {; 〈 statement 〉}
〈 guarded command set〉 ::= 〈 guarded command〉 {▯ 〈 guarded command 〉}
〈 alternative construct〉 ::= if 〈 guarded command set〉 fi
〈 repetitive construct 〉 ::= do 〈 guarded command set〉 od
〈 statement〉 ::= 〈 alternative construct〉 ∣ 〈 repetitive construct〉∣
                 "other statements"  .

The semicolons in the guarded list have the usual meaning: when the guarded list is selected for execution its statements will be executed successively in the order from left to right; a guarded list will only be selected for execution in a state such that its guard is true. Note that a guarded command by itself is not a statement: it is component of a guarded command set from which statements can be constructed. If the guarded command set consists of more than one guarded command, they are mutually separated by the separator "▯" ; our text is then an arbitrarily ordered enumeration of an unordered set. i.e. the order in which the guarded commands of a set appear in our text is semantically irrelevant.

Our syntax gives two ways for constructing a statement out of a guarded command set. The alternative construct is written by enclosing it by the special bracket pair: "if ... fi". If in the initial state none of the guards is true, the program will abort, otherwise an arbitrary guarded list with a true guard will be selected for execution.

Note. If the empty guarded command set were allowed "if fi" would be semantically equivalent to "abort" . (End of note.)

An example —illustrating the non-determinacy in a very modest fashion— would be the program that for fixed x and y assigns to m the maximum value of x and y :

if x ≥ y → m:= x
 ▯ y ≤ x → m:= y
fi

The repetitive construct is written down by enclosing a guarded command set by the special bracket pair "do ... od" . Here a state in which none of the guards is true will not lead to abortion but to proper termination; the complementary rule, however, is that it will only terminate in a state in which none of the guards is true: when initially or upon completed execution of a selected guarded list one or more guards are true, a new selection for execution of a guarded list with a true guard will take place. and so on. When the repetitive construct has terminated properly, we know that all its guards are false.

Note. If the empty guarded command set were allowed "do od" would be semantically equivalent to "skip" . (End of note.)

An example —showing the non-determinacy in somewhat greater glory— is the program that assigns to the variables q1, q2, q3 and q4 a permutation of the values Q1, Q2, Q3 and Q4, such that q1 ≤ q2 ≤ q3 ≤ q4 . Using concurrent assignment statements for the sake of convenience, we can program

q1, q2, q3, q4 := Q1, Q2, Q3, Q4;
do q1 > q2 → q1, q2 := q2, q1
 ▯ q2 > q3 → q2, q3 := q3, q2
 ▯ q3 > q4 → q3, q4 := q4, q3
od   .

To conclude this section we give a program where not only the computation but also the final state is not necessarily uniquely determined. The program should determine k such that for fixed value n (n > 0) and a fixed function f(i) defined for 0 ≤ i < n , k will eventually satisfy:

0 ≤ k < n and (∀i: 0 ≤ i < n: f(k) ≥ f(i))    .

(Eventually k should be the place of a maximum.)

k:=0; j:=1;
do j ≠ n → if f(j) ≤ f(k) → j:= j + 1
            ▯ f(j) ≥ f(k) → k:= j; j:= j + 1
           fi
od

Only permissible final states are possible and each permissible final state is possible.

3. Formal definition of the semantics.

3.1. Notational prelude.

In the following sections we shall use the symbols P , Q and R to denote (predicates defining) boolean functions defined on all points of the state space; alternatively we shall refer to them as "conditions", satisfied by all states for which the boolean function is true. Two special predicates that we denote by the reserved names "T" and "F" play a special role: T denotes the condition that, by definition, is satisfied by all states, F denotes, by definition, the condition that is satisfied by no state at all.

The way in which we use predicates (as a tool for defining sets of initial or final states) for the definition of the semantics of programming language constructs has been directly inspired by Hoare [1], the main difference being that we have tightened things up a bit: while Hoare introduces sufficient pre-conditions such that the mechanisms will not produce the wrong result (but may fail to terminate). we shall introduce necessary and sufficient —i.e. so-called "weakest"— pre-conditions such that the mechanisms are guaranteed to produce the right result.

More specifically: we shall use the notation "wp(S, R)" , where S denotes a statement list and R some condition on the state of the system, to denote the weakest pre-condition for the initial state of the system such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state satisfying the post-condition R . Such a "wp" —which is called a predicate transformer, because it associates a pre-condition to any post-condition R — has, by definition, the following properties.

1 ) For any S , we have for all states

wp(S, F) = F

(the so-called "Law of the Excluded Miracle").

2) For any S and any two post-conditions P and Q, such that for all states

P ⇒ Q

we have for all states

wp (S, P) ⇒ wp (S, Q)    .

3) For any S and any two post-conditions P and Q we have for all states

(wp(S, P) and wp(S, Q)) = wp(S, P and Q)  .

4) For any S and any two post-conditions P and Q we have for all states

(wp(S, P) or wp(S, Q)) ⇒ wp(S, P or Q)  .

Together with the rules of propositional calculus and the semantic definitions to be given below, the above four properties take over the role of the "rules of inference" as introduced by Hoare [1].

We take the position that we know the semantics of a mechanism S sufficiently well if we know its predicate transformer, i.e. can derive wp (S, R) for any post-condition R .

Note. This position is taken in full acknowledgement of the fact that in the case of non-deterministic mechanisms, the knowledge of the predicate transformer does not give a complete description: for those initial states that do not necessarily lead to a properly terminating activity, the knowledge of the predicate transformer does not give us any information about the final states in which the system might find itself after proper termination. (End of note.)

Example 1.     The semantics of the empty statement, denoted by "skip", are given by the definition that for any post-condition R , we have

wp("skip", R) = R  .

Example 2.    The semantics of the assignment statement "x:= E" are given by

wp("x:= E", R) = RxE

in which RxE denotes a copy of the predicate defining R in which each occurence of the variable "x" is replaced by "(E)".

Example 3.    The semantics of the semicolon ";" as concatenation operator are given by

wp("S1; S2", R) = wp(S1, wp(S2, R))  .

3.2. The alternative construct.

In order to define the semantics of the alternative construct we define two abbreviations.

Let "IF" denote

if B₁ → SL₁ ▯ ... ▯ Bn → SLn fi    ;

let "BB" denote

(∃i: 1 ≤ i ≤ n: Bi)    ;

then, by definition

wp(IF, R) = (BB and (∀i: 1 ≤ i ≤ n: Bi ⇒ wp(SLi, R))   .

(The first term "BB" requires that the alternative construct as such will not lead to abortion on account of all guards false, the second term requires that each guarded list eligible for execution will lead to an acceptable final state.) From this definition we can derive —by simple substitutions—

Theorem 1. From

(∀i: 1 ≤ i ≤ n: (Q and Bi) ⇒ wp(SLi, R)) for all states

we can conclude that

(Q and BB) ⇒ wp(IF, R) holds for all states .

Let "t" denote some integer function, defined on the state space, end let "wdec(S, t)" denote the weakest pre-condition such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state such that the value of t is decreased by at least 1 (compared to its initial value). In terms of "wdec" we can formulate the very similar

Theorem 2. From

(∀i: 1 ≤ i ≤ n: (Q and Bi) ⇒ wdec(SLi, t))   for all states

we can conclude that

(Q and BB) ⇒ wdec(IF, t)   holds for all states .

Note (which can be skipped at first reading). The relation between "wp" and "wdec" is as follows. For any point X in state space we can regard

wp(S, t ≤ t₀)

as an equation with t₀ as the unknown. Let its smallest solution for t₀ be tmin(X). (Here we have added the explicit dependence on the state X.) Then tmin(X) can be interpreted as the lowest upper bound for the final value of t if the mechanism S is activated with X as initial state. Then, by definition,

wdec(S, t) = (tmin(X) ≤ t(X) - 1) = (tmin(X) < t(X))    .

(End of note.)

3.3. The repetitive construct.

As is to be expected, the definition of the repetitive construct

do B₁ → SL₁ ▯ ... ▯ Bn → SLn od    ;

that we denote by "DO" , is more complicated.
Let

H₀(R) = (R and non BB)

and for k > 0: Hk(R) = (wp(IF, Hk-1(R)) or H₀(R))

(where "IF" denotes the same guarded command set enclosed by "if fi") then, by definition

wp(DO, R) = (∃k: k ≥ 0: Hk(R))   .

(Intuitively, Hk(R) can be interpreted as the weakest pre-condition guaranteeing proper termination after at most k selections of a guarded list, leaving the system in a final state satisfying R .) Via mathematical induction we can prove

Theorem 3.    From

(P and BB) ⇒ (wp(IF, P) and wdec(IF, t)) for all states

and             (BB and P) ⇒ (t ≥ 0) for all states

we can conclude that we have for all states

P ⇒ wp(DO, P and non BB)   .

Note that the antecedent of Theorem 3 is of the form of the consequents of Theorems 1 and 2.

Because T is the condition by definition satisfied by all states, wp(S, T) is the weakest pre-condition guaranteeing proper termination for S. This allows us to formulate an alternative theorem about the repetitive construct, viz.

Theorem 4.    From

(P and BB) ⇒ (wp(IF, P)   for all states

we can conclude that we have for all states

(P and wp(DO, T)) ⇒ wp(DO, P and non BB)   .

In connection with the above theorems "P" is called "the invariant relation" and "t" is called "the variant function".

4. Formal derivation of programs.

The formal requirement of our program performing "m:= max(x, y)" —see above— is that for fixed x and y it establishes the relation

R:        (m = x or m = y) and m ≥ x and m ≥ y   .

Now the Axiom of Assignment tells us that "m:= x" is the standard way of establishing the truth of "m = x" for fixed x, which is a way of establishing the truth of the first term of R. Will "m:= x" do the job? In order to investigate this, we derive and simplify

wp("m:= x", R) = (x = x or x = y) and x≥x and x≥y
               =  x≥y  .

Taking this weakest pre-condition as its guard, Theorem 1 tells us that

if x ≥ y → m:= x fi

will produce the correct result if it terminates succesfully. The disadvantage of this program is that BB ≠ T, i.e. it might lead to abortion; weakening BB means looking for alternatives which might introduce new guards. The obvious alternative is the assignment "m:= y" with the guard

wp("m:=y", R) = y ≥ x    ;

thus we are led to our program

if x ≥ y → m:= x
 ▯ y ≥ x → m:= y
fi

and by this time BE = T and therefore we have solved the problem. (In the mean time we have proved that the maximum of two values is always defined, viz. that R considered as equation for m has always a solution.)

As an example of the deriviation of a repetitive construct we shall derive a program for the greatest common divisor of two positive numbers, i.e. for fixed, positive X and Y we have to establish the final relation

x = gcd(X, Y)  .

The formal machinery only gets in motion, once we have chosen our invariant relation and our variant function. The program then gets the structure

establish the relation P to be kept invariant";
do "decrease t as long as possible under invariance of P" od   .

Suppose that we choose for the invariant relation

P:        gcd(X, Y) = gcd(x, y) and x > 0 and y > 0

a relation that has the advantage of being easily established by

x:= X; y:= Y   .

The most general "something" to be done under invariance of p is of the form

x, y: = E1, E2

and we are interested in a guard B such that

(P and B) ⇒ wp("x, y := E1, E2", P)
          = (gcd(X, Y) = gcd(E1, E2) and E1 > 0 and E2 > 0)  .

Because the guard must be a computable boolean expression and should not contain the computation of gcd(X, Y) —for that was the whole problem:— we must see to it that the expressions E1 and E2 are so chosen, that the first term

gcd(X, Y) = gcd(E1, E2)

is implied by P , which is true if

gcd(x, y) = gcd(E1, E2).

In other words we are invited to massage the value pair (x, y) in such a fashion that their gcd is not changed. Because —and this is the place where to mobilize our mathematical knowledge about the gcd-function—

gcd(x, y) = gcd(x – y, y)

a possible guarded list would be

x:= x – y   .

Deriving

wp("x:= x – y", R) = (gcd(X, Y)
= gcd(x – y, y) and x – y > 0 and y > 0)

and omitting all terms of the conjunction implied by p we find the guard

x>y

as far as the invariance of p is concerned. Besides that we must require guaranteed decrease of the variant function t. Let us investigate the consequences of the choice

t = x + y      .

From

wp("x:= x – y", t ≤ t₀) :=
wp("x:= x – y", x + y ≤ t₀) := (x ≤ t₀)

we conclude that

tmin := X     ;

therefore

wdec("x:= x – y", t) = (x < x + y) = (y > 0)   .

The requirement of monotonic decrease of t imposes no further restriction of the guard because wdec("x:= x – y", t) is fully implied by p and we come at our first effort

x:= X; y:= Y;
do x > y → x:= x – y od    .

Alas, this single guard is insufficient: from p and non BB we are not allowed to conclude x = gcd(X, V). In a completely analogous manner, the alternative y:= y – x will require as its guard y > x and our next effort is

x:= X; y:= Y;
do x > y → x:= x – y
 ▯ y > x → y:= y – x
od    .

Now the job is done, because with this last program non BB = (x = y) and (P and x = y) ⇒ (x = gcd(X, Y)) because gcd(x, x) := x   .

Note. The choice of t = x +2y and the knowledge of the fact that the gcd is a symmetric function could have led to the program

x:= X; y:= Y;
do x > y → x:= x – y
 ▯ y > x → x, y:= y, x
od    .

The swap "x, y := y, x" can never destroy P : the guard of the last guarded list is fully caused by the requirement that t is effectively decreased.

In both cases the final game has been to find a large enough set of such guarded lists that BB, the disjunction of their guards, was sufficiently weak: in the case of the alternative construct the purpose is avoiding abortion, in the case of the repetitive construct the goal is getting BB weak enough such that P and not BB is strong enough to imply the desired post-condition R  .

5. Concluding remarks.

The research, the outcome of which is reported in this article, was triggered by the observation that Euclid's Algorithm could also be regarded as synchronizing the two cyclic processes "do x:= x – y od" and "do y:= y – x od" in such a way that the relation x > 0 and y > 0 would be kept invariantly true. It was only after this observation that we saw that the formal techniques we had already developed for the derivation of the synchronizing conditions that ensure the harmonious co-operation of (cyclic) sequential processes, such as can be identified in the total activity of operating systems, could be transferred lock, stock and barrel to the development of sequential programs as shown in this article. The main difference is that while for sequential programs the situation "all guards false" is a desirable goal —for it means termination of a repetitive construct— , one tries to avoid it in operating systems —for there it means deadlock.

The second reason to pursue these investigations was my personal desire to get a better appreciation —among other things in order to be able to evaluate how realistic some claims towards "automatic programming" were— which part of the programming activity can be regarded as formal routine and which. part of it seems to require "invention". While the design of an alternative construct now seems to be a reasonably straightforward activity, that of a repetitive construct requires what I regard as "the invention" of an invariant relation and a variant function. For me, the main value of the calculus shown in section 4 is that it has strengthened my skepticism about some of the claims or goals of "automatic programming"; me presenting this calculus should not be interpreted as me suggesting that all programs should be developed that way: it just gives us another handle.

The calculus does, however, explain my preference for the axiomatic definition of programming language semantics via predicate transformers above other definition techniques: the definition via predicate transformers seems to lend itself most readily to being forged into a tool for the goal-directed activity of program composition.

Finally I would like to say a word or two about the role of the potential non-determinacy. I quote in this connection C.A.R.Hoare: "A system which permits user programs to become non-deterministic presents dreadful problems to the maintenance engineer: it is not a "facility" to be lightly granted." (This is particularly true in the absence of self-checking hardware.) I myself had to overcome a considerable mental resistance before I found myself willing to consider non-deterministic programs seriously. It is, however, fair to say that I could not have discovered the calculus shown before having taken that hurdle and I leave it to the environment whether the non-determinacy is eventually resolved by human intervention or mechanically, in a reproducible manner or not. (It is only in an environment in which all programs should be deterministic, where non-reproducible behaviour is interpreted as machine malfunctioning: I can easily think of an environment in which non-reproducible user program behaviour is quite naturally and almost always correctly taken as an indication that the user in question has written a non-deterministic program!)

Acknowledqements.

In the first place my acknowledgements are due to the members of the IFIP Working Group W.G.2.3 on "Programming Methodology": it was, as a matter of fact, during the Blanchland meeting of this Working Group in October 1973 that the guarded commands were both born and shown to the public. In connection with this effort its members R.M.Burstall, C.A.R. Hoare, J.J.Horning, J.C.Reynolds, D.T.Ross, G.Seegmüller, N.Wirth and M. Woodger deserve my special thanks. Besides them, W.H.J.Feijen, D.E.Knuth, M.Rem and C.S.Scholten have been directly helpful in one way or another. I should also thank the various audiences —in Albuquerque (courtesy NSF), in San Diego and Luxembourg (courtesy Burroughs Corporation)— that have played their role of critical sounding board beyond what one is entitled to hope.

[1] Hoare, C.A.R., An Axiomatic Basis for Computer Programming, Comm.ACM 12 (Oct. 1969). 576 - 583.

[2] Naur. Peter, (Ed.) Report on the Algorithmic Language ALGOL 60, Comm.ACM 3 (May 1960) 299 - 314

26th June 1974 NEUNEN | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

Transcription by Moti Ben-Ari.
Revised Sun, 19 Nov 2006.

  EWD 420

Trip report E.W.Dijkstra, Luxembourg, 7-12 April 1974.

Previous experience had taught me —to put it mildly— that train connections between the Netherlands and Belgium are not quite up to the general standards of continental Western Europe: they are hardly there. As a result I was not too surprised to learn that it would take more than seven hours to cover by train the 170 miles from Eindhoven to Luxembourg; a car seemed a more realistic proposition. When I made a call to Burroughs, Amstelveen, with the intention to suggest timidly to the controller that a car should be hired for me, the controller was away and I was connected to one of his subordinates who, upon my request, explained that he was not really entitled to make such a decision, but promised me to discuss it with the controller next day, when the latter would be back again. A few minutes later I was called back: the subordinate had discussed it with one of his colleagues and "as Burroughs USA was charged for all my expenses" everything was OK and I could go by car! At that moment not inclined to question the validity of their logic, I asked them to hire a small car.... On Sunday afternoon I left in a Ford Escort, with a colour so ugly, that I could only guess that Hertz has chosen it to reduce the chance of theft! But the carlett was in excellent condition and without problems —it was beautiful weather— I arrived in Luxembourg before sunset. The trip implied a renewed acquaintance with Belgian roads: they were as they used to be, even the warning signs "route dégradée" were so old and dirty as to be hardly readable....

Luxembourg is a charming city that seems to have been passed by what in surrounding countries is regarded as "progress". The cross roads in town are protected by traffic lights that change at such a low frequency that a trip through the town leaves the driver all opportunity to wonder about what other civilizations have lost. Later in the week we had dinner in a restaurant that was evidently the regular meeting place of the town's older establishment: we were somewhat regarded as intruders —what, of course, we were!— and particularly one of our company (a Californian) seemed not to understand the atmosphere of the place. Needless to say, the food was superb.

But Luxembourg has not been completely untouched by progress, oh no: it too has its Holiday Inn. It is not located in the town itself, but at the other side of a deep valley in the "European Centre", the bulwark of the European Community, a ghetto of concrete skyscrapers, stainless steel and plastic. And in the Holiday Inn we had our seminar.

When I arrived I found a note that at seven o'clock Jack Cleary would be in the bar —where else?— to meet the participants, and furthermore that I had been given room 511, which is, if you know your binary numbers as I do, of course a beautiful number. The privilege of occupying that room was a short one for its telephone was out of order. I complained about that on Saturday night, on Monday at noon the receptionist told me that "the expert would arrive within an hour", at six o'clock p.m. they told me that the trouble had been dealt with. In spite of all this —mind you, we were in Luxembourg— the telephone was still out of order and I asked to be moved to a room in good condition. When they said that they had only a room available on the fourth floor, I answered that —as all floors were identical— I could not care less, and thus was moved to room 423, a change that I later had cause to regret. A few nights later I shared the floor with a few bus loads of American teenagers who arranged their noisy party largely in the corridor: late at night —early in the morning, I should say— peace was still disturbed by heated arguments about who should sleep where. With nothing else to do I lay thinking about the older people we had disturbed in the restaurant, hoping that they did not know what happened in the ghetto.

Because I had not had the slightest advance information about the audience I was going to address, I had hardly been in a position to prepare my presentation: I had to rely on the feedback I would get. To start with I asked my audience to compose a list of participants, mentioning name, address, activity and educational background. The background was much higher than I had expected (or feared), the overall list being quite impressive —in a few cases the indication was not clear and I have made a guess—

M.Sc (mathematics, physics or computer science) | 6
engineers (mostly electronical) | 5
B.Sc | 3
Ph.D (mathematics, physics or computer science) | 4
economics/management | 2
total | 20

I do not think the latter two have understood a single word of what I have said: as all their colleagues those two seemed utterly blind to the subtle, but profound difference between "being vague" and "being abstract": that it is the specific purpose of abstraction to create a new semantic level in which one can be absolutely precise, is more than I can teach to a superficial person to whom such considerations are, intellectually speaking, totally foreign. That leaves a well-educated audience of 18.

Yet it was a difficult audience to address. Seven had English or American as their native language, another two had studied at an English or American university, but the remaining nine (1 Italian and 8 Frenchmen or French-speaking Belgians) suffered from the usual language barrier. (At meals they had a tendency to separate themselves from the others....) If one is the kind of speaker that delivers monologues in front of any audience, such a language barrier only causes problems in the audience; I, however, do like to adjust my presentations to my audience, I do like to develop a dialogue of some sort. The French half, however, did not give any feedback: they listened respectfully. (Later I have been given to understand that it was not only the language barrier that made them so silent, but also the Latin respect —or even: awe— for authority.) As a speaker I suffered very much from this lack of response and I must confess that after a few days I more or less forgot them and focused my attention on the responding part of the group, no longer consciously restricting my use of the English vocabulary (to the extent of using the verb "to obfuscate", which seemed to puzzle even some of the English natives).

Despite these difficulties it was, on the other hand, some sort of an excellent group: I spoke to them five mornings and four afternoons, and each of these 9 sessions lasted more than three hours —once even close to four!— at a stretch, with one interval for coffee of at most 10 minutes. This is an absolutely cruel thing to do to an audience, in particular if they had —as they had— to sit on plastic. Such long sessions, however, were not planned, they "happened" and that would never have taken place had I seen their attention wavering.

I observed one marked phenomenon: while most of them followed the formal part of my lectures with a keen interest and some even with considerable intellectual excitement, the group was very disappointing when I asked them to solve a problem themselves. For all sorts of problems admitting a solution in the form of a five-line program, it was exceptional if more than one-and-a-half solutions turned up. (This was similar to the San Diego experience: there they were more productive, but also more productive of errors. This group has a little bit stronger inhibitions.) I do not think that this is in all cases a basic incapability, it must be the result of our educational systems that pay not enough attention to the development of skills and tend to restrict themselves to the broadcasting of "knowledge". The resulting wide-spread incapacity to "do something" (rather than "to know something") is nonetheless frightening and alarming.

Outside the official sessions —but occasionally also during them— I observed, perhaps stronger than in San Diego, feelings of strain between "technology" and "management". These are reactions that do not amaze me a bit: I have encountered them at least a few dozen times. During the after-lecture discussion, someone nearly always remarks —after I have shown a perfectly decent way to solve a problem— "But, Sir, our problem is that our managers won't let us do it that way." My standard answer, of course, is "If misunderstanding from the side of your manager is your main problem, perhaps you should try to educate him..." an answer, by now, I have given frequently enough to know that it evokes roars of bitter laughter. In other words, the feelings of strain are quite well-known to me, and I can also understand them, from both sides; I do not have much material for comparison, yet I could not escape the impression that in this group the feelings of conflict, frustration etc. were stronger than average.

We broke up on Friday at noon. The departure is always a little bit sad: however imperfectly one has built up a kind of "family", which then dissolves for no other reason than that the end of the week has come. We said good-bye to each other.

Also the homeward trip was done by day-light, be it that, after a week of continuous sun, I encountered between Bastogne and Liege a severe rain storm. In Nuenen the sun was shining again. A week earlier I had left Nuenen with the trees still bare, when I returned they were green. But the magnolia, who had [been] in full bloom when I left, had lost its flowers.

14th April 1974
BURROUGHS
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
research fellow

transcribed by Tristram Brelstaff
revised Sun, 14 Jan 2007

  EWD 423

Trip report E.W.Dijkstra, W.G.2.3 Meeting "Boldern" 28th April - 3rd May 1974

Characteristic of this traveller's life is the fact that this trip report is written on board of a KLM Boeing 747 taking me from Amsterdam to Chicago. The traveller's life, however, is not without pitfalls.

On Sunday 28th April 1974 I went to Boldern near Zurich. At the Eindhoven railway station my train to Amsterdam was announced at the usual platform. When I was aboard the train, had settled myself nicely and was on the verge of getting lost in my thoughts, a voice over the sound system announced that I was now on the train heading for Tilburg! I picked up my coat in panic, jumped out of the train —in the mean time the announcements on the screen had been changed!—, found out where the train to Amsterdam was expected to leave now, only to discover that I had left my luggage in the Tilburg train that I had left in panic! I managed to retrieve it before that train left the station, I even caught my train to Amsterdam and by the time we passed Vught my heart rhythm was back to normal.

When I checked in at Schiphol Airport I discovered that the travel agent had not booked me on the four o'clock plane as ordered, but on the plane leaving Amsterdam at nine o'clock in the evening. A most unpleasant surprise; in my capacity as stand-by passenger —a miserable position, one feels oneself an outcast, a refugee, a third-class citizen— I have done my best, but to no avail. Schiphol Airport is, of course, an absolutely exciting place, but yet.... I did some writing, had two beers and an "uitsmijter", and was well in time at the gate for the next Swiss Air flight to Zurich, which departed dead on time. I arrived at Kloten, Zurich Airport, doubtful as to whether public transport would still take me to Boldern. When a taxi driver told me that the distance was less than 18 miles I opted for the taxi; the next time in Switzerland I shall ask that question not in the dimension of distance, but in the dimension of money: upon my arrival even my Swiss host —who had stayed up: most of the participants had already gone to their rooms— was shocked when I told him the amount.

The meeting of the IFIP Working Group W.G.2.3 on "Programming Methodology" was held in "Boldern", a conference place near Zurich that had been selected by Niklaus Wirth. It was ideally suited to the purpose: we had small two-bed rooms with a desk and a sink, common toilets and showers, simple but excellent meals and the whole thing was run on an idealistic basis (if you took a beer or a small bottle of wine you were supposed to drop coins in a bowl). Besides that it had a few excellent conference rooms, one even with a decent blackboard. Prepared for a beautiful view —Boldern is half-way up the mountain slope— I had taken my binoculars with me (in my hand luggage! it was quite a sacrifice of space), but we had fog all week, the other side of the lake was hardly visible. Well, not all one's kites can be supposed to fly....

Compared with our previous meeting —Blanchland, near Newcastle, last October— we had a huge attendance, observers included about 25 persons (of about 12 different nationalities: it was a truly international meeting). and it was perhaps exactly this larger participation that made —at least for me and a few others who could compare— this meeting less exciting than the previous one. It was a mixed lot. (To some extent Brian Randell —who was absent this time and therefore could not observe the consequence— who likes and loves "the clash of opinions" has been responsible. I remember him, with a justified fear of inbreeding, urging for variety of backgrounds. Sometimes I now fear that he has overstated his case, as he had certainly done in arranging the NATO Conference on Software Engineering Techniques in Rome, 1969, a conference that was an unrivalled misery! In Boldern we had a faint echo of that...)

I observed various types of scientific paralysis. A few of our (full-time) university types —and they are by no means the worst ones: they do have standards, they do want to sift in deciding what to present— yet made the impression of having made their courses their standards of relevance. If something was too difficult for their average students, if their administration would not allow it, their first reaction was to turn away from it. This was particularly true in the case of our best known language designers: they too had accepted political pressure as a fact of life to the extent that they could sometimes hardly bring themselves even to consider suggestions that they considered as "heretic". I do not blame them, for I have some idea of the agonizing intrigues they have gone through in order to get their product more or less accepted. Yet I would rather remain aware of the scars. One American academic had reacted quite differently: he had opted for Artificial Intelligence work in connection with the NSW —"National Software Works"—, ARPA's new grandiose project that is intended to prolong the glory of the ARPA-net. Even if one did not know ARPA, the name "National Software Works" is enough to make one somewhat suspicious. He gave two wishy-washy talks on how grand it was all going to be, failing to convince us both of the project's desirability and its possibility. It left a very dirty taste in my mouth and it becomes very hard to be more explicit about one's impression of ARPA under the constraints that the words "fraud" and "corruption" are to be avoided. As far as the project was described I can only describe it as "a simulation project", viz. the simulation of a research project. Its advocate was quite sure it was a true research project "for it was not a priori sure that they could do it!" A most amazing argument that would place all incompetent development in the ranks of research. My misgivings about Artificial Intelligence —which had already grown into more solid misgivings by the reading of Sir James Lighthill's report— have been reinforced. In a few years time AI-addicts will call me "prejudiced".

Personally I had no reason for complaint, nor regret. Both within and outside the official hours I have shown what I wanted to show and asked what I wanted to ask and have received as much feedback as I could hope for. On Monday afternoon I have spoken on "Some engineering aspects of the programming task", using the design exercise as described in EWD408 as an example. O.-J.Dahl reinforced my feelings that the replacement algorithm should not be terribly important and suggested a "randomizer" as a means for avoiding systematic mis-behaviour. I had never thought about that and was grateful for the suggestion. In a discussion it transpired that I had guarded against unjustified growth of the window size, but had failed to detect "justified shrinking" under unfavourable circumstances. The lesson is taken in gratitude. From both Ross and Seegmüller I hear that their people had gone through the literature and the suggestion about the T/C-ratio (and its motivation) both seem new. On Monday evening I gave a quick talk —i.e. two hours— on guarded commands and the calculus for the derivation of programs, just to bring my co-members in the picture —the first half was a second exposure to those that had attended the Blanchland meeting. On Tuesday evening I have exposed my array exercises to a small group in Niklaus' room —the discussion was continued at the closing dinner on Thursday evening—. In the mean times we had Barbara Liskov's paper as supplementary material for comparison and although not all my questions have been answered, some are and I have a clearer insight in the issues involved. Rewarding. On Wednesday evening I had a long talk with Rod Burstall, whose lectures I had liked: his "derivation" of the repetitive Fibonacci generator was quite impressive; that evening I went with him in greater detail through a few of my derivations. They continued to hold water. On Thursday afternoon —a free afternoon scheduled for a trip that was cancelled on account of the fog— I spoke in my room for two hours with the NSW guy —in his sales talk he had said nothing, that afternoon he showed me that there was, indeed, nothing behind his smoke-screen of impressive jargon and bad syntax—, thereafter I had a long discussion with Mr. Nori, an observer from India. A nice lad who made a very sensible effort of raising the confidence level of a compiler. Given the time, he might do a nice job; a considerable amount of water has still to stream through the Ganges, but I am not worried. After the NSW guy he was refreshingly solid and modest.

Cliff Jones gave a short talk, as an act of "verbalizing" it was not a very good one. Yet it was helpful, at least for me, for it made me realize that my recent experience with the problem of the strong components is a perfect example for my judgement that an automatic implementation of a program expressed in terms of sets is currently a foolish goal for other than "quickies". So much for Courant Institute's SETL —if I am well informed— and also (I am sorry to say) to a certain extent for Barbara's efforts.

1st June 1974

Burroughs
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Research Fellow

transcribed by Tristram Brelstaff
revised Sun, 9 Jul 2006

  EWD 425

Trip report E.W.Dijkstra, USA and Canada, 5th – 25th May 1974.

On Sunday morning, two days after my return from Boldern, I flew to Chicago where I arrived at four o'clock in the afternoon. O'Hare is a frightening airport —once, when trying to fly to Purdue, I had very bad experiences there— and I was duly frightened. After an unsuccessful (!) attempt at the KLM desk to reconfirm my return flight and after having discovered that, contrary to my expectations, there was no one to pick me up, I suddenly became aware of the fact that I had lost my briefcase. Thank goodness I could retrieve it —I had lost it in the customs area— so that I could at least look up the name of the hotel where I was expected to go. Instructions as to which coach to take were of an ambiguity in the best of O'Hare's tradition and, not quite sure of whether I was doing the right thing, I went on board of one of the coaches. (Everybody was shouting and it was utter chaos.) Suddenly I saw the experienced Horst Hünke entering the same coach: at that moment I knew I was in the right coach and after a few minutes I was again relaxed. Chatting about this and that we arrived at the Palmer House. In front of the reception desk stood a huge crowd of pushing people, mixed with heavy luggage. When at last my turn had come, I was told that I —a guest of honour— should go to the special desk for "Quick Registration"! In an effort to speed up the adjustment to the time shift, I went to bed at the normal local time, but I woke up at (their!) four o'clock in the morning; on Tuesday morning it was much better: five 'clock in the morning.

I have spent most of Monday and Tuesday at the National Computer Conference, but have not attended many talks: in most lecture rooms it was hot and crowded and most of all I remember the worst talk, because I was genuinely shocked: a man grafting a parallel programming language —in order to cope with the Goodyear machine— on PL/I (of all programming languages! in the discussion he justified his choice by explaining that he knew no others well...) without even having considered the problems. It was all wrong. He was from "Rome Air Development Center"; the USA had better try to stay away from war for the next few years.... I spent most of my time in the "speakers' lounge" where I talked with all sorts of (mostly young) people.

On Tuesday, at the Conference Luncheon, I received the AFIPS Harry Goode Memorial Award 1974 in the form of a big bronze plaque, whereupon I gave a brief —and very carefully prepared!— acceptance speech, which was well received. My feelings of excitement at getting this scientific distinction —probably the highest I shall ever get— were somewhat tempered by the fact that I hardly felt myself in a scientific environment.

After the lunch I was approached by Yeh and Good, who exerted new pressure that I should present a tutorial at their reliability conference next spring, but I resisted the temptation. When they assured me that it would be "a big attraction" for the participants to see me and Hoare together, I felt that they were trying to exploit me, like the 600-pound woman exhibited at the circus. In the afternoon Bob Merrel and I flew to Detroit and had a late but pleasant dinner in a Chinese restaurant near his home and my hotel.

The next few days at the Corporate Engineering Headquarters were mainly for my education —I don't remember whether I have given a lecture, maybe I did— and I was exposed to various groups. The most striking observation was the enormous variation between those groups: some told me how great it was what they had done and were going to do, others just plainly told me their problems. (My impression was that the latter were the better ones.) I particularly remember a discussion of a cheque sorter where dimension analysis enabled me to suggest what seemed a great simplification (but knowing nothing about "flimsy paper handling" but its name, I doubt whether it would work. I remember this discussion because it enabled me to apply the kind of dimension analysis that I have lately applied to a completely different design, in a quite unexpected environment! This tickled me: even if it does not work I have had the intellectual satisfaction of an otherwise useless invention. The third day was spent in discussions with Bob Merrell and efforts to get my raincoat back, which I lost in Chicago. (They have succeeded! Delphine —Bob's secretary— must be an absolute marvel: I had already done my utmost best in Palmer House, where I had lost it, but then they were most uncooperative, to put it mildly. My impression was that to get the Palmer House security man in action, at least a corpse in the bathroom would be needed, and I had only a lost raincoat to offer!) Late Friday afternoon I flew to Philadelphia, where Steve Schmidt expertly picked me up at the airport (for which I was very grateful to him).

The discussions scheduled for the weekend were not as successful as I had hoped, some underlying material was lacking and I guess that —it being the weekend— we were tired, all of us. I had my birthday anyway.

We stayed in the "Valley Forge Hilton", a hilarious place where "The Bell Captain will be happy to direct you to a nearby house of worship. (Dial 4)". The television set had the name of the hotel carved on the cabinet, as a further incentive not to steal it, a little notice said that it was connected to their central theft alarm system. We looked at the co-ax cable connecting it to the antenna and also at the cord connecting the plug and they both looked quite normal. When, 24 hours after total disconnection, the alarm had not come yet, we gave up and reconnected the equipment. But my laundry was returned in a box saying "every Garment a masterpiece!"....

On Monday I visited two, on Tuesday one plant in the area. At all places I have done a lot of lecturing. It was a pleasure to see Frank Zurcher again, whom I had met at most once since we were introduced to each other in 1967 at Gatlinburg.

On Tuesday evening I went to Syracuse with something of a sigh of relief: seven days continuous exposure to the World of Industry is quite enough when one is not used to it and I was looking forward to the familiar and comfortable peace of the University Campus —which, of course, turned out to be another fata morgana. (After a few days I had heard already so much campus politics that with a faint nostalgia I looked to my sweet Detroit days where I could discuss cheque sorters!)

In Syracuse I stayed with an old friend who is there professor of chemistry: I slept in a room at the top floor of their house and on Wednesday morning they did not give me a wake-up call, a gesture that was appreciated. As in Detroit I had to give in Syracuse as well a performance for the local chapter of the ACM. I had planned to give the same talk at both occasions, but in Detroit my local representative, when urged to give a title before he had heard from me, had invented a title for me himself. So there I ended up, giving the announced talk instead of the prepared one (which is a kind of challenge: I only made the discovery a few hours before count zero!) But in Syracuse I gave the prepared talk and I was very successful. As a token of gratitude the Syracuse Chapter gave me a great silver tray with an inscription; four days later I would discover that it did not fit in my suitcase.

On Thursday I was at the University of Syracuse as the guest of my colleague John C.Reynolds. In the morning I showed him a formal derivation —which involved inequalities between absolute values, so I nearly got lost in the algebra*)—, he showed me exercise with sorting that were quite nice. In the afternoon I gave a lecture, in the evening we had dinner in his home.

*) The critical formulae, not very well known but indispensable when you need them, are

(abs(a) < b) = (a < b and -a < b)                      and

(a < abs(b)) = (a < b or a < -b)            .

On Friday I went by Greyhound to Ithaca —via the less exciting quarters of Syracuse, past "Simmon's School for Embalment and Mortuary Science"— where I arrived at the end of the morning. David Gries picked me up and took me to Cornell University, where I lectured in the afternoon. In the evening we had dinner: we were joined by a lady from Washington who told that nowadays the Nixon's are so lonely: in the evenings they do not know where to go and nobody anymore pays them a visit. They are outcasts....

The next day, on Saturday afternoon, David Gries and Bob Constable drove me back to Syracuse where I had a peaceful weekend. On Monday morning I was back under the yoke again and flew via Buffalo to Toronto where Jim and Jane Horning and Rich Holt met me at the airport. That afternoon graduate students of Jim Horning's showed me what they were doing —a startling variety! That night I had dinner at the Hornings where we were joined by Derek and Barbara Corneil. On Tuesday I talked to students in the morning and gave the first of three lectures in the afternoon. I had dinner with David Wortman and a few others in a good French restaurant. (The Canadians have the best of both worlds: the French kitchen and Anglo-Saxon toilets!); in the evening a taxi took me to Waterloo where I stayed for one night in the Waterloo Motor Inn. The later part of that evening I was very sad....

Next morning I went by taxi to the University of Waterloo where I was picked up by Ashcroft, who failed to excite me. As it transpired he had just discovered the phenomenon of individual starvation (in 1974!). At lunch we were joined by Fisher and his wife, Don Cowan and a few others. Before my talk I had a discussion with two nice lads that were very eager not to repeat the mistakes made by others and pumped me vigorously. Were they aware of Waterloo's professional isolation? My lecture went down very well: I had prepared it with extra care because the day before, in Toronto, I had a black-out of at least 30 seconds. Besides that, the Waterloo auditorium was cooled. After dinner with Ashcroft and his wife and a very amusing Pole (± Brozovski) —again in a French restaurant! Ashcroft was a gourmet— I went back to Massey College in Toronto. The next two days in Toronto were very much like Tuesday: in the morning talking to groups of students about whatever subject they wanted to raise and in the afternoon my lecture. At Thursday evening I had dinner at Richard Holt's place, on Friday afternoon, after my lecture I was rescued by Derek Corneil who has a house quite near the airport. Barbara had prepared open sandwiches of which I had a few. And two glasses of milk and one glass of whiskey (or the other way round). At six o'clock I was at the airport because I hate missing planes: I was one of the first passengers at the gate. While waiting there the same thing happened to me that happened to me in the Valley Forge Hilton at supper: a young man came up to me and asks "Excuse me, Sir, but are you professor Dijkstra?". In both cases they turned out to be computer scientists with an American M.Sc. degree (Utah and Wisconsin respectively) of which the ink was still wet. Presumably I must get used to this; and then, later I must get used to no longer being recognized at airports and the like!

In Waterloo I heard a story about the University of Chicago, a story that, of course, happens all over the world, but seldomly in such naked cruel clarity. As student enrolment for mathematics was declining, the overstaffed Dept. of Mathematics managed to get itself merged with the flourishing Dept. of Computer Science. As the latter department was not understaffed, a simple calculation will tell you that the union of the two departments was still overstaffed, whereupon the mathematicians managed to get a number of the original computer science faculty members fired, thus, as my spokesman added "killing the subject at the University of Chicago". The story has an all too familiar ring! In Albuquerque, last January, I heard a similar story about Berkeley hinted at, but probably one must be outside the country if one wants to hear the details.

In the departments of computing science visited, Ithaca (Cornell) was clearly better than Syracuse, Toronto was clearly better than Waterloo. Syracuse is really small; they have Robinson —of resolution fame, but he seems a bit fed up with it— and Reynolds —of Scottery fame, but he seems a bit fed up with it—. Complication for Syracuse is that a considerable amount of their research contracts are with aforementioned Rome Air Development Center and, boy, that must be a miserable place! ((John Reynolds told me that he heard that someone in Oxford tried to cope with non-determinacy, but that all arms and legs of Scottery had to be twisted rather seriously. If I can get that rumour confirmed, it will reinforce my attitude towards Scottery.) Cornell, as a university seems more independent, the Dept. of Computing Science as a whole, however, feels less secure: they feel ashamed because they still teach FORTRAN to the Great Unwashed. (While I was there Constable was totally absorbed by the organization of a multiple-choice examination on FORTRAN idiosyncrasies: the poor boy was so miserable and felt so foolish. It was, of course, his bad luck that I had to arrive exactly at that moment. And the defense was the usual one: the X-engineers want it and if we don't give it then they will do it themselves, thereby making us superfluous. In the latter respect, Toronto was refreshing: there the Department of Computer Science refused to teach that junk, and if X-engineers wanted to inflict that upon their students, well, that was their business! Knowing the scene I know that such an attitude takes courage: the courage was well rewarded.

Waterloo was bad: it was really two worlds and never the twain shall meet. The pragmatists were appallingly pragmatic, the theorists were appallingly theoretic. Both parties were conceited and seemed to live in an atmosphere of mutual contempt that does not seem conducive to healthy university life. In this respect Toronto was a surprisingly pleasant exception: faculty members spoke with respect about their students and about their colleagues. (This in contrast to MIT, where respect for students was always combined with nasty remarks about colleagues; but that place is poisoned by competition.)

From the grapevine I picked up two indications that IBM has some problems with its research facilities. The one indication came from a man from Yorktown Heights, a man I know as a knowledgeable person. They were clearly losing a battle concerning IBM's next product. His nerves were very tense, he apologized for not being able to give me any further details and his comments ended in "inaudibles" from which I still picked up expressions like "terrible mistakes" and "unbelievable stupidity". It was frightening to witness. The other indication was from the Vienna Laboratory and was much more specific: while that group was coming to terms with the problem of proving the correctness of compilers, high quarters exerted too strong pressure to focus upon the specific problem of proving the correctness of PL/I compilers, much to the dismay of the people in the Vienna Laboratory: the quarters seem to kill the hen that could lay the golden eggs. It is all not very comforting.....

Furthermore I got the impression that the False Religion of Multidisciplinary Research is still making all sorts of victims. In principle there is, of course, nothing wrong with multidisciplinary research if you know how to organize it; but the preachers of the False Religion make in their sermons (uni-disciplinary) competence suspect on account of the mere competence. The preachers I can fight, the victims I can only pity when the result is that they have lost the confidence and self-respect to which —to my taste at least— they are entitled. Some doubts are the incentive for further probing that reveals, other doubts only paralyze.

3rd June 1974
Burroughs
Plataanstraat 5
NUENEN – 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
research fellow

PS. An influential Californian software institute had the feeling of being able to construct an abadile. Because said institute was very influential the design, development and implementation of an abadile became an official ARPA project. When the research project named "abadile" was announced, the said software institute was, if not the only, at least the lowest tender and it got the million-dollar contract as was intended and therefore only to be expected.
       The said software institute had the idea that they could make an abadile on the following grounds. As in the nearby Pacific Ocean abalones are abundant, they felt that they only needed to import a few crocodiles and cross-fertilize them. And although they passed the deadline by 50 percent, they indeed managed to cross-fertilize abalones with crocodiles; the result was a crocolone.....

I was present when the above story was told to Bob Balzer, who duly laughed about the pun, but the funniest thing of all was, that he seemed not to recognize the truth of the story!

transcribed by Tristram Brelstaff
revised Mon, 14 Aug 2006

EWD426

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

     EWD 426: Self-stabilizing systems in spite of distributed control

was published in Commun. ACM 17(1974), 11: 643-644. It is
        reproduced here by permission.

Self-stabilizing systems in spite of distributed control.

| by Edsger W.Dijkstra *)

Abstract. In a sparsely connected system with distributed control the local rules of behaviour can guarantee within a bounded number of steps convergence of the system as a whole towards satisfying a global requirement.
Keywords: multiprocessing, networks, self-stabilization, synchronization, mutual exclusion, robustness, sharing, error recovery, distributed control, harmonious co-operation, self-repair.
CR Category: 4.32

*) Author’s address: | BURROUGHS
| Plataanstraat 5
| NUENEN - 4565
| The Netherlands

Self-stabilizing systems in spite of distributed control.

The synchronization task between loosely coupled cyclic sequential processes (as can be distinguished in, for instance, operating systems) can be viewed as keeping the relation “the system is in a legitimate state” invariant. As a result each individual process step that could possibly cause violation of that relation has to be preceded by a test deciding whether the process in question is allowed to proceed or has to be delayed. The resulting design is readily —and quite systematicly— implemented if the different processes can be granted mutually exclusive access to a common store in which “the current system state” is recorded.

A complication arises if there is no such commonly accessible store and “the current system state” must be recorded in variables distributed over the various processes and furthermore the communication facilities are limited in the sense that each process can only exchange information with “its neighbours”, i.e. a small subset of the total set of processes. The complication is that the behaviour of a process can only be influenced by that part of the total current system state description that is available to it: local actions taken on account of local information must accomplish a global objective. Such systems (with what is quite aptly called “distributed control”) have been designed, but all such designs I was familiar with were not “self-stabilizing” in the sense that, when once (erroneously) in an illegitimate state, they could —and usually did!— remain so forever. Whether the property of self-stabilization —for a more precise definition, see below— is interesting as a starting procedure, for the sake of robustness or merely as an intriguing problem falls outside the scope of this article. It could be of relevance on a scale ranging from a world-wide network to common bus control. (I have been told that the first solution shown below was used a few weeks after its discovery in a system where two resourcesharing computers were coupled via a rather primitive channel along which they had to arrange their co-operation.)

We consider a connected graph in which the majority of the possible edges are missing and with a finite state machine placed at each node; machines placed in directly connected nodes are called each other’s neighbours. For each machine one or more so-called “privileges” are defined, i.e. boolean functions of its own state and the states of its neighbours; when such a boolean function is true, we say that the privilege is “present”. In order to model the undefined speed ratios of the various machines, we introduce a central daemon —its replacement by a distributed daemon falls outside the scope of this article— that can “select” one of the privileges present. The machine enjoying the selected privilege will then make its “move”, i.e. is brought into a new state that is a function of its old state and the states of its neighbours; if for such a machine more than one privilege is present, the new state may also depend on the privilege selected. After completion of the move the daemon will select a new privilege.

Furthermore there is a global criterion, telling whether the system as a whole is in a “legitimate” state. We require that
1)     in each legitimate state one or more privileges will be present, and
2)     in each legitimate state each possible move will bring the system again in a legitimate state, and
3)     each privilege must be present in at least one legitimate state, and
4)     for any pair of legitimate states there exists a sequence of moves transferring the system from the one into the other.

We call the system “self-stabilizing” if and only if regardless of the initial state and regardless of the privilege selected each time for the next move, always at least one privilege will be present and the system is guaranteed to find itself in a legitimate state after a finite number of moves. For more than a year it has —at least to my knowledge— been an open question whether non-trivial (e.g. all states legitimate is considered trivial) self-stabilizing systems could exist. It is not directly obvious whether the local moves can assure convergence towards satisfaction of such a global criterion; the non-determinacy as embodied by the daemon is an added complication. The question is settled by each of the following three constructs. For brevity’s sake most of the heuristics that lead me to find them and the proofs that they satisfy the requirements have been omitted and —to quote Douglas T.Ross’s comment on an earlier draft— “the appreciation is left as an exercise for the reader”. (For the cyclic arrangement discussed below the discovery that not all machines could be identical was the crucial one.)

In all three solutions we consider N+1 machines, numbered from 0 through N. In order to avoid avoidable subscripts I shall use for machine nr. i:
L:     to refer to the state of its lefthand neighbour, machine nr. (i-1)mod(N+1),
S:     to refer to the state of itself, machine nr. i,
R:     to refer to the state of its righthand neighbour, machine nr. (i+1)mod(N+1).
In other words, we confine ourselves to machines placed in a ring (a ring being roughly the sparsest connected graph I could think of); machine nr. 0 will also be called “the bottom machine”, machine nr. N will also be called “the top machine”. For the legitimate states I have chosen a set of (those) states in which exactly one privilege is present. In describing the designs we shall use the format: if privilege then corresponding move fi.

Solution with K-state machines (K > N).

Here each machine state is represented by an integer value S, satisfying 0 ≤ S < K. For each machine, one privilege is defined, viz.

for the bottom machine: | if L = S then S:= (S+1)mod K fi
for the other machines: | if L ≠ S then S:= L fi.

Note 1. With a central daemon the relation K ≥ N is sufficient.
Note 2. This solution has been generalized by C.S.5cholten [1] for an arbitrary network in which the degree of freedom in the legitimate state is that of the special Petri-nets called “event graphs”: along each independent cycle the number of privileges eventually converges towards an arbitrary predetermined constant.

Solution with four-state machines.

Here each machine state is represented by two booleans xS and upS. For the bottom machine upS = true by definition, for the top machine upS = false by definition: these two machines are therefore only two-state machines. The privileges are defined as follows:

for the bottom machine: | if xS = xR and non upR then xS:= non xS fi
for the top machine: | if xS ≠ xL then xS:= non xS fi
for the other machines: | if xS ≠ xL then xS:= non xS; upS:= true fi;
| if xS = xR and upS and non upR then upR:= false fi

The four-state machines may enjoy two privileges. The neighbour relation between bottom and top machine is not exploited; we may merge them into a single machine which is then also a four-state machine for which also two privileges have been defined.

Solution with three-state machines.

Here each machine state is represented by an integer value S, satisfying 0 ≤ S < 3. The privileges are defined as follows:

for the bottom machine: | if (S+1)mod 3 = R then S:= (S-1)mod 3 fi
for the top machine: | if L = R and (L+1)mod_3 ≠ S then S:= (L+1)mod 3 fi
for the other machines: | if (S+1)mod 3 = L then S:= L fi;
| if (S+1)mod 3 = R then S:= R fi .

Again the machine nr. i with 0 < i < N may enjoy two privileges, the neighbour relation between bottom and top machine has been exploited.

Acknowledgements are due to C.S.Scholten who unmasked an earlier effort as fallacious and since then has generalized the first solution, to C.A.R.Hoare and M.Woodger whose fascination by the first two solutions was an incentive to find the third one and to the referees whose comments regarding the presentation of these results have been most helpful.

[1] Scholten, C.S. Private communication.

NUENEN, 4th June 1974 | prof.dr.Edsger W.Dijkstra
| Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

Copyright Notice

The following manuscript

EWD 427: Speech at the Occasion of an Anniversary

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 50-53 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN: 0�387�90652�5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

EWD 427

Speech at the Occasion of an Anniversary.

by Edsger W.Dijkstra

Ladies and Gentlemen!

It is my pleasure and privilege, as Chairman of the Board of “Mathematics Inc.”, to address you, its shareholders, at the 10th Anniversary of our Company. At this occasion it seems befitting to give you a short survey of its illustrious history.

All of you, of course, know how the company was founded, when three young, eager and enterprising mathematicians left their common employer, dissatisfied as they were with its purely commercial objectives and also convinced that, on their own, they could make much more money. And right they were!

We are all here as witnesses of the fact that it was not the inside information they took with them, but the vigor of the fresh young organization they founded, based on professional competence only, that made the enterprise the financial and scientific success their initiative deserved. Their native abilities were, of course, supported by a keen insight in the problems and possibilities of their former employer’s market, but it clearly needed people of their keen intellectual perception to see that the old four-colour problem —almost forgotten to be a problem!— could serve as the basis and starting point of a business as successful as ours.

Up till that moment all cartographers had always thought that they would never need more than four different colours on their maps. Similarly, eye tests for colour sensitivity of pilots and ship captains had never required the ability to distinguish more than four different colours. It was in this sensitive area of map making and traffic by air and sea that these three gentlemen pointed out that up to that moment the sufficiency of the number “four” was no more than a mere assumption that could be killed by the first counter-example.

In view of the reorganizations that would be needed when a fifth colour would be discovered to be necessary, a great nervousness was aroused and at that moment the young company saw the possibility of one, or possibly two contracts in connection with the four-colour problem. A quick but thorough piece of market research was launched in order to discover where the greatest opportunities would lie: would it be in the proof that four colours would always suffice or would it be in the proof that occasionally five (or perhaps even six!) would be needed? For the first product they had the support of the Map Makers Association and of the International Union of Airline Pilots, for the second product the support of printing ink manufacturers and some small shipping companies that would like to use the result as a means of getting rid of a few of their older captains. The critical question, of course, was which of the two products would be preferred by the Navy and the Air Force. As luck would have it, the needs of the latter two pointed into the same direction and within two months, based on solid contracts with both the military and the civilian, our Company was founded.

In its earliest time it was beset by all problems of a young and growing company: moving from modest dwellings to more sumptuous quarters, readjusting the planning, the budget etc. and, as was to be expected, after the almost canonical period of nine months, serious disagreement between the three founders caused one of them to leave the Company and to start all by himself. His parting —I am happy to say— did not create any ill-feelings: he still owns a part of the company’s stock and occasionally he acts as independent consultant. The disagreement was on planning.

The remaining two directors felt that a first Working version of the Proof could be delivered at 27 months after the contract had been signed and this planning was not reconsidered until the 12th month. At that critical stage it became apparent that the project had suffered from two misfortunes. Upon closer scrutiny one of the smallest Proof Modules had presented difficulties that, with the then present state of the art, proved to be unsurmountable. For a few weeks the company hesitated between two different courses of action, either to redesign the interface between the Proof Modules such as to make each of them more manageable, or to launch a research effort that would yield the technology enabling us to deal with the obstinate, unruly Module. As some of you will remember, this was the Company’s most critical moment, not in the least because either course of action was preferred by one of the two remaining directors.

Within a few weeks, however, one of them managed to get the Navy’s support for his approach, as a result of which the other director got the Air Force’s support the next day. Of course this meant doubling the Company’s size, a move to new quarters and all that: the Company’s two Divisions, I am happy so say, work together in full harmony and the Board was very happy to see the broadening in scope: a one-product company is always somewhat vulnerable.

A second misfortune —that really could not have been foreseen and for which we cannot blame our Company— was that two Universities failed to fulfil their obligations: in January they had accepted the obligation to produce at the end of the academic year a given number of brilliant mathematicians. At the end of term time the two Universities, however, de-committed themselves in the most shameful manner; as there was no written contract we could not sue them. But this is typically what happens to young companies only: we have learned our lesson and since the second year of our existence our contracts with Universities as regards the delivery of brilliant mathematicians protect our interests so well that, as a matter of fact, we often prefer to recover the damages.

We had to redo our PERT-planning and we had a hard time explaining to our clients that the first delivery of a Proof had been re-scheduled at month 35 instead of 27, but we succeeded. A next critical moment occurred when that second deadline was approaching. In the mean time, however, we were more firmly established. Firstly we could point to the fact that we had over 200 mathematicians working on the project, secondly we had been able to reshape the decommitment of the two Universities into an advantage: as they felt somehow guilty, pressure could be exerted to make them our first two so-called “Institutional Members” of our organization. As the two Universities in question were both very influential and also anxious to share the responsibility, we had 12 Institutional Members —7 of which very well-known— by the time that the 35-month deadline approached.

As a result it was not too difficult to appoint a fully independent Supervisory Board that was willing to assert that the 35-month deadline —the result of youthful optimism and all that— had to be postponed: at the modest price of a few magabucks we bought the officially approved postponement until month 48.

When that deadline approached we indeed delivered the first release of the Proof. Admittedly it contained still a number of bugs, but the Company in the mean time had grown up to 350 mathematicians and was fully confident that, with the aid of the trouble reports coming from the field, it would get the Proof basicly straightened out within the next four releases, a confidence that, as you all know, turned out to be fully justified.

The Proof of the four-colour conjecture turned out to be a most successful product of the Company. After our first customers had reported that, on the whole, they could live with it, general confidence grew and at month 75, shortly after our third release, the number of customers had grown with a factor of three. The more extensive field testing leading to more experience and trouble reports was met by a healthy growth of the Company which at the age of six years had grown to 720 brilliant mathematicians.

Although the Proof was not yet fully completed, it became obvious that with new products we had to open new markets. It was not quite obvious which. The progress with the four-colour problem eventually had been so rapid that the accompanying decrease of its personal budget came somewhat as a surprise to our young management that had had no earlier experience with projects in the stage of successful completion. Again we had a hectic period: should we fire the surplus mathematicians with the risk of not having them at our disposal when we would need them for our next project?

In the mean time the government was so heavily committed that a few of its organizations and persons, who first had been our foes, could be turned into our friends at a price modest compared to what our Company gained in terms of continuity and stability. It was observed that for Pythagoras’ Theorem at least 100 different proofs were hanging around, and practically all incompatible with each other! We managed to lend 150 mathematicians on a temporary basis to the appropriate Standardizing Body to sort out that mess and decide upon a Standard Proof for Pythagoras Theorem. And as you all know well, a few of our Institutional Members have been most successful in rejecting with their Academic Authority all constructive proposals for a Standard, thereby prolonging the proceedings until, within the Company, a new project would be well on its way. What did I say, a new project? No! Two projects even!

The Company hesitated between Fermat’s Last Theorem, Goldbach’s Conjecture and Riemann’s Hypothesis. After careful market research Fermat and Goldbach —having more appeal to the man in the street— proved to be more promising than Riemann at this stage. As they seemed equally profitable, both were selected.

Now we have our 10th Anniversary: the four-colour problem has been nearly solved, for Goldbach’s Conjecture and Fermat’s Last Theorem we have solid contracts and the size of our Company has grown to nearly a thousand! You, shareholders, are of course mostly interested in the Company’s growth potential. To you I can only describe it as “magnificent”! Know your shares supported by the loyal devotion of one thousand brilliant mathematicians, by a Company that, by its earlier successes, has established itself firmly in the market place. We have often been copied, but never been equalled! “Semper floreat et crescat Mathematics Inc!”

(Applause.)

16th June 1974

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD428

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Array variables.

I have been trained to regard an array in the ALGOL 60 sense as a finite set of elementary, consecutively numbered variables, whose “identifiers” could be “computed”. But for two reasons this view does not satisfy me anymore. The first reason is my abhorrence of variables with undefined values. In the previous chapter we solved this problem by introducing for each variable a passive scope and an active scope, separated by a syntactically recognizable initialization for that variable. But when we regard the array as a collection of (subscripted) variables, that solution breaks down.

The second reason is of a combinatorial nature and more fundamental. In ALGOL 60 the compound statement that causes the variables, x and y to interchange their values, needs an additional variable, h say,

| h:= x; x:= y; y:= h

which is cumbersome and ugly compared with the concurrent assignment

| x, y := y, x .

For the concurrent assignment we have insisted that all variables at the left-hand side should be different: it would be foolish to attach to “x, x := 1, 2” any other meaning than “error”. For a long time, however, I hesitated to adopt the concurrent assignment on account of the problems it causes in cases like

| A[i],A[j]:= x, y ;

should this be allowed when i ≠ j , but not when i = j ? Or is, perhaps, i = j permissible if x = y holds as well, as for instance in

| A[i], A[j] := A[j], A[i] ?

If we go that route we are clearly piling one logical patch upon another. However, I have now come to the conclusion that it is not the concurrent assignment, but the notion of the subscripted variable that is to be blamed. In the axiomatic definition of the assignment statement via “substitution of a variable” one cannot afford —as in, I guess, all parts of logic— any uncertainty as to whether two variables are the same or not.

The moral of the story is that we must regard the array in its entirety as a single variable, a so-called “array variable”, in contrast to the “scalar variables” discussed so far. In the following I shall restrict myself to array variables that are the analogon of one-dimensional arrays.

We can regard (the value of) a variable of type “integer” as an it integer-valued function without arguments —i.e. defined on a domain consisting of a single, anonymous point—, a function that does not change unless explicitly changed (usually by an assignment). It is somewhat unusual to consider functions without arguments; but we mention the viewpoint for the sake of the analogy. For, similarly we can regard (the value of) a variable of type “integer array” as an integer-valued function of one argument with a domain in the integers, a function, again, that does not change unless explicitly changed.

But the value of a variable of type “integer array” cannot be any integer-valued function defined on a domain in the integers, for I shall restrict myself to such types that, given two variables of that type, we can write an algorithm establishing whether or not the two variables have the same value. If x and y are scalar variables of type “integer”, the this algorithm boils down to the boolean expression x = y, i.e. both functions are evaluated at the only (anonymous) point of their domain and these integer values are then compared. Similarly, if ax and ay are two variables of type “integer array”, their values are equal if and only if, as functions, they have the same domain and in each point of the domain their values are equal to each other. In order that all these comparisons are possible, we must restrict ourselves to finite domains. And what is more, besides being finite, the domains must be availabe in one way or another to the algorithm that is to compare the values of the array variables ax and ay.

For practical purposes I shall restrict myself to domains consisting of consecutive integers (when not empty). But even then there are at least two possibilities. In ALGOL 60 the domain is fixed by giving in the declaration —e.g. “boolean array A[1:10], B[1:5]” — the lower and upper bounds for the subscript value. As a type determines the class of possible values for a variable of that type, we must come to the conclusion that the two arrays A and B in the above example are of different type: A may have 1024 different values, B only 32. In ALGOL 60 we have as many different types “boolean array” as we can have bound pairs (and, as the bound pair may contain expressions, the type is in principle only determined upon block entry). Besides that, the necessary knowledge about the domain must be provided by other means: without further information it is impossible to write in ALGOL 60 an inner block determining whether two global boolean arrays A and B are equal!

The alternative is to introduce only one type “integer array” and only one type “boolean array” and to regard “the domain” as part (aspect) of any value of such type; we must then be able to extract that aspect from any such value. Let ax be an array variable; in its active scope I propose to extract the bounds of the domain from its value by means of two integer-valued functions, denoted by “ax.lob” and “ax.hib” respectively, with the understanding that the domain of the function “ax(i)” extends over all integers i satisfying

| ax.lob ≤ i ≤ ax.hib .

Besides those two I propose a third (dependent) one, “ax.dom”, equal to the number of points in the domain. The three functions satisfy

| ax.dom = ax.hib - ax.lob + 1 ≥ 0 .

(Note that even the empty domain —dom = 0— has a place along the number line: lob and hib remain defined, they then satisfy hib = lob - 1 .)

We have used here a new notation, the dot as in “ax.lob”, “ax.hib” vand “ax.dom”. The names following the dot are what is called “subordinate to the type of the variable whose name precedes the dot”. Following the dot that follows a variable, only names subordinate to the type of that variable may occur and their meaning will be as defined with respect to that type.

Remark 1. In other contexts, i.e. not following the dot, the same names may be used with completely different meaning. We could introduce an array variable named “dom” and in its active scope we could refer to “dom.lob”, “dom.hib” and even “dom.dom” ! Such perversities are not recommended and therefore I have tried to find subordinate names that, although of some mnemonic value, are unlikely candidates for introduction by the programmer himself. (End of remark 1.)

Remark 2. A further reason for using the dot notation rather than the function notation —e.g. “dom(ax)” etc.— is that, unless we introduce different sets of names for these functions defined on boolean arrays and integer arrays respectively —which would be awkward— we are forced to introduce functions of an argument that may be of more than one type, something I would like to avoid as long as possible. (End of remark 2.)

Remark 3. The expression “ax(i)” is used to denote the function value in point i. Only when the value of “ax(i)” is required needs the argument i to be defined and to satisfy

| ax.lob ≤ i ≤ ax.hib .

In view of the dot notation we could regard “ax(i)” as an abbreviation for “ax.val(i)” , where “val” his the subordinate name indicating evaluation in the point as indicated by the value of the further argument i. For each type, such an abbreviation can be introduced just once! Note that also the type “integer” could have a subordinate name “val”, that would enable us to write a little bit more explicitly:

| x:= y.val

instead of the usual and somewhat sloppy x:= y .(End of remark 3.)

For the sake of convenience we introduce two further functions; for the array variable ax they are defined if ax.dom > 0 . They are

| ax.low , defined to be equal to ax(ax.lob) and
| ax.high , defined to be equal tot ax(ax.hib)

They denote the function values at the lowest and the highest point of the domain respectively. They are nothing really new, they are defined in terms of concepts (ready known and in the definition of the semantics of operations on array values we do not need to mention the effect of them explicitly.

As stated above, a scalar variable can be regarded as a function (without argument) that can be changed by assigning a new value to it: such an assignment destroys the information stored as “its old value” completely. We also need operations to change the value of an array variable —without them it would always be an array constant!—but the assignment of a new value to it that is totally unrelated to its old value will play a less central role. It is not that the assignment to an array variable presents any logical difficulties —on the contrary, I am tempted to add— but there is something wrong with its economics. With a large domain size the amount of information stored as “the value of an array variable” can be very large, and neither copying nor destroying such large amounts of information are considered as “nice” operations. On the contrary: in many programming tasks the core of the problem consists of building up an array value gradually, i.e. in a number of steps, each of which can be considered as a “nice” operation, “nice” ln the sense that the new value of the array can be regarded as a “pleasant” derivation of its old value. What makes such operations “nice” or “pleasant” depends essentially on two aspects: firstly, the relation between the old and the new value should be mathematically manageable —otherwise the operations are for us too cumbersome to use— and, secondly, its implementation should not be too expensive for the kind of hardware, that we intend to instruct with our program. The extent to which we are willing to take the latter hardware constraints into account is not a scientific question, but a political one and as a consequence I don‘t feel obliged to give an elaborate justification of my choices. For the sake of convenience I shall be somewhat more liberal than many programmers would be —particularly those that are working daily with machinery, the conceptual design of which is ten or more years old—; on the other hand I hope to be sufficiently aware of the possible technical consequences of my choices, that they remain, if not realistic, at least not totally unrealistic.

Our first modification of the value of an array variable, ax say, does not change the domain size, nor the set of function values, nor their order, it only shifts the domain over a number of places, k say, upwards along the number line. (If k < 0 it is a shift over -k places in the other direction, if k = 0 it is the identity transformation, semantically equivalent to “skip”.) We denote it by

| ax:shift(k) .

Here we have introduced the colon “:”. Its lowest dot indicates in the usual manner that the following name is subordinate to the type of the variable mentioned to its left; the upper dot is just an embellishment (inspired by the assignment operator “:=”), indicating that the value of the variable mentioned to its left is subject to redefinition.

Immediately we are confronted with the question, whether we can give an axiomatic definition of the predicate transformer wp(“ax:shift(E)”, R) . Well, it must be a predicate transformer similar to the one of the axiom of assignment to a scalar variable, but more complicated —and this will be true as well for all the other modifiers of array values— because the value of a scalar value is fully defined by one (elementary) value, while the value of an array variable involves the domain itself and a function value for all points of the domain. Because the value of the array variable ax is fully determined by

| the value of ax.lob ,
| the value of ax.dom and
| the value of ax(i) for ax.lob ≤ i < ax.lob + ax.dom

we can —in principle, at least— restrict ourselves to post-conditions R referring to the array value only in terms of “ax.lob”, “ax.dom” and “ax(arg)” where arg may be any integer-valued expression. For such a post-condition R the corresponding weakest pre-condition

| wp(“ax:shift(E)”, R)

is derived from R by simultaneously replacing

1) | all occurrences of ax.lob by (ax.lob + (E))
2) | all occurrences of (sub)expressions of the form ax(arg) by ax({arg) - (E)) .

Note. If E itself depends on the value of ax , the safest way is to evaluate first for the given R with a completely new name, K say, wp(“ax:shift(K)”, R) , in which then the actual expression E is substituted for K . We have already encountered the same complication when applying the axiom of assignment such as x:= x + f(x). (End of note.)

We give a few examples. Let R be ax.lob = 10 , then

| wp(“ax:shift(ax.lob)”, R) = (ax.lob + ax.lob = 10)
|  | = (ax.lob = 5) .

Let R be (A i: 0 ≤ i < ax.dom: ax(ax.lob + i) = i) , then

| wp(“ax:shift(7)”, R) = (A i: 0 ≤ i < ax.dom: ax(ax.lob + 7 + i - 7) = i)

An alternative way of formulating the weakest pre-condition is

| wp(“ax:shift(E)”, R) = Rax’ → ax

(i.e. a copy of R , in which every occurrence of ax is replaced by ax’),where

| ax’.lob= ax.lob + (E)
| ax’.dom = ax.dom
| ax’(arg) = ax(arg - (E) for any value of arg .

From these three definitions it follows that

| ax’.hib = ax.hib + E
| ax’.low = ax.low
| ax’,.high = ax.high .

Note. Such equalities are meant to imply that if the right-hand side is undefined, the left-hand side is so as well.

For the definition of our further operators we shall follow the latter technique: it describes more clearly how the final value ax‘ depends on the initial value ax .

The next operators extend the domain at either the high or the lows end with one point. The function value in the new point is given as parameter which must be of the so-called “base type” of the array, i.e. boolean for a boolean array, etc. The operators are of the form ax:hiext(x) or ax:loext(x) .

The semantic definition of hiext is given by

| wp(“ax:hiext(x)”, R) = Rax’ → ax

where

| ax’.lob = ax.lob
| ax’.hib = ax.hib + 1
| ax’.dom = ax.dom + 1
| ax’(arg) = x         for arg = ax.hib + 1
|  | = ax(arg)       for arg ≠ ax.hib + 1 .

The semantic definition of loext is given by

| wp(“ax:loext(x)”, R) = Rax’ → ax

where

| ax’.lob = ax.lob - 1
| ax’.hib = ax.hib
| ax’.dom = ax.dom + 1
| ax’(arg) = x         for arg = ax.lob - 1
|  | = ax(arg)       for arg ≠ ax.lob -1 .

Note. Our earlier remark that also the empty domain would have its place along the number line was to ensure that the extension operators hiext and loext are also defined when applied to an array variable with dom = 0 . (End of note.)

The next two operators remove a point from the domain at either the high or the low end. They are only defined when initially dom > 0 holds for the array to which they are applied; when applied to an array with dom = 0 , they lead to abortion. They destroy information in the sense that one of the function values gets lost.

The semantic definition of hirem is given by

| wp(“ax:hirem”, R) = (ax.dom > 0 and Rax’ → ax)

where

| ax’.lob = ax.lob
| ax’.hib = ax.hib - 1
| ax’.dom = ax.dom - 1
| ax’(arg) = undefined         for arg = ax.hib
|  | = ax(arg)         for arg ≠ ax.hib

The semantic definition of lorem is given by

| wp(“ax:lorem”, R) = (ax.dom > 0 and Rax’ → ax)

where

| ax’.lob = ax.lob + 1
| ax’.hib = ax.hib
| ax’;dom = ax.dom - 1
| ax’(arg) : undefined         for arg = ax.lob
|  | ax(arg)         for arg ≠ ax.lob .

For the sake of convenience we introduce two further operations, the semantics of which can be expressed in terms of the functions and operations already introduced: they are

| x, ax:hipop , semantically equivalent to “x:= ax.high; ax:hirem” and
| x, ax:lopop , semantically equivalent to “x:= ax.low; ax:lorem” .

They are given in a notation which is reminiscent of the one for the concurrent assignment; the name following the “:” must be subordinate to the type of the variable immediately before the “:”. Obviously, the other variable x must be of the base type of the array variable ax .

The above modifiers all change the domain of the function, either only its place along the number line or also its size. Two further modifiers will be introduced, modifiers that leave the domain as it stands, but only affect one or two function values.

A very important one does not introduce new function values, but only rearranges them. It is of the form

| ax:swap(i, j) .

It leads to abortion when invoked without both i and j lying in the domain. Its semantics are given by

| wp(“ax:swap(i, j)”, R) = (ax.lob ≤ i ≤ ax.hib and
|  | ax.lob ≤ j ≤ ax.hib and
|  | Rax‘ → ax)

where

| ax’.lob = ax.lob
| ax’.hib = ax.hib
| ax’.dom = ax.dom
| ax’(arg) = ax(j)        for arg = i
|  | = ax(i)        for arg = j
|  | = ax(arg)         for arg ≠ i and arg ≠ j .

Note. Initially i ≠ j is not required: if initially i = j holds. the value of the array variable remains unaffected. (End of note.)

Our last modifier redefines a single function value; it is of the form

| ax:alt(i, x) .

It leads to abortion when invoked without i lying in the domain; the second parameter x must be of the array variable’s base type. Its semantics are given by

| wp(“ax:alt(i, x)”, R) = (ax.lob ≤ i ≤ ax.hib and
|  | Rax“ → ax)

where

| ax’.lob = ax.lob
| ax’.hib = ax.hib
| ax’.dom = ax.dom
| ax’(arg) = x         for arg = i
|  | = ax(arg)        for arg ≠ i .

The operation denoted above as “ax:alt(i, x)” is semantically equivalent to what FORTRAN or ALGOL 60 programmers know as “the assignment to a subscripted variable”. (They would write “AX(I) = X” and “ax[i]:=x” respectively.) I have introduced this operation in the form “ax:alt(i, x)” in order to stress that such an operation affects the array ax as a whole: two functions with the same domain are different functions if they differ in at least one point of the domain. The “official” —or, if you prefer: “puritan”— notation “ax:alt(i, x)” is, however, even to my taste too cumbersome and too unfamiliar and I therefore propose —I too have my weaker moments!— to use instead

| ax:(i)= x

a notation which is somewhat shorter, reminiscent of the so much more familiar assignment statement and still reflecting, by its opening “ax:” that we must view it as affecting the array variable ax. (The decision to write “ax:(i)= x” is not much different from the decision to write “ax(i)” instead of the more pompous “ax.val(i)”.)

None of the previous operators can be used for initialization: they can only change the value of an array under the assumption that it has already a value, they can only occur in the active scope of the array variable. We have not yet introduced the assignment

| ax:= bx

a construct that would do the job. I am, however, very hesitant to do so, because in its full generality “assignment of a value” usually implies “copying a value” and if the domain of the function bx is large, this is not to be regarded as a “nice” operation in present technology: Not that I am absolutely unwilling to introduce “unpleasant” operations, but if I do so, I would not like them to appear on paper as innocent ones. A programming language in which “x:= y” should be regarded as “nice”, but “ax:= bx” should have to be regarded as “unpleasant” would be misleading; it would at least mislead me. A way out of this dilemma is to admit as the right-hand side of the assignment to an array variable only enumerated constants, e.g. of the form

< integer > {, < value of the base type >})

such that

| bx:= (5, true, true, false, true)

would establish

| bx.lob = 5 bx(5) = true
| bx.hib = 8 bx(6) = true
| bx.dom = 4 bx(7) = false
|  | bx(8) = true

The consequence of such a restriction is that assignment of or initialization with a value with a large domain size cannot be written down unnoticed. My expectation is that most initializations will be with values with dom = 0 .

A few concluding remarks are in order.

There is, to start with, the question of economics. My basic assumption is that all operations mentioned in this chapter can be performed at roughly the same price. Some assumption of this nature has to be made, for without it the programming task does not make sense. For instance, instead of writing

| ax:(5)= 7

we could have written the inner block

| begin glovar ax; privar bx;
|  | if ax.lob ≤ 5 and 5 ≤ ax.hib →
|  |  | bx vir int array:= (0);
|  |  | do ax.hib ≠ 5 → bx:hiext(ax.high); ax:hirem od
|  |  | ax:hirem; ax:hiext(7);
|  |  | do bx.dom ≠ 0 → ax:hiext(bx.high); bx:hirem od
|  | fi
| end

but I would like to reject that inner block as a worthy substitute, not so much on account of the length of the text, but on account of its inefficiency. I will not even regard “ax:(5) = 7” as an abbreviation of the above inner block.

With the possible exception of the assignment of an enumerated value I assume in particular the price of all operations independent of the values of the arguments supplied to it: the price of executing ax:shift(k) will be independent of the value of k, the price of executing ax:swap(i, j) will be independent of the values of i and j, etc. with present-day technology these assumptions are not unrealistic.

It is in such considerations that the justification is to be found for my willingness to introduce otherwise superfluous names: we could have restricted ourselves to ax.lob and ax.dom, for whenever we would need ax.hib, we could write

| ax.lob + ax.dom - 1

instead, but that would make the effective use of ax.hib “twice as expensive” as the effective use of ax.lob and our consciousness of this fact could easily twist our thinking. (Worse: it is guaranteed to do so.)

I said that the prices are of the same order of magnitude. What I also mean is “of the same order of magnitude as other things that we consider as primitive”. If the array operations were orders of magnitude more expensive than other operations, we would, for instance, find ourselves invited to replace

| ax:swap(i, j)

by

| if i ≠ j → swap(i, j) ▯ i = j → skip fi

and very quickly we should need to know both the exact price ratios and a very good estimate for the probability of hitting the case “i = j” in order to be able to decide, whether our replacement of ax:swap(i, j) by the alternative construct is actually an improvement or not. I know of mathematicians who revel in such optimization problems, problems of which they sometimes seem to thing that they constitute the central problems of computer programming. I leave these problems gladly to them if they are happy with them: the operations that we prefer to consider as primitive should not confront us with such conflicts. I like to believe that we have more important problems to worry about. A final remark about implementation. It is conceivable that upon initialization of the array variable ax some limits are given: a lower limit for ax.lob, or an upper limit for ax.hib or both, or perhaps only an upper limit for ax.dom. If such “hints to the compiler” are included, a wealth of traditional storage management techniques becomes exploitable. I prefer, however, to regard such “hints to the compiler” not as part of the program: they only make (on some equipment!) a cheaper implementation possible, they represent for the implementation the permission (but not the obligation!) to abort a program execution in which such a stated limit is exceeded.

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD429

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A generalization of the Shaffer Stroke for n-valued logic.

by C.S.Scholten

For binary variables —i.e. ranging over {0, 1}— x and y the “Shaffer Stroke” —a1ias “alternative denial” or “nand”— is the operator —or binary function— denoted by

| x | y

and (usually) defined as

| 1 - x.y .

As 1 - x.y = (x.y + 1) mod 2

and x.y = min(x, y)

an alternative definition is:

| x | y = (min(x, y) + 1) mod 2 .

It is well-known [1] that any binary function of k binary arguments can be expressed using the Shaffer Stroke as the only primitive operator.

In the following we regard n-ary variables —i.e. ranging over {0, 1, ..., n-1}— and shall demonstrate that any n-ary function of k n-ary arguments can be expressed, using as the only operator the generalization

| x | y = (min(x, y) + 1) mod n .

In the following we shall use the notation

| suc(x) = (x + 1) mod n .

in terms of which we can rewrite:

| x | y = suc(min(x, y)) .

Theorem 1. The function suc —as defined above— is expressible.

Proof. suc(x) = x | x

Theorem 2. The function pred —defined by pred(x) = (x - 1) mod n— is expressible.

Proof. pred(x) = sucn-1(x)

Theorem 3. The function min is expressible.

Proof. min(x, y) = pred(x | y)

Note. Because

| min(x, y, z) = min(min(x, y), z) etc.

also the minimum of more than two arguments is expressible. (End of note.)

Theorem 4. For any n-ary constant c the discriminator function dc(x),

given by dc(x) = n - 1 for x = c

| = 0 for x ≠ c

is expressible.

Proof. Because
| sucn-c(x) = 0 for x = c
|  | = 0 for x ≠ c

is expressible.

we have min(1, sucn-c(x)) = 0 for x = c

| = 1 for x ≠ c ,

so that dc(x) = pred(min(1, sucn-c(x))) .

Theorem 5. For any n-ary constant c the weighten discriminator function wc(x, y), given by

| wc(x, y) = y for x = c
|  | = n - 1 for x f c

is expressible.

Proof. min(dc(x), suc(y)) = suc(y) for x = c

| = 0 for x ≠ c

and because pred(suc(y)) = y , we find

| wc(x, y) = pred(min(dc(x), suc(y))) .

Theorem 6. The selector function, defined by

| sel(x, y₀, y₁. ... , yn-1) = yi for x = i

is expressible.

Proof. sel(x, y₀, y₁, ... , yn-1) =

| min(w₀(x, y0). w₁(x, y₁). . wn-1(x, yn_1)) .

The final induction from 2 to k arguments is straightforward.

[1] Shaffer. H.M., A set of five independent postulates for Boolean algebras, with applications to logical constants. Trans.Amer.Math.Soc. vol 14, pp,481-488

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

   EWD 432

Burroughs

PLATAANSTRAAT 5 NUENEN THE NETHERLANDS

DR. EDSGER W. DIJKSTRA

Professor C.A.R.Hoare
Department of Computer Science
The Queen's University of Belfast
BELFAST BT7 1NN
Northern Ireland                                                          13 July 1974

Dear Tony,

I feel guilty for not having given you my reactions to your Stanford report "STAN-CS-73-400: Recursive Data Structures", although I have it already for six months in my possession. I have read it many times, I liked most of it very much and should have told you so much earlier. Please forgive my long reaction time.

In a quite different context I had already used very tentatively "equations" as a kind of "guards" that are to be considered true when the equation has a solution, which then can be used in its guarded statement. I had done so successfully, but only in a very restricted environment; to see you doing something very similar in a much more general environment, was a great encouragement for me, for which I am thankful.

Last week I was doing all sorts of little experiments, introducing new data types with a BNF-notation, like

<record-file> ::= {<record>} <final record>
<transaction> ::= <deletion> | <update> | <insertion> ;

it seemed to work after a fashion, but as soon as I tried to find the correct generalization of the instance I had constructed, I got in a hopeless mess. So, in utter despair, I picked up again your report "Recursive Data Structures" and immediately saw the trap I had fallen into —in spite of having studied your report a number of times: I am very slow-witted and it takes a lot of time to sink in!—. The trap of BNF, of course, being that all generators, as introduced by you, are kept anonymous. And very quickly I found myself dragged into the adhoccery of introducing all sorts of implied transfer functions and the mess was complete. Yet the stupid exercise taught me something, that I would like to try to explain to you.

I started thinking "why introduce such data type definitions in the first place?". For after all, one only introduces an enumerable set of distinct values, and why not just identify them with the integers 0, 1, 2...? The answer is obvious: because we want to introduce operations and functions of these values, operations and functions which become utterly chaotic, when expressed in terms of these identifying integers. It is for that purpose that one needs a more adequate terminology for the description of these values. The first moral is, that the introduction of a new data type can only be justified after the set of operations and functions has been decided upon. (You probably knew this already a long time ago, I even may have read it in your writings; for me it was a good thing to discover this obvious truth in all clarity for myself.)

The next thing I realized is that many such function —see, for instance, EWD428— are not mutually independent, and that the separation between "primitive" and "derived" functions, which is then always possible, is often too arbitrary to be attractive. And it is exactly such an arbitrary choice that your data type definitions force upon us, as long as we insist upon each value being generated in a unique way. For instance, with

type string = simple(letter) | conc(string, letter)

the function "last" —last(abcd) = d— is much better catered for by the syntax than the function "first" —first(abcd) = a—. It does, of course, not help to switch to

type string = simple(letter) | conc(letter, string)

for then we have the misery the other way round. So, I searched for a syntax that would cater equally well for both functions "first" and "last".

The answer is that our syntax must be ambiguous, that our data type definitions must be able to generate the same value in more than one way. This seems in full accordance with well-known types, such as "integer" where we really do not care whether the state x = 21 has been brought about by 17 + 4 or by 13 + 8: its value is more interesting than the history that created it, the fact that different histories can lead to the same value is exactly the sort of information destruction that seems so characteristic of all meaningful computing.

So I would venture

type string = simple(letter) | ass conc(string, string)

indicating explicitly that the generator "conc" is associative; as a result I shall admit in my equations "conc" with more than two arguments, when that is convenient. Then

last(s:string):letter;
last:= case s of
       (simple(v) → v
       [] conc(u, simple(v)) → v
       )

first(s:string):letter;
first:= case s of
        (simple(v) → u
        [] conc(simple(u), v) → u
        )

and finally

sym(s:string):boolean;
sym:= case s of
      (simple(x) → true
      [] conc(simple(x), simple(y)) → x = y
      [] conc(simple(x), y, simple(z)) → x = z and sym(y)
      )

With the unique syntax of the previous page, the coding of the body of "sym" becomes a glorious horror, its execution becomes orders of magnitude worse. You should code it, if you have not already done so yourself. (My guess is that the true LISP-addict won't complain, or, still more foolish, will proudly show his optimizing LISP compiler!)

Instead of inserting the reserved character "ass", telling that the generator "conc" is associative, one could also insert the axiom, say

conc(conc(x, y), z) = conc(x, conc(y, z)),

but I don't know what Pandora's Box we then have opened! It then begins to smell like artificial intelligence, a subject, my safe distance from which I have never had reasons to regret.

As you will realize without me pointing that out, we have now non-deterministic functions like

rot(s:string):string;
rot:= case s of (conc(u, v) → conc(v, u))

(leading to abortion in the case s=simple(x), for which we have not catered; rot(abc) = bca or cab.) Is it the traditional fear for non-deterministic programming languages that has made LISP the way it is?

The above ideas emerged when I tried to tell Carel S.Scholten —with whom I work now quite regularly for more than 20 years!— what I liked about your report and in what respect I had my hesitations. The above ideas are therefore perhaps as much his as mine. The possibility of indicating that a generator is a symmetric function has been mentioned, but not explored.

I hope that in terms of "inspiration" I have repaid some of my debt to you!

cc.:  
R.D.Merrell
D.E.Knuth
C.S.Scholten
M.Woodger

Yours ever

Edsger

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

(list not necessarily exhaustive)

transcribed by Tristram Brelstaff
revised Fri, 3 Jun 2005

EWD435

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Associons: an effort towards accommodating potentially ultra-high concurrency.

|  | by
| Edsger W.Dijkstra, W.H.J.Feijen and M.Rem

The following is a research proposal to investigate the linguistic consequences when it is desired to program for a machine that could work with an ultra-high degree of concurrency. The subject has been suggested by the advent of LSI-techinques that store large amounts of information on essentially active components: once in the far future we may be invited to think of algorithms instructing machines, such that the major part of the logical manipulations will take place distributed all through “the store”.

It is felt that the above invitation could have a deep linguistic consequence: if the purpose of the whole game is a drastic reduction of computation time, we may expect both a reduction of the number of “instructions” to be executed and of the number of “instructions” to be written down. One way of trying to achieve a similar goal is the introduction of large fancy data-types, upon which numerous, powerful operations are defined, the implementation of which allows a considerable —“internal”, if you wish— concurrency. Efforts along those lines that we are aware of, are, however, on this macroscopic scale still purely sequential, at each moment only a very small number of such fancy operands will be actually involved in the computational process. We would like to go a considerable step further, at each moment involving “all of the storage contents” so to speak in the activity.

To achieve the high degree of concurrency by asking the programmer to regulate —i.e. synchronize etc.— explicitly the co-operation between a huge number of possibly all different concurrent sequential processes, seems a dead alley in the sense that the implied programming task will quickly exceed our abilities. It seems more attractive to look for a simple and systematic instruction repertoire such that each “instruction” can interfere in a homogeneous fashion with the total contents of the store. Its interference must be homogeneous, because otherwise there is no hope that we, as programmers, will be able to manage the beast.

In order to avoid misunderstandings, we would like to point out that it is most emphatically not our intention to design a machine. Our “instruction repertoire” can, of course, be interpreted as the functional specifications of a machine; in choosing this instruction repertoire, however, we do not feel ourselves obliged to restrict ourselves in such a way that the corresponding machine could be built realistically with current-day technology. We are perfectly willing to consider functional specifications that would make most hardware designers shudder at the thought of having to build something meeting them! Our primary concern is that the machine will be manageable from the programmers point of view.

In one specific aspect we feel ourselves obliged to be kind to the poor hardware engineer or —to put in another way— to leave the door open: our goal is to write down understandable programs under control of which a highly concurrent activity is possiblie, but not obligatory. An (obvious) underlying desire is to arrange our programs in such a fashion that, in spite of the high potential concurrency, most of the in the mean time developed techniques for the programming of sequential processes remain applicable; (We expect to maintain the “semicolons” but would like powerful “statements” in between!)

As understandability is one of our primary concerns, we shall certainly at the start allow ourselves the luxury that is characteristic of the so-called “higher programming languages”, viz. arbitrarily complicated expressions as components of our commands. In classical environments it is well-known how the evaluation of an arbitrarily complicated (algebraic) expression can be broken down such that a (very) finite arithmetic unit can produce the result. For the time being we just hope that the “breaking down” of our expressions will not present unsurmountable logical difficulties.

*              *
*

Highly associative techniques seem indicated for two reasons. Firstly, associative techniques are a way of distributing an activity (viz. comparing) all through the store; secondly, the potential but not obligatory concurrency could very well make the storage management problem as is cuased by a store consisting of explicitly addressed cells, unmanageable. The desire to use something that smells like “association” is a direct consequence of our desire to broadcast commands that all through the store will be processed in a “homogeneous” fashion.

Having abolished addresses, we have to introduce “names”. We assume the machine able to deal with (values of) variables of type “name”, we assume the cardinality of this type to be high enough. “To deal with” will certainly include the ability to test the equality of two names (as with all types!). Assuming all entities to be referred to, to be indentified by mutually distinct names, any relation between some of these entities can be represented by a relation between their names. If “p₁” through “P₁₀₀” stand for the distinct names of 100 different persons, we may have the relations

fatherof(pi, pj) | meaning: “pi is the father of pj” and
olderthan(pi, pj) | meaning: “pi is older than pj” .

(We then know, for instance, that for any i and j

| fatherof(pi, pj) ⇒ olderthan(pi, pj)

buth not the other way round!)

Instead of representing “all sorts of relations” —such as “fatherof” or “olderthan”— we choose the more general —and neutral!— technique of considering different relations as “named entities” as well,—e.g. named by “fatherof” and “olderthan” respectively—, leaving us with a single universal relations —which, therefore, can remain anonymous— and represent “(fatherof, pi, pj)” and “(olderthan, pi, pj)”.

(Note that we could also have “(implies, fatherof, olderthan)” ! This is to stress that what from one point of view was regarded as “a relation”, from another point of view can be regarded as “an argument”.)

Such an ordered n-tuple of names is called: an “associon”. The contents of the store is considered to be an unordered set of (different) associons. The presence of an associon in store will be interpreted as the truth of the universal relation applied to its arguments, i.e. the members of the n-tuple.

Note 1. For the time being we shall not worry about arithmetic. If so desired we could postulate —i.e. bring into store— the following collection of associons:

(integer, zero) | (nought, zero)
(integer, one) | (suc, zero, one)
(integer, two) | (suc, one, two)
etc. | etc.

as many as we like. (End of note 1.)

Note 2. Many relations are symmetric. As the possibilities are numerous, we shall not make up our mind now. For the time being, we can assume that whenever “(asoldas, pi, pj)” is in store, “(asoldas, pj, pi)” will be in store as well. (Alternatively, we could store besides the specific associon “(asoldas, pi, pj)” the general “(twosym, asoldas)”.) (End of note 2.)

Names occurring as elements of associons in store may occur as constants in our program texts: this facility should enable us to refer to subclasses of associons, e.g. all 3-tuples with “fatherof” in the leading position. We may expect that as the computation proceeds, new names have to be generated: such a new name will be different from any name occurring anywhere in an associon in store or as a constant in our program. We can restrict the rule to “different from any name occurring in an associon in store” when reading in a program , in which the name “fatherof” occurs, gives rise to an 1-tuple associon “(fatherof)” in store. As the creation of associons must anyhow be something that can be ordered by a program, its opening statement could start by greeting these associons, thereby reserving the unique meaning of its constants.

*              *
*

The presence of associons in store is interpreted as recorded truths of facts. The evaluation of a computation is view as the creation of new associons, recording the truths of facts that are implied by already known truths. One truth is fairly universla, it is the truth of “true”; this will be recorded by the irrevocable presence in store of the empty associon “()”. when we refer to “an empty store”, this means “a store containing only “()””.

Besides creating new associons, we shall also —“to save storage space”!— cater for the destruction of associons. This may represent the abolishment of records of truths still valid, but no longer of any interest —e.g. at the end of a computation, an abolishment, very similar to the traditional block exit—, it may also represent that, from now onwards, a (transient) interpretation is no longer valid. In all probability, this second need for associon destruction will only emerge as soon as explicit repetitive mechanisms are introduced.

Note. The insertion “to save storage space” was not made jokingly: destruction of information seems characteristic of all non-trivial machine usage. (End of note)

Above, we have said that the creation of new associons would take place as a recording of truths implied by already recorded truths. To do justice to this observation, we propose —as a rather fundamental language construct— to use the implication for that purpose. Creating the two associons “(fatherof)” and “(olderthan)” could take place by

| () ⇒ (fatherof) and (olderthan)

or by

| () ⇒ (fatherof); ()⇒ (olderthan) .

The idea is that, upon completion of such a statement the “stated implication” holds. If the implication holds to start with, it will act as the empty statement, if not, however, it will react to it by creating missing associons as mentioned at the right-hadn side and not by removing “()”. (This is not unlike the asymmetry of the ALGOL 60 assignment statement “x:= y”.)

Note. For the time being we assume that the semicolon indicates successive execution in the usual way. (End of note.)

The Sheffer Stroke suggests, that we must be able to negate as well; the negation of the left-hand side presents no problem, the creation of “(fatherof)” could then also be prescribed by the (longer) statement:

| non (fathers?) ⇒ (fatherof) .

If “(fatherof)” is present, the implication holds; otherwise, in order to make the right-hand side true, the associon “(fatherof)” is created, whereafter the implication holds. (That in the mean time, the left-hand side has become false, is an admissible side-effect, that does not invalidate that the implication still holds.)

*              *
*

The above suggests a notation for destruction of associons, viz. precede by a negation at the right.hand side, e.g.

| () ⇒ non (fatherof) and non (olderthan)

or

| () ⇒ non (fatherof); () ⇒ non (olderthan) .

Just as the creation can be described without using the universal truth “()”, so can the destruction, viz.

| (fatherof) ⇒non (fatherof) .

*              *
*

In our previous examples the liberty we had when positive terms at the right-hand side could be created or negative terms at the right-hand side could be destroyed was, that as an equation, the implication had only one solution. But what, for constants “A”, “B” and “C”, about

| (A) ⇒ (B) ?

If initially (A) holds, and (B) doesn’t, an associon “(B)” will be created, but when initially (A) is false, both presence and absence of (B) would satisfy the implication. Viewing (B) as stating a fact that can be concluded from the truth of (A), it is not allowed to create (B) —establish that truth!— when (A) does not hold. If, however, the truth of (B) had already been established otherwise, it will remain so. In other words: if (A) does not hold, (B) is left as it is and the little program:

| (A) ⇒ (C); (B) ⇒ (C)

it equivalent to (A) or (B) ⇒ (C) . In other words (A) ⇒ (B) will only change the store contents, when initially (A) and non (B) holds. As long as constant are involved, the above shows that we do not need the or as a connective at the left-hand side. The connective or at the right-hand side, e.g.

| (A) ⇒ (B) or (C)

is still more misplaced: even if the implication is true, we may not arbitrarily conclude either the truth of (B) or (E) or of both. For the time being, the connective “or” will not be used anymore. (The introduction of or at the right-hand side is certainly not a good way of introducing non-determinacy.)

*              *
*

Also the and at the right-hand side should be used with precaution, such as is shown by the trivial example

| () ⇒ (A) and non (A) .

For the time being we shall therefore not use the and at the right-hand side anymore. (Time will show!)

Our format for the left-hand side is new reduced to a conjunction of terms, for the right-hand side to a single term, where a term is a possibly negated associon.

*              *
*

(To be continued.) 18th July 1974

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD439

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Associons continued.

|  | by
| Edsger W.Dijkstra, W.H.J.Feijen and M.Rem

Up till now our original goal, that is high concurrency, has hardly been incorporated. We intend to introduce the possibility of high concurrency by introducing statements operating on sets. But rather than introducing variables, whose values are sets, we propose to characterize sets as “all the solutions of equations”. The unknowns of these equations will be names: in our equations we shall indicate them with the reserved identifiers x0, x1, x2 etc.

For instance, let the store contain a large number of associons of the form (fatherof,“n1”,“n2”), where “n1” and “n2” stand for names of persons. To derive from this genealogy the brother-relation, we would write

| (fatherof,x0,x1) and (fatherof,x0,x2) ⇒ (brotherof,x1,x2) .

Here the expression at the left-hand side of the implication sign is regarded as an equation in the names x0, x1 and x2, and it defines the set of all ordered triples “x0, x1, x2” such that, upon substitution, the two associons mentioned occur in store. For each solution for whivh (brotherof,x1,x2) is not in store it will be created; the amount of concurrency is up to the implementation. The statement terminates when for all solutions of the left-hand side the righthand side holds as well.

The above program records any person with a father as a brother of himself. If that is not the intention, the situation could be adjusted by adding a next statement

| (brotherof,x0,x0) = non (brotherof,x0,x0) .

Note: For the time being we impose upon ourselves the rule that the set of solutions must be fully determined by the equation at the left-hand side. As a result no x at the right-hand side may occur that does not occur at the left-hand side as well, and we, therefore, do not admit as a replacement for our last statement

| () ⇒ non (brotherof,x0,x0);

according to our rule that only associons of the form mentioned at the right-hand may be created or destroyed

| (brotherof,c0,c0) ⇒ non ()

is equally inacceptable. (End of note.)

For all unknowns that occur only once in a statement —i.e. once at the left-hand side and not at the right-hand side— it seems a bit superfluous to give that unknown a specific name. For instance, if we want to create associons indicating who is a father, we could of course do it with

| (fatherof,c0,x1) = (isfather,x0)

but in the solution set, as defined by the left-hand side, a father with five sons occurs five times, while we know that we only need him once. We propose the notation

| (fatherof,c0,?) ⇒ (isfather,c0) .

The question-mark has the function of the existential quantifier: (fatherof,n, holds if and only if there exists at least one person of whom n has been recorded to be the father. Viewed in terms of “associon matching” refers to a don’t care position.

We may also have it at the right-hand side, provided that the term is negated:

| () ⇒ non (fatherof,?,?);

would destroy the whole genealogy.

We do allow the question-mark in a negated term at the left-hand side as well, e.g.

| (fatherof,?,c0) and non (fatherof,c0,?) ⇒ (nooffspring,x0) .

The term (fatherof,?,x0) requires the presence of an associon telling that x0 is a son, the term non (fatherof,c0,?) requires the total absence of associons of three elements, the first two of which are fatherof and “x0” respectively.

To create the above set of associons “nooffspring” without a question-mark is very painful. It could be done by

| (fatherof,x0,x1) ⇒ (nooffspring,x1);
| (fatherof,c0,x1) ⇒ non (nooffspring,c0)

The first one makes all sons in the class nooffspring, the second removes from that class all fathers.

What would have failed to work is

| (fatheroff,x1,x0) and non (fatherof,x0,x2) = (nooffspring,x0) .

The term non (fatherof,x0,x2) is no restriction at all, because there are nearly infinitely many values of x2, such that the associon (fatherof,x0,x2) is absent. We, therefore, insist upon the rule that

| | a negative trem at the left-hand side may contain no x that does not
| | occur in a positive term of that left-hand side as well.

Note. The failing statement above cannot be corrected by adding positive terms containing x2 at the left-hand side. (End of note.)

*              *
*

Let for any node name n, n1, n2,

| (r0,n) <=> “n is the name of a node of a given directed graph”
| (r1,n1,n2) <=> “the directed edge from n1 to n2 belongs to the given directed graph.”

Let it be requested to generate all associons:

| (r2,n1,n2) <=> “from.n1 the node n2 can be reached.”

Program 1.

| (r0,x0) ⇒ (r2,x0,x0);
| (r2,x0,x1) and (r1,x1,x2) ⇒ (r2,x0,x2)

The first line expresses that each node can be reached from itself; the second line expresses the rest. Note that, as solutions of the left-hand side are found and new associons are created, new solutions to the left-hand side are possible. The statement stops when the transitive closure has been formed.
Program 2.

| (r0,x0) = (r2,x0,x0);
| (r1,x0,x1) = (r2,x0,x1);
| (r2,x0,x1) and (r2,x1,x2) ⇒ (r2,x0,x2)

In program 2 the possible concurrency in the last statement may grow more rapidly than in program 1. (With N nodes in a directed ring, program 1 is linear in N, program 2 in logN.)

*              *
*

When no three points are on the same line, let

| (r0,n) <=> “n is the name of a point in the plane”.
| (r1,n1,n2,n3) <=> “n1,n2,n3 is a clock-wise triangle.”

Requested (r2,n1,n2) <=> “n1,n2 is an edge of the clock-wise convex hull.”
Program

| (r1,x0,x1,?) and non (r1,x1,x0,?) = (r2,x0,x1) .

*              *
*

Let

| (r0,n) <=> “n is the name of a node”.

We would like to select an arbitrary node, i.e. we should like to create exactly one associon

| (r1,n) <=> “n is the chosen node”.

We cannot write

| (r0,x0) = (r1,x0)

because that would select all nodes. We could try the following one

| (r0,x0) and non (r1,?) ⇒ (r1,x0) . | (1)

This is OK under the assumption that the implementation selects only one solution of the left-hand side at a time: it would select e.g. x0 = nl, then create (r1,n1) and then it would stop. However, we would not like to impose this non-concurrency as a general requirement, i.e. we would like this statement also to allow that an unknown number of nodes is selected, n1 through nk, and that for all of them (r1,ni) is created. In short: our statement selects an arbitrary non-empty subset of the set of nodes. (If the given set is empty, the selected set is empty as well.) Well, (1) is a nice, non-deterministic tool, but it is still not a way for selecting exactly one!

Alternatively: if we cannot select one, can we remove all but one? With the aid of

| (r1,n1,n2) <=> “n1 is n2”

we could try

| (r0,x0) = (r1,x0);
| (r0,x0) = (r2,x0,x0);
| (r1,x0) and (r1,x1) and non (r2,x0,x1) ⇒ non (r1,x1)

but this works equally bad: if x0,x1 is a solution, so is x1,x0 and the last two associons of the type (r1,n) could disappear simultaneously.

A new tool seems indicated: we must be able to prescribe that we only need one solution. We shall do so by using instead of the x, the equally reserved identifier y and the selection of the unique node will be accomplished by

| (r0,y0) and non (r1,?) ⇒ (r1,y0) .

The term non (r1,?) is obligatory, because

| (r0,y0) ⇒ (r1,y0)

would still copy the whole set, be it one at a time: as long as there are solutions of the left-hand side that do not satisfy the right-hand side, the game proceeds as usual.

Let it be required to order the nodes in an arbitrary permutation, i.e.

| (r3,n1,n2) <=> “n1 is n2’s left-hand neighbour.”

Program:

| (r0,y0) and non (r3,?,?) ⇒ (r3,handle,y0);
| (r3,?,y0) and non (r3,y0,?) and (r0,y1) and non (r3,?,y1) ⇒ (r3,y0,y1);
| () ⇒ non (r3,handle,?)

The constant “handle” has been introduced such that :

| (r3,?,n) <=> “n has been placed in the sequence”.

The left-hand side of the second statement is in words: y0 must occur in the sequence without right-hand neighbour and y1 must be a node not in the sequence. Frased that way, it is not too bad.

Here we have our first equation with two y’s. It means: select from all solutio —as if they had been x’es!- exactly one sing1e pair. What about x’es and y’s occurring in the same left-hand equation?

Let us have one x and one y in a left-hand side equation. The corresponding solution set could be either:
a)     every possible value of x combined with one then possible value of y.
b)     one value of y combined with all then possible values of x. The choice we have is due to the fact that the universal and the existential quantifier do not commute.

We propose to distinguish between the two cases by the way in which we number our unknowns; and to indicate

case a) |     by     | x0 y1
case b) |     by     | y0 x1.

The set of solutions for an equation in

| z0,z1, ... ,zn

where z may either be an x or an y, is given recursively as follows:

We start with one empty k-tuple for k = 0.
If zk = xk,

| each k-tuple gives rise to as many k+1-tuples that we can form by extending
| it with a permissible value for xk; each k-tuple gives rise to at least one
| k+1-tuple;

If zk = yk,

| each k - tuple gives rise to exactly one k+1-tuple that we can form by
| extending it with an arbitrary permissible value for yk.

The set of n+1 tuples is our set of solutions.

Note 1. The relative ordering of succesive x’es is irrelevant; so is the relative ordering of successive y’s. (End of note 1)

Note 2. When in a statement all x’es are replaced by y’s, its activity is equal to a possible activity of the original form, because the concurrency when x’es are present is not obligatory. They are therefore identical when the statement with the x’es is deterministic. (End of note 2)

Note 3. We don’t expect much use of complicated alternation of x’es and y’s in the ordered sequence of unknowns. (End of note 3)

*              *
*

Let for N different values of n

| (r0,n) <=> “n is the name of a node”.

Let it be requested to form N-1 associons

| (r1,n1,n2) <=> “n1,n2 is a directed edge of an arbitrary rooted spanning tree.”

Program:

| (r0,y0) and non (r1,?,?) ⇒ (r1,handle,y0);
| (r0,x0) and non (r1,?,x0) and (r1,?,y1) ⇒ (r1,y1,x0)
| () ⇒ non (r1,handle,?)

The middle statement has the property thet many new nodes may be attached simultaneously to the tree, but no one in more than one way: a merging of branches is excluded. Different new nodes may be attached simultaneously to the same old one.

*              *
*

(To be continued.)

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD 440

The problem of the most isolated villages.

We consider n villages (n > 1), numbered from 0 through n–1; for 0 ≤ i < n and 0 ≤ j < n, a computable function f(i, j) is given, satisfying for some given positive constant M:

for i ≠ j : 0 < f(i, j) < M

for i = j : f(i, j) = M       .

For the i-th village, its isolation degree “id(i)” is given by

id(i) = | minimum | f(i, j) = | minimum | f(i, j)
| j ≠ i |  | j |

(Here f(i, j) can be interpreted as the distance from i to j; the rule f(i, j) = M has been added for the purpose of the above simplification.)

We are requested to determine the set of maximally isolated villages, i.e. the set of all values of k such that

(∀ h: 0 ≤ h < n: id(h) ≤ id(k))     .

The program is expected to deliver this set of values as

miv(miv.lob), ... , miv(miv.hib)

Note that eventually all values 1 ≤ miv.dom ≤ n are possible.

A very simple and straightforward program computes the n isolation degrees in succession and keeps track of their maximum value found thus far. On account of the bounds for f(i, j) we can take as the minimum of an empty set the value M and as the maximum of an empty set 0.

begin glocon n, M; virvar miv; privar max, i;
      miv vir int array := (0); max vir int, i vir int := 0, 0;
      do i ≠ n →
      begin glocon n, M; glovar miv, max, i; privar min, j;
            min vir int, j vir int := M, 0;
            do j ≠ n →
                  do f(i, j) < min → min:= f(i, j) od;
                  j:= j + 1
            od {min = id(i)};
            if max > min → skip
             ▯ max = min → miv:hiext(i)
             ▯ max < min → miv:= (0, i); max:= min
            fi;
            i:= i + 1
      end
      od
end

The above is a very unsophisticated program: in the innermost loop the value of min is monotonically non-increasing in time, and the following alternative construct will react equivalently to any value of min satisfying min < max. Combining these two observations we conclude that there is only a point in continuing the innermost repetition as long as min ≥ max. We can replace the line “do j ≠ n →” therefore by

“do j ≠ n and min ≥ max →”

and the assertion after the corresponding od by

{ id(i) ≤ min < max or id(i) = min ≥ max }     .

Let us call the above modification “Optimization 1”.

A very different optimization is possible if it is given that

f(i, j) = f(j, i)

and —because the computation of   f   is assumed to be time-consuming— it is requested never to compute f(i, j) for such values of the argument that f(j, i) has already been computed. Starting from our original program we can achieve that for each unordered argument pair the corresponding f-value will only be computed once by initializing j each time with i+1 instead of with 0 —only scanning the upper triangle of the symmetric distance matrix, so to speak—. The program is then only guaranteed to compute min correctly provided that we initialize min instead of with M with

.minimum |   f(i, h)
0 ≤ h < i |                         .

This can be catered for by introducing an array, b say, such that for k satisfying i ≤ k < n:

for i = 0  :   b(k) = | M
for i > 0  :   b(k) =  | minimum |   f(k, h)
| 0 ≤ h < i

(In words: b(k) is the minimum distance connecting village k that has been computed thus far.)

The result of Optimization 2 is also fairly straightforward.

begin glocon n, M; virvar miv; privar max, i, b;
      miv vir int array := (0); max vir int, i vir int := 0, 0;
      b vir int array := (0); do b.dom ≠ n → b:hiext(M) od;
      end {all virgin variables at outer level are initialized};
      do i ≠ n →
      begin glocon n; glovar miv, max, i, b; privar min, j;
            min vir int, b:lopop; j vir int := i + 1;
            do j ≠ n →
            begin glocon i; glovar min, j, b; privar ff;
                  ff vir int := f(i, j);
                  do ff < min → min:= ff od;
                  do ff < b(j) → b(j)= ff od;
                  j:= j + 1
            end
            od {min = id(i)};
            if max > min → skip
             ▯ max = min → miv:hiext(i)
             ▯ max < min → miv:= (0, i); max:= min
            fi;
            i:= i + 1
      end
      od
end

To try to combine these two optimizations presents a problem: in Optimization 1 the scanning of a row of the distance matrix is aborted if min has become small enough, in Optimization 2, however, the scanning of the row is also the scanning of a column and that is done to keep the values of b(k) up to date. Let us apply Optimization 1 and replace the line “do j ≠ n →” by

“do j ≠ n and min ≥ max →”           .

The innermost loop can now terminate with j < n; the values b(k) with j ≤ k < n, for which updating is still of possible interest are now the ones with b(k) ≥ max, the other ones are already small enough. The following insertion will do the job:

do j ≠ n →
        if b(j) < max → j:= j + 1
            ▯ b(j) ≥ max →
            begin glocon i; glovar j, b; privar ff;
                ff vir int := f(i, j);
                do ff < b(j) → b(j)= ff od
                j:= j + 1
            end
        fi
od

The best place for this insertion is immediately preceding “i:= i + 1”, but after the adjustment of max: the higher max, the larger the probability that a b(k) does not need any more adjustments.

*         *         *

The two optimizations that we have combined are of a vastly different nature: Optimization 2 is just “avoiding redoing work known to have been done”, and its effectiveness is known a priori. Optimization 1, however, is a strategy whose effectiveness depends on the unknown values of f: it is just one of the many possible strategies in the same vein.

We are looking for those rows of the distance matrix whose minimum element value S exceeds the minimum elements of the remaining rows and the idea of Optimization 1 is that for that purpose we do not need to compute for the remaining rows the actual minimum if we can find for each row an upper bound Bi for its minimum, such that Bi < S. In an intermediate stage of computation, for some row(s) the minimum S is known because all its/their elements have been captured; for other rows we only know an upper bound Bi. And now the strategic freedom is quite clear: do we first compute the smallest number of additional matrix elements still needed to determine a new minimum, in the hope that it will be larger than the minimum we had and, therefore, may exceed a few more B’s? Or do we first compute unknown elements in rows with a high B in the hope of cheaply decreasing that upper bound? Or any mixture?

My original version combining the two strategies postponed the “updating of the remaining b(k)” somewhat longer, in the hope that in the mean time max would have grown still further, but whether it was a more efficient program than the one published in this chapter is subject to doubt: it was certainly more complicated, needing yet another array for storing a sequence of village numbers. The published version was only discovered when writing this chapter.

In retrospect I consider my ingenuity spent on my original program as wasted: if it was “more efficient” it could only be so “on the average”. But on what average? Such an average is only defined provided that we postulate —quite arbitrarily!— a probability distribution for the distance matrix f(i, j). On the other hand, it was not my intention to tailor the algorithm to a specific subclass of distance matrices!

The moral of the story is that, in making a general program, we should hesitate to yield to the temptation to incorporate the smart strategy that would improve the performance in cases that might never occur, if such incorporation complicates the program notably: simplicity of the program is a less ambiguous target. (The problem is that we are often so proud of our smart strategies that it hurts to abandon them.)

Remark. Our final program combines two ideas and we have found it by first considering —as “stepping stones”, so to speak— two programs, each incorporating one of them, but not the other. In many instances I found such stepping stones most helpful. (End of remark.)

transcribed by Corrado Cantelmi
revised 14-Mar-2012

EWD442

Inside "Mathematics Inc.".

From the Private Correspondence of the Chairman of the Board:

"In passing it is a pleasure to inform you that Mathematics Inc. fully lives up to its device "Semper floreat et crescat." Recently the chairman of its board has been invited to deliver the keynote address at the the 108th Annual Meeting of the International Federation of Mathematical Societies IFMS, to be held in the fall of 1976 in Loempia, the capital of Angora. In order to reflect the international recognition we are considering to move to more sumptuous appartments, viz. the top twelve floors of the Hosanna Building. But the negotiations are very difficult, as the even floors are owned by mr.J.Simpson —not the well-known J.F.Simpson, just J.Simpson— while the odd floors are the property of a certain mr.Hayes, mr.Simpson's father-in-law's brother, a very old gentleman who considers himself a keen businessman. His price is exorbitant and his conditions are utterly preposterous: currently he wishes to impose upon our personnel that they will only use the toilets on Simpson's floors! To appease the old gentleman we may have to install —at our expense, of course— a Toilet Flushing Water Recycling System; I have already contacted an architect. Mr.Hayes, however, is already 87 and his health, I am told, is not too good.

But as you will understand, all these negotiations, time-consuming as they are, make me a very occupied man, and whether I can accept the IFMS invitation depends on whether I can find a free weekend to write my address; the deadline is 1st October 1974 (in duplicate, double-spaced)."

From an address to the senior staff members:

"As token of our deeply felt gratitude for what he has done for the Company we shall send a large bunch of orchids to mr.Hayes, the weary traveller who has, at last, reached his final destination...."

From the minutes of the Board of Directors:

"Our Manager International Promotion has reported political troubles in some countries, caused by the fact that in our Brochure MX-785-5456-a: "What Counts what Counts", a reference is made to "Arabic Numerals"; a quick investigation has shown that a switch to "Arabian Numberal" whould solve the problems there, but would create similar difficulties in the rest of the world. If switching to "Arabesque Numerals" is not an internationally acceptable solution, we shall try to escape nationalization by delegating, where necessary, our activities to a full daughter "Algebraics Inc." After a long and nostalgic monologue by our Chairman about the good old days when we were not operating on a multinational basis, the Meeting returns to the order of the day. The decision is postponed until the next meeting."

Transcription by Matthew Singletary.
Last revised on Mon, 13 Nov 2006.

Copyright Notice

The following manuscript

EWD 443: A Multidisciplinary Approach to Mathematics

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 56-59 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN: 0�387�90652�5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

EWD 443

A Multidisciplinary Approach to Mathematics

by Edsger W.Dijkstra *)

(Extracts from the keynote address to be delivered at the 108th Annual Meeting of the International Federation of Mathematical Societies (IFMS) at Loempia, Angora, Monday 11 - Friday 15 October 1976.)

*)     | Authors address:
| Mathematics Inc.
| Hosanna Building.

Ladies and Gentlemen,

Now and again the great public is taken by surprise by the announcement of some startling discovery, some exciting invention breakthrough, and they cannot but get the impression that such things happen suddenly, even the scientists themselves being utterly unprepared for it. But the student of the history of science knows differently: even if he cannot smooth the discontinuity completely, he knows that in all cases such a breakthrough is the natural consequence of a usually long preparation —be it hidden for the casual observer— like the development of a carbuncle, deep under the skin.

The same holds for the current breakthrough in the practice of Mathematics, for which, as I hope to show, the seeds have been sown during the last three decades. For, this time the breakthrough did not only surprise the outsiders, it surprised many mathematical insiders as well, the reason being that the first seeds were sown and took root outside the Mathematical world itself.

We all still carry with us the cherished and endearing image of the Mathematician as it has come to us through the ages: half genius, half nitwit, partly deep thinker and partly just juggler with symbols, a man so absorbed by his own artificial world that he hardly belongs to the real one. Are not Archimedes’ words to the Roman soldier: “Don’t disturb my circles!” the archetypical ones? And when the Roman soldier did as is usually done with someone who is not understood, and killed Archimedes with a single thrust of his glorious sword, we all feel that sword piercing our own romantic hearts....

The image may have been a true one, but World War II has changed the world: it caused a collision not only between nations, but between sciences and between different walks of life as well. The intercommunication has broken the isolation, the lonely scientist burning the midnight oil has been replaced by the scientific worker keeping normal office hours, the romantic thinker believing in truth for truth’s sake has been replaced by the businesslike and efficient solver of problems of social, economic and technical relevance.

As Chairman of the Board of “Mathematics Inc.” —now the world’s leading mathematical industry with a firm grip on more than 75 percent of the world market— I am in a better position than anyone else to give you all the inside information about the refreshing breeze that has blown new life into the mathematical science, at a moment that it was getting stale and in danger of dying of old age.

*         *         *

The decision to give the mathematical industry, for the first time in history, a solid foundation based on market research has, of all the changes, probably had the most profound effect. For instance, one of the most successful discoveries of our sales department was directly related to a significant trend in today’s civilization, viz. the use of square tiles instead of wall-to-wall carpeting. The result was a revolutionary re-edition of the old-fashioned multiplication tables, but now, in order to ease the estimation of the number of tiles needed, in the form of a two-colour halftone division table. Its title alone “Tiles for Everyone.” is, all by itself, a masterpiece of mathematical popularization. (Our original title “Tile estimations made understandable for the layman.” was completely demolished by our sales department as being too condescending; so was our next effort “Tile estimations made easy.”.) In a sense, it was only a minor product, but in another sense it was the beginning of a mathematical revolution: as for years this table has been responsible for over 20 percent of our revenue, it has taught us all, that in the past, mathematicians, guided by their intuition instead of by scientific market research, have tackled the wrong problem.

*         *         *

Another discovery, perhaps surprising for the older ones among you, is that there is absolutely no market for the so-called “eternal truths” previous generations of mathematicians have been after. But we have understood that in the world of fast progress we are living in now, the only important results are those with a halflife of at most five years. As in the traditional mathematical papers the delay between submission of a paper and its eventual publication is of the same order of magnitude, we had to bypass the established channels, but as the lack of referees with social responsibility forced us to do so anyhow, this posed no additional problem.

*         *         *

We have also found that, as important as what you publish, is how you publish it. A small example: when it was made a company regulation to replace “etc.” —as most readers are not quite sure of which obsolete Latin expression this is an abbreviation— by the more homely “and so on”, sales immediately jumped by more than 15 percent! That shows what public relations can do for mathematics!

*         *         *

The mathematical establishment works on paper that is higher than wide. Our ergonomics department did a work analysis and discovered that the hand’s horizontal mobility exceeds its vertical mobility by a factor of 1.4 and, as a result, it became a company rule to turn the normal office paper over 90 degrees. The results were startling. At first, Productivity Control was very disappointed, because, after the change, productivity measured —as they were used to— in lines of mathematics produced per manday seemed to have decreased slightly. Measured in number of symbols written down per manday, however, the increase was significant! Measured in number of pages of mathematics produced per manday the improvement was still more striking! Needless to say, the discovery of that last productivity unit must be considered as one the greatest recent contributions to the gross national product in all countries where we are represented. (White, oval office paper has been tried, but the experiment has been abandoned: it led to too many circular arguments.)

*         *         *

As a company with the avowed aims of not enriching itself at the expense of others, but to work for the benefit of our total civilization, a thorough study has been made of the thresholds that, traditionally, restrict the benefits of bourgeois mathematics to an elite minority. As a socially responsible organization, and also from market considerations, we felt it, already early in the company’s history, as one of our primary duties to try to bring Mathematics to the Millions. The major stumbling block turned out to be the abundant use of Greek and Hebrew characters and other fancy symbolisms, which, since then, have been rigorously abolished. (The re-education of our mathematical staff, implied by this abolishment, I am sorry to say, has not been without problems, because, although apparently converted, many staff members tended to persist in their bad habits in secret. A number of strong measures, based on undeniable evidence of guilt from the staff member’s wastepaper baskets, has implemented the ultimate solution to the Greek-and-Hebrew-letter problem.) As new educational experts —so-called “enlightening specialists”— have been attracted, we are confident that future re-orientations of out technical staff will be implemented so smoothly as to remain totally unnoticed by them.

We have taken this measure, as new re-orientations are only to be expected: a current experiment to restrict, for instance, the use of the alphabet to that of capital letters only, is underway and looks very promising. In retrospect, it is no surprise that, in spite of a tradition of 2500 years, Mathematics has no more achieved than the little it has: all through those 25 ages, a thorough scientific study of the Man-Paper Interface has never been made!

*         *         *

Compressed into a single sentence my message is that the Interdisciplinary Approach to Mathematics will lead to a better world. The chains of inhuman formalism being broken, intellectual slavery will become intellectual freedom, “the happy few” will become “the happy many”! *)

And finally, for Mathematics in general, and for Mathematics Inc. in particular —what, after all, is the difference?— I can only end with the deeply felt prayer: “Semper floreat et crescat.”!

*)     For those interested in further details, we refer to “A Guide to Positive Problem-Solving” to be published shortly by the Hosanna Press.

11th August 1974

transcribed by Corrado Cantelmi
revised ...

EWD447

On the role of scientific thought.

Essentially, this essay contains nothing new, on the contrary: its subject matter is so old, that sometimes it seems forgotten. It is written in an effort to undo some of the more common misunderstandings that I encounter (nearly daily) in my professional world of computing scientists, programmers, computer users and computer designers, and even colleagues engaged in educational politics. The decision to write this essay now was taken because I suddenly realized that my confrontation with this same pattern of misunderstanding was becoming a regularly itself repeating occurrence.

Whether the misappreciation of the proper role of scientific thought that I observe within the "computing community" is a phenomenon that is specific for the computing community, or whether it also a current phenomenon in other disciplines, is not for me to judge. One thing seems certain: in the computing community itself we can find enough historical explanation, and we don't need to look for outside influences when we try to understand how the phenomenon came about. (This is not meant to say, that those outside influences have been absent!)

As we shall see in a moment, the adjective "scientific" when used in the expression "scientific thought" more refers to a way of thinking than to what are the thoughts about: to use the Latin expressions: it refers to the "quo modo" rather than to the "quod". This partly explains why the tradition of scientific thought has only been imported into the computing world to such a limited extent by the many pioneers who immigrated in the early days from other scientific disciplines. The early academics who became involved with computers all had had their training in other scientific disciplines and many of them were quite able to practice "scientific thought" in their original field of intellectual activity. But for a great number of them, that had been the only confrontation with scientific thought. As a result, it is understandable that they associated their notion of scientific thought as much with the specific field in which they had practiced it as with a general way of thinking that could (and should!) be transferred to their new field of activity. In addition, many of them must have felt that scientific thought was a luxury that one could afford in the more established disciplines, but not in the intellectual wilderness they now found themselves in. But, as we shall also see in a short while, scientific thought is not a luxury made possible in established scientific disciplines, on the contrary: it has been the tool that has made the establishment of those disciplines possible!

Besides emigrants from other academic fields, the computing world has attracted people from all over the world: businessmen, administrators, operators, musicians, painters, unshaped youngsters, you name it, a vast majority of people with no scientific background at all. By their sheer number they form all by themselves already an explanation for the phenomenon.

To introduce the subject, I would like to quote two paragraphs from a letter that I recently wrote to one of my professional friends.

"Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one's subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects. We know that a program must be correct and we can study it from that viewpoint only; we also know that it should be efficient and we can study its efficiency on another day, so to speak. In another mood we may ask ourselves whether, and if so: why, the program is desirable. But nothing is gained —on the contrary!— by tackling these various aspects simultaneously. It is what I sometimes have called "the separation of concerns", which, even if not perfectly possible, is yet the only available technique for effective ordering of one's thoughts, that I know of. This is what I mean by "focussing one's attention upon some aspect": it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect's point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously.

"I remember walking with Ria when we were engaged —it was near Amsterdam's Central Station— when I explained to her that I wanted to be glad and happy with my eyes fully open, without fooling myself in the belief that we lived in a pink world: to be happy to be alive in the full knowledge of all misery, our own included...." (End of quotation.)

Scientific thought comprises "intelligent thinking" as described above. A scientific discipline emerges with the —usually rather slow!— discovery of which aspects can be meaningfully "studied in isolation for the sake of their own consistency", in other words: with the discovery of useful and helpful concepts. Scientific thought comprises in addition the conscious search for the useful and helpful concepts.

The above should make it clear that I want to discuss the role of scientific thought for the sake of its practical value, that I want to explain my pragmatic appreciation of a tool. It is no slip of the pen that the above quotation refers to the "effective ordering of one's thoughts": the efficiency of our thinking processes is what I am talking about. I stress this pragmatic appreciation because I live in a culture in which much confusion has been created by talking about the so-called "academic virtues" (sic!) with moral, ethical, religious and sometimes even political overtones. Such overtones, however, only confuse the issue. (If you so desire, you may observe here scientific thought in action: I do, for instance, not deny political aspects, I would be a fool if I did so! The anti-intellectualistic backlash against "the technocrats" that is so en vogue today, is inspired by a —largely unjustified— fear for the power of him who really knows how to think and by a —more justified— fear for the actions of him who erroneously believes to know how to think. These political considerations, however, have nothing to contribute to the technical problem of ordering one's thoughts effectively, and that is the problem that I want to discuss "in isolation, for the sake of its own consistency".)

I intend to describe for your illumination the most common cases in which the "average" computing scientist fails to separate the various concerns; in doing so I hope and trust that my colleagues in the profession do interpret this as an effort to help them, rather than to insult them. For the sake of the non-professional, I shall present the least technical cases first.

One of the concerns, the isolation of which seems most often neglected, is the concern for "general acceptance". (In the world of pure mathematics —with which I have some contacts— this problem seems to be fairly absent.) The concern itself is quite legitimate. If nobody reads the poems of a poet that wanted to communicate, this poet has failed, at least as a communicating poet. Similarly, many computing scientists don't just solve problems, but develop tools: theories, techniques, algorithms, software systems and programming languages. And if those, that —they feel— could profit from their designs, prefer to ignore these inventions and to stick to their own, old, rotten routines, the authors get the miserable feeling of failure. Have they? Yes and no. They can adopt the Galileian attitude: "Nothing becomes true because tenthousand people believe it, nor false because tenthousand people refuse to do so.", and can decide to feel themselves, in splendid isolation, superior to their fellow computer scientists for the rest of their lives. I can deny no inventor who feels underappreciated, such a course of action. I don't recommend it either: the sterile pleasure of being right tends to get stale in the course of a lifetime. If one's aim is to design something useful, one should avoid designing something useless, because unused: in other words, I fully accept "general acceptance" as a legitimate concern. We must, however, be willing to ignore this concern temporarily —for a few days or a few years, depending on what we are undertaking— for unwillingness to do so will paralyze us.

Some time ago I visited the computing center of a large research laboratory where they were expecting new computing equipment of such a radically different architecture, that my colleagues had concluded that a new programming language was needed for it if the potential concurrency were to be exploited to any appreciable degree. But they got their language design never started because they felt that their product should be so much like FORTRAN that the casual user would hardly notice the difference "for otherwise our users won't accept it". They circumvented the problem of explaining to their user community how the new equipment could be used at best advantage by failing to discover what they should explain. It was a rather depressing visit....

The proper technique is clearly to postpone the concerns for general acceptance until you have reached a result of such a quality that it deserves acceptance. It is the significance of your message that should justify the care that you give to its presentation, it may be its "unusualness" that makes extra care necessary. And, secondly, what is "general"? Has Albert Einstein failed because the Theory of Relativity is too difficult for the average highschool student?

Another separation of concerns that is very commonly neglected is the one between correctness and desirability of a software system. Over the last years I have lectured for all sorts of audiences about the techniques that may assist us in designing programs such that one can prove a priori that they meet their specifications. One of the standard objections raised from the floor is along the following lines: "What you have shown is very nice for the little mathematical examples with which you illustrated the techniques, but we are afraid that they are not applicable in the world of business data processing, where the problems are much harder, because there one always has to work with imperfect and ambiguous specifications." From a logical point of view, this objection is nonsense: if your specifications are contradictory, life is very easy, for then you know that no program will satisfy them, so, make "no program"; if your specifications are ambiguous, the greater the ambiguity, the easier the specifications are to satisfy (if the specifications are absolutely ambiguous, every program will satisfy them!).

Pointing that out, however, seldom satisfies the man who raised the objection. What he meant, of course, was something different. He meant something along the following lines: "We make something with the best of intentions in the hope of satisfying a need as we understand it, but when our product has been put into action, it does not perform satisfactorily and how are we to discover whether we have correctly made the wrong thing or whether there is just a silly bug somewhere?". The point is that that this question is empty as long as the specifications do not define — are not accepted to define by definition — what the system is supposed to do. It is like asking the judge to settle a business dispute caused by the absence of a contract stating the mutual rights and obligations. It is the sole purpose of the specifications to act as the interface between the system's users and the system's builders. The task of "making a thing satisfying our needs" as a single responsibility is split into two parts "stating the properties of a thing, by virtue of which it would satisfy our needs" and "making a thing guaranteed to have the stated properties". Business data processing systems are sufficiently complicated to require such a separation of concerns and the suggestion that in that part of the computing world "scientific thought is a non-applicable luxury" puts the cart before the horse: the mess they are in has been caused by too much unscientific thought.

But from the above, please don't conclude that unscientific thought is restricted to the business world! In Departments of Computing Science, one of the most common confusions is the one between a program and its execution, between a programming language and its implementation. I always find this very amazing: the whole vocabulary to make the distinction is generally available, and also, the very similar confusion between and computer and its order code, remarkably enough, is quite rare. But it is a deep confusion of long standing. One of the oldest examples is presented by the LISP 1.5 Manual: halfway their description of the programming language LISP, its authors give up and from then onwards try to complement their incomplete language definition by an equally incomplete sketch of a specific implementation. Needless to say, I have not been able to learn LISP from that booklet! I would not worry, if the confusion were restricted to old documents, but, regretfully enough, the confusion is still very popular. At an international summer school in 1973, a very well-known professor of Computing Science made the statement that "ALGOL 60 was a very inefficient language", while what he really meant was that with the equipment available to him, he and his people had not been able to implement ALGOL 60 efficiently. (That is what he meant, he did not mean to say it!) Another fairly well-known professor of computing science has repeatedly argued in public that there is no point in proving the correctness of one's programs written in a higher-level language "because, how do you know that its compiler is correct?". In the motivation of a recent research proposal doubt is cast upon the adequacy of "the axiomatic semantics approach" as it may lead to deductive systems that are "undesirable in that they may not accurately reflect the actual executions of programs". It is like casting doubt on Peano's Axiomatization of the Natural Numbers on the ground that some people make mistakes when they try to do an addition!

On the one hand we have the physical equipment (the implementation), on the other hand we have the formal system (programming language). It is perhaps a question of taste —I don't believe so— to whom of the two we give the primacy, that is whether it is the task of the formal system to give an accurate description of (certain aspects of) the physical equipment, or whether it is the task of the physical equipment to provide an accurate model for the formal system —and I prefer the latter—. But under no circumstance we should confuse the two!

I have —I think— very good reasons for my preference, because if I cannot appreciate a formal system for the sake of its own consistency, but must view it as a description of physical equipment, I could not deal with a programming language that has not been implemented! (And that is, for instance, exactly what a language designer has to do.)

The confusion is perhaps most clearly demonstrated by the often expressed opinion that "one cannot use a programming language that has not been implemented". But this is nonsense, of course one can! One can use any well-defined programming language, whether implemented or not, for writing programs in; it is only when you want to use those programs to evoke computations, that you need an implementation as well. Being well-defined, rather than being implemented, is a programming language's vital characteristic.

The above remarks are no jokes, nor puns, on the contrary: they are pertinent to multi-million-dollar mistakes. They imply for instance that the development projects —erroneously called "research projects"— aiming at the production of "natural language programming systems" —currently en vogue again— are chasing their own tails.

Note (which I hate to add, because it is nearly an insult to my readers, whom its inclusion accuses of possible superficiality). I have not said that when considering a programming language, one should not care about its implementability: one had better! But also this concern, no matter how serious, is one we should try to isolate.(End of note.)

In my opening paragraph I also mentioned colleagues engaged in educational politics. The writing of this essay was, as a matter of fact, also prompted by a recent study of two Computing Science Curricula at university level. They were from different sides of the Atlantic Ocean, but shockingly similar in two respects: unbelievably elaborate budgets and a total lack of understanding of what constitutes a scientific discipline.

A scientific discipline separates a fraction of human knowledge from the rest: we have to do so, because, compared with what could be known, we have very, very small heads. It also separates a fraction of the human abilities from the rest; again, we have to do so, because the maintenance of our non-trivial abilities requires that they are exercised daily and a day —regretfully enough— has only 24 hours. (This explains, why the capable are always busy.)

But of course, any odd collection of scraps of knowledge and an arbitrary bunch of abilities, both of the proper amount, do not constitute a scientific discipline: for the separation to be meaningful, we have also an internal and an external requirement. The internal requirement is one of coherence: the knowledge must support the abilities and the abilities must enable us to improve the knowledge. The external requirement is one of what I usually call "a thin interface"; the more self-supporting such an intellectual subuniverse, the less detailed the knowledge that its practitioners need about other areas of human endeavour, the greater its viability. In the terminology of the computing scientist I should perhaps call our scientific disciplines "the natural intellectual modules of our culture". (When the layman asks the computing scientist, what is meant by "Modularization", a reference to the way in which the knowledge in the world has been arranged, is probably the best concise answer.)

In view of the preceding it becomes quite obvious why many earlier efforts to concoct Computing Science Curricula at our universities have been such dismal failures. They were just cocktails! For lack of other ingredients, they tried to combine scraps of knowledge from the most diverse fields that seemed to have some relation to the phenomenon Computer. That the ingredients of the cocktail did not mix into a coherent whole, is not surprising; that the cocktail did not taste too well, is not surprising either.

In those early days, the only alternative was waiting, as for instance still in 1969 urged by Strachey: "I am quite convinced that in fact computing will become a very important science. But at the moment we are in a very primitive state of development; we don't know the basic principles yet and we must learn them first. If universities spend their time teaching the state of the art, they will not discover these principles and that, surely, is what academics should be doing." I could not agree more.

Now, of course, one can argue whether five years later we computing scientists have enough of sufficiently lasting value that can be "studied in isolation, for the sake of its consistency". I think that now we have enough to start, but if you think Strachey's advice still appropriate now, you have my full sympathy.

The two recent(!) curriculum proposals I just referred to, however, presented the old cocktail as if absolutely nothing had happened, and, not as a timid first step, but as the final goal..... And when scientists no longer know, what science is supposed to be about, we are in bad shape. Hence this essay.

30th August 1974
Burroughs
Plataanstraat 5
NUENEN - 4565 The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

Transcribed by Richard Walker.

Last revised on Mon, 25 Oct 2010.

EWD448

Trip report E.W.Dijkstra, Edinburgh and Newcastle, 1 - 6 September 1974.

On Sunday 1st September 1974 I flew via London from Amsterdam to Edinburgh, where I arrived with a delay of only two hours. The little bit of the afternoon that was left and the evening I spent talking shop with Rod Burstall, who was my host. Monday morning I passed at the Department of Machine Intelligence, Hope Park Square, where we were joined by a number of staff members of the Department of Computer Science. The somewhat erratic nature of that morning's discussion seemed to reflect the way in which the various related groups of the University are scattered all over the town. Carl Hewitt from MIT had to divide his attention between the subject of the conversation and one of Edinburgh's female students, whom he found at least as attractive. There was also Richard Waldinger from Stanford Research Institute, who confirmed my impression of SRI as had been formed a week before, when I had received a visit from two other people from that institute. Waldinger referred to that visit, but in order not to spoil the atmosphere I did not pursue that topic. The more I hear about Artificial Intelligence the more ridiculous becomes its often heard defense that Artificial Intelligence has contributed so much to programming technology --for both, the claim and its debunking, see the various contributions to the Lighthill Report--. I see more and more reason to characterize its contribution as "adding to the confusion".

LISP is a good example. In the early sixties we have suffered from a piece of computer science folklore, viz. that the crucial test whether on had designed "a good language" was, whether one could write its own interpreter in itself. I have never understood the reason for that criterion --it was suggested that such a language definition would solve the problem of the definition of (particularly) the semantics of the language--, the origin of the criterion was the example of LISP, which was "defined" by a ten-line interpreter written in LISP, and that, somehow, set the standard. (I found this hard to accept because when I started to study LISP from the LISP 1.5 Manual, I could not understand it:after an incomplete definition of the language, its authors try to supplement these deficiencies by an equally incomplete sketch of a specific implementation, and that was a confusion if there ever was one!) This unfortunate LISP-interpreter formulated in LISP has somehow given mechanistic (or "operational") language definitions an undeserved aura of respectability, and its unwholesome influence can be traced right through the Vienna Definition Language and ALGOL 68 --what I knew-- and even --what I learned this week to my surprise and disappointment-- to the work of Dana S.Scott. It is enlightening to know --what I also learned later that week-- that LISP's most awful property, viz. "shallow binding" --now religiously defended by its addicts!-- is described by McCarthy as "a mistake" in that ten-line interpreter (which, of course, it is)!

On Monday afternoon I gave a formal lecture in which I showed the development of Rem's Algorithm for the Recording of Equivalence Classes, and I found it an uncongenial audience. Immediately afterwards I sought the explanation in the AI-environment to which designing something that should meet rigorous specifications and working backwards from them does not come naturally. It was only later that week, while in Newcastle, that I realized that in a sense I had been "too modern" for them, and that I had underestimated the extent to which the mechanistic approach was still in full vigour. The next day Rod Burstall told me that a number of people had told him that --contrary to my impression-- they had liked the talk very much. Early in the evening I went by train from Edinburgh to Newcastle: there was a real Scottish rain outside and I had plenty of time to sort out my mixed feelings.

The next four days I attended at the University of Newcastle the yearly seminar, this time on "Formal Aspects of Computing Science." (My sweater was identified as one of the informal aspects of computing science.) This was an exhausting affair because --in contrast to the previous seminars-- all speakers were of such a calibre that one did not want to miss a single lecture.

Three speakers dealt with various aspects of the subject now known as "computational complexity" and among themselves --or by accident, but I don't think so--- they had divided the subject quite nicely.

Dr.M.Rabin --rector of the Hebrew University of Jerusalem-- stole the show as far as I was concerned. He was a very capable --and probably very experienced--- lecturer, who mainly gave results (and definitions needed to formulate these results) but hardly proofs, sometimes a sketch of a proof. While the distinction between decidable and undecidable is now quite well-known, Rabin dealt with "decidable, but.....", e.g. decidable theories where the number of steps required for the shortest possible proof could explode (super)exponentially with the length of the theorem (and we don't even talk about the search process usually needed for discovering the proof). A sobering thought. I had not studied the program of the seminar at all and Rabin's collaboration was therefore a surprise for me, a most exciting one even. (I had already been thrilled by his IFIP.)

Dr.S.Winograd of the IBM Research Center in Yorktown Heights was the second speaker on the same subject. Apparently Rabin and Winograd knew each other fairly well, they also resembled each other in their way of presentation: slightly mocking and irreverent, and very modest. (This is perhaps a consequence of the subject!) Winograd followed the same pattern of showing results and sometimes sketching a proof, but Winograd focussed our attention on the minimum number of operations needed for (otherwise quite finite) problems as matrix multiplication etc. Being less less easily excited about efficiency considerations than many others (Knuth!), I was quite surprised to find my attention fully absorbed by Winograd's lectures. (Was it because I recognized some of the tricks I had played myself in the late fifties when making subroutines for standard functions?) Both Winograd and Rabin struck me as "wise men".

The third speaker on complexity was professor John Hopcroft from Cornell University, who showed that from the point of view of complexity many at first sight different problems can be viewed as different instances of the same problem, with the result that superficially different, shrewd algorithms can be viewed as instances of the same method. I had met Hopcroft, but had never heard him lecture: it was a pleasure and I shall buy his new book. I had heard him state his opinion that, essentially, there are no more than, say, thirty basic algorithms and that today a competent computing scientist should know them: the days of the bright young lad without the necessary knowledge are past. He made his case so convincingly that I started wondering to what extent the book I am writing --mostly without the afore-mentioned knowledge-- will be obsolete even before the printer's ink has dried. And this my worry is saying a good deal about the quality of Hopcroft's lectures! I think that "unifying and consolidating" are about the most appropriate terms for the contents of his message.

The fourth speaker that I had never heard before was professor D.S.Scott, now from Oxford University. His first lecture was a bitter disappointment. He reacted rather inadequately when asked for clarification about terminology, notation and even inconsistency displayed by his prepared transparencies. With the possible exception of his faithful followers --for whom we cannot blame him-- he left his audience very unsatisfied. In the discussion at the end of the first day our host, professor E.S.Page from Newcastle, urged him to use his next slot to try to make at least his purpose clear. So he tried to do the next day (his effort to do so was a great relief for most of us: it showed his good will and that his previous failure to communicate had not been caused by contempt for his audience). Unaware of what had happened two years ago to speakers who did the same, he explained his purpose in the good American tradition via a diagram with arrows. His audience appreciated his effort and, in order to avoid further embarrassment, refrained from asking what the arrows meant. (I needed at least two different meanings, probably more....) On the whole he struck me as the mathematician who, in order to help the English bookkeeper, develops the theory of mixed radix number representations several years after Britain has switched to decimal currency. His last lecture, which had very little connection with the previous ones (nor with computing science, for that matter) was self-contained and much better. It had very much the flavour of John Backus's Reduction Languages and van der Poel's fiddling with the so-called paradoxical combinator. Although (or because?) I do not care too much about that subject, I could stand that last lecture very well.

The fifth lecturer was dr.H.Bekic from the IBM Laboratory in Vienna on "Semantics of Parallel Programs". In his first lecture he was so shy and nervous that it was hard to see what he was driving at. In his next lectures this became clearer but the effort struck as misguided in more than one sense. In a very mechanistic approach he tried to formalize the non-determinacy caused by the arbitrary interleaving of (the executions of) arbitrary programs, situations no one cares about (or should care about after three minutes reflection). Secondly he tried to squeeze his formalization into Scott's formalism. I pitied Scott, for the horrible formulae produced by Bekic could only act as a witness for the prosecution. Of course one can dismiss the whole thing by saying that, with VDL to formalize the definition of PL/I in its past, one can expect anything from that crew (which, of course, is true: the crew members themselves, I guess, will be the last ones to deny it). Looking at it from the outside, however, one cannot escape the uneasy feeling that the crew is under heavy company pressure to tackle the wrong problems. And the company in question is large enough to consider such ill-directed pressure as a rather alarming symptom of the general misunderstanding of the role that scientific thought could and should play in our culture. (I shudder at the thought of the havoc that can be caused by similarly ill-directed funding policies of our various national governments! Also there, frightening things could nowadays happen quite easily!)

Side remark. In passing Bekic mentioned that the group in Vienna now wrote semantic definitions "in a new style". At the end of that lecture he got an alarmed question about that new style from Ollongren: Ollongren had just published a book on VDL! In a microcosm we could see how manufacturers must have felt when IBM changed from 7-track to 9-track magnetic tapes; it was very funny....

The sixth speaker was professor C.A.R.Hoare from the University of Belfast, who devoted three talks to data representation, monitors and parallel programming respectively. In spite of the fact that I had heard most of it at earlier occasions, it was, as always, a pleasure to listen to him. More or less expecting three disjoint talks, I was pleasantly surprised to see he tied them in together. He is a very cautious man, who tries to avoid the introduction of complications by not generalizing more wildly than he can cope with, instead of the immodest compounding of combinatorial complexity generators so many language designers seem to revel in. (It was Hoare who stressed in North Berwick in 1968 already the need for humility!) Another quotation: "reliability can only be achieved by the utmost simplicity, but most manufacturers think this is a price too high to pay!" Wednesday afternoon he and I did not join the excursion and talked together for four hours.

The opening lecture "Formalization, history, present and future" was by professor H.Zemanek from IBM Laboratory in Vienna, a nice talk that suited the occasion. Our host E.S.Page, had given a long quotation from von Neumann about mathematicians formalizing for formality's sake. I thought it was a pity that at the closing session he did not repeat the quotation: those whom it would concern would probably fail to hear the warning. There were 56 participants and, as a result of the subject, there was a relatively heavy representation of what pushes itself as "theoretical computing science" which, I am afraid, is just a euphemism for "unpractical computing science"; and the latter could very well turn out to be a contradictio in terminis. The split in the audience was rather marked. I saw Nivat (from the University of Paris) and found my impression confirmed that the new journal (!) "Theoretical Computer Science" is no more than the next political move of the French mathematicians, who seem to fear but one thing: to loose their power. I guess that they will succeed in preventing the birth of Computing Science in France for at least another decade and it is always nice to know of the existence of yet another journal that one can ignore. I am willing to make a bet that de Bakker will publish in it....

Ollengren and de Bakker were my only countrymen at the Newcastle Seminar; Verrijn Stuart, who did attend the previous seminars, was absent.

16th September 1974
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Burroughs Research Fellow

cc:
Rabin
Winograd
Hopcroft
Scott
Bekic
Zemanek
Page
Randell
Burstall
Hoare

transcribed by Tristram Brelstaff
revised Wed, 26 May 2004

EWD449

Het curriculum informatica aan de THE.

“Informatics must become a field of exceptional character at a new abstract level; the graduate of this curriculum must be a scientist of a class which has not existed until now: he must be an engineer by education and by mentality, but he must construct abstract objects which so far had been studied by mathematicians only. Mathematicians, however, study abstract objects for quite different purposes and in a different frame of mind.” (Professor Dr.Heinz Zemanek, “What is informatics”, Management Informatics, Vol.1 [1972], No.2, pages 43–52.)

Uitgangspunten.

1. Ongeacht het in de wet genoemde oogmerk waarmee een academische studie wordt gevolgd, dient de opleiding qua kennis, vaardigheden en habitus een gezonde basis te kunnen leggen voor een rijk en werkzaam verder intellectueel leven. Dit lange-termijn-aspect bestempelt o.a. snel verouderende kennis tot een suspect ingredient voor academische curricula.

2. Wetenschappelijke disciplines representeren hoe de kennis in de wereld over mensen is verkaveld: zij representeren, om een term uit de informatica te gebruiken, de “modularisering” van menselijke kennis. Opdat deze modularisering effectief zij, dwz. opdat een wetenschappelijke discipline levensvatbaar zij, moet tenminste aan de volgende vier voorwaarden zijn voldaan.

2.1 De voor de discipline onmisbare kennis mag qua omvang de capaciteit van een redelijk begaafd mensenhoofd niet te boven gaan.

2.2 De voor de discipline onmisbare vaardigheden mogen niet te veel, noch te moeilijk zijn: een redelijk begaafd mens moet ze zich eigen kunnen maken en ze op een voldoend hoog peil kunnen handhaven.

2.3 De discipline dient een grote mate van innerlijke coherentie te vertonen, zodat de kennis en de vaardigheden kunnen bijdragen tot wederzijdse ondersteuning en perfectionering.

2.4 De discipline dient zo “self-supporting” te zijn, dat zijn kennis bestudeerd en ontwikkeld kan worden, zijn vaardigheden aangekweekt en uitgeoefend kunnen worden, desgewenst in isolatie, in (tijdelijke) afzondering van de geestelijke rijkdom (en noden!) van andere gebieden.

3. Bij de vraag of een academisch curriculum in de informatica ingesteld moet worden, dient met het oog op het in 1. gestelde de existentie van een wetenschappelijke discipline, die aan het in 2. gestelde voldoet, als noodzakelijke en centrale voorwaarde beschouwd te worden.

3.1. Het kompas dat zich richt op polen zoals “huidige werkkringen in de automatisering” is voor richtingsbepaling bij het opstellen van een curriculum in de informatica onvoldoende betrouwbaar: nu juist deze polen zelf vrij drastisch lijken te gaan verschuiven, is dat kompas zelfs voor korte-termijn-planning nauwelijks bruikbaar, laat staan voor de lange-termijn-planning die met elk weloverwogen curriculum voorstel dient samen te gaan. (Dit alles nog afgezien of de expliciete afstemming op “werkkringen” bij het academisch onderwijs —in tegenstelling tot het hoger-beroepsonderwijs— wel zo op zijn plaats is.)

4. Als een kernopgave van de informaticus beschouwen wij het beheerst ontwerpen en ontwikkelen van (zonodig uiterst geraffineerde) systemen, die een welgekozen doel op aantoonbaar betrouwbare wijze zullen realiseren. De wetenschappelijke discipline “informatica” bestrijkt de voor deze opgave onmisbare kennis, inzichten, theorieen, methodologieen en vaardigheden.

4.1 Een analyse van deze taakstelling impliceert dat de informatica een discipline van uitgesproken wiskundige signatuur moet zijn: zonder als wiskundige te werk te gaan, zal de informaticus nimmer de “aantoonbare betrouwbaarheid” kunnen bereiken. Elk informatica, curriculum dat (om wat voor reden dan ook) dit wiskundig aspect verdoezelt, is dan ook tot falen gedoemd.

4.2 Een analyse van deze taakstelling impliceert dat informatica een discipline is met uitgesproken ingenieursaspecten, al was het alleen maar vanwege het type contractuele verplichting die de informaticus aangaat en vanwege de wijze waarop hij door de physische realiteit gestelde grenzen dient te respecteren.

*              *
*

Met het oog op het bovenstaande is de THE —uiteraard ook onder invloed van locale omstandigheden— gekomen tot een curriculum voorstel voor een afstudeerrichting “informatica” voor wiskundig ingenieurs, een curriculum dat thans grotendeels is gerealiseerd of zich in staat van actieve voorbereiding bevindt. De beslissing is genomen op grond van ons inzicht dat de informatica zich inmiddels als voldoend rijke, coherente en isoleerbare discipline begint af te tekenen om zulk een curriculum te kunnen schragen. Het spreekt vanzelf, dat hierbij ruimte gelaten wordt voor accentsverschuivingen, die op grond van didactische ervaringen of verdere ontwikkelingen van de discipline noodzakelijk kunnen blijken. (Aan de onderstaande nummering dient geen betekenis toegekend te worden.)

1. Inleiding tot de kunst van het programmeren. (2 * 2 semesteruur).

De bedoeling is op basis van een intuitief geintroduceerde semantiek de student te leren heldere en effectieve programma’s te concipieren; een college met sterk methodologische inslag.

2. Toegepaste logica. (2 * 2 semesteruur).

De bedoeling is de student vertrouwd te maken met een aantal formele technieken van standing, welke onmisbaar zijn als men het vak op solidere basis wil bedrijven; een fundamenteel college.

3. Inbeddingsproblematiek. (1 * 2 semesteruur).

De bedoeling is de student een gedeelte van de kennis en inzichten bij te brengen om hardware —in het bijzonder adressering in de ruimste zin des woords— op adequaatheid te kunnen taxeren en de taak van z.g. “operating systems” gestalte te geven; een meer encyclopedisch college.

4. Representatietechnieken. (1 * 2 semesteruur ).

De bedoeling is de student bekend te maken met de representatietechnieken voor lijsten, bomen, grafen, ruimtelijke objecten etc., in het licht van de wijze waarop zij moeten worden gewijzigd en geraadpleegd; een methodologisch/ encyclopedisch college.

5. Syntactische technieken. (1 * 2 semesteruur).

De bedoeling van dit college is de student te leren zijn talen zo te ontwerpen dat mechanische tekstverwerking —“parsing”, “compile time checking”, “error recovery” etc.— geen nodeloze complicaties oproept; een disciplinerend college.

6. Axiomatisering van de semantiek. (1 * 2 semesteruur).

De bedoeling is de student vertrouwd te maken met axiomatisch gedefinieerde semantiek als basis voor formele correctheidsbewijzen en een calculus voor de formele afleiding van programma’s; een fundamenteel/practisch college.

7. Informatiebeheer. (1 * 2 semesteruur).

De bedoeling is de student vertrouwd te maken met de (zowel logische als technische) problematiek die optreedt bij het bespelen van grote gegevensbestanden; een meer encyclopedisch college.

8. Parallellisme en communicatie. (1 * 2 semesteruur).

De bedoeling is de student vertrouwd te maken met de moeilijkheden en mogelijkheden van de organisatie van de samenwerking tussen sequentiele processen; een fundamenteel college.

9. Computer architecture. (1 * 2 semesteruur).

Nog niet nader gespecificeerd.

Bovenstaand curriculum is ontworpen omdat dit de enige weg was die wij zagen om als informatici onze wetenschappelijke verplichtingen jegens de maatschappij na te komen. Ter onderstreping van de urgentie en aard dezer verplichtingen eindigen wij met een tweede citaat, ditmaal van professor Andrei P.Ershov uit Novosibirsk:

“In my opinion programming is, for at least the following three reasons, the most humanly difficult of all professions involving numbers of men:

1. Programmers constitute the first large group of men whose work brings them to those limits of human knowledge which are marked by algorithmically unsolvable problems and which touch upon deeply secret aspects of the human brain.

2. A programmer’s personal push-down stack must exceed the depth of 5–6 positions, which psychologists have discovered to characterize the average man; his stack must be as deep as is needed for the problem which faces him, plus at least 2–3 positions deeper.

3. In his work, the programmer is challenged to combine, with the ability of a first-class mathematician to deal in logical abstractions, a more practical, a more Edisonian talent, enabling him to build useful engines out of zeros and ones, alone. He must join the accuracy of a bank clerk with the acumen of a scout, and to these add the powers of fantasy of an author of detective stories and the sober practicality of a businessman. To top all this off, he must have a taste for collective work and a feeling for the corporate interests of his employer.” (A.P.Ershov, “Aesthetics and the Human Factor in Programming.” Comm.A.C.M. Vol. 15, No. 7 (July 1972), pages 501–505.)

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD 450

Correctness concerns and, among other things, why they are resented.

Invited paper, to be presented at the 1975 International Conference
on Reliable Software, 21–23 April 1975, Los Angeles, California U.S.A.

Edsger W.Dijkstra
Burroughs
Plataanstraat 5
NUENEN – 4565
The Netherlands

According to Webster's definition of a tutorial: "a paper and esp. a technical paper written to give practical information about a specific subject", this paper is not worthy of the name "tutorial", because I would never describe what I intend to do as "giving practical information". On the contrary: I intend to give as little "practical information" as I possibly can. I am not going to enumerate facts, results and theories, for those you can find —in abundance, I am tempted to add— in the published literature. What I do hope to achieve, however, is helping you to understand and evaluate those facts, results and theories when you encounter them in the literature. I intend to do so by providing you with a historical perspective, be it —in more than one sense— a partial one. It is a lucky circumstance that the amateur historian, like myself, can always come away with very few facts: the fewer the facts, the greater our freedom of interpretation, and it is that freedom that I intend to enjoy.

For a short while we have to go back to the scientific climate at the beginning of this century, for there we seem to find the roots of the philosophical opinions that prevailed a few decades later. And these philosophical opinions, in turn, seem to be the source of today's tacit assumptions. By being tacit, these assumptions tend to escape being challenged and that is bad, because they are third generation off-spring of scientific hopes that, in the mean time, have been shown to have been unjustified, they express everyman's image of a goal that, in the mean time, has been proved to be unattainable.

The scientific optimism of the late 19th century is responsible for the common opinion that "the greater our knowledge, the more perfect our understanding". This assumption is the ultimate justification for so many of our university curricula, that one can hardly challenge it without running the risk of being accused of preaching the virtues of ignorance. Yet I challenge it: the greater our knowledge, the more perfect our understanding..... what sheer nonsense! Think about the wealth of information that the modern communication media give us about the world and its inhabitants: never before, Mankind has been so confused about itself as today! The overpowering flood of conflicting impressions leaves many of us so bewildered that, in utter despair, they seek salvation in cheap mysticism or a narrow minded ideology: the greater knowledge has not created greater understanding, it has created extremism instead. Another fine example is provided by the last decade of nuclear physics. At a fantastic expense a fantastic number of bubble chamber experiments have been made. And what has happened? By discovering a new "elementary particle" every other week, the nuclear physicists have made themselves the laughingstock of the scientific community.

What, you may ask, has all this to do with Computing Science? Well, everything. In perfect analogy to the belief that our understanding was imperfect, because we did not know enough, it was also felt that many goals were not reached, because what had to be done for that purpose, could not be done fast enough. The usual explanation of the successful advent of the automatic computer refers to Babbage's technical failure to make one with mechanical means, and observes that, at last, electronic technology had made its construction feasible. I would like to offer another explanation: at last there was a cultural climate in which the attitude of "the more, the better" was such a predominant one that it was willing to accept the gimmick as the obvious tool for our salvation. And if you do not believe this explanation, try to imagine, how Confucius, Buddha, Jesus, Mohammed or Homer would have reacted when they had been offered a UNIVAC 1..... Who of us doesn't remember the advertisements for the first electronic business machines, proudly announcing that "our machines will take for you more than a hundred thousand decisions a second!". The advertisement did not warn the reader that they were all trivial, nor that in this connection the use of the term "decision" is misleading, but to that misleading terminology I shall return later. Speed was the key issue and in the thinking of many still is.

The first warnings that with faster and faster machines, the conceptual problem of designing those wonderful computations for which tomorrow's machines would be powerful enough, would at least grow in proportion, were not taken in gratitude. They were not even heard, for they would have spoiled a dream .... Babbage's daydream had first to become a fully transistorized nightmare .... And has the latter traumatic experience cured all of us from confusing day-dreams with attainable reality? I am afraid not: the distorting spell of speed still seems to make its victims. We see automatic theorem provers proving toy theorems, we see automatic program verifiers verifying toy programs and one observes the honest expectation that with faster machines with lots of concurrent processing the life-size problems will come within reach as well. But, honest as these expectations may be, are they justified? I sometimes wonder ...

Another path via which the last century's unwarranted scientific optimism has influenced our trade is psychology. In an effort to understand Man, psychologists decided to study Rat. They designed a crude model of the Rat's behaviour, a model that showed only a superficial resemblance to the behaviour of the true, average Rat. But in the scientific optimism of those days, that did not disturb anybody: the beginning, full of promise, was there, in principle the modelling worked and from now onwards it was only a question of refining the model. Once we should have a fully acceptable model of Rat, and from there to a model of Man would then be only a next step. That the ensuing image of Man would, in all probability, be somewhat ratomorphic did not seem to bother many psychologists either. But again the question is: how long can one live with a "promising start" without becoming blind to the possibility that the promise will never be fulfilled?

What, one may ask again, has this to do with our trade? Well, as I hope to explain: everything. At the beginning of the computer revolution a book appeared with the ominous title "Giant brains, or machines that think". Once at a time I was tempted to write a compensating companion to it under the title "Giants hearts, or machines that fall in love", but I did not do so, when I realized that the title about the giant brains was more symptom than cause. To the somewhat excited hopes as to what machines can do had been added a somewhat simplified image of Man.

Extreme consequences of that attitude can be found in all efforts aimed at developing "natural language programming systems", a theme that recurs with the same regularity as influenza epidemics. It is observed that without considerable dedication people have a hard time expressing themselves precisely in a formal system as provided by a programming language. Man at large being rather education-resistant in that view, the problem is solved by letting him express himself in a way which precludes precision. By posing smart questions about the Man's intentions —the Man in this connection always being denoted as "the user"— the system will eventually guess his intentions. Interactive facilities have added a new dimension to this game and ultimately the "user" will produce his design specifications as a kind of Pavlovian slobber.

These are, of course, extremes cases. But even efforts to prove mechanically a posteriori the correctness or —because for the latter there seems to be a bigger market— the incorrectness of programs, efforts to guess mechanically invariant relations for repetitive constructs —because most programmer's are supposed to be too lazy or too stupid to write them down themselves—, they all have something of that condescending flavour. Just because a machine is very good at a few things we are poor at, it does not follow that ultimately the machine will be very good at something just because we, ourselves, find it difficult. Yet, the euphoric pressure to believe so is still very strong.

Although not directly connected with the theme "software reliability", I cannot resist the temptation to draw from the wider field of Computing Science a few further examples. The desire to understand Man in terms of Machine has —as is only to be expected— its inverse counterpart, viz. the desire to understand the Machine in terms of Man: in computing science the terminology is shockingly anthropomorphic. What with Babbage was still called "a store" is now "a memory", what used to be called "an instruction code" is now called "a programming language". I picked up the sentence "When this guy wants to talk to that guy..." while the speaker referred to distant components of a computer network. I contend that this preponderance of anthropomorphic terminology is the symptom of a widespread confusion, a confusion without which, for instance, so-called "conversational programming" would never have enjoyed the glamour that, at one time, it did enjoy. Finally: the traces of the superstition "the more, the better" can be found in the awe for so-called "powerful" programming languages, with all their bells and whistles, and does the belief "the greater our knowledge, the better our understanding" not find its ultimate confirmation in today's cult of large data bases?

*                       *
*

I would not like to leave you with the impression that Computing Science has developed along 30 years of foolish projects: such a distortion of the truth would be too gross even for the worst amateur historian! With respect to Software Reliability a lot has happened, insights of lasting value seem to have been gained, and all that took place in a relatively short period of time!

The first expression of serious concern about the confidence level of our programs, that I could find in the open literature dates from 1961. In 1965, at the IFIP Congress, it is voiced by more. Stanley Gill, for instance, remarks: "Another practical problem, which is now beginning to loom very large indeed and offers little prospect of a satisfactory solution, is that of checking the correctness of a large program.", certainly an expression of serious concern! John McCarthy opens his introduction with: "The prize to be won if we can develop a reasonable theory of computation is the elimination of debugging. Instead, a programmer will present a computer-checked proof that a program has the desired properties." Here the reader is left in doubt as to whether McCarthy's main concern is really the ultimately attainable confidence level or only the great expense of the debugging process, but serious concern is in any case expressed. In passing we note —we shall return to this later— that both speakers don't mention yet any alternative for a posteriori verification.

Were these quotations two fairly isolated examples taken from the 1965 Conference Proceedings, in 1968 the climate changed drastically. In October 1968 the NATO Conference on Software Engineering created a sensation by its open admission of the software crisis. Anyone doubting, that much has changed since then, should read those conference proceedings! One now very well-known professor of Computing Science confesses that "the word "proof" causes him to have a sort of mental hiccough", another very well-known professor of computing science calls the notion of proof "idyllic" and nowhere one finds a reference to R.W.Floyd's article that by that time is already one year old! Was that NATO Conference perhaps technically not very significant, its political significance can hardly be underestimated: the most significant work could happen since!

*                       *
*

After the above sketches of the intellectual climate, we turn, in a little bit more detail, to some of the more technical aspects: obviously we do so without any claim to completeness.

One of the, in retrospect, most striking things is that for many years the correctness problem was solely viewed as a posteriori verification of given programs. Given a program and given a set of requirements, does the given program meet the given requirements? Phrased as a question that could be answered by "Yes" or "No", it was apparently not without appeal for the mathematicians of that period, mathematicians who, by their training, were on the average perhaps rather analytically oriented. But besides that, I think that a specific tradition pushed them into that analytic direction, and that is the tradition that got its pronounced form with the work of Alan M.Turing. It is the approach, in which a —hopefully well understood!— mechanism is started and we are invited to figure out, whether we can prove something about the class of ensuing happenings, corresponding to the class of initial states in which the mechanism may be started. We can ask ourselves whether it will terminate or, if that is too difficult, whether we can say something about the final state provided the activity terminates, and so on. It is the mechanistic, operational point of view which regards the "answer" to be defined as the last one of a long sequence of intermediate machine states of which the initial state is the first one. Turing's work and the branch of mathematics that emerged from it were so impressive that they caused a strong bias in the earlier work on program correctness, a bias which I do not consider as wholly fortunate. Its main consequences seem to have been the following.

Firstly, nearly all through the sixties, efforts at giving a formal definition of the semantics of programming languages have been in the form of writing an interpreter, i.e. designing an abstract machine, for such a programming language. Developing means for describing the intermediate states of such an abstract machine became soon a major concern.

Secondly, the unsolvability of the halting problem, combined with an early desire to mechanize correctness proving, has caused many to restrict themselves —apparently without much hesitation— to proving partial correctness only, viz. proving only that an acceptable answer will be produced under the additional assumption that the computational process terminates.

Since the late sixties we distinguish, however, a process for which "shedding the shackles of automata theory" could be an appropriate —be it perhaps too vivid— description. Two things started to happen in parallel, initially, as far as I can see, rather independently of each other.

The first development was the result of challenging the choice of a posteriori verification of given programs as the most significant problem, the argument against that choice being that programs are not "given", but must be designed. Instead of trying to find out which proof-patterns are applicable when faced with a given program, the program designer can try to do it the other way round: by first choosing the proof-pattern that he wants to be applicable he can then write his program in such a way as to satisfy the requirements of that proof. This "inversion" of the problem of program correctness was one of the cornerstones of the field of activity which about five years ago became known as "programming methodology". Correctness proofs began to play in that field of activity two significant roles: firstly, in the constructive approach to the problem of program correctness, proof-patterns provided an important heuristic guidance during the programming process, secondly, the length of the correctness proof required was generally accepted as an objective measure for the "elegance" of programs and for the "adequacy" of proposed language features. This objectivity has probably been more effective in reaching a comfortable consensus of opinion among many than anything else, certainly more effective than eloquence could ever have been. I mention this consensus explicitly, because it has been so important: it was the only way in which we could hope to raise language design from the political and commercial level, aimed at "user satisfaction", to the level of a scientific activity.

In parallel to the exploration of programming methodologies, the methods for proving program correctness and their foundations, slowly divorced themselves from the operational point of view. Naur's article of 1966 and Floyd's article of 1967 are still rather operational, but Hoare's article of 1969 presents a step away from that point of view, as he suggests that "axioms may provide a simple solution to the problem of leaving certain aspects of a language undefined". This remark is deeper than the primarily suggested applications such as leaving wordlength or precise specification of rounding rules unspecified. Hoare's rules for the repetitive construct rely on the fact that the repeatable statement leaves a relevant relation invariant. As a result the same macroscopic proof is applicable to two different programs which only differ in the form of the repeatable statements S1 and S2, provided that both S1 and S2 leave the relevant relation invariant (and ensure progress). But then the same proof applies to a non-deterministic machine in which a daemon decides quite arbitrarily at each repetition, whether S1 or S2 will be chosen! The fact that the obvious way was shown for dealing with at least some very common and desirable forms of non-determinacy although obvious in retrospect, only came to be exploited systematically a few years later. From the operational point of view, such daemons seem to create problems: they must be assumed to supply some "ghost-input" to the mechanism that, assumed to be deterministic, otherwise would not know which way to go. Reasoning from the other end and starting with the functional specifications, the daemons only enter the picture by the time that we start thinking about implementations: they appear as the freedom of the implementation, viz. wherever the choice does not matter.

*                          *
*

I now skip the enumeration of a long series of important publications, successful development projects and promising research efforts, and would like to round up by drawing your attention to two side-effects of all these efforts, the final impacts of which still lie in the future.

The first one is that most techniques for proving the correctness of a program treat the program text as a static, rather formal, mathematical object that can be dealt with independently of the fact that there may exist machines that could execute such a program. As such, a clear separation of concerns emerges: we might call them the mathematical concerns about correctness and the engineering concerns about efficiency. In contrast to the correctness concerns, the efficiency concerns are only meaningful in relation to implementations and it is only during the efficiency concerns that we need remember that the program text is intended to evoke computational processes. Both the mathematical and the engineering concerns have, of course, always been with us, but once they used to be dealt with inextricably intertwined. The discovery how to separate them rigorously in our thinking is relatively young, and even when aware of this possibility, we often fall back into our old bad habits. But I guess that this discovery will have profound consequences, which will become fully apparent when new generations of programmers have been educated who separate these concerns more naturally than we do, unhampered as they are by our obsolete experience and worn-out habits.

The second side-effect concerns the bells and whistles of yesterday's programming languages. When the correctness guys started their efforts, they used at first very simple programming languages, mini-languages, one might say. For the programmers who lived "in the real world of computing", this restriction was often a reason for some scorn: "Toy problems, solved by toy-programs written in toy-languages: what has that to do with us?".

But things, again, are changing. People decided to try to program without go-to statements, and it did not do much harm to the efficiency of their programs, quite often on the contrary even. People decided to do away with "controlled variables" as we know from FORTRAN's DO-loops or ALGOL 60's for-statements, and this did not impair the efficiency either. But after a while, these "restrictions" turned out to bear unexpected fruits: for instance, people who had trained themselves in using a very simple, but very elegant repetitive construct, could discover algorithms that turn out to be much harder to find by a programmer in whose mind repetition was irrevocably connected with a controlled variable. The abolishment of the "controlled variable" turned out to be a gain! And this process seems to be continuing: the correctness guys have still a tendency to use mini-languages, but in the mean time their experience in using them is no longer restricted to toy-problems, on the contrary!

I would like to end this talk by relating a recent personal experience that may be exemplary for the kind of surprises that the use of such mini-languages still has in store for us. I had been exploring programming methodologies and as a carrier for my investigations I had used a mini-language without recursion (although intuitively I was fully familiar with recursive programs for about fifteen years). I did not feel the urgent need to introduce recursion at this stage, because my language did contain extensible one-dimensional arrays and, when tempted to use recursion, I felt that I could always try to program around it.

Tackling a problem from graph theory I developed (as a matter of fact without feeling the need of recursion) without much hesitation in a number of steps a beautiful algorithm, clear, compactly coded and highly efficient in terms of operations needed (viz. linear in the sum of the number of edges and the number of vertices of the given graph). It turned out that, shortly before, an algorithm for the same problem had been published in an American journal, an algorithm that had the same efficiency characteristics, but was very hard to understand and —as a result!— was generally considered as a great intellectual achievement: no one less than Donald E. Knuth described the published version as "a deep algorithm". For the difference in clarity and ease of discovery I have only one explanation: my program manipulates explicitly —they entered the design quite naturally, one after the other— four independent stacks, most of them growing and shrinking asynchronously with each other. The published version, however, was a recursive program, by its very nature favouring a solution with one (anonymous) stack, and squeezing a four-stack algorithm into that straightjacket is in all probability indeed "a great intellectual achievement", which, however, cannot be expected to lead to a very natural program.

The discovery that doubts may have to be casted upon recursion —in Computing Science for more than a decade the hallmark of academic respectability!— was something of a shock for me. Although at the moment of writing not yet conclusive, evidence is piling up: a number of our established "powerful" programming language features, even beloved ones, could very well turn out to belong rather to "the problem set" than to "the solution set". And even if this were the only lasting contribution of the work of the correctness guys, their efforts seem already well-rewarded!

22nd November 1974

transcribed by Mario Béland
revised Sun, 23 Jul 2006

EWD451

Heer, verlos ons van de charlatans!

Het is met grote tegenzin, dat ik de heer B. Wilbrink (NRC-Handelsblad van 27 - 9 - 1974, pag. CS3) van repliek dien, tegenzin, omdat het bijna altijd een heilloze onderneming is om met een warhoofd in discussie te treden. Het belang van het onderwerp staat zwijgen evenwel niet toe.

Blijkens Wilbrink's definitie is een 18-jarige "geschikt", respectievelijk "ongeschikt", indien hij, toegelaten tot het hogeronderwijs, de studie met, respectievelijk zonder goed gevolg blijkt af te leggen. Onder aanname van een maximum toegelaten studieduur is de aldus gedefinieerde "geschiktheid" inderdaad in een eindig experiment te bepalen, een experiment, dat gemiddeld, zeg, een jaar of zes duurt. De eigenschap "geschiktheid" is daarmee slechts gedefinieerd voor de gemiddeld 24-jarige.

De heer Wilbrink suggereert echter, dat dit binaire kenmerk ook voor de 18-jarige gedefinieerd zou zijn. Wanneer van een homogene groep van 18-jarigen 1 van de 5 later ongeschikt en 4 van de 5 geschikt bevonden zijn, noemt hij (achteraf!) van de 18-jarigen er 1 ongeschikt en 4 geschikt, en hij presenteert het selectieprobleem als het probleem die ene op 18-jarige leeftijd van de overige vier te scheiden. Als evenwel de groep op 18-jarige leeftijd zich als homogeen voordoet —bij wijze van gedachtenexperiment: het zouden op die leeftijd vijf identieke jongens kunnen zijn, hetwelk niet hoeft uit te sluiten, dat een van de vijf in zijn studie faalt—, kunnen wij hoogstens tot de uitspraak komen, dat voor een 18-jarige uit zulk een groep de kans op succesvolle voltooiing op 0.8 gesteld mag worden (dit onder een continuiteitsveronderstelling op grond van vroegere ervaringen met soortgelijke groepen).

En als het er om gaat de verwachtingswaarde van de opbrengst van de kennelijk beperkte onderwijscapaciteit te maximaliseren, staat ons slechts één weg open, nl. toelating, niet door loting, maar op grond van een vergelijkend examen, waarbij studentengroepen toegelaten worden in volgorde van afnemende geschatte kans op succes. Dat hierbij de caesuur vallen kan in een gebied, waar de kans nog groter dan een half is, is, in tegenstelling tot de suggestie van de heer Wilbrink, volledig irrelevant.

Als lezer van de/het NRC-Handelsblad hoop ik van quasi-wetenschappelijke kronkelredeneringen als van de heer Wilbrink in de toekomst verschoond te blijven.

| prof.dr.Edsger W.Dijkstra NUENEN

transcribed by Paul de Vrieze
revised Fri, 11 Aug 2006

EWD452

About robustness and the like.

I cannot expect the following to exceed the status of a very tentative and preliminary report, for that is what it is as far as I am concerned. In the year behind me I have confined my attention —intentionally!— almost exclusively to one-and-a-half aspect of the programming task. Let me summarize it, so that I can use it as my starting point.

The one side had to do with "program correctness." For this purpose I considered a program as a code for a predicate transformer that for each post-condition R allowed us in principle to derive the corresponding weakest pre-condition for the initial state that would guarantee a terminating process ending in a final state satisfying R. In order to get a balanced view of the significance of that theory, the following remarks seem in order.

1.     For "crazy" R —i.e. a totally unintended post-condition— the method works only "in principle," namely in the sense that carrying out the predicate transformation would lead to totally unmanageable formulae. I do not consider this as a serious defect —as a matter of fact: as no defect at all.

2.     Focusing attention upon the intended post-condition, the formalism could be used in a constructive manner, designing programs for which a sufficient pre-condition could be derived as well. The corresponding formal discipline is certainly on the plus-side of the achievement.

3.     In order to get not too excited we should observe that the formal method referred to is quite sufficient when we want to compute the greatest common divisor, because there both problem and answer are phrased in terms of integers, i.e. the basic subject matter being manipulated by our programming language. Quite often, however —when dealing with graphs, for instance— we introduce (because neither problem nor answer is really stated in terms of integers) a convention for representing the current state of affairs —initial, intermediate and final— with the aid of integer variables and arrays. In one direction we introduce a representation, in the other direction an abstraction function, associating with each collection of integer values a unique value in the abstract domain. The question whether this representation/abstraction is adequately mirroring our intentions has largely been left outside our considerations (To quote an older sentence, by which I tried to capture this state of affairs: "The only thing a computer can do is the manipulation of symbols, the only reason for doing so is that the symbols stand for something else.")

3.1.  I think that I know what has to be done: the abstract values and the operations upon them have to be captured in a formal system. Independent of the program we can ask ourselves if we think that the axioms of that formal system capture the subject matter we would like to talk about. (I hope that this remark silences the complaint: "When do you know that the given specifications are the ones intended?" The obvious answer is: "Never, but we can do our best in trying to be pretty sure.") Using techniques —see Hoare's article on the correctness of data representations in ACTA INFORMATICA— we can verify formally that our manipulations on our represented values satisfy the axioms of the abstract formal system. Usually we don't do that!

3.2   The situation is a little bit more serious in the sense that we are often willing to use known properties of the abstract world to "guarantee" things about the histories displayed by the represented values manipulated. 

We shall argue that a certain loop does terminate because we can relate each history to a directed path on a graph —our abstract entity— of which we know that it has no cycles! And such a sweeping statement is not without danger when, for instance, each terminal "leaf" is represented as a node with an arc leading from itself to itself! Yet we do it, and I do as yet see no real alternative. The best seems to be aware of it —and to hesitate three or four times when introducing "a cunning representation convention." Without further information and further thought I assume for the time being that this oscillation between "the representation" and "what it stands for" is an intrinsic part of the programmer's game, of which he had better be aware! (It could be also this oscillation, which makes programming so difficult for people untrained to switching between levels.)

4.  On the plus-side is certainly that our approach has shown the possibility to separate to a much higher degree than I was able to achieve before, the correctness concerns on the one hand from the efficiency concerns on the other. It is only for the latter concerns —which only have a meaning with respect to an implementation— that the other interpretation of the program text —viz. as executable code— becomes relevant. 

The half aspect taken into account during the past year was "the corresponding computational processes." It was only taken into account as a source of efficiency considerations —based upon fairly neutral assumptions regarding time and space requirements of the implementation—, as a means of providing a motivation for preferring one possible (correct) solution above another possible (and equally correct) one. Again some remarks are in order.

5.  Under the assumption of availability of (in particular) the array operations —the fact that in actual fact integers stored have to remain within a bounded range can be dealt with in the usual way— our mini-language allowed very efficient and delightfully compact algorithms of great sophistication, and was certainly helpful in their discovery. This was very encouraging and it was refreshing to get hints that many of the usual bells and whistles of our powerful programming languages —possibly including recursion!— had perhaps better be discarded.

6.  Thanks to the fact that precise execution times had been left undefined a host of optimization problems became meaningless (leaving one's mind free to replace an algorithm of cubic growth by one of quadratic growth, say). It is a mistake to think that without precise execution times, the programming task —at least the efficiency part of it— becomes empty or trivial. When we shift our attention from "efficiency" to "robustness", we hope —and to be quite honest: trust— to be able to do so without (in complete analogy) postulating precise probabilities for various forms of malfunctioning, yet retaining the ability to "increase robustness by an order of magnitude" in very much the same way we as we could "increase the efficiency by an order of magnitude" without fixing the execution times.

6.1  The unwillingness to make precise assumptions about the execution times or fault rates is not only a (commendable!) laziness from my side: it does also provide a means by which one's considerations gain in general applicability. (How many of Don Knuth's optimizations based on counting memory accesses will lose their validity under the assumption of a small associative store?)

6.2  My stubborn unwillingness to restrict the erratic behaviour of the daemon which is assumed in the implementation of non-determinacy is a decision of the same category. 

As I have argued elsewhere —in EWD447— scientific thought derives its effectiveness from our willingness and ability to isolate an aspect of our problems temporarily and to try to study it for a while in isolation, for the sake of its own consistency, so to speak. This "focusing of one's attention" is different from (completely) ignoring the other aspects, for the one who does the latter is, indeed, a narrow-minded fool whose work cannot be expected to have any significance outside the little world he has created for himself. Consciously trying not to be a narrow-minded fool, I have tried to focus my attention upon the correctness problem, without forgetting about the engineering considerations that are related to the computational histories. There was a reason for tackling the correctness issue first —besides it being easier— and that is the following. (I mention it, because it seems often overlooked.)

In very pragmatic environments, it is often argued that "our software need not be more reliable than our hardware." (Note. This statement only makes sense if, with respect to software, the adjective "reliable" can be used in exactly the same meaning as with respect to hardware— otherwise we let ourselves in for statements like "this cup of tea is sweeter than that cup of coffee is hot"—; anyhow I have my doubts.) As an assumed consequence it is allowed that programs may contain errors producing erroneous results, erroneous results that could have been provoked by hardware malfunctioning as well: they will be caught by the same recovery mechanisms that have to be included anyhow. Here, however, I have a few comments.

7.  From a point of view of maintenance of the hardware —of which we must assume, in contrast to software, that it is subject to wear and tear— it is highly desirable to be allowed to conclude from certain recovery needs that only —hopefully rather specific— hardware malfunctioning can have caused them!

8.  Even if we allow malfunctioning and introduce recovery protocols, we would like the recovery process itself —please!— to be correctly programmed! This gives a certain technical priority to the problem of program correctness over recovery.

9.  The task of recovery is one that I can only understand in relation to what a correct program correctly executed would cause to happen. This gives a certain philosophical priority to the problem of program correctness.

10.  I am not sure that such systems of hierarchical recovery do not suffer from the same disease as most "system engineering systems" seem to suffer from: having understood from Winer that a system should have feedback, they make a religion out of "design iteration cycles" without worrying whether the iteration converges towards something acceptable. Looking at the history of 0S-like projects, one can only get the impression that they often don't do so.

*                     *
*

In the three-day interval denoted by the above stars I cleared up a confusion in my mind that I must deal with first, before I can proceed. It has to do with so-called "defensive programming." We teach students explicitly that if in a certain point in the program only three cases are allowed to occur, and all three have to be dealt with separately, the program should not test explicitly for the presence of two cases, and treat by default anything else as "the third case," but that for the third case should be tested explicitly as well. (That with the advent of the guarded commands the temptation for which we had to warn has largely disappeared, is fine, but here of no relevance). In the history of the program, including its development, such "superfluous tests" played, however, very different roles!

In the beginning —we know how programs used to be!— they were a debugging aid. And upon the alarm that a fourth case, uncatered for, was presented, we usually still had to figure out, whether not catering for the fourth case had been an omission of the program part, or whether the fourth case had been erroneously produced by a program bug somewhere else! (It is typically the function of explicit program interfaces to settle that dispute in advance.) In any case the alarm was taken at the beginning as the indication of a program bug. By the time that one was fully confident in the program's correctness —fully confident to the standards of those days—, however, one did not remove the checks, on the contrary! If, after intensive use of such a debugged program, one of these checks suddenly gave an alarm, the first thought was a detected machine malfunctioning.

If in the following I consider the justification for additional checks, it will always be in that second function. While designing "correct programs" as I have been considering during the past period, I always assumed a perfect machine in the case that you wanted the program executed. (Perhaps you were not interested in its execution at all: the question of the program's correctness still makes sense.) But now I am shifting my attention from the program towards its execution, and now I must assume a perfect program! I pretend to be no longer interested in the question of the correctness of the program, but only to be interested in the correctness of the answer, the correctness of the execution. I know that this violates our common sense of modesty. Yet this is the only sensible assumption that I can make if I want to separate the various concerns, and if I don't do that, I know that I shall never come to grips with the problem. (If it hurts too much, we shall assume our programs to have been made by The Good Lord Himself, in exactly the same way as we have delegated last year the execution of our programs to The Good Lord's Machine GLM!)

*                     *
*

So we envisage the situation of a perfect program executed by a possibly lousy machine, i.e. a machine that possibly does not provide a perfect implementation of our programming language (and those who regard this situation so utterly realistic as to have difficulty in reading on, I can only beg to have patience, lots of patience...).

In our aims we may be modest or ambitious: in the modest approach we only try to decrease the probability of producing the wrong result, in the ambitious approach we try also to increase the probability of producing the right result, the difference being in the probability that the machine "gives up." In the modest approach the adagium will be "When in doubt, abstain!", in the ambitious approach the adagium will be "When in doubt, try something else, try to recover!". The ambitious approach is clearly self-defeating if the decreasing probability of "giving up" is brought at the price of an increasing probability of producing a wrong result, i.e. our modest approach points at a goal that we should never forsake; it is the most fundamental of the two, and therefore, I shall focus my attention upon that one first. (It has the added advantage of seeming to be the easier of the two).

How can we increase our confidence —because that is now what it boils down to— that during program execution nothing has gone wrong? Well, the machine can certainly assist by its very structure to increasing that confidence. There is one very important way in which it can do so, so important as a matter of fact, that we may state that a well-designed machine must do that.

I assume that our programs have been written for the GLM, because that is a machine we can hope to be able to program for. The designer of the actual machine knows —or at least, he should know— that he is not the Good Lord Himself, and that he can hope at most to build a partial simulator of the GLM. While in the GLM, for instance, there is in principle no upper bound on the maximum value of integer variables, the actual machine simulating the behaviour of the GLM may be such —usually is such— that it can only cope with integers up to a certain limit. The simulator should check constantly whether it fails, not by virtue of malfunctioning, but by virtue of its designed construction, to simulate the GLM faithfully. As a result a test on overflow of integer capacity is absolutely essential and a machine which in order to remain in range, reduces integer values, for the sake of its own convenience and without warning, modulo something, is a monstrum, unfit for human use. From now onwards we assume that the design of the actual machine is perfect as well, perfect in the sense that — apart from malfunctioning— no wrong answers will be produced in account of undetected inability to simulate the GLM, as incorporated in the design. (The simulation of the GLM's behaviour is only claimed for a subset of the computations that could take place in the GLM. The simulation as designed is only a partial function of the correct programs + input, and it is the duty of the actual machine to check that in this sense it is not invoked outside its domain.)

So far so good. But now the problems come. There are two types of results: there is the result that is laborious to find, but easy to check, once you have it, there is also the result that is not only laborious to find, but equally laborious to check, once you have it.

Suppose that we know how to multiply quickly, but don't know how to extract a square root. Then "finding the square root" will be regarded as a laborious process, in order to check it, we only need to compare the square of the result with the argument.

Suppose that we want a very large number to be factorized in prime factors. If the result is a long series of small factors of which we know that they are all prime numbers, we only need to multiply them with each other, in order to check that the original number returns. But what, if the outcome of the computation is that the given number itself is already a prime number? (It is then clearly a prime not known to us, because otherwise there would have been no point in providing it as the argument to our factorization program!)

At first sight, there seem only two ways of increasing our confidence in the correctness of a result that is as laborious to check than it is to find. And in a certain sense they both seem to double the costs of computation.

The one way is usually described as "repeating the computation." If the repetition is done —as they some times do— with a different program and/or a different machine and/or a different mathematical approach, and the two answers confirm each other, we have checked in some way a lot more than the correct execution of a program. We shall —in accordance with the position taken— ignore those additional advantages, and only remark, that comparing two independently derived results is only any good if the result is unique, if we could come away with a deterministic machine. I think —but this is no more than a feeling— that even for the answer of a non-deterministic computation matters can be arranged in such a way that verification can be done at a price similar to construction of the result.

The other way is indeed relying on the result, "without back-substitution" so to speak, because one knows that the individual steps of the simulation of the GLM have been checked rather abundantly. The second approach has the undoubted advantage of being a general purpose solution; add to this the advantage of getting diagnostic information about hardware functioning, and it is clear that no computer manufacturer can afford not to explore the possibilities of that approach. It is, however, not the whole story, for such a machine makes the outcome of a long computation still less trustworthy than the outcome of a short one. Trying to supply the rest of the story is one of the things I should do!

*                     *
*

The above, which has the nature of a research proposal, was written about three months ago, from which it can be deduced that, in the mean time, I have been engaged on other tasks. At odd moments I have given some attention to the problem of increasing the reliability of answers produced by a not fully reliable machine, but I intend to describe these exercises in separate documents. I can, however, already mention one tentative conclusion.

One way of trying to prevent the machine from producing a wrong answer is trying to prevent it from making any undetected error. This very puritan attitude shifts the stress from the correct answer to the correct machine, and from the point of view of hardware maintenance, it might be the most helpful one.

My experiments, however, seemed to indicate that "checking the machine" to such an extent is a very hard problem, and that the whole problem becomes more manageable if we don't care for such machine malfunctions that, although "malfunctions" in the sense of not being intended behaviour, are harmless insofar that, despite their occurrence, the final answer will still be correct.

The simplest example of such a malfunctioning is when in a repetitive construct

do B -> S od

after B has been correctly evaluated to the value "true" the execution of S erroneously reduces to the empty statement "skip." This is a completely harmless error, and I am afraid that it would be very expensive to catch.

Although being a puritan by nature, I expect therefore to confine my attention at first to the prevention of the generation of wrong results.

31st January 1975 | prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Jordan Olsommer
last revision Monday, 14 August 2006

EWD453

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Finding the maximal-strong components in a directed graph.

Given a directed graph, i.e. a set of vertices and a set of directed edges, each leading from one vertex to another, it is requested to partition the vertices into so-cal1ed “maximal strong components”. A strong component is a set of vertices, such that the edges between them provide a directed path from any vertex of the set to any vertex of the set and vice versa; a single vertex is a special case of a strong component: then the path can be empty. A maximal strong component is a strong component to which no further vertices can be added.

In order to establish this partitioning, we have to be able to make two kinds of assertions: the assertion that vertices belong to the same strong component, but also —because we have to find maximal strong components— the assertion that vertices do not belong to the same strong component.

For the first type of assertion, we may use the following

Theorem 1. Cyclically connected vertices belong to the same strong component.

Besides (directed) connections between individual vertices, we can talk about directed connections between different strong components: we say that there is a connection from a strong component A to a strong component B if there exists a directed edge from a vertex of A to a vertex of B. Because A and B are strong components; there is then a path from any vertex of A to any vertex of B. And as a result, Theorem 1 can be generalized into

Theorem 1a. Vertices of cyclically connected strong components belong to the same strong component.

Corollary 1. A non-empty graph has at least one maximal strong component without outgoing edges.

So much for theorems asserting that vertices belong to the same strong component. Because for different points to be in the same strong component, there must be paths between them in both ways, assertions that vertices do not belong to the same strong component can be made on account of

Theorem 2. If the vertices are subdivided into two sets svA and svB, such that there exist no edges originating in a vertex of svA and terminating in a vertex of svB , then

firstly: | the set of maximal strong components does not depend on the presence or absence of edges originating in a vertex of svB and terminating in a vertex of svA , and
secondly: | no strong component comprises vertices from both sets.

From Theorem 2 it follows that as soon as a strong component without outgoing edges has been found, we can take its vertices as set svA and conclude that this strong component is a maximal strong component and that all ingoing edges of svA can further be ignored. We conclude

Theorem 2a. A strong component whose outgoing edges, if any, are all ingoing edges of maximal strong components, is itself a maximal strong component.

Or, to put it in another way: once the first maximal strong component without outgoing edges —the existence of which is guaranteed by Corollary 1— has been found — identified as such by being a strong component without outgoing edges— the remaining maximal strong components can be found by solving the problem for the graph consisting of the remaining vertices and only the given edges between them. Or, to put it in still another way, the maximal strong components of a graph can be ordered according to “age”, such that each maximal strong component has only outgoing edges to “older” ones.

In order to be able to be a little bit more precise, we denote by

sv: | the given set of vertices (a constant)
se: | the given set of edges (a constant)
pv: | a partitioning of the vertices of sv .

The final relation to be established can then be written as

R: | pv = MSC(se)

in which for the fixed set sv the function MSC, i.e. the partitioning in Maximal Strong Components, is regarded as a function of the set of edges se.

The corresponding invariant relation is suggested by the standard technique of replacing a constant by a variable, se1 say, whose value will always be a subset of se:

P: | pv = Msc(se1) .

Relation P is easily initialized for empty se1 —i.e. each.vertex of. sv is a maximal strong component all by itself— . Because se1 is bounded in size by se , monotonically increasing se1 is guaranteed to terminate; if we can accomplish this under invariance of P , relation R has been established by the time that se1 = se . In our discussions it will be convenient also to have a name, se2 say, for the remaining edges, i.e. se = se1 ⏉ se2

Our task is clearly to discover the most convenient order in which edges are to be added to se1 , where “convenience” is related to the ease with which the invariance of relation P is maintained. This, as we know, can also be phrased as: what is our general intermediate state, what types of pv-values do we admit? In order to describe such a general intermediate state, it seems practical to group the vertices of sv also in disjoint subsets (as we have done for the edges: sel and se2 ). After all: we are interested in partitioning vertices!

The general intermediate state should be a generalization of both initial and final state. At the beginning, for none of the vertices it has been established to which maximal strong component in MSC(se) they belong, eventually it has been established for all vertices. Analogous to se1 we can introduce (initially empty and finally comprising all vertices) sv1, where

sv1 | contains all vertices of sv , for which the maximal strong component
| in MSC(se) to which they belong has been identified.

We intend to use Theorem 2a for deciding that a strong component is at maximal one, that is, after having established something about all its outgoing edges, when we now identify:

se1 | with the set of all processed edges, and
se2 | with the set of all unprocessed edges, i.e. edges whose presence has not
| yet been taken into account,

then we see that

P1: | all outgoing edges of vertices in sv1 are in se1.

It is, however, too crude to group all remaining vertices in a single set sv2. The way in which sv1 is defined implies that, each time a new maximal strong component of MSC(se) has been identified, all the vertices of that maximal strong component have to be transferred together to svl Between two such transfers, in general a number of edges have to be processed (i.e. transferred from se2 to se1 ), and for the description of the intermediate states that have to be taken into account with respect to “processing one edge at a time”, the remaining vertices have to be separated a little bit more subtly, viz, into two disjoint subsets, sv2 and sv3 say, (with sv = sv1 ⏉ sv2 ⏉ sv3 ), where sv3 contains the totally unprocessed vertices, P2: no edge in se1 begins or ends at a vertex in sv3, sv3 is initially equal to sv and finally empty).

Transfer from sv3 to sv1 can then take place in two steps: from sv3 to sv2 (on at a time) and from sv2 to sv1 (together with all other vertices from the same definite maximal strong component).

In other words: among the vertices of sv2 we shall try to build up (by enlarging sel) the next maximal strong component of MSC(se1) to be transferred to sv1, The maximal strong components in MSC(se1) —note the argument!— are such that they comprise either vertices from sv1 only, or vertices from sv2 only, or a (single) vertex from sv3 . We propose a limitation on the connections that the edges of se1 provide between the maximal strong components in MSC(se1) that contain nodes from sv2 only: between those maximal strong components the edges of se1 shall provide no more and no less than a single directed path, leading from the “oldest” to the “youngest” one. We call these maximal strong components “the elements of the chain”. This choice is suggested by the following considerations.

Firstly, we are looking for a cyclic path that would allow us to apply Theorem 1 or 1a , in order to decide that different vertices belong to the same maximal strong component. Under the assumption that we are free to prescribe which edge will be the next one to be added to se1 , there does not seem to be much advantage in introducing disconnected maximal strong components in MSC(se1) among those built up from vertices of sv2 .

Secondly, the directed path from the “oldest” to the “youngest” component in the chain —as “cycle in statu nascendi”— is easily maintained, as is shown by the following analysis.

Suppose that se2 contains an edge that is outgoing from one of the vertices of the youngest maximal strong component in the chain. Such an edge “e” is then transferred from se2 to se1 , and the state of affairs is easily maintained:

1) | if e leads to a vertex from sv1, it can be ignored on account of Theorem 2;.
2) | if e leads to a vertex from sv2 , the youngest element of the chain can be combined

with zero or more next older elements to form the new youngest element of the chain; more precisely: if e leads to a vertex in the youngest element, it can be ignored, if it leads to an older element in the chain, a cycle between strong components has been detected and then Theorem 1a tells us, that a number of the younger elements of the chain have to be combined into a single one, thus reducing the length of the chain, measured in number of elements.

3) | if e leads to a vertex from sv3, that latter vertex is transferred to sv2 and

as new youngest element (a maximal strong component in MSC(se1) all by itself) it is appended to the chain, whose length is increased by one.

If there exists no such edge “e”, there are two possibilities. Either the chain is non-empty, but then Theorem 2a tells us, that this maximal strong component of MSC(se1) is a maximal strong component of MSC(se) as well: the youngest element is removed from the chain and its vertices are transferred from sv2 to sv1. Or the chain is empty: if sv3 is not empty, an arbitrary element of sv3 can be transferred to sv2 , otherwise the computation is finished.

In the above degree of detail we can describe our algorithm as follows:

| se1, se2, sv1, sv2, sv3 := empty, se, empty, empty, sv;
| do sv3 ≠ empty → {the chain is empty} .
|  | transfer a vertex v from sv3 to sv2 and initialize the
|  |  |  | chain with {v};
|  | do sv2 ≠ empty → {the chain is non-empty}
|  |  | do se2 contains an edge starting in a vertex of the youngest
|  |  |  |  | element of the chain →
|  |  |  |  |  | transfer such an edge e from se2 tot se1 ;
|  |  |  |  |  | if e leads to a vertex vi in svl → skip
|  |  |  |  |  |  | ▯ e leads to a vertex v in sv2 → compaction
|  |  |  |  |  |  | ▯ e leads to a vertex v in sv3 → extend chain and
|  |  |  |  |  |  |  | transfer v from sv3 to sv2
|  |  |  |  |  | fi
|  |  | od {the chain is non-empty}
|  |  | remove youngest element and transfer its vertices from. sv2 to svl
|  | od {the chain is again empty}
| od

Note 1. As soon as vertices are transferred from sv2 to sv1 , their incoming edges (if any) that are still in se2 could be transferred simultaneously from se2 to se1 , but the price for this “advanced” processing —the gain of which is doubtful— is that we have to be able to select for a given vertex the set of its incoming edges: as the algorithm is described, we only need to find for each vertex its outgoing edges. Hence the above arrangement. (End of note 1.)

Note 2. Termination of the innermost repetition is guaranteed by decrease of the number of edges in se2; termination of the next embracing repetition is guaranteed by decrease of the number of vertices in sv2 ⏉ sv3 ; termination of the outer repetition is guaranteed by decrease of the number of vertices in sv3 . The mixed reasoning, sometimes in terms of edges and sometimes in terms of vertices, is a symptom of the non-triviality of the algorithm we are developing. (End of note 2.)

To the degree of detail in which we have described our algorithm, each edge is transferred once from se2 to se1 and each vertex is transferred once from sv3 via sv2 to sv1 : as such our algorithm implies an amount of work linear in the number of edges and vertices. In our next refinement, we should try not to spoil that pleasant property, as we would do if, for instance, the test, whether v is in sv1 , sv2 or sv3 —which occurs within the innermost repetition!— implied a search with a computation time proportional to the number of vertices. The restricted way in which our vertex sets are manipulated, in particular the fact that the vertices enter and leave the chain in last-in-first-out fashion, can be exploited for this purpose.

We consider our vertices consecutively numbered and tabulate the function “rank(v)”, where v ranges over all vertex numbers; we assume NV to denote the number of vertices:

rank(v) = 0 means: vertex nr. v is in sv3

rank(v) > 0 means: vertex nr. v is in sv1 ⏉ sv2

(The sets sv2 and sv1 are, to start with, combined: one of the possible forms of compaction is a skip!)

If nvc equals the “number of vertices in the chain” —i.e. the number. of vertices in sv2 — then
1 ≤ rank(v) ≤ nvc means: vertex v is in sv2
rank(v) ≥ NV + 1 means: vertex v is in sv1
All vertices in sv2 will have different rank-values, and as far as rank and nvc are concerned, transferring vertex v from sv3 to sv2 will be coded by

| “nvc:= nvc + 1; rank:(v) = nvc”

i.e. the vertices in the chain are “ranked” in the order of increasing “age in the chain”. The latter convention allows us to represent, how the vertices of sv2 are partitioned in strong components quite efficiently: vertices belonging to the same element of the chain have consecutive values of rank , and for the elements themselves, the rank of their oldest vertex is an increasing function of the element age. Using cc(i) to denote the rank of the oldest vertex of the i-th oldest element of the chain —we have then: cc.dom = the number of elements in the chain— , as far as rank , nvc and cc are concerned, we can code the alternative construct (combining the first two alternatives) as follows:

| if rank(v) > 0 → do cc.high > rank:(v) → cc:hirem od
|  | ▯ rank(v) = 0 → nvc:= nvc + 1; rank:(v)= nvc; cc:hiext(nvc)
| fi

In the mean time we have somewhat lost trace of the identity of the vertices in the chain: if, for instance, we would like to transfer the vertices of the youngest element of the chain from sv2 to sv1 , our current tabulations would force us to scan the function rank for all values of v , such as to find those satisfying cc.high ≤ rank(v) ≤ nvc . We would not like to do that, but thanks to the fact that at least for the vertices in sv2 , all values of rank(v)are different, we can also store the inverse function:
for 1 ≤ r ≤ nvc: rank(v) = r <=> knar(r) = v

So much for keeping track of the vertices; let us now turn our attention to the edges. The most crucial question with regard to the edges is, of course, the guard of the innermost repetitive construct: “se2 contains an edge starting in a vertex of the youngest element of the chain”. That question is answered easily with the aid of a list of edges from se2 , outgoing from the vertices of the youngest element of the chain. One of the ways in which the youngest in the chain may change, however; is compaction: in order to maintain that list we therefore, also need the corresponding lists for the older elements of the chain. Because for those edges we are only interested in the identity of their “target vertex”, we introduce as the next part of our chain administration two further array variables —with domain = 0 when the chain is empty— called “tv” (for target vertices) and “tvb” (for “tv-bounds”).

The domain of tvb will have one point for each element of the chain: its value equals the number of outgoing edges of se2 from vertices of older elements in the chain (the domain of tvb is all the time equal to that one of cc , which also stores one value for each chain element). Each time a new vertex v is transferred from sv3 to sv2 , the array tvb is extended at the high end with the value of tv.dom , whereafter tv is extended at the high end with the target vertices of the outgoing edges of v . Denoting that latter operation with “extend tv with targets of v ” the whole inner repetition now becomes —taking knar , tv and tvb into account as well—

| “inner loop”:
| do tv.dom > tvb.high →
|  | v, tv:hipop
|  | if vrank(v) > 0 →
|  |  |  |  | do cc.high > rank(v)→ cc:hirem; tvb:hirem od
|  |  | ▯ rank(v) = 0 →
|  |  |  | nvc:= nvc + 1; rank:(v)= nvc; knar:hiext(v);
|  |  |  | cc:hiext(nvc); tvb:hiext(tv.dom);
|  |  |  | “extend tv with target of v ”
|  | fi
| od

We had introduced for vertices v in sv1 the convention: rank(v) > NV. We can make a stronger convention by numbering the maximal strong component from 1 onwards (in the order in which they are detected) and introducing the convention that for a vertex. v in sv1 we will have

| rank(v) = NV’+ v’s maximal strong conponent number .

with the variable “strno” (initially = 0), we can new code the

| “middle loop”:
| do cc.dom > 0 →
|  | “inner loop”;
|  | strno:= strno + 1;
|  | do nvc > cc.high →
|  |  | nvc:= nvc - 1; rank:(knar.high)= NV + strno;
|  |  | knar:hirem; sv1count:= sv1count + 1
|  | od;
|  | cc:hirem; tvb:hirem
| od

(The variable sv1count —initially = 0— counts the number of vertices in sv1 : then sv1count = NM will be the criterion for completion of the task.

We assume the vertices numbered from 1 through NV , and the edges to be given by means of two array constants “edge” and “edgeb”, such that for 1 ≤ i ≤ NV the values of edge(j) for edgeb(i) ≤ j < edgeb(i + 1) give the numbers of the vertices to which the edges outgoing from vertex nr. i lead. We can then code

| “extend tv with targets of v ”:
| begin glocon edge, edgeb, v; glovar tv; privar j;
|  | j vir int := edgeb(v + 1);
|  | do j > edgeb(v) → j=: j - l; tv:hiext(edge(j)) od
| end

The last problem to be solved is the selection of an arbitrary vertex v from sv3 for the initialization of the chain. If each time the search would start at vertex nr. 1 , computation time could be proportional to NV², but again this can be avoided by taking a relation outside the repetition and introducing at the outer level a variable “cand” (initially = 1) with the property:

| sv3 contains no vertex v with v < cand .

| begin glocon edge, edgeb, NV; virvar rank; privar sv1count, cand, strno;
|  | rank vir int array := (1); do rank.dom ≠ NV → rank:hiext(0) od;
|  | sv1count vir int, cand vir int, strno vir int := 0, 1, 0;
|  | do svlcount ≠ NV →
|  |  | begin glocon edge, edgeb, NV; glovar rank, sv1count, cand, strno;
|  |  |  | privar v, cc, tv, tvb, knar, nvc;
|  |  |  | do rank(cand) ≠ 0 → cand:= cand + 1 od; v vir int := cand;
|  |  |  | nvc vir int := 1; rank:(v)= 1; knar vir int array := (1, 0);
|  |  |  | cc vir int array := (1, 1); tvb vir int array := (1, 0);
|  |  |  | tv vir int array := (1);
|  |  |  | “extend tv with targets of v ”;
|  |  |  | “middle loop”
|  |  | end
|  | od
| end

Note 1. A very similar algorithm has been developed independently by Robert Tarjan. (End of note 1.)

Note 2. In retrospect we see that the variable “nvc” is superfluous, because nvc = knar.dom . (End of note 2.)

Note 3. The operation “extend tv with the targets of v ” is used twice. (End of note 3.)

Remark 1. The reader will have noticed that in this example the actual code development took place in a different order than in the development of the program for the convex hull in three dimensions. The reason is —I think— the following. In the case of the convex hull, the representation had already been investigated very carefully as part of the logical analysis of the problem. In this example the logical analysis had been largely completed when we faced the task of selecting a representation that would admit an efficient execution of the algorithm we had in mind. It is then natural to focus one’s attention on the most crucial part first, i.e. the innermost loop. (End of remark 1.)

Remark 2.It is worth noticing the various steps in which we arrived at our solution. In the first stage our main concern has been to process each edge only once, forgetting for the time being about the dependence of the computation time on the number of vertices. This is fully correct, because, in general, the number of edges can be expected to be an order of magnitude larger than the number of vertices; (As a matter of fact, my first solution for this problem —not recorded in this chapter— was linear in the number of edges but quadratic, in the number of vertices.) It was only in the second stage that we started to worry about linear dependence on the number of vertices as well. How effective this “separation of concerns” has been is strikingly illustrated by the fact that in that second stage, graph theory did no longer enter our considerations at all! (End of remark 2.)

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

   EWD 454

Burroughs

PLATAANSTRAAT 5 NUENEN THE NETHERLANDS

DR. EDSGER W, DIJKSTRA

Dr.H.Bekic
IBM Laboratorium Wien
Parkring 10
1010 WIEN
Oostenrijk

8th October 1974

Dear Dr.Bekic,

            I received your letter of 2nd October 1973 yesterday and it distressed me to see that you found much of it quite upsetting. Perhaps one should not let other people peep in one's diary. I am not going to repeat here what I wrote you in my personal covering letter: it still holds and I trust that you will honour my request.

       In your letter you raise a number of questions, thereby challenging some of the opinions I expressed. The best I can do is to try to describe to you how I came to these opinions.

       To start with: my suspicions with regard to defining the semantics of programming languages by means of an interpreter are of quite long standing, at least compared to the youth of our field. My first suspicion was roused by the observation that whenever we invoke via our program an available primitive —such as an ADD-instruction, say— its occurrence in that program can only be justified by what that instruction achieves, by "what it does for you", rather than by "how it works". On the level of machine-code programming I could, for instance, not care less whether my machine has a serial adder or a parallel adder, as long as it adds. As soon as you decide to define what you mean by the sum of two numbers as the output of a carefully described adder when you feed it the operands as its input, you pay immediately a rather heavy price in at least two respects.

       Firstly, the properties of addition —such as being commutative and associative— are fairly well hidden and you have to prove them as a property of your adder. I considered that a heavy price because, as far as the use of the ADD-instruction is concerned, it is exactly these properties that matter.

       Secondly, it is practically impossible to give such a mechanistic definition without being over-specific. The first time that I can remember having voiced these doubts in public was at the W.G.2.1 meeting in 1965 in Princeton, where van Wijngaarden was at that time advocating to define the sum of two numbers as the result of manipulating the two strings of decimal (!) digits. (I remember asking him whether he also cared to define the result of adding INSULT to INJURY; that is why I remember the whole episode.) And being over-specific seemed harmful to me in more than one respect. Firstly one must state very carefully which aspects of the mechanism's behaviour are to be considered "essential" and which may be considered as "irrelevant", because without having done so it is impossible to consider an alternative but, in essentials, equivalent alternative. Secondly, the presentation of an alternative implementation presents the problem of demonstrating the equivalence of algorithms, a problem which I did not regard as an attractive one.

       At the moment, I could not offer van Wijngaarden an alternative technique for the definition of the semantics of programming languages, but feeling that the mechanistic definition did not seem to fulfil its most important functions too well, I started to think about how and why I would like to use the semantic definition. And as a result I started to think about how to prove the correctness of programs —not all the time! I had other axes to grind as well!—. And I discovered the following. At that time considerable attention had been paid to the question how to decide whether two programs were equivalent or not. (For this fact I can think of two explanations. It was one of the ways in which the problem of compiler correctness came to us; besides that, the boolean question "equivalent or not" has a certain mathematical appeal.) Very little attention —as far as I could find— had, however, been given to the question how to design programs in such a systematic way that they would be correct by virtue of the way in which they were constructed. That second question, however, seemed to me more relevant —after all: programs are not "given", they have to be "constructed"— and also more tractable. As the result of some exercises I wrote an article "A constructive approach to the problem of program correctness." (It was published in BIT: if I remember the dates correctly, it was written in 1967 and published in 1968.) Much of the argument was still fairly informal, all sorts of hand-waving included, but at that time I did not worry about that: before developing a formalism I wanted to get a feeling of the demands that would be made upon that formalism. About that time, three articles appeared that gave a first start towards such a formalism: Peter Naur's article about General Snapshots, Robert Floyd's article about Assigning meanings to programs, and, a year later Tony's article on the axiomatic definition in the Comm.A.C.M.

       I think that at that time, Peter's article appealed the most to me. From my reaction to Bob's article I remember that I was rather put off by his use of flowcharts and the resulting need to isolate cycles in the corresponding graph. Tony's article attracted me in the sense that it tied in with the syntactical structure of the program text, but the separation in axioms and rules of inference —a logical tradition, but not my tradition— worried me. My first reaction to these three articles was "Interesting, wait and see...".

       In the next years, Scott's Mathematical Semantics began to appear. I found that very difficult when I first saw it, on account of sheer lack of mathematical knowledge on my side. I studied a certain amount of it and also decided "Interesting, wait and see...". For a considerable period of time I hesitated whether I should develop my agility in the propositional calculus, or get a thorough knowledge of the ins and outs of lattice theory or both. I decided to wait another half year before tentatively making up my mind, and to go my own way in the mean time.

       As a side-effect of lectures I gave during that period of time, I learned how to develop in a systematic way the synchronization conditions needed to ensure a given form of harmonious cooperation between loosely coupled sequential processes. I became more and more constructive in my approach and the experience at that time is, I think, responsible for the fact that what for a number of years had been a matter of personal policy, now became a firm principle, viz. never to manoeuvre myself in to the position where I would have to derive the unknown properties of a given algorithm, nor to try to prove the correctness of a given algorithm a posteriori. Both problems struck me as putting the cart before the horse. When, later, I saw Wegbreit's article in the Comm.A.C.M, in which, for instance, he tried to find the invariant of a loop, I felt fully justified in my decision to avoid that problem.

       In the mean time the balance slowly started to tip over in favour of the axiomatic method compared to the mathematical semantics. While Tony's original article presented axioms or postulates about programming constructs of which it was not fully clear —at least to me— to what extent they could take the place of a definition of the semantics and while they only enabled the derivation of sufficient pre-conditions for partial correctness, that has been cleaned up and one can now give —very much in the same style— the weakest pre-condition for total correctness and as a system for semantic definition it now seems fully satisfactory. (In particular, all arguments in favour of "complementary definitions" as suggested by Hoare and Lauer in Acta Informatica seem to have disappeared —this is not only my impression: Tony confirmed it when I spoke to him last September—; thank goodness, for I never liked complementary definitions: that was another article of which I said to myself "Wait and see....", but this time in the hope that it would become superfluous.) Another reason why the balance started to tip over was that the probability that the theory could be forged into a tool, helpful for actual program construction, seemed greater for the axiomatic method than for mathematical semantics.

       The next tipping of the balance took place during the meeting of W.G.2.3 in Munich in April 1973, where John Reynolds gave for our instruction a commented survey of mathematical semantics. It then came towards me as a view of computing that can be appreciated for its consistency, for its conceptual unification, but not without a few drawbacks, which I am beginning to regard as serious. The first one is the size of the mathematical machinery involved, compared to which the propositional calculus —and for an axiomatic definition now nothing more seems needed— is negligible. Of course one can point out that up till now the axiomatic method is quite modest in its aims —e.g. no functions as values—, on the other hand, within that limited scope (and I am greatly in favour of choosing our limitations wisely) the cost/performance ratio —if you allow me the use of that term as one computing industrialist writing to another one— of the two different approaches seems to be very different. The second drawback is that defining the semantics as a minimal fixpoint is a very indirect one —some people would even call it clumsy—: first one needs functional analysis in order to introduce the concept of a fixpoint, and after that lattice theory to formulate that it is not just any fixpoint, but among the fixpoints the minimal one.

       A further reason that tipped the balance was our realization at that Munich meeting, that one of the usual motivations for the mathematical semantics does not hold water, viz. that the study of infinite computations is of importance for "operating systems and airline reservation systems". (We heard it repeated in Newcastle, if I remember correctly by Milner.) John Reynolds started in Munich also with the operating systems and the airline reservation systems and after that two minute motivation... he talked for the remainder of more than an hour about the logical difficulties of dealing with real numbers! It was a very nice and illuminating talk (at which I rejoiced that real numbers are no longer my problem!), but by the time it is suggested that one needs real number theory for dealing with operating systems and airline reservation systems, some hilarious mistake has been made. (Actually, that a theory for dealing with operating systems and airline systems can shed some new light on the real numbers is perhaps more probable.) The inclusion of infinite computations should have a better motivation, for instance for the sake of simplification of one's arguments (the invention of projective geometry by extending the Euclidean plane with its horizon is an example, where such an extension made a drastic simplification possible). Such a simplifying breakthrough, was not transmitted to me. It may happen one day —I try to keep my mind open— but I expect it less and less the more I realize to what extent the simplicity of the axiomatic method is dependent on the explicit restriction to computations which are guaranteed to be finite.

       Other facts that i take into consideration when trying to estimate significance and potential of a scientific theory are the problems it evokes and the problems it is applied to. You write to me in your letter "Nondeterminism is a phenomenon we are all interested in and the question how to deal with it in any given semantical framework seems to be a legitimate and interesting one." Of course, as long as you allow me to draw at least some conclusions about the apparent adequacy of such a "given semantical framework" when dealing with nondeterminism presents any more or less serious problems: the drawing of such conclusions seems to me the major purpose of such an exercise. I could not help comparing your struggle with the current state of affairs in the axiomatic method, in which non-determinism —as a matter of fact: to the extent of the non-determinism as displayed by a general, finite Petri net— enters the picture so naturally, that I have come to regard determinism as a special case (which, by the way, does not seem to be very interesting either, because, as far as mathematical manageability is concerned, there is hardly anything to be gained by restricting oneself to the fully deterministic case). I could not help to compare, could I?

       Furthermore, during the last decade there seems a shift of emphasis to have taken place, a shift of emphasis that seems worthwhile to draw your attention to, as also such an emphasis plays a role when trying to estimate significance and potential of a scientific theory. While in the beginning of formal definitions of programming languages the efforts were very much directed upon the needs and problems of the language implementer, this emphasis shifted during the next ten years via the problems of the language designer towards the needs of the language user. Taking into account that the combined users present the broadest interface, I think we must regard this as a healthy and welcome development. But such a shift has a profound influence on our appreciations.

       For instance, in the most recent Computing Reviews I found (CR27.102) Zemanek being quoted, when he observed that an axiomatic method only works for a "highly elegant environment". I hope that he is right. Under the assumption that he is, ten years ago this observation would have been interpreted as one of the shortcomings of axiomatic methods. Now, however, I think that we react inversely and say "One up for axiomatic methods!": at last a discipline which, when you stick to it, forces elegance on you! Great! And if I am then exposed to a lecture in which Scott has chosen to demonstrate the descriptive power of his method quite emphatically with an example including goto-statements, what do you think that happens to the balance? It, again, tips a little bit further. There is between the two of us perhaps a profound difference in appreciation of the "power" of a descriptive method: I do not care for the ability to describe things, of which I already know on other grounds that they had better be left alone, stronger: I rather had not such an ability.

       You see, that I am answering your letter backwards. I have not "dismissed the whole thing" (yet), but it is undeniable that the balance made a further tip. And I trust that you now understand why.

*                        *
*

On page 1 I described to you my first reasons for being suspicious as regards mechanistic definitions of semantics. As time went on, that suspicion grew. Defining the semantics of a programming language by means of an interpreter for it, defines the meaning of algorithms written in that programming language by means of . . . another algorithm! As such, it does not solve the problem, it only pushes it one stage further. But even if we assume to be able to understand —or "agree upon"— how the interpreter is supposed to act, what then can we do with that interpreter, when faced with a program written in the language concerned? Well, the interpreter can interpret the program, provided we choose values for the input. But that gives us no more information than program testing, and such sampling will never enable us to make assertions pertaining to "any" input value of the domain. So how can we proceed? Well, we could try to prove —how is somewhat mysterious, but for the sake of the argument we can suppose that we can— certain properties of the programs being interpreted, which, of course, must depend on the program text. But seems this a sensible approach? I do not think so.

       Firstly, the mystery of how we can prove such properties of the interpreter bothers me, but secondly, it seems a very tortuous way of deriving properties of the programs interpreted, because if those are the properties we are after, why not postulate directly, how they depend on the program text and forget about the whole interpreter? That seems much more efficient. Instead of interpreting program text as a piece of executable code, we can also give it a completely timeless interpretation and introduce axiomatically how each program text defines a relation between the initial state space and the final state space. (If I am in a very puritan mood, I even talk about the left-hand state space and the right-hand state space, just in order to remove all connotations with sequential execution.)

       If you start to think about it, the advantages of the latter approach are overwhelming. It gives, for instance, a clear distinction between the semantics of the programming language proper —i.e. how the text defines a relation between the left-hand state space and the right-hand state space— and its implementation. Correctness concerns belong to the realm of the semantics of the programming language proper, efficiency concerns have only a meaning with respect to a specific implementation, and nothing is gained by mixing these concerns, on the contrary.

       In one mood I can regard the program text as a mathematical object and convince myself that, according to the rules of the semantics it defines the desired relation between left-hand state space and right-hand state space: time, sequencing, alternative actions, repetition, determinism, intermediate machine states and all that, none of it needs to enter my mind, when I am in that mood (if it does, it is only confusing, because irrelevant as far as correctness is concerned). In another mood, I can ponder about the price of execution by a given implementation, for instance by knowing that, what in my first mood was something like functional composition, indicated in the text by, say a semicolon, corresponds in that implementation to a concatenation in time of two activities, separated by "an intermediate state of that machine". In that second mood, however, I need not worry about the question whether the execution will produce the desired result.

       The grave disadvantage of defining programming language semantics by means of an interpreter is that it defines the relation between left-hand state space and right-hand state space as the result of a computational process, as the last of a long series of machine states, while during correctness considerations, of this long series only the first and the last matter. But if the intermediate ones don't matter, please define your semantics in such a way that they don't enter the picture to start with. As far as thinking about programs and programming languages is concerned, that is much more efficient. Distinguishing in one's mind between a programming language and its implementation(s) is already difficult enough, (as illustrated by not uncommon assertions such as "ALGOL 60 is an inefficient language" or "PL/I pointers are more efficient than ALGOL 68 references", sentences so elliptic as being close to nonsense).

       When I first heard that the Vienna crew were tackling the formal definition of PL/I, I was horrified, because on account of what I knew of it, PL/I seemed to me one of the most unattractive objects to give a formal definition of. I certainly did not envy them their job. The next thing I heard was that a definition by means of an abstract interpreter was chosen, a message to which I could give only one interpretation, viz. that, indeed, PL/I was a most unattractive object to give a formal definition of. Without further knowledge I have assumed without hesitation that "an interpreter" was at least your second choice, as I could not envisage the Vienna crew not sharing a good fraction of my misgivings about mechanistic definition of semantics. (And I still believe that they are shared by many of its members.) And when I received what is known as "The Vienna Telephone Directory", I was once more horrified; also very much impressed. I had not the slightest intention of being "unfair" to the Vienna crew and, if you smelled criticism, it was criticism regarding PL/I rather than VDL. But you understand that the whole project struck me as a relatively successful attempt to make the best of a bad job. That "at least with metalanguages we should be given a chance to correct our mistakes" is a prayer that has my full sympathy, I would even like to extend the prayer to programming languages.

       With some of the points raised in the preceding paragraph I have more or less dealt, but not with your suggestion that eventually the study of such a merging operator is unavoidable. Is it? And, if so, has it a place in the definition of the semantics of programming languages? I am not so sure. In the case of what is usually called a sequential programming language, we have seen that as far as its semantics are concerned a completely time-less interpretation suffices, so time-less, as a matter of fact, that even the notion "before-after" has no place. For the sake of convenience one is usually not a puritan and one talks about initial and final state, about pre- and post-conditions, but I found it most convenient to start at the post-condition. (To follow the relation the other way round is something I gladly leave to the machines!) Stronger: on that level it is totally irrelevant that one's primitives and the way in which they may be combined, are such that implementation by a sequential machine is absolutely straightforward. The usual consequence of such choices is that the implementation by a machine that we would like to display more concurrent activity is less obvious.

       One can certainly think about a programming language for which the primitives and the way in which they may be combined have carefully been chosen in such a way that implementation by a "less sequential machine" becomes equally obvious, but again: the way in which its semantics have been defined need (and I think, therefore should) in no way reflect this fact. It is not unthinkable that the implementor can exploit nondeterminism of the programming language by omitting some synchronization constraints, leaving speed ratios rather undefined, you name it. But starting at this end the nondeterminism has already been introduced in the usual noiseless fashion and one is never faced with the question what all possible sequences may do in the sense that, whatever sequence may be chosen, one has already established that what will happen will be acceptable, so one does not bother about what happened. The merging operator only needs to be studied if one intends to use it to generate non-determinism that one can then study. I should rather start with the non-determinacy at the semantic level and later exploit it while implementing.

       Compared with the mechanistic approach this is, of course, in the other way. I think it is easier. The only thing the traditional logicians did was to try to find a model for the real world, but, since in the form of computing science logic has also become an engineering activity, I prefer the real world to provide a model for my dreams. . . .

       As to the preceding paragraph of your letter: please don't be worried by the fact that in your first lecture you more or less failed to reach your public: not all kites fly. . . . (As you have seen, more or less the same happened to me in Edinburgh the day before. Of course one regrets it, but one should take the risk: it is vain to pretend all one's talks are a guaranteed success.)

       In view of the fact that you have sent a copy of your letter to nine gentlemen, I guess, that I should do the same with my answer to you. I hope that my explanations in this letter have made the trip report less upsetting. Please don't feel guilty on account of the length of the answer. It was a pleasure to write to you and to show to you, by doing so, my appreciation for the fact that you wrote to me in the first place.

       With my best wishes and warmest regards,

yours ever

Edsger

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

cc:
R.M.Burstall
C.A.R.Hoare
J.Hopcroft
E.S.Page
M.Rabin
B.Randell
D.S.Scott
S.Winograd
H.Zemanek

transcribed by Tristram Brelstaff
revised Thu, 25 Aug 2005

EWD456

Determinism and recursion versus non-determinism and the transitive closure.

Two years ago I pondered about the design of an intellectually well-manageable programming language, the implementation of which would allow a potentially very high degree of concurrency without imposing it (nor, of course, requiring the amount of temporary storage that would be needed to simulate the concurrency.) One can try to reach such a goal by the introduction of multi-component datatypes like in APL, but then the price to be paid seems to be a very elaborate repertoire of operations, and, having seen where that leads to, I obviously did not want to go down "that slippery road of reasoning".

I found myself considering the massaging —under control of a very limited repertoire— a set of n-tuples, the possibility of concurrence being modelled by the simultaneous creation of a whole lot of such n-tuples. Wanting to be kind to my hardware friends, I focussed my attention at a very early stage to the question whether I could fix n. Extremely far-fetched analogies suggested that if n could be fixed, it should be fixed at 4, and as a result the n-tuples became 4-tuples and were tentatively called "quadrons". In a next stage my (originally hardware) friend C. S. Scholten came with an argument that, whatever could be done using n-tuples could be done —after a fashion equally well— with k-tuples, with k = entier((n+1)/2)+2. After this encouraging confirmation of my hunches, we got stuck completely and the exercise was dropped for at least one-and-a-half year.

A number of months ago, the exercise was picked up again by W.H.J.Feijen and M.Rem (with some stress on the latter) and occasionally me. Analyzing the previous failure we came to the conclusion that the fixation n = 4 had been premature, so we dropped it and from then onwards called our n-tuples "associons". We tried again —and some of our efforts that need not concern us here, have in the mean time again been unmasked as dead alleys—, and one thing seems to have emerged more or less solidly: about our most central primitive operation can be viewed as forming the transitive closure, i.e. given a set of nodes of a finite, directed graph as "starting set", determine the set of all nodes reachable via a directed path from at least one of the nodes of the starting set.

*                *
*

The incentive to start the experiment two years ago was only partly a desire to explore the programming of potentially high concurrency, it was also the result of my difficulties in writing a — "sequential", i.e. ALGOL-like— program that should determine the convex hull of a (large) set of given points in three dimensions. For the convex hull in two dimensions I knew a host of algorithms; I tackled the three-dimensional version of that problem in the expectation that from that exercise I should be able to learn something about programming methodology. The first thing I learned was that I could not solve the problem nicely: what I tried became so messy —at least to my standards— that I aborted each effort long before I had reached a working solution. So I dropped that problem for the time being —apparently not ripe for it yet—and started to write a book instead.

The problem of the convex hull in three dimensions presents some difficulties which are absent in the two-dimensional version: it is not patently obvious how the result —and, therefore, intermediate states— should be represented in an (essentially) "linear" store, nor is it patently clear, how the two-dimensional surface should be processed by a "sequential" machine. Wanting to include in my book a true and non-embellished design history, —including the risk of failure—, I needed a non-trivial problem I had never successfully solved before. I chose the problem of the convex hull in three dimensions, and, after having reported what I had learned from my non-successful attempts, I started to try to solve the problem in earnest. I succeeded —as a matter of fact: I arrived at a solution which filled me with some pride— and my solution had two characteristics which seem worth mentioning. The one observation is that the need to introduce more-dimensional arrays emerged nowhere; the second observation is the central role played —at two/three places, in different disguises— by the task to determine a transitive closure. More precisely:

Given a finite set S and a subset B; for each element x of S, zero or more other elements of S are by definition "the consequences of x". Determine the set V, defined by
1)     each element of B belongs to V;
2)     if x belongs to V, so do its consequences
3)     V contains only elements that belong to it on account of 1 and 2.

The pattern of my program was as follows:

C := B; V:= empty;
do C ≠ empty → choose an arbitrary element c from C ;
    transfer c from C to V ;
    extend C with all consequences of c that do not
      belong to the (disjoint) union C + V
od

It is worth noticing that the intersection of C and V remains empty and that under the assumption that the time needed for the test for set-membership does not depend on the size of the set concerned, the time taken by this algorithm is absolutely independent of the choice for c: at each repetition the set V is extended with one new element.

In the case that the graph is a rooted tree, whose root node is taken as B, the problem of finding the transitive closure is also known under another name: traversing a tree. Its standard solution is a recursive one, stronger: the recursive solution for tree-traversal is often regarded as the prototype application for recursive procedures. If we compare the recursive tree-traversal with the above, more general, algorithm for the transitive closure, we see that the role of C is taken over by the anonymous stack. This can be done because in the case of tree-traversal the test, whether consequences of c are members of C+V can be suppressed: the absence of cycles in a tree guarantees that we shall never "meet" the same node more than once.

In my innocence, I had always regarded this recursive solution for tree-traversal etc. as a, in some sense, basic and fundamental algorithm, and for years I have taken the central role of anonymous stacks for granted. It was a little bit of a shock for me to discover that the anonymity of the stack is only allowed, provided that we restrict ourselves to a rather special case of a more general (and perhaps in its general form more "fundamental") problem, viz. the transitive closure. It made me wonder, whether in the last fifteen years —since LISP and ALGOL 60, say— we have perhaps over-emphasized recursive solutions, and have taken the last-in-first-out strategy for choosing c —often purely a matter of convenience, as far as storage management is concerned!— so much for granted, that the rediscovery of the freedom to select an arbitrary element c from C could rank as a scientific discovery of some sort.

The above may shed some light on current linguistic exercises in artificial intelligence work. A last-in-first-out queueing discipline engenders —as every operating system designer knows— the danger of individual starvation, and if the purpose of the algorithm is to traverse a finite portion of a potentially infinite tree, the last-in-first-out strategy is clearly unacceptable (whether other strategies will lead to acceptable performance is a question that falls outside the scope of this note). When, however, these linguistic exercises give birth to some system of recursive co-routines, should we not then raise the question, whether such exercises are not drastic enough, are only half-hearted attempts at freeing ourselves from the shackles of recursive solutions, which, perhaps, have dominated the scene already too long? (If the mere suggestion that recursive solutions may fail to be a cure for all our problems, don't blame me!)

The question, among other things, hinges upon the assumption that the problem of the transitive closure for directed graphs in which arrows may merge, is —besides being a logical generalization of the tree-traversal— a sufficiently frequently recurring theme to give it the status of "central problem". I cannot collect all evidence in the world, but I can give you some. Last Saturday morning the postman delivered two reports at my doorstep: "A case for the for-statement" by Edouard Marmier (ETH Zurich) and "Constructing correct and efficient concurrent programs" by M. Sintzoff and A. van Lamsweerde (MBLE Brussels) and I had a pleasant weekend studying them. When Marmier has remarked that for the sake of robustness, implementations should enforce a certain requirement —one of non-interference, essentially— he ends that paragraph by observing that even without additional information in the program text " . . . the problem of enforcing the requirement is only of moderate difficulty, since it reduces to the problem of forming the transitive closure of a directed graph. For this, a nicely implementable algorithm exists." The major part of the report by Sintzoff and van Lamsweerde is concerned with the problem of reducing the number of dynamic re-evaluations of synchronizing conditions. But the whole problem of determining, which sleeping processes can be woken up is one of determining a transitive closure! (A process goes to sleep when execution of a critical activity would cause violation of the imposed invariant relation. Such a critical activity remains pending until, after completion of another critical activity, it is detected that it could and decided that it should be fired. Such a secondary critical activity may enable other pending ones to proceed and the waking-up should continue until the fired critical activities have caused a state in which none of the still pending critical activities is kept pending without justification: only then the waking-up obligations have been fulfilled. The waking up has exactly the same cascading nature —with "merging arrows" included— as the detection of the transitive closure of a directed graph.) Was it entirely accident, that these two reports were dropped on my doormat simultaneously?

*                       *
*

While pondering about all this, it struck me that there is another area in which we encounter rooted trees, viz. the states of terminating computations in a (finite state) deterministic automaton: if we so desire, we can distinguish a forest of trees, with a one-to-one correspondence between terminal states and (roots of) trees. The question of the weakest precondition for terminating in a given final state amounts to traversing the tree with that final state as its root node. But consider now the non-deterministic automaton, in which some states may have a set of possible successor states. From a very operational point of view, one may feel forced to introduce some "ghost-input", because, without it, the automaton would not "know" which way to go: logically, however, this amounts to squeezing the non-deterministic automaton into the straitjacket of the deterministic one.

(In the process of mathematical discovery, the introduction of "something", from which then later can be "abstracted" is an utterly respectable one. But, once such an abstraction has been discovered, from a methodological point of view, I always feel that then the concept should be given its independent right of existence if it is to bear fruit. First Descartes introduces coordinates by choosing the axes arbitrarily; it is when the arbitrariness of this choice is fully realized, that coordinate-free methods are born, and I hope never to forget my excitement when I saw the following proof (from the lectures of J.Haantjes) of the fact that the perpendiculars of a triangle go through one and the same point. It defines H as the intesection of two perpendiculars and shows that the line through H and the third angle is also a perpendicular:
    given:   (a  −  h)  *  (b  −  c)  =  0
    given:   (b  −  h)  *  (c  −  a)  =  0
            ------------------------------- +
             −(c  −  h)  *  (a  −  b)  =  0    Q.E.D.
The usual high-school proof is by tortuously constructing another triangle, of which the original perpendiculars are the bisectors. So much for the fruits!)

The removal of the restriction to deterministic automata means that our "backward scan" can no longer be viewed as traversing a rooted tree, because such backward paths are now allowed to merge. (In this discussion it seems irrelevant that, if we want the weakest precondition it is not exactly the predecessor relation that we want the transitive closure of; we have something like
1)     all states satisfying R are in V
2)     each state whose successor set is in V, is itself in V as well.
The important thing is that we have departed from rooted trees.)

The methodological question that I am tempted to raise is the following: could the problem presented by generalizing the current theory of denotational semantics so as to cover non-determinism as well, be related to a preponderant role of recursive definitions, in a way "pushing" trees where more general graphs are needed?

*                   *
*

The next question to which I may need the answer by the time that I can formulate it precisely, is the following. Assuming that the formation of some sorts of transitive closures do indeed play the fundamental role that I currently do not exclude —all evidence in either direction would be most welcome!— and assuming that a "machine code" can be designed in which such operations are regarded as primitive, while we hope that they can be implemented by highly associative techniques, involving concurrent activity "all over the place"; assuming further, that such a machine code suggests solvability of a problem in orders of magnitude less exploding number of steps than today's complexity theory tells us. It certainly implies that my "machine" will be hard to build; will it also imply the impossibility to do so? I just don't know, to what extent the results of complexity theory can be carried over to unusual techniques. For instance, finding the shortest connection between two nodes of an undirected graph with positive edge-lengths is polynomial or something in the number of nodes and/or edges. How much of that argument, however, is applicable to the analogue device, that is made by replacing the edges by gas tubes of proportional lengths and applying a voltage difference between the two nodes? The spark will choose the shortest path. In polynomial time...?

If the above is clarifying or inspiring for any of its readers, I am glad that he saw it. If it evokes possibly helpful comments, I shall be glad to receive them.

14th October 1974
Burroughs
Plataanstraat 5
NEUNEN – 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Research Fellow

Transcription by Moti Ben-Ari.
Revised Fri, 13 Oct 2006.

(A replacement of EWD416)

EWD458

On non-determinacy being bounded..

This is again a very formal chapter. In the chapter "The characterization of semantics." we have mentioned four properties that wp(S, R) , for any S considered as a function of R , should have if its interpretation as the weakest pre-condition for establishing R is to be feasible. (For non-deterministic mechanisms the fourth one of these was a direct consequence of the second one.)

In the next chapter "The semantic characterization of a programming language." we have given ways for constructing new predicate transformers, pointing out that these constructions should only lead to predicate transformers enjoying the aforementioned properties (i.e. if the whole exercise is to continue to make sense). For every basic statement ("skip", "abort" and the assignment statements) one has to verify that they enjoy the said properties; for every way of building up new statements from component statements (semicolon, alternative and repetitive constructs) one has to show that the resulting composite statements enjoy those properties as well, in which demonstration one may assume that the component statements enjoy them. We verified this up to and including the Law of the Excluded Miracle for the semicolon, leaving the rest of the verifications as an exercise to the reader. We leave it at that: in this chapter we shall prove a deeper property of our mechanisms, this time verifying it explicitly for the alternative and repetitive constructs as well. (And the structure of the latter verifications can be taken as an example,for the omitted ones.)

Property 5. For any mechanism S and any infinite sequence of predicates C₀ , C₁ , C₂ , ... such that

for r ≥ 0:     Cr ⇒ Cr+1            for all states | (1)

we have for all states

wp(S, (E r: r ≥ 0: Cr)) = (E s: s ≥ 0: wp(S, Cs))    . | (2)

For the statements "skip" and "abort" and for the assignment statements, the truth of (2) is a direct consequence of their definitions, assumption (1) not even being necessary. For the semicolon we derive

wp("S1; S2", (E r: r ≥ 0: Cr)) =

(by definition of the semantics of the semicolon)

wp(S1, wp(S2, (E r: r ≥ 0: Cr))) =

(because Property 5 is assumed to hold for S2 )

wp(S1, (E r': r' ≥ 0: wp(S2, Cr'))) =

(because S2 is assumed to enjoy Property 2, so that wp(S2, Cr') ⇒ wp(S2, Cr'+1) and S1 is assumed to enjoy Property 5)

(E s: s ≥ 0: wp(S1, wp(S2, Cs))) =

(by definition of the semantics of the semicolon)

(E s: s ≥ 0: wp("S1; S2", Cs)) | QED.

For the alternative construct we prove (2) in two steps. The easy step is that the right-hand side of (2) implies its left-hand side. For, consider an arbitrary point X in state space, such that the right-hand side of (2) holds, i.e. there exists a non-negative value s', say, such that in point X the relation wp(S, Cs') holds. But because Cs' ⇒ (E r: r ≥ 0: Cr) and any S enjoys Property 2 , we conclude that

wp(S, (E r: r ≥ 0: Cr))

holds in point X as well. As X was an arbitrary state satisfying the right-hand side of (2), the latter implies the left-hand side of (2). For this argument, antecedent (1) has not been used, but we need it for proving the implication in the other direction.

wp(IF, (E r: r ≥ 0: Cr)) =

(by definition of the semantics of the alternative construct)

BB and (A j: 1 ≤ j ≤ n: Bj ⇒ wp(SLj, (E r: r ≥ 0: Cr))) =

(because the individual SLj are assumed to enjoy Property 5)

BB and (A j: 1 ≤ j ≤ n: Bj ⇒ (E s: s ≥ 0: wp(SLj, Cs)))   . | (3)

Consider an arbitrary state X for which (3) is true, and let j' be a value for j such that Bj'(X) = true ; then we have in point X

(E s: s ≥ 0: wp(SLj', Cs)) | (4)

Because of (1) and the fact that SLj' enjoys Property 2, we conclude that

wp(SLj', Cs) ⇒ wp(SLj', Cs+1) |

and thus we conclude from (4) that in point X we also have

(E s': s' ≥ 0: (A s: s ≥ s': wp(SLj', Cs))   . | (5)

Let s'= s'(j') be the minimum value satisfying (5) . We now define smax as the maximum value of s'(j') taken over the (at most n , and therefore the maximum exists!) values j' for which Bj'(X) = true. In point X then holds on account of (3) and (5)

BB and (A j: 1 ≤ j ≤ n: Bj ⇒ wp(SLj, Csmax)) =

(by definition of the semantics of the alternative construct)

wp(IF, Csmax)     .

But the truth of the latter relation in state X implies there also

(E s: s ≥ 0: wp(IF, Cs))   ;

but as X was an arbitrary state satisfying (3) , for S = IF the fact that the left-hand side of (2) implies its right-hand side as well, has been proved, and thus the alternative construct enjoys Property 5 as well. Note the essential role played by the antecadent (1) and the fact that a guarded command set is a finite set of guarded commands.

Property 5 is proved for the repetitive construct by mathematical induction.

Base:       Property 5 holds for H₀.

H₀(E r: r ≥ 0: Cr) =
(E r: r ≥ 0: Cr) and non BB =
(E s: s ≥ 0: Cs and non BB) =
(E s: s ≥ 0: H₀(Cs))

QED.

Induction step:   From the assumption that Property 5 holds for Hk and H₀ follows that it holds for Hk+1 .

Hk+1(E r: r ≥ 0: Cr) =

(by virtue of the definition of Hk+1)

wp(IF, Hk(E r: r ≥ 0: Cr)) or H₀(E r: r ≥ 0: Cr) =

(because Property 5 is assumed to hold for Hk and for H₀)

wp(IF, (E r': r' ≥ 0: Hk(Cr'))) or (E s: s ≥ 0: H₀(Cs)) =

(because Property 5 holds for the alternative construct and Property 2 is enjoyed by Hk)

(E s: s ≥ 0: wp(IF, Hk(Cs))) or (E s: s ≥ 0: H₀(Cs)) =
(E s: s ≥ 0: wp(IF, Hk(Cs)) or H₀(Cs)) =

(by virtue of the definition of Hk+1)

(E s: s ≥ 0: Hk+1(Cs))   . | QED.

From base and induction step we conclude that Property 5 holds for all Hk , and hence

wp(DO, (E r: r ≥ 0: Cr)) =

(by definition of the semantics of the repetitive construct)

(E k: k ≥ 0: Hk(E r: r ≥ 0: Cr)) =

(because Property 5 holds for all Hk )

(E k: k ≥ 0: (E s: s ≥ 0: Hk(Cs))) =

(because this expresses the existence of a (k, s)-pair)

(E s: s ≥ 0: (E k: k ≥ 0: Hk(Cs))) =

(by definition of the semantics of the repetitive construct)

(E s: s ≥ 0: wp(DO, Cs))   . | QED.

*                *
*

Property 5 is of importance on account of the semantics of the repetitive construct

wp(DO, R) = (E k: k ≥ 0: Hk(R)))   ;

such a pre-condition could be the post-condition for another statement. Because

for k ≥ 0: | Hk(R) ⇒ Hk+1(R) | for all states   ,

—this is easily proved by mathematical induction— the conditions under which Property 5 is relevant, are satisfied. We can, for instance, prove that in all initial states in which BB holds

do B₁ → SL₁ ⌷ B₂ → SL₂ ⌷ ... ⌷ Bn → SLn od

is equivalent to

if B₁ → SL₁ ⌷ B₂ → SL₂ ⌷ ... ⌷ Bn → SLn fi;
do B₁ → SL₁ ⌷ B₂ → SL₂ ⌷ ... ⌷ Bn → SLn od    .

(In initial states in which BB, does not hold, the first program would have acted as "skip", the secend one as "abort".) That is, we have to prove that

(BB and wp(DO, R)) = (BB and wp(IF, wp(DO, R)))    .

BB and wp(IF, wp(DO, R)) =

(on account of the semantics of the repetitive construct)

BB and wp(IF, (E k: k ≥ 0: Hk(R))) =

(because Property 5 holds for IF)

BB and (E s: s ≥ 0: wp(IF, Hs(R))) =

(because (BB and H₀(R)) = F )

BB and (E s: s ≥ 0: wp(IF, Hs(R)) or H₀(R)) =

(on account of the recurrence relation for the Hk(R) )

BB and (E s: s ≥ 0: Hs+1(R)) =

(because (BB and H₀(R)) = F )

BB and (E k: k ≥ 0: Hk(R)) =

(on account of the semantics of the repetitive construct)

BB and wp(DO, R)  .    QED.

*                *
*

Finally, we would like to draw attention to a very different consequence of the fact that all our mechanisms enjoy Property 5 . We could try to make the program S: "set x to any positive integer" with the properties:

a) | wp(S, X > 0) = T
b) | (A s: s ≥ 0: wp(S, 0 ≤ x < s) = F)    .

Here property a) expresses the requirement that activation of S is guaranteed to terminate with x equal to some positive value, property b) expresses that S is a mechanism of unbounded non-determinacy, i.e. that no a priori upper bound for the final value of x can be given. For such a program S , we could, however, derive now:

T = wp(S, X > 0)
  = wp(S, (E r: r ≥ 0: 0 ≤ x < r))
  = (E s: s ≥ 0: wp(S, 0 ≤ x < s))
  = (E s: s ≥ 0: F)
  = F   .

This, however, is a contradiction: for the mechanism S: "set x to any positive integer" no program exists!

As a result, any effort to write a program for "set x to any positive integer" must fail. For insiance, we could consider:

go on:= true; x:= 1;
do go on → x:= x + 1
 ▯ go on → go on:= false
od    .

This construct will continue to increase x as long as the first alternative is chosen; as soon as the second alternative has been chosen once, it terminates immediately. Upon termination x may indeed be "any positive integer" in the sense that we cannot think of a positive value X such that termination with x = X is impossible. But termination is not guaranteed either! We can enforce termination: with N some large, positive constant we can write

go on:= true; x:= 1;
do go on and x < N → x:= x + 1
 ▯ go on → go on:= false
od   

but then property b) is no longer satisfied.

The non-existence of a program for "set x to any positive integer" is reassuring in more than one sense. For, if such a program could exist, our definition of the semantics of the repetitive construct would have been subject to doubt, to say the least. With

S: do x > 0 → x:= x − 1
    ▯ x < 0 → "set x to any positive integer"
   od

our formalism for the repetitive construct gives wp(S, T) = (x ≥ 0) , while I expect most of my readers to conclude that under the assumption of the existsnce of "set x to any positive integer" for x < 0 termination would be guaranteed as well. But then the interpretation of wp(S, T) as the weakest pre-condition guaranteeing termination would no longer be justified. But when we substitute our first would-be implementation:

S: do x > 0 → x:= x − 1
    ▯ x < 0 → go on:= true; x:= 1;
               do go on → x:= x + 1
                ▯ go on → go on:= false
               od
  od

wp(S, T)= (x ≥ 0) is fully correct, both intuitively and formally.

The second reason for reassurance is of a rather different nature: a mechanism of unbounded non-determinacy but yet guaranteed to terminate would be able to make within a finite time a choice out of infinitely many possibilities: if such a mechanism could be formulated in our programming language, that very fact would present an unsurmountable barrier to the possibility of the implementatlon of that programming language.

Acknowledgement. I would like to express my great indebtness to John C.Reynolds for drawing my attention to the central role of Property 5 and to the fact that the non-existence of a mechanism "set x to any positive integer" is essential for the intuitive justification of the semantics of the repetitive construct. He is, of course, in no way to be held responsible for any of the above. (End of acknowledgement.)

Transcription by Moti Ben-Ari.
Revised Sat, 9 Dec 2006.

EWD459

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

(To be inserted after EWD437).

The pattern matching problem.

The problem that is solved in this chapter is a very famous one, that has been tackled independently by many programmers. Yet we hope that our treatment gives some pleasure to even those of my readers who considered themselves thoroughly familiar with the problem and its various solutions.

We consider as given two sequences of values

| p(0), p(1), , p(N -1)      with N ≥ 1      and
| x(0), x(1), , x(M -1)      with M ≥ 0

(usually M is regarded as being many times larger than N). The question to be answered is: how many times occurs the “pattern”, as given by the first sequence, in the second sequence?

Using | (N i: 0 ≤ i < m: B(i))

to denote “the number of different values of i in the range 0 ≤ i < m , for which B(i) holds”, a more-precise description of the final relation R that is to be established is

R: | count = (N i: 0 ≤ i ≤ M - N: match(i))

where the function match(i) is given by

for 0 ≤ i ≤ M - N: | match(i) = (A j: 0 ≤ j <N: p(j) = x(i + j))
for i < 0 or i > M - N: | match(i) = false .

(To define match(i) = false for those further values of i , thus making it a total function, is a matter of convenience.)

If we take as invariant relation

P1: | count = (N i: 0 ≤ i < r: match(i)) and r ≥ 0

we have one which is trivially established by “count, r:= 0, 0” and, furthermore, is such that

| (P1 and r > M - N) ⇒ R .

(The “matter of convenience” referred to above is that now the above inequality will do the job.) This gives a sketch for the program:

| count, r:= 0, 0;
| do r ≤ M - N → “increase r under invariance of P1 ” od

and the reader is invited to work out for himself the refinement in which r is always increased by 1; worst case the time taken by the execution of that program will be proportional to M * N .

Depending on the pattern,however, much larger increases of r seem sometimes possible: if, for instance, the pattern is (1, 2, 3, 4, 5) and match(r) has been found to hold, “count, r:= count + 1, r + 5” would leave P1 invariant! Considering the invariant relation

P2: | (A ≤ j < k: p(j) = x(r + j)) and 0 ≤ k ≤ N

(which can be expected to play a role in the repetitive construct computing match(r)), we can investigate, what we can gain by taking that relation outside the repetitive construct, i.e, we consider:

| count, r, k:= 0, 0, 0;
| do r ≤ M - N → “increase r under invariance of P1 and P2 ” od

(relation P2 being vacuously satisfied by k = 0 ).

In view of the validity of relation P2 and the formula for match(r), the most natural thing to start the repeatable statement with is to try to determine match(r) : as the truth of match(r) can be concluded from P2 and k = N we prescribe that k be increased as long as is necessary and possible:

| do k = N cand p(k) = x(r+k) → k:= k + 1 od | (1)

upon termination of which —and termination is guaranteed— we have

| P2 and (k = N cor p(k) ≠ x(r + k))

from which we can conclude that match(r) = (k = N) . Thus it is known, whether increasing r by 1 should be accompanied by “count:= count + 1” or not. We would like to know, by how much r can be increased without further increase of count and without taking any further x-values into account. (The taking into account of x-values is done in statement (1): to do so is its specific purpose! Here we are willing to exploit only properties of the —constant— pattern;)

If k = 0, we conclude (because N > 0 ) that match(r) = false : the relation Pl then justifies an increase of r by 1 —leaving P1 invariant by leaving count unchanged— but P2 does not justify any higher increase of r ; and k = 0 —making P2 vacuously true— is maintained.

For general k , however, there is the following argument. Define for 0 < i ≤ k ≤ N the boolean function

| dif(i, k) = (E j: 0 ≤ j < k - i; p(j) ≠ p(i + j)) .

From this it follows that dif(k, k) = false . If, however, dif(i, k) = true, (we conclude —because 0 ≤ i + j < k— on account of the truth of P2

| (E j: 0 ≤ j < k - i: p(j) ≠ x(r + i + j)) .

that is: dif(i, k) ⇒ non match(r + i) . Therefore, the variable “count” needs no further adjustments —besides the one on account of the value of match(r)— when r is increased by d(k), where d(k) is the minimum solution for i with 0 < i ≤ k of the equation dif(i, k) = false , or:

| (A j:0 ≤ j < k - i: p(j) = p(i + j)) . | (2)

The fact that d(k) is a solution of (2) implies

| (A j:0 ≤ j < k - d(k): p(j) = p(d(k) + j)) .

which, with P2 amounts to

| (A j:0 ≤ j < k - d(k): p(j) = x(r + d(k) + j)) .

and as a result —besides the adjustment of “count” as implied by the value of match(r) —both P1 and P2 are kept invariant by “r, kt: r + d(k), k - d(k)”.

Because the minimum solution of (2) depends on k and p only, we find:

| begin glocon p, N, x, M; virvar count; privar r, k; pricon d; . “initialize d”;
|  | count, r, k := 0, 0, 0; 3 * vir int
|  | do r ≤ M - N →
|  |  | do k ≠ N cand p(k) = x(r + k) → k:= k + l od;
|  |  | if k = N → count:= count + l; r, k := r + d(k), k - d(k)
|  |  |  | ▯ 0 < k < N → r, k := r + d(k) , k - d(k)
|  |  |  | ▯ k = 0 → r:= r + 1
|  |  | fi
|  | od
| end

The only job left is the initialization of the array variable d , i.e. to establish for each k satisfying 1≤ k ≤ N the minimum solution for i of (2) . The Linear Search Theorem tells us that we should try i-values in increasing order. It pays, however, to realize that this minimum value for i has to be determined for a whole sequence of k-values. Let k1 > k2 and let d(k1) be the minimum solution for i of (2) with k = k1 . From

| (A j:0 ≤ j < k1 - d(k1): p(j) = p(d(k1) + j)) and k1 > k2

follows:

| (A j:0 ≤ j < k2 - d(k1): p(j) = p(d(k1) + j))

i.e. for k = k2 , d(k1) is also a solution for i of (2) , but not necessarily the smallest! From that we conclude that d(k) is a monotonically non-decreasing function of k. And the algorithm therefore investigates increasing values of i , each time deciding whether for one or more k-values i = d(k) can be concluded (should be established). More precisely: let j(i) (for given value of i be the maximum value ≤ N - i , such that

| (A j: 0 ≤ j <j(i): p(j) = p(i + j)) ;

then d(k) = i for all k such that k - i ≤ j(i) (or: k ≤ j(i)+ i), for which no solution d(k) < i exists. As the values of i will be tried in increasing order and, as soon as existing as minimal solution, will be recorded in the monotonically non-decreasing function d , the condition is

| d.hib < k ≤ j(i)+ i

and we get the following program:

| “initialize d”:
| begin glocon p, N; virvar d; privar i;
|  | d vir int array, i vir int := (1), 0;
|  | do d.hib ≠ N →
|  |  | begin glocon p, N; glovar d, i; privar j;
|  |  |  | j vir int := 0; i:= i + 1;
|  |  |  | do j < N - i cand p(j) = p(i + j) → j:= j + l od;
|  |  |  | do d.hib < j + i - d:hiext(i) od
|  |  | end
|  | od
| end

Exercise 1. Give a formal correctness proof for the above initialization. (End of exercise 1.)

Exercise 2. With “r, k := r + d(k), r - d(k)” For 0 < k , our algorithm adjusts r and k without changing r + k . Investigate the slight gain that is possible for 0 < k < N if it is known that the x-values are two-valued. (End of exercise 2.)

Remark. Our final algorithm is one, the execution time of which I regard as to grow proportional to, M + N . Once one has set oneself the goal to find —if possible— an algorithm with such a performance, its actual development. does not seem to require much more than the usual care; the crucial point seems the refusal to be satisfied (without further investigation) with the obvious M * N -algorithm, the development of which I have left as an exercise to the reader. A slight reformulation of the problem, however, enables us to recognize also here a general design principle, which might be called “The Search for the Small Superset.” Suppose that we had not been asked to count the number of matches, but to generate the sequence of r-values, for which match(r) holds.

When a program has to generate the members of a set A , there are (roughly) only two situations. Either we have simple, straightforward “successor function” by means of which a next member of A can be generated —and then the whole set can be trivially generated by means of repeated application of that successor function— or we do not have a function like that. In the latter case, the usual technique is to generate the members of a set B instead, where
a)     each member of A is a member of B as well
b)     there exists a generator for successive members of B
c)     there exists a test whether a member of B belongs to A as well. The algorithm then generates and inspects all members of B in turn.

If this technique is to lead to a satisfactory performance, three conditions should be satisfied:
1)     the members of set B should be reasonably efficient to generate
2)     the test whether an element of B belongs to A as well —particularly in the case that it does not, for, usually, B is an order of magnitude larger than A — should be reasonably efficient
3)     set B should not be unnecessarily large.

The trained problem solver, aware of the above, will consciously look for a smaller set B than the obvious one. In this example, the set of all r-values satisfying 0 ≤ r ≤ M - N is the obvious one. Note, that in the previous chapter “An exercise attributed to R.W.Hamming” the replacement of the set “qq” by the much smaller set “qqq” was another application of the principle of The Search for the Small Superset. And besides “taking a relation outside the repetitive construct” this illustrates the second strategical similarity between the solutions presented in the current and in the previous chapter. (End of remark.)

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

EWD462

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 462: A time-wise hierarchy imposed upon the use of a two-level store.

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 67–78 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,

Springer-Verlag, 1982. ISBN O–387–90652–5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited. .

A time-wise hierarchy imposed upon the use of a two-level store.

| by Edsger W.Dijkstra.

Authors address:

BURROUGHS

Plataanstraat 5

NUENEN - 4565

The Netherlands

Abstract: Following general design principles a paging system has been developed in which has been aimed at high efficiency and a strong separation between store management and processor scheduling and a minimal influence of the program mix upon the system's performance. It is, furthermore, described how some dedicated hardware can be expected to contribute effectively to memory management and the prevention of thrashing. Finally, the properties of the system should be such that a mismatch between configuration and workload gives a clear indication as to what reconfigurations seem indicated.
Key Words and Phrases: demand paging, window size, thrashing control, smoothness virtual store, two-level store, operating systems, design, reconfiguration, separation of concerns.
E.R.Categories: 4.32, 4.34. 6.21, 6.34, 6.39.

NUENEN, 6th December 1974 | prof.dr.Edsger W.Dijkstra
| Burroughs Research Fellow

A time-wise hierarchy imposed upon the use of a two-leve1 store.

This paper is really two articles, merged into one. On the one hand it deals with a general design principle, on the other hand it deals with the design of a virtual storage system, a design to which that principle has been applied. Although the first aspect is the more general one, the title refers only to the second aspect, firstly because its elaboration occupies most of the space, and, secondly, because the virtual storage system to be developed below seems to be new and not without attractive properties.

The design principle in its most general form is that, whenever we have to design a mechanism meeting certain requirements, it does not suffice to design something of which we hope that it meets the requirements, on the contrary: we must design it in such a way that we can establish that it meets the requirements. As far as program correctness is concerned, this design principle has led to a programming methodology that is becoming more and more widely accepted: instead of making the program first and trying to establish its correctness afterwards —which may be near to impossible— correctness proof and program are now developed hand in hand. (As a matter of fact, the development of the correctness proof is often slightly leading: as soon as the next argument in the proof has been chosen, a program part is designed so as to meet the proof's requirements.) Besides the mathematical requirement of correctness, we have the engineering requirement of “reasonable preformance” as well: this time the principle tells us, that it does not suffice to design a mechanism of which we hope that it will perform “reasonably well”, but that we should (at least try to) design it in such a way that we can predict a priori how well it will perform. If we ask very precise questions about the performance, these questions may become very hard to answer: to predict that the computation time for the Horner scheme grows linearly with the degree of the polynomials is not hard; the estimation of the computation time needed for iterative computation of eigenvalues and eigenvectors of a symmetric matrix, however, is harder and probably most easily expressed in terms of the separation of the eigenvalues, i.e. in terms of part of the answer; then this dependence is something that we should try to derive and prove! Often we have to be content with “worst case” bounds (which in contrast to averages have at least the advantage of not depending on the usually unknown input popu1ation).Sometimes we have even to be content with still vaguer definitions of what “reasonable performance” means: yet this is no licence to design, for instance, a mechanism whose performance is occasionally surprisingly bad.

The actual performance of a machine with a virtual storage system is dependent of what is usually denoted as “the workload characteristics”. In the name of the predictability of that performance we shall try to design the system such as to make that dependence as simple as possible: in particular we require that a mismatch between configuration and workload does not only make itself manifest in the form of poor performance, but will in addition give a clear indication what type of change —if any— of the configuration would improve the performance.

In order not to complicate the discussion unduly at the start, we shall make a few simplifying assumptions about the hardware. At the end we can reconsider these assumptions; some may be weakened easily, of others, however, we may come to the conclusion that if our hardware does not allow such idealizations, the scheduling problem will be “complified” seriously, perhaps even beyond our comprehension and control. In the latter case we don't need to feel having failed “to cope with the problem”; on the contrary: the identification of seriously “complifying” hardware characteristics seems in the light of the present state of the art a valuable discovery.

As primary store we assume a random access store as randomly accessible as, say, a core store. As secondary store we assume a device with the characteristics of, say, a drum or a head-per-track disc, such that
1)     place of information in secondary store need not influence decisions to change the contents of primary store, i.e. that page-wise it can be regarded as a random access store;
2)      the processor speed is sufficiently slow and/or the cycle time of the primary store is sufficiently small and/or the transfer rate between primary and secondary store is sufficiently low that any slowing down of the processor as a result of cycle stealing by the channel (to all intents and purposes) can be ignored;
3)      transport between the two storage levels is taken care of by a single. dedicated channel.

Furthermore I assume
4)      a single processor
5)      demand paging with fixed-size pages
6)      such a modest amount of processor-status information (registers included!: that the time needed to switch the processor from one process to another can (to all intents and purposes) be ignored in view of an upper bound on the frequency with which these switchings may have to take place
7)      no page-sharing between user programs (for instance possible on account of a common procedure library).

Remark 1. The above asumptions are —or at least: were— not unrealistic. We shall later discuss some of the temptations that should be resisted when they are only partly fulfilled. (End of remark 1.)

Remark 2. Assumption 6 means that as far as scheduling processor time is concerned, we can regard the total processor time as the sum of the periods of time devoted to actual program process, and are at any time free to grant the processor to what is concerned as the most urgent task. If the price of switching the processor from one task to another has to be regarded as high, one is faced with the often conflicting aim to grant the processor to the task with the maximum expectation value for the period of time for which full-speed progress is possible. (End of remark 2.)

The role of the replacement algorithm in a multiprogramming environment.

The idea of demand paging is that processing proceeds at full speed as long as the information is present in primary store. Upon a so-called “page fault” —i.e. the detected desire to access a page that is currently not in main store— the missing page must be brought in from secondary store. (The program causing the page fault has to wait until the channel has completed that transport; in a multiprogramming environment the processor is in the mean time available for other programs.) Besides bringing in the missing page, another page has to be dumped. It is the task of the so-called “replacement algorithm” to choose that victim; its goal is to keep the interesting pages in primary store. Obviously, with each reasonable replacement algorithm, permanently unreferenced pages have a tendency to disappear sooner or later from primary store.

The ideal replacement algorithm embodies clairvoyance: it kicks out the page that in view of future needs can be missed best. Clairvoyance, however, is hard to implement, and actual replacement algorithms are based upon, essentially, three different ideas. (We shall later see that for our purposes the first two have to be rejected.)

1)      With a (quasi-)random number generator an “arbitrary” page residing in primary memory is chosen as the victim. It is reasonable in the sense that permanently unreferenced pages have indeed a tendency to disappear from primary store, it is simple and its performance is not half as bad as might be expected.

2)      In an effort to speed up the disappearance of permanently unreferenced pages the machine keepts track of the order in which the pages currently residing in primary store came in, and the older ones are given a greater probability of being chosen as the victim. In the extreme case, always the oldest is chosen and the algorithm becomes a FIFO (“First-In-First-Out”) rule.

3)      Predicting tomorrow's weather according to the principle “the same as today”, the machine keeps to a certain extent track of the order in which pages currently in primary store have been accessed, and pages which for a relatively long time have not been accessed are given a greater probability of being chosen as the victim. In the extreme case we get the so-called LRU algorithm (“Least Recently Used”).

Note 1. In the case of cyclic access to n+1 pages with room for only n , both FIFO and LRU give the worst possible choice. As purely periodic access patterns are not unrealistic, it has been suggested to incorprate always a randomizing element in the page replacement algorithm, so as to reduce the probability of such a “disastrous resonance” to nearly nil. (End of note 1.)

We shall resume the discussion of the replacement algorithm later, because in a multiprogramming environment a more crucial decision has to be taken first. When a new victim has to be chosen, there are two alternatives::

1)      either we regard primary store as a homogeneous pool of page frames and the victim is chosen on account of the total history in core, independent of the identity of the program that caused the page fault;

2)      or we regard the page fault as a private occurrence of the program in which it happened, only the history of the pages of this program is taken into account and one of its own pages will be selected as the victim.

In the design of the THE-multiprogramming system in the early sixties I have chosen the first alternative and I remember the (opportunistic) arguments in favour of that decision: firstly it removed the obligation to keep track of which page frames were occupied by which programs —an administration that would have been complicated by the presence of shared library pages—, secondly it would automatically see to it that a program idling for other reasons would not continue to occupy page frames, as its then permanently non-accessed pages would disappear via the normal mechanism (which was LRU, related to the total history). This paper is a peccavi in the sense that —as I hope to demonstrate convincingly in the sequel— this decision has been more than a mistake: it was a sin against proper design. (One of its unattractive features was that a large high-vagrancy program always lost its pages, and, as a result, suffered from very slow progress.) In the mean time we know that “separation of concerns” should be one of our dearest goals, and in the case of choice 1 the page faults caused by a single program are dependent both on its fellow-programs and on the relative speeds with which they are allowed to proceed. In the case of choice 2, however, were each program has its own, fixed number of page frames at its disposal, the generation of page faults is each program's private business, only dependent on that number of page frames, its access pattern and its(!) replacement algorithm. The mistake we made ten years ago was to allow a hardly controllable finegrained interference between fellow programs that had been independently conceived but found themselves by accident mixed, instead of maintaining for these mutually independent programs to a much courser grain of time the mutual independency between their computational histories.

In the following we make the weak assumption about the replacement algorithm(s) used, that the average frequency of a program's page fault generation is a non-increasing (and usually even: a decreasing) function of its so-called “window size”, i.e. the number of page frames allocated to it.

About the ideal window size.

In this section we shall describe how we propose to exploit our first three assumptions. After having observed that it is the function of the replacement algorithm to try to reduce —with a given window size— the number of page faults caused by that program and, therefore, the total amount of time the channel is busy for the benefit of that program, our next purpose is to keep the channel nicely busy.

For each program we can introduce the total time C the processor has performed “computation” for that program, and also the total time T the channel has been occupied with “transports” between storage levels as a result of page faults caused by that program, both times C and T being recorded for that program since the same moment. When deciding how to allocate page frames to programs, i.e. when deciding the window size for each program, we seem to be managing three resources, viz. processor, channel and primary store. In this management problem, general dimension considerations tell us that the dimensionless quantity C/T must be significant. The point is, that processor and channel are resources doing something at a certain speed, but we cannot change the “speed” with which something is kept in store (no more than we are able to wait twice as fast for something).

Under the (temporary) assumption that for each program such a window size exists, we define for each program the “ideal” window size as the one that would give rise to a ratio C/T = 1 , i.e. the window size that would cause on the average equal demands on processor time and channel time, the reason being that then processor and channel can be scheduled as a single resource. The result of demand paging is that a program has no use for the processor during the period of time that the channel is busy for it; as a result no program can occupy more than 50 percent of this combined resource, and if we want to keep the latter busy, we conclude that our degree of multiprogramming should at least be equal to two. This degree will usually not suffice (see below).

About the degree of multiprogramming.

In this section we assume that for each program the vagrancy characterist are such that for each program a constant —and known— window size can be considered as ideal.

In order to keep the combined resource constantly busy, individual C/T ratios close to 1 is in general not enough. Suppose that the one program generates its page faults —when executed all by itself— quite regularly, one at a time, while the other program would generate under the same circumstances with half the frequency bursts of two page faults at a time: the combination would not fit and both processor and channel could be busy for at most 80 percent of the time. with a third program (of either type) full occupation is possible and an arbitrary program can use the maximum 50 percent. The typical purpose of multiprogramming is clear as far as utilization of the active resources is concerned: to absorb the bursts in which programs may generate page faults. After some consideration —and in analogy to other statistical phenomena— it becomes hard to believe that the desire to absorb the bursts would ever give rise to a degree of multiprogramming exceeding 4 or 5 .

About the adjustment of window sizes.

We have introduced the notion of the “ideal” window size as the one by which program progress implies on the average equal loads C and T for processor and channel respectively. As a result the question whether for a given program the actual window has the ideal size or not, is meaningless unless it is related to a sufficiently large section of computation history, in which the increase of C + T is an order of magnitude larger than the T-increase caused by a single page fault (say: 20 times). Up till now, we have done as if during each computation the access pattern was sufficiently constant so that from beginning to end a single window size could be regarded as “ideal” for it, and also that for each program this size was known. In usual practice neither of these two conditions is fulfilled and, therefore, the system is required to discover for each computation what the ideal window size is, and to adjust for each program the window size when needed. For each program reconsideration (and possibly adjustment) of the window size should only take place with a frequency which is an order of magnitude smaller than that of the target frequency of page fault generation: it is pointless to be willing to vary a program's window size so rapidly that the periods during which it is by definition constant are so short that the question as to-whether it was “ideal” becomes meaningless!

Let us assume therefore that for each program the system reconsiders its window size each time when that program has increased its C + T by a certain amount (equal to, say, 20 times the T-increase corresponding to a single page fault.) When since the previous reconsideration of the window size C has increased much more than T , a smaller window might be more adequate, when T has increased much more than C , a larger window might be more adequate. We could think of a simple negative feedback, based upon the quotient of the observed increases of C and T , say decreasing the window size by one page frame when that quotient exceeds 1.1 and increasing the window size by one page frame when that quotient is less than 0.9 . Such a simple negative feedback, however, will not do the job, because even if our replacement algorithm is such that we can prove that a larger window would never lead to more page faults, the program might be such that a larger window would not lead to fewer page faults either!

A computation with high-frequency access to two fixed (program) pages and random access to 10,000 other (data) pages will not perform any better with a window of 100 frames (our maximum say) than with a window of 3 . If it has a window of 3 and its C/T ratio is too small, there is no point in increasing the window size. The simple negative feedback would continue to increase it and (like a young cuckoo) this program would eventually push the other programs out of primary store. This cuckoo effect cannot be remedied without penalty by suppressing growth of the window —although desirable on account of C/T— as soon as no improvement is observed, and the reason is the following. A program with high-frequency access between 12 pages may perform equally poor with windows up to 11 frames and beautifully with a window of 12 frames, and this is something we would like to be discovered when its current window happens to be 4 . In other words: it is not enough to know the C/T- ratio caused by the current window size, we should also know it for other ones!

Monotonic replacement algorithms.

There is an important class of replacement algorithms —LRU is one of them, RANDOM and FIFO are not— which we might call “monotonic”, and are characterized by the following property. Considering two synchronized executions of the same program but with different window sizes, we call the replacement algorithm “monotonic” if at all times all pages contained in the smaller window will be contained in the larger window as well, provided that this was true at the beginning. As a result,in the computation with the larger window no page fault occurs that does not occur in the other computation as well.

Therefore, if a program is executed with a monotonic replacement algorithm and an actual window size w , it cannot cost much to record how many page faults would have occurred if the window size had been w + 1 , w + 2 .... up to the maximum: it would only be a minor overhead on the actual page faults and would, therefore, be negligible. This information can be used to prevent the growth of a cuckoo, it does not cater for the detection of an existing cuckoo, i.e. a program whose window size can be decreased without any ill effects.

To record the page faults that would have occurred with window sizes smaller than the actual ones, additional hardware seems indicated. The knowledge of the number of page faults that would have occurred with smaller sized windows (particularly for the size w - 1 ) is so attractive to have, that the additional hardware seems justified. (In the latter case it can probably also take care of the recording of the number of page faults corresponding to window sizes larger than w .) Plotting page-fault frequency against window size it is not uncommon that this curve has a very sharp band: we may expect programs that for a given window size w will give a ratio C/T > 1 , while with a size w - 1 the ratio C/T would drop down unacceptably close to zero. With the simple feedback mechanism the effort at window size adjustment would lead to thrashing half the time —a nasty property of that feedback mechanisms that has been used as an argument against virtual storage systems as such— . If additional hardware counts the virtual page faults that would have occurred with window sizes smaller than the actual one, the thrashing half the time is easily avoided.

In view of the above it is doubtful whether the introduction of a randomizing element in the page replacement algorithm in order to avoid “disastrous resonance” —see Note 1— is still desirable: most desastrous resonances occur when the window size is a few frames too small. But now we can detect this and know how to remedy it, it seems better not to obscure the detection by the noise of a randomizer.

The time-wise hierarchy.

At our lowest level we have the individual access: the recording of its having taken place (for the sake of the replacement algorithm) and the test whether it causes a (virtual or actual) page fault are obvious candidates for dedicated hardware.

At the next level we have the actual page faults, which occur several orders of magnitude less frequently. Taken in isolation they only influence the program in which they occur.

At the next level, but again an order of magnitude less frequent, the window size is reconsidered. In the decision to increase or decrease the window size a threshold should be introduced so as to increase the probability that the result of reconsidering the window size will be the decision to leave it as it stands. Furthermore, if available information suggests a drastic change in window size, follow this suggestion only partly —halfway, say— : either the suggestion is “serious” and the total change will be effectuated within two or three adjustments anyhow, or the suggestion is not “serious”, because the access pattern is so wild, that the notion of an “ideal” window size is (temporarily or permanently) not applicable to that program. In the latter case it is better to allow this program to contribute unequal loads to the processor and the channel —if it only occupies one tenth of that combined resource, it can only bring the two total loads mildly out of balance— .

At the last level, but again at a lower frequency, change of window sizes may have to influence the degree of multiprogramming: growing window sizes may force load shedding, shrinking window sizes can allow an increase of the degree of multiprogramming.

As a result of past experience, the fact that these different levels (each with their own appropriate “grain of time”) can be meaningfully distinguished in the above design, gives me a considerable confidence in its smoothness, in its relative unsensibility to workload characteristics.

Efficiency and flexibility.

The purpose of aiming at C/T-ratios close to 1 was to achieve for the active resource (i.e. processor and channel combined) a duty cycle close to a 100 percent, to a large extent independent of the program mix. This freedom can still be exploited in various ways. A program needing a large window on account of its vagrancy can be given the maximum 50 percent of the active resource in order to reduce the time integral of its primary storage occupation. Alternatively we can grant different percentages of the active resource in view of (relatively long range) real time obligations: to allocate a certain percentage of the active resource to a program means to guarantee a certain average progress speed. (This seems to me more meaningful than “priorities” which, besides being a relative concept, can only be understood in terms of a specific queueing discipline that users should not need to be aware of at all!)

Remark 3. when a producer and a consumer are coupled by a bounded buffer, operating system designers prefer to have the buffer half-filled: in that state they have maximized the freedom to let one partner idle before it affects the other, thus contributing to the system's smoothness. Granting no program more than 50 percent of the active resource is another instance of consicously avoiding extreme of “skew” system states! (End of remark 3.)

Temptations to be resisted.

If we enjoy the luxury of a full duplex channel, the page being dumped and the page being brought in can be transported simultaneously (possibly at the price of one spare page frame). Usually, however, such a page swap between the two storage levels takes twice as much time as only bringing in a page. If the channel capacity is relatively low, it is therefore not unusual to keep track of the fact whether a page has been (or: could have been) written into since it was lastly brought in: if not, the identical information still resides in secondary store and the dumping transport can be omitted. This gain should be regarded as “statistical luck” which no strategy should try to increase and which should never be allowed to influence one's choice of the victim (quite apart from the fact that it is hard to reconcile with the monotinicity of the replacement algorithm, as the monotonic replacement algorithm is defined for all window sizes simultaneously, independent of the size of the actual window).

We have also assumed the absence of page sharing. But this was not essential: if program A wants to access a page from the common library which at that moment happens to reside in program B's window, a transport can be suppressed by allowing the windows to overlap on that page frame. Both programs keep, independently of eachother, track of their own usage of that page for the sake of their own replacement algorithm and the page only disappears from main store when it is no longer in any window at all. Again, this gain should be regarded as “statistical luck” which should never be allowed to influence our strategies. Such pressure should be resisted, yielding to it would be terrible!

Analyzing the mismatch between configuration and workload.

If the channel achieves a duty cycle close to 100 percent , but the processor does not, a faster channel (or more channels) or a slower processor may be considered. If the processor achieves a duty cycle close to 100 percent , but the channel does not, a faster processor (or more processors) or a slower channel may be considered. (With two processors and one channel each program has the target C/T-ratio = 2 .)

Note 2. A change in the quotient of processing capacity and transport capacity will give rise to other window sizes. With the built-in detection of virtual page faults as well, a user can determine himself what effect on the window sizes the change in that capacity ratio would have for his workload, without changing the actual window sizes. He should do so before deciding to change the configuration. (End of note 2.)

If neither processor, nor channel achieves an acceptable duty cycle, we either have not enough work, or are unable to buffer the bursts. If we have enough independent programs, a larger primary store could be considered so as to increase the degree of multiprogramming. Otherwise we should consider the attraction of more work, or reprogramming —so as to change vagrancy characteristics—, or a completely different installation (e.g. with very different secondary store characteristics). Or we may decide to do nothing about it at all and live with it.

Acknowledgements. Collective acknowledgements are due to the members of the IFIP Working Group W.E.2.3 on “Programming Methodology” and to those of the Syracuse Chapter of the ACM. Personal acknowledgements are due to the letter's Chairman, Jack E.Cover, to Steve Schmidt from Burroughs Corporation, to John E.Savage from Brown University and Per Brinch Hansen from the California Institute of Technology.

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-13 .

EWD463

Some questions

Some questions are posed, that by the very fact of being put forward, reveal deep insight. Other questions display, by the very same fact of being put forward, only ignorance. In all probability, my questions fall in the latter category.

It begins with Gödel's Theorem, and here I start already with a display of ignorance. Someone --who was it?-- borrowed my copy of Kleene's "Introduction to Metamathematics." and, as a result, I have only my memory to rely upon. That would not be too bad if I had studied the book thoroughly, but I have not. That I did not study it, but only read (parts of) it, was caused by the fact that the reading of it did not give me the feeling that its contents really concerned me. But if I remember correctly it states --pardon my loose terminology!-- that no consistent set of axioms can serve as a basis for the demonstration of its own completeness. The above loose formulation may cause a professional logician to shudder --I am sorry: my memory is not any better-- what I do remember more clearly was that the result did perhaps startle me, but most certainly did not bother me. Is it, because Gödel's Theorem denied the possibility of a form of perfect understanding that had never been my ideal in the first place?

The above is brought up because over the past years I have discovered that many people are very suspicious about either the legitimacy or the adequacy of axiomatic methods. And recently I came to the conclusion that I could not understand why.

In a recent letter Tony Hoare asked me, whether I knew Bertrand Russell's verdict: "The advantages of the method of postulation are great; they are the same as the advantages of theft over honest toil.". (Somehow I knew it; perhaps it was Tony himself who had thrown the quotation to me at an earlier occasion!) An (intellectual?) dishonesty characteristic for the method of postulation is more than mildly suggested. I allow for a difference in criteria for "honesty" between Russell and me --and, with due respect: such a difference would not necessarily bother me!--; yet the verdict intrigues me enough to raise the question "Why?".

Russell's verdict would not interest me, were it not for the fact that I hear it echoed today with respect to proposals for defining the semantics of programming languages. What is known as "the axiomatic method" --would "postulational method" have given rise to fewer misunderstandings?-- defines the semantics of a programming language in close parallelism to its syntax: for each new way of defining the semantics of a composite object in terms of the semantics of its components a new syntactic construction is chosen. I was greatly attracted by that approach: for the type of programs that I would like to be better able to design in a controlled fashion, such postulates seemed to be most readily forged into a tool for practical program composition. I found it, for instance, much more attractive than mechanizing --or at least: developing a calculus for-- the translation of recursive programs into repetitive ones.

The usual defense for that two-step approach was that it was a way of reconciling the potentially greater efficiency of repetitive solutions with the fact that "recursive solutions come most naturally". But do they? Is this a Law of Human Nature? Or are people that feel so, confusing "convenient" with "conventional" and is the feeling no more than the symptom of a mathematical inability to cope with repetition --and "variables" as they occur in programming languages-- in its own right?

I found a confirmation in the temptation --I myself yielded to it once, in a moment of weakness!-- to define the semantics of

"while B do S od"

as that of the call

"while(B, S)"

of the recursive procedure

"proc while(B, S): if B then S; while(B, S) fi corp"

but is not that cracking an egg with a sledgehammer? (I know that for the purpose of an analogy, it may be illuminating to regard all scalar constants as functions, defined on the same one-point domain, whose argument, therefore, can remain anonymous, but must we always regard constants as such functions? That, I am afraid, would be a similar sledgehammer. And, if I may raise the question, is the use of sledgehammers to crack eggs honest, in as far as the need for the sledgehammer is suggested?)

Other proposals for defining programming language semantics have been developed, and superiority over the axiomatic method has been claimed on account of an argument, that I do not understand. The argument is that in such alternatives, the axioms of the axiomatic method need not be "postulated" but can be proved as theorems. Fine and interesting. But what is the gain? Is it unfair to invert that argument, and to point out the superiority of the axiomatic method on account of the fact that there you don't need to prove them as theorems, as just postulating them suffices? If those few axioms in the one scheme and theorems in the other are the only interface through which the theory has its impact upon the programming activity --and let us assume this for the sake of the argument to be the case--, is it then not more efficient just to postulate that interface, ignoring the elaborate fabric that could be woven underneath them? Here we are clearly back at Russell's verdict. Is the method of postulation unfair, or perhaps deadly dangerous?

One possible attack on the method of postulation is "But how do you know that your postulates are true, if you have not proved them?", but that question only makes sense if we regard the postulates as stating properties of something already defined otherwise, and the question of "truth" becomes irrelevant when regard postulates as "interface specifications". A possibly more valid doubt may be raised by the question "How do you know that your axioms are consistent?".

My inclination --but am I perhaps awfully naive?-- is to say "Well, I am pretty sure that they are consistent. And if they are not, well that is my risk! The worst that I could have done is talking about an empty universe, and, although fruitless, that cannot have done much harm either." My impression is that, when logicians talk about "interpreting" or "providing a model" --as soon as they start doing that, I always get confused-- they are trying to demonstrate(?) the consistency of a set of axioms by showing the existence(?) of a universe to which they apply. This they do in terms of another formal system, about the consistency of which they are more confident? Is this a fair description of what logicians are doing? If so, it strikes me as an utterly respectable way of trying to raise a confidence level, the relevance of which, however, seems closely related to our having reasons for being not too confident about the first system, and the effectiveness of which seems closely related to our sympathy with the second system.

If the point of "model making" is to give an "existence proof" I think that I can understand the purpose of the exercise. I hesitate --to put it very mildly-- when the semantics of the first system is identified with --or: defined as-- the properties of the model, because besides --hopefully!-- displaying the intended properties, the model will, in general, have many other properties as well, some of them already known, some of them, perhaps, not discovered yet. And that seems a most unattractive way of defining an interface!

And now we are back at our old dilemma. Either we take by definition all properties of the model as relevant, or we specify in one way or another which of its properties are the relevant ones. In the first case we have failed to introduce in the name of "divide et impera" an interface that would allow us to divide and rule and the study of how we could build upon the (only implicitly defined) interface seems bound to deteriorate into a study of the model itself; in the second case we are again close to the axiomatic method....

In short: I am convinced of "the great advantages" mentioned by Russell, but why the "theft"? Who is being robbed of what? Or is it "dishonest" to create a system in which questions are void that otherwise could be solved by "honest toil"?

Even if I ignore the moral judgement implied by Russell's verdict, I find it difficult to swallow. I judge a theory not only on its intrinsic beauty, but also by which problems it evokes, which efforts it attracts, how much is needed for it, which problems it solves and how efficiently it does so, etc. And as far as I can see, the method of postulation, when applied to programming language semantics, scores rather high in most of these various aspects. Am I blind to some philosophical questions --in very much the same way as some other people are tone-deaf or colour-blind-- or comes Russell's verdict and its echos from an intellectual climate in which pure science was fairly divorced from applied science, let alone from engineering?

Or, to put it in another way: if the traditional automata theory tends to make us insensitive to the role interfaces could and should play in coping with complex designs, should it then (continue to) occupy a central position in computing science curricula?

17th November 1974
Burroughs
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sat, 12 Jun 2004

EWD464

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 464: A new elephant built from mosquitos humming in harmony

is held in copyright by Springer—Verlag New York.

The manuscript was published as pages 79-83 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,

Springer-Verlag, 1982. ISBN O—387—90652—5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited. .

A new elephant built from mosquitos humming in harmony.

In an earlier document —EWD456— I mentioned a problem, suggesting that it boiled down to forming a transitive closure. M.Rem pointed out to me that suggestion was wrong; this report deals with the problem in question.

We consider a non-deterministic finite state automaton with N states, each state being either a terminal or a non-terminal state. We can associate each state with a different node of a directed graph —and vice versa— in which each node has at least one outgoing arc. Terminal nodes —i.e. nodes corresponding to a terminal state— are the nodes whose only outgoing arc leads back into themselves: the only outgoing arc of a terminal node is also one of its incoming arcs. For each node the outgoing arcs point to the set of permissible “successor nodes”, a node with only one outgoing arc is a deterministic node and all directed paths along the graph correspond to a possible computation of the machine.

Let R be a set of terminal nodes. We can then ask for the set V of nodes v , such that any directed path, starting at a node v will arrive after a finite number of arcs in a node from R. (This is asking for the weakest pre-condition for the finite state automaton.) After reducing the given graph by removing from each node from R its only outgoing arc, with respect to that reduced graph we can also define the set V as all the points v , such that each directed path starting at v is finite.

The following sequential program would do the job. Assuming the nodes to be consecutively numbered, we introduce an array nia —i.e. “number of ill-directed arcs— that (after the removal of the outgoing arcs from nodes r in R) count for each node the number of its outgoing arcs that lead to a node outside V.

| “initialize nia such that nia(r) = 0 for r in R and nia(n)=
| number of node n’s outgoing arcs for any node n not in R;
| C:= R; V:= empty;
| do E ≠ empty → transfer an arbitrary node c from C to V;
|  | PC:= predecessor set of c;
|  | do PC ≠ empty → remove an arbitrary node pc from PC;
|  |  | if nia(pc) > 1 → nia:(pc)= nia(pc) - 1
|  |  |  | ▯ nia(pc) = 1 → nia:(pc)= 0; C:= C + pc
|  |  | fi
|  | od
| od . ”

And this sequential program demonstrates the ugliness of the problem quite nicely: for the initialization of nia we need for each node outside R (the size of its) successor set; thereafter we need for each node c its predecessor set.

The following “program” is a little bit less sequential: it manipulates the connection matrix. Let con(i, j) = 1 if the is an arc from i to j , otherwise con(i, j) = 0. (To each terminal node corresponds a 1 on the diagonal which is the only 1 in its row.) The array con will be broken down as the computation proceeds:

| “C:= R; V:= empty;
| do C ≠ empty → V:= V + C:
|  | make all columns corresponding to the elements of
|  |  | C equal to all zeros;
|  | C:= all elements outside V to which correspond
|  |  | all-zero rows
| od . ”

Here the “ugliness” observed above is reflected by the repeatable statement itself, in which the connectivity matrix is accessed either by rows or by columns. In its second form the algorithm reflects, however, the potential parallellism, because each time all columns or all rows respectively can be treated concurrently.

One and a half year ago I designed a number of so-called “elephants built from mosquitos”. The idea was that we should have a large set of microcomputers —mosquitos—with only very few input legs and output legs (and possibly some antennae for synchronization). According to a fixed pattern, input and output legs would be paired, each pair thus providing a directed communication link between two mosquitos. The question was whether we could design powerful special-purpose elephants built from such mosquitos, harmoniously humming together. (The hyper-fast Fourier elephant was the most spectacular output of that effort, but it turned out to be known.) The remainder of this report deals with the design of an elephant solving the problem posed above. It is reasonable to wish to design an elephant for this task: the modifications to which the matrix con is subjected is strictly monotonic and that should simplify the problems, otherwise present in elephant design, considerably. We are not interested in a one-mosquite elephant, not in an N²-mosquito elephant either, and we are heading for an N-mosquito elephant, and we shall try to come away with the simplest strongly connected arrangement I can think of: a cyclic arrangement with traffic in one direction only, with a mosquito associated with each node.

We consider the nodes and the associated mosquitos numbered from 0 through N-1 . In order to do away with superfluous subscripts, each machine j refers to machine (j+1)mod N as “its right-hand neighbour”. If all machine have a variable called “x” , transmission of information to one’s right-hand neighbour will be coded as “xR:= ....” (We are heading for fully synchronized mosquitos.)

We shall now describe mosquito nr j . It is primarily the manager of the j-th column of the matrix con . We shall represent it as a boolean vector (with “true” for “1”, i.e. the presence of an incoming arc for node j )
arc(i) means: from node i leads (still) an arc to node j.

Furthermore, we observe that in an arrangement like this, it does not seem to do any harm if a mosquito, once in set V , continues to set its vector “arc” to all elements false (for the time not bothering about termination). We introduce for each mosquito j a boolean out means: node i is (still) outside set V.

We initialize V:= R , i.e. out = false for all target nodes and still true for all the others.

Consider what will happen if all machines j are now, after this initialization, simultaneously started on a synchronous execution of the following program:
mosquito j:

| arc:(j)= arc(j) and out; xR:= arc(j);
| i:= (j - 1) mod N;
| do i ≠ j → arc:(i)= arc(i) and out;
|  | xR:= x or arc(i);
|  | i:= (i - 1) mod N
| od
| out:= out and x

Each row is inspected starting at the diagonal and then towards the right. Each mosquito starts updating its column at the diagonal and then upwards. Each time a mosquito has updated element arc(i), x means “in row i a 1 (or true) occurs to the left of column j up to and including the diagonal element of row i”, and updating and confrontation take place in complete synchronism. The above program should be repeated as many times as necessary. The following program will see to that with the same initialization
mosquito j:

| new:= non out; act:= true;
| do act →
|  | goonR:= new;
|  | arc:(j)= arc(j) and out; xR:= arc(j);
|  | i:= (j - 1) mod N;
|  | do i ≠ j →
|  |  | goonR:= goon or new;
|  |  | arc:(i)= arc(i) and out;
|  |  | xR:= x or arc(i);
|  |  | i:= (i - 1) mod N
|  | od;
|  | new:= out and nonn x;
|  | out := out and x;
|  | act:= goon
| od .

All mosquitos will terminate simultaneously. (The local boolean “act” is not strictly necessary: we could have done it with “goon” itself.)

*              *
*

Time-wise, the above elephant is not very spectacular. Perhaps this is not too surprising: it has been remarked before —for instance by Hopcroft and Tarjan in print— that algorithms manipulating graphs in terms of the connection matrix tend to be relatively poor. This elephant has been recorded for a few other reasons.

Firstly —with the exception of the hyper-fast Fourier elephant— very little has been documented about our earlier efforts at elephant design.

Secondly, this is the first time that I have been able to solve a problem from graph theory with an elephant whose internal connection pattern between the mosquitos does not depend on the structure of the graph. (If it does, the elephant is such a very special-purpose one to be hardly interesting.) In view of the remark by Hopcroft and Tarjan it remains questionable whether much may be expected from such elephants, but that is still an open question.

Thirdly, it has been recorded as “a reminder”, viz. a reminder of the fact that we do not have any systematic methodology for elephant design as we now seem to have for the design of sequential programs. The latter we can now usually present as the “natural” outcome of a number of stepwise refinements. The reader who has seen a number of such program developments will have noticed the completely different presentation of the above elephant. I can only say: “Well, here it is.” and the reader, at the moment of understanding it, is expected to react with: “Ain’t that cute!”; But this is, of course, very unsatisfactory, for it just means that we have not understood yet the problems involved in elephant design. (The interlocking of updating the columns and scanning the rows is, of course, “cute” and there is no point in denying that I show it with some pride!)

Fourthly, the way in which simultaneous termination of mosquito activity is controlled —although not “deep” in any sense— seems to have the virtue of generality, and therefore, deserves recording.

Fifthly, the solution seems remarkable for its very low demands on the facilities for inter-mosquito communication.

28th November 1974     |     prof.dr. Edsger W.Dijkstra
Plataanstraat 5     |     Burroughs Research Fellow
NUENEN - 4565 |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-13 .

EWD465

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 465 Monotonic replacement algorithms and their implementation

is held in copyright by Springer—Verlag New York.

The manuscript was published as pages 84-88 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,

Springer-Verlag, 1982. ISBN O—387—90652—5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited. .

Monotonic replacement algorithms and their implementation.

(The following is written with demand paging for fixed-size pages in mind; the size of the pages being fixed is probably not essential.)

The idea of a virtual storage implementation is that not all the stored information (both program and variables) needed for the progress of a computation need to be in primary store simultaneously, but that for large periods of time parts of it may reside in secondary store. For this purpose the information is partitioned over a number of chunks such that during progress the information of a chunk will be either totally present in, or totally absent from primary store. In this sense the chunks are our “units of presence”. If all the chunks have the same size, they are called “pages”; primary store is then subdivided into so-called “page frames”, i.e. units of store able to contain exactly one page.

The idea of demand paging is that the computation can proceed at full speed until access to an absent page is required. Such a requirement is called “a page fault”: the computation causing it comes to a grinding halt until the page needed has been brought in. If only pages were brought in, the capacity of primary memory would be exceeded very quickly; therefore, upon a page fault a page swap takes place: one of the pages present in primary memory while the page fault occurs is sent back to secondary store, is “dumped”. The page subjected to this fate is called “the victim” and it is the purpose of the so-called “replacement algorithm” to choose the victim.

Elsewhere —in EWD462 (and in its preliminary version EWD408)— I have argued that in a multiprogramming environment the victim should be chosen from the present pages of the program causing the fault. The number of pages that a program has present in primary store, its so-called “window size”, is; as a result, not changed by the occurrence of a page fault. It is the purpose of this note to describe how the information is to be collected on account of which a reconsideration of the window size can be justified,

We call a replacement algorithm “monotonic” iff (i.e. if and only if) it has the following property. If the program were executed twice (but in strict synchronism) with two different window sizes, the pages present in the smaller window will at any moment all be present in the larger window, if this were the case at program start. Monotonic replacement algorithms have the pleasant property that the page faults occurring with the larger window size are a subset of those occurring with the smaller window size, and an increase of the window size can never lead to a higher page fault frequency. It is easily seen, however, that a larger window size needs not to lead to a lower page fault frequency either.

Note 1. Here “frequency” is not meant as “number of times per unit of real time”, but as “number of times per unit of computational time”, i.e. with repect to a clock that runs while the program is being executed at full speed and is stopped while the computation is not in progress.(End of note 1.)

Note 2. In the sequel we shall take the freedom to consider for fixed window size the page fault frequency as a function of —computation, see previous note— time, although a frequency cannot be the function of a moment, as it is only defined as an average over a period. For the time being we can think of something like

| 8 /(now - the moment of the last page fault but 7)

Physicists —vide Lorentz— do things like this all the time; we shall return to this later. (End of note 2.)

Although we know that at any moment the page fault frequency is a non-increasing function of the window size, we have without further information no knowledge about the slope of that curve (nor need, for a given computation that slope be constant in time). As a result, with a certain target page fault frequency in mind, we cannot trust the effectiveness of the simple feedback mechanism that increases or decreases the window size if the page fault frequency observed with the current window size was too high or too low respectively. (This would be like trying to keep a car on the road for which the actual steering mechanism reacts with unknown and varying sensitivity to a rotation of the wheel!)

In particular:
1)     If the current window size gives a page fault frequency which is higher than the target value, we would like to know the larger window size (if any!) for which the page fault frequency would be small enough. (We just cannot expect to find this larger value by trial and error: if within the bounds of primary store no such window exists, all trials become errors, and quickly even expensive ones!)
2)     If the current window size gives a page fault frequency which is higher than the target value —and therefore, decreasing the actual window size is not something one feels tempted to suggest— we would like to know how much the window size can be decreased without increasing the page fault frequency.
3)     If the current window size w gives a page fault frequency lower than the target value, we should like to know the page fault frequency for a window of size w - 1 : if that is much higher than the target value, we must abstain from decreasing the window size.

Note 3. The curve plotting the page fault frequency as a (non-increasing) function of the window size has very often rather sharp knees. In such a situation the simple feedback system can easily lead to thrashing half the time.(End of note 3.)

The moral of the above is that in order to justify an adjustment of the window size, we would like to know the (current) page fault frequency for all possible window sizes, and not just for the actual window size w. In the sequel we shall show how this information can be obtained for monotonic replacement algorithms.

Monotonic replacement algorithms define (independent of actual window sizes!) after each access a unique order for the pages of the computation that have been accessed at least once during program start. (In the following that ordering only interests us for the first maxw elements, if maxw is the maximum window size.) At any moment the k-th page in that order is the unique (!) page that would be contained in the window of size k, but not in that of size k -1

Consider now the effect of an access to a page which, prior to the access to it, is at position K in that order; upon completion of that access it must be at position 1 . (If we had executed the program with a window size = 1, the page concerned would have been in that single page frame window.) If K > 1 , then the page originally in position 1 has to move to a position higher up in the order, k₁ say; then the page originally in position k₁ has to move to a higher position, k₂ say etc. until a page is brought into position K . More precisely:
with ki₀ = 1, kin = K and for 0 < j < n: kij < kij+1
a cyclic permutation of pages has to take place with the page originally at position K moving to a lower position (viz. 1), all other ones moving to a higher position. For position k with k > K, the ordering remains unaffected.

Note 4. If, for 0 ≤ i < K we take ki+1 = ki + 1, i.e. each page originally at a position k < K moves one position higher up in the order, we have the LRU-algorithm (Least Recently Used). For each window size w we have that K > w indicates a page fault, the page originally at position w is indeed both the least recently used one and also the one that will be pushed outside the window. (End of note 4.)

Note 5. All other reorderings than the cyclic permutations described above would lead to more than one page moving to a lower position in the order, i.e. for some window sizes an unasked for page would be brought inside the window, but that is not what we call “demand paging”: the combination of demand paging and monotonicity makes the above cyclic permutations the only permissible ones. (End of note 5.)

*              *
*

The mechanism consists of a string of mosquitos numbered from 1 through wmax. Mosquito nr. i has a variable cp (current page) whose value equals —for the moment we assume that the mosquitos are fast enough— the name of the page currently in the i-th position of the order. Furthermore each mosquito is activated by placing a page name on its “A input” and one on its “B input”. The A input will equal the name of the page that arrives in its position, the B input is the name of the page being accessed. Upon access of a page, its name is placed on both A input and B input of mosquito nr. 1. The code for mosquito or. i is: (for LRU)

| if cp ≠ B input → A output:= cp;
|  |  | B output:= B input;
|  |  | cp:= A input
|  | ▯ cp = B input → cp:= A input
| fi

where the output of mosquito nr. i is the input for mosquito nr. i + 1 .

Left alone, the mosquitos will update their cp-value in the order of increasing ordinal number. If the accessed page was originally in position K, the first K-1 mosquitos will select the first alternative, the K-th mosquito will select the second alternative and there the “ripple” ends. If K > w, a genuine page fault occurs.

If this string of mosquitos were used to detect the presence or absence of a page, the transmission speed of the ripple would have to be very high viz. wmax mosquitos per memory access at least. Under the assumption of independent presence/absence detection with respect to the current window, higher mosquitos may lag behind! It suffices if they can go through the above motions with a speed of once per memory access: they are like the elements of a fancy shift register.

For the i-th mosquito each selection of the first alternative corresponds to a page fault that would have occurred if i has been the actual window size. Each mosquito has to extract from this series a corresponding “page fault frequency”. They can do so by taking the past into account by an exponentially decreasing weight, for instance by keeping each a variable amppf (“average moment previous page faults”) and transmitting “now”, and adjusting each time the first alternative is selected amppf for instance by
     amppf := amppf + (new - amppf)/8, (where “now” refers to the moment that the ripple entered the string of mosquitos). If for a certain window size the page faults occur at regular time intervals “delta”, then in the limit:

before each adjustment: | now - amppf = 8 * delta and
after each adjustment: | now - amppf = 7 * delta

If we don’t like this discontinuity, we can store per mosquito in addition for instance amppf’, each time updated by

| amppf’:= amppf’ + (now - amppf’)/2 .

With page faults occurring at regular time intervals “delta”, we have then in the limit:

before each adjustment: | now - amppf’ = 2 * delta
after each adjustment: | now - amppf’ = 1 * delta

As a result we have constantly amppf’ - amppf = 6 * delta, and with the above we have achieved a Lorentz-like smoothing (see Note 2.)

*              *
*

Two questions have been left unanswered, but it seems premature to try to settle them now.

The first question is what to do when a processor switches from one program to another. As an elephant contains the information of wmax mosquitos, wmax may be high and processor switching may occur at great frequency, switching one elephant with equal frequency from one program to another might lead to unacceptable switching delays. I can only think of the crude solution: have at least as many elephants as we have high-priority programs. With LSI-techniques —the more of the same hardware, the better-this is perhaps no so unacceptable as it sounds in my puritan ears.

The second question is how the collected information for a program is to be delivered. This has to occur at a page fault —when the victim has to be chosen— and upon reconsideration of the window size. Particularly in the first case the “lagging behind” of the mosquitos higher up in the order presents some difficulties: it makes instantaneous selection of the victim impossible.

19th December 1974 |  | prof.dr.Edsger W.Dijkstra
NUENEN - 4565 |  | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-15 .

Copyright Notice

The following manuscript

EWD 466: Trip report E.W.Dijkstra, Meeting IFIP W.G.2.3., Munich, 8-14 December 1974

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 89–94 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 466

Tripreport E.W.Dijkstra, Meeting IFIP W.G.2.3., Munich, 8 - 14 December 1974.

"Schlaf aus deine Freude, schlaf aus dein Leid..."
(my translation: "Sleep off your joy and sleep off your sorrow....")

Wilhelm M�ller (1794 - 1827)

The first record I placed upon the turntable after arrival back home was the (2nd) Fischer Diskau/Moore recording of "Die sch�ne M�llerin" by Schubert/M�ller. In view of the poet's avowed longing for death —"Das Wild, das ich jage, das ist der Tod" (again my translation: "The game that I hunt is death itself.")— and the fact that 1827 - 1794 equals only 33, Wilhelm M�ller had done fairly well.....

I made the trip from Eindhoven to Munich —on Sunday— and vice versa —on Saturday— by train: it is a through connection and the fact that it takes slightly more than nine hours does not worry me. Trips like these remind me of the story told to me by Brian Randell, of the man who commented on his ability to do two things concurrently "I can sit and think." and then added "and often I only sit....". On the trip to Munich —German international railway carriages really run smoothly!— I wrote the major part of a paper on the implementation of monotonic replacement algorithms —in the literature erroneously known as "stack algorithms"— on the way back I thought —rather unsuccessfully, I must admit— on grammars for defining the structure of classes of strongly connected graphs, and, when that alley seemed dead for the moment, on redundant object code representation. (To think again thoughts with a possibly direct bearing on the machine design is great fun!). By the time I crossed the German/Dutch border I had arrived to a few firm conclusions according to which all machines in the design of which I have ever been involved —and many others, for that matter— contained the same flaw).

I am not sure when I shall find the time to work this out and write a readable report about it. Arriving home after a week's absence I received from my dear wife the carefully collected mail. (For the purpose of this report I weighed it: 2300 gram, all from people I have never written before. In about one hour I read a —French— thesis of 500 gram, which I shall direct along the appropriate channels, but the remaining 1800 gram I have to process myself more seriously.) My youngest son saw me browsing through all that mail and announced that later in life he did not intend to become a professor! Blessed are the innocent children, even one's own.... (At the party on Thursday evening, quite a few people asked me what it meant and how it felt to be a Burroughs Research Fellow. After my explanation that it is my main commitment "to do my own thing", the usual reaction is something like "That must be an exciting, but also frightening challenge." It was quite remarkable that all German-speaking colleagues only saw the exciting part and that none of them saw the frightening side of it: they all reacted with undiluted envy. Thus they confirmed my earlier impression that at the German-speaking Universities the level of life is not just bad as everywhere else, but distinctly below average.)

The Working Group "On Programming Methodology" met from Monday morning to Friday afternoon. I spoke to them on Monday afternoon on highlights from my book and I was moderately successful. I should have given them a list of highlights and the chance of selecting from them; I made the choice instead. Secondly I should have taken the time to prepare a number of transparencies, for now I struggled continuously with a lack of blackboard space. Friday afternoon I tried to get a discussion going on the purpose of "types" and the "pros and cons of polymorphic functions". That seemed a disaster, but I think that we miss the point when we blame that on our being tired and my having half a flu. Later I remembered that my effort to bring that topic in discussion in Bristol had been equally unsuccessful. In all probability, the moral of the story is that types do not play such a predominant role as we may have thought, and are certainly no good for abolishing the notion of partial functions. And secondly —but that conclusion was not drawn that afternoon— that "scope rules" (both positive and negative ones) provide probably a much more useful form of redundancy.

Doug McIlroy from Bell Labs described a program structure built from modules connected by "pipes", which was nice for the way in which he used the —not unknown— ideas for program composition and modification. It was his talk that made me think about grammars for strongly connected graphs; as the latter is not a trivial problem, it remains to be seen whether we shall see modules in a much more complicated arrangement then, say a pipe line. (Note that with one noteworthy exception, all my elephants up to now are built as a cyclic arrangement of mosquitos: I sometimes have the feeling that this is not just lack of originality on my side!)

The next morning I missed Doug Ross (Softech), as I had to act as the opening speaker at a meeting of the German Chapter of the ACM. This, again, was only moderately successful: I was amazed to find in the Max Planck Institut no throat microphone; besides that I had to work on a grey blackboard. Shortly after my performance I went back to the Leibniz Rechenzentrum, where first Peter Naur (Copenhagen) and then Jim Horning (Toronto) described experiments with large number of students: Peter's statistical material came from inquiries filled in by the students, Jim's statistical material came from mechanically observed errors. It was instructive in the sense that they described experiments I would never do myself; on the other hand the results seemed very inconclusive. I do not expect that with respect to such an individual activity as "thinking" any deep insights can be obtained by observing group behaviour. I have similar doubts regarding Lehman's (London) "Evolution dynamics of large programs."

In the course of the week it was suggested that my sequencing discipline would lead to an unusual great fraction of complicated boolean expression. To stay in tune with the statistical approach I counted the "guards" in the program texts in my manuscript: 155 simple ones (either a relation or a boolean variable or a negated boolean variable) and 27 complicated ones (in which I had counted all cand's and cor's double): 15 percent. I then conducted an inquiry among the people present, asking for their personal estimation of the percentage of complicated boolean expression in their programs: the average of the answers was 17.5 percent. "...but, please, always be sure to call it: Research" (Tom Lehrer).

Niklaus Wirth (Zurich) gave a very illuminating (critical) review of PASCAL: illuminating because he was more explicit than ever about the motivations that had gone into the design and, besides that, was not defensive. He was the first to evoke a real discussion among the members; in some other cases I think members were afraid to give their minds. David Gries showed how he tried to extend the axiomatic approach of Tony Hoare: it was not complete yet, but looked promising and eminently manageable. In any case he has already made clear to me that the technique of "ghost variables" is more powerful than introducing "progress functions" which are just a special case. Brian Randell (Newcastle-upon-Tyne) described the current state of their recovery project. It was only after the meeting, when Brian had already left, that I remembered having a precious document in my pocket. It was titled "THINGS TO BE PUT INTO A SYSTEMS DESIGN LANGUAGE" and compiled by him and me at the first ACM Symposium on Operating Systems Principles, Gatlinburg, 1967, when a number of the participants blamed the difficulties of operating system design on the absence of a suitable "language" and founded an ad-hoc subcommittee for the design of such a tool. We did not join that subcommittee but, during dinner time, compiled a list of recommendations instead. (When it was completed, we did not want to keep our fun for ourselves; at the other end of the dining room a larger group of participants was having dinner and for their amusement we let our list circulate around their table. It was only the next day that we discovered that at that other table.... the subcommittee had its meeting!) our list contained:

automatic backup features
dynamic maintenance facility
condition reallocation facility
built-in heuristic procedures
levelling and delevelling concepts
file system generators
interrupt dispatcher control
automatic flaw recovery
system retry
parametric fork and spoon generators
system into madness putter
peripheral abstraction detector
general purpose modularity device
page fragmentation absorber
recursive scheduler
symbolic resource optimizer
graceful degradation (of female operators) (Brian's handwriting)
garbage assembly
maximized cost performance
self-documentation
underware (= system support)
cognitive self-reproducibility
interruptable virtuality
delay module insertion coordinator.

I have the feeling that many of the subjects listed above have been discussed last week in one way or another. A sobering thought...

Tony Hoare (Belfast) spoke on "Levels in Operating Systems" and this looked very promising. He had bent SIMULA to his purpose. Although I was very keen on getting a good grasp on what he was proposing and why, I intentionally made no notes, because I know that the only way in which I can hope to come to grips with that problem —a rather continuous evolution from rather bare machine to user programs added as "the last layer"— is by writing it down myself. I had tried to design something like that many years ago and remember where I got hopelessly stuck and I think that Tony showed how to get out of it. But his presentation —usually he is crystal clear— was influenced by its historical origin, and carried a lot of the SIMULA confusions with it. So I guess that I must reinvent the wheel in such a way that also simple-minded persons like myself can see that it is round.

George Rabin (Poughkeepsie) gave a talk in which he failed to communicate to me: my guess is that his problems have only a meaning provided one takes a number (how many?) of OS/360 positions for granted. I was wondering what he was talking about, and so did a few others.

The encounters outside the official sessions were more rewarding and have covered all sorts of things. Tony made a promising suggestion as how to deal with "dual elephants", although it will require at least a very good taste if the notation is not to become too hairy. Two subscripts, which in turn may be associated with time and space seems a minimum. Niklaus told a terrible story about CDC-software. With 10 six-bit characters (from an alphabet of 63) packed into one word, CDC used the 64th configuration to indicate "end of line"; when for compatibility reasons a 64th character had to be added, they invented the following convention for indicating the end of a line: two successive colons on positions 10k+8 and 10k+9 —a fixed position in the word!— is interpreted as "end of line". The argument was clearly that colons hardly ever occur, let alone two successive ones! Tony was severely shocked "How can one build reliable programs on top of a system with consciously built-in unreliability?". I shared his horror: he suggested that at the next International Conference on Software Reliability a speaker should just mention the above dirty trick and then let the audience think about its consequences for the rest of his time slice! At another occasion Mike Woodger (Teddington) gave a verbal clarification for his enthusiasm for the work of the Polish logician Lesniewski, an enthusiasm he had earlier communicated to me by mail. If Mike says that this work is far superior to the work of better known logicians like Quine, Fraenkel, Bernays and Rosser who have "abandoned hope of relying on intuitive logical common sense in the face of the antinomies" because Lesniewski has successfully avoided the paradoxes by introducing "sets" as coins with two faces, I believe him. But it will take a long time before it will soak in. Firstly Lesniewski's notation is somewhat hair-raising, secondly, practically all people that could read it, would have to unlearn the Principia Mathematica first. I came to the conclusion that I am not a logician, nor that I feel a strong desire to become one.

On Friday evening Tony —who had also addressed the German Chapter of the ACM— and I were invited for dinner by Christiane Floyd and Peter Schnupp, who had organized the meeting of that Chapter earlier that week. We were joined by four other Germans and had a quite pleasant dinner, that did not start very early, nor ended very early. (As my train left the next morning at 11.42, I did not mind too much.) The spirit at the dinner table is quite well characterized by one of the Germans quoting "You may be consistent or inconsistent, but should not all the time switch between the two."

Gerhard Seegm�ller had organized the meeting in the Leibniz Rechenzentrum and the party in his home on Thursday evening as smoothly as the previous occasion. At that party I also met Manfred Paul and Fritz Bauer. The latter was very busy, because that very week there was in Munich a meeting of numerical analysts in honour of Householder. Olga Tauski and Dick Verga —with whom I had one or two breakfasts— shared our hotel.

I left Munich on Saturday morning gladly, when I came home in the evening I was a little sad.

16th December 1974 NUENEN | prof.dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 28-Sep-2011

EWD469

Programming methodologies, their objectives and their nature.

Years ago I gave a talk at a large software house, showing what techniques we had at our disposal for proving the correctness of programs. The talk was a disaster. My audience rejected the topic for what they regarded as sound business reasons: from a business point of view, correctness was their last goal: it was much more important to make a customer dependent on a software product so poorly documented and still so full of bugs, that its maintenance contract fell into your hands as well. But not only the managers of the firm rejected my topic, so did the programmers in my audience: they felt that I was tampering with the magic of their craft. While I had urged that a programmer should continue to understand what he is doing, it transpired during the discussion that many a professional programmer derives his intellectual excitement from not quite understanding what he is doing, from the daring risks he takes in his irresponsibility. They wanted the magic of their craft to remain black magic.... I mention this story because their reaction took me by surprise. My first explanation for it was, that in this streamlined society, the craving for magic is one of our most undernourished ones and that programming without truly understanding what one is doing, is one of the ways to satisfy that deep psychological need for magic. Later I understood that there is a second explanation.

All through the centuries, knowledge and skills have been transmitted to the next generation by two techniques.

The one technique we find with the guilds: here the apprentice works for years under the guidance of the master, all knowledge is transferred implicitly, by osmosis, so to speak, until the apprentice has absorbed enough of it to become a master himself. The members of the guild typically keep their common knowledge and skills among themselves as a well-guarded secret.

The other technique we find at the Universities: here teachers try to make the knowledge explicit, to formulate it in words and symbols and, by doing so, try to bring it into the public domain. It is no accident that the rise of the Universities coincided with the emerging art of printing: by being formulated, the knowledge became more stable and lasting and could, indeed, become public property.

But, whenever the followers of the University try to bring a new field of knowledge into the public domain, try to make an explicit science out of a secret craft, the members of the corresponding guild feel themselves to be threatened. And that feeling of being threatened accounted for the barrier that I hit when I tried to reach the programmers of that software house! But, thank goodness, that audience did not make up the world. The so-called "software crisis" became so apparent, that all sorts of people involved, both programmers and managers, felt that something should be done about it and started to wonder what.

For a long time many people felt that the software failure was largely due to a failure of management. This is understandable: the larger a project is, the more management is involved, and it were particularly the large software projects turned into disaster, that attracted the most attention. Besides that, many were justly impressed by the American space program that, by being so successful, led many of us to believe that with perfect management one can reach any goal.

The idea that improved management techniques could solve the problem was further inforced by the discovery that the techniques, used for managing software projects so far, were indeed highly questionable. To take a simple example: in those days it used to be quite usual to measure a programmer's productivity by number of lines of code produced per day. Reasonable, isn't it? It is a programmer's job to produce programs, and the more programs he produces, the more productive he is! But on closer inspection, that measure was discovered to be not only meaningless, but even harmful. It is meaningless, because the programmer is not supposed to produce "programs", he is supposed to produce solutions, and the program he writes is only a carrier for that solution, and the more unnecessary lines of code he uses, the poorer his solution. But measuring his productivity by the production speed of lines of code encourages such poor solutions: it encourages the fast production of insipid code. Besides that, that crazy measure of productivity encourages coding as such, and more and more people began to discover that the coding stage, at least most of it, had better be postponed as long as possible: being in a sense the most laborious stage of the programming process, we had better try to postpone it until we are as sure and certain, as we can, about what the piece of code should accomplish. The modern advice is "Don't rush into coding!" and I expect that in a well-run establishment today a programmer is not allowed to start coding something without explicit permission. I also guess that many managers would be happy with the rule that everyone pays the punched cards he uses out of his own pocket.

But those who had great expectations of the new management techniques, those who embraced Systems Engineering or something of the same nature as the new religion that would bring salvation, were disappointed. The question is simply the following: better management techniques, although indispensable, will, all by themselves, never compensate technological shortcomings. While it is clear that without some sort of quality control it is vain to hope to produce good products, it is also clear that no amount of quality control will ensure the production of good products if you are unable to make them in the first place. And it was at that stage, when the shortcomings of our programming ability were recognized, that people started to talk about Programming Methodology (with two capital letters). Needless to say, a considerable amount of thought had already been given to it, under the surface, so to speak, before that problem area had a name.

Questions that became important were "Why is programming so difficult?" and "When we know why programming is so difficult, can we avoid some of its difficulties?" Again, the spectacular failures of a few large software projects attracted, at first at least, most attention. I remember myself having been responsible for the following argument, showing why the size of a program has consequences for the confidence level of its parts. The argument was as follows: we all know, that we must make a large program by composing it out of a number of "modules", N say, and if p is the probability for a single module to be correct, the probability P for the whole program to be correct, satisfies something like

P ≤ pN

We may now laugh a little about that formula and wonder, how much it means as long as we don't know what we call "a module", but the formula showed one thing quite clearly: if N is large (and such programs we were thinking about), then p should be indistinguishable from 1 if P is to differ appreciably from 0. The size of the whole system puts heavier demands upon the confidence level of the individual components. Perhaps was the argument only put forward as a justification for the already existing desire to study software reliability!

There were a number of reasons for turning our attention to the process of programming itself. A really compelling reason was the demonstrated ineffectiveness of the debugging process. People spent more than fifty percent of their time to the debugging of their programs and still they delivered error-loaded products: it was concluded that program testing might demonstrate the presence of bugs very convincingly, but is hopelessly inadequate to demonstrate their absence. And therefore attention turned to the problem how we could prevent most of the bugs from entering the design in the first place. In view of the well-known advice "Prevention is better than cure" not a surprising conclusion; yet it was a conclusion with considerable effects.

There was a second reason for turning our attention to the programming process, equally compelling, although perhaps less obvious. The insufficiency of a posteriori quality control by testing being demonstrated, there might be the possibility of proving the programs to be correct. A correctness proof seems indeed a much more effective alternative for raising the confidence level of our software products. But the first efforts at proving a posteriori that a given program was correct were not encouraging, to put it mildly: if the proofs could be given at all, they were so laborious and sometimes tortuous even, that they failed to inspire much confidence. This was partly due to our limited experience, to the absence of useful theorems, etc., but it was also a consequence of the programs themselves. Comparing these "given" programs with programs that were designed with the intention of proving their correctness as well, showed that the amount of formal labour and of detailed reasoning needed, could depend critically upon the structure of the program itself.

This was a very valuable discovery, for it drove home the message, that it does not suffice to design a program of which we hope that it meets its requirements, but that we have to design such a program that we can demonstrate that it meets its requirements. The program must be such that whatever we accept as convincing correctness proof must be feasible as well.

This additional requirement of demonstrability of the program's correctness implied very obviously a change in the programming task and therefore a change in the act of programming. At first sight it seemed that this additional requirement would place another burden on the poor programmer's shoulders, but upon closer inspection it turned out to make his task in some sense lighter. Needless to say, this was a very encouraging discovery. As more and more became understood of what it means to prove the correctness of a program, we got gradually a better knowledge of what kind of dirty tricks are most harmful to the feasibility of giving the proof. As such, the additional requirement of the demonstrability of the program's correctness limited the programmer's freedom, but that is only a negative way of describing its influence; the positive way of describing its influence is saying that it gave him elements of a discipline. The smaller his solutions space, the smaller the probability that he loses his way.

It is about here in my story that I must insert a small interlude about the social role of mathematics. In the above I have referred numerous times to "proofs" and one may raise the question, whether formal proofs in a strict mathematical sense are really needed. They are not, of course. The real need is a convincing demonstration of the program's correctness, and as the number of cases that we can try is negligible compared with the number of possible cases, we must to all intents and purposes rely for all of them on reasoning. Whether this reasoning takes the strongly codified form of a mathematical proof is quite another matter. In many cases good English is as adequate a vehicle for expressing the reasoning in a convincing manner as a mathematical symbolism. Most demonstrations of correctness of programs that I see today are largely prose, only at specific points —where the subject matter requires it and prose would give rise to lengthy and clumsy descriptions— supplied with some formalism. The competent reasoner always chooses the vehicle that is most convenient for the situation.

Why then, one may ask, the stress on formality, a formality that frightens the layman and tires the reader? This question is fully justified, for the formal aspects of correctness proofs for programs are given considerable attention. I would like to give several answers to that question. If you think a formal treatment an obfuscation and failing to convince because formal manipulations are as error-prone as programming is itself, I must warn you, that verbal arguments are tricky too, often more tricky than we would like to admit, and more often than the superficial reader suspects general cautiousness fully justifies taking recourse to formal treatment. This is a justification. Secondly, believe me or not, there are quite a number of bright young lads, who just like those formal games. That is an explanation. But most important is its consequence, thanks to the fact that it is a generally accepted standard: it has turned out to be instrumental in reaching a consensus on many points.

Since the early sixties I have attended many discussions about the elegance of programs, about the adequacy of proposed language features, discussions which were distressingly inconclusive for lack of a common yardstick that was generally accepted as relevant, and was also effective. Too much we tried to settle in the name of "convenience for the user", which was a nice altruistically sounding name for our ignorance and lack of direction. As soon as the possibility of formal correctness proofs emerged, the picture changed completely. The suggestion that what we intuitively regard as an elegant program is usually also the program that admits the shortest formal correctness proof —there was a reasonable amount of experimental confirmation of that hypothesis— was immediately accepted by many as a sound and effective working hypothesis. By its objectivity it was very effective and has done more for the reaching of a consensus with regard to the goals of programming methodology than anything else I can think of. Such a consensus is indispensable for any joint effort that should have impact, and, from a historian's point of view, the general acceptance of the working hypothesis is more important than the question how correct it is. The fact that from then onwards a number of mathematicians claim to contribute to computing science by studying the structure of such proofs for their own sake and forgetting that they were intended to convince in the first place, is a price that we should ungrudgingly pay.

So much for the role of mathematical formality: it has a place whenever it assists us in understanding what we are doing or considering. And such greater understanding has been the main target of programming methodologies.

*                    *
*

The considerations that have been the most helpful fall in two broad categories. On the one hand we have the general considerations concerning the question how to avoid unmastered complexity, on the other hand we have their applications to the specific problem of programming. And I am very glad that we had both of them: the general considerations without very tangible consequences for the programming activity would have had a hard time in trying to rise above the level of motherhood statements, the specific remarks concerning the programming activity would have had an ad hoc character without the general considerations.

The general considerations try to do justice to the fact that we have small heads and cannot think about many things simultaneously, but, besides that, get tired and unreliable when we have to think about a very great number of things in succession. The way to avoid these situations with which we can hardly cope has been captured more or less by many catch-phrases: the exploitation of one's powers of abstraction, divide and rule, the judicious postponement of commitments, the separation of concerns etc. In any case we must never forget its dual purpose: to parcel out the necessary detailed reasoning into portions of manageable size, but, more important still, to reduce the total amount of detailed reasoning that remains necessary.

Of these, the advice "divide and rule" was, of course, the best known one, and at one stage of the game people have felt that the problem of programming would be solved provided that we could divide the program to be made over "modules" of a manageable size. In retrospect it is not hard to see, that without further guidance, such an arrangement would only postpone the hard problems till the stage of "integration", i.e. when all the modules have to be hooked together. This simple view of "modularization of the program" regarded the program too much as the final product, and took the early decisions as to what the computer was to do too much for granted. From there the attention shifted towards what the computer was supposed to achieve and then it became apparent that what the computer may have to do in order to achieve the desired effect, is greatly dependent on how one structures one's solution. And "separation of concerns" is, since then, a more adequate term, because now one tries to parcel out —or, to use another term: to factorize— the requirements.

To mention a few of such separations, we want our program to be correct, we want our program to be efficient. Although the choice of the algorithm is usually heavily influenced by efficiency considerations, by the time that we focus our attention upon the question whether under all circumstances the execution of the program will deliver a correct result, all efficiency considerations can be temporarily forgotten, we can even forget the possibility of interpreting our text as executable code and settle the problem of correctness quite independent of possible computational histories. This has given rise to all the theory and practice of proving the correctness of programs, theorems about repetitive constructs expressed in terms of invariant relations —to ensure that no unacceptable result will be delivered— and variant functions —to ensure effective progress for each repetition. The emergence of such theory and practice was greatly facilitated by the restriction to more disciplined sequencing, to well-known alternative and repetitive constructs rather than arbitrary jumps. (For instance: the most useful theorems apply to the alternative and repetitive constructs as a whole.)

Secondly, we want our programs to be efficient. It is here that computation times are taken into account. But by that time one does not need to worry about what result will eventually be produced, the only question that then matters is: how long will the computer be engaged on that task? In general this is a very hard question and again, people have discovered that the most efficient way for solving a problem is to run away from it, i.e. to try to avoid such computational processes to be evoked, for which the run-time behaviour becomes time-wise hardly predictable. Here Herbert A. Simon's "The Architecture of Complexity" (reprinted in The Sciences of the Artificial) has had great influence, as it has pointed out the virtue of what he calls "nearly decomposable systems." It says very roughly the following: if a system is expected to adjust itself to changes in the environment of two types, A and B say, and the adjustment to a change of type A takes place an order of magnitude faster that the adjustment called for by a change of type B, then, while studying the latter adjustment process, we are allowed to idealize adjustment to a change of type A as instantaneous: the "mechanics" of the two adjustments need hardly to interfere: and both can be studied (with respect to speed, stability etc.) in isolation. As soon as one becomes aware of the great benefits that can be derived from the "near decomposability", one immediately tries to design one's systems with the absence of such undesirable —because uncontrollable— interferences as one of one's main design criteria. The successful abolishment of such interference pays twice: we don't need to mess up our thinking, and the machine need not waste its time in elaborate strategies for coping with them.

It is not surprising that these techniques have found at first their most spectacular applications in the design of operating systems. Many of them are now shaped in the form of a family of loosely coupled, harmoniously cooperating sequential processes. The harmonious cooperation is guaranteed by synchronizing them explicitly, without making thereby any assumptions about speed ratios. It is in that realm that mutual integrity of fellow programs in a multiprogramming environment, the absence of deadlock and of individual starvation etc., can be dealt with rigorously. It is in the way of dealing with microsecond phenomena —such as interrupt handling—, and millisecond phenomena —such as page fault handling— and second phenomena —such as resource allocation— that we try to achieve a nearly decomposable system.

In a later stage, when these techniques were applied more consciously, similar techniques have been applied to the design of purely sequential programs. One of the ways in which this was possible, was the following. In sequential programs, we have Boolean expressions (as part of our alternative and repetitive constructs) influencing during execution the flow of control. The way in which they prevent something either disastrous or only undesirable from happening is very similar to the way in which, in multiprogramming, the so-called synchronizing conditions describe whether a process could continue or should be hold up until a more favourable situation has arisen. The techniques that had been developed for the derivation of such synchronizing conditions could be taken over, practically lock, stock and barrel, for the deriviation of the sequencing expressions as they have to occur in sequential programs.

Also: inspired by the successful decomposition that could be obtained in operating systems, people have tried to separate their concerns equally effectively in the design of purely sequential programs. People trying to do so had the pleasant experience that this could be done to a much higher degree than they were used to.

A simple advice that will often show you the way for achieving such a separation is to become extremely suspicious as soon as one finds oneself faced with a case analysis which has to distinguish between a great number of cases that have been generated by some multiplicative mechanism. I have much experience with a problem in which pebbles which are either red, white or blue, are —under a number of additional constraints to make the problem difficult enough— to be sorted in the order of the Dutch National Flag. In a not uncommon approach —which from a point of efficiency seems quite reasonable— people find themselves essentially faced with a case analysis which has to cover 6 different cases. Six is a very high number and usually they get stuck somewhere in the design process. The answer is: think for a moment with how many cases you would be faced, if we had had five different colours, instead of only three! Then one will discover that the answer is 20 —if n is the number of colours, the formula is n*(n-1)—; as soon as that observation has been made, one sees that this multiplicative building up could have been avoided by looking at only one pebble at a time and the case analysis collapses to one with as many cases as we have colours, and from then onwards the problem is trivial. And, in retrospect, the discarded efficiency gain turns out to be close to negligible!

*                    *
*

Developing programming methodologies is more than trying to become a more competent programmer: one must not only learn to become that, one must also be able to teach it. From the above it is clear that the programming methodologies have close connections with problem solving, with effective ordering of one's thoughts, with at least one important aspect of thinking: how not to get lost! And the teachability of such aspects of thinking is not obvious. It is not so much that one must teach manipulative ability, for that can be done, it is done at all levels: arithmetic at the primary school, algebra at the secondary school, and symbolic logic at the university. Now we must try to teach how to think with the aim of reducing the need for otherwise exploding amounts of manipulation.

To give a course "How to Think Big Thoughts in Ten Easy Lessons" is obviously nonsense. But I firmly believe that something else is quite possible. That is, firstly, to drive home the message, that we should think with the purpose of reducing the amount of detailed reasoning eventually needed; that is, secondly, to show the most common mechanisms by which the exploding need for manipulation is generated, i.e. don't only warn them for the symptoms, but also for as many causes as you can name explicitly. To a certain extent this can be done in the explicit style of University teaching.

It becomes harder when we know that we should try to separate concerns, but do not know how to untie and to disentangle the amorphous knot of the initial goals. Some striking examples, dealt with by an inspiring teacher can certainly do no harm. The extent to which we have to be content with teaching this in the style of the guilds, by showing only what we do and hoping that the apprentice will discover for himself how to do it, is still an open question for me. My experience over the last years is encouraging.

One thing is certain: learning how to program well requires a great amount of exercise and confrontation. Exercise in order to get the agility, confrontation in the sense that the learning student must struggle in order to discover how hard programming is: and after having constructed a one- or two-page program in four hours of hard work, show him an eight-line solution that a more competent programmer wrote down within fifteen minutes. It is cruel, but without that confrontation the student will remain stuck at his current level of competence, unless he can learn, all by himself, from his own experience. But people who can do that are extremely rare: if one of our students can do that, he will soon be our Master!

[1] Simon, Herbert A. The Sciences of the Artificial, MIT Press, 1969

prof.dr.Edsger W. Dijkstra
Burroughs Research Fellow
Plataanstraat 5
NUENEN – 4565
The Netherlands

transcribed by Alejandro Ruiz
revised Wed, 29 Apr 2009

EWD470

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Letter to the referees of EWD4l8.

(I refer to the referee who started with “I think this...” as Referee A, to the one starting with “OPINION This paper contains...” as Referee B.)

In response to Referee A’s remark (2): it was not my intention to introduce a terminological innovation when using the word “calculus”. On the contrary! I wanted to be in step with common usage --which I felt obliged to explain, because many people are confused about it-- . I shall change the last sentence of the introduction, as that seems to be the source of the erroneous impression. Referee B suggested that the word “calculus” should be removed from the title because “nowhere a calculus for the derivation of programs is defined”. Instead of defining, I thought --and still think-- that I have “shown” it, at least in my sense of the word “calculus” --and in very much the same sense in which D.E.Knuth uses the term (between quotes!) on page 283 of his recent article in the December 1974 issue of the ACM Computing Surveys--. In order not to arouse false hopes I shall, however, remove the word “calculus” from the title. (Besides that, I prefer underselling above overselling.)

Referee A asks (3) “Why have the notes on page 2 as notes?” Simply because I do not propose to allow empty guarded command sets; they are conclusions, irrelevant for the rest of the story, that have been included as redundant material so that the reader can check his understanding of the two constructs. Referee A’s suggestion (4) will be followed: as the note on page 5 stands, it contains indeed too many negations. I shall also follow his suggestion (5) --to combine the hypotheses of Theorem 3-- and ::although with some reluctance-suggestion (6) “either don’t mention personal feeling [...] or elaborate the reasons”. I know that his suggestion is in full accordance with the scientific tradition (and that tradition is not without wisdom, as it eliminates, for instance, unsubstantiated slander!) But we loose by it too, for even scientists have, besides a head, a heart as well and there is no point in denying the latter one its right of existence. (More than once I have given advice or formulated an expectation while, when asked “to elaborate the reasons”, I found myself unable to do so: I just felt it in my bones.) In this case elaboration would fall outside the scope of the article and the mentioning of my feelings will be removed.

The note on page 6 --referee A’s remark (10)-- is hard to understand: the relation between wp and wdec is, although formally simple, conceptually hard to understand. I have to leave it as it stands, because it says as well as I can manage what I want to say and from Referee A’s remark I cannot deduce a suggestion for improvement. (I don’t see how his “Q(X)” suddenly enters the picture.) May I ask him to try to read the note on page 6 another time?

Referee A’s remark that the four properties of wp are derivable was a remark that I expected. The point, however, is this: either one postulates that our wp’s describe an input/output relation and then they follow from more fundamental axioms of relations or one introduca the wp’s as a formal game and groves -by structural induction-- that our wp’s enjoy those properties (which are then used for proving formally assertions about composite wp’s ). That the wp’s can be interpreted as describing input/output relations then follows. My preference is for the second position, but --intentionally, because it is not a key issue in this paper-- I have used the non-committing term “properties”, and have left the option open whether “by definition” refers to the definition of the notion “weakest pre-condition” --for those readers who prefer the first position-- or to the definition of the specific wp’s I have introduced. I shall mention, however, the issue of non-determinacy versus determinacy in relation to the 4th Property.

(As a matter of fact, the 2nd property is a special case of a more general property --call it “continuity” if you prefer-If for k ≥ 0 we have Ck ⇒ Ck+1 , then we have for any S wp(S, (E k: k ≥ 0: Ck)) ⇒ (E r: r ≥ 0: wp(S, Cr)) . Also this is proved by structural induction. I did not consider its inclusion, although it is fundamental in demonstrating that computations guaranteed to terminate only embody bounded non-detetminacy.)

Referee B makes two comments: he states that “theorem 3 is not entirely obvious and there ought to be a quick proof of it from Fix Point Induction (which ought to be given).” I thought it fairly obvious, for a guarded list is only invoked under such initial condition that P remains invariant and t is decreased by at least 1 . But then it cannot do so indefinitely, because that same condition is stated to imply t ≥ O . It is easily proved by mathematical induction with k --from the definition of the semantics of the repetitive construct (3.3)-- as induction variable. I shall add a remark to that effect. (I shall not remark explicitly that one of the reasons why the formalism introduced in section 3.1, 3.2 and 3.3 attracts me is that all those properties and theorems are quite easily proved without using the Fix Point machinery. I don’t like to crack eggs with sledgehammers, even if the sledgehammer is very good at it.) Referee B further remarks “It is the semantics of guarded statements that are ostensibly discussed, but in fact the major point is really the use of wp(S, R) to ”tighten things up a bit“ from Hoare’s treatment.” I am glad to hear that he regards this “tightening things up a bit” really as “a major point” --so do I myself in my more exalted moments-- but that part of, shall we call it “theory of programming semantics” was not the subject of this paper, which was meant to be of pratical assistance for the programming process. So I just mentioned the necessary results, and proceeded to show how they can be exploited while programming

Referee B’s second remark “It is not pointed out that wp(S, R) need not be a decidable statement. That fact might help some readers to see the disadvantages of the concept.” reveals the nigger in the woodpile that I had thougt to have hidden so carefully! I have taken the point of view that as long as we have not proved that an initial state satisfies wp(S, T) , the semantics are not defined and that a machine, embarking upon the execution of S in such an initial state may do as it pleases in the sense that, whatever it does, we have no right to complain. As an immediate consequence I must reject the follow program for trying to refute Goldbach’s Conjecture that every natural number ≥ 2 is the average of two primes: begin integer n, x, y; boolean refuted; n:= 1; refuted:= false; do non refuted → n:= n + 1; x:= 2; y:= 2 * n; do x < y and x + y < 2 * n → x:= smallestprime larger than(x) ▯ x < y and x + y > 2 * n → y:= largest prime smaller than(y) od; refuted:= (x + y ≠ 2 * n) od; printbool(refuted) end

Because I have not proved that Goldbach’s Conjecture is false, I have not proved that wp(S, T) is initially true, therefore the machine may act as it pleases and I am, therefore, not allowed to conclude that Eoldbach’s Conjecture is wrong when it prints “true” and stops! I would be allowed to draw that surprising conclusion, however, if the third line had been changed into “do non refuted and n < 1 O00 O00 000 →” , i.e. we must be willing to state beforehand “howlong” we are willing to wait for the answer. Now the nigger is out, I shall insert --between parentheses, so as not to alarm the reader who would like to skip the remark-“We consider the semantics of S only-defined for those initial states for which has been established a priori that they satisfy ”wp(S, T).“ , leaving to the reader to decide for himself whether he regards this way of running away from the halting problem a wise restriction or a sneaky way out. Is referee B, after the above still convinced that it is ”a disadvantage of the concept“? I guess, that he is still convinced of the ”disadvantages“. But to quote from a personal letter from one of our greatest colleagues ”Some problems are better evaded than solved, such as the problem how many angels can dance on the pin of a needle (for instance by denying the existence of angels).“

I shall do justice to Referee B’s remark about ”less efficiency at run time (e.g. unnecessary tests).“. It greatly depends on the question whether we view the fuards of a guarded command set to be evaluated concurrently, something that is entirely permitted. But even when we think of evaluating them sequentially, the expectation value of the number of tests to be performed may be less: compare the published version of Euclid’s Algorithm with x, y:= X, Y; while x ≠ y do if x > y then x:= x - y else y:= y - x fi od .

Referee B’s QUESTION, whether we can confine the do ... od construction to guarded command sets of a single guarded command --that is what his question boils down to-- is answered by ”In principle, yes“. but it could be harmful to the efficiency (see the above example). It would, furthermore, be an arbitrary restriction that would destroy the symmetry between the repetitive and the alternative construct and from which I, therefore, do not expect a simplification.

I shall include a further example --I think computing XY for a binary and a decimal machine-- to put some meat into the assertion of the ability to ”map otherwise (trivially) different programs on the same program text“, in the hope of also meeting Referee A’s general request about-the practical use. (Although I am not sure that I can convince everybody of the ”practical“ significance: norms of practicality tend to be heavily dependent on personal circumstances.)

I regret that only one suggestion has been made to shorten the paper --needless to say: it will be followed-- and thank my referees also for minor remarks as typing errors: your sets of typing errors pointed out to me had an empty intersection! In order to reduce the probability of introducing new typing errors, I shall produce the final version of the manuscript with scissors and paste.

With feelings of gratitude, yours ever signature 22nd January 1975 prof.dr.Edsger W.Dijkstra Plataanstraat S Burroughs Research Fellow NUENEN - 4555 The Netherlands

Post-scriptum d.d. 28th January 1975: EWD418 has been rebuilt into EWD472. Efforts to include other examples have been abandoned as I discovered that they would lengthen the article considerably. I have tried, instead, to formulate explicitly what would be concluded from those examples. The lower half of EWD472 makes one of the advantages of the guarded command set explicit by comparing my version of Euclid’s Algorithm with conventional ways of writing it down. On that same example I could graft some remarks about efficience. The paragraph extending from EWD472 - 12 to EWD472 - 13 gives a further description of why they are useful. As far as contents is concerned I think that the additions are improvements; the English of the new sections seems to run less smoothly, I am sorry to say!

EWD.

EWD 471

Bij de aanvang van het semester.

Gevraagd naar mijn gevoelens over het huidige kabinet zou ik in mij opwellende termen als "rapalje" en "janhagel" wel onderdrukken, maar ik zou toch wel moeten zeggen "onbeschaafd, zeer onbeschaafd". De krant heeft in extenso de rede afgedrukt, die ons aller premier enkele weken terug in Amsterdam heeft gehouden; deze tekst zou moeten dienen als basis voor een verplicht proefwerk Nederlands op alle middelbare scholen: wie het grootste aantal taalen stijlfouten aanstreept, heeft gewonnen. Waarom vertel ik U dit? Wel, omdat het moeilijk is de volgende generatie op te voeden in een land, waar erbarmelijk taalgebruik geen beletsel meer is om premier te worden, maar het haast wel lijkt, of erbarmelijk taalgebruik eer voorwaarde is om tot roem en eer te komen. En dat, terwijl ik U een tak van wiskunde moet doceren, waarvoor exceptioneel goed taalgebruik een vereiste is.

Alsof onze taak daardoor niet al ernstig genoeg bezwaard wordt, grijpt bovendien de overheid hevig in op het Universitaire bestel zelve, daarin gesterkt door de overtuiging, dat het welzijn van "The Great Unwashed" niet beter gediend kan worden dan door de afschaffing van zeep. Ik moet U, die de oorlogsjaren niet meer aan den lijve hebt meegemaakt, L.de Jong's werk over Nederland in die barre tijden ter lezing aanbevelen: U zult daar een voortreffelijke beschrijving vinden van de persoonlijke conflictsituaties, die thans veroorzaakt worden door de WUB, een wet, welke met enig recht helaas als bezettingsmaatregel gekarakteriseerd kan worden.

Het meest benarde evenwel is, dat we in dit gezagsgetrouwe Nederland thans zijn opgezadeld met een regering, die zoveel ideologie in haar beleid doet, en voor het eerst begin ik enig gevoel te krijgen voor de pressie, waaraan intellectuelen aan gene zijde van het ijzeren gordijn blootstaan. Dat is een beangstigende observatie.

Wie laat merken de ideologie van de huidige regering niet te onder- schrijven, maakt zich nl. verdacht. Wie een analogie voelt tussen de ver- vanging van "de leerstoel" van weleer door "de vakgroep" van thans en de vervanging van het huwelijk door de commune, en twijfelt of deze vervangingen verbeteringen zijn, maakt zich een suspect dissident en ieder weet, wat er met dissidenten gebeurt: zij worden geweerd en gebannen. Dat ik geen spookbeelden oproep, blijkt uit de advertenties die bij vacatures voor wetenschappelijke Universitaire functies worden geplaatst. In deze advertenties wordt maar al te vaak zonder blikken of blozen "de bereidheid tot samenwerking" als de meest vanzelfsprekende zaak gevergd. Dat de nieuwe funct onaris niet tegenwerkt, is een redelijk verlangen, maar als hij zijn wetenschappelijke plicht beter als solist denkt na te kunnen komen, wordt dit kennelijk al ervaren als strijdig met het heilig ideaal. Ook heb ik al in meer dan één advertentie gezien, dat van de nieuwe functionaris verlangd werd, dat hij de doelstellingen (!) van de WUB onderschreef. Kortom: hij mag geen dissident zijn, hij mag niet vrezen, wat in zo'n advertentie al uitkomt, nl. dat de zg. democratisering de Democratie ondergraaft.

Dit is een heel ernstige zaak en ik wil —verplicht als ik geacht word tot Uw maatschappelijke vorming bij te dragen— mijn college dan ook niet aanvangen, zonder U hierop te hebben gewezen.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

EWD472

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript

EWD 472: Guarded commands, non-determinacy and formal derivation of programs

was published in Commun. ACM 18(1975), 8: 453-457.

It is reproduced here by permission.

Guarded commands, non-determinacy and formal derivation of programs.

| by Edsger W.Dijkstra *)
*) Author’s address: | BURROUGHS
| Plataanstraat 5
| NUENEN - 4565
| The Netherlands.

Abstract. So-called “guarded commands” are introduced as a building block for alternative and repetitive constructs that allow non-deterministic program components for which at least the activity evoked, but possibly even the final state, is not necessarily uniquely determined by the initial state. For the formal derivation of programs expressed in terms of these constructs, a calculus will be shown.

Keywords. programming languages, sequencing primitives, program semantics, programming language semantics, non-determinacy, case-construction, repetition, termination, correctness roof, derivation of programs, programming methodology.

CR-category: 4.20, 4.22.

Guarded commands, non-determinacv and formal derivation of programs.

1. Introduction.

In section 2, two statements, an alternative construct and a repetitive construct will be introduced, together with an intuitive (mechanistic) definition of their semantics. The basic building block for both of them is the so-called “guarded command”, a statement list prefixed by a boolean expression: only when this boolean expression is initially true, is the statement list eligible for execution. The potential non-determinacy allows us to map otherwise (trivially) different programs on the same program text, a circumstance that seems largely responsible for the fact that now programs can be derived in a more systematic manner then before.

In section 3, after a prelude defining the notation, a formal definition of the semantics of the two constructs will be given, together with two theorems for each of the constructs (without proof).

In section 4, it will be shown, how upon the above a formal calculus for the derivation of programs can be founded. We would like to stress that we do not present “an algorithm” for the derivation of programs: we have used the term “a calculus” for a formal discipline —a set of rules— such that, if applied successfully
1)     it will have derived a correct program
2)     it will tell us that we have reached such a goal. (We use the term as in “integral calculus”.)

2. Two statements made from guarded commands.

If the reader accepts “other statements” as indicating, say, assignment statements and procedure calls, we can give the relevant syntax in BNF [2]. In the following we have extended BNF with the convention that the braces “{...}” should be read as: “followed by zero or more instances of the enclosed”.

< guarded command > ::= < guard > → < guarded list >

< guard > ::= < boolean expression >

< guarded list > ::= < statement > {; < statement >}

< guarded command set > ::= < guarded command > {▯ < guarded command >}

< alternative construct > ::= if < guarded command set > fi

< repetitive construct > ::= do < guarded command set >od

< statement > ::= < alternative construct > | < repetitive construct > | “other statements” .

The semicolons in the guarded list have the usual meaning: when the guarded list is selected for execution its statements will be executed successively in the order from left to right; a guarded list will only be selected for execution in a state such that its guard is true. Note that a guarded command by itself is not a statement: it is a component of a guarded command set from which statements can be constructed. If the guarded command set consists of more than one guarded command, they are mutually separated by the separator “▯” ; our text is then an arbitrarily ordered enumeration of an unordered set, i.e. the order in which the guarded commands of a set appear in our text is semantically irrelevant.

Our syntax gives two ways for constructing a statement out of a guarded command set. The alternative construct is written by enclosing it by the special bracket pair: if ... fi“. If in the initial state none of the guards is true, the program will abort, otherwise an arbitrary guarded list with a true guard will be selected for execution.

Note. If the empty guarded command set were allowed ”if fi“ would be semantically equivalent to ”abort“ . (End of note.)

An example —illustrating the non-determinacy in a very modest fashion— would be the program that for fixed x and y assigns to m the maximum value of x and y :

| if x ≥ y → m:= x
|  | ▯ y ≥ x → m:= y
| fi .

The repetitive construct is written down by enclosing a guarded command set by the special bracket pair do ... od” . Here a state in which none of the guards is true will not lead to abortion but to proper termination; the complementary rule, however, is that it will only terminate in a state in which none of the guards is true: when initially or upon completed execution of a selected guarded list one or more guards are true, a new selection for execution of a guarded list with a true guard will take place, and so on. When the repetitive construct has terminated properly, we know that all its guards are false.

Note. If the empty guarded command set were allowed “do od” would be semantically equivalent to “skip” . (End of note.)

An example —showing the non-determinacy in somewhat greater glory— is the program that assigns to the variables q1, q2, q3 and q4 a permutation of the values Q1, Q2, Q3 and Q4, such that q1 ≤ q2 ≤ q3 ≤ q4 . Using concurrent assignment statements for the sake of convenience, we can program

| q1, q2, q3, q4 := Q1, Q2, Q3, Q4;
| do ql > q2 → ql, q2 := q2, ql
|  | ▯ q2 > q3 → q2, q3 := q3, q2
|  | ▯ q3 > q4 → q3, q4 := q4, q3
| od

To conclude this section we give a program where not only the computation but also the final state is not necessarily uniquely determined. The program should determine k such that for fixed value n (n >0) and a fixed function f(i) defined for O ≤ i < n , k will eventually satisfy:

| 0 ≤ k < n and (∀i: 0 ≤ i < n: f(k) ≥ f(i))

(Eventually k should be the place of at maximum.)

| k:= 0; j:= 1;
| od j ≠ n → if f(j) ≤ f(k) → j:= j + 1
|  |  | ▯ f(j) ≥ f(k) → k:= j; j:= j + 1
|  | fi
| od

Only permissible final states are possible and each permissible final state is possible .

3. Formal definition of the semantics.

3.1. Notational prelude.

In the following sections we shall use the symbols P, Q and R to denote (predicates defining) boolean functions defined on all points of the state space; alternatively we shall refer to them as “conditions”, satisfied by all states for which the boolean function is true. Two special predicates that we denote by the reserved names “T” and “F” play a special role: T denotes the condition that, by definition, is satisfied by all states, F denotes, by definition, the condition that is satisfied by no state at all.

The way in which we use predicates (as a tool for defining sets of initial or final states) for the definition of the semantics of programming language constructs has been directly inspired by Hoare [1], the main difference being that we have tightened things up a bit: while Hoare introduces sufficient pre-conditions such that the mechanisms will not produce the wrong result (but may fail to terminate), we shall introduce necessary and sufficient —i.e. so-ca1led “weakest”— pre-conditions such that the mechanisms are guaranteed to produce the right result.

More specifically: we shall use the notation “wp(S, R)”, where S denotes a statement list and R some condition on the state of the system, to denote the weakest pre-condition for the initial state of the system such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state satisfying the post-condition R . Such a “wp” —which is called “a predicate transformer”, because it associates a pre-condition to any post-condition R — has, by definition, the following properties .

1)     For any S, we have for all states

| wp(S, F) = F

(the so-called “Law of the Excluded Miracle”).
2)     For any S and any two post-conditions, such that for all states

| P ⇒ Q

we have for all states

| wp(S, P) ⇒ wp(S, Q) .

3)     For any S and any two post-conditions P and Q we have for all states

| (wp(S, P) and wp(S, Q)) = wp(S, P and Q).

4)     For any deterministic S and any post-conditions P and Q we have for all states

| (wp(S, P) or wp(S, Q)) = wp(S, P or Q) .

For non-deterministic mechanisms S the equality has “to be replaced by an implication; the resulting formula follows from the second property.

Together with the rules of propositional calculus and the semantic definitions to be given below, the above four properties take over the role of the “rules of inference” as introduced by Hoare [1].

We take the position that we know the semantics of a mechanism S sufficiently well if we know its predicate transformer, i.e. can derive wp(S, R) For any post-condition R.

Note. We consider the semantics of S only defined for those initial states for which has been established a priori that they satisfy wp(S, T), i.e. for which proper termination is guaranteed (even in the face of possibly non-deterministic behaviour); for other initial states we don’t care. By suitably changing S, if necessary, we can always see to it that wp(S, T) is decidable.(End of note.)

Example 1. The semantics of the empty statement, denoted by ’“skip”, are given by the definition that for any post-condition R, we have

| wp(“skip”, R) = R .

Example 2. The semantics of the assignment statement “x:= E” are given by

| wp(“x:= E”, R) = REx

in which REx denotes a copy of the predicate defining R in which each occurence of the variable x is replaced by “(E)”.

Example 3. The semantics of the semicolon “;” as concatenation operator are given by

| wp(“S1; S2”, R) = wp(S1, wp(S2, R)) .

3.2. The alternative construct.

In order to define the semantics of the alternative construct we define two abbreviations. Let “IF” denote

| if b₁ → SL₁ ▯ ... ▯ Bn → SLn fi ;

let “BB” denote

| (∃i: 1 ≤ i ≤ n: Bi) ;

then, by definition

| wp(IF, R) = (BB and (∀i: 1 ≤ i ≤ n: Bi ⇒ wp(SLi, R)) .

(The first term “BB” requires that the alternative construct as such will not lead to abortion on account of all guards false, the second term requires that each guarded list eligible for execution will lead to an acceptable final state.) From this definition we can derive —by simple substitutions—

Theorem 1. From

| (∀i: 1 ≤ i ≤ n: (Q and Bi) ⇒ wp(SLi, R)) for all states

we can conclude that

| (Q and BB) ⇒ wp(IF, R) holds for all states .

Let “t” denote some integer function, defined on the state space, and let “wdec(S, t)” denote the weakest pre-condition such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state such that the value of t is decreased by at least 1 (compared to its initial value). In terms of “wdec” we can formulate the very similar

Theorem 2. From .

| (∀i: 1 ≤ i ≤ n: (Q and Bi) ⇒ wdec(SLi, t)) for all states

we can conlude that

| (Q and BB) ⇒ wdec(IF, t) holds for all states.

Note (which can be skipped at first reading). The relation between “wp” and “wdec” is as follows. For any point X in state space we can regard

| wp(S, t ≤ t0)

as an equation with t0 as the unknown. Let its smallest solution for t0 be tmin(X). (Here we have added the explicit dependence on the state X.) Then tmin(X) can be interpreted as the lowest upper bound for the final value of t if the mechanism S is activated with X as initial state. Then, by definition,

| wdec(S, t) = (tmin(X) ≤ t(X) - 1) = (tmin(X) < t(X)) .

(End of note.)

3.3. The repetitive construct.

As is to be expected, the definition of the repetitive construct

| do b₁ → SL₁ ▯ ... ▯ Bn → SLn od

that we denote by “DO”, is more complicated.

Let | H₀(R) = (R and non BB)
and for k > 0: | Hk(R) = (wp(IF, Hk-1(R)) or H₀(R))

(where “IF” denotes the same guarded command set enclosed by “if fi”) then, by definition

| wp(DO, R) =(∃k: k ≥ 0: Hk(R)) .

(Intuitively, Hk(R) can be interpreted as the weakest pre-condition guaranteeing proper termination after at most k selections of a guarded list, leaving the system in a final state satisfying R .) Via mathematical induction we can prove

Theorem 3. If we have for all states

| (P and BB) ⇒ (wp(IF, P) and wdec(IF, t) and t ≥ 0)

we can conclude that we have for all states

| P ⇒ wp(DO, P and non BB) .

Note that the antecedent of Theorem 3 is of the form of the consequents of Theorems 1 and 2.

Because T is the condition by definition satisfied by all states, wp(S, T) is the weakest pre-condition guaranteeing proper termination for S . This allows us to formulate an alternative theorem about the repetitive construct, viz.

Theorem 4. From

| (P and BB) ⇒ wp(IF, P) for all states,

we can conclude that we have for all states

| (P and wp(DD, T)) ⇒ wp(DO, P and non BB) .

In connection with the above theorems “P” is called “the invariant relation” and “t” is called “the variant function”. Theorems 3 and 4 are easily proved by mathematical induction, with k as the induction variable.

4. Formal derivation of programs.

The formal requirement of our program performing “m:= max(x, y)” —see above— is that for fixed x and y it establishes the relation

R: | (m = x or m = y) and m ≥ x and m ≥ y .

Now the Axiom of Assignment tells us that “m:= x” is the standard way of establishing the truth of “m = x” for fixed x, which is a way of establishing the truth of the first term of R. Will “m:= x” do the job? In order to investigate this, we derive and simplify

| wp(“m:= x”, R) = (x = x or x = y) and x ≥ x and x ≥ y
|  | = x ≥ y .

Taking this weakest pre-condition as its guard, Theorem 1 tell us that

| if x ≥ y → m:= x fi

will produce the correct result if it terminates succesfully. The disadvantage of this program is that BB ≠ T, i.e. it might lead to abortion; weakening BB means looking for alternatives which might introduce new guards. The obvious alternative is the assignment “m:= y” with the guard

| wp(“m:= y”, R) = y ≥ x ;

so thus we are led to our program

| if x ≥ y → m:= x
|  | ▯ y ≥ x → m:= y
| fi

and by this time BB = T and therefore we have solved the problem. (In the mean time we have proved that the maximum of two values is always defined, viz. that R considered as equation for m has always a solution.)

As an example of the deriviation of a repetitive construct we shall derive a program for the greatest common divisor of two positive numbers, i.e. for fixed, positive X and Y we have to establish the final relation

| x = gcd(x, v) .

The formal machinery only gets in motion, once we have chosen our invariant relation and our variant function. The program then gets the structure “establish the relation P to be kept invariant”;

| do “decrease t as long as possible onder invariance
|  | of P” od .

Suppose that we choose for the invariant relation

P: | gcd(X, Y) = gcd(x, y) and x > O and y > 0

a relation that has the advantage of being easily established by

| x:= X; y:= Y .

The most general “something” to be done under invariance of P is of the form

| x, y:= E1, E2

and we are interested in a guard B such that

| (P and B) ⇒ wp(“x, y := E1, E2”, P)
|  | = (gcd(X, Y) = gcd(E1, E2) and E1 >0 and E2 >0) .

Because the guard must be a computable boolean expression and should not contain the computation of gcd(X, Y) —for that was the whole problem!— we must see to it that the expressions E1 and E2 are so chosen. that the first term

| gcd(X, Y) = gcd(E1, E2)

is implied by P, which is true if

| gcd(x, y) = gcd(E1, E2) .

In other words we are invited to massage the value pair (x, y) in such a fashion that their gcd is not changed. Because —and this is the place at which to mobilize our mathematical knowledge about the gcd-function—

| gcd(x, y) = gcd(x - y, y)

a possible guarded list would be

| x:= x - y .

Deriving

| wp(“x:= x - y”, P) = (gcd(X, Y) = gcd(x - y, y) and x - y > 0 and y > 0)

and omitting all terms of the conjunction implied by P we find the guard

| x > y

as far as the invariance of P is concerned. Besides that we must require guaranteed decrease of the variant function t . Let us investigate the consequences of the choice

| t = x + y .

From

| wp(“x:= x - y”, t ≤ t0) =
| wp(“x:= x - y”. x + y ≤ t0) = (x ≤ t0)

we conclude that .

| tmin = x ;

therefore

| wdec(“x:= x - y”, t) = (x < x + y) = (y > 0) .

The requirement of monotonic decrease of t imposes no further restriction of the guard because wdec(“x:= x - y”, t) is fully implied by P and we come at our first effort

| x:= X; y:= Y;
| do x > y → x:= x - y od .

Alas, this single guard is insufficient: from P and non BB we are not allowed to conclude x = gcd(X, Y). In a completely analogous manner, the alternative y:= y - x will require as its guard y > x and our next effort is

| x:= X; y:= Y;
| do x > y → x:= x - y
|  | ▯ y > x → y:= y - x
| od .

Now the job is done, because with this last program non BB = (x = y) and (P and x = y) ⇒ (X = gcd(X, Y) because gdc(x, x) = x .

Note. The choice of t = x +2y and the knowledge of the fact that the gcd is a symmetric function could have led to the program

| x:= X; y:= Y;
| do x > y → x:= x - y
|  | ▯ y > x → x, y:= y, x
| od .

The swap “x, y := y, x” can never destroy P : the guard of the last guarded list is fully caused by the requirement that t is effectively decreased.

In both cases the final game has been to find a large enough set of such guarded lists that BB, the disjunction of their guards, was sufficiently weak: in the case of the alternative construct the purpose is avoiding abortion, in the case of the repetitive construct the goal is getting BB weak enough such that P and non BB is strong enough to imply the desired post-condition R .

It is illuminating to compare our first version of Euclid’s Algorithm with what we would have written down with the traditional clauses;

| x:= X; y:= Y; (version A)
| while x ≠ y do if x > y then x:= x - y else y:= y - x od od

and

| x:= X; y:= Y; (version B)
| while x ≠ y do while x > y do x:= x - y od ;
|  |  | while y > x do y:= y - x od
|  | od

In the fully symmetric version with the guarded commands the algorithm has been reduced to its bare essentials, while the traditional clauses force us to choose between versions A and B (and others), a choice that can only be justified by making assumptions about the time taken for tests and about expectation values for traversal frequencies. (But even taking the time taken for tests into account, it is not clear that we have lost: the average number of necessary tests per assignment ranges with guarded commands from 1 to 2, equals 2 for version A and ranges from 1 to 2.5 for version B. If the guards of a guarded command set are evaluated concurrently —nothing in our semantics excludes that— the new version is time-wise superior to all the others.) The virtues of the case-construction have been extended to repetition as well.

5. Concluding remarks.

The research, the outcome of which is reported in this article, was triggered by the observation that Euclid’s Algorithm could also be regarded as synchronizing the two cyclic processes “do x:= x - y od” and “do y:= y - x od” in such a way that the relation x > 0 and y > 0 would be kept invariantly true. It was only after this observation that we saw that the formal techniques we had already developed for the derivation of the synchronizing conditions that ensure the harmonious co-operation of (cyclic) sequential processes, such as can be identified in the total activity of operating systems, could be transferred lock, stock and barrel to the development of sequential programs as shown in this article. The main difference is that while for sequential programs the situation “all guards false” is a desirable goal —for it means termination of a repetitive construct—, one tries to avoid it in operating systems —for there it means deadlock.

The second reason to pursue these investigations was my personal desire to get a better appreciation, which part of the programming activity can be regarded as a formal routine and which part of it seems to require “invention”. While the design of an alternative construct now seems to be a reasonably straightforward activity, that of a repetitive construct requires what I regard as “the invention” of an invariant relation and a variant function. My presentation of this calculus should, however, not be interpreted as my suggestion that all programs should be developed in this way: it just gives us another handle.

The calculus does, however, explain my preference for the axiomatic definition of programming language semantics via predicate transformers above other definition techniques: the definition via predicate transformers seems to lend itself most readily to being forged into a tool for the goaldirected activity of program composition.

Finally I would like to add a word or two about the potential nondeterminacy. Having worked mainly with hardly self-checking hardware, with which non-reproducing behaviour of user programs is a very strong indication of a machine malfunctioning, I had to overcome a considerable mental resistance, before I found myself willing to consider non-deterministic programs seriously. It is, however, fair to say that I could never have discovered the calculus before having taken that hurdle: the simplicity and elegance of the above would have been destroyed by requiring the derivation of deterministic programs only. Whether non-determinacy is eventually removed mechanically —in order not too mislead the maintenance engineer— or (perhaps only partly) by the programmer himself because, at second thought, he does care —e.g. for reasons of efficiency— which alternative is chosen, is something I leave entirely to the circumstances. In any case we can appreciate the non-deterministic program as a helpful steppingstone.

Acknowledgements.

In the first place my acknowledgements are due to the members of the IFIP Working Group W.G.2.3 on “Programming Methodology”. Besides them, W.H.J.Feijen, D.E.Knuth, M.Rem and C.S.Scholten have been directly helpful in one way or another. I should also thank the various audiences —in Albuquerque (courtesy NSF), in San Diego and Luxembourg (courtesy Burroughs Corporation)— that have played their role of critical sounding board beyond what one is entitled to hope.

[1] Hoare, C.A.R., An Axiomatic Basis for Computer Programming, Comm.ACM 12 (Oct. 1969) 575 - 583.
[2] Naur, Peter, (Ed.) Report on the Algorithmic Language ALGOL 60, Comm.ACM 3 (May 1960) 299 - 314

27th January 1975 | prof.dr.Edsger W.Dijkstra
NUENEN | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWDnnn

On the teaching of programming, i.e. on the teaching of thinking.

It is said that the murderer must return to the place of his crime. I feel myself in the murderer's position, for I found in my files an unfinished manuscript, of some seven years ago, with the ambitious title: "On the organization of one's intellect in scientific research". I quote its first paragraph:

"This is a ridiculous project. It is the kind of project for which one must be slightly drunk, before one dares to undertake it, all the time knowing that one will be sober thrice, before it will have been finished. My only excuse is, that I know its ridiculousness."

Honesty forces me to admit that since the above was written, I have been sober far more than three times and that the manuscript is still as unfinished as I had left it.

*                  *
*

Before starting with the real subject of this talk, viz. the teaching of thinking, I must dwell for a short while at the "i.e." in the title that equates the teaching of programming to the teaching of thinking. We still find the opinion that the teaching of programming boils down to the teaching of programming languages. This misconception is not restricted to the organizers of the vocational training courses in the field and their victims. On many an application for a research fellowship I find the applicatant in his curriculum proudly advertising his fluency in, or at least experience with, a wild variety of instruction codes, programming languages and systems. An organization that in my country claims a central role in the education of programming professionals gives two courses in programming: its introductory course covers FORTRAN and some ALGOL 60, its advanced course deals with .... COBOL! We call such courses "driving lessons". The student's attention is almost entirely absorbed by becoming fully familiar with the ideosyncrasies of the various languages and is made to believe that the more of these ideosyncrasies he understands, the better a programmer he will be. But no one tells him that all those bells and whistles —those so-called "powerful features"— belong more to the problem set than to the solution set. Nobody tells him that at best he will become an expert coder of trivial algorithms, and that his difficulties will never arise from the problem itself, but always from the funny way the (usually given) algorithm has to be coded.

After a number of such courses, the really tough problems are way beyond his mental horizon. His difficulties are not the ones I think worthwhile to discuss, and I shall confine my attention to the difficulties of solving intrinsically hard problems, problems that come only within reach by the time that we use an adequate, elegant mini-language and our vision is no longer blurred by the wealth of mutually conflicting "powerful features" of the more baroque programming languages. Addressing an audience of computing scientists, I assume that I don't need to belabour this point any further: by the time that all knowledge of one's programming language can conveniently be formulated on a single sheet of paper and can be gotten across the limelight in about twenty minutes lecturing, it becomes clear what "programming" really amounts to, viz. designing algorithmic solutions, and that activity requires the ability to think efficiently more than anything else. Hence the "i.e." in my title.

*                  *
*

Talking about "thinking" and, even worse, its teaching is regarded by many as something very ambitious, on the verge of foolishness, a feeling which I shared seven years ago. As the reasons for such a feeling are so obvious, some disclaimers and restrictions of the subject matter seem indicated.

First of all, I am not going to speculate how the brain works, nor am I going to suggest models for it —be they neurological, physiological, philosophical or what have you—. My interest is in using the facility and the fact that some writers of detective stories insist on referring to their hero's "grey matter" has always struck me as confusing and as a symptom of bad taste; for after all, what has its colour to do with it?

Secondly, "thinking" is a word covering such a wild variety of vague activities that we should restrict it for the purpose of our discussion. (It nearly covers non-activity as well, because it is what we are doing when doing nothing while awake!) If I were addressing a PEN-congress I might try to capture aspects of what goes on in my head when I am writing poetry, but I would like to make clear that I am aware of the fact that I am now addressing computing scientists interested in programming and its teaching: my subject is restricted accordingly.

Thirdly, we should not be deterred by the circumstance that "thinking about thinking" has a markedly incestuous flavour, full of hungry snakes that satisfy their appetite by starting at each other's, or even worse: their own, tails for dinner. Unsatisfactory as this may seem to the orderly mind, we should recognise that this world of our understanding is full of such circularities. Surface tension is explained in terms of the properties of molecules, which are explained in terms of properties of atoms, which are explained in terms of electrons and a nucleus, which is explained in terms of protons and neutrons, in the so-called "drop model" held together by some sort of surface tension. But if the circle is long enough, no one notices it and no one needs to bother: each understands his part of the chain.

In order to disguise the incestuous nature of "thinking about thinking" I shall introduce different names for distinguishable thinking activities.

*                  *
*

I intend to use the (hopefully sufficiently descriptive) term "reasoning" for all manipulations that are formalized —or could readily be so— by techniques such as arithmetic, formula manipulation or symbolic logic, etc. These technique have a few common characteristics.

First of all, their application is straightforward in the sense that as soon as it has been decided in sufficient detail, what has to achieved by them, there is no question anymore how to achieve it. And whenever such a technique has been applied, the question whether this has been done correctly is undebatable.

Secondly —and this is not independent of the first characteristic— we know how to teach the techniques: arithmetic is taught at primary school, formula manipulation is taught at the secondary school and symbolic logic is taught at the university.

Thirdly, we are very good at doing modest amounts of reasoning. When large amounts of it are needed, however, we are powerless without mechanical aids. To multiply two two-digit numbers is something we can all do, for the multiplication of two five-digit numbers most of us would prefer the assistance of pencil and paper, the multiplication of two hundred-digit numbers is a task that, even with the aid of pencil and paper, most of use would not care to undertake.

The amount of reasoning that we need when undertaking a non-trivial problem is often our stumbling block and I am therefore tempted to relate the effectiveness with which we have arranged our thoughts to the extent that we have been able to reduce the demands on our reasoning powers. Depending on how we attack a problem —and this is, of course, one of the main points in my whole argument— the amount of reasoning needed may vary a great deal. Before proceeding, I would like to show you one simple example to drive home the message.

On a flat earth with a constant acceleration of gravity a cannon ball is shot away under a given angle and with a given initial velocity. Ignoring air resistance we may ask the question: at what distance from the cannon will the ball hit the ground again?

I have seen more than one professional mathematician solve this problem by deriving —with or without differential equations— the equation of the trajectory and then solving it for x after substitution of 0 for y. Compared to the length of their calculation, "to their amount of reasoning", a relatively simple answer was produced.

I have seen schoolboys derive the same answer in a quite different manner. They were familiar with the first principles of mechanics but had the advantage of knowing nothing about differential equations, nor about analytical geometry and parabolas. The argument is then that, because the horizontal speed vx of the cannon ball is constant (because gravity works vertically) the required answer is

t * vx,

where t is the time that the cannon ball travels. Conservation of energy then requires that the ball that has left the cannon with an upward speed vy returns to the surface of the earth with a downward speed vy, i.e. after a change in vertical speed of 2 * vy. The acceleration g of gravity being given, the amount of time needed for that equals

2 * vy / g .

But that was the time that the ball had travelled, and therefore the required distance is

(2 * vx * vy) / g

And this was the end of their derivation, completed without any computation of the trajectory, the maximum height, etc. (It was typical that all professional mathematicians that produced the latter solution without hesitation had already discovered it in their schooldays!)

Compared with the first solution, the second one is so much simpler that it is worthwhile to try to analyse, how this simplification could be achieved. The first solution uses the parabola that describes the trajectory, i.e. it gives the full connection between the horizontal and the vertical movement. The second solution, however, consists of two isolated arguments, a consideration about the horizontal movenment and a consideration about the vertical movement, the two being connected by what we computer scientists would call "a thin interface", viz. the total travelling time. It is an example of a "modularized" argument; it is apparently characterized by concise modules connected via thin interfaces. (It is worth noticing that in our little cannon ball example the interface was expressed in terms of "time", a concept that hardly occurred in the problem statement! Refusal to introduce this concept or —what amounts to the same thing—: its immediate elimination, leads immediately to the timeless aspects of the problem, to the shape of the trajectory, i.e. to the clumsy first solution.)

I have used the computing term "modularization" intentionally. Too often in the past the justification of "modularization" of a large software project has been that it allowed a number of groups to work in parallel on different parts of the same project. And we also know from sad experience that unless the interfaces are indeed sufficiently thin, communication problems become prohibitively severe and that trying to solve these problems by improving the communication facilities between the groups is fighting the symptoms instead of the cause. Here, however, we see in all its clarity a quite different and more fundamental purpose of modularization, viz. to reduce the total reasoning (irrespective of whether thereafter it will be done by different groups in parallel, or by a single one in succession).

How we choose our "modules" is apparently so critical that we should try and say something about it in general. History can supply us with many illuminating examples, I shall just pick one of them, viz. Galileo's discovery of the laws of the falling body. Since Aristotle, who had observed feathers, leaves and pebbles, heavy bodies fell faster than light ones. It was a first-rate discovery to separate two influences, the pull of gravity and the resistance of the air, and to study the influence of gravity in the hypothetical absence of air resistance, regardless of the fact that, due to the "horror vacui" this absence was not only unrealistic but philosophically unimaginable to the late medieval mind. Galileo could also have chosen the other abstraction, viz. to study the influence of air resistance in the equally unimaginable absence of gravity's pull, but he did not and the reason is quite obvious: he would not have known what to say about it!

The moral of the story is two-fold and, after some consideration, clear. Firstly, whenever an intellectual subuniverse, such as that of Galileo's falling bodies, is created, it is only justified to the extent that you can say something about that subuniverse, about its laws and their consequences. Secondly, the subuniverse must be concise and, therefore, we must have a "thin" interface. Without assumptions, laws or axioms or how you call them, one can say nothing about the subuniverse, so something must be taken into account. But it should be the minimum with the maximum gain, for the more is dragged into the picture, the less concise our reasoning that relies on it: at some stage in the game, some sort of Law of Dimnishing Returns comes into action and that is the moment to stop extending the module of our reasoning.

The relevance of this type of considerations to our own trade of programming I can easily illustrate with an example from my own experience, viz. the introduction of the concept of cooperating sequential processes as a way of coming to grips with the problem of operating system design. It is one thing to decide to try to parcel out what should happen under control of an operating system as what happens under control of a set of cooperating sequential processes. It is quite another thing to decide to regulate their cooperation without any assumptions about their different speed ratios, not even between such processes for which such speed ratios are known well enough. But the decision is easily justified: only by refusing to take such analogue data into account could we restrict our subuniverse to one for which discrete reasoning was sufficient. The gain was two-fold: firstly, our more general considerations were applicable to a wider class of instances, secondly, the simplicity of our subuniverse made the study of phenomena such as deadlock and individual starvation feasible. Furthermore it showed the great benefits that could be derived from the availability of primitives catering for the so-called "mutual exclusion".

The idea of trying to reduce the demands on our reasoning powers is very close to a philosophical principle that since many centuries is known as "Occam's Razor": if two competing hypotheses explain the same phenomenon, the one that embodies the weaker assumptions should be preferred. (And we must assume that William of Occam knew how to compare the relative weaknesses of competing hypotheses.)

Of one thing we should always be aware. Our reasoning powers get strained by a case-analysis in which we have to distinguish between a great number of different cases. When the number of cases to be distinguished between builds up multiplicatively, they get quickly strained beyond endurance and it is almost always a clear indication that we have separated our concerns insufficiently. (From this point of view it is not surprising that many, who have thought, feel that the technique of the so-called "Decision Tables" is self-defeating. In view of their tendency towards exponential growth, the advice to use them seems hardly justified.)

In the mean time we have encountered a very different kind of thinking activity. Besides the reasoning that actually solves the problem, we have the —hopefully preliminary!— thinking that reduces that amount of reasoning. Let us call it "pondering", thereby indicating that, ideally, it is done before the actual reasoning starts. It is, however, intended to include as well the "supervision" during the reasoning, the on-going "efficiency control".

The ability to "ponder" successfully is absolutely vital. When we encouter a "brilliant, elegant solution", it strikes us, because the argument, in its austere simplicity, is so shatteringly convincing. And don't think that such a vein of gold was struck by pure luck: the man that found the conclusive argument was someone who knew how to ponder well.

Reasoning, we know, can be taught. Can we also teach "pondering"? We certainly can teach pondering, as long as we do not flatter ourselves with the hope, that all our students will also learn it. But this should not deter us, for in that respect "pondering" is no different from the subject "reasoning", for also for the latter subject holds that some students will never learn it.

Among mathematicians I have encountered much skepticism about the teachability of pondering, but the more I see of the background of that skepticism, the less discouraging it becomes. Sometimes the skepticism is no more than expressing the justified doubt, whether anyone can learn how to ponder well, but as just stated, that need not deter us: let us focus our attention on that part of the population that could learn how to ponder provided that they are taught how to ponder. I see no reason why that part of the population should be empty. Sometimes the skepticism is the result of the inability to form a mental picture of how such pondering lessons would look like, but that inability should not deter us either, for it is so easily explained. Today's mathematical culture suffers from a style of publication, in which the results and the reasoning justifying them are published quite explicitly but in which all the pondering is rigorously suppressed, as if the need to ponder were a vulgar infirmity about which we don't talk in civilized company. (And if the author has not already suppressed it, there is a fair chance that the editor will do so for him!) In the nineteenth century —read Euler, who quite openly and apparently with great delight mentioned all his hunches with what is now a surprising frankness!— we did not suffer from such a cramped style. And as a result of this fashion to regard explicit reference to one's pondering as "unscientific", many contemporary mathematicians even lack the vocabulary in which they could describe it and this lack makes them very unconscious about their own methology. Their way of pondering being unknown to themselves, it becomes something "unknowable" and highly personal, it becomes regarded as a gift with which someone must be "born". And here we find the third source of skepticism: the mere suggestion that pondering could be taught is experienced as a threat upon their ego.

To those who have never tried to visualize how lectures in pondering could look like and, therefore, doubt their feasibility, I can only give one advice. Suppose that you stop teaching results and solutions, but start to solve problems in the lecture room and that you try to be as explicit as possible about your own pondering. What will happen? The need to get some sort of verbal grip on your own pondering will by sheer necessity present your ponderings as something in which, as time progresses, patterns will become distinguishable. But once you have established a language in which to do your own pondering, in which to plan and to supervise your reasoning, you have presented a tool that your students could use as well, for the planning and supervision of their reasoning. In all probability it will have your own personal flavour —I hope that it will, I am tempted to add— but this does by no means exclude that it won't help some of your students: you would not be the first to found a school of thought! They will learn in your way never to embark unnoticed on an extensive new line of reasoning; then they will learn in your way never to do so without a prior evaluation of the chance of simplification versus the chance of further complication, etc. And, eventually, when they grow up, they will learn to ponder in their own way, although the traces of your teaching will probably remain visible all though their lives.

*                     *
*

In the above I have presented "pondering" as an optimization problem, viz. how to get the maximum result out of the minimum amount of reasoning. In doing so I followed a quite respectable tradition that presents certain forms of "laziness" as an indispensable mathematical virtue. This may surprise all those who know my profound distrust regarding the simplifications that underly the "Homo Economicus" as a picture of Man, a picture in which the self-sacrifying person (if admitted as a human being at all!) is classified as a non-interesting fool. To correct a wrong impression I may have made, let me quantify my considerations. If you would like to think effectively (because you like doing so), then you had better try to become an expert at it! But, if you would prefer to dream (because you like having beautiful dreams), then you had better become an expert at dreaming! (Remarks to which we can add, that the two facilities do not exclude each other.)

There is a third, indispensable mental activity which, for lack of a better name, I indicate with "revolting". This is what has to take place when, no matter what we try, our maximized output remains nil, i.e., when we are stuck in an impossible task. The only effective reactions are either to change the problem until it becomes managable, or to throw it away and to turn to something else. Obvious as this may seem, I must mention it explicitly, because experience has shown that these are difficult decisions to consider, and that, therefore, we must teach the courage to revolt.

The decision is always difficult because it has the connotation of failure —usually without justification, for most tasks are impossible anyhow—, it is, however, particularly difficult if the impossibility of the task is politically impalatable to the society of which one is a member. In serious cases the victim who has embarked on a popular, but impossible task, can hardly afford to admit even to himself its impossibility and the resulting inner conflicts may form a serious threat to one's integrity, one's health and one's sanity. For those who doubt their courage to revolt, it seems a safe precaution to stay away from popular projects, particularly if they work in an intolerant environment. For those who have learned to revolt well, the act is always one of liberation: it is an ability shared by most innovators of science.

13th February 1975 NUENEN | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Arnout Engelen
revised Mon, 3 Sep 2007

EWD474

Trip report visit ETH Zurich, 3 - 4 February 1975 by E.W.Dijkstra.

Invited by Niklaus Wirth I gave three lectures at the Eidgenössische Technische Hochschule Zurich. The first one (Monday 16.00-18.00) was reasonably successful, the second one (Tuesday 11.00-12.00) was bad —at the end I lost my way in a trivial proof and had to give up—, the last one (Tuesday 14.15-16.00) went perfectly. For some reason I was very tense: I have, for instance, completely forgotten to open each lecture (as usual) with a quotation! I also forgot the first day to invite "interrupting questions". Niklaus suggested that at my second talk I should give the audience some "homework" for the break at lunch. I did so, but at the beginning of the second talk instead of at its end: one question was so intriguing that more than one member of the audience tried to solve the problem during the lecture.

My trip from Eindhoven (dep. 9.08) to Zurich (arr. 18.14) was most comfortable. I had to change twice (Köln and Basel), but as all trains kept perfect time and I travelled light, this was no problem at all. It was my intention to prepare the lectures during the journey, but that was not entirely successful: my thoughts wandered away and I ended up reading in "Mathematics in Western Culture", a book that I can highly recommend (in spite of the sad foreword by R.Courant, that refers to today's "anti-mathematical fashion in education".). It has been written by Morris Kline. I find such accounts of the birth of new sciences very instructive and inspiring: the analogy with what happens in computing science is sometimes quite close.

Niklaus picked me up at the Zurich railway station and took me to his house where I slept the next two nights. Sunday evening he had some family over from various parts of the world, and not counting Dutch, four languages were spoken at the dinner table. (At the end of the dinner I addressed their oldest daughter upon her request in Dutch: it was truly a multi-lingual dinner!) The next evening, after dinner we —i.e. Niklaus's wife and children and I— gave a small "house concert" (piano, recorder, ukelele, clarina and vox humana) and I found it touching to observe the earnest devotion of the young performers. Later that evening Niklaus and I were joined by Gene Golub —the numerical mathematician who is now at Stanford— and an American statistica called "Grace"—I am sorry that I do not remember her full name, for she contributed a fair share to an enjoyable evening— who now came from Oxford and was on her way to Rehovot, Israel. The last evening —knowing that I wanted to sleep on the night train— I drank more freely. As a result I slept very well, but I am afraid that when I was woken up at 5.15., so that I could leave the sleeper at Köln at six o'clock in the morning, I did not feel too happy. (Whether I would have felt any better without the alcohol of the previous night is, of course, an open question!) At 9.04 I arrived in Eindhoven, where my wife was with the car to pick me up.

I had two unexpected, but pleasant encounters. The one was with Dana Scott, who happened to pass his sabbatical leave at the ETH Zurich. On Sunday evening Niklaus gave me a 15-page letter from Scott, which I studied before I went to bed and discussed with Scott the next afternoon, during the hours before my first performance. The other was that, after I had spoken a few minutes, I suddenly discovered Robert Fano in my audience (he was the director of Project MAC at the time that I was guest-professor at MIT); he happened to pass his sabbatical year at the IBM Laboratory in Zurich. It was a pleasure to meet him again.

The remaining time I have talked with Niklaus, his colleagues and assistants, mainly about their work and their ideas. I observed a consensus that skepticism about automatic program composition is as justified as skepticism about automatic theorem provers. (As I have always stayed far away from these subjects, I have to rely upon opinions and expectations of those with more experience or better insight in the field.) I was shown a very nicely decomposed "message switching system" designed for a "terminal": in particular the high degree of isolation of hardware-dependent parts was impressive. It had been implemented for a Hewlett-Packard machine, and a few PDP-machines were the next candidates. To write the system —i.e. nearly all of it— in an extended version of PASCAL and then performing a "hand translation" is, indeed, the most sensible approach.

We also talked about the teaching of programming and the position and role of computer science. My strong impression is that the way in which the mathematical department in Chicago first absorbed and then strangled computing science —Golub told the story— is not an isolated case: such things are in danger of occurring at more places, universities and journals. Apparently it has happened already with Acta Informatica; Niklaus expressed himself very strongly (like Turski did in November), viz. that Acta Informatica is now doomed beyond salvation. The mathematicians immediately restrict and extend the subject to what they see in it. I may write a letter to the Editor, Niegel, but it won't help much, for we know his answer: he will explain the situation by saying that such are the papers he receives (and we all believe that, for they are so much easier to write!)

The other threat comes from organized user groups, that prefer complete stagnation ("the physicist's FORTRAN"). Upon closer scrutiny, their arguments are alarming. The argument for standardization is the exchange of their expensive programs, but that means that they exchange the bugs as well. (And it is somebody's law that, the more expensive a program, the greater the number of bugs.) In the old days, physicists used to repeat each other's experiments, just to be sure. Now they repeat each other's mistakes, fully automated repetition! The only justification for exchange, for sharing, is the ultra-high quality of the shared object, but now they insist upon sharing because it was expensive to make, although it is almost certainly expensive junk. On account of their desire to share, they should welcome all improvements that could raise the quality of the shared object, but they resist all change with the fallacious argument that they cannot afford to do so. I sometimes smell also the unwillingness to admit that their professional responsibility extends itself over the quality of their "vital" programs. It is frightening: here we have a mechanism that could easily kill a science on a world-wide scale! The only respectable answer of computing science is never to yield to the pressure.

In one respect I found the intellectual climate a little bit "sticky"; I do not know whether this is characteristic for the ETH Zurich or whether it is a Swiss national trait to be "solid" first and only "adventurous" as far as then allowed (and that is not very far). Part of my talk dealt with guarded commands. Now, for anyone with some understanding, it is clear that as sequencing tools they are much more attractive to use than the traditional while-do and if-then-else and if, fifteen years ago, someone had thought of them, while-do and if-then-else would perhaps never have become established the way they are now. While at other places —Albuquerque and Toronto, for instance— it sufficed to show the difference, I felt this time more or less pressed to quantify the improvement, to demonstrate that "the improvement justified the change". I am not preaching irresponsibility, but the danger of such a climate is, of course, that you lose the ability of having day-dreams, just for fear that you can never turn them into reality. In view of this "stick-to-what-you-have" attitude it is a marvel that Niklaus managed to get PASCAL implemented at all! (The design of PASCAL itself has, of course, been heavily influenced by the local facilities and political situation. But, how else could it be?) It is, in view of the prevailing attitude of "clinging to the soil" remarkable, how the computing science there has managed to remain relatively unaffected by the awful properties of the CDC-machine they have to use. They have probably been saved by knowing its flaws very well; usually the obligation to use a poor machine ruins a computing science department. They have survived!

10th February 1975 NUENEN | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

P.S. The problem that intrigued parts of my audience was the following. Consider for X > 0 and Y > 0 the following program part:

x:= X; y:= Y; u:= Y; v:= X;
do x > y → x := x - y; v := v + u
  [] y > x → y := y - x; u := u + v
od;
print((x + y)/2); print((u + v)/2)

The knowledge of Euclid's algorithms suffices to see that the first number printed is gcd(X, Y); the question was to discover the functional dependance of the second number printed on X and Y and to prove it. (It is, of course, the type of "inverted question" that I detest, but letting prople struggle with it makes them more receptive for the beauty and the power of the invariance theorem.)

transcribed by Reynir Heîberg Stefánsson
revised Thu, 13 Aug 2009

Copyright Notice

The following manuscript

EWD 475: A letter to my old friend Jonathan

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 99–103 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 475

A letter to my old friend Jonathan.

My dear Jonathan,

After so many years of silence, you will be surprised to receive such a long letter from me. But, read on, and you will understand that this time I must address myself to a lawyer I can trust and of whom I know that he understands.

Remember our schooldays, when we argued about the relative merits of the Greek and the Roman culture? How I defended the Greeks by quoting Plato and you the Romans by quoting Cicero, and how the unsettled question did not impair the friendship and companionship between the two of us? (Happy youths, who could argue hotly about the relative superiority of classical cultures, whereas, today, the inferiority of contemporary civilization seems to be the only common meeting ground!) Our fates were decided that evening by the choice of our heroes: you chose law and I chose mathematics and our ways parted. (It is a strange thought that, if in that same discussion, I had chosen Homer and you Horatius, we might both have become professional poets and our paths might have continued to cross each other....)

Dear Jonathan, I am in a fix. I leave it to your great wisdom or to your worldly experience to decide for yourself, whether my problem is that I don’t understand them, or whether they are so short-sighted that they are unable to understand me. But the long and the short of it is that I am in a fix, I have painted myself into a corner to the extent that I need legal advice, imagine! As you know —Hugo has certainly told you something about it— I am presently responsible for Mathematics Inc., the most exciting and most miserable business ever conceived. It is really most exciting, because —beside being a most flourishing business (and that is saying a good deal, these days)— by blending the strength of Greek contemplation with that of Roman enterprise, we are changing the face of the world! Our problem is, however, that apparently the world is not quite ready for this (truly!) “Cultural Revolution” and is beginning to fight back in a most unartistic manner, just because it —and in particular: its legal procedures!— cannot cope with it. There are legal procedures for the protection of property of “things”, but there is no true protection of property of “ideas”, and of such nature are the products of Mathematics Inc. (There are, of course, patent law and copy-right, but as you read on, you, as a lawyer, will immediately see that in our cases they are insufficient.)

One of our most successful product lines is connected with what used to be known as the Riemann Hypothesis, but now should be named our Theorem. To bring you into the picture, Riemann —originally trained to become a Lutheran minister!— was one of those romantic mathematicians of the nineteenth century, who maintained his fame by dying young enough to ensure that nobody saw that he himself was also unable to prove his conjecture. Riemann completely missed the vision and imagination, needed to escape from the prejudices of the pre-industrial society and, according to the tradition of the period, he fought his problem single-minded: the amateur, needless to say, failed miserably.

To supply the missing proof was for Mathematics Inc. an obvious target, not only because we have built up the first (and only) corporation in the world, that is technically capable of constructing such a proof, but also, because commercially it is a most attractive proposition. The point is that whole flocks of mathematicians have made themselves dependent on it and have (somewhat irresponsibly) based whole branches of mathematics on Riemann’s assumption. Think what a market! All those dangling results, ready to be harvested by the first company that provides the missing link! We have provided the link and, having the Proof, besides claiming all previous results based on Riemann’s Hypothesis, we insist on substantial royalties for all future use of it. That is fair, isn’t it? You cannot expect a huge company like Mathematics Inc. to distribute its goodies like Father Xmas, can you? But, reasonable as our claims are, we experience the greatest difficulties in getting our rights recognized.

As most royalties would come from abroad, our own government —with an eye on the balance of payments— is in principle eager to assist us and to support our foreign claims, but, Good Heavens!, it is incredible how it paralyzes itself (to the point of complete ineffectiveness) by insisting upon all sorts of clearly inadequate, inappropriate and impossible legal procedures. I have now received three letters from three different departments (Science and Education, Commerce and Foreign Affairs), all of them stating that according to (different!) articles so-and-so they can do nothing for us before we have shown our Proof! What do they think? For, as they also explain, this disclosures does not guarantee that they can do anything real for us, oh no, only after the disclosure they can start the investigations whether our claims can be supported! Knowing how our departments work, my heart sinks, for it would take at least another five years!

But, besides this, disclosure of the Proof is absolutely out of the question! Has no one heard of industrial property? You see, we want to sell the result of the Proof —viz. that Riemann’s Hypothesis is no longer a hypothesis but a truth—, but certainly not disclose the Proof itself, for that embodies a radically new technique of mathematical reasoning that, as long as it is ours and exclusively ours, we would like to apply to a few similar outstanding problems. Disclosure of the Proof would be similar to the disclosure of “manufacturing secrets” of classical industries. How can we make them understand this situation?

(There is another reason —but this is strictly between you and me— why I do not care too much about disclosure of the Proof right now, because the Proof, although essentially correct, is still in the prototype stage: minor deficiencies —of which we know, that they are easily mended: it has already all been planned— could be misused to weaken our claims. My marketing division has made quite clear that, as far as they are concerned, disclosure has to be postponed until the Proof has reached such a state of stability that it won’t require significant maintenance for the first five years after delivery.)

Another serious problem —in view of the huge amounts of money involved— is connected with exportation within the European Community, viz. how to compute the Value Added tax to be paid, when we sell the Proof. As you, no doubt, are aware of, the rules don’t provide for it, as we cannot define our “raw materials”: are they the symbols we use, or the Laws of Aristotelean Logic? (Here, I am sorry to say, I expect from my government an even less cooperative attitude!)

*         *         *

Thank goodness we don’t have only serious problems, but ridiculous ones as well. Before we could get the top twelve floors of the Hosanna Building, I had (to humour the old gentleman who owned half of them) to order from an architect a Toilet Flushing Water Recycling System —I have included a copy of his design—. As the old gentleman died, he did not need any humouring anymore and we decided not to implement the TFWR System, although brilliantly designed, in view of the risks involved. But now the architect complains, even after having received his fee. His argument is that he is entitled to have his ideas realized. He points out that if all his customers would act as we have done, he would end his days with lots of money, received but not earned, and none of his brain-children to survive him. He is now threatening to sue us for wasting his creative powers. I am afraid he is an uncurable artist. (Don’t worry, our regular lawyer will deal with him in the usual way.)

*         *         *

Dear Jonathan, one of these days I shall ask my secretary to make an appointment for an afternoon. Can we have a dinner afterwards? (I suggest the Restaurant “Bali”: it adds to an excellent kitchen the advantage of the proximity of a cafeteria where my chauffeur can have some food while we are having dinner.) I would like to discuss with someone like you the current mis-education provided by our Universities. Today’s graduates leave the campus made to believe that it is Knowledge that matters, while all of us know that only Secrets matter. If all goes well, I could endow the major Universities with an appropriate chair. How should I call it? “The Edsger W.Dijkstra Chair of Industrial Espionage” or “The Mathematics Inc. Chair of Security and Privacy”? I shall ask my P.R.-man, anyhow, but would appreciate your unbiased opinion.

I am very much looking forward to meeting you again. Till then!

Yours ever

9th February 1975 | Edsger W.Dijkstra Mathematics Inc. Hosanna Building

transcribed by Corrado Cantelmi
revised 04-Dec-2011

EWD476

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

14th February 1975

Concurrent programming: a preliminary investigation.

(Instead of the usual term “parallelism” I prefer the term “concurrency”: parallelism is a term that I would like to reserve for a number of rather identical components, progressing “in parallel”, i.e. in rather strict synchronism. The term “concurrency” only refers to the (possibility of) simultaneous activity.)

I observe that rather operational approaches to the problem of defining the semantics of programming languages encounter problems when it is tried to extend them to “concurrent programming languages”. The way in which the problem manifests itself is that a set of sequential processes —all by themselves well-understood— are allowed to operate in a common memory (at some grain of interleaving) and that then the non-determinacy is investigated that is generated by this uncontrolled interleaving. This form of non-determinacy is —not surprisingly— rather hard to cope with.

What I have done in the past year suggests a rather different attack. In that year I have introduced —not necessarily deterministic— programs by regarding them as (codes for) predicate transformers. During that stage it is totally irrelevant that the program can also be interpreted as executable code for a sequential machine (that is only a pleasant surprise when we try to implement the programming language the next day). Because initial and final states are by definition connected by a predicate transformer (and only tomorrow, when we consider implementations, by a long chain of intermediate states) nothing in my language is “sequential” as long as I do not drag implementations into the picture. The result is that I do not truly understand anymore what is meant by the usual phrase “parallel programming languages”, and that I see only one feasible way of attacking the problem: designing a programming language in my usual way, and then observing (tomorrow) that an implementation with a lot of concurrency is possible. (The language design may silently be motivated by that possibility, but that should not confuse us today, when neither implementation, and a fortiori “time” nor “concurrency” play any role at all.) It is fairly obvious that our programming language should be non-deterministic, but that need not frighten me anymore: it is, after all, now more than a year ago that I decided to regard non-determinacy as the rule and determinacy as a —not very interesting— special case. This report —of which I hope that it will be followed by others on the same topic— is only a preliminary survey. (My intention to introduce the possibility of concurrency dates —according to my notes— back to January 1973, but non-determinacy had to be catered for first —-fall 1973—. A new incentive to take up this investigation I received at the IBM-Seminar at Newcastle in September 1974, but I wanted to finish my book first.)

The reversal of an algorithm.

This section records an observation that we made in the fall of 1974 —while we were playing with little programs— an observation to which we did not pay much attention at the time (it was not even recorded). The other week, when making programs fit for concurrent execution, we were suddenly reminded of it .

Our example dealt with a recognizer for the following syntax:

| < sentence > ::= < expression > ;
| < expression > ::= < primary > {< operator > < primary >}
| < primary > ::= < digit > {< digit >} | (< expression >)

where the braces are to be read as “followed by zero or more instances of the enclosed”.

We assume that our recognizer finds the characters of the text in an array variable “in”, where “in.low” is the currently “lowest” element —i.e. the one with the lowest index value— and the operation “in:lorem” removes from “in” this lowest element. (We have separated the reading of the next symbol and the moving of the tape.) The call “sent” will do the recognition —i.e. if “in” does not begin with a sentence, the program will abort— if we assume the self-explanatory boolean procedures “issemi”, “isopen”, “isclose”, “isop” and “isdigit” with a symbol as argument available.

proc sent: exp; if issemi(in.low) → in:lorem fi corp;
proc exp: prim; do isop(in.low) → in:lorem; prim od corp;
proc prim: if isdigit(in.low) → in:lorem; do isdigit(in.low) → in:lorem od
|  | ▯ isopen(in.1ow) → in:lorem; exp;
|  |  | if isclose(in.low) → in.lorem fi
| fi corp .

Here, sent , exp and prim try to remove from the low end of “in” the largest < sentence >, < expression > and < primary > respectively that they can find. If they cannot do so (because in.low is inacceptable) they abort. Note, that there are only three reasons for abortion: a missing semicolon where it is needed (e.g. on the text “123(....”) in sent, a missing digit or open parenthesis (e.g. on the text “123+)....”) in prim, or a missing closing parenthesis were it is needed (e.g. “(123(...”) in prim as well.

The observation we made that the generator of an arbitrary < sentence > —we take the liberty of not bothering about termination— can be derived from the recognizer in a straightforward manner. (The operations “out:hiext” add symbols at the high end of the array variable “out”, which is initially assumed to be empty.)

proc sent: exp; out:hiext(semi) corp;
proc exp: prim; do ?? → out:hiext(op); prim od corp;
proc prim: if true → out:hiext(digit); do ?? → out:hiext(digit) od
|  | ▯ true → out:hiext(open); exp;
|  |  | out:hiext(close)
| fi corp .

(Here do ?? → S od means “zero or more times S”, i.e. it is short for something like

| goon := true;
| do goon → S ▯ goon - goon:= false od .

This notation with questionmarks has been introduced here for convenience, and also with the intention of presenting recognizer and generator with exactly the same layout.) The transformation from generator to recognizer is equally obvious.

We liked the transformations and said to each other “That is nice, isn’t it?”, in my short enthousiasm I showed it twice to a colleague, and then we turned to other matters. At that moment we had clearly other interests, for none of us remarked that the output of such a generator could be fed directly as input into a concurrent recognizer.

*              *
*

Buffering mosquitos.

A configuration that I would like to study at some state of the game is a so-called “elephant built from mosquitos”. Mosquitos are little machines and they have a few connections —“legs”— and an input-leg of one mosquito is paired to the output-leg of another mostquito. When one mosquito transfers information to another one, I shall use in the description of both mosquitos the same name for the connection: if a sending mosquito transmits via leg A the current value of its local variable x , we shall denote this in its text by “A:= x” ; in the description of the receiving mosquito that assigns the transmitted value to its local variable y , reception will be indicated by “y:= A” and for the time being we shall assume that some magic sees to it that these two statements are executed simultaneously, i.e. legs are not supposed to contain memory elements.

A one-place buffer is easily coded as a mosquito: let it have one input leg, A say, and one output leg, B say; then its text can be:

| do true → x:= A; B:= x od .

This is a fully deterministic mosquito: after the one-place buffer has been filled, we can only empty it and vice versa.

More interesting is a mosquito buffering (FIFO) a maximum of, say, 20 values. Suppose that it has a classical array with twenty elements from buf(0) through buf(l9) . In its simplest form —and too naive— we can code it (with “f” for “filling” and “e” for “emptying”)

| f, e := 0, 0;
| do true → buf:(f)= A; f:= (f + 1) mod 20;
|  | ▯ true → B:= buf(e); e:= (e + 1) mod 20
| od .

But this is very naive, even if we assume that the selection of alternatives is dependent on whether the environment is ready to offer via A and/or to accept via B a next value. We are making rather strong assumptions about the decency of that environment and it seems nicer to make the mosquito itself control its capacity and contents, i.e.

let nf be the number of values accepted via A
let ne be the number of values delivered via B
then the values accepted but not yet delivered should be stored (in order of age) as the values buf(e) through buf((e + nf - ne -1)mod 20) and the mosquito itself should maintain

P: | 0 ≤ nf - ne ≤ 20 which leads to the program

| f, e := 0, 0; nf, ne := 0, 0;
| do nf - ne < 20 → buf:(f)= A; f:= (f + 1) mod 20; nf:= nf + 1
|  | ▯ nf - ne > 0 → B:= buf(e); e:= (e + 1) mod 20; ne:= ne + 1
| od .

We leave to the reader the exercise to convince himself that the following program will do the job as well, provided K ≥ 21:

| f, e := 0, 0; n1, n2 := 0, 0;
| do (n1 - n2) mod K < 20 → buf:(f)= A; f:= (f + 1) mod 20; n1:= (n1 + 1) mod K
|  | ▯ (n1 - n2) mod K > 0 → B:= buf(e); e:= (e + 1) mod 20; n2:= (n2 + 1) mod K
| od .

(The easiest way to do this seems to maintain first the statements operating on nf or ne and then to prove the invariance of P.)

I would like to make the following remarks about the above programs.
Remark 1. I have not bothered about “termination” but that is so easily fixed that I feel entitled to allow myself the convenience.(End of remark 1.)
Remark 2. From a time-less point of view, the FIFO buffer is strictly deterministic: the output stream equals the input stream. It is only when we consider the sequence of consumptions via A and production via B , that the non-determinism shows itself. When we consider this program as working in a fully cooperative environment —i.e. willing to produce via A and to accept via B when our mosquito feels like it— the non-determinism of the sequential program displays the complete freedom we envisage (with the possibly meaningless exception that as long as we regard the above executed by a strictly sequential machine, production and consumption will never take place simultaneously.) (End of remark 2.)
Remark 3. Very little prohibits “concurrent execution” of both alternatives. We must make the assumption that “buf:(f)= A” and “B:= buf(e)” will not interfere with each other when tried concurrently, but with e ≠ f . We must further make the assumption that programs dealing with different variables can be executed concurrently. The only possible form of interference is via the n’s, but with respect to these, our programs have a very special property. If —sequentially interpreted— the one alternative is selected while the other guard is true, the other guard remains true. And that, of course, implies that we can implement the whole game as two cyclic processes which may be detained during their stream-operations when the environment is not ready and must be detained when the guard is found to be false. (End of remark 3.)
Remark 4. These programs have an even stronger property, but it seems too special perhaps, to make much use of it here: the execution of one alternative is guaranteed to make the other guard true. This means that the one process evaluating (n1- n2)mod K need not even read either the old or the new value of an n with which the other process fools: the evaluation of the guard may be supplied with a rubbish value, a mixture: the only result can be that erroneously the value “false” is evaluated, but then we can say “better luck next time”. In this special case we don’t even need the mutual exclusion usually provided by a switch. The remark is of significance if we wish to abolish daemons that cater for mutual exclusion in unsynchronized self-stabilizing systems, I think we can drop it here.(End of remark 4.)

Experiments with a sorting elephant.

We consider a long string of mosquitos with between each pair of neighbours a connection L for traffic to the left and a connection R for traffic to the right. The terminology is at first sight perhaps confusing, because now each mosquito has two legs, both called L, but it will turn out to be convenient: in mosquito nr. i

| L:=.... means sending to nr. i-1
| ....:= L means accepting from nr. i+1
| R:=.... means sending to nr. i+1
| ....:= R means accepting from nr. i-1 .

Our simplest elephant consists of as many (plus 1 or 2) mosquitos as numbers have to be sorted. We distinguish even and odd mosquitos alternating in the string and do not bother about the fact that the terminal mosquitos have to be slightly different, nor do we bother for the time being about termination.

Initially the even mosquitos contain two numbers, while the odd mosquitos start empty. The even mosquito sorts its contents, sends the smalles value to the left, the largest to the right and then waits (empty) until it has received from both its neighbours a number back and repetatur. The odd mosquito waits until it has received a number from both sides, sorts them and send the smallest to the left and the largest to the right and repetatur.

Let each even mosquito have two variables x and y (for the communication with its lefthand and righthand neighbour respectively). Its repertoire of actions consists of

A: | do x > y → x, y:= y, x od (sorting)
B: | L:= x (sending to the left)
C: | x:= R (receiving from the left)
D: | R:y (sending to the right)
E: | y:= L (receiving from the right)

The logically necessary precedence relations can be pictured in the following graph

                  /→ B -→ C\
        entry -→ A          →A   etc.
                  \→ D -→ E/

and the question is, how to represent them. One way of doing this is with a boolean for each arrow:

| ca:= true; ea:= true; ab:= false; bc:= false; ad:= false; de:= false;
| do ca and ea → A; ca:= false; ea:= false; ab:= true; ad:= true
|  | ▯ ab → B; ab:= false; bc:= true
|  | ▯ be → C; bc:= false; ca:= true
|  | ▯ ad → D; ad:= false; de:= true
|  | ▯ de → E; de:= false; ea:= true
| od .

But, although perfectly general, this notation does not attract me very much: it is worse than jumps. Another experiment has been (with “dop” for “do permanently”)

| dop A; par [B]; [E]
| ▯ [D]: [E] rap pod

where the squate brackets denote the unit of interleaving, and the par - rap are a sort of parbegin and parend. But this turned out to be a dead alley. (As we shall see shortly, it is awkward for the description of the odd mosquitos.)

I am now mostly attracted —perhaps because it is so new, that I have not seen its shortcomings yet— by the following notation

| dop ![A]; [B]; [C]
|  | ▯ ![A]; [D]; [E]
| pod

where we have two cyclic processes, and the exclamation mark indicates “mutual coincidence”, i.e. the two loops must “share” the single point event A each time, The odd mosquitos can be described similarly: each odd mosquito has two variables u and v , its repertoir consists of

F: | do u > v → u, v := v, u od
G: | L:= u
H: | u:= R
J: | R:= v
K: | v:= L

and its program is

| dop [H]; ![F]; [G]
|  | ▯ [K]; ![F]; [J]
| pod .

The charm of the above notation is that we can now combine an even mosquito with its righthand neighbour into a single one, by eliminating the internal traffic, by identifying H(u:= R) and D(R:= y) with

IR: | u:= y (“IR” for Internal to the Right)

and by identifying E(y:= L) and G(L:= u) with

IL: | y:= u

and the formal combination becomes the following program

| dop ![A]; [B]; [C]
|  | ▯ ![A]; ![IR]; ![IL]
|  | ▯ ![IR]; ![F]; ![IL]
|  | ▯ [K]; ![F]; [J]
| pod

The next observation is that without any change in its semantics, the middle two lines can be combined:

| dop ![A]; [B]; [C]
|  | ▯ ![A]; [IR]; ![F]; [IL]
|  | ▯ [K]; ![F]; [J]
| pod

The last observation is that, now the alternation of A and F has been nicely expressed by the middle line, that u and y can be the same variable, and that IR and IL disappear, i.e. with

A: | do x > y → x, y := y, x od
F: | do y > v → y, v := v, y od

the combined mosquito becomes, when all is filled in

| dop ![A]; [L:= x]; [x:= R]
|  | ▯ ![A]; ![F];
|  | ▯ [v:= L]; ![F]; [R:= v]
| pod

The above nicely describes the endless graph with the precedence relations

      A\-> B -> C ->/A\-> B -> C ->/ 
        -→   -----→   -→   ------→            etc.
      K ->\F/-> J -> K ->\F/-> J ->   

Merging two successive mosquitos of the above type leads to

| dop ![A]; [L:= x]; [x:= R]
|  | ▯ ![A]; ![F]
|  | ▯ ![A’]: ![F]
|  | ▯ ![A’]; ![F’]
|  | ▯ [v’:= L]; ![F’]; [R:= v’]
| pod

Here the primed items refer to the righthand side component. Drawing the beginning of the endless graph with the precedence relations, as I did for the previous mosquito, is an exercise that I leave to my readers. It is quite instructive and gives some idea of the power of this notation. (That very power may also be its greatest weakness, but that is another story.)

Again a buffering mosquito.

The following mosquito describes a buffer with a maximum capacity of

three values in our new notation:
| dop ![a:= L]; ![b:= L]; ![C:= L]
|  | ▯ ![a:= L]: ![L:= a]
|  | ▯ ![b:= L]; ![L:= b]
|  | ▯ ![c:= L]; ![L:= c]
|  | ▯ ![L:= a]; ![L:= b]; ![L:= c]
| pod

Here I am, playing with a new toy! The top line expresses that the local variables are filled cyclically in the order (a, b, c), the bottom line expresses that they are emptied in the same cyclic order. The second line expresses that with regard to the local variable a filling and emptying alternate (so that everything going in goes out again), the next lines express the same relation for b and c .

Remark. In the above description I have allowed myself a sloppy thing: after the exclamation marks I have written down the statements themselves, instead of their names. We could require in several lines the coincidence of ![S1] and the coincidence of ![S2] , while elsewhere it is defined that both S1 and S2 are, For instance, “skip”. (End of remark.)

Although I think the above mosquito intriguing, I should not close my eyes to the fact that I currently don’t see, how to derive from the above a buffering mosquito in the style of EWD476-4 (above). If this inability is not overcome in an acceptable manner, that fact may point to an, as yet unfathomed, weakness of the notation. I hope that time will show, either in one way, or in the other.

Multiple coincidence.

It seems unnatural to restrict coincidence to two occurrences, more precisely, to the occurences in just two cyclic processes. In the elephant for the hyper-fast Fourier transform, with the so-called “perfect shuffle”, each mosquito starts broadcasting its contents z via the legs 01 and 02 to two different mosquitos, simultaneously waiting to receive via I1 and I2 to values from two different mosquitos, accepting these values in the local variables x and y. After all this information exchange, it performs basically F: z:=f(x, y). This would lead to the structure

| dop [O1:= z]; ![F]
|  | ▯ [O2:= z]; ![F]
|  | ▯ [x:= I1]; ![F]
|  | ▯ [y:= 12]; ![F]
| pod .

It seems unattractive to reduce the number of four cyclic processes to two by imposing more stringent sequencing constraints upon the contacts with the mosquito’s outer world. First of all we must be careful not to introduce global deadlocks, such as would be caused by

| dop [O1:= z]; [x:= I1]; ![F]
|  | ▯ [U2:= z]; [y:= I2]; ![F]
| pod

as this would start all mosquitos sending and none in the mood to receive. Secondly, we would like all mosquitos to be of identical structure, and for two of the mosquitos one of their own output legs is connected to one of their own input legs. Obviously I do not care too much about the analysis which sequencing constraints to be imposed upon the external contacts are still admissible. Thirdly, it would reduce the traffic density between the mosquitos, so time-wise it is not attractive either. Perhaps it would be wise to indicate at the exclamation marks the multiplicity of coincidence. The synchronization structure of the mosquitos of the hyper-fast Fourier transformer is mentioned here as a recording of the issues involved in elephant construction.

Things to be done sooner or later.
1)     Instead of falling in love with my new notation, I should continue the investigation of alternatives.
2)     The current notation has to be extended so as to include a termination criterion as well.
3)     It should be investigated whether the current notation should be extended so as to include other reasons for delay besides (internal or external) coincidences. I would feel safer about it, if I could find an argument that this extension is not necessary, for that would do away with the analysis of obligations for waking up.(Is it, therefore, too much to hope for?)
4)     I have not given yet a formal definition of the semantics of a single mosquito. Only thereafter can I hope to derive theorems about merging several mosquitos into a single one.
5)     It should be tried on some standard exercises, such as The Dining Philosophers, and perhaps also on the Readers and the Writers.
6)     It should be discovered, whether proving something about an elephant is more conveniently done by merging its mosquitos into a single giant mosquito —which is equivalent to the elephant— or, whether we prove our assertions about the elephant in two steps: first proving everything about the individual mosquito’s, regarded in isolation, and then, knowing the relevant properties of the nodes, our assertions about the whole network. Intuitively I prefer the second approach, but I must admit that it is rather unclear to me, how such prrofs should look like. The article by W.H.Burge “Stream Processing Functions” (IBM J.Res.Develop., Vol.19, No. 1, pp 12 - 25) as yet does not strike me as very helpful.
7)     How to design elephants.
8)     etc.

It is nearly three weeks ago, since I started on this preliminary investigation and it seems that the time has come to sollicit comments.

5th March 1975 | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NUENEN - 4565 |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD 477

Tweede toespraak tot mijn studenten.

Vandaag wil ik U toespreken over wetenschapsbeleid, en wat ik U te zeggen heb is gelijkelijk van toepassing op wat mijnheer Trip probeert, op wat een industrieel of universitair centrum van onderzoek probeert, als op wat elke individuele onderzoeker probeert.

Bij elk wetenschappelijk onderzoek poogt men twee heren te dienen: de ene heer heet "qualiteit", de andere heer heet "relevantie". De eis van qualiteit betekent, dat het werk moet voldoen aan de normen, die door de wetenschappelijke traditie zijn gegroeid. Die normen impliceren, dat het werk met de grootst mogelijke zorgvuldigheid is uitgevoerd, zodat geen onverantwoorde conclusies als betrouwbaar gepresenteerd worden. Die normen impliceren voorts, dat het werk door zijn innerlijke consistentie en adequaatheid effectief bijdraagt tot ons collectief kennen en/of kunnen. De eis van relevantie betekent, dat het andere mensen op een of andere manier met hun moeilijkheden helpt. Het schijnt in deze dagen helaas nodig te zijn, er de nadruk op te vestigen, dat relevantie niet noodzakelijkerwijs directe maatschappelijke relevantie hoeft te zijn in die zin, dat het zichtbaar bijdraagt tot de oplossing van die problemen, die de voorpagina van de krant halen: wij dienen ons het recht voor te behouden, menig "culturele" bijdrage zeker zo "relevant" te vinden.

Het is heel makkelijk om beide eisen zo hoog op te voeren, dat er haast niets meer aan voldoet. Wie de hieruit voortvloeiende stagnatie niet wenst en de wetenschapsbeoefening wil stimuleren, moet zich dan afvragen, in welk opzicht hij zich toleranter opstelt. Het is duidelijk, dat er met de qualiteitseis niet geschipperd mag worden: een goed stuk werk, dat evenwel niemand interesseert, is in elk geval goed en ongevaarlijk, wat niet gezegd kan worden van een niet ontmaskerde schijnbijdrage tot een actueel probleem. Integendeel!

Onze overheid heeft helaas anders gewild. Nu zelfs het hoger onderwijs een rol is toebedeeld bij de fanatieke poging tot grotere homogenisering van onze maatschappij, is aldaar voor qualiteitseisen geen plaats meer. Niet alleen, dat het slechtere nu is toegestaan, het is zelfs zover, dat de excellentie geweerd wordt, want hoe kan je homogeniseren, zolang je uitschieters toestaat? Vervolgens is de overheid om de groei van het universitaire bedrijf te breidelen op het lumineuze idee gekomen de overgrote tolerantie ten aanzien van de qualiteit te compenseren door een uitgesproken intolerantie ten aanzien van de relevantie: als iets niet bijdraagt tot het energieprobleem, de milieuhygiene of nog zo'n paar vulgaire onderwerpen, dan hoeft het niet meer....

Hoe hard deze tweede nekslag aankomt, volgt uit het volgende citaat van Sir Hermann Bondi:

"The problem of academic research I think can be put reasonably bluntly. If you look at the problems that arise outside, in their own right, almost 20 per cent. of them are trivial and 80 per cent. or so are evidently insoluble, and it is the task of the academics to swim in that exceedingly narrow layer separating the trivial from the insoluble, that remarkably thin layer in which thought, skill and work can actually make a difference."

De intolerantie, die dit dunne laagje tot verboden gebied verklaart, maakt wat daarna nog voor wetenschapsbeoefening moet doorgaan tot vruchteloze schijnbewegingen.

Na aldus tot Uw maatschappelijke vorming te hebben bijgedragen, ga ik over tot Uw wetenschappelijke vorming.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

EWD478

NOTE: This transcription was contributed by Martin P.M. van der Burgt. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On one-sided smoothing of event sequences.

We consider a finite number of events Ei (i from 0 through N) occurring at moments ti (i > j ⇒ ti > tj). The problem I found myself faced with was how to define a continuous function f(t) that could be interpreted as “the event frequency at moment t.” (I encountered this problem when trying to discover a strategy for deciding how much primary store should be allocated to independent programs in a multiprogrammed environment when for each program a “target page fault frequency” had been decided.)

A possible definition of the event frequency is in terms of the Dirac function:

| N |
f(t) = | Σ δ (t - ti) | (1)
| i=0 |

which has the obvious advantage that it satisfies

| +∞ |
| ∫ f’(t).dt = N + 1 | (2)
| -∞ |

but the equally obvious disadvantage of severe discontinuities, which makes the comparison of f0(t) and f1(t) — two different frequencies corresponding to different values of the parameter I could control — rather difficult. Hence our desire to smooth the data. The smoothing, however, had to be one-sided in the sense that the smoothed value f’(t) may at any moment t only depend on the set of values ti with ti ≤ t. In order to make a sensible choice among the wealth of possibilities for f(t) we should impose upon f(t) as many “sensible” constraints as we can think of. To start with, property (2) seems a good choice. The next one is that we should realize that frequencies —as usually understood— have a dimension “time ⁻¹”, i.e. if we consider at moments t’i = ati and define the corresponding frequency f’(t) for that second event sequence, then

| f’(at) = (1/a) f(t) | (3)

should hold. Poperty (3) is not in conflict with requirement (2), for

+∞ | +∞ | +∞
∫ f’(t’).dt’ = | ∫ f’(at).d(at) = | ∫ a.f’(at).dt =
-∞ | -∞ | -∞
| +∞ |
| ∫ f(t).dt = N + 1 |
| -∞ |

Reasonable as requirement (3) may seem it is (for finite sequences) too much to hope for: if t₀ = 0 the relation (3) will not hold for t₀ ≤ t ≤ t₁, for how are we going to guess “a”? Therefore we must loosen it and can only require (3) to hold asymptotically for t > ti with sufficiently large i.

Relation (2) however, still stands rather firmly. Because in (2) we have only used

| +∞ |
| ∫ δ(t) dt = 1 |
| -∞ |

We could consider functions wi(t) such that

| w(t) = 0 for t < 0 | (4)
| ∞ |
and | ∫ w(t).dt = 1 | (5)
| 0 |

N

and replace (1) by f(t) =
Σ wi (t - ti)

i=0

(6)

where (4) does credit to the one-sidedness of the required smoothing , (5) guarantees (2) and (6) makes the whole definition invariant for shifting of the origin. The question is whether we can choose the wi in such a way — satisfying (4) and (5) — as to approximate (3) at least asymptotically.

A reasonable first guess — corresponding to fading out of the past in an exponential way — for wi(t) is with ki > 0:

| wi(t) = 0 for t < 0 |
|       = ki.e-ki.t for t ≥ 0 | (7)

where we can try to adapt ki — on account of past history, if any — towards a better approximation of (3). I called (7) a first guess, because we also wanted a continuous function f(t) and with (6) and (7), f(t) is discontinuous for any t = ti. A continuous f would follow from the proper linear compositum — proper in view of (4), (5) and wi(t) = 0 —

| wi(t) = 0 for t < 0 |
|       = (e-ki.t - e-hi.t).(hi.ki)/(hi - ki) for t ≥ 0 | (8)

and now we are free in the choice of both hi and ki, provided that they are both positive and different from each other. I am severely tempted to restrict myself to

| hi = c * ki with c ≠ 1 and c > 0 | (9)

the reason being that both hi and ki are of dimension “time⁻¹” and that I cannot forget my target (3).

*              *
*

In order to come to grips with the constant c I studied (omitting subscripts “i”) according to (8) & (9)

| w(t) = k . c/(c-1) . (e-kt - e-ckt)

and tried to determine c so as to minimize the maximum value of

| c/(c-1) . (e-kt - e-ckt)

(I wanted my ripples as smooth as possible.) As this led to the inacceptable value c = 1, I took the limit for c → 1 and found — and this is my final suggestion —

| w(t) = 0 for t < 0 |
|       = ki²t.e-kit for t ≥ 0 | (10)

| ∞
Also (10) has the property that | ∫ wi(t).dt = 1
| 0

*              *
*

The next thing to decide is, how to choose the value ki. A constant value for ki seems in view of (9) out of the question, because ki has the dimension of a frequency. Apart from initial difficulties it seems reasonable to choose ki proportional to f(ti) i.e.

| ki = d * f(ti) | (11)

To get some feeling for a reasonable value for d, we consider f(t) for t≥0 as results from an infinite sequence of events that have occurred at t=0, -1, -2, -3, .... etc; for all passed events we may assume the same value ki = k and we find for f(t), according to (6) and (10)

| ∞
f(t) = k. | Σ k.(t+i).e-k.(t+i)
| i=0

which, indeed satisfies f(0) = f(1) as was to be expected.

Note. I summed the sequence and found

|     k².e-k.t                 e-k
f(t) = | (————) . (t + ————)
|     1 - e-k                  1 - e-k

(End of note)

The functions (10) have all one maximum, viz. at t = ki⁻¹. We would like to attribute the maximum of f(t) for 0 ≤ t ≤ 1 to the term with i = 0 (i.e. the last event). For i > 0 all the terms should be decreasing functions of t for t > 0. We can expect the smoothest maximum of f(t) if it is in the neighbourhood of t = ½ and this suggests k in the neighbourhood of 2 and

| d = 2 | (12)

For, because in the average f(t) = 1, we know that f(0) = f(1) < 1, therefore with d = 2 we shall find k < 2 and the term with i = 0 will reach its maximum at t₀ > ½. Because the contribution of the remaining terms is a decreasing function of t, this will be compensated and f(t) will find its maximum at tf < t₀.

Note. Using I sliderule I have investigated the consequences of the choice d = 2. Salvo errore et omissione I found for k=1.616, f(0) = f(1) = 0.808 as minimum value for f(t) and f(0.41) = 1.105 as maximum value. Anyone that would like to rely on these figures should reestablish them in a more reliable manner, I only mention these results because they represent the outcome of an hour’s work and give some impression of how smooth f(t) becomes in the case of equally spaced events. If it were of importance, I would try slightly smaller values of d as well. (End of note)

19th February 1975 | prof.dr.Edsger W. Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NUENEN - 4565 |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD479

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Commentaar op “Structuur plan Informatica (W.O.) van de ARSI.

        “Learn to write well, or not to write at all.” (John Dryden)

        “Groot is mooi en veel is lekker.” (Maarten Toonder)

Het eerste dat aan het ”Structuurplan Informatica (W.O.) van de Academische Raad, Sectie Informatica, code “AR 74/75-5” (in navolging van de ARSI hieronder aan te duiden als het Magnum Opus) opvalt, is zijn omvang en het slechte Nederlands, waarin het is gesteld: even weinig had beter in het halve aantal pagina’s gezegd kunnen worden.

Het tweede is de onduidelijkheid. Men stelle zich een rapport voor over “Het onderwijs in het schrijven”, waarbij de lezer geregeld in het ongewisse blijft of passages nu betrekking hebben op het onderwijs, dat kindertjes in de eerste klas leert letters op papier te krijgen, of op onderwijs in spelling, of op onderwijs in handelscorrespondentie, of op colleges voor toekomstige literatoren en auteurs: zo schrijft het Magnum Opus over “informaticaonderwijs”.

Het derde is, dat in dit Magnum Opus —dat handelt over een Structuurplan Informatica voor het Wetenschappelijk Onderwijs!— een halve pagina over de wetenschapsbeoefening gaat, de resterende 69.5 over onderwijs. (Ten aanzien van de wetenschapsbeoefening weet het Magnum Opus niet veel meer te vertellen, dan dat deze “bevorderd” moet worden.)

Het vierde is de nadruk, waarmee “de behoefte van de maatschappij” als voornaamste leidraad is gekozen. Niet een wetenschappelijke discipline, maar “werkkringen” fungeren als uitgangspunt, in zo sterke mate, dat —hoewel de auteurs dit met een weinig overtuigend beroep op de diversiteit van de werkkringen ontkennen— het Magnum Opus eigenlijk een paar beroepsopleidingen voorstelt, die nauwelijks boven het het niveau van het NOVI (beter bekend onder de oude, en misschien eerlijkere naam SSAA) lijken uit te komen: het enige verschil lijkt, dat de docenten de toga mogen dragen. Deze nadrukkelijke afstemming op werkkringen is des te bedenkelijker, omdat in dit nog verre van volgroeide vak wetenschappelijke en technische ontwikkelingen de aard van het werk nog zo drastisch kunnen veranderen. (Hierbij zij opgemerkt, dat naarmate mensen minder aan deze ontwikkelingen deel hebhen, zij een statischer beeld van de maatschappelijke behoefte hanteren.) De vrees, dat de gedoceerde stof, zo Űberhaupt van enige waarde, een halfwaardetijd van hooguit vijf jaar zal hebben, klinkt in het Magnum Opus nergens door. (Integendeel! In het basisprogramma wordt leerstof opgevoerd, die reeds nu aantoonbaar als rijp voor de schrothoop ontmaskerd is.)

De grootste leemte van het Magnum Opus is, dat het de zinvolheid en realiseringsmogelijkheid van de voorgestelde (tamelijk gigantische) onderwijsactiviteit als zo vanzelfsprekend veronderstelt, dat zelfs geen poging is ondernomen om deze waarschijnlijk te maken. Aangezien schier alle wetenschappen van de computer zouden kunnen profiteren, moeten grote horden studenten —alpha’s, beta’s, gamma’s, de hele troep— basisonderwijs in de informatica krijgen. Heel eenvoudig! Maar wat blijft daar van over? Dat wordt van het niveau van een college “girokaart invullen” —wat is de automatisering van de girodienst anders dan een groot “applicatiepakket”?—. (Het feit dat wij bij de Inleiding tot de Kunst van het Programmeren voor de HBO-leraren, die dat college volgen, al een speciaal schertstentamen moeten opstellen, omdat ze anders nooit een voldoende halen, spreekt waarschuwende boekdelen.)

Naast dit dubieuze basisonderwijs aan allen, worden twee beroepsopleidingen gesuggereerd, informatica “I” en bedrijfsinformatica “BI”, en het Magnum Opus betoogt herhaald met klem, dat een “studierichting informatica” in het Academisch Statuut dient te worden opgenomen. De enige motivering is een politieke: als we nu het officiele etiket van “academisch gevormd informaticus” maar kunnen uitdelen, dan halen we onze “achterstand” wel in. (De aanhalingstekens rond de “achterstand”, waarmee het Magnum Opus het departement onder druk probeert te zetten, duiden aan dat ik bij de wijze, waarop het Magnum Opus deze meent aan te tonen, nog wel mijn kanttekeningen heb.) Het Magnum Opus vermeldt tactvol nergens, dat de levensvatbaarheid van een academische studierichting o.a. afhangt van een haar schragende wetenschappelijke discipline. In het geval van de informaticaopleiding “I” —mits niet zo oubakken voorgesteld als in het Magnum Opus— begint een dergelijke discipline zich weliswaar af te tekenen (maar er zijn nog genoeg andere redenen voor mij om zo huiverig te zijn, dat ik zelfs een afstudeerrichting “I” in het Academisch Statuut prematuur acht); ten aanzien van de bedrijfsinformatica “BI” is een dergelijke schragende wetenschappelijke discipline grotendeels afwezig. Deze absentie —hoewel ruiterlijk in het Magnum Opus toegegeven— is voor de opstellers geen beletsel geweest om toch maar een aantal hoogleraren in dit vooralsnog hypothetische vak voor te stellen! Kortom, zelfs zonder de gepaneerde hehoeften van de maatschappij in twijfel te trekken, en zonder het geponeerde primaat van deze leidraad aan te vechten —iets, waar ik overigens van ganser harte toe bereid ben— moet ik concluderen, dat het Magnum Opus bedenkelijk veel overeenkomst vertoont met het bekende voorstel, om aan alle medische faculteiten leerstoelen te stichten voor “De genezing van vooralsnog ongeneselijke ziektes.”. Deszelfs voorstellers mogen menen, daarmee van visie te getuigen, de praktijk heeft geleerd, dat hiermee slechts kwakzalvers worden aangetrokken.

Een laatste karakteristiek van het Magnum Opus mag. omdat hij zo uiterst bedenkelijk is, helaas niet onvermeld blijven: deszelfs onverholen anti-intellectualisme. Zo wordt in de appendix voor de I-Opleidi�ng gesteld, dat het voorstel er garant (sic!) voor staat, dat er geen “ivoren toren” informatici zullen worden opgeleid. (In naam van de wereldvrede, of zo?) En ik maar bidden, dat, zo dat voorstel onverhoopt opgevolgd mocht worden, er af en toe nog een “ivoren toren” informaticus door de mazen van het net heen glipt. Maar dat is natuurlijk wel naief, want ze staan er immers garant voor, dat zoiets niet meer zal gebeuren......

21 februari 1975 | prof.dr.Edsger W.Dijkstra
| Technische Hogeschool Eindhoven

P.S. Nu er nog wat ruimte op deze pagina over is, voor wie het anders niet geloven wil, tot slot een stijlbloempje uit het Magnum Opus (pg. 31): “Als doelstelling wordt genoemd ”de behoefte aan onderwijs met betrekking tot informatiesystemen in organisaties“, hetgeen geanalyseerd wordt aan de hand van het gebruik dat organisaties op dat moment van computers maakten, in vergelijking met het wezen van bestuurlijke informatiesystemen.”

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

   EWD 480

27th February 1975

"Craftsman or Scientist?"

(Luncheon Speech to be held at "ACM Pacific 75" at San Francisco, Friday 18th April 1975, by Edsger W. Dijkstra, Burroughs Research Fellow.)

My somewhat elliptic title refers, of course, to the programmer; so much you may have guessed. What, in all probability, you could not have guessed, is that I have chosen to use the words "craftsman" and "scientist" in a very specific meaning: they have been chosen to characterize the results of two extreme techniques of education, and this luncheon speech will be devoted to a (be it short) discussion of their role in the education of programmers, in the teaching of programming. For the transmission of knowledge and skills both techniques have been used side by side since many centuries.

The future craftsman joins a master for seven meagre years, he works as an apprentice under his guidance and supervision, absorbing gradually, by osmosis so to speak, the skills of the craft, until he may be called a master himself. Craftsman typically form Guilds and the guild members tend to keep their common craft as a well-guarded secret among themselves: not blowing the gaff is one of their rules of professional conduct. Note, finally, that old crafts have been lost, dependent as their survival was on the continuing transmission from one generation to the next.

The future scientist learns his trade as student from a teacher, who, in contrast to the master who transfers his knowledge implicitly to his apprentice, tries to formulate the knowledge and to describe the skills as explicitly as possible, thereby bringing both to the public domain. The latter technique is the prevailing one at the Universities. It is no coincidence that the rise of the Universities occurred when the printing press became widely established, and it is no accident that each University regarded its Library as its greatest treasure: the library was the embodiment of its specific calling. The scientists regard the free interchange of knowledge and insights as essential, and, in consequence, being non-secretive is one of their rules of professional conduct.

To this day both techniques are applied side by side: physicists, for instance, are mostly scientific, physicians, however, are mostly much more like guild members. Mathematicians are somewhere in between: mathematical results are published and taught quite openly, but there is very little explicit teaching on how to do mathematics, and publishing besides the results also the heuristics that led to them is regarded by many as "unscientific" and therefore, bad style: quite often the editor's censorship will try to prohibit their publication.

I have sketched for you two extreme educational techniques, but this was only preparation: my real topic is "Where along this scale should we place the teaching of programming?". This, as I have learned by sad experience, is a risky subject to discuss, because one always discusses it with people who themselves are involved in one way or another in the programming profession, and their personal involvement tends to evoke strong emotional reactions. Let us try to understand them, for only then we may be able to cope with them.

To make implicit knowledge explicit and to discuss how to describe skills so that they can be transferred implies, if not the birth at least the conception of a new science. But we should realize that changing a craft into a science, and making public property of the secret knowledge of the guild, will always cause the guild members to feel threatened. For many a "puzzle-minded" virtuoso coder of the early sixties, the scientific development of the last decade has been most unwelcome. He feels like the medieval painter that could create a masterpiece whenever his experience enabled him to render proportion well, who suddenly found himself overtaken by all sorts of youngsters, pupils of Albrecht Dürer and the like, who had been taught the mathematical constructions that were guaranteed to surpass his most successful, but intuitive renderings. And with nostalgia he looks back to the good old days when his experience and feeling made him an outstanding craftsman. And we should realize that, as far as programming is concerned, the battle is still going on. From a European country, the name of which I shall not divulge in order to avoid personal complications, I recently studied a proposal for the organization of its computing science teaching at University level. The majority of its authors --all if them professors of computing science in their country-- should be characterized as "craftsmen". As a result, their proposal had a pronounced anti-intellectualistic flavour: it stressed that students should be taught how to solve the problems of "the real world" and that, therefore, the curriculum should pay as little attention as possible to "abstract subjects". Such utterances are unmistakable and, undoubtedly, you recognize them. So much for the pure craftsman's point of view.

At the other end we have the pure scientist: if we gave him the power of decision, the result will be equally disastrous. He will see his discipline --be it automata theory, recursive function theory, formal language theory, logic or queuing theory, you name it-- with the exceptional clarity that we are entitled to expect from the modern scientist, but one thing is for him nearly impossible to accept, viz. that his beautiful and formal apparatus indispensable as it may be, does not necessarily suffice. Since Turing we have the complete theory of how to manipulate bits and is not that, what all computing boils down to? And why all that fuss about, the problems of "the real world"? His theory proves, that all these problems can be solved, so why bother about actually solving them? Also such utterances are unmistakable and, undoubtedly, you recognize them.

So, the extremes are no good, we must blend them. But now we must be careful, for "blending" is no longer a one-dimensional question. It is not just "so many per cent. craftsman and so many per cent. scientist", but "this from the craftsman and that from the scientist". To drive home that message I shall describe to you a disastrous blending, viz. that of the technology of the craftsman with the pretence of the scientist. The craftsman has no conscious, formal grip on his subject matter, he just "knows" how to use use his tools. If this is combined with the scientist's approach of making one's knowledge explicit, he will describe what he knows explicitly, i.e. his tools, instead of describing how to use them! If he is a painter he will tell his pupils all he knows about all the brushmakers and all he knows about the fluctuating price of canvas. If he is a professor of computing science, he will tell his students all he knows about existing programming languages, existing machines, existing operating systems, existing application packages and as many tricks as he has discovered how to program around their idiosyncrasies. And in a short while, he will not only tell what the manual says that should be punched in column 17 of the first card in order to indicate your choice of priority queue, but he will also tell and explain the illegal punching in column 17 that will place your program in the highest priority queue while only charging for you the lowest priority one. Again, the symptoms are unmistakable and, undoubtedly, you recognize them.

This disastrous blending deserves a special warning, and it does not suffice to point out that there exists a point of view of programming in which punched cards are as irrelevant as the question whether you do your mathematics with a pencil or with a ballpoint. It deserves a special warning because, besides being disastrous, it is so respectable! You see, on the one hand you stick to the problems of the real world and no one can accuse you of being overdemanding with regard to the powers of abstraction of your students, on the other hand you are as explicit as possible and everything you tell is the objective, undeniable truth. And when someone has the temerity of pointing out to you that most of the knowledge you broadcast is at best of moderate relevance and rather volatile, and probably even confusing, you can shrug out your shoulders and say "It is the best there is, isn't it?" As if there were an excuse for acting like teaching a discipline, that, upon closer scrutiny, is discovered not to be there .... Yet I am afraid, that this form of teaching computing science is very common. How else can we explain the often voiced opinion that the half-life of a computing scientist is about five years? What else is thansaying that he has been taught trash and tripe?

With a little bit of knowledge of human nature, after the above tirade against the wrong blending, all of you will now expect me to say that my sympathy is with the inverse blending. This expectation is correct: as teachers of programming we should try to blend the technology of the scientist with the pretence of the craftsman.

Sticking to the technology of the scientist means being as explicit as we possibly can about as many aspects of our trade as we can. Now the teaching of programming comprises the teaching of facts --facts about systems, machines, programming languages etc. -- and it is very easy to be explicit about them, but the trouble is that these facts represent about 10 per cent, of what has to be taught: the remaining 90 per cent. is problem solving and how to avoid unmastered complexity, in short: it is the teaching of thinking, no more and no less. The explicit teaching of thinking is no trivial task, but who said that the teaching of programming is? In our terminology, the more explicitly thinking is taught, the more of a scientist the programmer will become.

This, of course, raises the question of feasibility of the teaching of thinking. In order to make this question realistic, we shall qualify it somewhat: knowing how to teach thinking will not imply that each student is also able to learn it. This need not deter us: in this respect "thinking" would not differ from any other subject that we try to teach. So, let us consider the question after this qualification: can thinking be taught? The blurb on the backside of my 1957 edition of Polya's How to Solve It. is quite positive: "Deftly, Polya the teacher shows us how to strip away the irrelevancies which clutter our thinking and guides us toward a clear and productive habit of mind."

Fine, but that is only the blurb: on the other side it has been remarked that its first edition dates already from 1944 and that Polya's larger work on the same subject "Mathematics and Plausible Reasoning" has been coolly received by the mathematical community and has had at most a very minor influence on the teaching of mathematics at university level. Its cool reception by the mathematical community says at second thought, however, nothing against the feasibility of Polya's project. On the contrary! For its cool reception can also be interpreted as the rejection by the mathematical guild that feels threatened, as all guilds do, when the secrets of their trade are made public. To publish 30 years ago a book about the making of mathematical discoveries was heresy, as it still is in the eyes of many mathematicians today. And to quote from Management and Machiavelli by Antony Jay: "In corporation religions as in others, the heretic must be cast out not because of the probability that he is wrong but because of the possibility that he is right." In other words, the relative rejection of Polya's work on heuristics tells probably more about the intellectual inertia of the mathematical establishment than about his books themselves and I suggest you this time --unusual as the advice may seem!-- to believe the blurb.

I regard Polya's How to Solve It as a promising and significant first step. It presents heuristics as a kind of checklist of standard questions which may be helpful in not overlooking a simple, but somehow unexpected solution, if there is one. When I first read it, I was somewhat disappointed by it, a disappointment that was a direct consequence of my already being deeply involved in programming: I felt that my problems as a programmer were for a large portion beyond the scope of what Polya covered. At first I hesitated to say so aloud, because stressing the exceptional nature of the one's field is usually a sure way of making oneself utterly ridiculous. But after careful consideration I concluded that the intellectual challenge presented by the programming task is, indeed, as unprecedented as the high-speed automatic computer itself. And it had caused in my mind a shift of attention from "how to discover the unexpected" towards "how to avoid unmastered complexity", towards "how to reduce the demands made on our quantitatively limited powers of reasoning".

You must take my word for it, that past experience has made me a firm believer that this newer aspect of thinking, i.e. how to avoid unmastered complexity, can indeed be taught. This strikes you perhaps as a strong statement, it becomes only stronger when you also know that I am usually not given to unwarranted optimism. Among other things it can be done by the identification and subsequent description of the more productive "complexity generators".

But it is good to remember, that there are some intrinsic limits to the degree in which thinking can be taught explicitly, "in the scientific manner" so to speak. To quote Polya: "The first rule of discovery is to have brains and good luck. The second rule of discovery is to sit tight and wait till you get a bright idea. It may be good to be reminded somewhat rudely that certain aspirations are hopeless. Infallible rules of discovery leading to the solution of all possible mathematical problems would be more desirable than the philosopher's stone, vainly sought by the alchemists. Such rules would work magic; but there is no such thing as magic. To find unfailing rules applicable to all sorts of problems is an old philosophical dream but this dream will never be more than a dream." And it is there, where, unavoidably, the teaching of thinking becomes more like the teaching of a craft, where the student picks up by unconscious imitation: it is here, where as in the good old days of the guild, an inspiring master can do wonders and can found a School by his example.

To those of you that are in the academic teaching business I have only one urgent plea: please be not ashamed of the extent in which your teaching of thinking is "unscientific"! It is good to remember that all the unfathomed depth of the human mind is already at play in the process of human communication. We have --despite what psychologists, pedagogues and the like may think-- not the faintest idea how knowledge, insights and habits are transferred. It is not unlikely, that the actual transfer is always by imitation, and that all the explicit teaching in the scientific tradition is no more than giving the student some verbal handles, which are no more than an aid to memory. If this is true, then all purely "scientific teaching" --i.e. the explicit rules and no more-- is bound to be, and to remain forever, a barren activity.

To end up my talk I would like to tell you a small story, that taught me the absolute mystery of human communication. I once went to the piano with the intention to play a Mozart sonata, but at the keyboard I suddenly changed my mind and started playing Schubert instead. After the first few bars my surprised mother interrupted me with "I thought you were going to play Mozart!". She was reading and had only seen me going to the piano through the corner of her eye. It then transpired that, whenever I went to the piano, she always knew what I was going to play! How? Well, she knew me for seventeen years, that is the only explanation you are going to get. Since then I believe that is vain to try to understand what goes on in the classroom between who teaches and who learns, and that having no model of that process is safer than having one, of which the crudeness has been forgotten.

I thank you for the attention.

5th March 1975
Plataanstraat 5
NUENEN – 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

G. Polya How to Solve It. (Anchor A93) Doubleday and Company, Inc., Garden City, New York, U.S.A., 1957

Antony Jay Management and Machiavelli, Penguin Books Ltd., Harmondsworth, Middlesex, England, 1970

transcribed by Jorge Andrés Pérez Parra
revised Thu, 18 Nov 2004

2 maart 1975 EWD 481

Derde toespraak tot mijn studenten.

Bij mijn recente overpeinzingen over de herstructurering van het universitair onderwijs kreeg ik het idee om, als belangrijkste hervorming, een driejarige cursus in te voeren ter opleiding van staatssecretarissen; een kwart van de abiturienten (uit de aart der zaak door loting te selecteren) mag nog een jaar doorleren voor minister.

Een zo brilliante inval komt natuurlijk niet zomaar uit de lucht vallen: uw nederige dienaar heeft niet meer gedaan dan de synthese tot stand brengen van allerlei gedachten die anderen, aan wie hij zijn diepste dank verschuldigd is, hebben aangedragen. Maar als je even doordenkt, is het duidelijk: aan de ene kant wordt het steeds duidelijker dat zij, die thans onze regering uitmaken, niet goed voor hun taak zijn opgeleid, anderzijds wordt de roep om een universitair onderwijs, dat in zijn opleidingspatroon duidelijker is afgestemd op de maatschappelijke behoeften, steeds luider.

Jaren lang heeft het Nederlandse tertiaire onderwijs op twee gedachten gehinkt, gestrompeld, mogen wij wel zeggen. Enerzijds was er het hoger beroepsonderwijs —het HBO voor de intimi—: dat was een degelijke zaak, die zonder wetenschappelijke pretentie zijn leerlingen opleidde voor duidelijke functies, waarvoor goed bekend was, wat je er voor weten moest. Anderzijds was er het z.g. wetenschappelijke onderwijs —ook wel WO genaamd—, maar dat functioneerde veel onduidelijker. Het claimde, dat het zijn opleidingen niet centreerde op erkende beroepen, maar op wetenschappelijke disciplines, het claimde in het bijzonder dat het zijn studenten de geestelijke bagage zou meegeven, die nodig zou kunnen zijn voor functies in de toekomst, die nu, als zodanig, nog helemaal niet onderkend zijn. In plaats van zijn studenten voor een duidelijk beroep op te leiden, pretendeerde het zijn studenten te leren, hun hersens te gebruiken en te leren denken. Op kleine schaal is een dergelijke aberatie nog wel te tolereren, maar aangezien het voor de meeste functies volledig ongewenst is dat hun vervullers hun hersens gebruiken, leidt dit op grote schaal tot rampen.

Stel je eens even voor in wat voor rampzalig parket we zouden zitten, als staatssecretaris Klein zijn hersens zou gebruiken! Hij zou eens iets origineels kunnen decreteren, en we zouden van pure schrik niet weten, hoe we het hadden! Nu weten we tenminste, waar we aan toe zijn. Ter voorkoming van de onverantwoordelijke uitwassen bij het WO —afgelopen week hebben we het nog duidelijk in de krant kunnen lezen— gaat hij met de harde bezem door de universiteit en er komt een structuurwet, een raamwet, een kaderwet of hoe dat ook heten mag, waarin het WO ter voorkoming van verder misverstand bij het HBO wordt ingedeeld. Staatssecretaris Klein is gelukkig voldoende weinig origineel, dat je dit had kunnen zien aankomen. Nu heeft het HBO gelukkig voldoende lang van te voren zijn maatregelen kunnen treffen en er voor kunnen zorgen, dat ook in de nieuwe constellatie alleen zal worden opgeleid voor functies die nu al bestaan. Tenslotte is de werkgelegenheid het enige betrouwbare kompas.

Bij het academisch onderwijs zijn er misschien nog wel een stelletje, dat het tempo der vooruitgang niet helemaal heeft kunnen bijhouden, een stelletje, dat nog steeds de illusie koestert, dat van de academie het intellectueel leiderschap hoort uit te gaan, in plaats van dat de academie, zich op de maatschappelijke behoeften afstemmend, dienstbaar, zoals dat hoort, achter de feiten aanholt. Ik vrees, dat dat stelletje, te dom om in te zien, dat de tijd voor de Nieuwe Orde is gekomen, mokkend in de illegaliteit zal gaan.

Na aldus tot uw eigentijdse vorming te hebben bijgedragen, ga ik over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

EWD482

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

7th March 1975

Exercises in making programs robust.

(This is a sequel to the very exploratory EWD452: “About robustness and the like” which was initiated in September 1974 and closed on 31st January 1975)

In this report I shall pursue a very simple idea. Provided that we give an adequate formulation of what we admit as “a single machine malfunctioning”, we can interpret the effort as that of making a program in such a way that under the assumption of at most a single malfunctioning, the machine will never ’produce a wrong result as if it were the right one. I shall not, however, start my considerations with a very precise definition of the class of malfunctionings I am going to allow a single instance of: the probability that I have designed a tool of which, after much hard labour, we must conclude that it is insufficient for reaching our goal, is then just too high. I shall therefore start at the other end, and investigate the consequences of applying a technique which —with a certain amount of goodwill— can be viewed as “making” a program more robust“ and afterwards analyse, which class of malfunctionings it catches under the assumption of at most a single instance. The more elaborate exercises, I am sorry to announce, will be rather painful ones, because we cannot do them with too simple examples: if the example is very simple —like forming the sum of a hundred stored values— the only way to make the program more robust boils (in some way or another) down to doing the computation twice and I am —obviously!— more interested in what we can achieve without paying that price. (All by itself, this observation is already somewhat alarming: under assumption of a perfect machine, we are used to break down the whole computation as a succesion of little steps, all of them trivial by themselves, but if they can only be made more robust by duplication, our robustness concerns force us to consider larger “units”. This seems a warning, that we are tackling a nasty subject!)

*              *
*

A very simple example to start with. A common program structure to establish a relation R is

(1) | establish P; do BB → S od
where | (P and BB) => wp(S, P)
and | (P and non BB) => R

and we could replace (1) by

(2) | establish P; do BB → S od; if P and non BB → skip fi

where the added statement causes abortion if the loop terminates with non P or BB, i.e. in a state in which we are not entitled to conclude the validity of R.

Time-wise this seems an attractive modification, because it does not generate an overhead on the repeatable statement S . An example would be (for N ≥ 0) with

R: | do a² and (a+1)² > N and P: a² ≤ N

to add to the program

| a:= 0 {P}; do (a+1)² ≤ N → a:= a+1 od {R}

the checking statement

| if a² ≤ N and (a+1)² > N → skip fi

But this example immediately illustrates the very restricted —i.e. nearly empty— range of applicability of this transformation: it only works in those cases where finding the answer may be hard, but checking the answer is (always!) easy. These cases seem to be rather the exception than the rule, and it would not amaze me if, often, when we think that we have found an example, the property that the correctness of a result is so easily checked can be used to speed up the process of finding one. (The above square root example is, indeed, ridiculously inefficient for larger values of N.)

*              *
*

What do we do, if —as for instance, when the correctness proof appeals to the Linear Search Theorem— the verification of P and non BB amounts to redoing the computation? Very crudely, if our first program operates on a variable (set) x

(3) | establish P(x);
| do BB(x) → S(x) od .

we could introduce a second set of variables, y say, and duplicate (under the assumption of determinacy)

(4) | establish P(x);
| do BB(x) → S(x) od;
| establish P(y);
| do BB(y) → s(y) od;
| if x = y → skip fi .

We can also merge the two processes, but establish P(x) and P(y) do BB(x) → S(x); S(y) od; if x = y → skip fi is a little bit too optimistic if we allow —and I think that we should— erroneous sequencing as would result from an erroneous evaluation of a guard as possible malfunctioning:

(5) | establish P(x) and P(y);
| do BB(x) → if BB(y) → S(y) fi; S(x) od;
| if non BB(y) and x = y → skip fi

is in this sense safe.

Up till now, there has been no gain by the transition from (4) to (5). But a fairly common structure of type (3), however, operates on a state space (x, z) and has the general form establish P1(z) and P2(x, z); do B1(z) and B2(x, z) → x:= f(x, z); z:= g(z) od

Here, repeated application of z:= g(z) generates a sequence of z-values —on account of B1(z) possibly finite— and in the variable x , some function value of this sequence of z-values is computed (collected, if you prefer). The relation P1(z) —which z:= g(z) will keep invariant— has been introduced to represent any possible redundancy in the representation of z. (If this redundancy is absent, P1(z) does not depend on z at all, is identically true and the remainder of this section —probably the whole report— is no longer applicable.) If B2(x, z) is identically true, the sequencing is independent of x and, therefore, of the function f. If however, we are looking for the first z-value (if any) that satisfies some property —e.g. if we are looking for the smallest divisor less than the square root plus one— B2 indicates that the search can be stopped as soon as a z-value satisfying the criterion has been found.

Again, we can merge to two copies, but what about letting the two state spaces share the same z ?

(6) | establish P1(z) and P2(x, z) and P2(y, z);

| do B1(z) and B2(x, z) →
|  | if B1(z) and B2(y, z) → y:= (y, z) fi;
|  | x:= f(x, z); z:= g(z)
| od
| if non (B1(z) non B2(y, z)) and x = y → skip fi .

How good is (6)? Suppose that the values of x , y and z are currently all correct, but that the evaluation of a guard is incorrect: as this incorrect evaluation is supposed to be the only malfunctioning, it will either itself cause abortion, or the next guard evaluation will do so. Suppose that the value of x has been corrupted and that this was our only malfunctioning, which is assumed to imply that y and z are and will remain correct. There are three cases: either we will, during x ≠ y , encounter a case that B2(x, z) ≠ B2(y, z) and this will cause abortion; the second possibility is that, although x ≠ y remains, this will not occur, but then the last guard will cause abortion (on account of x = y ). The third possibility is that this last abortion will not occur, because in the mean time x = y has been re-established, i.e. the (apparently information destroying) operation x:= f(x, z) has absorbed the malfunctioning: apparently, it did not matter! For a corruption of y (with the assumption that then x and z are, therefore, correct) the same applies. We are left with a corruption of z.

The operation z:= g(z) is already supposed to satisfy

(7) | (P1(z) and B1(z)) ⇒ wp(“z:= (z)”, P1(z)) ,

i.e. it is supposed not to destroy the validity of P1(z). If we assume that the operation z:= g(z) will, in addition, not destroy the validity of non P1(z)

(8) | (non P1(z) and B1(z)) ⇒ wp(“z:= g(z)”, non P1(z))

—i.e. will keep P1(z) invariant in the strict sense—, then changing the last line of (6) into

| if non (B1(z) and B2(y, z)) and x = y and P1(z) → skip fi

will guarantee that a corruption of z will be caught as well, if we assume that

(9) | z is represented in such a redundant fashion, that any corruption of
| it, that would not destroy the validity of P1(z) can be regarded as
| a multiple malfunctioning, or, to put it in another way, each single
| malfunctioning affecting z will make P1(z) false.

*              *
*

I have done extensive exercises with a program solving the following problem: generate all cyclic arrangements of 16 zeroes and 16 ones, such that all 32 possible configurations of 5 successive bits occur (and therefore: exactly once). Another formulation of describing the same problem is: generate all permatations h₀ ... h₃₁ of the numbers 0 through 31 that

0) | h₀=0 ,
2) | suc(hi, hi+1) for 0 ≤ i < 31
3) | suc(h₃₁, h₀) ,

where suc(a, b) = (a mod 16 = b div 2) .

It is in the latter form that we shall tackle it. First of all: because suc(0, x) has only the solutions x = 0 and x = 1, and h₁ ≠ h₀ , it follows that h1 = 1 . Therefore in a permutation satisfying 1) and 2) it follows that h₃₁ = 16, for: suc(16, x) has as only solutions x = 0 and x = 1 and thus, for all i < 31 we have hi≠ 16. In short, we can drop for the permutation requirement 3) as it is implied by the others. -The original inner block as designed by W.H.J.Feijen, was essentially the following one:

| begin virvar x ; privar h, p;
|  | x vir int array := (0) ; h vir int array := (0, 0) ;
|  | p vir bool array := (0, true); do p.dom ≠ 32 → p:hiext(false) od;
|  | do h(0) = 0 → ,
|  |  |  | begin glovar x, h, p; privar c;
|  |  |  |  | if h.dom < 32 → skip
|  |  |  |  |  | ▯ h.dom = 32 →
|  |  |  |  |  |  |  | begin glovar x; glocon h; privar j;
|  |  |  |  |  |  |  |  | j vir int := 0;
|  |  |  |  |  |  |  |  | do j ≠ 32 → x:hiext(h(j)); j:= j + l od
|  |  |  |  |  |  |  | end
|  |  |  |  | fi;
|  |  |  |  | c vir int := 2 *(h.high mod 16);
|  |  |  |  | do p(c) →
|  |  |  |  |  |  | do odd(c) → c, h:hipop; p:(c)= false od;
|  |  |  |  |  |  |  | c:�= c + 1
|  |  |  |  | od;
|  |  |  |  | h:hiext(c); p:(c)= true
|  |  |  | end
|  |  | od
| end .

The extensive exercises, however, have been thrown into the waste-paper basket, because they had a very ad hoc character and the proofs that the resulting programs were resistant to a single malfunctioning either failed or became so laborious as to become unconvincing. It was that disappointing experience that prompted me to try to formulate —“in abstracto” so to speak— what I was really doing, while designing the above robust structure (6). My next experiment will therefore be to try the above general technique in a hopefully systematic manner to this specific program. (In order to keep the experiment fair, I shall not exploit the fact that something more about the answer is known: it has been proved that the number of solutions equals 2048 , but we continue as if this theorem were unknown to us.)

To establish the connection: the general x of (6) corresponds to the output array x of our example and the role of the general z of (6) has been taken over by the pair h, p in our example. Relation P2 is the simple (and not too interesting) one: in our example it is

P2(x, h, p): | the value of the array variable x “consists” of all solutions in alphabetical order that precede alphabetically the permutations that begin with         h(0) ... h.high .

(The term “consists” is loose, but hopefully clear enough. It is further to be noted that in the above formulation of P2 , the boolean “presence” array p is not mentioned.)

Relation P1 is more interesting: it consists of two terms P1.1(h) and P1.2(h, p):

P1.1(h): | for all i satisfying h.lob ≤ i < h.hib we have suc(h(i),h(i+1)
P1.2(h, p): | for all k satisfying 0 5 ≤ k < 32, p(k) implies that there exists 1 value for i, and non p(k) implies that there exists no value for i , such that        h.lob ≤ i ≤ h.hib and h(i) = k .

According to P1.l , the integer array h contains in general redundant information: a boolean array —manipulating the bits of the original statement of the problem would have done the job also—. Feijen replaced the boolean array by an integer array for reasons of efficiency.

According to P1.2 the boolean presence array p stores purely additional information that follows functionally from h; it has been introduced also for reasons of efficiency by Feijen.

And here lies our hope for gain: the redundancy that we need for the robust presentation of z may already be present for efficiency’s sake!

We may wonder, whether the redundancy provided by h and p is sufficient: because p follows uniquely from h , a scrambling of the value of p will always violate P1.2 . It is, however possible to scramble h without violating P1.1 nor P1.2 (it is difficult, but it can be done). This can be remedied by replacing the boolean “presence” array p by an integer “place” array p, satisfying the new

P1.2(h, p): | for all k satisfying 0 ≤ k < 32,
| either p(k) = -1 and there exists no value i satisfying h(i) = k ,
| or 0 ≤ p(k) ≤ h.hib and then i = p(k) is the only value for i ≥ 0 (see below), satisfying h(i) = k.

As the cost is negligible and it is our plan to do a thorough job, I propose to switch to the integer “place” array p. (The last requirement i ≥ 0 has been added because it is a simplification to extend the array h at the low end with h(-1) = 16 for the verification of P1.1 : upon removal of a top element the array h does not become empty.)

The critical operation is now “z:= g(z)”. We must change it so as to satisfy (8) as well. We can, indeed, insert additional tests that would lead to abortion if the intended modification of z would lead to a violation of non P1(z) , but this is not sufficient, because how do we know that the correct new value of z has been assigned to it? (If z:= g(z) would have acted as a skip, we might produce the same solution twice!)

The critical value, of course, is that of “c”: if the initialization of c had erroneously been carried out as

| c vir int := 2 *(h.high mod 16) + 1

a whole class of solutions could be skipped.

So we had better concentrate upon the active scope of c and repeat our games (or similar ones: wait and see). We have for the active scope of c —i.e. more precisely: until the extension h:hiext(c)— if all goes wel the invariant relation

P3(h, c): | suc(h.high, c) .

Because (non P3(h, c)) ⇒ wp(“h:hiext(c)”, non P1.1(h))
it suffices, as far as our obligations versus the invariance of non P1.1(h is concerned, to keep during the active scope, besides non P3(h, c) also non(P1.1(h) and P3(h, c)) invariant, i.e. we do not need to check, whether

| c, h:hipop

perhaps could destroy non P1.1(h), because that would imply the emergence of non P3(h, c), which will not disappear unnoticed.

As P3(h, c) covers the four most significant digits of c, the least significant digit of c seems to be our remaining Achilles heel. I propose to count the number of even numbers among

| h(0) through h(h.hib), extended with c during the latter’s active scop

This will catch erroneous initialization of c ; if the guard odd(c) is erroneously evaluated, an even c will disappear without the count being decreased, if the gaurd is erroneously evaluated false, c:= c + 1 will increase the number of even values, while it should decrease them by one. This count is a kind of fancy parity bit. The full program is shown

begin virvar x, y; privar h, p, n; n vir int := 1;
| x vir int array := (0); y vir int array := (0); h vir int array := (-1, 16, 0)
| p vir int array := (0, 0); do p.dom ≠ 32 → p:hiext(-1) od
| do h(0) = 0 →
|  | begin glovar x, y, h, p, n; privar c;
|  |  |  | if h.dom < 32 → skip
|  |  |  |  | ▯ h.dom = 32 → if p(0) = 0 → skip fi;
|  |  |  |  |  | begin glovar x; glocon h; privar j; j vir int := 0;
|  |  |  |  |  |  | do j ≠ 32 → x:hiext(h(j)); j:= j + 1 od
|  |  |  |  |  | end
|  |  |  | fi
|  |  |  | if h.dom < 32 → skip
|  |  |  |  | ▯ h.dom = 32 → if p(0) = 0 → skip fi;
|  |  |  |  |  | begin glovar y; glocon h; privar j; j vir int := 0;
|  |  |  |  |  |  | do j ≠ 32 → y:hiext(h(j)); j:= j + 1 od
|  |  |  |  |  | end
|  |  |  | fi
|  |  |  | c vir int := 2 *(h.high mod 16); n := n +1;
|  |  |  | do p(c) ≥ 0 → if p(c) ≥ 0 → skip fi;
|  |  |  |  |  |  | do odd(c) → if suc(h.high, c) → c, h:hipop fi;
|  |  |  |  |  |  |  | if p(c) = h.hib + 1 → p:(c)= -1 fi;
|  |  |  |  |  |  | od
|  |  |  |  |  |  | c:= c + 1; n:= n - 1;
|  |  |  | od
|  |  |  | if suc(h.high, c) → h:hiext(c) fi;
|  |  |  | if p(c) = -1 → p:(c) = h.hib fi
|  | end
| od
| if h.dom = 2 and h(0) = 1 and n = 0 .and p(0) = - 1 and p(1) = 0 →
|  | begin glocon p; privar j; j vir int := 2;
|  |  |  | do p(j) = - l and j < 31 → j:= j + l od;
|  |  |  | if p(j) = - l → skip fi
|  |  | end
| fi
end

The comparison of the global values x and y , which should be equal, has been delegated to the surroundings.

(Warning: the proof reading of the program text on page EWD482 - 6 has not b done with the same care as I spent to the pages of my book.)

Let me give some explanatory notes.
The outer guard h(0) = 0 is not repeated automatically, if true: it only matters, when we think that we have found a solution, and then it should be confirmed by p(0) = 0; this means that after the last solution has been found and p(1) is already = 1, it would not be detected if the outer repetition we on for a while. Why should it?

The operations, which are essentially of the form x:= f(x, z) and y:= f(y, z) are themselves fully unchecked: if something goes wrong there that is harmful, different values of x and y will result. Note that the test, whether a new solution has been found is repeated: once for x and once for y .

The conclusion that p(c) ≥ 0 holds, has to be confirmed, otherwise the erroneous conclusion that extension with c would lead to duplication would cause possibly a large collection of solutions to be skipped. (This additional confirmation was lacking in my first version of the robust program I observed the omission while typing these notes!) The conclusion that on account of non p(c) ≥ 0 the repetition has to be terminated is asked for confirmation 7 lines lower.

The test odd(c) in the innermost repetition does not need further confirmation, as all erroneous evaluation would leave its traces in a non-correct value of n.

Finally, at the end of our original program, it is checked —somewhat superfluously— that h.dom = 2; the test h(0) = 1 is necessary for the confirmation that the outermost repetition has not stopped too early, thereby possibly missing a number of the last solutions. Finally P1.2(h, p) is fully checked. (We can regard the test h.dom = 2 as part of that test, so perhaps its presence is fully justified after all.)

And this concludes my treatment of this example.

*              *
*

As the plurals in my title betray, I had originally in mind to deal wit more examples. At second thought I shall confine myself in this report to thi single example: I am already on the eighth page, with single space typing. Although I had announced, that the exercises would be “rather painful ones”, I did not expect, that it would be so painful. So I think that I should send the report now away, as it stands, hoping for helpful comments. Therefore a f concluding remarks. If the inefficiency of our final program “hurts”, we should be aware of the following considerations. Why does it “hurt”? Well, because the many test that we have inserted, are on the one hand assumed to absorb computer time, on the other hand —unless the machine is completely lousy— will be very skew: of course, for if the machine were perfect, they would not give information at all! The normal reaction to such very skew tests has been to devote dedicated hardware to them (vide the parity check or the interrupt circuit). If techniques, as displayed in this report, would be applied to general purpo programs —note, that I have not made up my mind, whether-that would be a goo thing!— this conflict could perhaps be solved by the presence of some program-controlled hardware that could do some of the checking in parallel with the main computation.

For the time being, techniques as shown are probably more appropriate in special purpose environments, such as, for instance, micro-programs or just the instruction cycle. One of the reasons for undertaking all this was my growing doubt, whether our techniques for the quality control of both, chip design and chip construction, is sufficient. If techniques like the abov can be transferred to that more microscopic level, we might feel confident to catch in a single stroke both design errors and incidental machine malfunctionings.

20th March 1975 | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NUENEN - 4565 |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

8 maart 1977 EWD 483

Vierde toespraak tot mijn studenten.

Kort na de tweede wereldoorlog, toen U nog niet bestond, vestigde mijn leraar voor natuurkunde onze aandacht er op, dat we het Stenen Tijdperk gehad hadden, daarna het Bronzen Tijdperk, daarna het IJzeren Tijdperk en daarna, in Nederland tenminste, de Gouden Eeuw, maar dat de 20ste eeuw de historie zou ingaan als de Eeuw van de Incompetentie (waarna hij overging tot de orde van de dag). Ik wil daar, meer dan een kwart eeuw later, nog wel een bescheiden schepje bovenop leggen: hij zal in de historie geboekstaafd worden als de Eeuw van de Fraude. Het gaat hier om het wijdverbreide verschijnsel, dat de zandstrooiertjes vergoelijkend aanduiden met "wishful thinking", maar voor onbestrooide ogen niet anders is dan gewoon, vulgair bedrog, nl. het bedrog dat daaruit bestaat, dat het verlangen iets te doen, klakkeloos vervangen wordt door het geloof, en daarna de pretentie, zulks ook te kunnen.

We kennen ze allemaal: de economen, wier deskundigheid de recessie niet verhinderd heeft, de marketing deskundigen op wier advies producten op stapel zijn gezet, die we nu aan de straatstenen nog niet kwijt kunnen, de psychologen en paedagogen, die met de mammoeth het middelbaar onderwijs platgewalst en de eindexamenbul tot een vodje papier gemaakt hebben, de sociologen, die de verloedering in het besturen van de gemeente Amsterdam zo deskundig begeleiden, etc. We kennen ze allemaal, de zich in pseudo-wetenschappelijkheid verhullende kwakzalvers.

Dit grootscheepse bedrog is helaas nu zo wijdverbreid, dat allerlei jonge mensen niet beter meer weten, of het hoort zo. Zij vinden het de normaalste gang van zaken als een stel dilettanten, in plaats van te regeren, doelloos aan het roer van het schip van staat rukt en deze panische activiteit dan ook nog presenteert als onze glorieuze vaart naar de socialistische heilstaat; zij vinden het normaalste zaak van de wereld, wanneer het wetenschapsbeleid op ministerieel niveau wordt toevertrouwd aan een gesjeesd student en op plaatselijk niveau aan een allegaartje, dat in universiteits- of hogeschoolraad op verbale stokpaardjes zijn ideologische toernooien opvoert.

Met al die opdringerige charlatannerie om ons heen lijkt het voor velen steeds moeilijker om nog onderscheid te maken tussen de vele kwakzalvers en de enkele vakman, tussen de met veel propaganda aangesmeerde leuzenmakerij en de werkelijk, en dus bescheiden competentie. Velen hebben de moed, dit impopulaire onderscheid te maken, opgegeven en reageren met "Ach, het is allemaal één pot nat." en scheren gemakshalve iedereen, die iets te zeggen heeft, over de kam van de praatjesmakers. Het door de zogenaamde "soft sciences" geinstitutionaliseerde bederf heeft het zaad der desillusie in de wetenschap uitgestrooid, waaruit 't inmiddels alom verbreide anti-intellectualisme is voortgesproten. Dit is verontrustend, want nu wordt met het inderdaad smerige badwater een waarlijk schoon en onmisbaar kind weggegooid.

Want onmisbaar is het kind! Lang is de lijst van organisaties, die nadat ze iets geentameerd hadden, waarvoor de competentie ontbrak, hetzij op de fles zijn gegaan, dan wel kans gezien hebben het vege lijf te redden door, dankzij gechicaneer, de maatschappij met hun minderwaardig product op te zadelen. Zo redden soms firmas hun bestaan, soms regeringen, soms denken ook universiteiten zo hun hachje te kunnen redden: afstudeerrichtingen, waarvoor de wetenschappelijke discipline, die hen schragen moet, vooralsnog ontbreekt en die de studenten uiteindelijk met een leeg hoofd afleveren, zijn daarvan een schrijnend symptoom.

Na U gewaarschuwd te hebben, geen slachtoffer van academisch bedrog te worden, gaan wij over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

  EWD 484

Trip report E.W.Dijkstra, London, 9–10 March 1975.

This will be a short report on a short trip. I flew from Amsterdam to London (Heathrow) on Sunday afternoon and returned —with a direct(!) flight from London (Gatwick) to Eindhoven— on Monday evening, to be back in time for my Tuesday lectures at the University. Both flights were absolutely punctual (KLM and NLM respectively) and no misery about that part of the trip is to be reported. A number of people —in particular the Conference chairman, my good friend Mike Woodger and Infotech's Ian Hugo— expressed their regret that I could (or did) not stay for the full three days of the Conference, but I did not regret my quick return: the arrangement of the emergency exits in the Regent Centre Hotel in London seemed to me to be such that I was quite happy to have survived the one night I had to stay in that place. (A minor complication was further that all personnel were from non-English speaking countries and that most of the service had been delegated to slot machines that were out of order. Horst Heunke —from GDM, Bonn— was furious!)

Upon arrival in the Hotel, I discovered —by looking over the girl's shoulder— that at the porter's desk there was a message for me; it had been dictated over the telephone and the written rendering of it was not quite clear, but I figured out that I would be met in the hall at the ground level at about seven o'clock by Hugo from Infotech. Just to be on the safe side I checked with the girl at the reception that the next morning I should not pay, but only sign the bill, as Infotech had promised to pay my expenses, but that part of the arrangement was unknown at the reception (as usual). Later in the evening, two people from Infotech have spent more than fifteen minutes clearing that up. I found Horst Heunke, who was also expected to speak at the conference and had dinner with him and a next speaker (Thompson from Bell Labs) and a few people from Infotech. At ten o'clock Horst and I left the table and went for a refreshing walk. From eleven to twelve o'clock Horst and I have had a glass of whisky in my room and when Horst had left me, I have written for an hour or so. To talk with Horst is always very instructive for me, because the worlds in which we live have a very nearly empty intersection: but it is correspondingly hard to communicate. Horst is absolutely full of how to live with the IBM360 (hard by itself), how to live with the German government (also hard by itself) and how to live with the combination of the two. It seems impossible, but he is still very much alive: I have a slight suspicion that he likes it. He told me that Carl Adam Petri has not gone to Dortmund, but had stayed at the GMD, and heard that some illuminating stories about the German end of the "Mariage a trois" that the world knows under the name UNIDATA.

On Monday morning we walked from our hotel to the Piccadilly Hotel, where the Infotech Conference was held. (The original estimation was 80 people, but the title "Structured Programming" —what else?— had attracted about 280 participants, and they had had to move locations.) A walk through London in the early morning is somewhat depressing; the Piccadilly Hotel's main distinction seems to be worn carpets and primitive toilets. Mike opened the Conference at 9.30 and then acted as the first speaker. His talk was well prepared and quite nice, although perhaps a little bit boring. After the coffee break, during which I prepared some visuals, I had to perform.

The Infotech protocol is a very tiring one. It has been designed on the assumption that the "delegates" —although the texts are handed out at the beginning of the Conference— cannot read and that therefore the speaker is expected to read his text —or what is written on his visuals— slowly and in a clear voice. (Speaker's instructions are of the nature "First announce what you are going to say, then say what you have to say, and finally summarize what you have said.") I find this protocol very irritating. So I have started to comment for at least twenty minutes on my two visuals, and only then started to read my text. But then I heard the pages being turned in the audience, so this time the delegates could read, and from then onwards I departed more and more from my text (which was not very good anyhow: it had been produced under great pressure during two nights). My second visual was a four line program that I had tested by "desk simulation". No one saw the bug, so, after they had been looking at it while I was reading, I pointed out "the" case that went wrong, and repaired the program. Another fifteen minutes later, when I really did not feel like going on with the reading of my text, I told the audience that the program was still not OK. Mike more or less suggested that I should tell what was wrong, but I refused to do so and asked the audience to spot the error: it took them another few minutes, and I think that that (although a little bit cruel) drove the message home.

I had a pleasant lunch with Martin Richards from Cambridge and was picked up at two o'clock by Mr.Bachelor from Burroughs, who had arranged a lecture for people from Burroughs. (The location was a conference room in one of the buildings of Barclay's Bank, near Victoria Station, apparently conveniently located.) I spoke there for quite an inspiring audience from half past two until half past four. I used the opportunity to try out a semi-prepared talk that I am expecting to give next month at Berkeley and at Stanford. And it is a good thing that I tried it out, because it became clear that it needs some further work on it. As I had been warned that during the rush hour a train ride to Gatwick could not be expected to be very comfortable, I gratefully accepted Mr.Bachelor's offer that the chauffeur should drive me to the Airport, where I had a ham sandwich and a glass of milk (courtesy NLM, because nothing was served during the flight).

When I arrived at a quarter to ten at Eindhoven's tiny airport Welschap, it was as if war had just broken out, say the Belgian army crossing the frontier at the Eykse Barriere: the airport was fully guarded by soldiers with arms and dogs, and there was floodlight all over the place. I have no explanation....

Shortly after ten o'clock I was home again, reading the mail that had arrived that day.

12th March 1975 Plataanstraat 5 NUENEN – 4565 | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Wed, 24 Aug 2005

  EWD 485

16th March 1975

Marketing Questionnaire "A Discipline of Programming."

1. | Title: | A Discipline of Programming.
2. | Author: | Edsger W.Dijkstra (Ph.D., Amsterdam), Burroughs Research Fellow and Professor Extraordinarius at the Technological University Eindhoven, the Netherlands.
3. | About the book: | Presents programming for automatic computers as a scientific discipline. Stresses the formal aspects of correctness proving and program derivation as well as the informal aspects of problem solving.

4.
Outstanding features:

1.
It introduces "predicate transformers" as a means of defining the semantics of programming languages.

2.
About alternative and repetitive constructs theorems are derived which are of actual assistance in the act of program composition.

3.
It stresses total correctness over partial correctness.

4.
The treatment is not restricted to fully deterministic programming languages.

5.
In a series of worked-out examples great attention is given to the intertwined processes of problem solving and program development; for a longer program that solves a more difficult problem, the true design history is fully recorded.

6.
It uses a sober but well-chosen notation technique for programs and the reader, whose attention is no longer side-tracked by a wealth of fancy programming language features, can now concentrate upon the more fundamental aspects of the programming task.

5. | Teaching and learning aids in the book: | The book does not contain the usual type of confusing diagrams (it contains, as a matter of fact, hardly any illustrations).
6. | Supplementary teaching material: | None.

7.
Table of contents:
Table of contents: Preface. Executional abstraction. The role of programming languages. States and their characterization. The characterization of semantics. The semantic characterization of a programming language. Two theorems. On the design of properly terminating constructs. Euclid's algorithm revisited. The formal treatment of some small examples. On non-determinacy being bounded. An essay on the notion: "The scope of variables". Array variables. The Linear Search Theorem. The problem of The Next Permutation. The problem of The Dutch National Flag. Updating a sequential file. Merging problems revisited. An exercise attributed to R.W.Hamming. The pattern matching problem. Writing a number as the sum of two squares. The problem of the smallest prime factor of a large number. The problem of the most isolated villages. The problem of the shortest subspanning tree. Rem's algorithm for the recording of equivalence classes. The problem of the convex hull in three dimensions. Finding the maximal strong components in a directed graph. On manuals and implementations. In retrospect.

8.
Competing books:
Richard Conway, David Gries, "An Introduction to Programming" (Winthrop Publishers Inc., 1973) paperback, 460 pp. $??.??. More than 220 pages are devoted to the description of the idiosyncrasies of the programming language of their choice, leading to complicated treatment of simple problems, compared to Dijkstra's simple treatment of complicated problems.
Niklaus Wirth, "Systematic Programming: An Introduction" (Prentice-Hall, 1973), hard cover, 167 pp. $??.??. Only one sixth (25 pp) of this book deals explicitly with the act of programming, and much of its space is devoted to truly introductory material, in contrast to Dijkstra's more advanced treatment that does not deal with things such as number systems, the ASCII character code, etc., which can be found in any other book on computers and programming.

transcribed by Tristram Brelstaff
revised Tue, 6 Feb 2007

EWD 486

Vijfde toespraak tot mijn studenten.

De sectie Informatica van de Academische Raad heeft een zogenaamd "Structuurplan" opgesteld met betrekking tot het wetenschappelijk onderwijs, een structuurplan, dat gericht is tot het Departement van Onderwijs en Wetenschappen. Over de inhoud van dit structuurplan, hoe abominabel ook, wil ik het met U niet hebben. Het is nl. belangrijker om met U te spreken over wat ik de afwezigheid van inhoud zou willen noemen, en over de bedroevende vorm van dit rapport.

Het Nederlands, waarin dit rapport gesteld is, is ronduit erbarmelijk: hele woordreeksen betekenen niets, omdat er met de beste wil van de wereld geen goed Nederlands in te lezen is; andere zinnen, hoewel grammaticaal correct, betekenen ook niets, omdat ze zijn opgebouwd uit loze kreten. En waar het voorstel wel iets inhoudt, getuigt het van een incompetentie en een naieviteit, die niet meer ontroerend te noemen is: schandalig is een meer adequate term.

In het natuurlijk taalgebruik wordt de semantiek van wat wij zeggen en schrijven bepaald door hoe de ontvanger op onze uitingen reageert. Als ik U in heldere termen bijvoorbeeld de klokparadox uit de relativiteitstheorie zou uitleggen, zou U —dat hoop ik tenminste!— dat begrijpen en zou ik iets van een verbijsterende consistentie hebben beschreven. Als ik evenwel woordelijk ditzelfde verhaal zou afsteken tegen een klein buurjongetje van drie jaar, dan zou die zelfde toespraak plotseling leeg en betekenisloos zijn. In het conversationeel gebruik van de natuurlijke taal bepaalt het bevattingsvermogen van de toegesproken, wat onze uitspraken betekenen, en bepaalt ons beeld van de toegesprokene dientengevolge ons taalgebruik. Als we tegen een idioot praten, generen we ons niet, als we onzin uitkramen, want dan mag dat. In dit licht bezien is het rapport van de sectie Informatica van de Academische Raad ronduit een belediging aan het adres van de ambtenaren ten departemente, die geacht worden dit stuk te lezen en niet in dit drijfzand van taalmisbruik te verzinken.

Nou kan je natuurlijk proberen je hiervan af te maken en zeggen: ach, dit stuk is niet zo gelukkig uitgepakt, het is een beetje een compromis, dat in eerste instantie is opgesteld door vier hooggeleerde lummels, en de rest van de sectie, die het allemaal ook zat was, heeft zich er moedeloos mee accoord verklaard. Als dat mijn enige commentaar was, zou ik er verder niet over spreken: er worden immers wel vaker stukken geproduceerd, die bij nader inzien niet door de beugel kunnen. Ad nauseam, mogen we wel opmerken.

Maar er is iets veel angstigers: bij het merendeel van de mensen, die dit rapport onder ogen krijgen, wekt zijn erbarmelijkheid niet eens meer verbazing, laat staan verontwaardiging: men accepteert als de normaalste zaak van de wereld, dat stukken, die naar het departement worden gestuurd, van kaft tot kaft van de leuterkoek aan elkaar hangen. Wil het departement een structuurplan hebben? Goed, krijgt het departement een stuk, dat er als een structuurplan uitziet. Men heeft afgeleerd, ook maar de minste eisen te stellen ten aanzien van de eventuele inhoud, het enige wat telt is de existentie van het rapport: in plaats van een bijdrage volstaat men met een oppervlakkige nabootsing. En als je je over dit culturele bederf openlijk zorgen maakt, kijken de meeste mensen, alsof ze snot zien branden. En als ze merken, dat je ondanks hun vergoelijking in je bezorgdheid volhardt, word je als hinderlijk spelbreker beschouwd. Maar ik moet soms denken aan de geslachte kip, die zonder kop nog een paar stappen doorstrompelt.

Ik hoop, dat U even zorgvuldig geluisterd hebt, als het voorafgaande is opgesteld.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

  EWD 487

20 March 1975

Letter to the Burroughs Recipients of the EWD-series.

My dear Reader,

The other day I heard that by casting some doubts on the central role of recursion, I had caused commotion at some places within the Corporation. Although such was not my intention, I think that is great! Ours is such a young discipline that the separation between folklore and science still requires our conscious, continuous attention. Articles of faith are both a blessing and a curse: they are a blessing in so far as they embody a continuity of intellectual style —without which no company of products with a high technology content can survive—, they are a curse in so far as they may escape being challenged when their time has come. The mere fact that on the whole our competitors' products are so extremely poor at implementing recursive algorithms engenders, of course, the danger that inside our Corporation recursion, indeed, becomes an article of faith. But —periodically and not at too high a frequency— articles of faith have to be challenged: if they survive, fine, for then we know better why we have chosen them, but if they don't, also fine, because then we have freed ourselves of what in the mean time should have been unmasked as a superstition. Challenging (consciously or not) now and then an article of faith within the Corporation seems one of the more valuable ways in which I can contribute and, therefore, I am glad to discover that I have done so. But that is not why this letter is written to you.

This letter is written to you, because I heard of this commotion by pure accident, and that did not seem right to me, when I started to think about it.

When addressing an audience orally, I have learned how to avoid keeping a monologue ("I am quite used to the processing of interrupts." is the standard joke that some of you may remember.). But now I am addressing an audience by mail-and-Xerox, and it was something of a shock for me to realize that from all my reports that have been distributed inside Burroughs Corporation, hardly any reaction has reached me. This letter, therefore, is a plea not to hesitate to react, drop me a line when you feel like it.

Of course I do not expect everybody of you to study (and to react to) everything I write: the spectrum is broad enough that, quite naturally, parts of it fall outside your interests. But some of it should fall within your interests (otherwise you should not receive them!). And with respect to the documents within your interests, it would be nice if you dropped me a line now and then.

If you like them, or if they are helpful, I would like to hear so: even I can do with occasional encouragement. If you don't understand them, and would like to do so, don't hesitate to ask for clarifications, for such requests are most essential for me: they are the feedback that is indispensable for anyone who would like to continue to reach his audience effectively. If you don't agree with my conclusions or feel that I am committing a glorious oversight, please say so, for you may be right and your correction will be most welcome. To a certain extent I am dependent on and, therefore, eager to learn from your combined, extensive experience.

Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 8 Nov 2004

26 maart 1975 EWD 489

Zesde toespraak tot mijn studenten.

De mensen kunnen verdeeld worden in twee categorieen: enerzijds zij, bij wie de verontwaardiging een keer zo hoog is opgelopen, dat ze een Ingezonden Brief aan de krant gestuurd hebben, en anderzijds zij, die, hoe zwaar ook beproefd, tot nog toe aan deze verleiding weerstand hebben kunnen bieden. Lang heb ik tot de laatste categorie behoord, totdat de huidige premier door met de principes van de rechtsstaat te sollen mij ongeveer een jaar geleden mijn zelfbeheersing deed verliezen. Ik kon een week later, nog wat confuus van het gebeurde, enige troost putten uit het feit dat toen ook de volksvertegenwoordiging hem voor dit slippertje op de vingers tikte. Of hij dat ook gevoeld heeft, wist de krant er niet bij te vermelden.

Het blote feit je maagdelijkheid verloren te hebben, betekent natuurlijk niet, dat je daarna ongebreideld het slechte pad kunt opgaan, en ik kan U gelukkig mededelen, dat ik mij sindsdien niet meer aan Ingezonden Brieven heb bezondigd. Hoewel het onlangs wel weer veel moeite kostte! Maar ik was heel streng tegen mezelf en zei op barse toon "Doe dat nou niet! Deze keer doet een ander dat wel!" En wat is er gebeurd? Niets.

De krant wist te melden, dat de assemblage van Ford Cortinas te Amsterdam gestaakt werd, omdat in Engeland, waar de onderdelen gemaakt worden, de verzending der onderdelen niet gecontinueerd werd, zulks op last van de Britse vakbonden.

Het was die laatste toevoeging "op last van de Britse vakbonden", die allerlei boeiende vragen opwerpt. De eerste is bijvoorbeeld "Wie regeert Engeland? De Britse regering of de Britse vakbonden?". In het bijzonder: wie maakt de Britse buitenlandse politiek uit? Ik vind, dat onze regering dat wel weten moet. Per slot van rekening moeten wij over allerlei zaken met Engeland onderhandelen, en stel je voor, dat onze regering allerlei afspraken met de Engelse regering maakt, die bij nader inzien voos blijken te zijn, omdat ginds niet de regering de koers uitzet, maar de vakbonden de dienst —of: de non-dienst!— uitmaken. Aan wie de Britten het heft in handen willen geven moeten ze tot op zekere hoogte zelf weten, maar onze regering heeft recht op klaarheid en zou bij de haar bevriende Labourregering —zolang die nog te spreken is— eigenlijk eens haar licht moeten opsteken.

Want dat plotseling stopzetten van die onderdelenstroom is natuurlijk wel een complicatie: hier was in Amsterdam de werkgelegenheid van duizend man mee gemoeid. En de assemblage van Cortinas in Engeland worstelde met werktijdverkortingen. Dat zinde de Britse vakbonden niet, want als een fabriek wegens tekort aan werkgelegenheid plat ligt, kan je niet staken en daarom moest die onderdelenstroom naar het Engelse assemblagebedrijf worden omgebogen. Heel eenvoudig. Het feit dat de in Nederland geassembleerde Cortinas gemiddeld beter waren, zodat zelfs de Engelse klant liever een uit Nederland geimporteerde Cortina dan een van eigen bodem kocht, heeft of geen rol gespeeld, of een duistere. Zeker is, dat ook dit keer de deugd niet beloond is.

Er is nog een brandende vraag, die in mij opwelt. Als onze Nederlandse vakbondsleiders, zoals ze geregeld doen, de mond volhebben van "de internationale solidariteit der vakbonden", weten zij zelf dan nog, waarover ze het eigenlijk hebben? Het lijkt me strooizand.

Na aldus geen brief aan de krant te hebben gestuurd, ga ik over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

  EWD 492

2nd April 1975

On-the-fly garbage collection: an exercise in multiprocessing.

(After careful consideration of a wider class of problems, A.J.Martin and E.F.M.Steffens selected and formulated the following problem and did most of the preliminary investigations. I arrived at its solution during a discussion with the latter, W.H.Feijen and M.Rem. It is a pleasure to acknowledge their share in its discovery.)

With the emerging advent of multiprocessor installations, all of us have discovered that it is by no means obvious how a great number of processors should be engaged in a single task. One line of attack has been —and still is— to try to discover problems that can be solved by a great number of concurrently active processors; on the one hand we are inspired and encouraged by some spectacular results, on the other hand it is somewhat discouraging that these techniques are always only applicable thanks to the rather special nature of the specific problem to be solved. The other line of attack is inspired by the observation that any large scale computer installation today, a considerable amount of time of the (general purpose) processor is spent in "operating the system" and the question, therefore, emerges to what extent these "special purpose" activities inside a rather general purpose installation can be done concurrently with the execution of users' programs. Because the more intimate the interference, the harder the organization of the cooperation between the concurrent processors, the problem of garbage collection was chosen as one of the most challenging —and, hopefully: most instructive!— targets. Whether the following solution is of any economic significance is beyond the scope of this report: for the time being it suffices to be fascinated by its existence.

In the traditional LISP-environment the data structure to be stored at any moment is a directed graph in which each node has at most two outgoing edges. (By introducing a virtual target, called NIL, each node can always be given exactly two outgoing edges, a left-hand edge and a right-hand edge.) As a result the storage requirements for each node can be regarded as constant in time and equal for each node. The whole data structure has one node —called: the root— with a constant place in memory; at any moment only those nodes that via the edges can be reached from the root are significant for the progress of the computation. The computation consists essentially of two operations: either replacing for a node one of its outgoing edges by one with (another) existing node as its target, or by one pointing to a new target, i.e. a new node is to be added to the data structure. In the latter case the number of nodes of the data structure is increased by one: the new node is taken from the so-called "free list" —i.e. a linked list of node locations that are currently not used for storing a node of the data structure—. In the first case the number of nodes either remains constant or it decreases by a rather unpredictable amount: the removed edge may have been the last connection from the root to a possibly elaborate subgraph. It is the purpose of the so-called garbage collector to detect such disconnected and therefore obsolete nodes and to append them again to the free list.

In classical LISP-implementations the computation proceeds until the free list is exhausted (or nearly so). Then the LISP-computation comes to a grinding halt, during which the central processor is devoted to garbage collection, i.e. starting from the root the transitive closure as given by the current edges is established and all the nodes in memory outside this transitive closure —i.e. not reachable from the root and therefore obsolete— are appended to the free list, after which operation the LISP-computation can proceed. The minor disadvantage of this arrangement is the central processor time spent on the collection of the garbage, its major disadvantage is the absolute unpredictability of these garbage collection interludes, which makes it virtually impossible to design such a system so as to meet real time requirements as well. It is therefore tempting to investigate whether a second processor —called "the collector"— could collect garbage on a more continuous basis, concurrently with the activity of the other one —for the purpose of this discussion called "the mutator"— which is dedicated to the LISP-computation proper. Two additional constraints have to be obeyed: the (macroscopic) interference between collector and mutator should be minimal —i.e. no highly frequent mutual exclusion of elaborate activities— and, also, the overhead on the activity of the mutator (as required for the cooperation) should be kept as small as possible.

A certain amount of overhead for the mutator, alas, is unavoidable. Suppose that nodes A and B are permanently connected to the root via a constant set of edges, while node C is only connected to the root via an edge from A to C. Suppose furthermore that from then onwards the mutator performs with respect to C repeatedly the following four operations:

1) make an outgoing edge from B pointing to C

2) make the edge from A to C pointing to another node

3) make an outgoing edge from A pointing to C

4) make the edge from B to C pointing to another node.

The collector, which observes nodes one at a time, will discover that A and B can be reached from the root, but never needs to discover that C can be reached as well: while A is observed, C may be connected via B and the other way round.

Suppose that all nodes may have one of four colours: white, grey or black for nodes in the data structure and green for nodes in the free list. (Whether the colour green is necessary is a question that I leave open: it certainly eases the description.) Suppose that all nodes in the free list are green and all other nodes are white. Collector and mutator will now start to colour nodes that can be reached from the root black, but in general this will happen via grey as intermediate colour. They do so, observing two rules:

a) nodes will only darken monotonically (where green is regarded as light as white)

b) no edge will ever point from a black node to a white one.

The mutator will act as follows. If it adds a new node to the data structure —i.e. takes a green node from the free list— the mutator will make the source node of the new edge grey if it has observed it to be white and will leave the colour of the source node of the new edge unchanged if it has observed it to be grey or black; it changes the colour of the target node of the new edge from green to black. If the mutator makes an edge pointing to a node already in the data structure (i.e. currently pointed at by another edge), it will subject both source and target node of the new edge to the same treatment: make it grey if it has been observed to be white, otherwise leave its colour unchanged. For an increase of the number of grey nodes as a result of the mutator activity, the presence of at least one white reachable node is therefore a necessary condition.

The collector starts by making the root grey. It then looks for grey nodes: for each grey node it inspects its two successors (i.e. target nodes of its outgoing edges); if a white successor is found, it is made grey, otherwise its colour is left unchanged; when both its successors have thus been processed, the originally grey node —which could be its own successor!— is made black.

Note 1. Several times we have said "if the node has been observed to be white it will be made grey, otherwise its colour will be left unchanged". We have intentionally avoided to say if its colour has been observed to be grey (or black) its colour will be made grey (or black). In that case the mutator could observe a grey node and make it grey, just after the collector has made it black, thus undoing the collector's activity. (End of note 1.)

Note 2. We have assumed that the observation of a node colour will never lead to the observation "white" while the other partner changes it from grey to black. (End of note 2.)

Note 3. The collector inspects the successors of a node observed by it to be grey. The mutator may simultaneously change the outgoing edges of that node. It is assumed that the collector will be directed towards either an old or a new successor and everything is safe provided that the mutator first adjusts the colours of the end nodes of the new edge and only places the new edge afterwards. (End of note 3.)

Besides (possibly) belonging to the data structure or the free list, the nodes are linearly ordered by their order in store. The collector can then inspect them all, in cyclical order, say. When during a cyclic inspection of all nodes, the collector has found no grey node, all reachable nodes (and possibly more, viz. nodes that have been reached in the past) are black —the proof of this statement is not fully trivial— and the mutator can create no new grey nodes any more. Any nodes now white, will remain white: the collector can therefore add the now white nodes to the free list (by colouring them green etc.). After having done so, the nodes in the free list are green and all other nodes are black. In synchronism —but this is a relatively infrequent occurrence— collector and mutator now invert their white/black interpretation (grey remains grey and green remains green) and the game starts all over again.

To fill in the further details —such as arranging the free list as a first-in-first-out list so as to make simultaneous extension by the collector and consumption by the mutator possible, etc.— and to prove that it is all safe and sound requires great care, but it can be done. (I know even people , who could certainly do it, such as Alain J.Martin of Philips Research Laboratory, Leslie Lamport of Massachusetts Computer Associates Inc. and probably Severo M.Ornstein of Bolt, Beranek and Newman Inc. or one of his colleagues.)

*                        *
      *

As said in the introduction, a claim of economic significance is not made. The significance of the above solution lies in the fact that it displays a way of non-trivial cooperation between loosely coupled processors which differs rather radically from the usual communication via messages or mutually exclusive access to common variables. As the reader will have realized, the monotonicity argument (rule a) is as essential as the invariance (rule b). Finally, in order to enable the collector to detect termination, it is essential that the mutator colours green nodes immediately black (as far as rules a and b are concerned, grey would have been permissible as well). Isn't it fascinating?

2nd April 1975
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 13 Nov 2006

EWD493

U studeert af op een moeilijk ogenblik, Uw studietijd is samengevallen met een periode waarin het universitaire bedrijf door sterke groei uiteindelijk in grote moeilijkheden is geraakt. De moeilijkheden zijn bekend: het hoger onderwijs dreigt een ondraaglijk groot gedeelte van het budget op te slokken, de toename van de quantiteit kon slechts gerealiseerd worden door een bijkans evenredige afname van de qualiteit voor lief te nemen en de arbeidsmarkt weet met deze grote aantallen nieuwe academici niet goed raad. Allerlei instanties hebben van het ontstaan van deze misstanden de schuld gekregen.

Een gebruikelijke zondebok is het universitaire bedrijf zelf: vooral uit de mond van hen, die nu bezuinigingen bepleiten, wordt vaak het verwijt gehoord, dat de universiteit in de afgelopen vijftien jaar deze groei zelf gewild en gestimuleerd heeft. In zijn ongenuanceerdheid is dit verwijt absoluut onrechtvaardig en ik stel er prijs op deze aantijgingen hier in het openbaar tegen te spreken. Al zeker tien jaar vervult de opgedrongen schaalvergroting —en niet in de laatste plaats vanwege het hierdoor geinduceerde qualiteitsverlies— velen in de universitaire wereld grote zorg. Men kan het ten hoogste verwijten, dat zij, uit een misbegrepen plichtsbesef, zich er niet duchtiger tegen hebben verzet. Dat dit plichtsbesef —"meedoen, om erger te voorkomen"— veel van het plichtsbesef van de collaborateur heeft, is niet vreemd aan het schuldbesef dat nu aan velen hunner knaagt.

Een andere zondebok —hoe kan het ook anders!— is het bedrijfsleven, dat gefaald zou hebben door herorientering de bakens te verzetten. Ook dit verwijt is onrechtvaardig. Jaren geleden hebben optimisten wellicht oprecht gedacht, dat het werk waarvoor je een goed academicus nodig hebt, ook wel door twee halfwas-academici gedaan kon worden, maar nu gelooft alleen een struisvogel dat nog: geen tien mensen met slechts populair-wetenschappelijke kennis maken samen een geleerde, evenmin als een paar amateurs samen achter het toetsenbord de rol van een concertpianist kunnen overnemen. Wie kennis spreidt, spreidt domheid, want een wezenskenmerk van kennis is concentratie.

Naast de vraag naar de schuld is er de vraag, wie de tol betaalt. Het ligt erg voor de hand de nu afstuderenden als de kinderen van de rekening te zien. Op langere termijn is dat echter de halve waarheid maar, want op den duur dreigt ons hele volk de wrange vruchten van een ontbrekende elite te plukken: kleurloze mediocriteit op alle niveaus. Zolang een intellectuele elite afgeschilderd wordt als een zich ten koste van de rest bevoordelende priesterkaste, in plaats van als de kurk waarop onze beschaving drijft, is er weinig hoop. Het tuig, waarmee president Nixon zich omringde, gebruikte de term "elitair" graag om speciaal de meer integeren onder zijn tegenstanders verdacht te maken; laat ons hopen, dat dit een dieptepunt is geweest, van waar uit het eerherstel van de onmisbare elite zal kunnen plaatsvinden. Maar het zal een lange weg zijn, zeker in alle landen, waar nivellering als politiek ideaal geaccepteerd wordt.

U hebt als student een veelbewogen periode uit de universitaire wereld meegemaakt, soms verheffend, maar meestal minder verheffend. Ik zou me kunnen voorstellen, dat U met droefnis, misschien niet zonder wrok, zou vaststellen, dat de omstandigheden Uw studententijd aardig hebben bedorven, zoals, naar objectieve maatstaven gemeten, een goed deel van mijn jeugd door krijgsgewoel is "bedorven". Dat ik toch met dankbaarheid aan mijn jeugd terugdenk is, omdat ik dankzij de bedreigingen van toen beter weet wat mij nu dierbaar is een waarom. Moge het U gegeven zijn op een soortgelijke wijze eens, in weerwil van al zijn gebreken, in dankbaarheid op Uw studententijd terug te zien.

Met het behalen van Uw academische graad wil ik U graag van ganserharte gelukwensen, een felicitatie, waarin ik uit de aard der zaak eveneens Uw familie en overige U dierbaren wil betrekken. Ik moge eindigen met de wens, dat U een loopbaan beschoren zal zijn, die U tot in de lengte Uwer dagen voldoening zal blijven schenken.

transcribed by F. Koenders
revised Thu, 13 Nov 2008

Copyright Notice

The following manuscript

EWD 494: Trip report E.W.Dijkstra 16th April/7th May, U.S.A. and Canada

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 120–128 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

9th may 1975 | EWD 494

Trip report E.W.Dijkstra 16th April/7th May, U.S.A. and Canada.

With a Boeing 707, which can remain in the air for 11 hours and 45 minutes, our flying time from Amsterdam to Los Angeles was 11 hours and 30 minutes. One of the advantages of that flight is that upon arrival at Los Angeles no more time is wasted upon circling above the airport! At Immigration I found myself speeding up the proceedings by acting as a German-English interpreter between elderly Lufthansa passengers and the young (and beautiful) female U.S.Immigration officer, all in my own interest, because I wanted to catch my connection to San Francisco. (It worked.) For the benefit of my readers who enter the USA at Los Angeles as transit passenger the following advice:

1) get your luggage booked through to at least your next destination in the USA: already in the Custom's Area, your luggage will be placed on an "Express Belt". It works!

2) try to get TWA as your next carrier: from the International Arrivals to the TWA-building is really within walking distance (and on US airports, walking distances are very rare indeed!).

I caught my connection and at 22.00 (their time!) I was picked up by my host, Tony Wasserman, who drove me to his home. After some talking, two hard-boiled eggs, a glass of cold milk and a few glasses of whiskey I went to bed and slept from midnight until 6 o'clock in their morning. At 7 o'clock we had breakfast and then my host —who was Chairman of ACM Pacific 75— and his wife disappeared and I was left to myself. For one and a half hour I studied the Vol.1 nr.1 of the IEEE Transactions on Software Engineering. (With the exception of the Liskov-Zilles paper that was at least instructive, that first issue seemed to me alarmingly weak and I was glad to have refused to join its Editorial Board. The biographical blurbs about the members of that board —no doubt supplied by the subjects themselves— were very amusing when compared against each other! At Los Angeles, next week, many others would express their disappointment about that first issue.) Vol.1, nr.1 proved sufficiently soporific on that Thursday morning for another two hours of undisturbed sleep on the family couch. The net effect was that, at noon, I had had eight hours time shift. That was fine and reassuring, for it was with considerable trepidation that I had been looking forward to my commitments: a lecture on that Thursday at Berkeley at 4 o'clock (= midnight) and the next Friday at 4 o'clock a lecture at Stanford.

At Berkeley, the lecture room overflowed, and I had very little blackboard space. The sound system, however, was adequate and I was not expected to speak for more than 50 minutes. It was an acceptable performance. The Chinese restaurant where we should have meal together and where Tony Wasserman would pick me up during the evening having had a fire, we ended up in a Japanese restaurant. Between the talk and the dinner I was rescued by Sue Graham and Michael Harrison, with whom I drank a few glasses of nice, white wine in a cool and peaceful living room. For the last glass we were joined by Vuillemin, who had asked a question after my talk. (It turned out that I had had him in my audience at the Summer School in Le Breau-sans-Nappe, some five years ago: as usual, I did not remember, but, thank goodness, he did not blame me. Otherwise, he would not have turned up.)

On Friday morning I joined Tony Wasserman while going to the ACM Pacific 75. I bought a small, cheap camera and have not attended any of the sessions, except the Luncheon Banquet, where I had to read —no problem therefore— my Luncheon Speech. (It had been printed in the Conference Proceedings and under such a circumstance I find it always a little bit silly just to read my text: as if one's audience cannot read! I have used the Railway Parable by way of introduction. It all went very well.) I walked through the corridors, was introduced to Codd (we had never met) and encountered Lyle, Cowan and Barton from Burroughs. They invited me for an informal meeting near San Diego (with Holt and Petri), but next week I discovered that I could not make it.

Immediately after the Conference Banquet I was taken to Stanford, where I met Jim Eve as expected; I also found there Brian Randell and Peter Henderson —what I could have expected— and Rod Burstall —what was a pleasant surprise—. As Stanford had asked for the same lecture as Berkeley, I gave the same lecture again. This time we had been moved to a larger auditorium, so that it did not overflow. The sound system was not of a convincing quality —it was in the EE Department— and the old blackboards were of the type that cannot be cleaned anymore. I suffered less from these minor disturbing influences than the previous day and the lecture went very smooth. (I fear that I am getting quite spoiled by the lecturing facilities at the THE!) In the evening there was a party at Jim and Margaret Eve's (temporary) Castle and at 11 o'clock I disappeared with Don and Jill Knuth, where I woke up at four o'clock in the morning, awake beyond redemption. At 6 o'clock in the morning I was writing a letter to Ria at their dinner table and when it was nearly completed, Jill came down for breakfast. The morning was devoted to an exchange of problems and solutions, views and opinions between Don and me, the afternoon to walking over the Stanford Campus and piano playing —his organ was going to be installed within a few weeks— and early in the evening Don and Jill Knuth brought me back to Tony Wasserman's house, where we joined a party. There I met Richard Karp from Berkeley, Bob Floyd from Stanford and John Backus from IBM. Bob Floyd was very excited because he had just derived the exact minimum number of steps needed for addition in number systems with unique representation (by pushing a lower bound and an upper bound until they coincided). It had taken him about a year to do so and he was clearly still absolutely excited that he had been able to do so. (Without denying the brilliancy of the argument, I must confess that I am not convinced of the central importance of the problem as far as computing science is concerned: it strikes me more as pure mathematics.)

After having been shown the San Francisco surroundings on Sunday morning, I flew under Tony Wasserman's guidance from San Francisco to Los Angeles in order to attend from Monday through Wednesday the International Conference on Software Reliability. Those were three busy days: besides being the first speaker —that is, after the Keynote Address by Ruth Davies from the NBS, a Keynote Address that I did not understand— I was also the last speaker and it was intended that I should try to use the last slot for a summing up. (My printed text in the Proceedings was only an "Emergency Exit" in case that I had not figured out what to say. I fell a little bit shaky at that last session, confronted by an audience of about a thousand people and intending to speak without written text. As the audience was very mixed, I have mainly spoken about the various forms of pressure to do the wrong things, about the false hopes and the lies that are the curse of our profession and about the strains, tensions and pains caused by the fact that a craft is changing into a science. It was that kind of talk. At the end I have used only five paragraphs or so from the Emergency Exit. Three days later I heard —to my surprise!— that I had been "so bitter". I don't think so: "honest" would have been a better term. It was a quite risky performance, but quite a few came to me afterwards and thanked me. I hope that I have not offended or disturbed more people than necessary.)

The International Conference on Software Reliability was, to start with, a circus with about a thousand participants instead of the estimated four hundred. At a closer inspection it was a very mixed lot, as mixed as the title item "Software Reliability" was lousy. One lesson is clear: when organizing a conference, don't use a vague title like that.

There were mainly three groups of people:
a)   the correctness guys
b)   the program testers and other engineering pragmatists
c)   the software project managers.

The three categories are presumably listed in order of increasing magnitude and decreasing quality. Category c) felt itself very clearly threatened by the technicians of the other two categories, and showed this in various ways. One way was to deny flatly that —at least today and for the next years to come— the technicians could contribute, e.g. L.M.Culpepper's postulate (Naval Ship Research and Development Center): "For the present, reliable software must be produced by people whose primary skills and interests lie outside the field of programming." A specially sickening performance was R.D.Williams's (from TRW) salestalk "... In fact, at TRW, where the search has been intense and continuous over the years, a great deal of progress has been made, a lot has been learned and we can say conservatively (sic!) that we have come a long way. [...] Despite having introduced unprecedented rigor into the task of specifying and reaching mutual agreement on unambiguous requirements, we fully appreciate the need for even more rigor and a comprehensive technology to guide and control the requirement specification effort." Etc. There was at least one other TRW-paper in the same vein, and more than one has asked himself (or others) whether this conference was in part a piece of TRW's sales promotion. (Boehm, the program chairman, is from TRW.) If so, it must have had some negative effects as well, for I saw many people leaving the room in absolute disgust. Classifying programmer mistakes according various (ill-defined) categories was also a beloved pastime, and, of course, there was Weinberg, who does not know that anecdotes are only a poor substitute for conversation.

The type c) people thought mainly in terms of power. The type b) people were a little bit more pathetic, because they felt clearly threatened in their technical skills: on the whole they had at least the lurking suspicion that their approach was not fully right. It was here that we had a number of statistical papers based on the assumption that software errors caused malfunctioning subject to a Poisson distribution (what else?) and from then onwards, etc..... They had a tendency of defending themselves by putting on the hat of the "reasonable, reliable engineer", pointing out —sometimes at great length— that "correctness", although of course important, was only a very small aspect of the task. Too much of that was presented in terms of the vulgar controversy —vulgar because fruitless— of "common sense" versus "mathematics", of "the practical problems of the real world" versus "theory"; Parnas' paper had too much of that flavour for my taste.

The type a) speakers felt most secure. They showed proof techniques, either by hand or (partly) mechanized, to be applied during or after program development and, in general, they did not oversell too much. They derived their sense of security clearly from the firm mathematical basis of their work and some of their relative modesty from previous failures of Artificial Intelligence. I myself found the methods less convincing, the more they relied upon mechanical assistance. Various people showed how they tried to debug programs by "symbolic execution" (James C.King "A new approach to program testing" and Robert S.Boyer, Bernard Elspas and Karl N.Levitt "SELECT— a formal system for testing and debugging programs by symbolic execution.") but I have grave doubts whether these efforts make much sense: I fear that a combinatorial explosion will quickly prevent their application and thus reduce their significance. They tend to partition the input space according to the resulting flow of control ("the control path") and that seems self-defeating. A sentence like "each loop can be executed as many times as a user feels necessary to convince himself of its correctness" is taken as a support of my doubts! Shmuel Katz and Zohar Manna ("Towards automatic debugging of programs") state "The main tool we use will be the invariants of the program, which express the relationships among the variables at pre-chosen cutpoints during execution of the program" and that seems to make more sense. My judgement will be postponed until I have made a sufficiently thorough study of their paper; I hope that its presentation can be simplified! I was more attracted by Susan L.Gerhart's paper "Knowledge about programs: a model and case study." Susan L.Gerhart was also co-author (with John B.Goodenough) of "Towards a theory of test data selection"; while reading that I found myself somewhat depressed when I observed that these authors thought it still necessary to show that a program may be wrong, although testcases exercising the whole program text have been processed correctly. Later, while reading other papers, I became still more depressed when I discovered that this warning is still necessary! I came home with a fat, green bible of more than 560 pages, containing more than 60 papers of which perhaps 10 per.cent worth studying. I left the Conference rather depressed, but in retrospect it is perhaps not so bad at all (To quote Strachey's quotation "After all, 95 per.cent of everything is rubbish"; 10 percent worthwhile is then not bad at all!) Chairman Yeh was absolutely convinced that the conference had been a great success, but he seemed to judge primarily by the number of paying participants.

The next two days were passed at ISI where Ralph London had invited a small number of people for an informal gathering. I do not remember all that were present, for we came from eight different countries, and I remember only Manna, Ershov, Burstall, Randell, Bledsoe, Luckham, Good, London, Turski, Wulf and Musser. On Thursday morning I showed the on-the-fly garbage collection, proof included and the audience was duly impressed (Bill Wulf was even delighted, for he felt that he could use the solution very well). Bledsoe showed some mechanical proofs from normal analysis, using "extended reals", Burstall did his IFIP paper again, Randell showed the implementation of recovery blocks, London and his crew gave a demonstration of their verification system. My feelings with respect to that project are still very mixed, for a great variety of reasons. Their screens were beautiful and the whole system seemed nicely engineered, but .... the demonstration had to take place during lunch, because then we could have a dedicated PDP10 at our disposal with 256K words. The demonstration took nearly an hour, the program was a program for the binary search and got stuck in most of the proofs. After the demonstration I studied the program text that I found hard to understand, so I decided to program it myself and I delivered formally a much more beautiful (and more "efficient") program on the backside of an envelope in two minutes. This contrast gave me the uneasy feeling that with the economy of their system, something is still very wrong. One thing is certain: the stress on mechanical proofs is because they want a certified and (on what justification?) trust a machine better than a human being. That a proof is also the carrier of our understanding and that the joy of understanding is the last one we should delegate to machine is hardly stressed, probably because it cannot serve as a basis for funding.

On Friday afternoon I flew to Phoenix, Arizona, where I was due to perform on Saturday morning and afternoon on the invitation of the Phoenix Chapter of the ACM. Upon arrival in Phoenix my host, dr.Susan Brewer and her husband invited me for a concerto given by the Borodin Quartet. This was quite a surprise! The performance took place in the building of the Phoenix Chamber Music Society —or something very similar— and I was exposed to music and a new aspect of American social life. After the performance we had a late dinner with the soloists. My performance on Saturday morning was not too successful: in an overloaded room with the doors open (for reasons of ventilation) I had to fight the airport noise, only assisted by what was described as "a weak microphone". I had to work with an overhead projector, but the pen had a very blunt point and this was difficult to combine with my subject that required rather lengthy formulae. It was a distressing battle. During lunch I retrieved from my luggage a pen with a sharper point and used some of the prepared "visuals" that I had used at my first talk in Los Angeles. The second one went much better. Early in the evening I flew back to Los Angeles, where Bob Merrell and his wife were at the airport to pick me up and to take me to Mission Viejo, where I stayed in the Mission Viejo Hilton Inn.

(The room number on Mission Viejo was 242; in Los Angeles my room number had been 338 and as I am used to factorizing room numbers, this was a surprise! The Mission Viejo Hilton Inn was better than the International Hotel in Los Angeles, which was just terrible: "Two eggs any style", I discovered in Los Angeles, excludes hard boiled.... Both their bars had music and hardly any illumination, but in the International Hotel the volume was such as to make conversation nearly impossible.)

For a week I stayed in Mission Viejo at the Burroughs Large Systems Plant: it felt like coming home, most people I encountered I had met before. On the one hand it was hard work, about forty per.cent of the time I have been standing in front of a blackboard. But there were no communication difficulties: on one of the first mornings we entered the plant at about 8 o'clock in the morning and after having accepted coffee from one of the secretaries, they showed me what they wanted to ask me, at ten past nine we were down to essentials. Yet it all took place in a relaxed manner, orders of magnitude less hectic than the preceding ten days. My presence was responsible for a few social events and I saw a few very nice homes, often with a beautiful view. (I wondered whether that climate would make me utterly irresponsible!) I was, however, severely tempted to offer the plant something like the "Edsger W.Dijkstra Blackboard", but I have done no more than expressing the intention. On the anniversary of Her Majesty our Queen I took half an afternoon off; that evening I have eaten in solitude and written all evening.

I left Mission Viejo on Saturday morning. At a quarter to seven in the morning Bob Merrell was at the Hilton Inn's doorstep and took me to the airport in Los Angeles, from where I flew to Montreal. I had another four days to go and the stay in Canada enabled me to absorb at least three of the eight hours time shift in advance. The flight to Montreal was interrupted by a stop in Toronto, chasing my luggage, when at last it turned up, just in time for getting on the flight again. In Montreal I was picked up by someone from IBM who drove me to the Castle Montebello.

From Monday through Wednesday IBM sponsored there a conference on Software Engineering Education, and in my innocence I had expected an audience of computer scientists. My driver, however, was a manager, who opened the conversation with something like "So you are the world expert on structured programming and chief programmer teams." Then I knew that I was out in the wilderness and politely refused to be associated with Harlan D.Mills. During that car ride I have heard more about hockey than I ever wanted to know. I felt very low when we arrived at Montebello. Upon arrival I found the scene considerably brightened by the broad shoulders and similar neck of Wlad Turski.

The Montebello conference was very instructive for me, although I learned a lot without which I would have been happier. The participants were at most for fifty per.cent computing scientists, for the rest they were either IBM officials or managers of the automatic data processing department of large IBM customers. I had the full opportunity to observe all the intricate love/hate relations between the angles of the triangle "university-manufacturer-customer". It was all very frightening and I wish that I had a mastery of my pen like Arthur Koestler, for then I could have written a companion volume to his "The Call Girls".

The central victims in this drama are the so-called MBA's (short for "Master of Business Administration"), and the firms dependent on their services, in short their employers. They really have painted themselves into a corner with very sticky molasses! They have made a number of mistakes that are hard to forgive. The one mistake is that they have based their full automation upon the IBM 360. When that machine was announced, it was immediately clear to many —even inside IBM!— that it would be practically impossible to write decent software for that hardware, for the latter contained too many too serious blunders. You cannot program a crooked machine to go straight and a hardened piece of junk propagates all through the system. As the software cannot be acceptable, stability of it was the last that could be expected. Yet they chose that shaky basis as their starting point. The next thing is that they decided to program all of it in COBOL. And now they find the administration of these big firms dependent on 5 million lines of COBOL! That would already be terrible all by itself, but on top of that misery they find IBM coming with a next release of OS/360 by the time that they have hardly managed to adjust their program library to the changes introduced at the previous release. They have set up gigantic administrations and have made their firms fully dependent on them, but have done so in the absence of the necessary competence to do so. It is absolutely terrible and one of these days something terrible is bound to happen. It is irresponsibility on the verge of lunacy, but, believe me or not: the MBA's seem to believe that they have done something very clever! But now, quite unexpectedly it seems, they are in trouble. One of those speakers made the duty of the university quite clear: IBM came with its confusing releases at a greater speed than the system programmers in the business could cope with, customer training was also defective, and therefore the universities (who had lots of experts in the area of operating systems, all of them with a lot of educational experience) should give crash courses in "How to live with the next release of OS 360." Perhaps the government could mediate between the vendor and the universities so that the universities could get advance information, etc. And what can the University do? To quote C.A.R.Hoare: "And simplicity is the unavoidable price which we must pay for reliability." We know that this is going to collapse, it must, crushed under the weight of its own unwieldiness. And things are not going to improve, they will become worse. Herbert Schorr, now one of IBM's vice-presidents, announced in his keynote address —so bad, that many Canadians felt obliged to offer me their apologies on behalf of that American, and if you know something about the Canadian/American relations that is saying a good deal!— better times: primary memory would become so cheap that OS 360 could at last grow from 2.5 million something (bytes or words, does not matter) to 4 million somethings! Only more and more of the same, becoming demonstrably more intertwined. It is no longer "logical spaghetti", but "logical barbed wire". In the middle of the morning, Herbert Schorr thought it fit to intervene by shouting "Why is everybody so damned pessimistic?". Tome Hull gave, as the next speaker in the discussion, him the answer "Because all of us have heard this morning's keynote address." He did that perfectly.

But on the whole it was ghastly; unreal. I was severely shocked by the cultural level of the business participants. Their jokes were stale and sordid and —for people in business this amazed me— they could not drink their alcohol with style (and alcohol was provided by IBM plenty: "whiskey galore"; also this lavishness was somewhat appalling). But also technically they were absolutely uneducated. I remember one extremely fruitless discussion with a man, who talked all the time about "the user". I suggested to him that he should not use that term and that he should separate his concerns: on the one hand try to make you system meet the requirements —and during that phase it is wise to consider yourself as the user— and if the system's customer happens to be someone else than yourself, deal with the problem of discovering his needs and intentions as a separate issue. He absolutely refused to make this separation of concerns.

Later I heard Harlan Mills give a summing up of some of the things I had said —together with some Harlanesk additions— for that business audience. It was terrible, a misuse of language to which to the best of my powers I could not give a meaning. So, every third terrible phrase I interrupted Harlan "please could you explain or restate what you tried to say" but it was hopeless. Tom Hull helped me and I was very grateful to him. Later, when it was all over, our eyes met, and Tom gasped "Jezus!". It was the first time that I had heard him use strong language. How to sell empty but impressive slogans under the cloak of academic respectability...

Turski's comments were short "They don't want computer scientists, nor software engineers, they want brainwashed mental cripples." It is too true...

On the last morning, our great Harlan gave the summing up talk. It was again very much of the same, but, remarkably enough, I learned something from him, viz. the expression "entry level jobs". His argument was that the university should not train experts —as an aside: training and education were constantly confused— because the jobs those experts should get were no "entry level jobs". This may be a profound difference between the academic community and (at least some of) the business community: there is not the slightest objection to giving the most responsible university function, viz. a full professorship, to a youngster who has just got his Ph.D. It does not happen so very often, because really brilliant people are rare: but nothing in the university environment forbids it as soon as a really brilliant man emerges. On the contrary, I am tempted to add! But to the business communities represented it was unthinkable to give a youngster any real responsibility....

The most frightening thing —and that made it all so unreal— was that all those business blokes, although in great trouble, were so little alarmed. They said that they were trying to dig themselves out of the hole again, but only wished to try to do so by well-established practice. So they will only sink deeper into the mud. If they really want to get out of the mess, something drastic has to be done and if they don't, something drastic will happen all by itself. But this was clearly beyond their imagination.

Plataanstraat 5 NUENEN - 4565 The Netherlands | prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 29-Sep-2011

13 April 1975 EWD 494

Zevende toespraak tot mijn studenten.

In mijn studententijd was het Rectoraat nog een éénjarige functie en maakte ik dies jaarlijks de verversing van de Rector mee. Bij een van deze rectoraatsoverdrachten —in de vroege vijftiger jaren— beging de scheidende Rector de weergaloze stommiteit de bloei van de Leidse Universiteit te adstrueren met het feit dat het ledental van de Senaat van circa tachtig man ten tijde van de bevrijding inmiddels tot over de tweehonderd was toegenomen. Algemeen boe-geroep in de Stadsgehoorzaal, waar de overdracht plaatsvond, verhinderde hem enige tijd zijn rede voort te zetten. De studentenbevolking, die in meerderheid zijn gehoor uitmaakte, weigerde nl. deze groei van de senaat als symptoom van bloei te accepteren: gezien het qualiteitsverlies kwam het haar eerder als symptoom van verval voor.

Een aantal jaren later, bij het zoveelste symptoom van de groei van het Universitaire bedrijf in Nederland —ik denk, dat dit bij de oprichting van de zoveelste TH was— uitte een van mijn oudtantes vol verontrusting —het lieve mens was toen ongeveer tachtig jaar oud— in een brief aan mijn moeder haar verbazing: "Waar willen ze al die hoogleraren vandaan halen? Er zijn toch nooit voldoende mensen, die én voldoende knap én voldoende fatsoenlijk zijn!". De oude dame wist van zeer nabij, dat het fatsoen van een hoogleraar zeker zo zwaar op de proef wordt gesteld, als zijn intellect.

Waarom vertel ik U dit alles? Heel eenvoudig: omdat ik er zelf vol van ben ten gevolge van wat mij onlangs ter ore kwam. Ons ministerie krijgt vele adviezen van hooggeleerde commissies. Onlangs werd de voorzitten van een van die commissies aangeschoten over een van de adviezen, die in het rapport van zijn commissie gedaan werden. Het advies in quaestie was zwak, om niet te zeggen onverdedigbaar. De hooggeleerde voorzitter van de commissie in quaestie verdedigde het advies op twee wijzen. Ten eerste had zijn commissie niet gezegd dat zo en zo moest gebeuren, maar slechts dat het gewenst was dat zo en zo zou gebeuren. U moet mij inmiddels kennen als een liefhebber van zorgvuldig taalgebruik, maar er zijn grenzen, en hier kan ik slechts constateren, dat aan die voorzitter een Jezuiet verloren is gegaan. Maar ik wil het eigenlijk hebben over zijn tweede verdediging: "Staatssecretaris Klein wilde dit zo graag horen." Een Nederlands hoogleraar, door het Ministerie van Onderwijs en Wetenschappen om advies gevraagd, verdedigt zijn onhoudbare advies met de motivering, dat hij hier slechts geschreven had, wat men ten departemente zo graag wilde horen!

Realiseert U zich, hoe erg dit is? Er worden per jaar duizenden advie- zen uitgebracht, die de vrager van het advies naar de mond praten: van derge- lijke praktijken leven alle kwakzalvers. Afgemeten naar de eisen van intellectuele integriteit, die onze maatschappij nog steeds aan een hoogleraar stellen mag en moet —over de integriteit van staatssecretarissen praat ik liever niet— is een dergelijke zg. "tactvolle welwillendheid" evenwel niets minder dan corruptie: de Nederlandse hoogleraar is namelijk door Hare Majesteit onze Koningin aangesteld als het vleesgeworden geweten van de wetenschappelijke hoeksteen van onze beschaving, en niet als fraudeur.

Een en ander werpt voor het Academisch bedrijf wel een probleem op: wij doceren allerlei aspecten van de wetenschap, maar hoe doceren wij op overtuigende wijze deszelfs essentieelste aspect: onkreukbaarheid?

In de hoop juist hiertoe te hebben bijgedragen, ga ik over tot de orde van de dag, te weten: "identification and disposal of garbage".

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

12 mei 1975 EWD 495

Achtste toespraak tot mijn studenten.

Het motto van wat toevalligerwijze mijn laatste toespraak van dit semester zal worden, is simpel: "Hoedt U voor naamsveranderingen!".

Eeuwen geleden heeft Shakespeare zijn waarschuwend "What's in a name?" laten horen, maar het citaat, hoewel bekend, blijkt niet bekend genoeg. Omstreeks de voorlaatste eeuwwisseling hebben de drijvers van de Frans revolutie alle geloofwaardigheid verloren door nieuwe namen voor de maanden van het jaar in te voeren, maar ook dat heeft niet mogen baten: de charlatannerie gaat onverdroten voort.

Ik herinner me heel goed hoe tijdens de Duitse bezetting de nieuwe druk van "Schwere Wörter" van Brouwer, Gerzon en Ras slechts door Brouwer en Ras geschreven heette te zijn: Gerzon was immers Joods! Ik herinner me eveneens nog hoe tijdens de destalinisatie in Rusland in Amsterdam de Stalinlaan —o, bittere ironie!— in Vrijheidslaan werd omgedoopt. Dit onwaardig gebeuren deed mij me afvragen hoe lang ik moest wachten totdat ook de er op samenkomende Rooseveltlaan en Churchillaan herdoopt zouden worden... Ons Ministerie van Kolonien werd het Ministerie van Overzeese Gebiedsdelen of zo iets, ons Ministerie van Oorlog dat van Defensie, zoals de Verenigde Staten van Amerika nu hun Department of Defense hebben. Welk land kan zich immers de wrange eerlijkheid van een "Department of Aggression" veroorloven?

Als op last van de machthebber met auteursnamen gegoocheld wordt: let op Uw saeck! Als de heersende gezagsdragers straatnaambordjes gaan verhangen: let op Uw saeck! Als ministeries herdoopt worden: let op Uw saeck!

Als een kabinet in plaats van in formele kleding zich ostentatief in kotspak aan Hare Majesteit onze Koningin presenteert en —hoe terecht ook!— voor ministers de aanspreektitel "Excellentie" afschaft, let op Uw saeck!

Ik haal deze oude koeien uit de sloot naar aanleiding van een recent bericht in de krant dat op grond van "inkomenspolitieke overwegingen" —wie het laatste adjectief heeft uitgevonden, verdient een onvoldoende voor Nederlands, maar dit terzijde— besloten is in het bestuurlijke verkeer de academische titels af te schaffen.

Je kunt dit afdoen als het afreageren van een persoonlijke frustratie van onze premier, die het beu is om door de aanspreektitel "doctorandus" —nu immers "excellentie" niet meer mag!— er alsmaar aan herinnerd te worden dat hij zijn academische studie niet voltooid heeft en dat het langzamerhand hoog tijd wordt dat hij eindelijk eens promoveert. U kunt zich voorstellen hoe gaarne ik, al was het alleen maar om zijn taalmisbruik, in de promotiecommissie zitting zou nemen. Het zal mij niet gegeven zijn: mij rest slechts te wachten totdat deze vlegel zich een doctoraat honoris causa laat aanleunen!

Vergeet deze premier: hij is niet belangrijk genoeg om onthouden te worden. Onthoudt evenwel, dat in het jaar onzes Heren 1975 ex cathedra verklaard werd, dat in het bestuurlijke verkeer een academische opleiding —de opleiding die geacht wordt je te leren je hersens te gebruiken— liever niet meer vermeld moet worden. Het doet er immers niets toe of je een academische studie met goed of eventueel zelfs eclatant gevolg hebt afgelegd! Het zou immers ondemocratisch zijn als we het landsbelang niet even goed zouden kunnen toevertrouwen aan de eerste de beste louche bakkersknecht.

Van een regering die ter rechtvaardiging van de regerende bakkersknecht meent om in het bestuurlijk verkeer de academische titels af te moeten schaffen, kan slechts één soort maatregels verwacht worden, nl. maatregels, die pogen het academisch bedrijf tot een zodanige farce uit te hollen, dat de willekeurige bakkersknecht even goed of even slecht is als de even willekeurige academicus.

Dies zijn alle academische qualiteitsnormen uit den boze, wordt elke vorm van universitair toelatingsexamen als ondemocratisch van de hand gewezen en krijgt de academie de onwaardige taak ieder die zich aanmeldt met de titel op te tuigen, een titel, die vervolgens als van nul en generlei waarde wordt gebrandmerkt. Een sluitend systeem, maar ... let op Uw saeck!

Het doel is kennelijk om de thans nog aanwezige intellectuele elite de aankweek van geestelijk nakomelingsschap te verhinderen: genocide van een culturele minderheid. De socialistische regeringen in West Europa staat kennelijk een soort "Endlösung der Akademischen Frage" voor ogen.

Wij gaan, zolang het nog kan, over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

EWD496A

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On-the-fly garbage collection: an exercise in cooperation.

| by |
| Edsger W.Dijkstra *) |
| Leslie Lamport **) | Note: This copy has been made
| A.J.Martin ***) | before the last four authors
| C.5.Scholten ****) | had had the opportunity to
| E.F.M.Steffens ***) | express their agreement.

*) Burroughs, Plataanstraat 5, NL-4565 NUENEN, The Netherlands
**) Massachusetts Computer Associates Inc., 26 Princess Street, WAKEFIELD, Mass. 01880, U.S.A.
***) Philips Research Laboratories, EINDHOVEN, The Netherlands
****) Philips-Electrologica B.V., APELDOORN, The Netherlands

Abstract. A technique is presented which allows nearly all of the garbage detection and collection activity to be performed by an additional processor, operating concurrently with the processor(s) carrying out the computations proper. Exclusion and synchronization contraints between the processors have been minimized.

Key Words and Phrases: garbage collection, multiprocessing, cooperation between sequential processes with minimized mutual exclusion, program correctness for multiprocessing tasks.

CR Categories: 4.32, 4.34, 4.35. 4.39. 5.23.

On-the-fly garbage collection: an exercise in cooperation.

In any large-scale computer installation today, a considerable amount of time of the (general purpose) processor is spent on “operating the system”. With the emerging advent of multiprocessor installations the question arises to what extent such “housekeeping activities” can be carried out concurrently with the computation(s) proper. Because the more intimate the interference, the harder the organization of the cooperation between the concurrent processes, the problem of garbage collection was selected as one of the most challenging —and, hopefully, most instructive!— problems. Whether the following solution is of any economic significance, is a question beyond the scope of this article.

We tackled the problem as it presents itself in the traditional implementation environment for pure LISP (and shall describe our solution in the for that environment usual terminology, leaving the natural generalizations to the reader). The data structure to be stored consists of a directed graph in which each node has at most two outgoing edges, more precisely: may have a left-hand outgoing edge and may have a right-hand outgoing edge. (Either of them or both may be missing.) At any moment in time all the nodes of the graph must be “reachable” (via a directed path along the directed edges) from one or more fixed nodes —called “the roots”— with a constant place in memory. The storage allocated to each node is constant in time and equal in size, viz. sufficient to accommodate two pointers —one for each possible outgoing edge— pointing to the node’s immediate successors (if any: a missing edge is coded by means of a special pointer-value that has been reserved for that purpose). Given (the address of) a node, finding (the address of) its left- or right-hand successor node can be regarded in this representation as an atomic, primitive action; finding its predecessor nodes, however, would imply a search through memory.

For a reachable node an outgoing edge may be deleted, changed or added. Note that deletion and change of an outgoing edge may turn a number of formerly reachable nodes into unreachable ones: they become what is called “garbage”. Changing or adding an edge may direct the new edge towards a target node that was already reachable or towards a new node that has to be added to the data structure; such a new node —which upon creation has no outgoing edges— is taken from the so-called “free list”, i.e. a linked list of node (locations) that are currently not used for storing a node from the data structure. Garbage may arise anywhere in store and it is the purpose of the so-called “garbage collector” to detect such disconnected and therefore obsolete nodes and to append them to the Free list.

In classical LISP implementations the computation proper proceeds until the free list is exhausted (or nearly so). Then the computation proper comes to a grinding halt, during which the central processor is devoted to garbage collection. Starting from the roots all reachable nodes are marked; upon completion of this marking phase all unmarked nodes that are not in the free list are garbage and are appended to the free list, after which operation the computation proper is resumed. The minor disadvantage of this arrangement is the central processor time spent on the collection of the garbage; its major disadvantage is the unpredictability of these garbage collecting interludes, which makes it hard to design such a system so as to meet real time requirements as well. It was therefore tempting to investigate whether a second processor —called “the collector”— could collect garbage on a more continuous basis, concurrently with the activity of the other processor —for the purpose of this discussion called “the mutator”— which would be dedicated to the computation proper. We have imposed upon our solution a few constraints. The (microscopic) interference between collector and mutator should be minimal —i.e. no highly frequent mutual exclusion of elaborate activities, as this would defy our aim of concurrent activity—, the overhead on the activity of the mutator (as required for the cooperation) should be kept as small as possible, and, finally, the ongoing activity of the mutator should not impair the collector’s ability to identify garbage as such as soon as logically possible. (One synchronization measure is evidently unavoidable: when needing a new node from the free list, the mutator may have to be delayed until the collector has collected some garbage. This is the now traditional producer/ consumer coupling; in the context of this article it must suffice to mention that this form of synchronization can be achieved without any need for mutual exclusion.)

A counterexample taught us that the goal “no overhead for the mutator” is unattainable. Suppose that nodes A and B are permanently reachable via a constant set of edges, while node C is reachable only via an edge from A to C . Suppose furthermore that from then on the mutator performs with respect to C repeatedly the following sequence of operations: 1) making an outgoing edge from B to point to C 2) deleting the edge from A to C 3) making an outgoing edge from A to point to C 4) deleting the edge from B to C . The collector, which observes nodes one at a time, will discover that A and B are reachable from the roots, but never needs to discover that C is reachable as well: while A is observed by the collector, C may only be reachable via B and the other way round. Therefore, when changing or adding an edge, the mutator may have to mark in some way the target node of the new edge.

When we start with all nodes white, and, furthermore, the combined activity of collector and mutator can ensure that eventually all reachable nodes become black, then all white nodes that are not already on the free list can be identified as garbage. For each repetitive process —and the marking process certainly is one— we have always two concerns: firstly we must have a monotonicity argument on which to base our proof of termination, secondly we must find an invariant relation which, initially true and not being destroyed will still hold upon termination.

For the monotonicity argument we suggest (fairly obviously)

A) | each node will only darken monotonically.

For the invariant relation during the marking phase —a relation which must be satisfied both before and after marking— we propose (perhaps less obviously, but not unnaturally):

B) | no edge will ever point from a black node to a white one.

Additional action is required from the mutator when it is about to place an edge from a black node to a white node: just placing it would cause a violation of requirement B . Requirement A tells us that the black source node of the new edge has to remain black, and, therefore, requirement B implies that the target node of the new edge cannot be allowed to remain white. But the mutator cannot make it just black, because that could cause a violation of requirement B between the target node and its immediate successors. For that reason grey is introduced as an intermediate colour and the only overhead on the activity of the mutator will be —irrespective of the colour of the source node of the new edge—

| “before placing a new edge, the mutator makes its new target
| at least grey”.

Note 1. Making a node “at least grey” turns a white node into a grey one and leaves the colour of an initially grey or black node unchanged. It is assumed to be available as an atomic, primitive action. (End of Note 1.)

When all the roots have been darkened, requirement B is satisfied and there are no grey nodes, we can conclude that all reachable nodes are black and that. therefore, all white nodes are either garbage or on the free list. Two problems, however, present themselves: the collector has to distinguish between those two types of white nodes and, more seriously, as long as the nodes on the free list remain white, the mutator can create new grey nodes, and for the collector it will in general be very hard to reach the state without grey nodes and to detect that it has done so. The most elegant solution is to arrange matters in such a way that (due to collector activity) the nodes on the free list will eventually become black as well, as this solves both problems: when all reachable nodes are black, and all nodes on the free list are also black, further creation of grey nodes is excluded and all white nodes can be concluded to be garbage.

The simplest way to arrange that the nodes of the free list will be coloured as well is to introduce an additional root from which all the nodes on the free list (linked via edges!) are reachable. During the marking phase the collector makes no distinction between the free list and the data structure proper, and in the initial absence of black nodes it performs repeatedly the following program —assertion names being added within braces— :

marking phase: {PO}
| make all roots at least grey {P1};
| repeat for a node i observed by the collector to be grey:
|  | make the left-hand successor of node i (if any) at least grey;
|  | make the right-hand successor of node i (if any) at least grey;
|  | make node i black
| until in a single scan in some order all nodes have been observed to
|  |  | be non-grey {P2};
collecting phase:
| process all nodes in some order, where “to process a node” means that
| a white node is appended at the free list and a black node is made
| white {P0}

Note 2. To make a node black is assumed to be an atomic, primitive action available to the collector. The final colour of a node made black by the collector and “simultaneously” made at least grey by the mutator will be black, i.e. as if the two operations had been performed in some order. (End of Note 2.)

Note 3. To make a node white is assumed to be an atomic, primitive action available to the collector. The final colour of a node made white by the collector and “simultaneously” made at least grey by the mutator will be either white or grey, i.e. as if the two operations had been performed in some order. (End of Note 3.)

Note 4. The mutator takes nodes away from one end of the free list, the collector appends nodes at the other end. The prevention of undesired interference between those two actions does not require mutual exclusion in time. (End of Note 4.)

The assertions and conclusions justifying the design are the following.
P0:     There are no black nodes, and, therefore, requirement B (no edges from a black node to a white node) is satisfied.
P1:     There are no edges from a black node to a white node and all roots are at least grey; as a result the existence of a white reachable node (those on the free list included) implies the existence of at least one grey node.
P2:     There are no grey nodes —see Note 5— and as P1 still holds, all white nodes are garbage and will remain white as far as mutator activity is concerned. This state is reached by the collector thanks to the monotonicity of the colour history of each node during the marking phase and the fact that the collector effectively darkens (at least node i !) as long as it finds a grey node.
P0:     During the collecting phase requirements A and B may be violated. Requirement A is here inessential because the collecting phase does not depend on it for termination and requirement B is restored at completion of the collecting phase, because the mutator can't create a black node and all nodes that were black have been made white by the collector.

Note 5. The conclusion that there are no grey nodes when in a single scan all nodes have been observed by the collector to be non-grey requires some further justification, as one of the nodes observed to be non-grey —white, to be precise— in the meantime could have been made grey by the mutator. Thanks to the continuing validity of P1 and the fact that the mutator leaves a grey node grey, however, the conclusion is justified. Suppose that during the scan the mutator has introduced a number of grey nodes. Consider the moment of the first time that the mutator did so; at that moment that node was a white reachable node (those on the free list included) and, therefore, it must have been so when the scan started. On account of P1 we can now conclude that when the scan started a grey node must have existed. As the mutator leaves grey nodes grey, the collector must have encountered that grey node during the scan. Therefore, if during the scan the collector has not encountered a grey node, the mutator cannot have created one either and the conclusion “there are no grey nodes” is therefore justified. (End of Note 5.)

Note 6. It is assumed that when the collector establishes (the address of) the left-hand successor of node i “simultaneously” with a redefinition of the left-hand successor of node i by the mutator, the result will be as if inspection and modification are done in some order: the collector will be directed either towards the old or towards the new left-hand successor. It is not difficult to verify that under all circumstances requirement B remains fulfilled. (End of Note 6.)

Finally: at the beginning of a collecting phase some garbage may be white and some may be black. At the end of that collecting phase all initially white garbage has been collected, all initially black garbage has been made white and will remain so during the next marking phase until it will be collected during the next collecting phase. As a result we can guarantee that no garbage, once created, will escape being collected.

History and acknowledgements. (As in this combination this is our first exercise in international and inter-company cooperation, some internal credit should be given as well.) After a careful consideration of a wider class of problems the third and the fifth authors selected and formulated this problem and did most of the preliminary investigations. The first author found a first solution during a discussion with the latter, W.H.J.Feijen and M.Rem. It was independently improved by the second author —to give the free list a root and mark it as well was his suggestion— and, on a suggestion made by Jack Mazola, by the first and the third author. The first and the fourth merged these embellishments and produced the version published above.

30th May 1975

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-25 .

EWD496B

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On-the-fly garbage collection: an exercise in cooperation.

by

Edsger W.Dijkstra *)

Leslie Lamport **)

A.J.Martin ***)

C.S.Scholten ***)

E.F.M.Steffens ***)

*) Burroughs, Plataanstraat 5, NL-4565 NUENEN, The Netherlands
**) Massachusetts Computer Associates Inc., 26 Princess Street, WAKEFIELD, Mass. 01880, U.S.A.
***) Philips Research Laboratories, EINDHOVEN, The Netherlands
****) Philips-Electrologica B.V., APELDOORN, The Netherlands

Abstract. A technique is presented which allows nearly all of the garbage detection and collection activity to be performed by an additional processor, operating concurrently with the processor(s) carrying out the computations proper. Exclusion and synchronization contraints between the processors have been kept weak.

Key Words and Phrases: garbage collection, multiprocessing, cooperation between sequential processes with minimized mutual exclusion, program correctness for multiprocessing tasks.

CR Categories: 4.32, 4.34, 4.35, 4.39. 5.23. (Final version as is to be submitted to the Comm.ACM.)

On-the-fly garbage collection: an exercise in cooperation.

In any large-sca1e computer installation today, a considerable amount of time of the (general purpose) processor is spent on “operating the system”. With the emerging advent of multiprocessor installations the question arises to what extent such “housekeeping activities” can be carried out concurrently with the computation(s) proper. Because the more intimate the interference, the harder the organization of the cooperation between the concurrent processes, the problem of garbage collection was selected as one of the most challenging —and, hopefully, most instructive!— problems. Whether the following solution is of any economic significance, is a question beyond the scope of this article.

We tackled the problem as it presents itself in the traditional implementation environment for pure LISP (and shall describe our solution in the usual terminology, leaving the natural generalizations to the reader). The data structure to be stored consists of a directed graph in which each node has at most two outgoing edges, more precisely: may have a left-hand outgoing edge and may have a right-hand outgoing edge. (Either of them or both may be missing.) At any moment in time all the nodes of the graph must be “reachable” (via a directed path along the directed edges) from one or more fixed nodes —called “the roots”— with a constant place in memory. The storage allocated to each node is constant in time and equal in size, viz. sufficient to accommodate two pointers —one for each possible outgoing edge— pointing to the node’s immediate successors (if any: a missing edge is coded by means of a special pointer-value that has been reserved for that purpose). Given (the address of) a node, finding (the address of) its left- or right-hand successor node can be regarded in this representation as an atomic, primitive action; finding its predecessor nodes, however, would imply a search through memory.

For a reachable node an outgoing edge may be deleted, changed or added. Note that deletion and change of an outgoing edge may turn a number of formerly reachable nodes into unreachable ones: they become what is called “garbage”. Changing or adding an edge may direct the new edge towards a target node that was already reachable or towards a new node that has to be added to the data structure; such a new node —which upon creation has no outgoing edges— is taken from the so-called “free list”, i.e. a linked list of node (locations) that are currently not used for storing a node from the data structure. Garbage may arise anywhere in store, and it is the purpose of the so-called “garbage collector” to detect such disconnected and therefore obsolete nodes and to append them to the free list.

In classical LISP implementations the computation proper proceeds until the free list is exhausted (or nearly so). Then the computation proper comes to a grinding halt, during which the central processor is devoted to garbage collection. Starting from the roots all reachable nodes are marked; upon completion of this marking phase all unmarked nodes that are not in the free list are garbage and are appended to the free list, after which operation the computation proper is resumed. The minor disadvantage of this arrangement is the central processor time spent on the collection of the garbage; its major disadvantage is the unpredictability of these garbage collecting interludes, which makes it hard to design such a system so as to meet real time requirements as well. It was therefore tempting to investigate whether a second processor —called “the collector”— could collect garbage on a more continuous basis, concurrently with the activity of the other processor —for the purpose of this discussion called “the mutator”— which would be dedicated to the computation proper. We have imposed upon our solution a few constraints. The (microscopic) interference between collector and mutator should be minimal —i.e. no highly frequent mutual exclusion of elaborate activities, as this would defy our aim of concurrent activity—, the overhead on the activity of the mutator (as required for the cooperation) should be kept as small as possible, and, finally, the ongoing activity of the mutator should not impair the collector’s ability to identify garbage as such as soon as logically possible. (One synchronization measure is evidently unavoidable: when needing a new node from the free list, the mutator may have to be delayed until the collector has collected some garbage. This is the now traditional producer/ consumer coupling; in the context of this article it must suffice to mention that this form of synchronization can be achieved without any need for mutual exclusion.)

A counterexample taught us that the goal “no overhead for the mutator” is unattainable. Suppose that nodes A and B are permanently reachable via a constant set of edges, while node C is reachable only via an edge from A to C . Suppose furthermore that from then on the mutator performs with respect to C repeatedly the following sequence of operations:

1) | making an outgoing edge from B to point to C
2) | deleting the edge from A to E
3) | making an outgoing edge From A to point to C
4) | deleting the edge from B to C .

The collector, which observes nodes one at a time, will discover that A and B are reachable from the roots, but never needs to discover that C is reachable as well: while A is observed by the collector, C may only be reachable via B and the other way round. Therefore, when changing or adding an edge, the mutator may have to mark in some way the target node of the new edge.

Marking will be described in terms of colours. when we start with all nodes white, and, furthermore, the combined activity of collector and mutator can ensure that eventually all reachable nodes become black, then all white nodes that are not already on the free list can be identified as garbage. For each repetitive process —and the marking process certainly is one— we have always two concerns: firstly we must have a monotonicity argument on which to base our proof of termination, secondly we must find an invariant relation which, initially true and not being destroyed, will still hold upon termination.

For the monotonicity argument we suggest (fairly obviously)

A) | each node will only darken monotonically.

For the invariant relation during the marking phase —a relation which must be satisfied both before and after marking— we propose (perhaps less obviously, but not unnaturally)

B) | no edge will ever point from a black node to a white one.

Additional action is required from the mutator when it is about to place an edge from a black node to a white node: just placing it would cause a violation of requirement 8 . Requirement A tells us that the black source node of the new edge has to remain black, and, therefore, requirement B implies that the target node of the new edge cannot be allowed to remain white. But the mutator cannot make it just black, because that could cause a violation of requirement B between the target node and its immediate successors. For that reason grey is introduced as an intermediate colour and the only overhead on the activity of the mutator will be —irrespective of the colour of the source node of the new edge—

| “before placing a new edge, the mutator makes its new target at least grey”.

Note 1. Making a node “at least grey” turns a white node into a grey one and leaves the colour of an initially grey or black node unchanged. It is assumed to be available as an atomic, primitive action. (End of Note 1.)

When all the roots are non-white, requirement B is satisfied, and there are no grey nodes, we can conclude that all reachable nodes are black and that, therefore, all white nodes are either garbage or on the free list. Two problems, however, present themselves: the collector has to distinguish between those two types of white nodes and, more seriously, as long as the nodes on the free list remain white, the mutator can create new grey nodes, and for the collector it will in general be very hard to reach the state without grey nodes and to detect that it has done so. The most elegant solution is to arrange matters in such a way that (due to collector activity) the nodes on the free list will eventually become black as well, as this solves both problems: when all reachable nodes are black, and all nodes on the free list are also black, further creation of grey nodes is excluded and all white nodes can be concluded to be garbage.

The simplest way to arrange that the nodes of the free list will be coloured as well is to introduce an additional root from which all the nodes on the free list (linked via edges!) are reachable. During the marking phase the collector makes no distinction between the free list and the data structure proper, and in the initial absence of black nodes it performs repeatedly the following program —assertion names being added within braces— :

marking phase: {P0}
| make all roots at least grey {P1};
| repeat for a node i observed by the collector to be grey:
|  | make the left-hand successor of node i (if any) at least grey;
|  | make the right-hand successor of node i (if any) at least grey;
|  | make node i black
| until in a single scan in some order all nodes have been observed to
|  | be non-grey {P2};
collecting phase:
| process all nodes in some order, where “to process a node” means that
| a white node is appended to the free list and a black node is made
| white {P3}

Note 2. To make a node black is assumed to be an atomic, primitive action available to the collector. The final colour of a node made black by the collector and “simultaneously” made at least grey by the mutator will be black, i.e. as if the two operations had been performed in some order. (End of Note 2.)

Note 3. To make a node white is assumed to be an atomic, primitive action available to the collector. The final colour of a node made white by the collector and “simultaneously” made at least grey by the mutator will be either white or grey, i.e. as if the two operations had been performed in some order. (End of Note 3.)

Note 4. The mutator takes nodes away from one end of the free list, the collector appends nodes to the other end. The prevention of undesired interference between those two actions does not require mutual exclusion in time, see [1]. (End of Note 4.)

The assertions and conclusions justifying the design are the following.
P0:     There are no black nodes, and, therefore, requirement B (no edges from a black node to a white node) is satisfied.
P1:     There are no edges from a black node to a white node and all roots are at least grey; as a result the existence of a white reachable node (those on the free list included) implies the existence of at least one grey node.
P2:     There are no grey nodes 4-see Note 5— and as P1 still holds, all white nodes are garbage and will remain white as far as mutator activity is concerned. This state is reached by the collector thanks to the monotonicity of the colour history of each node during the marking phase and the fact that the collector effectively darkens (at least node i !) as long as it finds a grey node.
P3:     During the collecting phase requirements A and B may be violated. Requirement A is here inessential because the collecting phase does not depend on it for termination and requirement B is restored at completion of the collecting phase, because the mutator cannot create black nodes and all nodes that were black have been made white by the collector.

Note 5. The conclusion that there are no grey nodes when in a single scan all nodes have been observed by the collector to be non-grey requires some further justification, as one of the nodes observed to be non-grey —white, to be precise— in the meantime could have been made grey by the mutator. Thanks to the continuing validity of P1 and the fact that the mutator leaves a grey node grey, however, the conclusion is justified. Suppose that during the scan the mutator has introduced a number of grey nodes. Consider the moment of the first time that the mutator did so; at that moment that node was a white reachable node (those on the free list included) and, therefore, it must have been so when the scan started. On account of P1 we can now conclude that when the scan started a grey node must have existed. As the mutator leaves grey nodes grey, the collector must have encountered that grey node during the scan. Therefore, if during the scan the collector has not encountered a grey node, the mutator cannot have created one either and the conclusion “there are no grey nodes” is therefore justified. (End of Note 5.)

Note 6. It is assumed that when the collector establishes (the address of) the left-hand successor of node i “simultaneously” with a redefinition of the left-hand successor of node i by the mutator, the result will be as if inspection and modification are done in some order: the collector will be directed either towards the old or towards the new left-hand successor. It is not difficult to verify that under all circumstances requirement B remains fulfilled. (End of Note 6.)

Finally: at the beginning of a collecting phase some garbage may be white and some may be black. At the end of that collecting phase all initially white garbage has been collected, all initially black garbage has been made white and will remain so during the next marking phase until it will be collected during the next collecting phase. As a result we can guarantee that no garbage, once created, will escape being collected.

History and acknowledgements. (As in this combination this is our first exercise in international and inter-company cooperation, some internal credit should be given as well.) After a careful consideration of a wider class of problems the third and the fifth authors selected and formulated this problem and did most of the preliminary investigations. The first author found a first solution during a discussion with the latter, W.H.J.Feijen and M.Rem. It was independently improved by the second author —to give the free list a root and mark it as well was his suggestion— and, on a suggestion made by Jack Mazola, by the first end the third author. The first and the fourth merged these embellishments and produced the version published above.

Reference.
1. Lamport, Leslie. On Concurrent Reading and Writing. (Submitted to the Comm.ACM. ’

20th June 1975

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD497

A challenge to memory designers?

In the good old sequential days memory accesses took place one after the other, and a memory technique (such as ferrite core technology) that could accommodate one access at a time was adequate. When independent I/O-channels were introduced, the memory access mechanism became a resource shared between the central processor and the channel(s), and a switch was introduced which --usually on a priority basis-- granted mutually exclusive accesses to the various competitors. ("Cycle stealing" was the term then introduced to describe that arrangement.) It seems worthwhile to point out that originally the need for mutual exclusion was a purely technical one, dictated by ferrite core technology: as program areas, working space and buffers were at any moment in time disjoint, there was no logical reason.

Or: hardly so, to say the honest truth. This disjointness of these areas of concurrent activity could only be guaranteed thanks to a macroscopic synchronization of computing and I/O-activities, and for the implementation of such synchronization constraints, it was sometimes exploited that the mutually exclusive storage cycle consisted of a "read", followed by a "write". Examples are the test-and-set instruction, the swap (between a memory location and a register) or the indivisible "add-to-memory". The mutual exclusion, i.e. the indivisibility of these operations on memory words was suddenly a logical necessity: nothing prevented different processors to attempt to access the same location simultaneously.

The difference is pointed out in connection with the solution described in EWD496 "on-the-fly garbage collection: an exercise in cooperation.", in which two processors are supposed to operate in the same memory: as long as they access different words in memory, there is no logical objection at all to have these different accesses overlap in time. The possibility of simultaneous attempts to access the same storage location --all the time and all through memory-- is the rule, the actual coincidence of such attempts will be the exception.

For that reason one dreams of a memory arrangement in which simultaneous accesses can take place unencumbered as long as different locations are involved, and mutual interference (i.e. delays) will only occur at those exceptional moments when it is logically necessary, i.e. when the same word is involved in more than one attempted access. Compared with that dream, the current solution with the switch that always imposes mutual exclusion independent of such coincidence, is a safe but crude solution. This crudeness is pointed out because it might be acceptable with the number of processors N = 2, but it won't remain so if N grows: for sufficiently large N, the possibility of many simultaneous accesses seems to become some sort of must.

I have no idea how such a memory would look like --an electronically rotating memory with many sensing stations?--, hence the word "challenge" in my title. Let me finally explain the presence of the question mark: with EWD496 we now have one such algorithm with N = 2, say. The question of whether we shall be able to design more of those, with the values of N that are considerably higher, is still an open question.

9th June 1975
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sat, 12 Jun 2004

EWD498

How do we tell truths that might hurt?

Sometimes we discover unpleasant truths. Whenever we do so, we are in difficulties: suppressing them is scientifically dishonest, so we must tell them, but telling them, however, will fire back on us. If the truths are sufficiently impalatable, our audience is psychically incapable of accepting them and we will be written off as totally unrealistic, hopelessly idealistic, dangerously revolutionary, foolishly gullible or what have you. (Besides that, telling such truths is a sure way of making oneself unpopular in many circles, and, as such, it is an act that, in general, is not without personal risks. Vide Galileo Galilei.....)

Computing Science seems to suffer severely from this conflict. On the whole, it remains silent and tries to escape this conflict by shifting its attention. (For instance: with respect to COBOL you can really do only one of two things: fight the disease or pretend that it does not exist. Most Computer Science Departments have opted for the latter easy way out.) But, Brethren, I ask you: is this honest? Is not our prolonged silence fretting away Computing Science's intellectual integrity? Are we decent by remaining silent? If not, how do we speak up?

To give you some idea of the scope of the problem I have listed a number of such truths. (Nearly all computing scientists I know well will agree without hesitation to nearly all of them. Yet we allow the world to behave as if we did not know them....)

*                            *
*

Programming is one of the most difficult branches of applied mathematics; the poorer mathematicians had better remain pure mathematicians.

The easiest machine applications are the technical/scientific computations.

The tools we use have a profound (and devious!) influence on our thinking habits, and, therefore, on our thinking abilities.

FORTRAN —"the infantile disorder"—, by now nearly 20 years old, is hopelessly inadequate for whatever computer application you have in mind today: it is now too clumsy, too risky, and too expensive to use.

PL/I —"the fatal disease"— belongs more to the problem set than to the solution set.

It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration.

The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offence.

APL is a mistake, carried through to perfection. It is the language of the future for the programming techniques of the past: it creates a new generation of coding bums.

The problems of business administration in general and data base management in particular are much too difficult for people that think in IBMerese, compounded with sloppy English.

About the use of language: it is impossible to sharpen a pencil with a blunt axe. It is equally vain to try to do it with ten blunt axes instead.

Besides a mathematical inclination, an exceptionally good mastery of one's native tongue is the most vital asset of a competent programmer.

Many companies that have made themselves dependent on IBM-equipment (and in doing so have sold their soul to the devil) will collapse under the sheer weight of the unmastered complexity of their data processing systems.

We can found no scientific discipline, nor a hearty profession on the technical mistakes of the Department of Defense and, mainly, one computer manufacturer.

The use of anthropomorphic terminology when dealing with computing systems is a symptom of professional immaturity.

By claiming that they can contribute to software engineering, the soft scientists make themselves even more ridiculous. (Not less dangerous, alas!) In spite of its name, software engineering requires (cruelly) hard science for its support.

In the good old days physicists repeated each other's experiments, just to be sure. Today they stick to FORTRAN, so that they can share each other's programs, bugs included.

Projects promoting programming in "natural language" are intrinsically doomed to fail.

*                            *
*

Isn't this list enough to make us uncomfortable? What are we going to do? Return to the order of the day, presumably.......

18th June 1975
Plataanstraat 5
NUENEN – 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

PS. If the conjecture "You would rather that I had not disturbed you by sending you this." is correct, you may add it to the list of uncomfortable truths.

| EWD

Transcribed by Richard Walker.
Last revised on Thu, 3 Apr 2008.

EWD499

Na zeven jaar aan de Technische Hogeschool te Eindhoven te hebben doorgebracht, gaat U naar de Rijksuniversiteit te Leiden. Ik ben daar persoonlijk wel blij mee, want voor de laatste instelling, mijn Alma Mater, heb ik nog altijd wel een zwak plekje.

U zult merken, dat deze grillige oude dame, die zojuist haar vierhonderdste verjaardag heeft gevierd, een vat vol tegenstrijdigheden is. Zij is enerzijds een instituut waarin tradities een grote rol spelen, anderzijds is zij traditioneel progressief: in mijn studententijd, toen een politiek linksgericht student nog als een contradictio in terminis gold, was Leiden al duidelijk rose. Het is, alsof de dame vrolijk in de voorste gelederen der vernieuwing meer huppelt om een ieder te tonen, dat haar aderen nog niet verkalkt zijn. U zult merken, dat de oude dame daar soms wel moe van wordt, en zich soms amechtig laat overvallen door de gegronde twijfel, of het allemaal nu heus zo moet. We zijn nu in het stadium, dat de polonaise, waarin ze nog met enig enthousiasme meekon, door minister van Kemenade allengskens het rythme krijgt opgedrongen van de tarantella, de onheilspellende dodendans der bezetenen.....

Eertijds hadden we het ministerie van O.K. en W. In een vlaag van culturele barbarij is de K ervan afgevoerd, de W is hard aan het verdwijnen en menigeen vraagt zich met zorg af, hoelang de O nog voor Onderwijs zal staan. Leek het er enige tijd gelden nog op, dat het de O van Opleiding zou worden, nu blijkt het de O van Opvoeding (of misschien wel Omturning!) te worden, Omturning tot de grauwe eenheidsmens, het enige type, waarvoor blijkbaar nog plaats is in des ministers visioen van de socialistische heilstaat. U make zich geen illusies: de man meent het echt. We hebben een minister van O, die het onderwijs volledig aan zijn dictatoriale laars lapt, die in plaats van het Onderwijs te dienen, het Onderwijs dienstbaar wil maken, dienstbaar aan een visioen, dat alle kenmerken vertoont van de hallucinatie van een religieus fanaticus.

Ik overdrijf niet. Na gelijke onderwijskansen voor iedereen gepropageerd te hebben, maakt hij, blijkens de vorige week gepubliceerde contourennota, zich ernstige zorgen, dat als ieder in eigen tempo, naar eigen begaafdheid en ambitie studeren kan, dit de onderlinge verschillen der abiturienten zal vergroten. Allicht: wie door begaafdheid, door ijver of —nog erger— door de combinatie van beide op zijn leeftijdsgenoten uitloopt, zal steeds verder voor gaan liggen. Blijkens de tekst beschouwt de minister zulke uitschieters een ernstig gevaar, waarvan de bestrijding hem ernstige zorgen baart. En een dag later weet de krant te melden, dat met de invoering van de middenschool de traditionele schoolvormen dienen te verdwijnen. Niet dat b.v. de gymnasia, die op de dodenlijst geplaatst zijn, slechts zouden zijn. Integendeel! Volgens de minister zouden de moeilijkere traditionele scholen, als ze naast de middenschool zouden blijven bestaan, de begaafde leerlingen aantrekken, waardoor de middenschool niet tot zijn recht zou kunnen komen! Kortom: de gymnasia moeten weg, omdat ze te goed zijn. M.a.w.: we hebben een minister die zonder een spier te vertrekken een cultureel kostbaar erfgoed opoffert aan zijn Nieuwe Orde. Het is eerder 1984, dan U denkt.

In vind een door ideologie aangewakkerde vervolging van intellectuelen net zo'n griezelige zaak als een ideologisch gevoede jodenvervolging. Bij de jodenvervolging aarzelde de oude dame niet: zij sloot haar huis en dook onder. Zal zij weer weten, hoe ze zich dient te gedragen? U gaat in elk geval een moeilijke tijd tegemoet, waarin ik U sterkte wens.

Rest mij slechts U en de U dierbaren van ganser harte geluk te wensen met de voltooing van Uw academische studie en U een loopbaan toe te wensen, die tot in de lengte van Uw dagen U voldoening zal blijven schenken.

transcribed by F. Koenders
revised Thu, 13 Nov 2008

05xx

500: After many a sobering experience

501: Variations on a theme: an open letter to C.A.R. Hoare

502: On a gauntlet thrown by David Gries

503: A post-scriptum to EWD501

504: Erratum and embellishments of EWD503

506: Tripreport E.W.Dijkstra: NATO Summer School Marktoberdorf 1975

507: On a gauntlet thrown by David Gries

508: A synthesis emerging?

509: Eerste toespraak, najaar 1975

511: Tripreport E.W.Dijkstra W.G.2.3, Baden, 1–5 September 1975

512: Comments at a symposium

513: Tripreport E.W.Dijkstra Newcastle, 8–12 September 1975

514: On a language proposal for the Department of Defense

515: Tweede toespraak, najaar 1975

516: Derde toespraak, najaar 1975

518: Vierde toespraak, najaar 1975

520: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, E.F.M.Steffens)

521: Vijfde toespraak, najaar 1975

522: Zesde toespraak, najaar 1975

523: Zevende toespraak, najaar 1975

524: Review of “On the Feasibility of Software Certification”

525: On a warning from E.A.Hauck

526: Comments on “Woodenman” HOL Requirements for the DoD

527: On units of consistency

528: More on Hauck's warning

529: Achtste toespraak, najaar 1975

530: Negende toespraak, najaar 1975

531: Tiende toespraak, najaar 1975

532: An open letter to L.Bass

533: HOMO COGITANS

534: Elfde toespraak, najaar 1975

535: An answer to Jack Mazola

536: A sequel to EWD535

537: Twaalfde toespraak, najaar 1975

538: A collection of beautiful proofs

539: Mathematics Inc., a private letter from its chairman

540: Two views of programming

541: Dertiende en laatste toespraak, najaar 1975

542: [Toespraak tot twee afstudeerders]

543: Eerste toespraak tot mijn studenten, voorjaar 1976

544: An open letter to Ross Honsberger

547: Tripreport E.W.Dijkstra, England and USA, 3-26 January 1976

548: Tweede toespraak tot mijn studenten, voorjaar 1976

549: Derde toespraak tot mijn studenten, voorjaar 1976

550: A more formal treatment of a less simple example

551: Vierde toespraak tot mijn studenten, voorjaar 1976

552: Vijfde toespraak tot mijn studenten, voorjaar 1976

553: On a gauntlet thrown by David Gries

554: A personal summary of the Gries-Owicki theory

555: Aan de Raad van Advies

556: Zesde toespraak tot mijn studenten, voorjaar 1976

557: Zevende toespraak tot mijn studenten, voorjaar 1976

558: Achtste toespraak tot mijn studenten, voorjaar 1976

559: Negende toespraak tot mijn studenten, voorjaar 1976

560: Tiende toespraak tot mijn studenten, voorjaar 1976

561: A “non trip report” from E.W.Dijkstra

562: The effective arrangement of logical systems

563: Formal techniques and sizeable programs

564: A superficial book

564a: Aan de Raad van Advies, in tweede ronde.

565: Elfde toespraak tot mijn studenten, voorjaar 1976

566: Programming: from craft to scientific discipline

567: Twaalfde toespraak tot mijn studenten, voorjaar 1976

568: A programmer’s early memories

569: Dertiende en laatste toespraak tot mijn studenten, voorjaar 1976

570: An exercise for Dr.R.M.Burstall

571: A simple consideration with far-reaching consequences (DRAFT)

572: Tripreport E.W.Dijkstra, U.S.A. and U.K., 8 June - 10 July 1976

573: A great improvement

574: A letter to Professor Zohar Manna, 26 July 1976

575: To H.D.Mills, Chairman Software Methodology Panel

576: On subgoal induction

577: Tripreport E.W.Dijkstra, ECI-conference 9–12 August 1976, Amsterdam

578: More about the function “fusc” (A sequel to EWD570)

580: Waarom de onderafdeling der wiskunde zich met de informatica moet bezighouden

581: A somewhat open letter to Professor John McCarthy

582: A proof of a theorem communicated to us by S.Ghosh (with C.S.Scholten)

583: Eerste toespraak tot mijn studenten, najaar 1976

584: Tripreport E.W.Dijkstra, Poland and USSR, 4-25 September 1976

585: Tripreport E.W.Dijkstra, Tokyo, 28 Sep.—3 Oct. 1976

586: Tweede toespraak tot mijn studenten, najaar 1976

587: Derde toespraak tot mijn studenten, najaar 1976

588: Vierde toespraak tot mijn studenten, najaar 1976

589: Vijfde toespraak tot mijn studenten, najaar 1976

590: A first investigation of the crossflow computer

591: The problem of the maximum length of an ascending subsequence

592: A small note on the additive composition of variant functions

593: Zesde toespraak tot mijn studenten, najaar 1976

594: A parable

595: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, E.F.M.Steffens)

596a: Tripreport E.W.Dijkstra, Copenhagen 10–12 Nov. 1976

597: Yet another note about termination

  EWD 500

After many a sobering experience.

EWD492 was written in a state of great excitement: it described —without proof— for the on-the-fly garbage collection our first solution, which we had found on the previous Tuesday afternoon. (On Fool's Day! We should have known...) The next Tuesday afternoon, when we tried to give a proof of its correctness, we quickly found the bug. It was repaired by postulating the availability of the atomic action "make at least grey" instead of the original

if node is observed to be white → make it grey
⌷ node is observed to be non-white → skip
fi

The bug was, that between the node being observed to be white and the subsequent action "make it grey", if done by the mutator, the collector could have made it grey and subsequently black. Such interleaving would violate the intended monotonicity of the colour history for each node; hence our introduction of "make it at least grey". Our then correct solution went through a series of embellishments, and, eventually —more than two months later!— EWD496 was written. And that was that.

A few weeks later the question was raised whether the dual-processor configuration with one mutator and one collector could be generalized into a multi-processor one, with many mutators and, more interesting, many sequential processors for the garbage collection as well. And we designed a system with as many mutators as we had LISP-programs, an arbitrary number of "markers" and one "collector proper".

The mutators would, as before, make the target node of each edge at least grey before placing the edge.

The markers would search from grey nodes: each grey node found they would make black after having made its successors at least grey. This would be a continuously ongoing activity, their search for grey nodes would be such that eventually each grey node would be found by at least one of them.

The collector proper was proposed to consist of the repeated execution of

make the roots at least grey;

scan all the nodes in some order and make for each node observed to be black, its successors at least grey {now edges from a black node to a white node have disappeared};

wait until in a single scan in some order all nodes have been observed to be non-grey {all white nodes are garbage};

process all nodes in some order, where "to process a node" means that a white node is appended to the free list and a black node is made white.

In EWD496, the last activity caused all black nodes to disappear, so that edges from a black to a white node were then guaranteed to be absent. Because here our markers are supposed to continue their activity, the absence of edges from black to white cannot be guaranteed, hence the insertion of the second statement, which indeed establishes this absence (any edges from black to white that were present can no longer lead to a white node and neither mutators nor markers can have introduced new ones).

For nearly two weeks I thought the above solution was correct, until I started to try to prove its correctness. It turned out to be wrong. Observing in a single scan in some order all nodes to be non-grey is no longer sufficient to conclude that all white nodes are garbage. The argument breaks down where in EWD496 - 6, Note 5, was written: "As the mutator leaves grey nodes grey, the collector must have encountered that grey node during the scan." This conclusion does not hold for our collector proper, because during that scan the ongoing marker activity may have made the grey node black! So there I was. Fooled again....

So —rather reluctantly, I admit— I introduced some more activity for the collector proper and a fourth colour, ultrablack say (which is regarded to be darker than black). The mutators remain as they are, the markers react as above on a node observed to be grey, but make it "at least black" (instead of just "black" as above) and the collector proper that I considered was the repeated execution of the following program:

{Q0}
make all the roots at least grey {Q1};

scan all the nodes in some order and make for each node observed to be black its successors at least grey {Q2};

repeat make each node, observed to be black, ultrablack
until in a single scan in some order all nodes have been observed to be white or ultrablack {Q3};

process all nodes in some order, where "to process a node" means that a white node is appended to the free list and an ultrablack node is made white.

The intended assertions are:

Q0: | there are no ultrablack nodes
Q1: | there are no ultrablack nodes and the roots are at least grey
Q2: | there are no edges from black to ultrablack to white and the roots are at least grey. (As a result, the presence of a white reachable node implies the existence of at least one grey node.)
Q3: | there are no grey nodes and Q2 still holds. (As a result, all white nodes are therefore garbage.)
Q4: | there are no ultrablack nodes.

Assertions Q0 and Q1 present no problems, because neither mutators nor markers introduce ultrablack nodes. For Q2, the absence of edges from ultrablack to white follows from the absence of ultrablack nodes, the absence of edges from black to white follows from the fact that neither mutators nor markers introduce them and those originally present have disappeared or point no longer to a white node.

During the introduction of ultrablack nodes, Q2 remains valid: the only nodes made ultrablack are already black, therefore they don't point to a white node and edges from ultrablack to white are not introduced. (Remember that mutators make each new target at least grey.) But now the critical step: is conclusion Q3 justified? In a single scan in some order all nodes have been observed to be either white or ultrablack: does this fact justify the conclusion that there are no grey nodes? This must be hard to prove. Consider the following scenario:

Let there be an edge from a grey node A to a white node B; let marker 1 have observed node A to be grey and have decided to make node B at least grey; hereupon, marker 1 goes to sleep; let the edge from A to B be removed by a mutator; let marker 2 observe node A to be grey and make it black; let the collector proper make node A ultrablack. As soon as marker 1 wakes up again it will make the still white node B at least grey!

There seem to be two ways out: one of them could be to divide the memory into as many sections as we have markers, such that each marker only searches for grey nodes in its own section. Alternatively, we can try to weaken Q3.

I tried weakening Q3 first (such as "There are no grey, reachable nodes.") and although that would be sufficient to conclude that all white nodes are garbage, I could not exclude the occurrence of grey garbage at stage Q3. In its last phase the collector makes dark garbage white, so that it can be collected the next time; the presence of grey garbage, however, can trigger a counter activity of a marker and as a result, existing garbage may forever escape being collected.

So: can we conclude the absence of grey nodes when each node can only be made black by a single marker?

When after a single scan all nodes have been observed to be either white or ultrablack, Q3 "there are no grey nodes" can only be violated provided since the start of the scan, a grey node has been introduced.

The introduction of a grey node by a mutator would have implied the existence of a white reachable node, and therefore of a grey node, when the scan started. This latter grey node would have been detected during the scan as either a grey or a black one, contrary to the hypothesis.

The introduction of a grey node by a marker implies at that moment a grey node in its section, which at the end of the scan will be grey or black. The assumption that the scan has observed it to be white implies the earlier introduction of a grey node since the scan started, and as a mutator cannot have caused the earlier introduction, also that earlier introduction must have been caused by a marker. The argument can be repeated and, the store being finite, leads to a contradiction.

All through the scan there have been no grey nodes; as a result, no black nodes have been introduced, no black nodes have been observed either, and we can strengthen Q3 "There are no grey nodes and no black nodes, only white and ultrablack ones, and all white nodes are garbage."

During the last phase of the collector proper, the mutators and the markers will in general introduce grey and black nodes, but each of the nodes encountered by the collector will be either white or ultrablack: the ones that were originally ultrablack will remain so until the collector proper has made them white, the originally white ones will remain so until the collector proper has appended them to the free list, because before that moment, the white node was garbage, and garbage remain untouched by the mutators (by definition) and by the markers, because there were no grey nodes to start with. (Note that nothing prevents during the last phase of the collector proper the creation of —new!— grey garbage! But none of the grey nodes introduced during that last phase can have an outgoing edge with one of the originally white garbage nodes as target.)

Salvo errore et omissione, this completes the argument.

*                   *
*

The first moral of this story is never to believe the correctness of a solution without a proof for it. The second moral of this story is never to forget the first one. The moral is that for the design of multiprocessor installations we cannot rely on the traditional approach of the optimistic engineer, who, when the design looks reasonable, puts it together to see if it works.

With LSI-technology existing it seems unavoidable that multiprocessor installations will be built, and people being as they are, it seems equally unavoidable that many of them will be put together by aforementioned optimistic engineer. I shudder at the thought of all the new bugs: they will only delight the Devil. Am I too pessimistic? Nobody knows the trouble I have seen....

Plataanstraat 5 5671 AL NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sun, 13 Aug 2006

EWD501

Copyright Notice

The following manuscript

EWD 501: Variations on a theme: an open letter to C.A.R. Hoare

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 132-140 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
Springer-Verlag, 1982. ISBN 0-387-90652-5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

5th July 1975

Variations on a theme: an open letter to C.A.R.Hoare.

Dear Tony!

For a variety of reasons I have not yet reacted to your article on Monitors [1]. For one thing: it failed to convince me —something I felt bad about, because I knew that this might have been due to the circumstance that I had been too lazy to go in detail through your more sophisticated examples—. Secondly: I was not too pleased either with the alternatives I could offer myself —my difficulty in finding good identifiers for the operations I was considering was just a symptom of my own mixed feelings—. Eventually I got interested in what one can do without mutual exclusion, and I dropped the subject� —not without remorse, for I had left a task undone: I had failed to make up my mind!—.

Recently the topic was brought back to my attention by a nice technical report by Coen Bron [2], and in a Tuesday afternoon discussion with Wim Feijen, Alain Martin, Martin Rem and Liesbeth Steffens I tried, as a result, to redesign my (formerly rejected) alternative, in the hope that this time I could do a more conclusive job. This letter records the quintessence of that discussion and the following considerations.

About the microscopic delays implied by mutual exclusion.

The whole purpose of a monitor is to grant mutually exclusive access to a bunch of common variables, and this implies two things.

First: the whole monitor concept is only adequate in circumstances such that a monitor will only be "active" during a negligible fraction of time. (And, on the next higher level of abstraction, we shall indeed ignore the CPU-time spent on "monitoring"!) Second: in any multiprocessor installation, attempted monitor calls while the monitor is active imply delays, but in view of the first remark I propose to attach no significance whatsoever to the order in which such "microscopic" delays have been caused. Such microscopic delays will last until the moment when otherwise the monitor would have become inactive, and one of the microscopically delayed processes will be granted access to the monitor. Our only (logical!) requirement is the exclusion of the (in view of our first remark highly improbable) danger of individual starvation. (Round Robin, for instance, would do!) In the following the microscopic delays will not be mentioned anymore, logically it is as if "by magic" no process attempts to call a monitor while it is active. (Early in the discussion I had failed to make a clear distinction between microscopically delayed processes eager to call the monitor, and macroscopically delayed processes that, being woken up, were eager to continue an interrupted execution of a monitor procedure —in what follows the latter class will disappear—; this confusion was so disastrous that it did not last long!)

Note. At the lowest level I expect no objection to implementing the microscopic delays by means of the busy form of waiting. (End of Note.)

About the macroscopic delays introduced by a monitor

The further purpose of a monitor is to introduce macroscopic delays when necessary, and, ideally, a monitor is formulated in such a fashion that it does not reflect the number of partners between which the cooperation is regulated. It should describe "my" behaviour versus "the others". (In the THE-system the cooperation was coded in a context in which all partners were individually known and explicitly referred to; in retrospect I regard that now as one of the more significant shortcomings of that system.) In order to describe the rules of cooperation in a way which was independent of the number of partners involved, I envisaged to describe it in terms of a finite number of named queues of sleeping —i.e. macroscopically delayed— processes, where the queues themselves could be of any length, and each sleeping process would occur at exactly one queue.

Right at the start, our decision that the elements on a queue should be linearly ordered, seemed more emphatic than yours. You write: "If more than one program is waiting on a condition, we postulate that the signal operation will activate the longest waiting program. This gives a simple, neutral queueing discipline, which ensures that every waiting program will eventually get its turn." But if individual starvation is the danger you would like to exorcize, Round Robin or allowance counts would have done as well.

I propose for the linear order of the elements in each queue a role that seems to me much more fundamental: "the (sleeping) others" are known to "me" by virtue of their place in one of the queues. If they were sets instead of linearly ordered queues, the different "(sleeping) others" would have no distinct identities.

*                    *
*

(Continued after an interlude during which I just listened to Dvorak's Serenade —mainly for wind instruments— in D moll, opus 44: a delightful piece of music!)

I saw —you know my weakness for railroad metaphors!— the queues as one-directional railroad tracks of a shunting yard with each "(sleeping) other" in its own carriage —sleeper, if you so desire!— somewhere on one of the tracks of the shunting yard. Waking up a process implies that it leaves the yard and, therefore, the track on which it is waiting. But why should leaving a track imply waking up? In this view it comes quite naturally to allow that sleeping processes can be shunted from one track to another without being woken up. Thanks to this metaphor I freed myself of one of the constraints you had introduced.

Now for some terminology, in order to avoid misunderstanding. A process is "in monitor state" from the beginning of the execution of the first statement of a monitor procedure it has called until the end of the execution of the dynamically last statement of that monitor procedure, when its concurrently executable code can continue to be obeyed. For a given monitor n processes may be in monitor state. Either the monitor is inactive: in that case all n processes are sleeping somewhere on the shunting yard and each process, when woken up —i.e. removed from the shunting yard— will continue the execution of the monitor procedure it had called at the point, where it had gone to sleep. Or the monitor is active: in that case n-1 processes are sleeping somewhere on the shunting yard and one of them has the special status "me", viz. the process, whose monitor call is continued to be executed. (Associating your "conditions" with my "tracks" of the shunting yard, this represents a slight departure from your proposal, in which a process that is awake —i.e. does not occur on a queue— can wake up another by signalling: you then have more than one process being awake, but only one, whose monitor procedure execution is continued. I preferred to identify "me" with the one and only active process and to have all others in monitor state explicitly somewhere on the shunting yard.)

What I was looking for was a nice set of operations in terms of which I could describe the shunting, the reallocation of "me" and the leaving of "me" of the monitor state. I did not like your term "condition" as it evoked in my mind the wrong associations: it does not reflect a linearly ordered set of sleeping processes. For lack of a better name I introduced the type "fifoq" —being an acronym for "first-in-first-out-queue"—, but this was a very grave mistake, which led me astray for more than 24 hours! It implies too much about the long-range history whereas at each moment only the current value matters! It was a mental liberation when it dawned upon me that I could stay within the shunting yard metaphor and could just call them "trains". (For a while I used the term "tracks", but that was discarded on account of its associations with drums and disks. Eventually the transitions from track to train turned out to be a blessing: whereas the "track" suggests a "place holder" or a "location", the "train" suggests a value, viz. a linearly ordered sequence of sleeping processes. It opens the way to "train expressions", which describe how new trains are composed out of the cars already on the shunting yard. It is, by the way, frightening to observe the devious and sometimes obnoxious influence of the terms I tentatively introduce! The wrong choice can drag in the wrong associations or deny you the expressive power needed to describe what you would like to think about, but then are unable to do. How does one avoid falling unaware into the trap of the inadequate metaphor? I know so many earlier instances of my falling into that trap and I honestly try to be aware of the danger: yet I did it again!)

My next problem was with "wait" and "signal"; I tried "sleep" and "wake", but quickly ran out of names for more intricate shunting operations, possibly to be combined with a redefinition of "me": I found myself forced to describe the operation in which "me" should go to sleep "somewhere", and another sleeper should take over the role of "me" instead. I even considered horrible neologisms like "slake", in order to express the combination of putting one process to sleep and waking up another. As you can imagine, I quickly ran out of descriptive names.

The way out seemed the intrduction of "train expressions" and an assignment statement. The train expression would describe the new train as a concatenation of (cars of) existing trains: its "evaluation" would have as implicit side-effect taking away the cars used in the new train value from the train operands: shunting does not change the number of cars on the shunting yard! I tried to describe just shunting as an assignment to a train variable, just changing monitor activity from one process to another by an assignment to "me" and the combination of the two by a sort of concurrent assignment with at the left-hand side "me" and a train variable.

It was understood that "me" could occur as component of a train expression. And it was the idea that, by definition, the shunting yard should contain the sleeping processes, that caused the need for the concurrent assignment. Composing a new train, containing "me" could not be the first assignment statement, for then the active process would sleep before it had assigned a new value to "me", I could not invert the order either, because then I would have two "me's". Hence the idea of the concurrent assignment, which solves such problems.

It looked promising and I started to write a manuscript, but after a couple of hours at least ten pages were thrown into the waste paper basket, because, although it worked after a fashion, the code needed for the monitors became more and more tortuous as my examples became more ambitious. It was really appalling! I was coding in a conceptually nice and clean interface, but in spite of its conceptual simplicity apparently hopelessly inadequate. It was one of those rare beautiful days in which one can work in the garden, but in spite of the shining sun I was close to desperate. There was only one thing I could do: put all papers away, pour myself a glass of beer, look into the blue sky and figure out where I had got stuck.

One glass of beer —even parts of it!— sufficed. Although "I" have to describe "my" behaviour versus "the others", "I" am part of the whole community, and it is extremely awkward if I cannot treat "me" on the same footing as "the others". While during inactivity of the monitor, all "sleepers" occur on the shunting yard, it is rash to identify —what I had done!— the contents of the shunting yard with "the set of sleepers": during monitor activity, "me" should be allowed to occur (obviously at most once!) on the shunting yard as well, just as one of "the others"! This has a few drastic consequences. For reasons of safety, one should insist that all semicolons of a monitor procedure fall into one of two categories: those semicolons where "me" is somewhere on the shunting yard —and placing "me" on the shunting yard is not allowed and redefining "me" implies that the old "me" remains in monitor state and goes to sleep— and those semicolons, where "me" is not on the yard —where placing "me" on the shunting yard is allowed and redefinition of "me" implies that the old "me" leaves the monitor state—. To allow during monitor activity "me" to appear —at most once!— on the shunting yard solved all my problems. It is such an obvious generalization: during monitor inactivity, "me" does not exist and, therefore, cannot occur on the shunting yard. Yet it took me hours of following of false ideas to discover it! I shall describe my new solutions at another occasion: tomorrow is Sunday, so I am not in a hurry, but in the meantime it is past two o'clock, and I had better go to sleep. I thank you —although you must be unaware of it!— for your patience and your inspiring "presence". My problem is, that I really like letter writing.....

*                    *
*

(Sunday afternoon, 6th July 1975)

Let a train expression enumerate in order from left to right the trains the cars of which are concatenated to form the new train value in order from "head" to "tail". With

tr0, tr1, tr2: train

examples of train expressions are

(tr0, tr1)  :  this train consists of the cars of tr0 , followed by the cars of tr1. As a result of this train formation, the trains tr0 and tr1 have become empty, which value is indicated by "nil".

(tr2, me) forms a train one longer than tr2 , by appending "me" at the rear end.

(me, tr2) forms a train one longer than tr2 , by putting "me" in front of the train tr2.

Shunting operations I shall indicate by means of assignment statements

< train variable > := < train expression >       e.g.

tr0 := (tr1 , tr0)        tr2 := (tr2, me)        tr0 := (tr0, tr1 , tr2)         etc.

After evaluation of the train expression, the train assigned to must be empty, otherwise its cars would "disappear". One way of imposing this is to require that in the train assignment the train assigned to occurs somewhere in the train expression. I shall not do so, and allow

tr0 := (tr1, tr2)

—if you so desire as abbreviation of "tr0 := (tr0, trl, tr2)"— in those circumstances that I can assert the initial emptyness of tr0 .

Potential change of "me" will also be indicated by an assignment statement

me:= head(tr0) me:= nil .

When the value "nil" is assigned to "me", the monitor becomes inactive until the next call of a monitor procedure, which implicitly assigns to "me" the identity of the calling process. The evaluation of the function "head(tr0)" gives for initially non-empty tr0 as value the first element of tr0 , which is taken away from tr0 . (Note that also this is a glorious side-effect: all problems can be solved by postulating that the components of a train expression are evaluated in order from left to right.) If initially tr0 is empty, it remains so, and the value of head(tr0) equals "nil".

These two types of assignment statement enable us to separate completely shunting on the one hand and process switching on the other. Note that an assignment to "me"

1)    must be a dynamically last statement of a monitor procedure when "me" does not occur on the shunting yard; the process that was "me" leaves monitor state and can continue with its concurrently executable code

2)    should not be a dynamically last statement of a monitor procedure when "me" does occur on the shunting yard; the process that was "me" remains in monitor state, but remains asleep until its identity is reassigned to "me", whereafter the execution of the interrupted monitor procedure is resumed at the next statement.

Now for some examples. Let me first code your single resource monitor, which macroscopically on fifo basis grants the single resource ([1], page 550)

single resource: monitor
begin busy: boolean;
          nonbusy: train;
          proc acquire:
                  if busy → nonbusy:= (nonbusy, me); me:=nil
                   ⌷ non busy → skip
                  fi;
                  busy:= true; me:= nil
          corp acquire;
          proc release:
                  if busy → busy:= false; me:= head(nonbusy) fi
          corp release;
          busy:= false
end

(As you have seen, a call of "release" while non busy leads to abortion.) The above is a straight transliteration of your text and does not reflect too clearly, that acquire will only assign the value true to busy , when initially it is false. I offer the following alternative solution for acquire:

proc acquire:
        nonbusy:= (nonbusy, me); me:= head(nonbusy);
        do busy → nonbusy:= (me, nonbusy); me:= nil od;
        busy:= true; me:= nil
corp acquire

When you see this for the first time, it may strike you as a coding trick: depending on whether nonbusy is empty to start with "me: = head(nonbusy)" will leave "me" unaffected or not. The test on "business" is only performed by the one which was at the head of the queue, and when it finds busy true, it places itself back at the head side.

But it allows a nice generalization. Suppose that we have to synchronize the unbounded buffer, where (with p > 0 and c > 0)

prod(p): n:= n + p and cons(c): n:= n - c

have to be synchronized in such a fashion that n ≥ 0 remains invariant. Here we go: (consumers being served on fifo basis)

ubb:monitor
begin n: integer;
          con: train;
          proc prod(p: integer):
                  n:= n + p; me: = head(con)
          corp prod;
          proc cons(c: integer):
                  con:= (con, me); me:= head(con);
                  do n < c → con:= (me, con); me:= nil od;
                  n:= n - c; me:= head(con)
          corp cons;
          n:= 0
end ubb.

Finally, the same problem, but instead of serving the consumers on fifo basis, they may try on fifo basis.

ubb: monitor
begin n: integer;
          con, temp: train;
          proc prod(p: integer);
                  n:= n + p; temp:= (con); me:= head(temp)
          corp prod;
          proc cons(c: integer):
                  if n ≥ c → n:= n - c; me:= nil
                  ⌷ n < c → con:= (con, me) ; me:= nil;
                                  do n < c → con:= (con, me);
                                                   me:= head(temp)
                                  od;
                                  n:= n - c; me: = head(temp)
                  fi
          corp cons;
          n:= 0
end ubb

This strategy has, of course the danger of individual starvation: another strategy with the same danger is to give priority to the requesting consumer with maximum value of c . The coding of that one is quite fun and I leave it as an exercise to you.

                        *                     *
                                   *

If I wanted to make a really strong case for my constructs, I should, of course, continue this letter with the coding of all your examples, but I am not going to do that now: after all, it is Sunday afternoon! For the time being I have the feeling of having done my share, and I am looking forward to your comments in particular.

You will have noticed that, for instance, in "release" I need at the end an additional "me:= nil". We could allow its omission and make the additional rule that it will be supplied by default. If you are going to suggest that as an improvement of my proposal, I promise that I shall get very cross with you (or, for that matter, with anyone else who suggests that "improvement")!

A shortcoming could be that we have only variables local to the monitor and locals of each call: if you look at "temp" it could be a local of a "monitor activity". Do we think that a serious shortcoming? It could be overcome by declaring "temp", "prod" and "cons" inside an special "inner block" of the monitor that is entered upon activation of the monitor and left at the moment the monitor becomes inactive. I think that I don't care about this refinement, but I may be overlooking a forceful argument in favour.

My dear Tony, it was as always a pleasure and a privilege to write to you. With greetings and best wishes,

yours ever

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

Plataanstraat 5
NL-4565 NUENEN
The Netherlands

[1]  Hoare, C.A.R., "Monitors: An Operating System Structuring Concept"
      Comm. ACM, 17, 10 (Oct. 1974) 549-557
[2]  Bron, C., "Description of Conditional Critical Regions in Terms of
      P- and V-Operations." Memorandum nr. 84, May 1975, Department of
      Applied Mathematics, Twente University of Technology, P.O. Box 217,
      Enschede, The Netherlands.

To Professor C.A.R. Hoare
Department of Computer 5cience
The Queen's University of Belfast
BELFAST BT7 1NN
Northern Ireland

transcribed by Carl Ludwigson
revised Sat, 13 Oct 2007

EWD502

7th July 1975

On a gauntlet thrown by David Gries.

Freshly arrived from the U.S.A. —they still struggled with the time shift— David Gries and his family paid us a visit a few weeks ago. It was not an occasion for "working together", yet some shoptalk was unavoidable, and David confronted me with the problem how to generate the n! permutations of the numbers 0 through n-1 such that the transition from one permutation to the next would only involve the swapping of two neighbours. He told me the problem because he had found it a non-trivial task to present an algorithm solving this problem in a convincing manner. He —good boy!— respected my desire not to be told how he had solved the difficulties of presenting his solution, and he granted me the opportunity to think about the problem myself. (He told me, that the problem had been dealt with in the Algorithms Section of the Comm.ACM, but at the level of unintelligibility that is characteristic for that Section, and we agreed wholeheartedly that a tradition of clearer presentation of algorithms is most sorely needed.)

Note. Those of my readers who would like to try to solve this problem themselves should stop reading here. (End of Note.)

As the swapping of two neighbours changes the number of inversions —i.e. the number of pairs in the wrong order— by 1 , it is suggested to try to characterize each permutation by its inversions. If we consider an arbitrary permutation of the numbers 0 through n-1 , each permutation is uniquely characterized by the values inv(i) , with 0 ≤ inv(i) ≤ i for 0 ≤ i < n , where inv(i) equals the number of numbers < i , that are placed at "the wrong side" of i ; inv(i) = the number of inversions between the value i and smaller values. (The total number of inversions of the permutation is the sum of all the inv(i)-values.) That each permutation defines the inv(i)-values uniquely is obvious; that the inv(i)-values define the permutation uniquely is also not difficult to see, when we consider the algorithm constructing the permutation from the inv(i)-values —processing these values in the order of increasing i —: this is an algorithm that leaves us no choice.

There is, therefore, a one-to-one correspondence between the n! possible inv-values and the n! permutations, and the question becomes, which modifications of the inv-value correspond to a swap of neighbours: each swap of two neighbours changes exactly one inv(i)-value by one, viz. with i = the larger of the two values swapped. The value of inv(i) is to be increased by one if the swap brings the pair into the wrong order, otherwise it has to be decreased by one.

A feasible sequence of inv-values to be generated is now reasonably obvious: it is the generalization of the Grey-code. For n = 4 it would begin

0  0  0  0
0  0  0  1
0  0  0  2
0  0  0  3
0  0  1  3
0  0  1  2
0  0  1  1
0  0  1  0
0  0  2  0
0  0  2  1
0  0  2  2
0  0  2  3
0  1  2  3
0  1  2  2

etc.        

The rule is as follows: a number is changeable when it may be increased or decreased by one. It may be increased if the sum of the numbers to its left is even and it has not reached its maximum value; it may be decreased if the sum of the numbers to its left is odd and it has not reached its minimum value zero. At each step, always the right-most changeable number is changed.

After having established the value i such that inv(i) has to be changed and, also, whether the value i has to be swapped with its left-hand neighbour (because this is a smaller one, inv(i) has to be increased) or with its right-hand neighbour (a decrease of inv(i) by one), we have to establish the place c in the array, where the element i is positioned; this is given by

c = i − inv(i) + (the number of values j such that j > i and inv(j) = [?]

The reason for this formula: i is its original position, inv(i) is the number of smaller elements to the right of it; we have to add to it the number of larger elements in front of the section with elements ≤ i .

In the following program we have given inv(0) —which should be constantly 0— the funny value -2; this is just the usual, mean, little coding trick, in order to let the search for the right-most changeable number terminate artificially when there is no more such a number. The value totinv records the total number of inversions in the array a; the variable linv records the sum of the (non-funny) inv-values to the left of inv(i).

begin glocon n; privar a, inv, ready, totinv;
   a vir int array := (0, 0) {a initialized with a(0) = 0};
   inv vir int array := (0, -2) {inv initialized with inv(0) = - 2};
   do inv.dom ≠ n → a:hiext(inv.dom); inv:hiext(0) od
      {a(0),..., a(n-1) = 0,..., n-1   and  inv(0),...,inv(n-1) = -2, 0,...,
   ready vir bool :=  false; totinv vir int :=  0;
   do non ready →
      begin glocon n; glovar a, inv, ready, totinv;
         privar i, c, linv;   printarray (a);
         i vir int := n - 1; c vir int := 0; linv vir int := totinv - inv(i)
         do inv(i) = i and even(linv) → c:= c + 1 ; i:= i - 1 ;
               linv := linv - inv(i)
            ▯ inv(i) = 0 and odd(linv) → i:= i - 1 ; linv := linv - inv(i)
         od;
         c := c + i - inv(i);
         if even(linv) and i ≥ 1 → inv:(i) = inv(i) + 1 ;
               totinv := totinv + 1; a:swap(c - 1, c)
            ▯ odd(linv) and i ≥ 1 → inv:(i) = inv(i) - 1 ;
               totinv := totinv - 1; a:swap(c, c + 1)
            ▯ i = 0 → ready := true
         fi
      end
   od
end

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Carl Ludwigson
revised Thu, 15 Nov 2007

EWD503

Copyright Notice

The following manuscript

EWD 503: A post-scriptum to EWD501

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 141-144 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
Springer-Verlag, 1982. ISBN 0-387-90652-5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

9th July 1975

A post-scriptum to EWD501

Dear Tony!

Monday morning I went to XEROX to have a few copies made of EWD 501 and from there via the THE home. At the THE I showed Wim Feijen, what I had written during the weekend, and I discussed with him what I intended to write in the afternoon.

In the afternoon I wrote EWD502 —"On a gauntlet thrown by David Gries"— when that was completed, Wim came along. He had studied EWD501, and his first remark was, that the procedure cons on page EWD501 - 5 (13 - 7 lines from below) can be simplified, thanks to the initial emptyness of the train temp:

proc cons(c: integer):
    do n < c → con:= (con, me); me:= head(temp) od;
    n:= n - c; me:= head(temp)
corp cons;

Another observation he made was that when, for instance in the procedure acquire on top of page EWD501, the second line

nonbusy:= (nonbusy, me); me:= head(nonbusy)

is omitted, it is still correct, but now implements a last-in-first-out strategy. I had these remarks in the back of my mind when I designed the readers and writers monitor and the dischead monitor (see following pages).

Monday evening I was tired —Ria and I went away on the tandem—, Tuesday was my day at the THE. In the morning I had some examinations, in the afternoon we studied EWD501 with the little group and made a first solution to the readers and writers. Tuesday evening I embellished it, and thought about a few linguistic alternatives. This morning I had to write a referee's report, this afternoon I designed the diskhead monitor, and typed both monitors.

It is now early in the evening. Let me describe to you the linguistic alternative I have been thinking about. Up till now we have done as if the monitor only exists after the initialization has been completed. But we could regard the monitor "existing" as soon as the initialization starts, and regard the initialization as performed by an (anonymous) process in monitor state. The one consequence would be that all initializations in the monitors I have written these last days, should end with an additional "me:= nil". That obligation is hardly a recommendation, in contrast, perhaps, to the now created possibility that after initialization the monitor process can place "me" on the shunting yard, thereby remaining available for activities that would be hard to place otherwise.

In the dischead monitor you will see that the sortprocess, that should insert the new requester —placed in qu1— in the correct position into the train upsweep will fail to do so, when the new requester should be placed at the rear end of upsweep —this "appending" is no insertion—. As a result, requests and releases have to begin with

upsweep:= (upsweep, qu1)

just to be on the safe side. (When qu1 = nil, the above shunting has no effect.) This could be regarded as ugly. If the monitor itself could sleep on the shunting yard as well, I think that this could be remedied by attaching the monitor at the rear end of upsweep, before the new requester is placed in the correct position. It gives us the possibility to have some activity inserted after the last one, and that, in general, seems a sound and useful facility.

readers and writers: monitor:
begin ar, aw: integer;
      readers, writers: train;
      proc startread:
           readers:= (head(writers), readers, me); me:= head(readers);
           do aw ≠ 0 → readers:= (me, readers); me:= nil od;
           ar:= ar + 1; me:= head(readers)
      corp startread;
      proc endread:
           if ar > 0 → ar:= ar - 1; me:= head(writers) fi
      corp endread;
      proc startwrite:
           writers:= (writers, me); me:= head(writers);
           do ar ≠ 0 or aw ≠ 0 → writers:= (me, writers); me:= nil od;
           aw:= 1; me:= nil
      corp startwrite;
      proc endwrite:
           if aw = 1 → aw:= 0; readers:= (readers, head(writers));
                  me:= head(readers)
           fi
      corp endwrite;
      ar:= 0; aw:= 0
end readers and writers

This is my version of the readers and the writers, according to your specifications of page 556. (Although I wrote it on Tuesday evening, I should say "our", as the problem was discussed on Tuesday afternoon at the THE with the usual group; particularly the contribution of Wim Feijen should be acknowledged.

It has, I think, some charming features. The invariance of

ar ≧ 0 and aw = 0 or ar = 0 and aw = 1

is beautifully maintained, when we remember that the repetitive construct can only terminate with its guard(s) false. (The alternative constructs in endwrite and endread, which may cause abortion, are only there for safety.) The nice thing is that these two guards derived from the invariant relation occur only once! The whole choice of strategy is reflected in the shunting and switching! Isn't that nice?

The way in which in "startread" the presence of a waiting writer prevents new readers to get access, also pleases me. At first it may strike you as a coding trick, but after having played with these trains for a while, it comes quite natural. The way in which "endwrite" gives priority to the readers is also quite nice; at least, I think so.

In programming style, the above is very much different from your approach, in which the continuation after a "wait" can do no harm on account of what has been checked by the other process, that caused the "signal". In such a way one can also get one's programs right, but in principle I think the approach a wrong one: your procedures are logically more intertwined —at least so it seems to me— and it is therefore a stronger invitation to make logical spaghetti.

The convincing beauty of the above contrast with the program on the next page, where I did the dischead monitor without the scheduled wait, and without the "condname.queue". That was not easy!

dischead: monitor
begin headpos, newdest: cylinder;
      direction: (up, down);
      busy: boolean;
      upsweep, downsweep, qu1, qu2: train;
      proc request(dest: cylinder);
           upsweep:= (upsweep, qu1); downsweep:= (downsweep, qu2);
           newdest:= dest;
           if dest > headpos or dest = headpos and direction = up →
                qu2:= (upsweep); qu1:= (head(qu2), me); me:= head(qu1);
                do busy → if newdest ≧ dest → upsweep:= (upsweep, me);
                                              me:= head(qu2)
                           ▯ newdest < dest → upsweep:= (upsweep, qu1, me, qu2);
                                              me:= nil;
                          fi
                od
            ▯ dest < headpos or dest = headpos and direction = down →
                qu1:= (downsweep); qu2:= (head(qu1), me); me:= head(qu2);
                do busy → if newdest ≦ dest →
                               downsweep := (downsweep, me); me:= head(qu1)
                           ▯ newdest > dest →
                               downsweep:= (downsweep, qu2, me, qu1); me:= nil
                          fi
                od
           fi;
           if headpos < dest → direction:= up
            ▯ headpos > dest → direction:= down
            ▯ headpos = dest → skip
           fi
           headpos:= dest; busy:= true; me:= nil
      corp request;
      proc release;  busy:= false;
           if busy → upsweep:= (upsweep, qu1); downsweep:= (downsweep, qu2);
           if direction = up →
                downsweep:= (head(upsweep), downsweep);
                me:= head(downsweep)
           ▯ direction = down →
                upsweep:= (head(downsweep), upsweep);
                me:= head(upsweep)
           fi
           fi
      corp release;
      headpos:= 0; direction:= up; busy:= false
end dischead

Salvo errore at omissione, the above is a replacement for your dischead monitor on page 555-556. It could be argued that the above could only be programmed on a very warm day with thunderstorms —for your information: it is such a day!—. But it has not the danger of individual starvation when all requests are for the same cylinder! Your "scheduled wait" does not talk about this. Agreed? On account of the above I understand that you yielded to the temptation to introduce the scheduled wait. Note, how in the "release", some shunting avoids the need for "condname.queue". That part of the construction I think quite neat!

Greetings and best wishes! Yours ever

Edsger

transcribed by Edwin de Jong
revised Tue, 7 Dec 2010

EWD504

Copyright Notice

The following manuscript

EWD 504: Erratum and embellishments of EWD503

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 145-146 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
Springer-Verlag, 1982. ISBN 0-387-90652-5.

Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

12th July 1975

Erratum and embellishments of EWD503.

Erratum: the text of the procedure "release" on page EWD503 - 2 should begin as follows.

proc release:
     if busy → busy:= false;
               upsweep:= (upsweep, qu1); downsweep:= (downsweep, qu2);
               if ...etc

To keep the interpunction consistent, I should have used a colon in line 6:

proc request(dest: cylinder):

*               *
 *

First embellishment: the text of the procedure "endwrite" on page EWD503 - 1 is no longer "quite nice", since I discovered the alternative:

proc endwrite:
     if aw = 1 → aw:= 0; writers:= (head(readers), writers);
                 me:= head(writers)
     fi
corp endwrite;

When there are both readers and writers waiting, it avoids the final unnecessary activation of the oldest writer. Clearly, "shunting" is something I still have to learn!

*               *
 *

Second embellishment: C.S.Scholten pointed out to me, that the dischead monitor of C.A.R.Hoare, and therefore also the one on page EWD503 - 2 has on a macroscopic scale a danger of individual starvation. If direction = up and the train "upsweep" is not empty —more precisely: contains requests with dest > headpos— a continuous stream of requests with dest = headpos can cause the requests in upsweep never to be honoured. The moral of the story is that requests with dest = headpos have to be placed in the other stream! The remedy seems to be, to replace line 9 by

if dest > headpos or dest = headpos and direction = down →

and line 17 by

▯ dest < headpos or dest = headpos and direction = up →

Wasn't that a nice pitfall? And then to think that there are still people that still refuse to believe that programming is difficult……

*               *
 *

Remark about the devious influence of the programming language we are using:  if I had been trained to think in PL/I with its horrible "BEGIN statements", "END statements" and "RETURN statements" the invention as described in EWD501 in which the notion of "the dynamically last statement of a monitor procedure" plays a role, would probably not have been made! Again a frightening thought!

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Edwin de Jong
revised Tue, 7 Dec 2010

11th August 1975 | EWD506

Trip report E.W.Dijkstra: NATO Summer School Marktoberdorf 1975.

It was a hot summer school and, therefore, an exhausting one. I left Eindhoven on a Monday evening by train in the pleasant company of Braam, Feijen and Rem of the THE. After a few glasses of wine in each other's company , each of us went to his compartment to sleep. We left the train at seven thirty next morning in Munich, two hours later we were in Marktoberdorf with the rest of the day available for adjustment and final preparations. The breakfast that "Wagons Lits" served us between Augsburg and Munich was not exciting, but apart from that, it is a way of travel that I can heartily recommend.

The audience was a very mixed lot: nearly one hundred participants from twenty different countries. (The speakers —nine from about six different countries— would turn out to be an equally mixed lot!) And as the course progressed, I realized that such a great variety in origin was responsible for a lot more problems than just language barriers.

Different participants had been subjected in their home countries to quite different educational systems, and, as a result, they had come with widely diverging expectations to Marktoberdorf. At one end of the educational spectrum is the teaching and training that is primarily oriented towards the transmission of knowledge and very concrete abilities, at the other end we have the educational tradition that concentrates on the transmission of insights and understanding. The enumeration of facts that meets the expectations of the students of the former tradition, bores those from the latter; the considerations that students of the latter tradition find illuminating, exasperate those of the former. I found it impossible to satisfy both types with the same talk.

Besides those general cultural differences, there is the technical problem that in different nations computing science in general, and programming in particular, is quite differently appreciated.

Programming is one of the most difficult branches of applied mathematics because it is one of the most difficult branches of engineering, and vice versa. To explain this, for instance, to a Frenchman —even if he understands English!— is close to impossible: the impossibility —let alone the obligation!— of having a foot firmly planted in both fields of human endeavour is for such a victim of Bourbaki just way beyond his powers of imagination. For quite different reasons it is equally difficult to understand for the pragmatic bit-pusher from the American Mid-West.

A separate word or two must be devoted to German computing science, because there were so many Germans —about one third— among the participants. German computing science is still very unbalanced. With the intention of catching up and promoting the field, the German federal government has performed a magic act of high-speed foundation of departments of computing science at only God knows how many German universities. The problem left the universities was how to fill all those newly created chairs. The expected happened: most of them were filled either by specialists in automata theory and the like, or by experienced pragmatists, and new life was breathed into the barren controversy between "theory" and "practice". In between (and hopefully above) those two extremes a number of "true" computing scientists should hold the field together. The political decision that those true computing scientists should present (and represent) a unified view of the subject —and should do so in a unified German terminology— became disasterous, when the technical mistake was made of choosing the concepts of ALGOL 68 as the fundamental ones on which the subject should be further developed. But one cannot base a scientific discipline on confusion, and, consequently, we have seen preciously little German development of computing science since then. (The German adoption of ALGOL 68 has had a similarly paralyzing effect upon the Germans as the Russian decision in the late sixties to develop as their next national computer series a bit-compatible copy of the IBM 360 —the greatest American victory in the cold war!—.) And with the mental thinkers that only allow operational definitions of programming languages, there is really not much that one can do. Either forget about programming languages and return to the more familiar subject of recursive function theory, or focus upon the managing complicated implementations of complicated languages on complicating machines; and that is what seems to happen. The separation between theory not needed in practice and practice without supporting theory is again complete, and I hardly dare to ask a German colleague about the progress of his work, afraid that the question will be too painful.

A third problem was caused by the great difference in "professional level" (as could have occurred between participants from a single country). There were participants that identified the problems of computing science with the problems encountered within the four walls of their own institute. I was already familiar with the phenomenon of young computing scientists regarding the existing hardware as a God-given constraint within which computing science should be developed. Now I encountered a few that had gone a step further: also the commercially provided operating systems and the generally supported programming languages were accepted as an unquestionable confinement. An alarming development.....

I gave eight lectures on eight (of the nine) working days of the summer school, and they were not an unqualified success. During the first one —on reasoning and pondering— the sound system did not function properly. Besides that I felt the majority of the attendants wanted more concrete material. So I switched quickly to formal semantics for the next three lectures; it was only in the fifth lecture, when I showed and discussed four little programs, that that section of the audience felt more satisfied: at last I was showing programs and actually "saying something". The last three lectures were devoted to on-the-fly garbage collection; I restricted myself to rather coarse-grained interleaving. Some welcomed the confrontation with a new type of problems, but certainly not all of them.

Tony Hoare gave also eight lectures (on each of the first four days two). He used an old collection of transparencies, the lectures were perfect and he was practically the only other speaker who tried to transmit developed theory. (David Gries would do so on the last day as well.) On the whole he reached his audience well.

Bill Wulf (Carnegie Mellon) and Per Brinch Hansen (Cal.Tech.) reported both on their development projects (the Hydra system and a pilot model to try out the applicability of Concurrent Pascal, respectively). Both gave eight lectures, and it was a pity that their subjects were so similar: sometimes all the details became rather boring and the relative importance of operating system design became overstressed.

Gehard Seegmüller (Munich) and Andrei Ershov (Novosibirsk) gave together about eight lectures, the first on a Munich project on a machine independent system implementation language, second on a language/machine independent translation project. I found both projects depressing, the anomalies of PL/I and the IBM/360 having pervaded both of them.

Mike Griffiths (Rennes) and Fritz Bauer (Munich) also talked very much about the same subject: recursive formulations and the massaging thereof in an effort to avoid variables and assignments to them. After having heard Rod Burstall a few times on that subject I could not distinguish any new material, and am still of the opinion that this line of attack on the programming problem was better justified in the early sixties than it is now.

On the last Saturday morning David Gries (Cornell University) caused a surprise in a one hour lecture when he showed how newly developed techniques for proving the correctness of parallel programs —developed by his Ph.D student Susan Speer Owicki— could be applied to the on-the-fly garbage collector. That was nice, and his presentation was very much appreciated (David himself was very grateful for the opportunity of applying his new technique to a more complicated parallel program than he had ever envisaged himself.)

There were a few incidents. On about the third day Koster (Berlin) could stand it no longer that none of the speakers cared to stick to the ALGOL 68 dogmata, worse even: dared to challenge them, and during the discussion he read aloud a sort of manifesto in defense of ALGOL 68, that was amazingly aggressive, full of arguments "ad hominem" —Tony and me in particular—. I was baffled: is this the style of "scientific" discussions as is practiced nowadays in German universities? (His outburst was all the more surprising because none of the speakers had mentioned ALGOL 68 at all! Even politely ignoring it is apparently already offensive for that dogmatic environment.) On the last day a German staff member from Munich asked all the speakers —because the subject had not been mentioned— their opinion about "interactive programming". Did he have vested interests? When nearly all the speakers had given the verdict "insignificant" in one way or another, he got so annoyed that he started a voting procedure among the participants in the hope of getting a more favourable answer!

Thanks to Tony, my visit to Marktoberdorf has personally been very rewarding. On Sunday —our first free day— we have worked together in the garden of Hotel Sepp. Upon my request he has explained to me the SIMULA "class" —something I could never understand— and, in the courses of that Sunday, we have moulded the notion into something that looks very promising. On the next Thursday —the day of the excursion— we continued our work and at the end of the afternoon we had designed what had started as the design of a recursive data structure, but suddenly admitted the interpretation of an elephant built from mosquitoes as well. A surprising discovery, the depth of which is —as far as I am concerned— still unfathomed.

One discussion during a dinner should not remain unmentioned— Bill Wulf raised the question: "If there were a Nobel prize for computing science, what would be the next achievement in our field worthy of it?" In order to come into the mood, we went through the past and up till 1970 we had no difficulties; the significance of things done since then was much less clear, and, eventually, Bill Wulf's question remained unanswered.... How do we interpret this fact? One possible interpretation is that in computing science all essential discoveries have been made, and that the subject approaches completion, etc., an interpretation that is compatible with the scientific stagnation that various groups seem to display. But I feel that this interpretation is totally wrong. It may be true that certain lines of research seem to have got stuck, but a number of dead alleys do not imply a dead subject! The next achievement Bill Wulf was asking for might very well take the form of successfully challenging one of our common "tacit assumptions". Von Neumann's "instruction counter" —and the notion of "a sequential process"— seems the most likely victim: any workable conceptual framework in which "parallel programming" becomes as meaningless a term as "sequential programming" could be a worthy candidate for computing science's Nobel prize!

*                    *
*

Eight days ago we returned, again by train but this time by daylight. I had told my compatriots how beautiful the ride through the Rhine valley would be; later they told me that they had enjoyed it very much: I myself had slept! I was very tired when I came home, and my wife ordered that I would take two weeks off, a prescription that I followed gratefully, as the heat wave continued in full vigour. As my spectacles were beginning to hurt me on warm days I ordered new, very light ones ten days before my departure to Marktoberdorf. To my great regret they were not ready yet when we left. I finally got them, nearly a week after my return, two days before the heat wave ended....

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Tue, 18 Dec 2007

13th August 1975 | EWD507

On a gauntlet thrown by David Gries.

by
Edsger W. Dijkstra

It is requested to design a program that will generate the N! permutations of the values from 0 through N-1 in such an order that the transition from one permutation to the next is always performed by exactly one swap of two neighbours.

In a permutation each pair of values such that the larger value precedes the smaller one, presents a so-called "inversion". (In particular: the one and only permutation with zero inversions is the one in which the values are placed in monotonically increasing order.) The notion of inversions can be expected to be relevant because the swapping of two neighbours changes the total number of inversions by (plus or minus) 1, and it is, therefore, suggested to characterize each permutation by its inversions. This can be done by introducing N inversion counters inv[i] for 0 ≤ i < N, where inv[i] equals the number of inversions between the value i and the values smaller than i. (From this definition 0 ≤ inv[i] ≤ i follows; the total number of inversions of a permutation is the sum of the corresponding inv[i]-values.) That each permutation defines the inv[i]-values uniquely is obvious; that the inv[i]-values define the permutation uniquely is easily seen by considering the algorithm constructing the permutation from the inv[i]-values —processing these values in the order of increasing i — : this algorithm leaves us no choice.

There is, therefore, a one-to-one correspondence between the N! possible inv-values and the N! permutations, and the question becomes, which modifications of the inv-value correspond to a swap of neighbours: each swap of two neighbours changes exactly one inv[i]-value by 1, viz. with i = the larger of the two values swapped. The value of inv[i] is to be increased if the swap increases the number of inversions; otherwise it is to be decreased.

A feasible sequence of inv-values to be generated is now reasonably obvious: it is the generalization of the Gray-code. For N = 4 it would begin

inv[0] | inv[1] | inv[2] | inv[3]
0 | 0 | 0 | 0
0 | 0 | 0 | 1
0 | 0 | 0 | 2
0 | 0 | 0 | 3
0 | 0 | 1 | 3
0 | 0 | 1 | 2
0 | 0 | 1 | 1
0 | 0 | 1 | 0
0 | 0 | 2 | 0
0 | 0 | 2 | 1
0 | 0 | 2 | 2
0 | 0 | 2 | 3
0 | 1 | 2 | 3
0 | 1 | 2 | 2
etc.

The rule is as follows: a number is changeable when it may be increased or decreased by 1. It may be increased if the sum of the numbers to its left is even and it has not reached its maximum value; it may be decreased if the sum of the numbers to its left is odd and it has not reached its minimum value zero. At each step, always the right-most changeable number is changed. It is not difficult to see that in the permutation, the value i is, indeed, swapped with a smaller value.

After having established the value i, such that inv[i] has to be changed, and, also, whether the value i has to be swapped with its predecessor in the permutation (corresponding to an increase of inv[i]) or with its successor in the permutation (corresponding to a decrease of inv[i]), we have to establish the place c in the permutation, where the value i is located, because for all j > i, inv[j] has an extreme value, c is given by

c = i - inv[i] + (the number of values j such that j > i and inv[j] = j)

In the following program we have given inv[0] — which should be constantly 0 — the funny value -2; this is the usual, mean, little coding trick, in order to let the search for the right-most changeable inv[i]-value terminate artificially when there is no more such an inv[i]-value. The value "totinv" records the total number of inversions in the array a, that is used to record the permutation; the variable "linv" records the sum of the (non-funny) inv[j]-values to the left of inv[i] (i.e. with j < i).

begin integer array a, inv [0:N-1]; boolean ready; integer totinv, i, c, linv;
i:= 0; do i < N → a[i]:= i; inv[i]:= 0; i:= i + 1 od; inv[0]:= -2;
ready:= false; totinv:= 0;
do non ready → printarray(a);
      i:= N - 1; c:= 0; linv:= totinv - inv[i];
      do inv[i] = i and even(linv) →
            c:= c + 1; i:= i - 1; linv:= linv - inv[i]
       ▯ inv[i] = 0 and odd(linv) →
            i:= i - 1; linv:= linv - inv[i]
      od
      c:= c + i - inv[i];
      if even(linv) and i > 0 →
              inv[i]:= inv[i] + 1; totinv:= totinv + 1; swap(a, c-1, c)
       ▯ odd(linv) and i > 0 →
              inv[i]:= inv[i] - 1; totinv:= totinv - 1; swap(a, c, c+1)
       ▯ i = 0 → ready:= true
      fi
od
end

Post Scriptum.

The problem solved above has been posed to me by David Gries, who told me that he had found it a non-trivial task to present a solution to it in a convincing manner. The argument shown led quickly to the above solution, which is submitted for publication upon his request. (End of Post Scriptum.)

Burroughs
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Edwin de Jong
revised Tue, 7 Dec 2010

EWD508

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

20th August 1975

A synthesis emerging?

Introduction.

This document does not contain language proposals; at a later stage they may be inspired by it. It has no other purpose than the recording of discussions and programming experiments. It is exciting because it seems to open the possibili of writing programs that could be implemented

a) | either by normal sequential techniques
b) | or by elephants built from mosquitos
c) | or by a data-driven machine.

That programs intended for the second or third implementation could be “inefficient” when regarded as sequential programs, is here irrelevant. The important result would be that the same mathematical technique for the intellectual mastery of sequential programs can be taken over —hopefully lock. stock and barrell— for the intellectual mastery of those, as yet less familiar designs. Finally —and that seems the most important promise— it introduces the possibility of concurrent execution in a non-operational manner.

From the past, terms as “sequential programming” and “parallel programming” are still with us, and we should try to get rid of them, for they are a great source of confusion. They date from the period that it was the purpose of our programs to instruct our machines: now it is the purpose of the machines to execute our programs. Whether the machine does so sequentially, one thing at a time, or with a considerable amount of concurrence, is a matter of implementation and should not be regarded as a property of the programming language. In the years behind us we have carried out this program of non-operational definition of semantics For a simple programming language that admits (trivially) a sequential implementation; our ultimate goal is a programming language that admits (highly?) concurrent implementations equally trivially. The experiments described in this report are a first step towards that goal.

27th and 31st July, 1975.

It all started on Sunday 27th of July 1975, when Tony Hoare explained to me in the garden of Hotel Sepp in Marktoberdorf (Western Germany) upon my request the class-concept of SIMULA (including the so-called inner-concept); at least he explained his version of it. I had always stayed away from it as far as possible, in order to avoid contamination with the extremely operational point of view as practiced by Dahl c.s., and, after some time I could not even (under-) stand their mechanistic descriptions anymore: they just made me shudder. Late 1974 Tony sent me a paper, that looked better, but still made me shudder; I read it once, but doubting whether I could endure the exposure, I consciously refused to study it at that moment. On Saturday 26th I decided that the moment to be courageous had come, and asked Tony to explain to me what he was considering. He was a tolerant master, allowing me to change terminology, notation and a way of looking at it, things I had to do in order to make it all fit within my frame of mind. To begin with I shall record how our discussions struck root in my mind. (Whether a real SIMULA-fan still recognizes the class-concept, is something I just don’t know: maybe he gets the impression that I am writing about something totally different. My descriptions in what follows are definitely still more operational and mechanistic than I should like them to be: it is hard to get rid of old habits!)

*              *
*

Suppose that we consider a natural number, which can be introduced with the initial value zero, can be increased and decreased by 1. provided it remains non-negative. A non-deterministic, never ending program, that may generate any history of a natural number is then

| nn begin privar x; x vir int := 0;
|  |  | do true → x:= x +1
|  |  |  | ▯ x > 0 → x:= x - 1
|  |  | od
|  | end .

Suppose now, that we would like to write a main program operating on two natural numbers y and z , a main program that “commands” these values to be increased and decreased as it pleases. In that case we can associate with each of the two natural numbers y and z a non-deterministic program of the above type, be it, that the non-determinacy of each of these two program executions has ot be resolved (“settled”, if you prefer) in such a way that the two histories are in accordance with the “commands” in the main program. For this purpose we consider the following program. (Please remember that the chosen notations are not a proposal: they have been introduced only to make the discussion possible!)

| nn gen begin privar x; x vir int := 0;
|  |  |  |  | do ?inc → x:= x + 1
|  |  |  |  |  | ▯ x > 0 cand ?dec → x:= x - l
|  |  |  |  | od
|  |  | end

| main program
|  | begin privar y, z; y vir nn; z vir nn;
|  |  | .
|  |  | .
|  |  | .
|  |  | y.inc; ...; y.dec; ...; z.inc; ...; z.dec; .....
|  | end

Notes.
1)     We have written two programs, eventually we shall have three sequential processes, two of type “nn” —one for y and one for z — and one of type “main program”. The fact that the first one can be regarded as a kind of “template” I have indicated by writing gen (suggesting “generator”) in front of its begin.
2)     The main program is the only one to start with; upon the initialization “y vir nn” the second one is started —and remains idling in the repetitive construct— , upon the initialization “z vir nn”, the last one is introduced. in an identical fashion. It is assumed —e.g. because the “main program” is written after “nn”— that the main program is within the lexical scope of the identifier “nn”.
3)     The two indentitiers inc and dec —preceded in the text of nn by a question mark— are subordinate to the type nn , that is, if y is declared and initialized as a variable of type nn , the operations inc and dec — invoked by “y.inc” and “y.dec” respectively— are defined on it and can be implemented by suitable synchronizing and sequencing the execution of the y-program with that of the main program.
4)     When in the main program “y.inc” is commanded, this is regarded in the y-program as the guard “?inc” being true (once). Otherwise guards (or guard components) with the question mark are regarded as undefined. Only a true guard makes the guarded statement eligible for execution.

*              *
*

5)     The block exit of the main program, to which {he variables y and z are local, implies that all the “query guards” are made false: when ?inc and ?dec are false for the y-program, the repetitive construct terminates and that local block exit is performed: the “x” local to the y-program may cease to exists. It is sound to view the implicit termination of the blocks associated with the variables y and z to be completed before block exit if the block to which they are local —the main program— is completed. (End of Notes.)

*              *
*

In the preceding section we have assumed that the main program was somehow within the scope of “nn”. But one can argue what funny kind of identifier this is: on the one hand it is the name of a program text, there are, however, as many nn’s as the main program introduces natural numbers. The decent was to overcome this is to introduce a fourth program, one “natural number maker” say peano . Suppose that it is the purpose of peano not only to provide —i.e. to create and to destroy— natural numbers, but also to print at the end of its life the maximum natural number value that has ever existed.

peano
| begin privar totalmax; totalmax vir int := 0;
|  | do ?nn → gen begin privar x, localmax;
|  |  |  | x vir int, localmax vir int := 0, 0;
|  |  | (//do ?inc → x:= x + i;
|  |  |  |  |  | do localmax < x → localmax:= x od
|  |  |  |  | ▯ x > 0 cand ?dec → x:= x - 1
|  |  |  |  | od//);
|  |  |  |  | do totalmax < localmax → totalmax:= localmax od
|  |  | end
|  | od;
|  | print(totalmax)
| end

main program
| begin privar y, z; y vir peano.nn; z vir peano.nn;
|  |  | .
|  |  | .
|  |  | .
|  |  | y.inc; ...; y.dec; ...; z.inc; ...; z.dec
|  | end

The idea was, that the program called peano is read in and started, until it gets stuck at the repetitive construct with the (undefined) query “?nn”. With the knowledge of the identifier peano (and its subordinate peano.nn) the main program is read in and started, and because inc is subordinate to peano-nn, it becomes subordinate to y by the initializing declaration “y vir peano.nn”.

Notes.
1)     In the above it has not been indicated when peano will terminate and print the value of totalmax.
2)     The generator describing the natural rumter exists of three parts:

| its opening code;
| (// its local code//>;
| its closing code .

Only in the opening code —here the facility is not used and in “nN” the “(//” could have been moved forward— and the closing code access to totalmax , the local variable of peano is permitted. Different natural numbers may “inc” simultaneously, only their opening and closing codes are assumed to be performed in mutual exclusion.
3)     If the main program is a purely sequential one, y.dec immediately after initialization will cause the main program to get stuck. If the main program consists of a number of concurrent ones, the one held up in y.dec may procedd after another process has performed y.inc. Our natural numbers would then provide an implementation for semaphores!
4)     It is now possible to introduce, besides the peano given above, a “peanodash” that, for instance omits the recording of maximum values. The main program could then begin with

| begin privar y. z; y vir peano.nn; z vir peanodash.nn; .....

The importance of the explicitly named “maker” in the declaration/initialization lies in the fact that it allows us to provide alternative implementations for variables of the same (abstract) type. (End of Notes.)

The above records the highlights of Sunday’s discussion as I remember them. Many of the points raised have been recorded for the sake of completeness: we may pursue them later, but most of them not in this report, as the discussion took another turn on the next Thursday.

*              *
*

On Thursday a couple of hours were wasted by considering how also in the local code onstances of generated processes —natural numbers— could be granted mutually exclusive access to the local variables of their maker. Although we came up with a few proposals of reasonable consistency, Tony becamse suddenly disgusted, and I had to agree: the whole efforts had been “to separate” and now we were re-introducing a tool for fine-grained interference! Our major result that day was the coding of a recursive data structure of type“sequence”. The coding is given below (omitting the type of parameters and function procedures). It is not exactly the version coded on that Thursday afternoon, but the differences are minor.

It is a recursive definition of a sequence of different integers. Let s be a variable of type sequence.

s.empty | is a boolean function, true if the sequence s is empty, otherwise false
s.has(i) | is a boolean function with an argument i of type integer; it is true if i occurs in the sequence, otherwise false
s.truncate | is an operator upon s, which also returns a boolean value; if s is nonempty, the last value is removed and the value true is returned, if s is empty, it remains so and the value false is returned
s.back | is an operator upon s that returns a value of type nint (i.e. the integers, extended with the value nil ); if s is nonempty, the first value is returned and removed from s, if s is empty, it remains so and the value nil is returned
s.remove(i) | is an operator upon s with an argument i of type integer; if i does not occur in s , s is left unchanged, otherwise the value i is removed from the sequence s without changing the order of the remaining elements in the sequence
s.insert(i) | is an operator upon s with an argument i of type integer; if i does occur in s , s is left unchanged, otherwise s is extended at the far end with the value i.

sequencemaker
begin
do ?sequence →
|  | gen begin
|  |  | (//do ?empty → result := true
|  |  |  | ▯ ?has(i) → result := false
|  |  |  | ▯ ?truncate → result := false
|  |  |  | ▯ ?back → result : = nil
|  |  |  | ▯ ?remove(i) → skip
|  |  |  | ▯ ?insert(i) →
|  |  |  |  | begin privar first, rest;
|  |  |  |  |  | first vir nint := i; rest vir sequencemaker.sequence;
|  |  |  |  |  |  | do first ≠ nil cand ?empty → result := false
|  |  |  |  |  |  |  | ▯ first ≠ nil cand ?has(i) →
|  |  |  |  |  |  |  |  | if first = i → result := true
|  |  |  |  |  |  |  |  |  | ▯ first ≠ i → result := rest.has(i)
|  |  |  |  |  |  |  |  | fi
|  |  |  |  |  |  |  | ▯ first ≠ nil cand ?truncate →
|  |  |  |  |  |  |  |  |  | result := true;
|  |  |  |  |  |  |  |  |  | begin pricon absorbed;
|  |  |  |  |  |  |  |  |  |  |  | absorbed vir bool := rest.truncate;
|  |  |  |  |  |  |  |  |  |  |  | if absorbed → skip
|  |  |  |  |  |  |  |  |  |  |  |  | ▯ non absorbed → first:= nil
|  |  |  |  |  |  |  |  |  |  |  | fi
|  |  |  |  |  |  |  |  |  | end
|  |  |  |  |  |  |  | ▯ first ≠ nil cand ?back →
|  |  |  |  |  |  |  |  |  | result := first; first:= rest.back
|  |  |  |  |  |  |  | ▯ first ≠ nil cand ?remove(i) →
|  |  |  |  |  |  |  |  |  | if i ≠ first → rest.remove(i)
|  |  |  |  |  |  |  |  |  |  | ▯ i = first → first:= rest.back
|  |  |  |  |  |  |  |  |  | fi
|  |  |  |  |  |  |  | ▯ first ≠ nil cand ?insert(i) →
|  |  |  |  |  |  |  |  |  | if i ≠ first → rest.insert(i)
|  |  |  |  |  |  |  |  |  |  | ▯ i = first → skip
|  |  |  |  |  |  |  |  |  | fi
|  |  |  |  |  |  | od
|  |  |  |  | end
|  |  |  | od//)
|  |  |  | end
| od
| end

(The above is a set of rather crazy specifications: they grew in an alternation of simplification —we started with a binary tree— in order to reduce the amount of writing we had to do, and complications. when we became more ambitious and wanted to show what we could do.)
Note. I am aware of the lousiness of the notation of an operator upon s which returns a value. I apologize for this lack of good taste. (End of Note.)

The sequencemaker is very simple: it can only provide as many sequencies as it is asked to provide; the storage requirements for a sequence are very simple, viz. a stack. (In our rejected example of the binary tree, although lifetimes are, in a fashion, nested, life is not so simple.) The sequencemaker has no local variables (like peano ); accordingly, each sequence is simple: its opening and closing codes are empty. The outer repetitive constructs describe the behaviour of the empty sequence: all its actions are simple with the exception of ?insert(i) , as a result of which the sequence becomes nonempty. In an inner block, which describes the behaviour of a sequence that contains at least one element, two local variables are declared: the integer “first” for that one element, and the sequence “rest” for any remaining ones.

It is illustrating to follow the execution of the call “remove(i)”. Suppose that i does not occur in the sequence: in that case we have constantly “i ≠ first”, the task to remove i is constantly delegated to the rest, until it is delegated to an empty rest, fro which —9th line— remove(i) reduces to ’a skip. If, however, the value i occurs in the sequence, it occurs in a nonempty sequence and “i = first” is discovered; the command then propagates in the form “first:= rest.back”. The last non-empty sequence that performs “first:= rest.back” gets —see 8th line— the value “nil” from its successor and establishes for itself “first = nil”. As a result the repetitive construct in its inner block is terminated, an inner block exit is performed, prior to the completion of which all query-guards for its successor are set false, and its successor performs an exit from its outer block and ceases to exist.

It is also instructive to follow how upon the block exit from

begin privar s; s vir sequencemaker.sequence; ................. end

at a moment that s may contain many elements, the sequence s disappears. All query-guards to s are set false, which forces termination of the inrer repetitive construct for s which results in block exit from its inner block (which first requires deletion of its rest); upon completion of this block exit, the query-guards still being false, termination of the outer repetitive construct and block exit from the outer block of s are forced. This is very beautiful: the hint to delete itself, given to the head of the sequence, propagates up to its end, reflects there, travels back, folding up the sequence in a nice stack-wise fashion, as, of course, it should. In its elegance —or should I say: completeness?— it had a great appeal to us.

*              *
*

It was at this stage, that I realized, that the same program could be visualized as a long sequence —long enough, to be precise— of mosquitoes:

where each mosquito is essentially a copy of the text between // and //), and each mosquito is the “rest” for his left-hand neighbour. The execution of the declaration “rest vir sequencemaker.sequence” can be interpreted as a command to one’s right-hand neighbour to initialize its instruction counter to the begin of the program. Each mosquito is ready to accept a next command from the left as soon as it has nothing more to do, i.e. its control has successfully returned to one of the sets of query-guards. Giving a command to the right lasts until the command has been accepted when no answer is required, and until the answer has been returned when an answer is required.

It is instructive to follow the propagation of activity for the various commands.
     ?empty is immediately reflected.
     ?has(i) propagates up the sequence until i has been detected or the sequence is exhausted, and from there the boolean value (true or false respectively) is reflected and travels to the left until it leaves the sequence at the front end. All the time the sequence is busy and cannot accept another command. The time it takes to return the answer true depends on the distance of i from the begin of the sequence. the time it takes to return the answer false is the longest one, and depends on the actual length of the chain (not on the number of mosquitoes available).
     ?truncate and ?back propagate in practically full speed to the right: at each mosquito, there is a reflection over one place back to absorb the answer. Note that ?truncate (in the inner block) starts with “result= true” and ?back starts with “result:= first” —actions which can be taken to be completed when the mosquito to the left has absorbed the value. This is done in order to allow the mosquito to the left to continue as quickly as possible,
     ?remove(i) propagates still simpler (until it becomes a ?back).
     ?insert(i) propagates also quite simple, until the wave is either absorbed —because i = first is encountered— or the sequence is extended with one element. The fascinating observation is that any sequence of ?remove(i), ?insert(i), ?back and ?truncate may enter the sequence at the left: they will propagate with roughly the same speed along the sequence, if the sequence is long, a great number of such commands may travel along the sequence to the right. It is guaranteed impossible that one command “overtakes” the other, and we have introduced the possibility of concurrency in implementation in an absolutely safe manner.

Note. Originally truncate was coded differently. It did not return a boolean value, and was in the outer guarded command set
     ?truncate → skip
and in the inner guarded command set

| first ≠ nil cand ?truncate →
|  | if rest.empty → first:= nil
|  |  | ▯ non rest.empty → rest.truncate
|  | fi

As soon as we started to consider the implementation by a sequence of mosquitoes, however, we quickly changed to the code of EWD508 - 4, because the earlier version had awkward propagation properties: two steps forward, one step backward. The version of page EWD508 was coded when we had not yet introduced the type nint; after we had done so, we could also have coded truncate with a parameter of type integer: in the outher guarded command set
     ?truncate(i) → result:= nil
and in the inner guarded command set

| first ≠ nil cand ?truncate(i) →
|  | result := i; first:= rest.truncate(first) .

The last part of this note is rather irrelevant. (End of Note.)

This was the stage in which we were, when we left Marktoberdorf. As I wrote in my tripreport EWD506 “A surprising discovery, the depth of which is —as far as I am concerned— still unfathomed.”

*              *
*

What does one do with “discoveries of unfathomed depth”? Well, I decided to let it sink in and not to think about it for a while —the fact that we had a genuine heatwave when I returned from Marktoberdorf helped to take that decisior!— . The discussion was only taken up again last Tuesday afternoon in the company of Martin Rem and the graduate student Poirters, when we tried to follow the remark, made in my tripreport, that it would be nice to do away with von Neumann’s instruction counter. (This morning I found a similar suggestion in “Recursive Machines and Computing Technology” by V.M.Glushkov. M.B.Ignatyev, V.A.Myasnikov and V.A.Torgashev. IFIP 1974; this morning I received a copy of that article from Philip H.Enslow, who had drawn my attention to it.)

We had, of course, observed that the propagation properties of “has(i)” are very awkward. It can keep a whole sequence of mosquitoes occupied, all of them waiting for the boolean value to be returned. As long as this boolean ’value has not been returned to the left-most mosquito, no new command can be accepted by the first mosquito, and that is sad. The string of mosquitoes as shown above, is very much different from the elephant structure that we have already encountered very often, viz. all mosquitoes in a ring. Nice propagation properties would be displayed by a string of mosquitoes that send the result as soon as found to the right, instead of back to the left! Before we pursue that idea, however, I must describe how I implemented (recursive) function procedures in 1960 —a way, which, I believe. is still the standard one— .

Upon call of a function procedure the stack was extended with an “empty element”, an as yet undefined anonymous intermediate result. On top of that that procedure’s local variables would be allocated and during the activation of the procedure body, that location —named “result”— would be treated as one of the local variables of the procedure. A call

| ?has(i) → if i = first -→ result:= true
|  |  | ▯ i ≠ first → result:= rest.has(i)
|  | fi

could result in 9 times the second alternative and once the first, so that the answer is found at a moment of dynamic depth of nesting, equal to 10. In the implementation technique described, the boolean result is then handed down the stack in ten successive steps: the onymous result at level n+1 becomes at procedure return the anonymous result at level n , that is assigned to the onymous result of level n , etc.: a sequence of alternating assignments and procedure returns. Under the assumption that assignment is not an expensive operation, this is an implementation technique that can very well be defended.

But it is an implementation choice! When implementing

| result := rest.has(i)

no one forces us to manipulate the value of “res.has(i)” as an imtermediate result, that subsequently can be assigned! An alternative interface with the function procedure would have been to give it an additional implicit parameter, viz. the destination cf the result —e.g. in a sufficiently global terminology, such as distance from stack bottom, say—. In that case the implementation of

| result := rest.has(i)

would consist of a recursive call on “has” in which the implicit destination parameter received would just be handed over to the next activation. When, at dynamic depth 10, the boolean value would become known it would instantaneously be placed at its final destination, after which the stack could collapse. Because in the case of a fixed number of mosquitoes, always present, needed or not —that is the simplification I am thinking about now— there is not much stack collapse, the configuration that now suggests itself is the following

The mosquitoes still have the same mutual interconnection pattern, but I assume that each request for a value, entering the network at the left at the question mark, is accompanied by “a destination” for the result. The reason that I have added the line at the bottom is the following. A sequence is a very simple arrangement, and in that case, also the “external result” as soon as known, could be handed to the right-hand neighbour for further transmission. If, however, we consider the tree that would correspond to a variable of the type “binary tree” , the result would then finally arrive in one of the many leaves. If we associate a real copper wire with each connection between two mosquitoes, and we wish the result to appear at a single point, then we have to introduce some connecting network, such that the various paths of the results can merge. Hence the additional line; the points, marked “m” are binary merge points, we have arranged them linearly, we could have arranged them logarithmical logically —and perhaps even physically— we can think of “multi-entry merges”.

I am now not designing in any detail the appropriate mechanism for collecting the external result as soon as it has been formed somewhere in the network. My point is that there are many techniques possible, which all can be viewed as different implementation techniques of the same (recursive) program. Their only difference is in “propagation characteristics”. The reason that I draw attention to the difference in implementation technique for the sequential machine (without and with implicit destination parameter) is the following. In the case of the linear arrangement of mosquitoes, each mosquito only being able to send to his right-hand neighbour when his right-hand neighbour is ready to accept, we have a pipeline that, by the nature of its construction, produces results in the order in which they have been requested. This, in general, seems to severe a restriction, and for that purpose, each request is accompanied by a “destination”, which as a kind of tag accompanies the corresponding result when finally produced. Obviously, the environment driving the network, must be such, that never to requests with the same destination could reside simultaneously in the network.

*              *
*

True to our principle that about everything sensible that can be said about computing can be illustrated with Euclid’s Algorithm, we looked at good old Euclid’s Algorithm with our new eyes. We also took a fairly recent version, that computes the greatest common divisor of three positive numbers. It is

| x, y, z := X, Y, Z;
| do x > y → x:= x - y
|  | ▯ y > z → y:= y - z
|  | ▯ z > x → z:= z - x
| od

with the obvious invariant relation: gcd(x, y, z) = gcd(X, Y, Z) and x > 0 and y > 0 and z > 0.

Our next version was semantically equivalent, but written down a little bit differently, in an effort to represent that in each repetition, it was really the triple x, y, z we were operating upon. That is, we regarded the above program as an abbreviation of

| x, y, x := X, Y, Z;
| do x > y → x, y, z := x - y, y, z
|  | ▯ y > z → x, y, z := x, y - z, z
|  | ▯ z > x → x, y, z := x, y, z - x
| od .

We then looked at it and said: Why only change one value? This, indeed is not necessary, and we arrived at the following —similar, but mathematically different— program:

|  | (program 3)

| x, y, z:: X, Y, Z;
| do non x = y = z →
|  | x, y, z := f(x, y), f(y, z), f(z, x)

with

| f(u, v): if u > v → result := u - v
|  |  | ▯ u ≤ v → result := u
|  | fi

or, if we want to go one step further for the sake of argument

| f(u, v): if u > v → result := dif(u, v)
|  |  | ▯ u ≤ v → result := u
|  | fi

How do we implement this? We can look at program 3 with our traditional sequential eyes, which means that at each repetition, the function f is invoked three times, each next invocation only taking place, when the former one has returned its answer. We can also think of three different f-networks, which can be activated simultaneously. We can also think of a single f-network, that is activated three times in succesion, but where the comparison of the next pair of arguments can coincide in time with forming the difference of the preceding pair. To be quite honest, we should rewrite program 3 in the form

|  | (program 4)

| x, y, z := X, Y, Z
| do non x = y = z →
|  | tx, ty, tz := f(x, y), f(y, z), f(z, x)
|  | x, y, z = tx, ty, tz
| od

The reason is simple: we want to make quite clear that always the old values of x, y, z are sent as arguments to the f-network, and we want to code our cycle without making any assumptions about the information capacity of the f-network. The above program works also if we have an f-network without pipe-lining capacity.

*              *
*

I was considering a mosquito that would have six local variables, x, y, z, tx, ty and tz; it would first "open" tx, ty and tz. i.e. make them ready to receive the properly tagged results, and then send the argument pairs in the order that pleases it to either one or three f-networksm and would then, as a merge node, wait until all three values had been received. When I showed this to C.S.Scholten, he pointed out to me, that the same result could be obtained by two, more sequential mosquitoes: one only storing the x, y, z values, and another one, storing the tx, ty and tz values, waiting for the three values to be delivered by the f-network. This is right.

Some remarks, however, are in order. I can now see networks of mosquitoes, implementing algorithms that I can also interpret sequentially and for which, therefore, all the known mathematical techniques should be applicable. Each mosquito represents a non-deterministic program, that will be activated by its “query-guards” when it is ready to be so addressed and when it is so addressed, and where the act of addressing in the addressing mosquito is only completed, by the time that the mosquito addressed has honoured the request. We should realize, however, that these synchornization rules are more for safety, than for “scheduling”, because dynamically, such networks may have awkward macroscopic properties when overloaded. Take the example of the long string of mosquitoes, that, together form a bounded buffer, each of them cyclically waiting for a value from the left, and then trying to transmit this value to the right. If this is to be a transmission line, it has the maximum throughput when, with n mosquitoes, it contains n/2 values. Its capacity, however is n . If we allow its contents to grow —because new values are pumped in at the left, as long as possible, while no values are taken out at the right, it gets stuck: taking out values from the sequence filled to the brim empties the buffer, but this effect only propagates slowly to the left, and the danger of awkward macroscopic oscillations seems all but excluded.

The next remark is that I have now considered elephants built from mosquitoes, but the design becomes very similar to that of a program for a datadriven machine. The programs I have seen for data driven machines were always pictorial ones —and I don’t like pictures with arrows, because they tend to become very confusing—, and their semantics was always given in an operational fashion. Both characteristics point to the initial stage of unavoidable immaturity I now see a handle for separating the semantics from the (multi-dimensional, I am tempted to add) computational histories envisaged. In a sense we don’t need to envisage them anymore, and the whole question of parallellism and concurrency has been pushed a little bit more into the domain, where it belongs: implementation. This is exciting.

*              *
*

A sobering remark is not misplaced either, and that is that we have already considered highly concurrent engines —e.g. the hyperfast Fourier transform via the perfect shuffle— that seem to fall as yet outside the scope of constructs considered here. And so does apparently the on-the-fly garbage collection. We can only conclude that there remains enough work to be done!

PS. For other reasons forced to go to town, I combine that trip with a visit to the Eindhoven Xerox branch. The time to reread my manuscript for typing errors is lacking and I apologize for their higher density.

25th August 1975 | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NL-4565 NUENEN |
The Netherlands | v

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD 509

Eerste toespraak, najaar 1975.

Bij het begin van mijn colleges in dit semester wil ik graag zoveel mogelijk misverstanden uit de weg ruimen, die over deze colleges zouden kunnen bestaan of ontstaan. Waarom worden ze gehouden? Of, uitgesplitst: waarom geef ik ze en waarom, zou U er naar luisteren?

Ik breng deze punten ter sprake omdat ik enkele jaren geleden ontdekte dat hierover nauwelijks beschrijfbare misverstanden bestaan: een aanzienlijke fractie van mijn gehoor bleek als vanzelfsprekend aangenomen te hebben, dat ik college gaf, omdat ik ervoor betaald werd, met die veronderstelling een enorm paard achter een enorme wagen spannend. Het is namelijk andersom: omdat ik college geef, word ik daarvoor betaald. Het was een echo van de misvatting, die in het einde van de zestiger jaren opgeld deed, nl. dat hoogleraren hun status zouden ontlenen aan hun professoraat aan een instelling van hoger onderwijs, terwijl de facto de instelling van hoger onderwijs primair haar status ontleent aan wie zij als hoogleraar heeft weten aan te trekken.

Als ik dan niet college geef omdat ik daarvoor betaald word, waarom dan wel? Mijn antwoord is eenvoudig: omdat zonder de educatieve winkel, waarin wij het cultureel erfdeel, dat onze voorouders ons hebben toevertrouwd, aan de op ons volgende generatie overdragen, onze maatschappij binnen een halve eeuw zou vervallen in de barbarij. In die zin is het vak van de opvoeder een morele plicht, zowel jegens zijn voorgeslacht, als jegens zijn nageslacht. Rechtvaardigt deze overweging een algemene zorg voor het onderwijs —een zorg, die overigens niet door onze minister van Onderwijs en Wetenschappen gedeeld wordt—, het verklaart natuurlijk niet, waarom ik persoonlijk mij daarvoor zou inzetten. Ogenschijnlijk klemt dit des te meer omdat het vak in kwestie —programmeren voor automatische rekenmachines— nog niet eens bestond toen ik zo oud was als U nu. Wat leuter ik dan over overdracht van het voorouderlijk erfdeel? Waar haalt de parvenu het vandaan?

Wel, dat is heel eenvoudig. Natuurlijk heeft mijn voorgeslacht niet over het programmeren voor automatische rekenmachines gedacht, want het was nog niet met die dingen geconfronteerd. Wat ons voorgeslacht wel gedaan heeft is het opbouwen van een traditie effectief je hersens te gebruiken en duidelijk de functie van abstractie als intellectuele handeling onderkennen: het introduceren van abstracties is het tegendeel van het introduceren van vaagheden, het is het introduceren van een nieuw semantisch niveau, waarop men zich weer heel precies kan uitdrukken. Het is mijn functie te proberen U ervan te overtuigen, dat ook in dit nieuwe veld de beheersing der aloude, beproefde denktechnieken een conditio sine qua non is voor het leveren van werk van voldoende kwaliteit. Ik geef dit college omdat ik meer van die noodzaak overtuigd ben dan het gros van de wiskundigen, die zich nog niet zo erg in automatische rekenmachines verdiept hebben, en dan het gros van de informatici, die nog niet ontdekt hebben, dat zij hun vak ook als wiskundige beoefenen moeten. Ik geeft dit college, gedragen door mijn credo, dat programmeren een van de moeilijkste takken van de toegepaste wiskunde is, omdat het tevens een van de moeilijkste ingenieursvakken is, en vice versa.

Dat vakken instrinsiek heel moeilijk kunnen zijn, past niet in de ideologie van Dr.van Kemenade, en het liefst zou hij ze in het kader van de algemene onderwijsverwatering afschaffen. Ik acht het mijn plicht deze aanslag op onze cultuur te weerstaan, en in elk geval zolang deze lummel minister van Onderwijs en Wetenschappen is, acht ik het niet verantwoord mijn leerstoel te verlaten. Gif moet met tegengif bestreden worden. Nu weet U, waarom ik college geef: waarom U luistert moet U in de loop van het semester voor Uzelf maar uitzoeken.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

EWD511

Tripreport E.W.Dijkstra W.G.2.3. Baden, 1-5 September 1975.

I am very sorry to report that travel by international trains through Western Europe is no longer what it used to be. Coen Bron --from the University of Technology Twente-- and I travelled with the "Holland - Wien Express", and it sounded all right! We went aboard the train in Arnhem on Sunday afternoon at 4 o'clock. We knew that at Emmerich the dining car would be attached and we looked forward to our evening dinner while going through that beautiful part of the Rhine valley: we intended to eat our meal with the setting sun colouring the Lorelei. Great was our disappointment, when we discovered that the diner had been replaced by a help-yourself-snackbar, full of the noisy unwashed young travellers that one tries to avoid as much as possible. There was no "music" --the kind of audible wallpaper that now pollutes air ports and shopping centers!--, but that is the best I can say about the snackbar. After a miserable meal I had an excellent night on board of the sleeper. Five nights later, on our trip back, I would hardly sleep, because there wsa something basically wrong with the support of the carriage: it bumped and jumped and tossed me through my bed, that I sometimes feared a derailment... On the way back I did not sleep at all.

We arrived in Vienna at half past six in the morning, and at the end of the platform I recognized the great Teufelhart, waiting for us to pick us up. (I had hoped something of that sort, Coen was absolutely surprised by that excellent service: the difference being that I knew Teufelhart's efficiency, which was new for him.) We had breakfast in Baden's Parkhotel with the other members of the IFIP Working Group W.G.2.3 on "Programming Methodology". Of the people present I can remember Horning, Randell, Reynolds, Dahl, Ross, Gries, Hoare, Woodger, Naur, Bron, Parnas, Hönke, Sintzoff, Burstall, Jones (Cliff), Belady and Jackson (Michael), and there were still a few more.

Zemanek welcomed us, and then Mike Woodger --our excellent chairman-- opened the meeting in his usual informal way by making a schedule for the next of the week: two sessions in the morning, two sessions in the afternoon, morning sessions separated by a coffee break, and afternoon sessions also being separated by such a break. (In the morning from 9.00-10.30 and 11.00-12.30, afternoon 14.00-15.30 and 16.00-17.30.) The idea of these sessions is that participants report on their most recent work, either for the instruction of the other members or as a means for soliciting comments. The usual pattern is that each time a speaker fills all of his slot speaking and that there is not too much discussion on his talk in the slot itself. This is not too amazing, for usually the audience indeed needs all of the ninety minutes "to catch up" with the speaker. Comments on the things raised usually come later in the week, during dinner, in the evenings, etc., but usually outside the official sessions. In this respect I was very lucky to be the first speaker. I presented EWD 508 "A Synthesis Emerging?", a paper of which the ink was hardly dry. I am very glad that I had the opportunity to do so as the comments were very encouraging. The paper triggered quite a lot. On Tuesday Tony Hoare presented an equally fresh and also somewhat tenative paper "A constructive semantics for a programming language." which at first sight I did not like at all, at second sight I liked it better. On Wednesday afternoon --the traditional "afternoon off"-- he prepared his second presentation, that was to take place on Thursday morning: he used that opportunity to apply his descriptive techniques to the constructs I had introduced on Monday morning, and that was very illuminating for both our subjects.

On Monday morning when I started to describe how --via Tony's explanations in Marktoberdorf last month-- I had finally understood the quintessence of the SIMULA Class concept and had the feeling that I was describing something quite neat, clear and consistent, it was very noticeable that the one in my audience who had the greatest difficulty in grasping what I said was ... Ole-Johan Dahl --the designer of SIMULA-- himself! Not surprising: for him the amount of necessary "unlearning" was greater than for anyone else in the audience. To observe his struggles in grasping what I was explaining was most instructive; it confirmed me in my opinion that one must be very careful in the selection of to what one is going to expose oneself intensively, and it confirmed me also in the opinion that I have been right in staying away from SIMULA classes for such a long time. Had I really studied them, the discovery of synthesis would probably have been much harder. (I mention this, because Ole-Johan's struggles relieved me of a sense of guilt...)

The next presentation that should be mentioned was by Jim Horning, who showed the quintessence of the thesis by John v. Guttag "The precise specification of abstract data types." This looked very promising, not in the last place because he applied the techniques on something more ambitious than just the stack --in user-defined data types the stack seems to become the canonical example, very much like Euclid's algorithm at the algorithmic side!-- but, for instance, to a block-level symbol table. (One can argue --in fact I did-- that this is only a "fancy stack", but yet...; he then told us that they had applied the techniques to more.) As a means for interface definition it looked good, not in the least place because Guttag's specifications seemed to tune in nicely with our current proof techniques, and seemed to do so at both sides of the interface.

Two talks by David Gries --based on the work of Susan Owicki-- were very well received. In one of them he applied the proof techniques to the on-the-fly garbage collector --as he had done in Marktoberdorf. As the on-the-fly garbage collector was new for a large part of the audience, this was doubly instructive for the group as a whole, that experienced David's presentation as refreshing and again, encouraging, because from different sources different concerns had been met. Sintzoff showed a very nice --because constructive-- thing. He showed how --in principle, at least-- given synchronizing conditions could be strengthened in a systematic way so as to exclude the danger of deadlock. I say "in principle" because it was not clear (yet?) whether his formal manipulations would lead in a finite number of steps to the final answer; in his examples this was the case, but that was all. Wait and see!

I had my second slot at Friday morning, 9 o'clock, after IBM had offered us the farewell party on the preceding evening: not the easiest moment of the week for addressing the audience! I used it to show my exercises with making given programs in such a way that single machine malfunctions would not remain undetected. The discussions that followed confirmed my feeling that the path should be pursued. On the original document EWD482 "Exercises in making programs robust" I had received very little constructive comments. The exercise was just difficult and, besides that, most people like to believe that machines don't make errors. I now think, that I can see an argument that shows that with such global --and perhaps "tailor made-- redundancy, a degree of safety can be achieved that none of the other known techniques can attain. That probably means a lot of hard work, and if the result is really convincing and valid, a lot of writing to be done to make it available for a wider public. Again: wait and see!

So much for technicallities (is that spelled correctly?): the morning is drawing to a close and I would like to have this tripreport completed before I leave this afternoon for Newcastle.

At meeting like this one cannot help to pick up all sorts of inside gossip from universities, governments and machine manufacturers. Most of the gossip was depressing. I found much of the "scientific stagnation" that I saw recently at a number of universities, faithfully reflected within IBM; it confirmed my impressions that inside that company the appreciation for scientific research is dwindling rapidly. The first unmistakable symptoms showed up year ago --was it around the time that Brian Randell returned to the UK?-- when the status of Yorktown Heights was changed. (I am not quite sure about the jargon: I think it became a "research division".) The true scientist has one concern he had better never forsake: to strive after perfection. Only too often today he is expected (or pressed or forced) only to make the best of a bad job (or sometimes even worse: an impossible job). The results are terrible. On the one hand, he has to silence his own doubt and to close his eyes for the "badness" thus corrupting his carefully grown judgement. On the other hand, his employer --be it manufacturer or government-- gets very dissatisfied with his performance. If you ask a silly question, you get a silly answer! We all know that. But as soon as the scientific community has accepted a silly question as if it were a sensible one, misunderstanding and intellectual corruption set in. By accepting it as a sensible question, the other side is made to believe that the question makes sense; and when the acceptable answer fails to be given, the scientist is blamed for his "shortcomings". In the case of IBM the matter is exceptionally bad, because they really seem to believe that the 360 is "the final answer", not because it is good --they know very well that it is a lousy design-- but because it is there. Sometimes one gets the alarming impression that scientific activity fills IBM more with fear than with hope. And that would really be alarming, for that corporation is too large a body of our society to be ignored. I had a peep into a few intellectual infernos!

Another thing that struck me was the extent to which for some people "the dollar is their unit of thought"! It occurred most clearly as a reaction to my talk about robustness. Faced with the practical problem of making machine-produced results more trustworthy, one can --and should!-- invent the logical problem and the principles of its solution. To a large extent one can do so without any assumptions about the actual probability of certain forms of malfunctioning. I found a number of the people present unable to do so: they immediately argued that in view of the unlikelihood of a specific form of malfunctioning I was considering, the additional cost of my solution was unjustified. I could not explain to some of them the fundamental difference between

the analysis how, according to a given set of rules, a "perfect" solution would look like

the decision to implement a "perfect" or an "imperfect" solution.

Some engineers are amazing creatures!

When I came home, we had the most delicious climate: the flowers in the garden were blooming, the butterflies danced in pairs in the air, and with the fledglings grown up, all birds seemed to have a wonderful holiday. The sun was shining most of the day, a fresh breeze made the trees wave their branches --which still have most of their leaves-- and gentle clouds were aimlessly drifting through the sky as if they had nothing else to do. A perfect autumn day!

8th September 1975
Burroughs
Plantaanstraat 5
NL-4565 NEUNEN, The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

Transcribed by David J. Brantley
Last revised Mon, 9 Aug 2004.

EWD512

11th November 1975

Comments at a Symposium

Before airing a number of comments and remarks I would like to tell you something about my past lest I be misunderstood.

Firstly --and this is apparently in contrast to a number of people present-- I consider myself a lucky person because I am perfectly happy with the role that mathematics have played in my life. Extended over a period of 45 years, my mathematical education has been, I guess, about a 10 man year effort; you may not like the result, but I liked most of the experience immensely and that amount of fun and intellectual excitement I regard, all by itself, as a sufficient justification. Besides that, my enjoyment was untampered by the now fashionable quibble about "heredity" versus "environment", because in any case my dear mother played a major role in it.

Why do I bring this up? Well, simply, because the only fruitful way of considering computers, that I know of, is regarding them as mathematical machines. Knowing that, I came to this symposium with very low expectations, because this year's motto is "Computers and the educated individual". But mathematics, however, are no longer regarded as an essential ingredient of the cultural baggage of the educated man! Read Eric Temple Bell complaining about the watering down of the American high school, where mediocrity has become the norm, a degradation covered by a misuse of the notion "democratic". Read Courant's introduction to Morris Kline's "Mathematics and the Western Culture", and look around yourself: you will find many in your environment who pose as educated persons and simultaneously announce with some curious pride that "of course they never understood mathematics". Two generations ago, the pitiful one who found mathematics beyond him, tried to cover up his mental infirmity. In short: with today's "educated" individual, and with computers being mathematical machines, our subject "Computers and the educated individual" has a hard time in finding an area of application.

To make things worse, the "educated individual" is so unfashionable as to have become nearly extinct. In the name of justice and equality, the bright pupils are no longer allowed to understand what the stupid ones cannot grasp, and many a government threatens the race of the well-educated individuals with genocide. In the hands of the pedagogues education has been replaced by training, what used to be sowing the seeds of understanding with a hope for harvest has been replaced by educational engineering. Even the individual had better disappear and submerge into a team as quickly as possible. Instead of "Computers and the educated individual", I propose the more appropriate title: "Computers and the ill-trained mob".

In that setting I have been asked about software in the next 25 years! The safest weather prediction for tomorrow is as we all know, "the same weather as today" and if I followed that line I should predict another 25 years of FORTRAN and COBOL. I expect this prediction to be true to a large extent, because there have always been enough fools in this world. But it is the kind of uninteresting prediction saying that tomorrow morning the sun can be expected to rise again. It would only be the full truth if the name of our subject were "stagnation".

Mind you, the pressures to inforce stagnation are strong enough. Sound financial principles seem to dictate that the more expensive our mistake the longer we must maintain it, and there are computing scientists that honestly believe that OS/360 is here to stay, for now until eternity, the argument being that it is too expensive to replace it. There is the possibility that we learn to make a better system at lesser cost; there is the certainty that it becomes too risky and too expensive to continue to use it. Already many a large organisation is nearly crushed under the sheer weight of the illogical, unmastered complexity of its automatic data processing systems. Things have to change and, therefore, will change. Perhaps we have to wait for a few more spectacular collapses until it dawns upon mankind that we had better understand what we are doing. I don't believe in stagnation, I do believe in patience. The current tools will be replaced by better ones because the current ones are just too inadequate.

Please do not misinterpret my appreciation of FORTRAN: if there had been a Nobel prize for computing science FORTRAN would have been an achievement worthy of it. But that appreciation should not engender the mistaken belief that FORTRAN is the last word in computing; on the contrary, it was one of the first words. It is just no longer adequate: since the twenty years of its existence, the computing scene has changed by several orders of magnitude. How could it still be adequate? We don't control Jumbo Jets by whip and spur!

There are two views of programming. In the old view it is regarded as the purpose of our programs to instruct our machines; in the new one it will be the purpose of our machines to execute our programs. In the old view a programmer's expertise is proportional to his knowledge of all the funny properties of the equipment against which he has to fight a continuous battle. In the new view a programmer's competence is displayed by his good taste and the justification with which he rejects inelegant implementation and clumsy interfaces. In the old view, programming becomes easier when the machines become faster and bigger because we can then stay away further from the limits of their capacity; in the new view (recognising that before we had machines, programming was no problem at all), it is recognised that our programming problems will grow with the power of our machines, because we will become more ambitious.

I am perfectly convinced that there will come a time when it will be recognised that programming is one of the more difficult branches of applied mathematics because it is also one of the more difficult branches of engineering, and vice versa. I am equally convinced that simultaneously programming will evolve from a craft learned by apprenticeship, into an intellectual discipline that can be taught and studied, and need no longer be based on the technical mistakes of the department of defence and the computer manufacturers. Don't blame me for the fact that competent programming, as I view it as an intellectual possibility, will be too difficult for "the average programmer" -- you must not fall into the trap of rejecting a surgical technique because it is beyond the capabilities of the barber in his shop around the corner.

To imagine the teaching of a discipline of programming as a science requires some imagination. Any effort to teach programming while disguising its intrinsic mathematical nature, is doomed to failure, but we shall have to teach a discipline of programming in a way that differs from the average way in which mathematics is taught today. The problem with today's mathematical curricula is that mathematical results are published and taught quite openly, but how mathematics is done is not published, not taught explicitly, and the student must pick it up by osmosis so to speak. In this respect mathematics is only half-way between the open science and the secret craft of the guilds, and we are forced to observe that the great majority of trained mathematicians are only amateur thinkers.

But programming, when stripped of all its circumstantial irrelevancies, boils down to no more and no less than very effective thinking so as to avoid unmastered complexity, to very vigorous separation of your many different concerns.

As far as my experience goes programming in the sense of thinking, or thinking in the sense of programming, can indeed be taught. Not all of your students will learn it, but in that respect it is no different from any other subject. Polya's "How to solve it" and his "Art of Plausible Reasoning", although inspiring, are not enough. That would be more than can be expected, for the programming problem only emerged after those books by Polya had been written. And perhaps Polya tried to teach something more elusive than what we are trying to teach now. Polya was concerned with problem solving and he made a sort of checklist that one could go through when trying not to overlook the in some sense "surprising" or "unexpected" solution. But this time we are not so much concerned with problem solving in Polya's sense. I think that "solution composition" comes much closer to what we have to do now. We have to fight chaos, and the most effective way of doing that is the prevention of its emergence. We have to learn to avoid all forms of combinatorial complexity generators that when active rapidly tax our ability to carry out a case-analysis far beyond the limits of our power of reasoning. To recognise the emergence of a combinatorial complexity generator long before it has poisoned your design beyond salvation requires constant vigilance, a vigilance that can and should be taught. To circumvent such emerging complexity generators may very well be a tough problem the solution of which I can only describe as mathematical invention. A great advantage is that we know at least what we are looking for, and --perhaps most important of all-- that a terminology is emerging with which we can name the different stages and aspects of our intellectual endeavour, a terminology in which we can answer the otherwise frustrating question that so often emerges in the midst of one's struggles in "What the hell am I really doing?".

The main virtue of machines is that they have confronted us with a new class of extremely difficult problems that, with love, luck and discipline, we shall learn to cope with. As a reaction to this challenge, consciously trained thinkers will emerge: we need them. The first consciously trained thinkers will be largely self-taught ones, but ... consciously trained, and they will learn how to educate others.

No one needs to tell me that with all its political and social implications this will be a very slow process, much slower than technically necessary. It is that "ritenuto" enforced by society that may see to it that my prediction is good for --as Ewan Page asked-- the next 25 years.

transcribed by Kevin Hely
revised Mon, 7 Jun 2004

  EWD 513

13th of September 1975

Tripreport E.W.Dijkstra Newcastle, 8 - 12 September 1975.

        On Monday the 8th of September I flew —i.e. "was flown"— from Eindhoven to Amsterdam in the late afternoon. In the early evening I flew from Amsterdam to Newcastle; I did so in the company of Goos —now from Karlsruhe— , whom I had met in the waiting area of the Schiphol Airport and who was heading for the same destination as I: the IBM/Newcastle Symposium. Like nearly all German professors he talked more about the situations at his university than about his work. He told me that now they have 700 (!) students in computing science, and I could only guess, what he taught them. British Caledonian was only fifteen minutes late and the flight was about as pleasant as flights can be. After landing, the Newcastle cold surprised us; it would surprise us for the whole rest of the week.

        While the participants at these yearly symposia are always pretty much the same —as are the jokes of Ewan Page—, the subjects are rather different and the speakers are refreshed accordingly. Last year —Formal aspects of computing science— was a "hard" topic, this year's topic —Computers and the educated individual— was as "soft" as soft can be, and I would have been disappointed if I had went with high expectations. On Monday evening, shortly after our arrival, our hosts Page and Randell were "at home" as usual —at Page's home, to be precise— and this informal gathering was quite nice (as usual), and when all the other guests had left, I assisted (as usual) with the washing up. Brian and I walked back to "Hotel Randell", where I stayed, together with Jim Horning. The next morning, the symposium started in earnest, and the series of one-hour talks started.

        Hamming (Bell Laboratories) gave two talks on "The History of Computers to the year 2000" and "Computers in the Coming Society". I found it very interesting to observe him and to see, what a successful career in big business can do to an otherwise intelligent man. If he has still the ability to doubt, he did not show it.

        Naur (Copenhagen University) gave three talks, the first two on "An Adaptable Course of Elementary, University Level, Computer Science" and a last one on "Problems of Attitude in Discussing the Computer/Society Ralation." His three hours seemed about twice as much as what would be needed for what he wanted to tell. All three talks contained relevant information for those who are interested in the atmosphere of and the prevailing prejudices at Scandinavian universities today, and it all sounded pretty depressing. The course that he described was intended to be adaptable to students from various disciplines, what apparently meant that the medical students would get medical examples, the social scientists exercises from their field, etc. (I was surprised at the ease with which he referred to "social scientists": are there any?). It was made quite clear that, rather than giving definitions "students would be required to recognize a card punch, when they were shown a photograph of it". It left me wondering, where the "University Level" came in. In his last talk I remember him pointing out the danger when the authority of the university was misused to back opinions favoured by the labour unions —i.e. backed for that very reason— . I could not agree more; if it happens, I expect the authority of the university to fade rather rapidly. (It seems to be doing so already.)

        Clark (Washington University) gave three talks: The Basis of Present Computer Design, Alternative Computing Models, and Developments and Speculations. (His last one was the only talk that I missed, so I have really behaved myself quite well!) From the first two I have picked up nothing. The volume of his voice was terribly low, his diction made him difficult to understand, and, besides that, he made the impression of having given up hope, before he started, to cross the gap between his hardware interests and his (mainly) software-oriented audience. Those who have attended his third talk said later to me, that it had been much better than his first two ones. During the closing dinner on Thursday evening I has the pleasure of sitting next to him, and I enjoyed his then interesting company very much —to the extent that I have no memory at all of what we have eaten!— .

        Ms. P.C.Goldberg (Watson Research Center) was the obligatory IBM-speaker (or should I say "speakster" or "speak-person" or "voice"?) with three talks on "The Future of Programming for Non-Programmers." She was terrible, her misuse of English really drove me up the wall. One of my colleagues tried to survive her torrent of nonsense by counting noisewords, such as "simply, sort of, kind of, you know, really, I mean, more or less, OK, that is to say, in some sense, in fact, first of all", and gave up after a total of 180 in 27 minutes. It was impossible to filter them out. But even apart from the noisewords, her language was abominable, even on her prepared transparencies. Of course she used "to execute" —with the subject "program"— as an intransitive verb, she talked about "implementing answers", wrote about "objects" which in her explanation were "concepts" etc. and was able to state that something —obviously I have forgotten, what!— was "simply a little bit crucial". My impression is that IBM would love to sell a great number of computer-driven colour TV-screens, and that a number of AI techniques will be used to keep the electrons busy. The need for elaborate man/machine interaction can certainly be enhanced by designing more incomprehensible systems. She was an insult to the audience.

        Holt (Massachusetts Computer Associates) gave three talks on "Formal Methods in System Analysis" (title to be confirmed). On Wednesday afternoon —during the "excursion"— he talked to a small group of people at the university. (Because I had been writing that afternoon, I missed it but for the last 25 minutes.) He showed some very nice examples of the relevance of Petri-nets, for instance for the study of the possible behaviour of a consumer and a producer, coupled by alternatively used buffers. And he was very eloquent in arguing that it is a mistake to think that just "bare facts" can be recorded. He is very clearly —and I think: with great justification— convinced of the nearly all-pervading "relevance" of his considerations, by the time that he then chooses subjects that any course in computing science should contain, I am no longer with him. Should the curriculum contain as a subject "History and structure of the computer industry?". He thinks so. Finally I am grateful to him for having drawn my attention to "the tracking problem". Someone who extracts —or: constructs— such a beautiful example, must have thought deeply. (In Holt's case it was interesting to observe the great variety in reactions that he evoked from different members of his audience!)

        By far the most gifted speaker was F.J.M. Laver, C.B.E., a retired civil servant (from the post office) who gave two brilliant talks on "Informatics and Employment" and "Computation and Democracy". It was an absolute delight to listen to him, light-footed and serious simultaneously, he was the symposium's subject "Computers and the educated individual" become flesh! I shall not try to paraphrase what he said, as it is totally impossible for me to do justice to his performance. I wish that we would have more civil servants of that sort!

        There have been three one-hour discussions. The first one did not really get moving. The second one —with the specific topic "What to Include in Courses"— was not very exciting either, partly because curricula discussions are always depressing, but probably more because its chairman Hamming had already made up his mind many years ago. The last discussion, on Friday afternoon, was a little bit more lively. On Ewan Page's request to stir up matters a little bit, I opened it (with EWD512, that I had been writing on Wednesday afternoon, as soon as I knew that Ewan would like me to present some views).

        At various occasions, but particularly during the last discussion, I was reminded of a recent remark by Tony Hoare, that the main difference between the pure scientist and the business manager is, that the pure scientist has the duty to strive after perfection, while the business manager must make the best choice between the bad and the worse. And, seeing my English University Colleagues, I can only conclude that in England higher education has become big business... Their problem seems no longer to be what insights to create that should be taught if teaching is to be a worthwhile activity at all; their main problem seems to be which forms of coloured water can be poured into a glass as if it were wine. And after forgetting for reasons of convenience that this cannot ever be done without faking, the arguments start discussing in which semester it should be done, and by whom... Reminding them of their obligations towards perfection is an act of indecency. Depending on my mood I think all this saddening or alarming. (It was only this morning that I realized that with one or two exceptions, I do not know what these professors of computing science are doing! No one talked to me about his work; dwindling travel budgets was a more common subject.)

        The willingness to accept what is known to be wrong as if it were right was displayed very explicitly by Hamming —who, as said, seems to have made up his mind many years ago— . As so many others, he expressed in one of his talks programmer productivity in terms of "numbers of lines of code produced". During the discussion I pointed out that a programmer should produce solutions, and that, therefore, we should not talk about the number of lines of code produced, but the number of lines of code used, and that this number ought to be booked on the other side of the ledger. His answer was "Well, I know that it is inadequate, but it is the only thing we can measure." As if this undeniable fact also determines the side of the ledger...

        On Friday afternoon we flew back to Amsterdam; again British Caledonian did so with a delay of fifteen minutes. This time —but we shall not blame British Caledonian for that— the flight was bumpy. I made the trip in the company of my Utrecht colleague van der Sluis, with whom I talked about a few beautiful proofs and who told me something about the level of the discussions between representatives of the Dutch universities and our Ministry of Education. It is something like "If you believe only half of what I am saying, I am, therefore entitled to lie twice as much."

        At eight o'clock it was announced that the Amsterdam - Eindhoven flight was canceled, due to a thunderstorm near Eindhoven, and it was only late that evening when I came home. Saturday morning, while I was having a bath, we had a tornado, and I knew that the summer was no more.

Plataanstraat 5 NUENEN - 4565 The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

PS. After I had introduced the msi —milli-split-infinitive— as the practical unit of linguistic irritation, Brian Randell threatened to name the unit of "grammatical pedantry" after me; I took it as a compliment!

transcribed by Corrado Cantelmi
revised Fri, 11 Aug 2006

17th of September 1975 | EWD514

On a language proposal for the Department of Defence

"For fools rush in where angels fear to tread." 
             from "An Essay on Criticism" by Alexander Pope, 1688-1744

Introduction

If some of the following comments sound (unusually) grim, it should be borne in mind that I write these comments not in my native tongue and that combining in English clarity with the subtle use of understatement is not my greatest strength.

I have screened the report "strawman" —second cut— in my usual way, which I have found most effective in the past, asking myself the following questions.

How careful use has been made of the (English) language?
This I have found to be one of the most revealing criteria. It has nothing to do with grammatical pedantry or anything of that sort; I firmly believe that no project can result in a product better than the language in which the product has been discussed and carried out. For anything non-trivial careful use of language is not a luxury, but a must.

Is the justification of the goals convincing?
If it is not, it may mean a number of things. It may mean, that the author is consciously unconvinced of the worthiness of the goals: in that case he should abandon it. It may be, that the author is subconsciously unconvinced of their worthiness, but has been "talked into it": in that case he should clear up his mind.

Are the goals compatible with each other and well-understood?
If they are not, early discovery is often possible and then saves a lot of vain effort.

Are the most difficult aspects of the project well-identified and is it probable that their difficulties can be surmounted?
No chain is stronger than the weakest link so search for the latter.

Has the author separated his concerns in a helpful manner?
For any complicated undertaking I have learned to appreciate a clear separation of concerns as a (technical) conditio sine qua non; as a result I have learned to appreciate its absence/presence as one of the more telling indications for judging the expected (in)competence for the task at hand.

Whenever on the verge of embarking on a sizeable project —before speeding up towards the point-of-no-return, so to speak— I myself have always played with respect to my own projects the role of the doubter, of the advocatus diaboli, trying to kill the project. Embarking on an impossible task and failing is a most time-consuming and expensive way to demonstrate its impossibility. What is worse, the failure often fails to convince, because the stubborn optimists will say: "Well, if next time we avoid those and those mistakes, we may succeed.". In such circumstances a piece of a priori reasoning that argues why a project, even without mistakes in its development, is bound to fail, is, although in itself non-constructive, a rewarding exercise. The project "strawman" seems to be in a stage that justifies such a screening; or is its impetus already so large, that the point-of-no-return has been passed?

1. The Use of language.

The spellings —they occur with great "consistance"— "kernal" and "encapsolation" are somewhat piculier. But it is not only spelling: in section 2 "A Common Programming Language" (page 5) the author writes about "improvements in ... risks", and he titles a section "Criteria to Aid Existing Software Problems". He writes —"IV. A. Criteria to Satisfy Specialized Application Requirements"—

"... it must be possible to write programs which will continue to operate in the presence of faults."

To start with: "it must be possible" is very ambiguous: either this sentence concludes the existence of a possibility, or states the extreme desirability of a possibility, and by using "must" in this way, the author is close to confusing ends and means. My next objection is that programs don't "operate": a program is as static as a drawing, a proof, a novel or a bill. But, finally, what is meant by "continue to operate"? In a way that we can ensure that a machine will continue to operate by disabling the parity check? I will return to this section later.

On the same page is written

"Applications which must interface with equipment or people in real time must have access to real time programming capability."

How can an application interface? How does an application have access to a programming capability? (Reference to "capabilities" in connection with programming is, I am afraid, nearly always a symptom of fuzzy thinking: I, at least, don't have them for understanding them!)

I stop my linguistic comments here (but not for lack of further material). Pointing out that signalled linguistic sloppiness is quite usual and accepted in computing circles, is no excuse; for if it is true, that could very well be an explanation for today's sorry state of the art.

2. Justification of the goals.

A considerable part of the justification is financial. Now, although coins are very concrete objects, money is a highly abstract notion, and the author does not seem to understand it. How, otherwise can he write "Software is very expensive"? (III The Most Pressing Software Problems. A. High Cost.) As that paragraph continues, we must conclude that the author would agree to the remark that "poetry and platinum are very inexpensive", because only little money is spent procuring them. As most of the costs involved in the development etc. of software are personnel costs:

the "high price" is due to the great number of programmers engaged; in these times of unemployment, that may not be a bad thing at all.

alternatively the DoD could halve the programmers' salaries.

I came to the conclusion that money is not the real issue. (I know that those whose unit of thought is the dollar, will not understand this, and will therefore feel entitled to disagree, but never mind that.)

At various places —and that is a much more forceful justification— the author expresses his concern about the quality of today's software ("Programming errors can have catastrophic consequences.") and in the section "Timeliness" he justly points out "a common reaction is to aggravate the situation by adding additional manpower". The word "aggravate" is a true one: it is not so much the additional costs involved in adding the additional manpower, it is its degrading effect upon the quality of the final product that should worry us.

So I decided to read the document as a proposal aimed at improving the quality of DoD software. If this can be achieved, it can probably only be achieved by making fewer mistakes and from that a cost reduction is only to be expected. (Not software, but mistakes are expensive!) In short: I regard a possible cost reduction as a (possible considerable) fringe benefit, the higher quality as the main goal. I thought that I could do so while doing full justice to the author.

3. Are the goals compatible and well-understood?

The author writes "The distinction between high order and low level languages is that between people and machines". I can enlarge on that: in the past, when we used "low level languages" it was considered to be the purpose of our programs to instruct the machines; now, when using "high order languages" we would like to regard it as the purpose of our machines to execute our programs. Run time inefficiency can be viewed as a mismatch between the program as stated and the machinery executing it. The difference between past and present is that in the past the programmer was always blamed for such a mismatch: he should have written a more efficient, more "cunning" program! With the programming discipline acquiring some maturity, with a better understanding of what it means to write a program so that the belief in its correctness can be justified, we tend to accept such a program as "a good program" if matching hardware is thinkable, and if with respect to a given machine aforementioned mismatch then occurs, we now tend to blame that computer as ill-designed, inadequate and unsuitable for proper usage. In such a situation there are only a few true ways out of the dilemma

accept the mismatch

continue bit pushing in the old way, with all the known ill effects

reject the hardware, because it has been identified as inadequate.

The author concludes his discussion of High Order vs. Low Level Programming Languages with:

"The fourth approach, and the one which to our mind is most reasonable when object efficiency is important, acknowledges that the major limitation on automated optimization is lack of information. It may have been a mistake to use programming languages in which the programmer can underspecify his task and hide information from the compiler. [...] High level programs should contain a great deal of information of value to the compiler ..." etc.

But I have some questions. With "information of value to the compiler" is probably meant, information that will cause the compiler to produce a more efficient object program; what kind of "helpful" information does the author have in mind? Does the author believe, that the notion "helpful" is machine independent? And is also compiler independent? If so, why? If not, the purpose of the high order programming language is defeated, for, in order to write a good program, the programmer must not only know the target machine well, but in addition the HOL compiler for it! Has the author any notion of the algorithms that could be used in the compilers, so as to exploit that additional helpful information? Does the author believe that the desired efficiency can be achieved by such "assisted automated optimization"? At this place —where the controversy has to be talked away— he suggests so. Later he insists on the possibility to include "machine language"!

When mentioning the possibility of inserting machine language, the author does not seem too enthusiastic —and rightly so: has he yielded to pressure?—: he mentions that it would defeat the purpose of machine independence. I would like to point out that in all probability the mere possibility of inserting machine language —whether used or not!— will defeat much more!

it may be expected to constrain implementation techniques

it may be expected to complicate diagnostics which, remember, should be given in source language components

it may be expected to impair security: type checking conventions can be circumvented.

it may be expected to impair the ability to exclude in multiprogramming situations a priori a large class of ugly time-dependent bugs. Don't forget that in real time applications, scope rules —ruthlessly checked by the compiler— are a powerful tool for ensuring that one of the sequential processes will not interfere in an uncontrolled fashion with local variables of one of the other sequential processes of the aggregate. The same holds for a number of independent programs executed in an interleaved fashion; in the latter case it is not unlikely that the correct execution of my program depends on you not having inserted sneaky machine code!

I cannot suggest strongly enough each time to select one of the three ways out of the dilemma, and not to mix them. When the second alternative "continue bit pushing in the old way, with all the known ill effects" is chosen, let that be an activity with which the HOL project does not concern itself: if it does, the "ill effects" will propagate through the whole system.

*                       *
*

I agree with the author's remark in "Simplicity vs. Specialization": "Probably the greatest contributor to unnecessary complexity in programs is the use of overly elaborated languages with large numbers of complex features." I would like to point out that a vital word in that sentence is the word "unnecessary": the remark should not seduce us to believing that programming will become easy when we have a simple programming language, because the intrinsic complexity as might follow from the task, will remain. The author has not analyzed what caused the emergence of those baroque tools, nor does he indicate how he proposes to prevent that his "extensible (!) HOL" results in as many baroque horrors as extensions are made. The answer "Yes, but that is not the HOL, that is only an extension" is not adequate!

I agree with his remark in "Programming Ease vs. Security"; indeed, many people mistake ease of programming with ease of making undetected errors. His remarks in 3. "Object Efficiency vs. Clarity and Correctness" are inconclusive; so are the ones in section 4. "Machine Independence vs. Machine Dependence".

*                       *
*

By the time that I read under the heading Fault Tolerant Programs:

"In many weapon systems and control programs it must be possible to write programs which will continue to operate in the presence of faults, whether in the computer hardware, in input data, in operator procedures, or in other software. Crucial to fault tolerant programs is the ability of the program to specify the action to be taken at all (!) run time exception conditions.",

I wonder, whether the author has read what he has written. You see, we have to write "programs which will continue to operate". The language should therefore contain as one of the basic primitive building blocks the procedure called "get_me_out_of_the_mess"; its body consists of a faithful copy of the Philosopher's Stone.

*                           *
*

4. Are the most difficult aspects identified?

I don't think so. The author has a dream about a nice kernel —and a lot of things he writes about that kernel are quite sensible— but the word "kernel" itself is an OK-word that should make us suspicious. We have already seen that all machine-dependent characteristics —special peripherals, etc— are pushed into the extensions, and it is not inconceivable that that can be done. (In the great number of cases this has been done quite successfully, e.g. a bunch of standard library procedures manipulating an incremental plotter.) By the time, however, that (9. Standard Extensions, c) I read:

"Any selected common language must be capable of interfacing with data base systems; and, because standards are limited and there is ongoing research in this area, the data base interface should be designed as an extension which can grow at the user level without inventing a new language."

I shudder. This might turn out to be a non-trivial task, and, given a mechanism for "language extension", it is not clear to me at all that that mechanism will enable us to cater for any conceivable data base interface. In all probability it won't. And that would imply that the design of the extension mechanism implicitly delineates the class of data base interfaces to which the HOL can be extended so as to fit. In this sense we can regard the possibilities and limitations of the extension mechanism as a "downward meta-interface" towards the data base. Nowhere the author gives a hint that, for instance, here the HOL designers have a very serious responsibility. A more careful scrutiny of the proposal, I am afraid, will reveal similar instances of unawareness.

5. Separation of concerns

The author makes, for instance, an insufficiently clear separation between the definition of the language and its implementation. At "Source Language Characteristics" 3. Variables, Literals, Constants, c (page 10) 14 lines from below, he writes:

"Whether a variable will be assigned a value is in general unsolvable at compile time, but in those cases in which it is not easily determined by the translator, it will not be easily determined by the programmer and those who must maintain the program and should therefore be considered an error."

I am all in favour of a programming language that does away with the phenomenon of the possibly uninitialized variable, and I fully agree with the author's remark —in the same paragraph— that automatic initialization by default is a fake solution. The only solution that I know of introduces the initialization syntactically distinguishable from the assignment to a variable that already has a value and ensures by syntactic means that no uninitialized variable can ever be accessed; in this case the syntactic means are provided by a refinement of the scope rules. (I once designed such a system for a language with a pronounced sequencing discipline; needless to say, the inclusion of go to's —another of the requirements in the proposal!— makes this problem very much harder if not insolvable.) Under no circumstances, however, the question whether something is an error or not, should be made dependent on the cleverness of a compiler! And this is exactly what the above, quoted paragraph suggests to me.

6. Additional Remarks

The section 5 "Scope", c. suggests that the scope of a variable declared at the beginning of a block automatically extends over inner blocks —unless a new declaration for that identifier is given for the inner block— like it was done in ALGOL 60. Whether this automatic inheritance by an inner block of the global variables is a very safe convention is subject to serious doubts. I have experimented with a language in which at the beginning of an inner block all global identifiers identifying variables or constants needed in the inner block had to be listed explicitly —it even indicated the nature of the inheritance: as a constant, as an initialized variable or as a variable that had to be initialized—. I found this form of redundancy very helpful and can even argue why such redundancy is in a sense indispensible.

*                          *
*

The most revealing (and also most alarming) passages, however, I found in the recommendations. "The design of a simple, uniform language ... should be do-able in six months using qualified language designers/implementers." I was flabbergasted! (It taught me, again, that the best way to read documents is often reading them backwards! In cauda venenum.....) The problem is that I happen to know a few people that I would consider to be "qualified language designers/implementers", but none of them would regard the design of a simple, uniform language as only a six-month job! The design of something worth having really takes many times longer. If the six-month period mentioned does not already reveal what the author has in mind, the word "using" does it: how much nicer the quoted sentence would have been, if he had written "by" instead....

The whole document gives me the uneasy feeling that here I see a proposal to concoct yet another nil-solution to an unsolvable problem. The worst shock I got on the next pages "Thus the benefits will grow if the new efforts adopt the standard whatever it is." (7. my emphasis) and "Research in the design of programming languages ..., in programming methodology ... should continue in parallel with the use of a fixed common language" (10).

If the author knows anything about research, he should know that one of the most difficult mental gymnastics is to dissociate oneself from the inadequate experiences and prejudices collected in one's past. Section 6 "..through alteration of extant languages" strongly suggests a conservative effort. And the outcome of that conservative six-month effort should present the framework (constraints?) for research in programming methodology? Now, come on....

After having stated (7) that the benefits will grow if the new efforts adopt the standard "whatever it is" the text continues ominously "The ultimate measure of success must be in cost savings and failure of a project to adopt the common language should only be for demonstrable economic reasons." I don't like that sentence at all. The use of the word "failure" is incriminating in this context, "refusal to adopt the common language" would have made the sentence less offensive. It is perhaps as well that it has been written as it has been: it betrays a dangerous attitude which otherwise could have remained hidden.

Is it not amazing that the lack of "management visibility" can become so frustrating for the managers that people are seriously proposing to enforce a standard "whatever it is"? Such an enforcement could easily stifle all progress. It has already been suggested that Red China could win the next war provided that it manages to skip the FORTRAN/COBOL stage, which now paralyses much of computing in the Western hemisphere.

Note. COBOL has been designed with the intention to eliminate programmers. And what is the result? COBOL is only used by professional programmers (by about 75 percent of them, as a matter of fact). As COBOL has been pushed very strongly by the DoD, this failure of COBOL to meet one of its goals must have been noticed within the DoD, and I expect that some experts at the DoD must have investigated why COBOL has failed so miserably in this respect. Has that same group of experts also studied "strawman"? (End of note.)

The burning question that should be considered is, whether the adoption of a common language HOL will really improve "management visibility". I doubt that it will, I seriously doubt......

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Tue, 18 Dec 2007

20 september 1975 EWD 515

Tweede toespraak, najaar 1975.

Een min of meer mechanisch wereldbeeld wordt ten minste sinds de klassieke oudheid gehanteerd, toen de planeten, ieder in zijn eigen sfeer, geacht werden om de aarde heen te draaien. In de renaissance heeft het werk van Keppler, Copernicus en Galilei, en daarna dat van Newton het mechanisch wereldbeeld een nieuwe en niet te onderschatten stimulans gegeven. Aangespoord door het succes van de exacte wetenschappen is men meer en meer in dit keurslijf gaan persen en is bv. in de psychologie de school van het Behaviourisme ontstaan, een school, die een uiterst mechanisch mensbeeld hanteert. En daar zitten we nu mee! Als je goed kijkt, hebben de behaviourist eigenlijk helemaal geen echt mensbeeld: ze hebben een mechanische rat met de kwijlende hond van Pavlov gekruist en zeiden toen: "Wel, in principe werkt een mens net zo." Alleen het caveat "in principe" schijnt in de laatste halve eeuw weggesleten te zijn, Eerst de individuele mens, en vervolgens aggregaten van mensen reduceerden zich tot regelapparaat, tot boekhouding van respons versus stimulus. Na de psychologie zijn in het kielzog van deze simplificatie allerlei activiteiten ontstaan, die zich geheel ten onrechte als wetenschappen aandienen, zoals de economie, de sociologie, de paedagogie, de politicologie, de adragogie en noem maar op: dubieuze activiteiten die in het Engels taalgebied zo treffend als "the soft sciences" worden aangeduid, met de nadruk op "soft" en het woord "sciences" uit te spreken met het nodige sarcasme in de stem. Hun collectieve naam is "Bedrog", want zij toetsen hun hypothesen —die de toets der critiek niet kunnen doorstaan— daarom niet; hun collectieve naam is "Bedrog" omdat zij niet schromen aanbevelingen te doen zonder erkenning gefaald te hebben, wanneer het opgevolgde advies niet het voorspelde effect heeft. In feite onderscheiden zij zich niet van de regenmaker, die de ondanks zijn dansen aanblijvende droogte uitlegt als de wraak der goden, noch van de toekomstvoorspelster op de kermis, die uit haar kristallen bol —die in feite van persglas is— zo vage voorspellingen destilleert dat een duidelijk weerleggende toekomst nauwelijks denkbaar is. Maar in tijden van moeilijkheden, wanneer de mens meer zekerheid verlangt, dan waar hij recht op kan doen laten gelden, loopt het storm bij de waarzegster...

Onze overheid heeft dit gelukkig goed begrepen. In een poging om na de tweede wereldoorlog ons geruineerde land weer leefbaar te maken, is met man en macht het hoger onderwijs, dat in de dertiger jaren wat in het slop was geraakt, gestimuleerd. Deze injectie, die voor de wetenschappen bedoeld was, is helaas mislukt: hij is grotendeels ontaard en aan de universiteiten, ja zelfs aan de technische hogescholen, heef de kiem van de "soft sciences" zich tot een kankergezwel ontwikkeld. En 't oeverloos gezever deed zijn intree. Wat doet men met een grootscheepse mislukking? Heel eenvoudig: men neemt niet eens de moeite haar te ontkennen, men verklaart haar ex cathedra als een succes, als een veel belovende stap in de richting van een betere maatschappij!

Het is natuurlijk wel vervelend, dat er in de oudere wetenschappelijke disciplines nog wel bourgeois geleerden zijn, die het kaf van het koren kunnen scheiden; geen nood: men schroeft ze de financiele duimschroeven wat nauwer aan en dan zingen ze wel een toontje lager. Die techniek is sinds de inquisitie wel bekend. Als desondanks de heilsboodschap van de "soft sciences" door flagrante kwakzalverij toch nog wat onovertuigend doorkomt, wederom, geen nood! Men legt dit uit als het bewijs, dat in de afgelopen decennia voor de "soft sciences" te weinig gelden ter beschikking zijn gesteld, en rechtvaardigt daarmee de beslissing de aan de wetenschap onthouden gelden naar de kwakzalver over te hevelen. Ter dekking van deze malafide manoeuvre vindt men eerst een Minister van Wetenschapsbeleid uit; ter politieke onderstreping van het feit, dat de gevestigde wetenschappen eigenlijk niet zo belangrijk zijn, kiest men hier een gesjeesd student voor. Voor nadere details verwijs ik U naar de nota's van Minister Trip en naar de jongste Troonrede.

Verdere consequenties van de opkomende kwakzalverij uitstellend tot een volgende keer gaan wij thans over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Wed, 13 Jun 2007

28 september 1975 EWD 516

Derde toespraak, najaar 1975.

De toenemende verbreiding van het mechanisch mensbeeld heb ik vorige week genoemd als voornaamste oorzaak van de opkomst der charlatannerie; charlatannerie in alle geledingen en op alle niveaus, mogen wij in het moderne jargon wel toevoegen. Heden wil ik U op enkele specifieke consequenties van dit mechanisch mensbeeld wijzen, consequenties waarmee wij, dwz. U en ik, in dit instituut van wetenschappelijk onderwijs —en dit met evenveel nadruk op het adjectief, als op het substantief!— om de haverklap te maken hebben.

Om te beginnen zijn er de educatieve praktijken, die door een mechanisch studentbeeld geinspireerd worden. De student is een nummer, een inschrijvingsnummer om precies te zijn. Dit is, wat U op de eerste dag krijgt ingeprent: zonder inschrijvingsnummer bent U niets, bestaat U niet eens als student. Daarna mag U deel hebben aan het proces dat de psychologen, sinds ze het "kennisoverdracht" hebben genoemd, denken te begrijpen. U bent nu spons met gemiddeld voorspelbare opzuigeigenschappen: via multiple choice tentamina en andere formulieren voor imbecielen is vervolgens Uw objectief gemeten opzuigvermogen voer voor statistici. Ik dacht, dat er belangrijkere zaken zijn, dan wat de spons heeft opgezogen, bv. of U van een college genoten hebt, of U het ervaren hebt als een verrijkende ervaring die U uw leven bij zal blijven. Maar de mechanische student heeft geen leven, laat staan een geestelijke rijkdom, en dat de multiple choice vragen aan dergelijke impondera- bilia voorbijgaan, deert de moderne onderwijsorganisator niet.

En dan zijn er de educatieve praktijken, die door een mechanisch docenten- beeld worden opgeroepen. Er was een tijd, dat hoogleraren college gaven en studenten dictaat maakten. Daarna kwam de syllabus, het van te voren uitgereikte collegedictaat. Daar was aanvankelijk niets op tegen: het dictaat werd uitgereikt in de veronderstelling, dat de student lezen kon en gaf de docent meer tijd, en daarmee meer vrijheid zijn onderwerp te omspelen. Maar het mechanisch docentenbeeld heeft aan het vooraf uitgereikte collegedictaat een andere rol toebedeeld, nl. de rol van het zigzag gevouwen boek in een draaiorgel: de docent had zich aan zijn tekst te houden! Al dat oncontroleerbare, onvoorspelbare initiatief, dat moest maar eens afgelopen zijn! Als hoogleraren ieder jaar hun college zouden veranderen, hoe kunnen we dan in hemelsnaam tentamenuitslagen van opeenvolgende jaren zinvol statistisch vergelijken?

De volgende slag is, dat het collegedictaat niet meer door de verantwoordelijke docent zelf, maar door een daartoe ingestelde commissie wordt opgesteld. Ik gebruik expres het woord "opgesteld", het woord "geschreven" wil ik niet meer gebruiken, omdat dit nog een "schrijver" vooronderstelt.... Een tekst, waarmee alle commissieleden kunnen instemmen, is nimmer aanstootgevend, nimmer intellectueel prikkelend, en visie wordt vervangen door een kleurloos mengsel van versleten vooroordelen.

De managers hanteren immer een uiterst mechanisch mensbeeld, want zonder dat zou de grond onder hun activiteit wegzinken. Het bedenkelijke is, dat zij immer hun invloed aanwenden om in naam van de "management visibility" —dit is een auto- noom doel geworden!— alles wat door originaliteit kan verrassen te vervangen door voorspelbare flauwe kul. Het steeds verstikkender centralisme, op landelijke schaal bedreven door het departement van O. en W. en op locale schaal nagestreefd door universiteitsen hogeschoolraden, past volledig in dit beeld. Het is de wurgpaal voor de intellectueel en de kunstenaar.

En nou heb ik het nog niet eens over "geprogrammeerde instructie" gehad!

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

30 september 1975 EWD 518

Vierde toespraak, najaar 1975.

Wij hebben met de managers nog een appeltje te schillen; een zuur appeltje zelfs.

Een jaar of wat geleden hield ik een voordracht in een heel groot Engels "software house". De inrichting van hun auditorium was zojuist vernieuwd en mij viel de eer te beurt als eerste spreker van de nieuwe grandioze faciliteiten gebruik te mogen maken. Die grandioze faciliteiten bestonden onder andere daaruit, dat de voortreffelijke borden op last van de binnenhuisarchitect als "ouder wets" waren verwijderd, en ik me met een zg. "overhead projector" moest behelpen. Nu zijn dat ondingen! Om niet totaal verblind te worden, moet je je zonnebril opzetten, en om der wille van het contrast wordt de zaalverlichting gedempt. Het resultaat is, dat je op de eerste rijen nog wat van je publiek ziet zitten, maar vanaf de vierde rij verwijnen de schimmen in de duisternis. Ik begon desondanks met goede moed, want ik wist, dat mijn lezing, die ik al een keer eerder had gehouden, voortreffelijk was: ik speelde met een paar kleine probleempjes, waarvoor ik op nochtans ordelijke wijze allerlei verschillende oplossingen ontwikkelde. De voordracht was voor mij evenwel een marteling, want ik zag me mijn publiek niet bereiken: ik werd onbewogen aangestaard en voelde me, alsof ik marionetten van stopverf of kauwgum stond toe te spreken. Met de moed der wanhoop worstelde ik me door mijn stof heen en was stomverbaasd, toen bij het opdraaien der lichten een klaterend applaus uit de zaal opsteeg. Wat was er gebeurd? Mijn publiek had voor de helft uit collegae-programmeurs en voor de helft uit managers bestaan; de programmeurs, die achterin de zaal zaten, hadden van de beheerste inventiviteit genoten, vanuit het standpunt van de managers, die voorin hadden gezeten, was mijn voordracht een volslagen mislukking. Ze vonden me misschien wel opruiend: door in mijn onschuld zonneklaar aan te tonen, hoeveel verrassende inventiviteit programmeren met zich mee kan brengen, had ik even zonneklaar aangetoond, dat ze de activiteit nog steeds niet konden "managen" en dat "programmer performance" even onvoorspelbaar is als elke activiteit van hoog intellectueel kaliber. Tijden de discussie schrok ik, toen ik merkte hoe fervent ik op de voorste rijen gehaat werd.....

Managers voelen de continuiteit van grote organisaties het best gewaarborgd als zij kunnen werken met middelmatige mensen zonder fantasie, en als het werk niet veel fantasie vergt, gaat dat allemaal goed en kunnen zij de werkomstandigheden scheppen, waarin velen zich nuttig kunnen maken. In hun verwatenheid denken zij evenwel, dat alles zo georganiseerd kan worden, zijn er zelfs managers, die ongeacht de aard van de collectieve taak, bewust en openlijk brilliante employees weren "as they can be expected to disturb the organization". Jazeker... Elk project met grote technische en logische moeilijkheden is tot falen gedoemd, wanneer deze moeilijkheden onderschat worden, en deze onderschatting is waarin de software managers stug volharden: ze volharden in de fictie, dat het allemaal organiseerbaar routinewerk is. Als ware charlatans versluieren zij hun incompetentie met een rookgordijn van dure termen, bouwen een quasi-religie op met termen als "system engineering", "system life cycles" en noem maar op; de term "structured programming" die ik in 1968 gebruikt heb in een poging de intellectuele inhoud van het vak bloot te leggen, wordt schaamteloos gestolen door Harlan D.Mills van IBM, wanneer hij het "Chief Programmer Team" lanceert als nieuwe religie voor software management, een religie, waarin opnieuw de intellectuele inhoud van het vak ontkend wordt....

Wacht U voor zulke managers, want ze houden vol tot hun laatste snik: op hun manier waarborgen zij de continuiteit van de organisatie, totdat de organisatie in elkaar stort. En als de regenmakers, die ondanks de aanhoudende droogte in eigen wonderbare gaven blijven geloven, gaan zij onverdroten door de Steen der Wijzen aan te bieden.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

EWD 520

On-the-fly garbage collection: an exercise in cooperation.

            by
Edsger W.Dijkstra *)
Leslie Lamport **)
A.J.Martin ***)
C.S.Scholten ****)
E.F.M.Steffens ***)

*) | Burroughs, Plataanstraat 5, NL–4565 NUENEN, The Netherlands
**) | Massachusetts Computer Associates Inc., 26 Princess Street, WAKEFIELD, Mass. 01880, U.S.A.
***) | Philips Research Laboratories, EINDHOVEN, The Netherlands
****)   | Philips-Electrologica B.V., APELDOORN, The Netherlands

Abstract. A technique is presented which allows nearly all of the garbage detection and collection activity to be performed by an additional processor, operating concurrently with the processor carrying out the computation proper. Exclusion and synchronization constraints between the processors have been kept weak.

Key Words and Phrases: garbage collection, multiprocessing, cooperation between sequential processes with minimized mutual exclusion, program correctness for multiprocessing tasks.

CR Categories: 4.32, 4.34, 4.35, 4.39, 5.23.

20th of October 1975

On-the-fly garbage collection: an exercise in cooperation.

Introduction.

In any large-scale computer installation today, a considerable amount of time of the (general purpose) processor is spent on “operating the system”. With the emerging advent of multiprocessor installations the question arises to what extent such “housekeeping activities” can be carried out concurrently with the computation(s) proper. Because the more intimate the interference, the harder the organization of the cooperation between the concurrent processes, the problem of garbage collection was selected as one of the most challenging —and, hopefully, most instructive!— problems. (Our exercise has not only been very instructive, but at times even humiliating, as we have fallen into nearly every logical trap that we could possibly fall into.) In our treatment we have tried to blend a condensed design history —in order not to hide the heuristics completely— with a rather detailed justification of our final solution. Whether the following solution, which is the result of many iterations, is of any economic significance, is a question beyond the scope of this paper.

We tackled the problem as it presents itself in the traditional implementation environment for pure LISP (and shall describe our solution in the usual terminology, leaving the natural generalizations to the reader). The data structure to be stored consists of a directed graph in which each node has at most two outgoing edges, more precisely: may have a left-hand outgoing edge and may have a right-hand outgoing edge. In the original problem statement, either of them or both could be missing; for the sake of homogeneity we follow the —not unusual— practice of introducing a special purpose node called “NIL” and we represent an originally missing outgoing edge by an edge with the node called NIL as its target. As a result, each node had now always exactly two outgoing edges; the outgoing edges from NIL point to NIL itself. At any moment in time all the nodes must be “reachable” (via a directed path along the directed edges) from one or more fixed nodes —called “the roots”— with a constant place in memory. The storage allocated to each node is constant in time and equal in size, viz. sufficient to accommodate two pointers —one for each outgoing edge— pointing to the node’s immediate successors. Given (the address of) a node, finding (the address of) its left- or right-hand successor node can be regarded as an atomic, primitive action; finding its predecessor nodes, however, would imply a search through memory.

In the original problem statement, for a reachable node an outgoing edge could be deleted, changed or added. The effect of the special node NIL is that now all three modifications of the data structure take the same form, viz. the change of an outgoing edge of a reachable node. Note that such a change may turn a number of formerly reachable nodes into unreachable ones: they then become what is called “garbage”. Changing an edge may direct the new edge towards a target node that was already reachable or towards a new node that has to be added to the data structure; such a node —which upon creation has only NIL as successor node— is taken from the so-called “free list”, i.e. a linearly linked list of nodes that are currently not used for storing a node of the data structure. By linking the “free” nodes linearly —via their left-hand outgoing edge, say— and introducing a special root pointing to the begin node of the free list, also the nodes of the free list can be regarded as reachable. By furthermore declaring that also the node called NIL is a root, we achieve our next homogenizing simplification: a change redirects for a reachable node one of its outgoing edges to a reachable node. (See Appendix.)

Garbage may arise anywhere in store, and it is the purpose of the so-called “garbage collector” to detect such disconnected and therefore obsolete nodes and to append them to the free list. In classical LISP implementations the computation proceeds until the free list is exhausted (or nearly so). Then the computation proper comes to a grinding halt, during which the processor is devoted to garbage collection. Starting from the roots, all reachable nodes are marked —because we have made the nodes of the free list reachable from a special root, nodes of the free list (if any) will in our case be marked as well— . Upon completion of this marking phase, all unmarked nodes can be concluded to be garbage and are appended to the free list, after which the computation proper is resumed.

The minor disadvantage of this arrangement is the central processor time spent on the collection of garbage; its major disadvantage is the unpredictability of these garbage collecting interludes, which makes it hard to design such a system so as to meet real time requirements as well. It was therefore tempting to investigate whether a second processor —called “the collector”— could collect garbage on a more continuous basis, concurrently with the activity of the other processor —for the purpose of this discussion called “the mutator”— which would be dedicated to the computation proper. We have imposed upon our solution a few constraints (compare [2]). The interference between collector and mutator should be minimal —i.e. no highly frequent mutual exclusion of elaborate activities, as this would defy our aim of concurrent activity— , the overhead on the activity of the mutator (as required for the cooperation) should be kept as small as possible, and, finally, the ongoing activity of the mutator should not impair the collector’s ability to identify garbage as such as soon as logically possible. (One synchronization measure is evidently unavoidable: when needing a new node from the free list, the mutator may have to be delayed until the collector has appended some nodes to the free list. This is the now traditional producer/consumer coupling; in the context of this article it must suffice to mention that this form of synchronization can be achieved without any need for mutual exclusion.)

Preliminary investigations.

A counterexample taught us that the goal “no overhead for the mutator” is unattainable. Suppose that nodes A and B are permanently reachable via a constant set of edges, while node C is reachable only via an edge from A to C. Suppose furthermore that from then on the mutator performs with respect to C repeatedly the following sequence of operations:
1)   making an outgoing edge from B point to C
2)   deleting the edge from A to C
3)   making an outgoing edge from A point to C
4)   deleting the edge from B to C.
The collector, which observes nodes one at a time, will discover that A and B are reachable from the roots, but never needs to discover that C is reachable as well: while A is observed by the collector, C may be reachable via B only, and the other way round. We may therefore expect that the mutator may have to mark in some way target nodes of changed edges.

Marking will be described in terms of colours. When we start with all nodes white, and, furthermore, the combined activity of collector and mutator can ensure that eventually all reachable nodes become black, then all white nodes can be identified as garbage. For each repetitive process —and the marking process certainly is one— we have always two concerns (see [1]): firstly we must have a monotonicity argument on which to base our proof of termination, secondly we must find an invariant relation which, initially true and not being destroyed, will still hold upon termination. For the monotonicity argument we suggest (fairly obviously)

      during marking each node will darken monotonically.

For the invariant relation —a relation which must be satisfied both before and after the marking cycle— we must generalize initial and final state of the marking process and our first guess was (perhaps less obvious, but not unnatural)

P1:    | during marking there will be no edge pointing from a black node to a white one.

Additional action is then required from the mutator when it is about to introduce an edge from a black node to a white one: just placing it would cause a violation of P1. The monotonicity requirement tells us, that the black source node of the new edge has to remain black, and, therefore, P1 tells us that the target node of the new edge cannot be allowed to remain white. But the mutator cannot make it just black, because that could cause a violation of P1 between that new target node and its immediate successors. For that reason grey has been introduced as intermediate colour and the overhead considered for the mutator was

A1:    | when introducing an edge, the mutator shades its target node.

Note 1. Shading a node is defined to make a white node grey and to leave the colour of a grey or a black node unchanged. (End of note 1.)

The choice of the invariant relation P1 has been sufficient for a solution —not published here— with a rather coarse grain of interleaving (in which, for instance, A1 was assumed to be available as a single, indivisible action). We could not use it, however, as a stepping stone towards a solution that allowed a finer grain of interleaving, because total absence of an edge from a black node to a white one was a stronger relation than we managed to maintain. We could, however, retain the notion “grey” as “semi-marked”, more precisely, as representing our unfulfilled marking obligation: as before, the marking activity of the collector remains localized at grey nodes and their possibly white successors.

A coarse-grained solution.

In our unpublished solution we made essential use of the fact that after the collector had initialized the marking phase by shading all roots, the validity of P1 allowed us to conclude that the existence of a white reachable node implied the existence of a grey node (even of a grey reachable node, but the reachability of such an existing grey node was not essential). A weaker relation from which the same conclusion can be drawn is

P2:   
during the marking cycle (that the collector has initialized by shading all roots) there exists for each white reachable node a so-called “propagation path”, leading to it from a (not necessarily reachable) grey node, and consisting solely of edges with white targets (and, as a consequence, without black sources).

Note 2. In the absence of edges from a black node to a white one, relation P2 is clearly satisfied. (End of note 2.)

The existence of edges from a black node to a white one is restricted by

P3:    | during the marking cycle only the last edge placed by the author may lead from a black node to a white one.

Note 3. In the absence of black nodes, P3 is trivially satisfied. (End of note 3.)

When the mutator redefines an outgoing edge of a black node, it may direct it towards a white node: this new edge from a black node to a white one is permitted by P3, but because the previously placed one could still exist and be of the same type, we consider for the mutator the following indivisible action:

A2:    | shade the target of the edge previously placed by the mutator and redirect for a reachable node one of its outgoing edges towards an already reachable node.

Note 4. For the very first time the mutator changes an edge we can assume that, for lack of a previously placed edge, the shading will be suppressed or an arbitrary reachable node will be shaded; the choice does not matter for the sequel. (End of note 4.)

Action A2 has been carefully chosen in such a way that it leaves P3 invariant; it leaves, however, the stronger relation P2 and P3 invariant as well.

Proof. The action A2 cannot introduce new reachable nodes; it, therefore, does not introduce new white ones for which extra propagation paths must exist. If the node whose successor is redefined is black, its outgoing edge that may have disappeared as a result of the change was not part of any propagation path, and the edges of the old propagation paths will be sufficient to provide the new propagation paths. (Possibly we don’t need all of them as a result of the shading and/or white reachable nodes having become unreachable.) If the node whose successor is redefined was white or grey to start with, it will become at most grey and the resulting graph has no edge from a black node to a white one —if one existed, it has been removed by the shading and the change has not introduced a new one— and (see Note 2) P2 holds upon completion. (End of proof.)

We have now reached the stage where we can describe our first collector which repeatedly performs the following program. (Our bracket pairs “if...fi” and “do...od” delineate our alternative and repetitive constructs respectively (see [1]), comments have been inserted between braces and labels have been inserted for the discussion.) The program has two local integer variables i and k; the nodes in memory are assumed to be numbered from 0 through M–1.

marking phase:
begin  | {there are no black nodes}
| C1:  | “shade all the roots” {P2 and P3};
|  | i:= 0; k:= M;
| marking cycle:
|  | do k > 0 → {P2 and P3}
|  |  | if  | C2:  | “node nr. i is grey:” →
|  |  |  |  |  | k:= M;
|  |  |  |  | C3:  | “shade the successors of node nr. i and make node nr. i black” {P2 and P3}
|  |  | ▯ | C2: | “node nr. i is not grey” →
|  |  |  |  |  | k:= k – 1 {P2 and P3}
|  |  | fi {P2 and P3};
|  |  | i:= (i + 1) mod M
|  | od  | {P2 and P3 and there are no grey nodes, hence all white nodes  are garbage}

end;
appending phase;
begin i:= 0;

|  | do i < M →  | {a node with a number < i cannot be black;  a node with a number ≥ i cannot be grey;  and is grabage, if white}
|  |  | if | C2: | “node nr. i is white” →
|  |  |  |  | C4: “append node nr. i to the first free list”
|  |  | ▯ | C2: | “node nr. i is black” →
|  |  |  |  | C5: “make node nr. i white”
|  |  | fi i:= i +1
|  | od {there are no black nodes}
end

The indivisible actions of the collector —between the execution of which actions A2 of the mutator may occur— are
1)     “shading of a single root” (from which C1 is composed: the order in which the roots are shaded is irrelevant)
2)     establishing the current colour of node nr. i (labeled “C2”).
3)     the total actions C3, C4 (see, however, the Appendix) and C5.

Remark 1. With a more elaborate administration local to the collector —a list of grey or possibly grey nodes— a probably much more efficient marking phase could have been designed. For the sake of simplicity we have not done so. (End of remark 1.)

We observe that (even independent of the colour of node nr. i !) action C3: “shade the successors of node nr. i and make node nr. i black” can never cause a violation of P2 and P3: the shading of the successors can never do any harm, as a result of the shading the outgoing edges of node nr. i are no longer needed for a propagation path, and making node nr. i black maintains the existence of the propagation paths needed without introducing an edge from a black node to a white one.

The state characterized by the absence of grey nodes, which implies on account of P2 that all white ones are garbage and that all reached ones are black, is stable, because the absence of white reachable nodes prevents the mutator from introducing grey nodes, and the absence of grey nodes prevents the collector from doing so. Because, when a grey node is encountered, k is reset to M, the marking cycle can only terminate with a scan past all nodes, during which no grey node is encountered. Because the mutator leaves grey nodes grey, no grey node can have existed at the beginning of such a scan, i.e. the stable state must have been reached at that moment. Termination of the marking cycle is guaranteed because of the fact that resetting k to M is always accompanied by effective darkening of at least one node (nr. i to be precise).

When the appending phase starts, all reachable nodes are black and all white nodes are garbage. Note that the existence of black garbage is not excluded. The appending phase deals with each node in turn: as long as it has not been dealt with (i.e. has a number ≥ i) it cannot change colour: if black, it remains black because the mutator can only shade it, and if it is white, it is garbage and, by definition, the mutator won’t touch it. As soon as it has been dealt with (i.e. has a number < i), it has been white and can at most have been shaded by the mutator. Black garbage at the beginning of the appending phase will not be appended during that appending phase, it will only be made white; during the next marking phase it will remain white, and the next appending phase will indeed append it. Therefore, no garbage, once created, will escape being collected.

A solution with a fine-grained collector.

We would like to break C3 open as a succession of five indivisible subactions, say (m1 and m2 being local variables of the collector):

C3.1:   m1:= number of the left-hand successor of node nr. i;
C3.2:   shade node nr. m1;
C3.3:   m2:= number of the right-hand successor of node nr. i;
C3.4:   shade node nr. m2;
C3.5:   make node nr. i black

None of the actions C3.1, C3.2, C3.3, and C3.4 can cause violation of P2 and P3. The actions C3.1 and C3.3 cannot do so because they leave no trace in common memory, and the actions C3.2 and C3.4 cannot do so because shading cannot do so. Besides that, because shading of a node commutes with any number of actions A2, we have, by the time that the collector starts with C3.5, a state as if the shading of node nr. m1 had been part of C3.1 and the shading of node nr. m2 had occurred simultaneously with C3.3. Without loss of generality we can continue our discussion as if “shade left-hand successor” and “shade right-hand successor” are available as indivisible actions. The problem, however, lies with C3.5: can we safely make node nr. i black? Note that neither m1, nor m2 needs still to be one of its successors: m1 and m2 even never need to have been its left- and right-hand successor simultaneously! A more thorough study of the mutator, however, reveals that it is safe.

Proof. During the marking phase we define a changing set of edges to which we give —in order to avoid false connotations— the rather meaningless name “dodo-edges”. (Note that we only define the set of dodo-edges for our benefit. The mutator and collector would have a hard time if they had to update it explicitly: in the jargon the term “ghost variable” is sometimes used for such an entity.) The set of dodo-edges is defined as follows as a function of the evolving computations:
1)     at the beginning of the marking phase the set of dodo-edges is initialized with all the edges with a grey target
2)     each time a white node becomes grey, all its incoming edges (that were not already a dodo-edge) are added to the set of dodo-edges
3)     when the action A2, seen as a replacement of an outgoing edge, removes a dodo-edge —or an edge that, according to the second rule, would have become one as a consequence of A2’s shading act— the new edge that replaces it is also a dodo-edge: it “inherits the dodo-ness” of the edge it replaces.

The above rules imply a dodo-edge is never needed for a propagation path. The last one all by itself implies that once the left-hand outgoing edge of a node is a dodo-edge, it will remain so, no matter how often redirected by the mutator, until the end of the marking phase, and that the same holds for the right-hand outgoing edge. In short: when, since the beginning of the marking phase, a given node has had a grey left-hand successor and has had a grey right-hand successor, it has two outgoing dodo-edges and making it black will never cause violation of P2. It won’t violate P3 either: if it has a white successor, the corresponding edge must have been the last one placed by the mutator (it can therefore have at most one white successor) and that edge from a black node to a white one is the one explicitly allowed by P3. (End of proof.)

The above argument sheds another light upon the action C3. Instead of waiting until it has seen both successors of a node to be non-white, it forces termination of that waiting process by shading its successors itself. It refrains from shading the successors of a white node, as that would defeat garbage detection, it also refrains from shading the successors of a black node (although such a black node could have a white successors) because that is unnecessary. It is in this sense that the grey nodes represent our unfulfilled marking obligation.

Note 5. In breaking up C3 we have placed C3.5 “make node nr. i black” at the end. As making a node black commutes with all other actions A2 and C3.1 through C3.4, we could also have placed it at the beginning, before dealing (in some order) with the successors; P2 and P3 could then be violated temporarily. (End of note 5.)

A solution with a fine-grained mutator as well.

From the above it is obvious that no harm is done if at random moments a daemon would shade a reachable node. we now assume a very friendly daemon that between any two successive actions A2 of the mutator shades the target node of the last placed edge. For the initial state of an action A2 during a marking cycle, we can now assert (besides P2 and P3) the absence of an edge from a black node to a white node, regardless of the question whether the last shading by the friendly daemon took place during the current marking phase, or earlier. As a result, the proof that A2 leaves P2 and P3 invariant is now also valid if A2 does not shade at all! Thanks to the daemon, it does not need to do so anymore! We can therefore replace A2 by the succession of the following two separate indivisible subactions:

“redirect for a reachable node an outgoing edge towards a reachable node”;
“shade the target of the edge just placed”.

Remark 2. The detailed implementation of what we have described as “a grain of interleaving” falls very definitely outside the scope of this paper: many techniques —even allowing concurrent access to the same unit of information— are possible (see [3], [4]). (End of remark 2.)

In retrospect.

It has been surprisingly hard to find the published solution and justification. It was only too easy to design what looked —sometimes even for weeks and to many people— like a perfectly valid solution, until the effort to prove it to be correct revealed a (sometimes deep) bug. Work has been done on formal correctness proofs ([5], [6]), but a shape that would make them fit for print has, to our tastes, not yet been reached. Hence our informal justification (which we do not regard as an adequate substitute for a formal correctness proof!). Whether its stepwise approach —which this time seems to have been successful in reducing the case analyses— is more generally applicable, is at the moment of writing still an open question.

When it is objected that we still needed rather subtle arguments, we can only agree whole-heartedly: all of us would have preferred a simpler argument! Perhaps we should conclude that constructions that give rise to such tricky problems are not to be recommended. Our firm conclusion, however, can be drawn: to believe that such solutions can be found without a very careful justification is optimism on the verge of foolishness.

History and acknowledgements. (As in this combination this is our first exercise in international and inter-company cooperation, some internal credit should be given as well.) After careful consideration of a wider class of problems the third and the fifth authors selected and formulated this problem and did most of the preliminary investigations; the first author found a first solution during a discussion with the latter, W.H.J.Feijen and M.Rem. It was independently improved by the second author —to give the free list a root and mark its nodes as well, was this suggestion— and, on a suggestion made by Jack Mazola, by the first and the third author. The first and the fourth merged these embellishments, but introduced a bug that was found by N.Stenning and M.Woodger [7]. The final version and its justification are the result of a joint effort of the four authors in the Netherlands. The active and inspiring interest shown by David Gries is mentioned in gratitude.

References.

1. Dijkstra, Edsger W. Guarded Commands, Nondeterminacy and Formal Derivation of Programs. Comm. ACM 18, 8 (Aug. 1975), 453–457.
2. Steele Jr., Guy L. Multiprocessing Compactifying Garbage Collection. Comm. ACM 18, 9 (Sep. 1975), 495–508.
3. Lamport, Leslie. On Concurrent Reading and Writing. (Submitted to Comm. ACM.)
4. Scholten, C.S. Private Communication
5. Gries, David. An Exercise in Proving Parallel Programs Correct. (Submitted to Comm. ACM.)
6. Lamport, Leslie. Report CA–7508–0111. Massachusetts Computer Associates, Inc.
7. Woodger, M. Private Communications.

Appendix.

Here we give an example of how the free list and the operations such as taking a node from or appending a node to the free list can be implemented. We consider the nodes of the free list ordered according to “edge”. For each node in the free list, the right-hand successor is NIL, the left-hand successor is NIL for the youngest node and is the next-younger one for the others. We have a root called TAKE, its left-hand successor and its right-hand successor are both the oldest free node; we have a second root called APP, whose left-hand and right-hand successors are both the youngest free node.

Taking a free node —and making it the left-hand successor of some reachable node X, say— can be done in the following steps (shown in a hopefully self-explanatory notation):

X.left:= TAKE.left
TAKE.left:= TAKE.right.left;                
TAKE.right.left:= NIL;
TAKE.right:= TAKE.left
(All four actions should follow
the shading convention chosen.)

To append, say, node Y —in action C4— could be done by:

Y.left:= NIL; Y.right:= NIL;
APP.left:= Y;
APP.right.left:= Y;
APP.right:= APP.left

When a minimum of two free nodes is maintained, the collector that appends is certain to deal with nodes that are left alone by the mutator, and the action C4 need not be regarded as a single, indivisible action, but is trivially allowed to be broken up in the above subactions. The synchronization guaranteeing the lower bound for the length of the free list is here supposed to be implemented by other, independent means.

20th of October 1975 

transcribed by Corrado Cantelmi
revised 15-Mar-2012

12 oktober 1975 EWD 521

Vijfde toespraak, najaar 1975.

Op het gevaar af de indruk te wekken een bepaald thema aan mijn toespraken ten grondslag te leggen, moet ik nog ten minste eenmaal terugkomen op het mechanisch mensbeeld. Ik moet dit, omdat de onvermijdelijke pendant, nl. het menselijk machinebeeld, in mijn vak zo'n ravage heeft aangericht.

Ik doel dit keer niet alleen op de anthropomorfe terminologie, waarvan mijn vak vergeven is, zoals "memory", "programming language", "handshaking", "conversational programming" en "man/machine dialogue", enz. In een Amerikaanse voordracht hoorde ik eens: "When this guy wants to talk to that guy...": de spreker bleek te refereren naar twee componenten van een computer netwerk! Onthoudt U van mij: het gebruik van anthropomorfe terminologie ter beschrijving van wat zich in automatische rekenmachines afspeelt is een onmiskenbaar symptoom van professionele onrijpheid. Zolang we dat onthouden, is dit aspect van het menselijk machinebeeld ongevaarlijk en laten we ons niet meer belazeren door termen als "an intelligent terminal" en dergelijke.

Ik doel dit keer op de rol, die de machine wordt toegedacht. Ten eerste hebben we de fictie, dat we behalve werkzaamheden, ook "verantwoordelijkheid" aan een machine delegeren kunnen. Die fictie doet opgeld, hoewel het iedereen duidelijk moet zijn, dat we een machine niet ter verantwoording kunnen roepen. Moeten we hem in geval van wangedrag straffen, door hem een dag geen electriciteit te geven? En toch wordt de verantwoordelijkheid gedelegeerd, althans afgeschoven: wie klachten heeft over de uitkomsten van de mechanische administratie van een bank, een verzekering, de telefoondienst of de belastingdienst, krijgt nooit de schuldige te spreken, want "de computer heeft het gedaan". Dit, zo de fout al toegegeven wordt, want als we de zaak mechaniseren kunnen er toch geen fouten meer optreden? Zelfs als ten gevolge van zogenaamde "volledige computer-beveiliging" er twee treinen op elkaar rijden, heeft geen mens dat meer op zijn geweten. Dit is angstaanjagend, want een dezer jaren zal een computer uitrekenen, dat overmorgen het gunstigste moment is om een atoomoorlog te beginnen. Evenmin als de verantwoordelijkheid te beslissen, kan de verantwoordelijkheid te begrijpen gedelegeerd worden. Helaas wordt ook dit op grote schaal vergeten.

Een van de eerste projecten, die onder de suspecte bannier van "Artificial Intelligence" werd opgezet, was het mechanisch bewijzen van stellingen. Potentieel zit daar iets in: het bestuderen van een mechanisch gevonden bewijs zou in principe best nieuwe inzichten kunnen geven. Toen het vinden van nontriviale bewijzen niet lukte, verschoof men de bakens: laat een machine dan wat wij denken dat een bewijs is, op correctheid controleren. Alsof het bewijs van een stelling het certificaat van correctheid van die stelling zou zijn! Een bewijs van een stelling is de neerslag van ons begrip van de stelling, en als het bewijs zo bewerkelijk is dat het ons zonder mechanische verificatie niet overtuigt, hebben we gewoon de stelling niet begrepen.

Het ergste uitvloeisel van dit onbegrip zijn echter de zg. "natural language programming systems". Dit soort projecten keert terug met de regelmaat van griepepidemieen. De gebruiker hoeft niet meer te kunnen programmeren, hij zegt gewoon in het Engels, wat zijn probleem is; in geval van onduidelijkheid stelt de machine nog wat vragen, totdat de machine de bedoeling begrepen heeft en doet wat van hem verwacht wordt! Dat jaarlijks aan deze onzin millioenen verstookt wordt, is tot daar aan toe. Veel erger is, dat deze projecten nieuw voedsel geven aan de politieke leugen, dat expertise van mensen misbaar zou zijn.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

12 oktober 1975 EWD 522

Zesde toespraak, najaar 1975.

Eens is het socialisme een nobele beweging geweest, gedreven door een oprecht begaan zijn met de bittere armoede, waarin vele leefden en stierven. Maar de strijd tegen de armoede is ontaard in een strijd tegen de rijkdom; men nivilleert inkomens als een bezetene, spreekt over afromen van overwinsten terwijl het bedrijfsleven zich nauwelijks in stand kan houden, de overheid slacht schaamteloos de kip, die de gouden eieren zou moeten leggen en de Partij van de Arbeid zal als de Partij van de Werkloosheid de historie ingaan.

Maar de strijd —"onze strijd" zoals onze Joop zou zeggen!— moet op alle fronten gestreden worden: van het materiele vlak moet hij naar het culturele verlegd worden. Ook dit heeft nobele wortels in een ver verleden: het begon als een strijd tegen de culturele verkommering, waarin velen leefden en stierven. Maar ook deze strijd is al jaren geleden ontaard in de bestrijding van culturele rijkdom en intellectuele elite: het is al meer dan veertig jaar geleden, dat H.G.Wells voorspelde, dat de nieuwe klassestrijd de bestrijding der capabelen zou zijn!

Het is stil rond de Stichting "Nederland Muziek", die zich enkele jaren geleden onder aanvoering van Rudy Kousbroek en Theo Olof beijverde voor een vierde radiozender met constant goede muziek zonder gezever, een initiatief, dat zoveel adhesie oogste, dat zelfs minister van Doorn —en dat zegt wat!— het niet negeren kon. Gehoord de hoge kwaliteit en enorme varieteit van wat op de internationale gramofoonplatenmarkt geboden wordt, is de realisatie van een dergelijke pure muziekzender uit technisch oogpunt een trivialiteit.

Maar toen kreeg je de moeilijkheden. Eerst moest het dan maar op de middengolf, die gelijk een ieder weet, het aanhoren niet waard is. Dit was duidelijk te absurd; nu mag de vierde zender dan op de FM-golven, maar, als ik wel ben ingelicht, slechts overdag tot 's middags vijf uur. Tegen de tijd, dat de mensen van hun werk thuiskomen en van muziek zouden kunnen willen gaan genieten, moet het afgelopen zijn! En je moet vooral niet denken, dat als de vierde zender overdag dan wel in de lucht is, dat je dan op redelijke muziek kunt rekenen, oh nee, want met muziek alleen kunnen de omroepverenigingen hun specifieke gezicht niet tonen! Dus toch weer, dat expliciet niet de bedoeling was: gezever..... Het is stil rond de Stichting "Nederland Muziek", ik denk, dat zij zich kotsend van het gekonkel heeft afgewend.

De vierde zender is bestreden met de argumentatie, dat hij alleen zou appelleren aan een reeds muzikaal ontwikkelde minderheid, die hierdoor zich muzikaal nog verder zou ontwikkelen, daarmee de verfoelijke elitevorming in de hand werkend. Walgelijk als het argument is, het was waarschijnlijk het meest oprechte. Onthullend is in elk geval de drogreden, waarmee de omroepverenigingen de muziekzender 's avonds uit de ether gehouden hebben: hij zou hun eigen programma's teveel concurrentie aandoen, en een beroep op de heilige koe "luisterdichtheid" was voldoende om aan te tonen, dat zulks ontoelaatbaar was. Als leek in de omroepwereld zou je kunnen opmerken, dat als van een betrouwbare muziekzender zo'n enorme concurrentie uitgaat, zij hun eigen luistedichtheid zouden kunnen vergroten, door goede muziek uit te zenden in plaats van leuterkonten aan ethervervuiling te laten doen. Maar dan verdedigen zij de erbarmelijke kwaliteit van hun programma's met de opmerking, dat ze zich met het oog op het ledenaantal de luxe van goede programma's, die het volk zouden afstoten, niet kunnen veroorloven. Hier klopt iets in de logica niet... Het is kennelijk een misvatting te geloven, dat radioprogramma's voor de luisteraar worden uitgezonden, de luisteraar wordt slechts gebruikt. De relatie tussen Hoger Onderwijs en Studenten kon hiermee wel eens overeenkomsten vertonen.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

12 oktober 1975 EWD 523

Zevende toespraak, najaar 1975.

Ik ben vorige week geeindigd met de suggestie dat de troebele relatie tussen omroepverenigingen en luisteraars wel eens overeenkomsten kon vertonen met de blijkbaar even troebel voorgestelde relatie tussen faculteiten, resp. afdelingen en studenten. Volstaan met een niet toegelichte insinuatie is de stijl van goedkope journalistiek; ik zal dus toelichten, hoewel die toelichting mij bij hen, wie de aantijging niet lekker zit, niet populairder maken zal.

In het midden der zestiger jaren —ik was toen een aantal jaren gewoon hoogleraar— ging de overheid nadrukkelijker dan voordien aan het hoger onderwijs ter beschikking gestelde middelen relateren aan studentenaantallen. Dit was voor mij aanleiding ernstig te waarschuwen voor het hiervan te verwachten psychologische effect dat wij, onbewust hierdoor beinvloed, het hele belang van onze totale activiteiten aan studentenaantallen zouden gaan afmeten en dat ongewild in ons waardeoordeel onze educatieve activiteit —en dan nog wel een vrij platvloers aspect daarvan— het primaat zou usurperen. Aldus geschiedde. Wilt U een voorbeeld? De beide semesters strekken zich tesamen uit over ongeveer de helft van het jaar; ik herinner mij heel goed hoe in het begin van mijn hoogleraarschap de andere helft van het jaar het hoogtepunt van de cyclus was, wanneer nl. iedereen ongehinderd door studenten en niet afgeleid door de regelmatige plicht college te geven enthousiast aan zijn eigen werk bezig was. De opwindende maanden van het jaar vielen bij uitstek buiten de semesters. En hoe is het nu? Buiten de semesters en de examenperioden valt de TH in slaap, in de zomervacantie, wanneer zich destijds het wetenschappelijk leven van de onderafdeling concentreerde, is het nu zo uitgestorven, dat vorig jaar voor het eerst de wiskundelounge drie weken gesloten is geweest: een schrijnend symptoom van aftakeling!

Zodra uit het oog verloren was dat het belang van een afdeling afhangt van het niveau van haar werk en dus met toenemende studentenaantallen zakt, ging het snel bergafwaarts. Wetenschappelijk dubieuze afdelingen als bedrijfskunde en bouwkunde deden hun intrede en groeiden beangstigend. Maar ook wetenschappelijk van origine bonafide afdelingen bleven niet onaangetast. Zich ook tot groei verplicht voelend zetten ook zij de sluizen voor de algemene onderwijsverwatering open uit vrees door handhaving van het wetenschappelijk niveau hun quorum niet te halen. Ik overdrijf niet; integendeel: ik spreek uit bittere ervaring. Toen ik in mijn educatieve activiteiten het niveau wenste te handhaven en doorging op tentamina de eisen te stellen, die het vak nu eenmaal stelt, is zulks mij niet in dank afgenomen. Er werd mij voorgehouden, dat ik onvoldoende over had voor wat "het belang van de onderafdeling" genoemd werd. Voelt U de parallel met de omroepverenigingen, die ook een autonoom doel met een eigen "belang" geworden zijn?

Gelijk een omroepvereniging dingt de onderafdeling naar de gunst van het volk. In het basisonderwijs, dat zij voor de andere afdelingen verzorgt, geeft zij toe aan de pressie het bijbrengen van inzicht door het bijbrengen van kennis te vervangen: als ik goed ben ingelicht wordt het basisonderwijs in de informatica dat eens over programmeren ging, omgebogen tot een soort rijles op de computer. Het is, alsof een lezingenserie over goed taalgebruik vervangen wordt door een Schoevers-achtige tikcursus. Ook de opleiding van onze eigen wiskundige ingenieurs moet het ontgelden: alsof het om routinewerk zou gaan, wordt hij voorgesteld als een soort makelaar in wiskundige methoden, die zelf niets hoeft te bedenken. Wie in het huidige bestel probeert een afstudeerrichting gehalte te geven, krijgt als verwijt naar het hoofd geslingerd, dat hij zich "elitair tot de happy few" beperkt. Onderwijs en omroep delen kennelijk hun grootste zorg: "Is ons programma wel lullig genoeg?".

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

   EWD 524

13th of October 1975

Review of "On the Feasibility of Software Certification."

(Final Report, prepared by R.E.Keirstead for the National Science Foundation. SRI Project 2385, Stanford Research Institute, Menlo Park, California 94025, U.S.A.)

      The report itself has seven chapters (29 pages) and is followed by three appendices (39, 14, and 47 pages respectively). It is well written —motherhood statements are recommendably scarce!— and is quite illuminating, as a picture of both the present state of the art and the American political/industrial scene. (It is this mixture that makes the report somewhat unbalanced: while the technical problems of software certification are certainly international, the discussion how a certification institute should gets its revenue is more parochial.

      For the local political scene it contains a warning that should be repeated in this review: "Currently, there is some concern that formal or legal requirements for certified software may be imposed before means for certification are available. Such requirements, without the technical means to accomplish certification, can only lead to disillusionment with certification, to the detriment of the entire software industry." Amen.

      In stating our current inability to certify software the report is healthily explicit. Its analysis of the causes of this inability is, however, too superficial to justify fully its specific recommendations. The last appendix mentions the as yet unsurmountable difficulty in verifying sizeable programs "written in conventional programming languages with rich sets of primitives". After such a remark, one must make up one's mind: is there any hope that realistic verification techniques will become available that can cope successfully with such "rich sets of primitives"? The remainder of the report —and I am far from amazed— gives very little support for that hope. Having identified conventional programming languages as one of the the real culprits precluding verification, one could propose to exclude from the certification activity such programs that, on account of the way in which they have been written down, must be classified as "unverifiable", a suggestion that could do some much-needed harm to the popularity of those programming languages. The report —its authors seem more concerned with the certification institute being politically acceptable— have not done so. In view of the political/industrial scene, this omission is not surprising. It is, nevertheless, depressing, for, as a result, much of the document deals with how to make the best of a bad job.

*                              *
*

      The report shows a misunderstanding of the proper role of high-level programming languages, which may be at the root of many of our current problems. It is shown most clearly in: "The current state of formal proof [...] requires the proof to be developed at a representational level far removed from the pattern of bits that is the executable program in a real computer environment." (I have learned to become very suspicious when the word "real" is used in the above sense!) Clearly the author sees the pattern of bits as the programmers final target, and the high-level language and its compiler as a software tool, as a means for generating that pattern of bits. But for a user, this is a very impractical interface. The semantics of his high-level programming language should be so well-defined, that he can totally disregard the compiler and the bit patterns it generates as for him irrelevant aspects of the implementation. Unless programmers learn to separate the definition of a programming language from its possible implementations, very few programs worth certifying will be written.

*                              *
*

      The hilarious suggestion: "The solution appears to be to extend the sequence that begins with machine language, procedural-oriented language, problem-oriented language. Increasingly higher levels of expressive language are needed plus far more exotic compilers to go back down the levels." is only quoted for my reader's amusement.

*                              *
*

      Finally, because "every program of consequence is probably incorrect" the principal author suggests "to consider other attributes of programs in determining certifiability". Is this courage or cowardice? Is this wisdom or folly? Will this be to the advantage or to the detriment of "the entire software industry"? I think I would prefer my readers to answer these questions for themselves, hopefully after they have read the report concerned and have an overview of the numerous and varied issues concerned.

| prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Thu, 15 Sep 2005

EWD525

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice

The following manuscript
| EWD 525 On a warning from E.A.Hauck :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 169�171 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

29th of October 1975

On a warning from E.A.Hauck.

During my visit to Mission Viejo, last April, Erv Hauck made the passing remark that he did not believe that error recovery could compensate effectively for the ill effects of a basically unreliable storage technique. lntuitively I was perfectly willing to share that belief; this note reports on my efforts to justify it and to find the arguments that would change it into my considered opinion.

In the following I consider words of a length of n stored bits; with p0, p1, p2, etc. I shall denote the probability of no error, a one-bit error, a two-bit error, etc. If bit-errors are independent events occurring for each bit with a probability p —we shall call this “Assumption A”— we have
p0 =(1 - p)n , p1 = np(1 - p)n-1 , p2 = n(n - 1)p²(1 - p)n-2 /2, etc.

for large n and small p reasonably approximated by
p0 = 1 - p1, p1 = np, p2 = p1²/2, p3 = p1³/6 etc.

System 1, without rejected configurations.

To start with we consider a code that only corrects one-bit errors. (Such codes exist, e.g. for n = 3: ”zero“= 000 and ”one“= 111; then 001, 010, and 100 will be interpreted as ”zero“, and 110, 101, and 011 will be interpreted as ”one“.) with a memory with a microsecond cycle time and p1 = 10⁻⁶ , a one-bit error will be successfully corrected once every second, and under Assumption A an undetected error will occur once every 2,000,000 sec = 23 days. This may seem OK for the optimist, but it is not, on account of the absence of rejected configurations; suppose that —as a result of a drifting powersupply, say— it gets worse and we go up to p1 = 10⁻⁵: a one bit error will be corrected every 100 msec, an undetected error occurs every 20.000 sec = 5 hours, 30 minutes; when p1 = 10⁻³, an undetected error will occur every 2 seconds! The absence of rejected configurations means that we are not warned for this deterioration and the resulting memory is something one cannot rely upon.

System 2, with rejected configurations.

We now consider a code that corrects one-bit errors, and detects two-bit errors. (Also such codes exist, e.g. for n = 4:“zero”= 0000 and “one”= 1111; any configuration with two ones and two zeroes will be rejected, such as 0110.) With the same microsecond cycle time and p1 = 10-6, we have a one-bit error successfully corrected every second, under Assumption A a detected error every 23 days, and an undetected error once every 200.000 years. That seems safe, as a slowly increasing value of p , due to some technical degradation, may be expected to give the alarm of a two-bit error long before an undetected error has occurred. But it is, alas, absolutely unsafe, because in many —and in a sense: in all— technologies, Assumption A is not justified: the storing and reading of n bits are not technically independent. We therefore consider for the sake of simplicity the other extreme —Assumption B— “with a probability p the reading of a word will deliver n random bits”.

Exploring Assumption B.

System 1 could have been improved by counting the number of corrections: under Assumption A a correction once every second would imply that the memory is not in too bad a condition (at least, if we think an error every 23 days acceptable —I don’t actually, but that is now beside the point). Under Assumption B (because a random sequence is nearly sure to be interpreted as a one-bit error) the machine will perform a one-bit correction once every second, but whenever it does so, it is an erroneous correction: de facto the memory can be expected to make a fatal error once every second.

In order to estimate how System 2 would perform under Assumption B we must estimate how large the probability is, that a random sequence will be rejected. If each two-bit error is to be detected, any two correct codes must differ in at least 4 bit positions. For n = 2m , the exact solutions are known: there are then 2n-m-1 different codes. As each code has 2m+1 acceptable representations (the n=2m representations formed by changing one bit + the original code), the number of acceptable representations is 2n-m-1(2m+1)= 2(n-1)(1+2-m) , i.e. slightly more than half of the 2n possible bit sequences. As a consequence slightly less than half of them will be rejected.

From this we must conclude that —regardless of the value of p — when we start the machine, in 50 percent of the cases an undetected memory error has occurred before a memory error is detected: I cannot regard this as attractive either! (We could live with it if p is very small, i.e. a highly reliable memory, but that was not the case we were considering!)

Assumption B —all bits random— is, of course, a severe form of malfunctioning. But we don’t get any solace from that: instead of random values for n=2m bits, we arrive at the same probability for rejection when choosing only m+1 bits randomly, and accepting the remaining n-m-1 bits as read from memory.

The moral of the story is, that Hauck’s warning is not to be ignored!

*              *
*

The reason that my attention returned to Hauck’s warning and that I tried to find its justification, was that I was (re)considering the relative merits of neutral, local redundancy —such as parity checks and their embellishments— versus tailored, global redundancy, when our aim is to reduce drastically the probability that a wrong result will be mistaken for a correct one. Local error correction is in this respect harmful as soon as errors graver than those the detection mechanism can cope with, can occur as well. As the correction mechanism for single bit errors has enlarged the collection of acceptable representations, the probability that the computation proceeds with erroneous values increases with the length of the computation. But that is another story.

Burroughs | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NL-4565 NUENEN |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD526

Comments of "Woodenman" HOL Requirements for the DoD.

(This is a sequel to EWD514 "On a language proposal for the Department of Defense", written after reading "Strawman". Many of those comments on that earlier document are still applicable to its successor "Woodenman". I here confine myself to some further comments.)

1. Repercussions on future hardware design have not been taken into account.

If the DoD accepts as a standard a common HOL, its sheer buying power will ensure that efficient implementability of the HOL will become an important design criterion for computer manufacturers. This will then happen, if the DoD so desires or not. This implies that the DoD cannot restrict its responsibility to just serving its own software needs as it now sees them: the choice will have much wider consequences of (almost certainly) long duration, affecting the whole market place. These responsibilities have not been taken into account, and this is a serious omission.

The old view of programming was that it was the purpose of our programs to instruct our machines. With the software problems --and as a result: the software costs-- skyrocketing, a new view of that relation has emerged, viz. that it is the purpose of our machines to execute our programs! The latter, more modern and more appropriate view is hardly reflected in Woodenman, in which existing hardware --with the report's insistence on efficient implementation by existing techniques-- is too much taken for granted. Unless the HOL is designed for an ideal machine --or better: machines as we would like them to be--, the whole effort may in the long run cause great harm.

2. Simplicity and ease to learn the new language.

The report contains a discussion of simplicity versus complexity that itself is so simplified as to be misleading. I mention in connection the requirement that the new language should be "easy to learn".

It is perfectly clear that any unnecessary training burden should be avoided: programmers should not learn to fight problems that should not be there in the first place. And the report is fully justified when it points out the tremendous costs induced by grotesquely baroque programming languages. Hence the cry for a simple programming language, which, in my view, is fully justified.

To conclude that, therefore, the language must be "easy to learn", however, is a rash conclusion, for cruelly stated, that "easiness" suggests the desire to continue to design software with hardly educated programmers! And then our problems will remain with us, no matter which HOL is adopted.

The training of programmers cannot be "easy", for programming is and will remain difficult. The point is that "learning the language" should, indeed" be a minimal affair, and the major attention should be given to mastering an orderly discipline how to use it.

As long as we discuss the whole problem in terms of simplicity versus complexity, we may end up with the conclusion that machine code --or perhaps even a Turing machine!-- is the most "simple" code. The major point is that machine codes, the Turing machine and the most baroque higher programming languages, suffer from the same shortcoming, viz. the absence of such an orderly discipline for their use.

When designing a programming language the existence of a sound, orderly discipline for its use --a discipline that, by necessity shall be one of a rather mathematical nature-- should be one of one's major concerns. I stress this for immensely practical reasons. The existence of such a discipline is a prerequisite for the design of high-quality programs; it is also a very effective criterion for the decision what to include and what to exclude from one's language design! When considering a "feature", [if] one cannot find a way of avoiding the puzzles and the conflicts, omit it... The resulting language will be "small" and "simple" as a consequence: there are not so many "features" with the necessary (mathematical) properties.

Besides the existing population of machines, also the existing population of programmers is taken too much for granted. When I read --page 37-- "Most programmers are not used to origin 0 and find it inconvenient or unnatural.", I conclude that "inconvenient" has --again!-- be confused with "unconventional", and that the report is too much oriented towards the past and the present and too little towards the future.

3. Are so many "specialized capabilities needed"?

On a number of places --e.g. pages 11 and 31-- the report accepts the not uncommon assumption that, because applications are varied and the language must be geared to the application, a great number of specialized features or capabilities are needed. Is this true to the extent that the report suggests? I seriously challenge this opinion because

I do not believe it myself

the report does not motivate it and takes it just for granted

historical evidence is inconclusive, as the observable variation can also be interpreted as the obvious result of the absence of the discipline referred to above.

It will not surprise the reader that I consider the discussion on pages 11 - 12 "Generality versus Specificity" as rather inconclusive; page 31 even strikes me as misleading. When I read there:

"A common language must have capability for growth. It should contain all the power necessary to satisfy all the applications and the ability to specialize that power to the particular application task. A language with defining facilities for data and operations will make it possible to add new application-oriented structures and to use new programming techniques and mechanisms using descriptions written entirely within the language."

I feel like reading a misleading advertisement that would be rejected by the professional code of our advertisers.

*                             *
*

A few further, minor points. *)

[Footnote] *) In retrospect not so minor at all! EWD [End of footnote]

4. Equivalence for real numbers.

On page 38 I read:

"The use of equivalence is not recommended for real numbers but resolution of what equivalence means for imprecise quantities is a problem of numerical analysis not language design."

This is not true, the problem should not be left to the numerical analysts, because language design requires --and dictates-- a very precise answer to that question. The point has been settled fifteen years ago.

When I implemented ALGOL 60, I thought that --because exact equality of floating point numbers seemed too much to ask for-- I would provide a service by delivering the value true for the boolean expression a = b, when a and b were floating point values only differing in the least significant bit of the mantissa. This was one of the gravest mistakes I ever made, because it proved to be an absolute disaster, and I had to remedy the situation very quickly. The point is that such a loose equality is too weak a criterion to be of any use; for instance, the loose equality is no longer transitive. One could find a = b, b = c and a ≠ c all being true at the same time! Under those shaky circumstances it is very hard, if not impossible, to prove the correctness of a program manipulating real variables. If at that time, proving programming correctness had been the normal practice, I would never have made the blunder in the first place.

I mention this point for two reasons: firstly it settles a point that the report has erroneously left open, secondly it illustrates my point, made above, that the requirement of an orderly discipline indeed settles design questions.

5. The range.

I read on page 43:

"The source language should require its users to individually specify the range of values for integer and floating point variables [...] Range [...] specifications should not be interpreted as defining new types."

The latter addition seems in contradiction with page 35 "By the type of a data object is meant the set of objects themselves, the essential properties of those objects and the set of operations which give access to and take advantage of those properties.

There seems to be a confusion, it is not clear what the implications are when the integer variable x has the range declared to be from 0 through 15. There are at least two possibilities:

any implementation has to check that the values of the intermediate variable x always lies within that range from 0 through 15.

no implementation needs to allocate more than 4 bits to the variable x; any implementation has the right, but never the obligation, to signal an alarm when x is found to lie outside the range from 0 through 15, it has only the duty to signal an alarm when it has used the assumption that x would have such a value (by, for instance, only allocating 4 bits to it).

In interpretation (b) any implementation, therefore, may ignore the range specification, and may take it into account if it can do so at good advantage. In interpretation (a), each implementation has to take it into account; as this implies in general a run-time check, interpretation (a) is in conflict with some of the efficiency requirements. Interpretation (a) has the further dramatic disadvantage that "static type checking" is no longer possible. I call this "dramatic", because it introduces an intertwining of the semantics of the programming language --describing the net effect to be effectuated by the programs written in it-- and their implementations --i.e. possible computational histories that could achieve that effect--.

I have learned to appreciate axiomatic, non-operational definitions of programming language semantics, in which the program text defines the net effect to be established independent of the computational histories that may be invoked under control of the programs. In such an approach the program does not prescribe what has to happen during the execution, it only prescribes the answers; what happens during the execution of a program is only defined by the combination of program and implementation. But the implementation is not defined by the definition of the programming language, only constrained by the requirement that always the correct answer will be produced. I have found such a separation of concerns between what should be achieved and how it is to be achieved, absolutely essential. Interpretation (a) which refers to the computational history, would deny me that separation of concerns; it is for that reason --and not on account of the cost of run-time checks-- that I regard adoption of interpretation (a) as a disaster. The suggestion --page 80-- that formal definition of the semantics could be done via either the Vienna Definition Language or (a la LISP) by an interpreter --which are both operational definitions-- is one of which I cannot approve.

*                             *
*

To Dr. John B. Goodenough's list of typographical errors I can add:

Page
Line
As Is
Should Be

78
7
inovation
innovation

3rd November 1975
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edgser W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Wed, 26 May 2004

EWD527

On units of consistency.

(This is a replacement of EWD490 "Detection of malfetching of instructions", which never got completed.)

I am getting more and more worried about reliability. My natural pessimism got new food when I was told that the chips of pocket calculators are, in general, totally unchecked: the manufacturers don't know how to do it, and the rule is, therefore, that, if the customer complains, he gets a new one. Isn't that a simple solution.....

With regard to the reliability issue with large computers, we can try similar, but on closer inspection quite different things:
a)     reduce the probability of an undetected machine malfunctioning
b)     increase the probability that a correct result will be produced
c)     decrease the probability that a wrong result will be produced as if it were a correct one.

Techniques primarily directed towards target (a) are parity checks and redundant execution of arithmetic operations. They are very popular, and their popularity is well-deserved. They are neutral —i.e. generally applicable— built-in checks of great diagnostic value as far as hardware maintenance is concerned. They only serve the next two targets under the additional assumption that detected errors have a much greater probability of occurrence than undetected ones, an assumption which, alas, is often unjustified.

Techniques primarily directed towards target (b) combine —an effort at— error detection with —an effort at— error correction, under the motto "The show must go on." It may be a very local error correction, it may be a much more global recovery procedure. I have limited experience with such techniques, and, besides that, I have my doubts, because to the possibility of undetected errors the possibility of erroneously corrected errors has been added.

Target (c) is the most modest one: we sincerely hope, that the machine performs so well that the correct result will be produced and would be happy if each harmful machine malfunctioning would lead to abortion before the wrong result has been produced. The latter goal was the one discussed in EWD482. We now return to it in a more restricted environment, viz. the problem of the fetching of instructions.

In order to simplify my discussion I shall assume that programs are represented with one instruction per word, and that each word is stored with a parity bit. (The following is also valid under the assumption of a more redundant word-wise redundancy.) The question is: how certain are we, that the correct instructions are executed, i.e. that the correct bit-patterns appear in the instruction register? There seem to be roughly three things that can go wrong:
a)     while reading the instruction a multiple-bit error has occurred that has not been caught by the parity check
b)     the instruction that reached the instruction register is the result of the perfect reading of the wrong word
c)     the correct word has been read correctly, but the bit pattern has been corrupted somewhere on its way from the last checking station to the instruction register.

Error (b) can be caused in two different ways:
b1)     the program is correctly stored, but the wrong word has been read because something happened in the instruction counter or in the way from instruction counter to memory selection register
b2)     one of the instructions of the stored program has erroneously been overwritten (with a perfect parity of course!).

At least one system has been designed in which the instructions of a program are stored with a sum-check included, and, regularly, the machine interrupts its normal activities and inserts a sum-checking interlude in order to increase the confidence that all programs are still correctly stored. This approach, however, has a considerable number of unattractive consequences.
1)     because the sum-checking interludes have to be inserted at the expense of the machine's productivity, we have to settle the conflict, how frequently these interludes should be inserted
2)     in a paging machine, we have to perform the sum-check before a program page (of which I assume that it is not dumped) is overwritten by another page
3)     it only catches error (b2), and if errors (a), (b1) and (c) can occur as well —and why shouldn't they?— it is not very effective in view of our target (c). (In all fairness I should mention that the system in which this technique was applied had been designed for message switching, and in that area the usual attitude is that anything may go wrong, provided that the system comes in the air again. Whether this is a realistic and defensible attitude, is a question beyond the scope of this note.)

The only way to catch errors (a), (b) and (c), all at the same time, is to perform the sum-check —or the embellishment of a cyclic redundancy check as is done with words from a tape— on the successive contents of the instruction register, more precisely: each time after the instruction has been executed. (For the sake of simplicity I assume that during instruction execution the contents of the instruction register remains unchanged, knowing full well that there are machines for which this assumption does not hold: in that case the following can probably be made applicable by extracting for checking purposes the contents of the instruction register just before it is going to be modified. In the sequel we shall ignore the complication.)

The considerations in the previous paragraph tie the checking to the sequencing of the control; to do justice to this we introduce the notion of "a chunk":

a chunk occupies a number of consecutively stored instructions, of which the first is always the only so-called "redundancy dummy" in the chunk, and the last one is the only jump-instruction in the chunk; each execution of the redundancy dummy of a chunk leads some time later to the execution of the terminal jump-instruction of that chunk —because no jump-instructions occur in the interior of a chunk; each execution of a terminal jump-instruction of a chunk has been preceded by a corresponding execution of the redundancy dummy at the beginning of that chunk, because no jump-instruction is expected to transfer control to anything else but a redundancy dummy of a chunk. Note. When for a conditional jump-instruction the condition is not satisfied and the jump-instruction acts like a skip, it is regarded "to transfer control" to the next instruction in store. (End of note.)

Behind the instruction register an extra register of the length of a word is introduced, the so-called Instruction Redundancy Register "IRR". Each instruction, as it has arrived and has been executed in the instruction register is added —without carry propagation, I presume, i.e. bit-wise modulo 2— to the IRR, after IRR has been "rotated" over one place to the left; I have put "rotated" between quotes: a pure rotation means that the digit pushed out at the left is added at the least significant position at the right-hand side of IRR, but in a general "rotation" that addition may take place at a number of other bit-positions as well. The processing of a jump-instruction —which is always a terminal jump-instruction— has two additional effects:
1)     after the jump-instruction has been processed (its addition to the "rotated" IRR included) the contents of the IRR is required to be all zeros; with only target (c) in mind, the machine could stop immediately.
2)     the next word selected under control of the instruction counter and brought to the instruction register is by definition a redundancy dummy and, independent of its bit-pattern, its execution is further semantically equivalent to a skip.

The additional storage space occupied by each chunk is the redundancy dummy at its begin; because the interpretation of the redundancy dummy is independent of its bit pattern, the redundancy dummy can always be determined such that, when the chunk was entered with IRR = 0 , it will be left with IRR = 0. This is the reason why IRR has been chosen with the length of one word = the length of one instruction: it may not have more bits than the redundancy dummy, which was supposed to occupy one word.

Remark. Not rotating IRR would make the check insensitive to the interchange of any two instructions; pure rotation would make it insensitive to the interchange of two instructions for which the addresses of the locations occupied by them have a difference equal to the word-length. "Rotation" can rule that out. (End of remark.)

*         *         *

Since the above was written I have been reading in Algebraic Coding Theory by Elwyn R.Berlekamp (McGraw-Hill Book Company, New York, 1968), in particular chapter 4 "The Structure of Finite fields"; for our purpose the most important mathematical result is the following. As operation on IRR we consider the following "rotating" step:

the contents of IRR are shifted over one place to the left and the bit shifted out is added (modulo 2) at a well-chosen number of bit positions in IRR (among which the right-most one). For any wordlength n  the positions where the bit shifted out is added can be chosen in such a way that the step induces a cyclic order of the 2n-1 IRR-contents ≠ 0, in the sense that the step transforms each value into the next. Starting with a value ≠ 0, we have to repeat the step 2n-1 times, before the starting value reappears. The value 0 is obviously transformed by the step into itself.

The above made me understand why I was so much attracted by the "rotating" step as described above: it gives a great protection if there is a relatively large probability that while reading and executing a chunk two instructions will be corrupted in the same bit positions —with a parallel data path transporting the instructions from memory to instruction register, this is indeed a form of malfunctioning that should be considered— . If we don't shift at all, two such equal corruptions will always cancel; in the case of a pure rotation, such a corruption has returned to its original position in IRR after every  n  steps, and, therefore, two identical misreadings will cancel if they occur in the same chunk  n  (or 2n or 3n, etc.) words apart. With the proper choice of a "rotating" step we can ensure that this distance should be  2n-1 .

With  n = 30, we have the probability  2⁻³⁰ = 10⁻⁹  that the erroneous reading of a chunk will not be caught. If, for instance, half of the instructions of one chunk have been executed and the instruction counter contents is disturbed, and program execution is continued somewhere in another chunk, the probability that this error would escape the zero-check at the end of the second chunk is 10⁻⁹.

Note. Under the (unrealistic) assumption that "skipping" an instruction —i.e. increasing the instruction counter by 2 instead of by 1— is the only malfunctioning to guard against, our "rotating" step has a curious consequence. For each value of IRR there exists exactly one next instruction whose execution would not change the value of IRR. If that were the next instruction, skipping it would not be detected! And, if all our 10⁹ instructions are equally probable, there would be a probability of 10⁻⁹ that skipping an instruction would remain undetected. There is, however, a remedy against that. Let at a given place  Q  be the instruction whose skipping would not be detected. If  Q  is the skip-instruction, we don't need to continue our text with it, but we may (skipping the skip-instruction is a harmless error that we don't need to detect); if, however,  Q  is not the skip-instruction and it so happens that it is the next instruction with which we would like to continue our code, we can insert a skip-instruction. The execution of that skip-instruction would then change the contents of IRR and at the next place it is safe to place the instruction  Q . The moral of this story is that either we accept the probability of 10⁻⁹ that the skipping of an instruction will escape our check, or once every 10⁹ instructions our compiler would have to insert a skip-instruction! As for other reasons we have to be content with the probability of 10⁻⁹ for an undetected error, I would not burden a compiler with that obligation of inserting a skip; I only mention the result, because it is a remarkable one: I have never seen this form of trade off between reliability and storage space before. (End of note.)

*         *         *

The idea of this form of added protection to the reading of instructions emerged a year ago (December 1974, Tripreport EWD466:"on the way back I thought [...] on redundant object code representations. (To think again thoughts with a possibly direct bearing on machine design is great fun!) By the time I crossed the German/Dutch border I had arrived to a few firm conclusions. [...] I am not sure when I shall find the time to work this out and write a readable report about it."). Now it is eleven months later; the fact that the above was not written down earlier was, however, not the result of a lack of time, but was caused by the fact that I got stuck. As the design stands, there is one sequencing error that is not caught. At the end of the execution of a chunk it is checked whether IRR equals zero. (If the IRR-contents differ from zero but the check fails to discover it, the non-zero contents of IRR are "rotated" before the next redundancy dummy is added to it, so we have at the completion of the next chunk a second chance of detecting that IRR differs from all zeroes.) If, however, program execution now proceeds with the wrong chunk, it will not be detected! I tried all sorts of embellishments, but none of them was convincing. This report is written now, because I think that now I understand, why I failed.

The word is the minimum unit of consistency, and is, as such, protected by the parity check. Even if this check is effective —many parity bits per word, say— , so effective in fact that the risk of undetected corruption internal to a word can be tolerated, error (b) of page 1: the perfect reading of the wrong word remains an unchecked risk.

For that reason a next larger unit of consistency is introduced, viz. the chunk. The linear execution of all the individual instructions of a chunk and the check upon IRR = 0 is the perfect analogy of the parity bit! (Compare it with the parity bit for a serial store, delivering the bits of a word one after the other.) I now tend to consider it as the main function of the chunk with its redundancy to guard against error (b); the fact that it also picks up most of the "left-overs" of the parity check is a nice accidental feature —on account of which we may tell ourselves that a single parity bit per word will suffice—, but it is not the essential one: it does as a matter of fact, blur the picture. (With many parity bits per instruction, we could have sent them all to the instruction register and have performed the parity check form there, after instruction execution.)

But now, IRR and the redundancy dummy per chunk appear as a completely independent check, that is active each time a whole chunk is executed. But just as this mechanism is independent of the parity bits —i.e. the internal protection of the next smaller unit of redundancy— in the same way a mechanism checking that we don't have the perfect execution of the wrong chunks should be designed independent of the internal protection of the chunks themselves. There are a number of reasons in favour of this separation.
1)     with a probability of 10⁻⁹ of a left-over —i.e. an undetected error of the internal chunk consistency— I think that we can afford to forget about the left-overs
2)     IRR and the redundancy dummy are neutral in the sense that they can be built into any machine that has an instruction counter a jump instruction; I have considered additional techniques for checking the admissibility of the dynamic successor relation between chunks, but they turned out to assume some sequency discipline, at least more disciplined than wild goto's. Perhaps I find a solution without such assumptions; in any way it makes clear that checking the sequencing from chunk to chunk is a separate issue.

10th November 1975 Plataanstraat 5 NUENEN - 4565, the Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Chrys Alexander Panayiotou
revised 16-Aug-2013

EWD528

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
|  | EWD 528 More on Hauck�s warning :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages172�173 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

More on Hauck’s warning.

In EWD525 “On a warning from E.A.Hauck” I mentioned without proof that with n=2m bit there exist 2n-m-1 different messages —I called them “codes”, but that is an unusual terminology for which I apologize— , such that any two different messages differ in at least four bit positions, thus allowing correction of one-bit errors and detection of two-bit errors. Since then I have been shown a proof of that theorem; I report that proof because it is so nice, and because it gives some further insights.

For the sake of brevity I shall demonstrate the theorem for 16:24 bits (in a way which is readily generalized for other values of m ). We consider 16 bits numbered from 0 through 15 , writing their index in binary:

| d₀₀₀₀, d₀₀₀₁, d₀₀₁₀, d₀₀₁₁, ..., d₁₁₁₁

With “xxx1” we denote the set of odd indices, with “xx1x” the set {0010, 0011, 0110, 0111, 1010, 1011, 1110, 1111}, in general the set obtained by all possible substitutions of a 0 or a 1 at a place marked “x”, and define
h0 = parity(dxxx1 ) , h1 = parity(dxx1x ) , h2 = parity(dx1xx ) , h3 = parity(d1xxx )
where the function “parity” is = 0 if among the (8) bits with an index from the indicated set, the number of 1’s is even, and = 1 if it is odd. Further we introduce h = parity(dxxxx) , which is just the sum of all the 16 bits modulo 2.

The 2¹¹ correct messages are then characterized by the equations

| h0 = h1 = h2 = h3 = h = 0 .

Note. The above equations have indeed 2¹¹ different solutions: the 11 bits d₃, d₅, d₆, d₇, d₉, d₁₀, d₁₁, d₁₂, d₁₃, d₁₄, and d₁₅ can be chosen freely, we then solve h0 for d₁, h1 for d₂, h2 for d₄, and h3 for d₈, and finally h for d₀ .

We now denote by “a” the binary number formed by “h3 h2 h1 h0” and observe:
0)     for each correct message we have
          h = 0, a = 0
1)     for a one-bit error at bit position i we have
          h = 1, a = 1
2)     for a two-bit error at bit positions i and j
          h = 0, a = the bit-wise sum of i and j
(because i ≠ j , we conclude that a ≠ 0, thereby distinguishing this case from a correct message)
3)     for a three-bit error at positions i , j , and k
          h = 1, a = the bit-wise sum of i , j , and k.
4)     for a four-bit error at positions i , j , k , and l
          h = 0, a = the bit-wise sum of i , j , k , and l .

|  | etc.

Under the assumption that one- and two-bit errors are the only errors that can occur, the rules are

h = 0 and a = 0: | accept the bit sequence
h = 1 : | invert bit da
h = 0 and a ≠ 0: | alarm, as two-bit error has been detected.

From the above, however, we see that all errors in 3, 5, 7, ... bits will then erroneously be interpreted as one-bit errors, i.e. in those cases our error correction indeed increases the probability of a wrong result being produced as if it were a correct one. The above gives a clear demonstration of the possible “harmfulness” of error correction alluded to in EWD525’s last paragraph. Hence this note.

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
4565 - NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-27 .

8 november 1975 EWD 529

Achtste toespraak, najaar 1975.

Met de regelmaat der seizoenen worden op de TH de hallen, de gangen en de loopbruggen versperd en ontsierd door schreeuwerige, laat ik maat zeggen: tentoonstellingen. Als ik er langs lopend per ongeluk niet tijdig mijn gezicht afwend, welt bij mij als bij Heer Bommel de gedachte op: "Gelukkig, dat mijn goede vader dit niet meer heeft hoeven meemaken." Ook ik heb nl. een goede vader gehad, van wie ik me nog de verontwaardiging herinner, toen zijn eigen NRC voor de pressie tot grotere oppervlakkigheid zwichtte en overging tot het afdrukken van krantenfoto's: mijn goede vader kocht de krant om te lezen en niet om plaatjes te kijken. Dat de redactie ook wel besefte, dat deze beslissing niet helemaal in de haak was en de plaatjes veroordeelde tot een obscuur bestaan op de bovenste helft van de achterste pagina, was slechts een gebrekkige pleister op de wonde.

De inrichters van deze tentoonstellingen hullen zich in een bedenkelijke anonimiteit. Het is zelfs niet erg duidelijk onder wiens auspicieen deze tentoonstellingen worden ingericht. Ik ben bang, dat het ons Studium Generale is; zo ja, dan kan ik slechts hopen dat deszelfs voormannen en voorvrouwen met elkaar nog genoeg Latijn kennen, om zich te realiseren, dat de lading niet meer door de vlag gedekt wordt.

Onlangs was er een tentoonstelling over de barbarij van het Nazidom, met de bekende afschuwelijke tafrelen van razzia's, massatransporten, concentratiekampen en moordpartijen. In mijn onschuld dacht ik, op grond van de foto's, dat de tentoonstelling over de barbarij van het Nazidom ging. Toen ik de tekst ging lezen, werd ik snel uit de droom geholpen. Het was een tentoonstelling met de ongenuanceerde titel "Fascisme is Moord", en een aftreksel van het onmenselijk lijden van millioenen werd misbruikt om de bezoeker er van te doordringen, dat deze ellende het onvermijdelijk gevolg van de macht van het grootkapitaal was geweest; ter onderstreping van deze simplistische stelling werd tussen neus en lippen nog even geinsinueerd, dat na de oorlog de berechting der Nederlandse oorlogsmisdadigers uit de aard der zaak door onze rechtse politici gesaboteerd was.

God, wat eenvoudig! Dat ik, die die tijd nota bene nog zelf heb meegemaakt en alles met eigen ogen heb kunnen zien, deze simpele verklaring niet zelf bedacht heb, is inderdaad ronduit verbijsterend. Ik, die altijd gedacht had, dat Hitler's Nationaal Socialisme met de stichting van het Derde Rijk voor het Germaanse volk de heilstaat op het oog had; ik, die met eigen ogen gezien heb, hoe Hitler een verschopt lompenproletariaat toch maar weer netjes in de uniformen stak; ik, die met eigen ogen heb gezien hoe Hitler, met enorme offers aan intellect, de gewone Duitsers heeft bevrijd van de uitzuiging door het internationale Jodendom. Toegegeven, dat het bij de Jodenvervolging allemaal een beetje uit de hand is gelopen, in hun vuur voor de goede zaak zijn de SA-mannen wel eens een beetje ruwer opgetreden, dan strikt noodzakelijk was. Maar ja, waar gehakt wordt vallen spaanders, nietwaar? Ik als maar denken, dat het zo'n goede linkse dictatuur was, die voor het volk het beste op het oog had, zo'n linkse dictatuur, waarvoor de voorzitster van de PvdA nog best een goed woordje overgehad zou hebben. Hoe is het mogelijk, dit ik nooit heb ingezien, dat het juist een rechtse dictatuur is geweest! Ik begrijp nu ook plotseling, waarom het Rijksinstituut voor Oorlogsdocumentatie met sluiting bedreigd wordt voordat L.de Jong zijn geschiedsschrijving voltooid heeft: de Jong behandelt die tijd veel te genuanceerd, en dat werkt alleen maar verwarrend.

Na aldus tot Uw maatschappelijk verantwoordelijkheidsbesef te hebben bijgedragen, gaan wij over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

8 november 1975 EWD 530

Negende toespraak, najaar 1975.

Een ieder, die onze cultuur ter harte gaat, dient alert te zijn voor de vele, soms virulente anti-intellectualistische bewegingen, die hem bedreigen. Het is daarom goed, de meest voorkomende symptomen van zulk soort bewegingen te kennen, opdat men ze zo snel mogelijk kan ontmaskeren. Ik zal U er eentje noemen: het zich er op laten voorstaan zich bezig te houden met de problemen van "the real world". Ik geef het U op een briefje: zodra een groep zich bezighoudt met "the real world", kunt U er donder op zeggen, dat het mis zit.

Als ik mensen op dit onthullend taalgebruik attendeer, wil er nog wel eens een wenkbrauw gefronst worden ter uiting van twijfel aan deze correlatie. Maar nu kan ik elke twijfel wegnemen: sinds vorige week koester ik een nieuw bezit, dat mij via de brievenbus gewerd. Het is een brochure van "ISCOL Limited (International Systems Corporation of Lancaster)", een commerciele loot van de University of Lancaster "operated by the Department of Systems at the University". In deze brochure wordt een cursus getiteld "A Systems Approach to Problem Solving" aangeprezen. Heel interessant.....

Meteen op de eerste pagina werd mijn argwaan gewekt, toen ik las:

"Since 1966, the Department of Systems at the University of Lancaster has been seeking to develop systems-based methods of real-world problem solving..."

Je bent nog even welwillend en houdt er rekening mee, dat dit een slippertje van de pen is geweest, maar die optie wordt je niet gelaten: de laatste alinea van een op pagina 7 in een kader geplaatste tekst luidt als volgt

"There are many different approaches within the Systems Movement. The Department of Systems Engineering at Lancaster University has concentrated on the use of systems ideas and the development of methodologies for using them in real-world problem situations."

Het is evenwel de hieraan voorafgaande tekst, die onder de titel "Systems Thinking" in dit kader is geplaatst, die zo louterend onthullend is. Het begint met:

"The most powerful intellectual tradition developed by Western civilization is that associated with science, and it is the activity of science which has created the world we inhabit."

Dit eerbetoon aan de wetenschap is slechts lippendienst, want de tekst vervolgt:

"But though the methods of science are powerful, they are not all-powerful: there is no scientific solution to the problems of urban decay, planning the Health Service, launching a new product, deciding whether or not to build Concorde, or join the E.E.C. All these problems are many-sided, whereas one of the characteristics of science is that it reduces the range of variables considered and concentrates on a few. This is successful in laboratories but not in the real world." (Heb je hem weer!)

Na deze verdachtmaking van de wetenschap wordt "Systems Thinking" vanwege zijn onwetenschappelijkheid als heilsboodschap aangeprezen. Planners en managers aller landen, allen daarheen! Door zijn onverbloemdheid is deze brochure een kostbaar werkje geworden.

Het grote verschil tussen de wetenschapsman en de kwakzalver is, dat in voorkomende gevallen de eerste zijn onkunde dan wel onmacht zal toegeven. Zulks is zijn voorrecht, en daarmee zijn dure plicht.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

8 november 1975 EWD 531

Tiende toespraak, najaar 1975.

In dankbaarheid herinner ik me een lezing van een linguist over de WUB en de moeilijkheden, die bij de toepassing van deze wet waren gerezen. Op overtuigende wijze herleidde de spreker de toen heetste hangijzers op het erbarmelijke Nederlands, waarin de betrokken passages in de Memorie van Toelichting op deze wet gesteld waren. Deze lezing sterkte mij niet alleen in de overtuiging, dat ten Departemente een stel dilettanten de boventoon voeren, maar ook in een veel algemenere overtuiging, nl. dat geen product beter kan zijn dan de taal, waarin het besproken, ontwikkeld en gedocumenteerd is.

Ik moest hieraan terugdenken, toen ik mij onlangs door de zg. "Proeve van een beleidsvisie" heenworstelde, opgesteld door een gezamenlijke werkgroep van hogeschoolraad en college van bestuur van de THE. In eerste instantie is het een woordenbrij; wie tracht zich hier een weg doorheen te banen gaat het ervaren als een moeras, en de uiteindelijke indruk is, dat hogeschoolraad en college van bestuur bezig zijn, in dit verbale drijfzand verzwolgen te worden.

Nog niet murw —ik sla dit soort stukken meestal over— zie ik nog de overmaat aan neologismen en raak ik van een gepaste achterdocht vervuld door de hoge frequentie van woorden en uitdrukkingen, die niet alleen niet tot ons actieve vocabulaire behoorden, maar die zelfs in mijn van Dale niet te vinden zijn. Ik noem het figuurlijk gebruik van "invalshoek" als een van de onschuldigere voorbeelden van een veranderend taalgebruik, dat ik geen verbetering kan vinden. Grotesk is het woordgebruik van een van de commentatoren —nota bene iemand, die zich elders beklaagt over de leesbaarheid van de proeve zelf!— , die zich in zijn commentaar bedient van termen als "geëxpliciteerd", "gegevenheid" en "doelgroepen". Onnodig hieraan toe te voegen dat mijn van Dale mij hier niet kon helpen.

Erger wordt het, wanneer over "geintegreerde beleidsvorming" gesproken wordt. Wat betekent dat in Godsnaam? Het substantief "beleidsvorming" staat niet in mijn van Dale en is dus kennelijk weer zo'n nieuwertje; met wat goede wil kan ik daar nog wel een betekenis aan toekennen. Maar wat moet dat "geintegreerd"? Volgens het woordenboek moet dat betekenen "volledig gemaakt", maar waar slaat dat op? Syntactisch slaat het op de vorming en niet op het gevormde beleid... En wat betekent in dit verband "volledig" eigenlijk? Ik ben bang, dat het niets betekent.

Een hoogtepuntje onzin levert het volgende citaat: "Hiernaast moet het leveren van een bijdrage aan de zelfontplooiing van de studenten als een belangrijke taakstelling van de hogeschool worden beschouwd; deze zelfontplooiing dient, zeker voor wat betreft de ingenieursopleiding, mede te worden geplaatst in het kader van de maatschappelijke dienstverlening." Het wordt vervelend op te merken, dat het woord "taakstelling" niet in mijn van Dale voorkomt en dat waarschijnlijk gewoon "taak" bedoeld is geweest. Zo er al iets bedoeld is! Want wat dachten we van het eveneens niet in van Dale voorkomende woord "zelfontplooiing"? Als U denkt, dat de betekenis daarvan vanzelfsprekend is, vestig ik er wel de aandacht op, dat blijkens bovengenoemd citaat de hogeschool geacht wordt er een bijdrage aan te leveren! En denk er om, die zelfontplooing dient "mede te worden geplaatst in het kader van de maatschappelijke dienstverlening." Mede met wat? Ach, laat maar... het kader van de maatschappelijke dienstverlening is ook maar een loze kreet.

Als klap op de vuurpijl leert het document ons, dat het niet-bestaande woord "inzichtelijk" tegenwoordig een adjectief is. De bestuurlijke problemen van de THE hoeven ons niet meer te verwonderen.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

   EWD 532

17th of November 1975

An open letter to L.Bass.

Dear Sir

I have a problem. Last June I read an article in the Comm.ACM, and the more I read it, the more disgusted I became, because it was so poorly written that it was impossible to understand it. Eventually I wrote four pages of comments. After reading them, I decided that they were too grim for further distribution, and kept my comments in my strictly personal file.

In this letter I shall only analyse the title of the article: "Analysis and Performance of Inverted Data Base Structures".

a) The title is ambiguous, because in "Inverted Data Base Structures" it is unclear whether the Data Base or the Structures are inverted; the ambiguity is far from resolved in the article itself.

b) The title is nonsensical, because Inverted Data Base Structures don't "perform".

c) The title is wrong because it does not express that the main object of the "Analysis" is the "performance", and not the "Inverted Data Base Structures" themselves. If I have understood the author's intention well —of course I doubt!— "The Influence of File Inversion upon Retrieval Costs" would have been a much better title.

The linguistic quality of the title is, alas, fairly representative for the linguistic quality of the paper itself.

The problems of data base management are frighteningly difficult: the purely technical problems —which no one but an unknowledgeable fool underestimates— are compounded by the constraints of continuity: the show must go on! It is also patently obvious to me that we shall never concoct in time an acceptable —I don't say ideal— solution to these problems, unless we recognize and admit their difficulty and stop approaching them with tools that are hopelessly inadequate. By now I know that sloppy use of language is, in view of the size and complexity of the problems, an unmistakable symptom of inadequacy. To be as precise as we possibly can is not a luxurious mannerism that the academic prig can afford himself in his (supposedly!) sheltered environment; for people facing the problems of "the real world" it is a Must. In view of the complexity of their problems it is ridiculous to hope than they can come away with anything less than an exceptional mastery of their native tongue, and it saddens me to see people vainly trying to sharpen a pencil with a blunt axe.

My problem is how you could open your review CR 28,995 (Computing Reviews, October 1975, 442–443) with the words "This well-written paper...". How could you?

Burroughs
Plataanstraat 5
NL–4565 NUENEN
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sun, 11 Sep 2005

EWD 533

        HOMO COGITANS
                A Small Study of the Art of Thinking.

| "I cannot see that the machines have dethroned the Queen. Mathematicians who would dispense entirely with brains possibly have no need of any." E.T.Bell                            

Preface.

        This booklet is written by a man that regards himself as a programmer. The plans to write it I have harboured, at least subconsciously, for more than a decade; they came to the surface as the result of a cultural conflict between my professional surroundings and myself. My immediate professional surroundings consisted of pure mathematicians, who, by and large, seemed to ignore automatic computing, and applied mathematicians and numerical analysts, who regarded automatic computers as very useful tools that would have deep consequences for their own profession, but could only appreciate the significance of automatic computers in that specific capacity of being a useful tool. My wider professional surroundings comprised all sorts of "managing scientists" and they, too, considered automatic computers primarily as a tool: first as a device for saving money, later as a device that should give managers a better grip on what they were supposed to manage.

        Without denying the possibility that automatic computers could be used as tools to great advantage, I could not agree and felt very lonely. I had been programming for more than ten years and, as a result of the problems encountered, I was beginning to feel that the automatic computer belonged as much to the problem set as to the solution set. As the years went by, I became convinced that the influence of automatic computers in their capacity of tools would only be a ripple on the surface of our society, compared with the deep influence they were bound to have on our culture in their capacity of intellectual challenge to Mankind that was totally without precedent.

        I came to the conclusion that programming should be considered as one of the most difficult branches of applied mathematics, because it is also one of the most difficult branches of engineering, and vice versa. Obvious as this conclusion is now, it was at the time a hard conclusion to arrive at, for it was then very unpopular. It was a conclusion that met violent opposition when I tried to share it with others. The usual form of rebuttal was pointing to the hundred thousands of people then employed as programmers, the majority of whom had at best third rate intellects —it was a profession that had attracted many drop-outs and people without any formal training at all— : in view of that mediocre multitude the opinion that programming was among the most exacting of all human endeavours was clearly sheer nonsense! (I vividly remember one discussion in which my partner refused to listen to my arguments, and, instead, accused me and all my fellow computing scientists for having failed to design a programming language that would make programming as easy as it obviously should be!) The result was a mental collapse from my side, from which I only recovered when I realized that my considered opinions had been rejected, not because they were wrong, but because they were unpalatable. At the moment I knew that once I would write a little booklet about thinking.

        At last I now embark upon the little project, in spite of the fact that I do not feel quite ready, nor sufficiently equipped for the task. The brutal fact is that I embark upon the project because I need the little booklet myself. The more unusual the problem I tackle, the harder I find it to give a flawless solution. Two of my published papers contain an error, and recently I had to withdraw a submitted paper because a deep error was discovered (this in spite of the fact that it was the fourth or fifth iteration and many others had already studied and enjoyed it!) In retrospect I can see, where I have sinned against my own principles; the only way to prevent me from doing it again seems to make these principles more explicit than I have ever done before, and decide quite clearly for myself what I accept as "a convincing argument". Hence my personal need for the booklet.

*         *         *

        It is now more than thirty years ago when George Polya wrote his "How to solve it.", and I can only recommend his works to everyone who is interested in the process of discovery by the human minds. Polya is very much concerned with "discovery" and gives a kind of checklist of things to try in order that a simple, but somehow unexpected solution is less likely to be overlooked. But, being written in the time they were, his books hardly touch the specific problem of programming that would present itself more and more forcefully as the central one, as machines got larger and faster, viz. how to avoid the unmastered complexity that so easily emerges when we are faced with great multitudes, multitudes of instructions stored, multitudes of variables, multitudes of instructions executed, multitudes of possible computations, multitudes of possible cases, multitudes of possibilities for malfunctioning, etc. By their very power automatic computers created not only new possibilities, but also new problems, problems for which we were not too well prepared.

        In order to get some appreciation for the kind of "multitudes" I am talking about, consider the following numbers. On the one hand we now have machines for which the execution of a single instruction takes about a microsecond; on the other hand it is not unusual that such a machine embarks upon a computation that will take several thousands of seconds. Such a computation will consist of the successive execution of about 1,000,000,000 instructions, and what that means is way beyond our powers of imagination. (Everyone trying to grasp 1,000,000,000 should realize that, while "c" —the speed of light— is the maximum speed possible, continental European cars have speedometers gauged in "nano-c's": one nano-c is very close to 1 km/hour.) In spite of this terrifying gap a programmer has been asked to write the program, i.e. to design the class of computation of which this "unimaginable" one was a member.

        Thanks to the novelty of the programming task, our confrontation with it has taught us a few new things about the human mind. It has confronted us —most rudely, I am tempted to add— with a few of its limitations; it has also forced us to learn to come away with these limitations as well as possible.

        Programmers of the current generation have learned this —if they have learned it at all— the hard way. They have learned it by trial and error, and by —often subconsciously— acquiring the necessary, more effective thinking habits. Since about seven years, these have become the subject of conscious study —usually under the heading of "Programming Methodology"— and since a few years we are gaining (very encouraging!) experience in teaching them. It is now quite clear that a "Course in Programming" should no longer be what it used to be, viz. the teaching of a programming language, but should really be the teaching of programming, i.e. a human design activity in which effective thinking plays a predominant role. With respect to Programming Methodology —to both the development and the teaching of the subject— striking progress has been made, but it is also clear that we have still a long way to go. It is also becoming abundantly clear, however, that this development should not remain confined to the strict limits of the programmer's world.

        For the further development of Programming Methodology it seems desirable that the art of effective thinking is studied in a somewhat wider setting. For, when programmers think about programming, they always want to remain "realistic", and they always keep the overall characteristics of today's existing computers in the dim recesses of their minds. This colours their view of the world of problems and tends to make them blind for human facilities for which today's equipment provides no opportunity for use. But it is exactly the discovery of such human facilities that could provide the incentive to think about new, revolutionary different computer designs.

        The second reason is that already now, what has been discovered and developed for the sake of programming seems to have a much wider significance and to be pertinent to all of mathematics and, therefore, probably a lot more as well.

        All through the ages two educational methods have been used. The one method is that of the guild, where the young apprentice works for seven meagre years under the guidance and supervision of a master, absorbing the necessary knowledge implicitly, by osmosis so to speak, until he may be called a master himself. The result is the craftsman, and craftsmen typically keep their common knowledge as a well-guarded secret among the members of their guild. The other method is the prevailing one at the universities, where the young student studies under the guidance of a professor, who tries to transmit knowledge and skills as explicitly as possible, and who, by formulating them as explicitly as he can, thereby brings them into the public domain. The result is the scientist and his code of professional conduct prescribes to be absolutely open and explicit about his methods and results —a code, which, depending upon the nature of the significance of his work for his employer can cause him grave moral conflicts: it is no accident that in competitive organizations like industries and departments of defense, the craftsmen are more easily employed than the scientists—.

        Up to this day both techniques are used side by side: physicists are mainly trained as scientists, physicians mainly as craftsmen. The training of mathematicians is somewhere in between. Mathematical results are published quite openly and are taught quite explicitly; but how mathematics is done remains largely hidden. To publish besides the results the way (and the order!) in which they were reached, to mention the blind alleys as well, to mention whether the solution was found in three months or twenty minutes, to express the author's personal feelings (of hope, despair, or fascination), all this is regarded as "unscientific", and, therefore, "bad style". (Just try to include such remarks in your publication: if the referees don't object to them, the editor will!) This taboo seems to extend itself over the teaching of mathematics as well. The plain truth is that nearly all trained mathematicians must be regarded at best as self-taught thinkers, most of whom think very clumsily. *)

- - - - - - - - - - - - - - - - - - -
*)     Those who think the above remark too unkind, I refer to the following quotation: "one could not be a successful scientist without realizing that, in contrast to the popular conception supported by the newspapers and mothers of scientists, a goodly number of scientists are not only narrow-minded and dull, but also just stupid. (James D. Watson in "The Double Helix.")
- - - - - - - - - - - - - - - - - - -

        This seems the moment to warn in particular the more competitive of my readers. (The competitive attitude is responsible for much of the misery in this world.) I must warn them that the reading of this little booklet could easily become a very frustrating business for them. The problem is that you cannot read this booklet without realizing that it is also about you that I am writing! To make matters worse, I am not writing about something extraneous —like the colour of your hair— but I am writing about your most intimate, personal and specific aspect: how you think and understand. If your talent for aloofness is sufficiently well-developed, you will have no problem: "Of course I am an amateur thinker! What else could I be? When I come to think of it I have had eight years of piano lessons, but it never shocked me to regard myself as an amateur pianist. And, what is more, my amateur status has never prevented me from enjoying piano playing, nor from trying to improve my technique."

        But past experiences make me fear that a considerable fraction of my potential readers will react more defensively: each step in the transition from craft to science has always been a painful process and has always caused violent reactions from the craftsmen, who feel themselves threatened when what they regard as their private property is made explicit and is brought into the public domain. In this case the easiest defense is to postulate that thinking cannot be taught, as this dogma now fully justifies your decision not to read any further and to write me of as a quack. The alternative is to pretend that you have read and studied my text from cover to cover, but have learned nothing valuable from it, because

  alternative a:    | it is just a bunch of trivialities for the simple-minded, but —of course— does not help you in the least with the particularly tough problems you are working on, etc.
  alternative b: | it is very valuable, but says exactly what you yourself have been preaching over and over again, but nobody would listen, etc.

So you have your choice; a mixture of (a) and (b), however, is not to be recommended.

Note. Those who feel somewhat offended by the last paragraphs have totally misunderstood them, and should read them again. (End of note.)

        Finally I must warn for one fallacy, viz. that it is vain to think or say anything about thinking in general, because different people are so different: what is easy for the one, is difficult for the other and vice versa, it is all a question of what you are used to, etc. This objection is in essence a confusion between "convenient" and "conventional". Pianists can be —and have been!— trained not to use their thumbs, and for such pianists playing with eight fingers is then "easier", more "natural" than playing with all ten: then their thumbs always come in the way. To conclude from this observation the impossibility of saying anything conclusive about the well-known controversy between the proponents of eight-finger playing versus the proponents of ten-finger playing is nonsense. In a very objective sense the technique of using all ten is better, because more effective, a conclusion which is not belied by the fact that, after the general adoption of the ten-finger technique, there will still be people that will never learn to play a decent tune on the piano. My search for the most effective way of using our brains when thinking is very much like the search for the most effective way of using our fingers at the keyboard. I know that human hands differ from each other —Brahms's hands could do things mine are physically unable to accomplish— yet the well-made human hands are sufficiently similar to each other to admit rather universally valid statements about their application at the keyboard. We all recognize them as well-made human hands, and we also recognize a well-made human brain when we encounter somebody possessing one! The subject of this little booklet is how to use what we then recognize as a well-made brain.

On reasoning, and why to avoid it as much as possible.

        Of all our thinking activities one class stands out very clearly, viz. all manipulations that are formalized —or could readily be so— by techniques such as arithmetic, formula manipulation, symbolic logic etc. I shall denote these activities by the (hopefully sufficiently descriptive) term "reasoning". A single name seems justified, because they have a few common characteristics.

        First of all, whenever they have been applied, in principle there never needs to be an argument, whether they have been applied correctly or not, for each step (which is always one from a finite repertoire) can be checked.

        Secondly, as soon as it has been decided in sufficient detail, what has to be achieved by them, it is no longer a problem, how to achieve it.

        Thirdly —and this is not independent of the first two— we know how to teach them: arithmetic at primary school, formula manipulation at secondary school, and symbolic logic at the university.

        Fourthly, we are very good at doing modest amounts or reasoning. When large amount of it are needed, however, we are powerless without mechanical aids. Multiplying two two-digit numbers is something we all can do; for the multiplication of two five-digit numbers most of us would prefer the assistance of pencil and paper, the multiplication of two hundred-digit numbers is a task that, even with the aid of pencil and paper, most of us would not care to undertake.

        Our emotional appreciation of the various instances of reasoning is quite different, so different as a matter of fact, that quite a few people (I discovered) wondered whether arithmetic should be classified as a thinking activity. But let us be careful: less than 500 years ago a professor of mathematics taught at one of Europe's universities, that for the more gifted and industrious students it was not impossible to master long divisions: his students had to do it with Roman numerals! The majority of us might feel that the introduction of the decimal numbers has reduced arithmetic to a boring routine, but that is probably only, because most of us are so poor at it, and can do no more than laboriously applying the routine steps. Calculating prodigies, however, have many ways of arriving at a result and, as a consequence, can get quite excited by their mental gyrations, excited because they can search for a still shorter way.

        As said: we are very good at modest amounts of reasoning. In many arguments, the amount of reasoning needed often becomes the stumbling block. One of the central themata of this booklet is to relate the effectiveness of the way in which we have arranged our thoughts to the extent in which we have been able to reduce the demands on our limited reasoning powers: lengthy arguments are never convincing!

        Our ultimate goal may be to learn to think as effectively as possible; perhaps we are even more ambitious and would even like to learn how to teach how to think as effectively as possible. But considerations about heuristics —and, possibly, their teaching— should be postponed. Prior to that, we should study a number of "given" solutions. We should study a number of very effective ones, in order to get a clear view of the kind of intellectual elegance we are heading for. In order to satisfy our curiosity, we should compare different solutions for the same problem. In doing so we may hope to discover what to do, what to try and, above all, what to avoid if we are aiming at a reduction of the amount of reasoning.

Note. My very conscious desire to reduce the demands made on reasoning is undoubtedly the result of my professional experience as a programmer, but the seed has been sown nearly thirty years ago, when I received from my mother the shortest and wisest lesson in mathematics. Being asked by me what "trigonometry" was all about and whether it was difficult, she answered "Oh no, it is not difficult: know the formulae, and whenever you seem to need more than five lines for a problem, try something else, for in all probability you are on the wrong track." (End of note.)

Burroughs
Plataanstraat 5
NL-4565 NUENEN
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

(The typing of the above has been completed on 27th November 1975; the manuscript had been written in the summer.)

transcribed by Corrado Cantelmi
revised Wed, 3 Mar 2010

24 november 1975 EWD 534

Elfde toespraak, najaar 1975.

De zuidelijke begrenzing van onze campus, eens een uitnodiging voor remproeven en bekend onder de bijnaam van "de Professoren-renbaan" is sindsdien vierbaans geworden en nu, ter ere van onze eerste Rector Magnificus, bekend als de Dorgelolaan. Een mooie laan. Haaks hierop staat het Posthumuspad. Een mooi pad. Het is alleen verontrustend, dat het bordje aan zijn begin door zovelen niet gezien wordt, het bordje dat zegt "Doodlopende Weg". Onze derde rector was een zo gewiekst politicus, dat, naar verluidt, mettertijd een doolhof naar hem genoemd zal worden.

Maar terug naar Posthumus. Aan hem danken we, dat de enge technologische basis van onze TH met culturele aanwinsten als onderwijs research werd verbreed, dat we bedrijfskunde kregen en tenslotte met bouwkunde werden opgezadeld. En ik kan U de verzekering geven dat, als het aan hem gelegen had, de achtste medische faculteit niet in Maastricht gekomen was. Hij kon in zijn pleidooien lyrisch worden over wat hij "de menswetenschappen" noemde, en liet niet na hen te contrasteren met de koele techniek, aan dat vermeende contrast de noodzaak voor compensatie ontlenend. Als zovelen van zijn generatie had hij het gif van Frederik van Eeden gedronken en was hij het slachtoffer van het bijgeloof, dat "hart" en "hoofd" onverenigbaar zouden zijn, dat "emotie" en "ratio" elkaar slecht zouden verdragen. In die goedkope visie worden de exacte wetenschappen als iets onmenselijks voorgesteld met, uit de aard der zaak, de wiskunde als toppunt van inhumaniteit, en is Professor Sickbock niet een persiflage, maar de realiteit.

Velen voor mij hebben dit bijgeloof bestreden. Dorothy L.Sayers —ongetwijfeld zelf een slachtoffer van dit onbegrip om haar heen— ageert meermalen tegen de opvatting dat wie erg knap is, emotioneel onderontwikkeld zou moeten zijn. En Eric Temple Bell schrijft in 1937: "...a mathematician can be as human as anybody else — sometimes distressingly more so.". Ik kan Bell's observatie alleen maar bevestigen: in mijn leven heb ik het voorrecht gehad een aantal uitzonderlijk knappe collegae ontmoet te hebben, en zonder uitzondering waren dit zeer gevoelige mensen, wier leven van een genuanceerde volheid was, waarvan zelfs de literator C.P.Snow, die beweert "the scientists" te kennen, blijkens zijn geschriften niet het flauwste benul heeft.

Ik voel mij zelfs gemachtigd aanmerkelijk verder te gaan. De wiskunde is niet een geatrofieerde uitloper van een ontmenselijkte samenleving. Integendeel: het is het terrein bij uitstek waar onze grootste intellectuele en artistieke gaven tot synthese komen, en een bloeiend wiskundig leven is een van de duidelijkste symptomen van een levende cultuur. Toen Archimedes door een Romeins soldaat werd doodgestoken, was dit het eerste voorteken van het Romeinse verval, dat enkele eeuwen later door de kortzichtige Cicero bezongen zal worden, als hij er prat op gaat, dat zijn heerlijk Rome niet meer wiskunde duldt,dan nodig voor meten en tellen. Het hoeft geen verwondering te wekken, dat de Romeinse steriliteit tenslotte destructief werd en de bibliotheek van Alexandrie in vlammen deed opgaan. De donkere middeleeuwen zetten in, wanneer de laatste Griekse wiskundige Hypatia door de Christenen wordt gelyncht, en de Arabische wereld vervalt in achterlijkheid als in de zevende eeuw de bibliotheek van Alexandrie ten tweeden male, maar nu definitief, verwoest wordt, nu door de Moslims, met het motief dat de teksten, als ze onverenigbaar met de Koran zijn, fout zijn, en anders overbodig.

Het is gebruikelijk te denken, dat met Galileo Galilei het Westen zich aan de houdgreep der mystiek ontworsteld heeft, maar zijn we, met al die zogenaamde "menswetenschappen" daar wel zo zeker van?

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

EWD535

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

24th November 1975

An answer to Jack Mazola.

Thank you for your letter of 7 Nov. 1975. I was very pleased to read that my writings had inspired John McClintock and you to do better than your (or McElintock’s) first effort. I had —and I offer my apologies if this is a great disappointment— difficulties in understanding your invariants, because they are mixed expressions in two different languages: on the left-hand side of the implication we have boolean expression which at any moment in time are defined by the current state of the aggregate, at the right-hand side of the implication are phrases about past and future, and not all sentences —such as “if he ever restarts”— were too clear to me. The only thing left for me to do was to try to convince myself that everything was OK in my own (old-fashioned! see below) way. The following is not a description of how I would develop the program ab initio: I cannot fake that, I have been “spoiled” by studying your solution and, as a result, have lost my virginity. The first thing I did was to study the following program (here “x” is a local variable of each machine)

| do non initialized →
|  | done[me]:= false;
|  | x:= 1; do done[x] → x:= x + 1 od;
|  | if x = me → initialized:= true
|  |  | ▯ x < me → skip
|  | fi;
|  | done[me]:= true
| od

and asked myself the question whether “initialized” will become true, when a number of the machines is started. The answer is “Yes”, provided the machines that re not started have their done = true; the argument is that of the started machines the one with the lowest number is certain to end its inner loop with x = me and will therefore perform “initialize:= true”. Note that for this argument the initial value of done for the machines that are started, is irrelevant.

The next question is: can we make of “initialize:= true” mutually exclusive actions —so-called “critical sections”. So I tried to do it by inserting your waiter (note that in your letter, page 4, is a misprint, it should be

| “do X ≤ HI → do non DONE[X] → SKIP od&rdsquo; )
| do non initialized
|  |  | done[me]:= false;
|  |  | x:= 1; do done[x] → x:= x + 1 od;
|  |  | if x = me → do x < N → x:= x + 1;
|  |  |  |  | do non done[x] → skip od
|  |  |  | od;
|  |  |  | initialized:= true
|  |  | ▯ x < me → skip
|  |  | fi;
|  |  | done[me]:= true
| od

Assume that at moment t machines i and j (i ≠ j) are both ready to perform “initialized:= true”. Then we have at moment t: done[i] = done[j] = false. Let ti be the last moment < t such that done[i] was true; let tj be the last moment < t such that done[j] was true. From the fact that machine i has reached the statement “initialized:= true” we can conclude that done[j] = true has been observed while done[i] was already = false , hence ti < tj . Similarly we find that tj < ti , and this gives us the required contradiction. Mutual exclusion is guaranteed. The next question is: can we have introduced deadlock by our addition? We cannot have a number of processes mutually blocking each other with their done = false in that added waiting cycle, because the one with the largest number of the set does not inspect the other values done from the set. But machine i may be kept in that inner cycle by a machine j (j > i) happily rotating in the outer cycle, but with such a speed that machine i always misses the rare moments that done[j] = true . Therefore the assignment done[me]: true is followed by

| x:= 1;
| do x < me → do non done[x] → skip od;
|  | x:= x + 1
| od

Because of the arguments given by you this does not introduce the danger of deadlock in the last waiting cycle. The last modification is to ensure that initialization now occurs only once; because “initialized:= true” has been guaranteed to be executed in a critical section, it suffices obviously to replace it by

| do non initialized → initialize; initialized:= true od | (1)

and now I have arrived at a program that differs only marginally from your solution, which I thought a very beautiful one.

*              *
*

There is a second way in which I am no virgin with respect to this problem: it is very similar to the critical section problem that I solved in the Sep.1965 issue of the Comm.ACM., and naturally, the old patterns of reasoning come again floating in my consciousness. To prove things about such processes that may interfere with each other in such a fine-grained fashion is a risky business, as I have learned the hard way.(In the meantime you should have received EWD520, our next, and hopefully last, version of the on-the-fly garbage collection.) The person with the most extensive experience of proving things about such aggregates of programs is David Gries. One of the more valuable tricks is to associate “ghost variables” to which the programs only assign values. They —i.e. their values— can then be used to express things about the progress of the various programs, they provide means for expressing formally and without ambiguity such things as mutual exclusion. In this example, mutual exclusion is clearly needed if a precaution like (1) is to ensure that initialization will only be performed once. But even then, to formalize the ti < tj and tj < ti argument of the previous page is no fun; as yet I have seen no more formal, yet “decent” argument. (A challenge when I have nothing else to do!) For practical reasons I would regard the argument on the previous page convincing enough. As yet the formal proofs tend to become hairy....

*              *
*

Finally I would like to congratulate you with your decision not to be content with the first solution and it justification. The experience that the next effort gives something much nicer is a very common one, but it is only believed by those who have had the experience themselves!

Yours ever,

Burroughs | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NUENEN - 4565, The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-11-28 .

EWD536

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

26th November 1975

A sequel to EWD535.

I just realized that in EWD535 I have failed to touch upon the second point raised in your letter, where you write that you feel compelled to replace

| if B → S1 ▯ non B → S2 fi | (1)

by

| if B then S1 else S2 fi | (2)

because of the fact that two successive calls of B “may not return the same value on two calls because of another precessor changing the state”. I had forgotten about it, because in the EWD535-versions of your program the boolean procedure had disappeared.

In my book “A Discipline of Programming”, and in all the theory about semantics that underlies the notion of the guarded commands, all expressions —not only the guards, but also all arithmetic expressions at the right-hand side of an assigment operator— are regarded as (possibly partial) functions of the “current state”, which is supposed to change only as a result of explicit assignments. Furthermore I have restricted myself to a programming language that trivially admits a sequential implementation. I have given no further prescriptions about that implementation; in particular I have not prescribed that the execution of (1) must imply a separate evaluation of B and another one of non B . On the contrary! One can defend the point of view, that for any boolean expression B the evaluation of B by definition implies the concurrent evaluation of non B , because both answers give exactly the same information about the current state. From that point of view —I still talk about sequential uniprogramming— one can appreciate (2) as a hint to that part of the compiler that optimizes boolean expressions: it saves it the trouble to recognize that the two guards are the complement of each other. Needless to say, that all forms of side-effects are ruled out: they are regarded by me as invalid implementations as they would violate the axiom of assignment, etc.

The awkward point is how to transfer this pattern of reasoning in order to describe the semantics of a number of mutually unsynchronized programs that —at a certain grain of interleaving, say: a memory cycle— fool in the same store. I know of only one way (and it is not very attractive! I shall sketch it nevertheless; the unattractiveness is probably a consequence of the sad fact that these problems are inherently ugly.)

Consider programs A and B with the shared variables x and y; consider then separately program A in its private state space extended with x and y , and the program B in its private state space extended by x and y. When considering program A we now must admit that at each semicolon of A so to speak, the total state of A (i.e. including x and y) may change non-deterministically, only bound by the limitations of what B may do. If, for instance, B has the trivial form

| do true → x:= random od

(assuming that B has a private random number generator) this means for program A that at any semicolon the value of x may be subjected to a random variation. (A rather terrible form of interference!) If B has the trivial form

| do true → X:= 1 od | (3)

it means for program A that at any “semicolon” x is either equal to 1 or unchanged. In order to make this a workable system, one has to postulate, that in each “unit of evaluation” (see below) at most one shared variable is referenced at most once. Here a unit of evaluation is something about the internal sequencing of evaluation we don’t wish to make any committments. Without that constraint it could make a difference whether A evaluated “x + x” or “2 * x”: in the second case we could guarantee an even result, in the first case we can not! And then, a more or less decent mathematical system becomes totally impossible.

The problem, of course, is, that program B has more structure than (3), and that, when studying program A we have to take that into account. If, in program A we have

| do x > 0 → s:= x; x:= s - 1 od | (4)

we cannot guarantee termination with B of form (3) ; we could however, with B of the form

| do true → do y > 0 → x:= 1 od od | (5)

guarantee termination of (4) provided initially y ≤ 0, because then B can interfere with the loop (4) at most once. More detail you can find in the thesis of Susan Spear Owicki from Cornell University, Ithaca, N.Y. 14850 (according to my Webster), Department of Computer Science.

It was the experience of studying her thesis, and the moral of a number of my own exercises, that caused me —first thing I did!— when I tried to understand your solution, to do away with the boolean procedure INITIALIZERESPONSIBILITY: the value that its call returns is not a function of the state, but a (very complicated) function of past history. But that implies that I want to see at this level the semicolons, the sequencing to be more precise. One can read your observation as a plea for the if-then-else-fi construct; another conclusion can be that a function procedure, the evaluation of which references more than one shared variable is a misleading construct that we had better regard as “against the rules”. Susan Dwicki has made the latter choice, and she has my blessing. Unless new arguments emerge I think that I shall stick to my guarded commands: I am still quite happy with them!

The most effective way of mastering complexity is avoiding the introduction of complexity in the first place! I would love to know how I could put more “meat” into that observation.

Yours ever,

Burroughs | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 | Burroughs Research Fellow
NL-4565 NUENEN |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-08 .

26 november 1975 EWD 537

Twaalfde toespraak, najaar 1975.

Wie oplettend luistert naar het "Dona nobis pacem" uit de Krönungsmesse, KV 317, van Mozart, wordt getroffen door het weinig onderdanige karakter van deze muziek, die U evenveel kan leren over de Rooms-katholieke kerk als over de Vrijmetselarij. Dit "Dona nobis pacem" is geen nederige smeekbede om vrede, om den donder niet! In niet mis te verstane verklanking wordt hier de almachtige God aan zijn plichten herinnerd. Het is alsof een geteisterde mensheid met de vuist op tafel slaat en schreeuwt: "Vrede verdomme!". Bij Mozart klinkt het alleen veel mooier en overtuigender. Dat blijkens het verdere verloop der historie het de almachtige God niet overtuigd heeft, zullen we de componist niet euvelduiden.

Ik moest aan deze mis van Mozart denken —en de muziekminnaar vergeve mij de associatie— toen ik onlangs de dreigende taal las, die vakbondsbestuurders uitsloegen voor het geval het kabinet geen rekening zou houden met de eisen der vakbeweging. Jawel: eisen der vakbeweging! Geen verzoeken, geen verlangens of wensen, maar eisen! Een onvervalst "Dona nobis pecuniam". Ik was geschokt, dat deze loederige chantage van het kabinet in mijn oren de herinnering opriep aan een van de mij meest aangrijpende muziekstukken, en vroeg mij af, hoe zulks mogelijk was.

Kijk, we zijn tegenwoordig een beetje eiserig, en dat is een symptoom van domheid, nl. de domheid het vermogen aan de andere zijde te overschatten. Wij hebben een recht op medische verzorging, maar niet een recht op gezondheid. Als ik van mijn arts een zorgvuldige behandeling eis, sta ik in mijn recht, als ik altijd genezing van hem eis, ben ik dom en daardoor onrechtvaardig, want sommige ziekten zijn nu eenmaal ongeneeslijk. Evenzo heeft de student recht op onderwijs, maar niet op een diploma dat wat voorstelt. Als de student van zijn hoogleraren eist, dat zij hun colleges goed verzorgen, staat hij in zijn recht, als hij, wanneer hij voor een examen gezakt is, zijn docenten in gebreke stelt, omdat zij hem niet bijgebracht hebben wat geeist werd, is hij dom en daarmee onrechtvaardig: sommige materie is voor sommige studenten nl. gewoon te moeilijk.

Aan een almachtige God kun je eisen stellen, want Hij zou ze kunnen vervullen; wie eisen stelt aan een machteloze Joop maakt zich alleen maar belachelijk, want hij gedraagd zich dan alsof hij in onze Joop een heiland ziet.

Niet dat dit soort vertekeningen niet eerder vertoond zou zijn. Een van de beruchtste psalmen van de Hitlerjugend bezong de Führer en eindigde met de regels

"Gibt uns Arbeit, gibt uns Brot,
 Hilft in aller Not."

De dichter, die ongetwijfeld de sacrale functie van het brood kende, presenteert Hitler hier onverholen als heiland. Ten gunste van de soortgelijke lamstraal Bonaparte kan tenminste nog worden opgemerkt, dat hij de cultus van "Saint Napoleon" —jawel, compleet met bidprentjes en alle verdere paraphernalia— verboden heeft. Nou ja, verboden..... Althans tijdens zijn leven: eenmaal dood zag ook Bonaparte niet meer tegen de heiligenrol op.

De almachtige God zou vrede kunnen schenken, en als Hij dit niet doet, is het waarschijnlijk omdat Hij vindt, dat wij de vrede niet verdienen; de machteloze Joop zal niet de rijkdom verdelen, want hij heeft slechts armoe te verdelen. Joop is ook maar een mens! Laten vakbondsbestuurders dit —in God's naam!— niet vergeten.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

EWD538

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 538 A collection of beautiful proofs :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 174�183 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

A collection of beautiful proofs.

This chapter contains a compilation of beautiful proofs, proofs of which I expect that all mathematicians will agree that they are beautiful. The purpose of this compilation is to collect the material that may enable us to come to grips with the main qualities that together constitute “mathematical elegance”. Further analysis and comparisons of these gems will be postponed until the collection is thought to be large enough. In order to avoid too much of a personal bias (and, also, to build up a larger collection than I could think of myself) I have asked others for their contribution to the collection. The only constraint was that the proof could be appreciated by the “generally educated”; all contributions that required specialized mathematical knowledge had, alas, to be rejected.

1. A classical example.

In the late 18th century a German schoolmaster gave —with the intention of keeping his pupils busy for another hour— the task to sum hundred terms of an arithmetic progression to a class of little boys who, of course, had never heard of arithmetic progressions. The youngest pupil, however, wrote down the answer instantaneously and waited gloriously, with his arms folded, for the next hour while his classmates toiled: at the end it turned out that little Johann Friederich Earl Gauss had been the only one to hand in the correct answer. Young Gauss had seen instantaneously how to sum such a series analytically: the sum equals the number of terms multiplied by the average of the first and the last term. (To quote E.T.Bell: “The problem was of the following sort, 81297 + 81495 + 81693 + ... + 100899, where the step from one number to the next is the same all along (here 198), and a given number of terms (here 100) are to be added.”)

In two respects this is a classical example: firstly young Gauss produced his answer about a thousand times as fast as his classmates, secondly he was the only one to produce the correct answer. So much for the effective ordering of one’s thoughts!

2. The Pythagorean Theorem, proof I.

When I was twelve years old, I learned the following proof, in which a square with sides a + b is considered in two different ways.

The two expressions are different expression for the same area: they are therefore equal. Next we observe 2ab = 4ab/2 and by subtraction we find a² + b² = c². A beautiful proof in the good old Greek tradition that fascinated me when it was shown to me, and satisfied me for more than 30 years.

3. The Pythagorean Theorem, proof II.

The following proof was shown to me a few years ago. The areas of similar figures have the same relation as the squares of corresponding lines; for three similar figures with areas A, B, and C respectively and corresponding lines a, b, and c respectively, any homogeneous linear relation satisfied by A, B, and C is, therefore, also satisfied by a², b², and c², and vice versa. In particular we know that A + B = C implies a² + b² = c² .

Here we have three similar triangles with a, b, and c respectively as their hypotenuse; the sum of the areas of the first two equals the area of third triangle, i.e. A + B = C, hence a²+ b² = c².

4. The Theorem of Pompeiu.

For a triangle ABC of which at least two sides have different lengths, we can choose a point P such that the lengths AP , BP , and CP are such that no triangle can be formed from those three pieces.

In any triangle, each side must be smaller than the sum of the two others. But, if AC > BC , we can choose P so close to C , that AP > BP + CP, hence they can not be the lengths of the sides of a triangle.

This observation led the Rumanian mathematician Pompeiu to the conjecture that, conversely, for a equilateral triangle ABC no such point exists, i.e. that for every point P the lengths AP, BP, and CP satisfy the triangular inequalities. He gave a proof, which —I am told— was very ugly. The following beautiful proof is due to E.R.Veldkamp; it gives a constructive existence proof of such a triangle with sides equal to AP, BP, and CP respectively.

We rotate triangle CAP around point C over 60 degrees, so that A’ coincides with B and P gives rise to its corresponding point P’ . The process of rotation implies that AP = BP’ and CP = CP’; But now triangle PCP’ is an isosceles triangle with at point C a top of 60 degrees, hence it is equilateral, and we conclude that CP = PP’. Triangle PBP’ has three sides of the required lengths and the Theorem of Pompeiu has been proved.

5. Euclid’s Theorem on Primes.

Denoting the integer numbers ≥ 2 by the term “multiples”, we can define the primes as those multiples that cannot be written as the product of two multiples. From this definition it follows immediately that for each multiple there exists at least one prime dividing that multiple.

Let P be a prime; define the multiple Q as the product of all primes ≤ P , increased by 1. The multiple Q has been constructed in such a way, that none of the primes ≤ P devides Q ; the prime dividing Q must, therefore, be > P . Hence there is no largest prime number.

Note. It is not unusual that, after the construction of Q, the proof considers the two cases “Q is a prime” and “Q is not a prime” separately. The above proof shows that this case analysis is superfluous; the case analysis has probably been induced by the linguistic distinction between singular and plural forms. (End of note.)

6. Euclid’s Theorem on the Base Angles of an Isosceles Triangle.

Using the theorem that any two triangles which have two sides and the included angle equal to two sides and the included angle of the other are congruent, it should be proved that the base angles of an isosceles triangle are equal, more precisely, that from AC = BC follows that the angles A and B are equal to each other.

Because AC = BC, we have also CB = CA; angle C is equal to itself and the theorems alows us to conclude that the triangles ACB and BCA are congruent. These two triangles have angles A and H as corresponding parts, hence they are equal.

Note. It is not necessary —as Euclid seems to have done— to bisect angle C and then to use the theorem to show that the original trangle is cut into two congruent parts.(End of note.)

7. A covering problem.

Given the figure as shown below that could be covered by 138 squares, and 69 dominoes of two squares each —one such domino is shown below—

the question to be answered is: can the figure be covered by the 69 dominoes? The answer is negative, and the argument is as follows.

Consider the 10*14 rectangle before the two opposite squares have been removed, and colour its squares alternatingly black and white as wit a chess board: the rectangle then shows 70 white squares and 70 black ones. The two squares to be removed have, however, the same colour, and our figure, therefore, has 70 squares of the one colour and 68 squares of the other colour. Each domino covers one white and one black square; together the dominoes cover, no matter how they are placed, 69 black and 69 white squares. As a result they cannot cover the given figure.

8. The Harmonic Series Diverges.

Consider
Sn=1/1 + 1/2 + 1/3 + 1/4 + 1/5 + 1/6 + 1/7 + 1/8 + ... + 1/n .
It has to be shown, that by choosing n sufficiently large, we can achieve Sn > M for arbitrarily large value M; in other words we have to show that the sequence S₁, S₂, S₃ is unbounded. We observe that
S₂ - S₁ = 1/2
S₄ - S₂ = 1/3 + 1/4 > 1/4 + 1/4 = 1/2
S₈ - S₄ = 1/5 + 1/6 + 1/7 + 1/8 > 1/8 + 1/8 + 1/8 + 1/8 = 1/2 etc.
In other words: starting with n = 1 , Sn is increased by at least 1/2 each time n is doubled.

9. The Eigenvalues of a Hermitean Matrix are Real.

A Hermitean matrix is the generalization of a real, symmetric matrix; its transpose equals its complex conjugate

| AT = A* | (1)

For a given matrix A , lambda is an eigenvalue, if and only if the equation

| A.x = lambda.x | (2)

has a non-null vector x as solution.

Taking the transpose of both sides of (2) we get

| xT.AT = lambda.xT |

and then post-multiplying both sides by x* we get

| xT.AT.x* = lambda. xT.x* . | (3)

Taking the complex conjugate of both sides of (2) we get

| A*.x* = lambda*.x* |

and then pre-multiplying both sides by xT we get

| xT.A*.x* = lambda*.xT.x*. | (4)

On account of (1) we conclude that (3) and (4) have equal left-hand sides, and hence 0 = (lambda - lambda*).xT.x*.
Because x is a non-null vector and xT.x* is a sum of absolute values, we conclude that xT.x > 0 , and hence

| lambda = lambda . | Q.E.D.

10. The Cauchy-Schwarz inequality.

Let a₁,..., an and b₁,..., bn be 2n real numbers; then the following inequality holds:
        (a₁b₁ +...+ anbn)² ≤ (a₁²+...+ an²)(b₁²+ ... + bn²)
Consider the following quadratic form Q(x) in x , defined by
        Q(x) = (a₁ + b₁x)²+...+ (an + bnx)² . Because for real x, Q(x) is defined as the sum of the squares of n real numbers, for real x the inequality Q(x) ≥ 0 must hold. In other words, the equation Q(x) = 0 has at most one real root, and its discriminant is ≤ 0 . Collecting powers of x in the definition of Q(x) we find:
        Q(x) = (a₁²+...+ an²) + 2(a₁b₁+...+ anbn).x + (b₁²+...+ bn²).x²
with the discriminant
        (a₁b₁ +...+ anhn)² - (a₁²+...+ an²)(b₁² +...+ bn²) The conclusion that this discriminant is non-positive proves our inequality.

11. Reconstructing an odd polygon from the midpoints of its sides.

We shall show the construction for poly = 5 .

For the pentagon ABCDE , the points marked AB, BC. CD, DE, and EA respectively are the midpoints of its successive sides. Given the positions of those five midpoints, it is requested to reconstruct the original pentagon ABCDE.

Consider what happens when we subject a plane to five successive rotations of 180 degrees each with AB, BC, ED, DE, and EA as the successive centers of rotation. The point that originally coincided with A , coincides with B after the first rotation, with C after the second rotation, etc. and coincides again with A after the fifth and last rotation. Because the pentagon has an odd number of sides, the total transformation of that plane is therefore a rotation of 180 degrees with A as its center of rotation.

We now trace a point in the rotated plane that originally coincides with an arbitrary point X0 . Rotating it around AB gives us its position X1 after the first rotation, rotating that around BC gives us its position X2 after the second rotation, etc. until we have constructed its final position X5 . As that could also have been reached by rotating X0 ever 180 degrees around the —still unknown— point A , we conclude that A is the midpoint of the line from X0 to X5 ! The positions of the other four vertices B, C, D, and E now follow trivially.

12. The number of factors p for p prime in n!

Let n be a natural number, let p be a prime number; let s(n, p) denote the sum of the digits of the representation of n in the number system with radix p . Then the number of factors p in n! equals

| n - s(n, p) |
| ----------- | (1)
| p - 1 |

Expression (1) is clearly correct for n = 1 . Its general validity is proved by mathematical induction. Suppose that n + 1 has k factors p ; the transition from n! to (n + 1)! then increases that number of factors p by k . But replacing n by n + 1 also increases (1) by k , because when 1 is added to n , the carry is propagated over k digits = p - 1, which all turn into zero.

13. Frank Morley’s Theorem.

In 1904 Frank Morley discovered the following theorem —see picture—:

| The adjacent pairs of the trisectors of the angles of a triangle always meet at the vertices of an equilateral triangle.

The shortest proof I know for this theorem proves, in fact, a stronger theorem, that also determines the orientation of that equilateral triangle. We start in our proof not with the arbitrary triangle, but with the equilateral one.

Choose the three positive angles α, β, and γ such that α + β + γ = 60̊
Draw an equilateral triangle XYZ and construct the triangles AXY and BXZ with the angles as indicated in the above picture. Because ∠AXB = 180̊ - (α + β), it follows that if ∠BAX = α + φ, ABX = β - φ . Using the rule of sines three times (in triangles AXB , BXZ , and AXY ), we deduce

| sin(α + φ) |  | BX |  | XZ.sin(60̊+γ)/sin(β) |  | sin(α)
| ----------- | = | ---- | = | ----------------------- | = | -------
| sin(β - φ) |  | AX |  | XY.sin(60̊+γ)/sin(α) |  | sin(β)

Because in the range considered the left-hand side of this equation is a monotonically increasing function of φ, we conclude that Q = 0 is in this range its only root. Completing the picture and repeating the argument twice we conclude that the angles at A, B, and C are trisected, and thus Marley’s Theorem is proved without the aid of any additional lines.

(To be continued in a later report.)

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-08 .

EWD539

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 539 Mathematics Inc., a private letter from its Chairman :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 184�187 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

1st December 1975

Mathematics Inc., a private letter from its Chairman.

Dear ... ,

Yes, indeed, it has been a hectic year! Thank you for your kind feelings. As a matter of fact it started already around Xmas last year, when the rumour reached us that the International Research Development Corporation IRDC was trying to penetrate our market! IRDC is represented by Obfuscate et al., that old clannish sollicitors firm in Oldcaste-upon-Time, which —as luck would have it!— employs a former classmate of mine. I wrote him a letter —full of sugar, you may be sure!— as if I were appealing to him for legal advice. It all worked our beautifully, he even did send us a draft contract, thus providing us with all the information we wanted to have! It was all most reassuring: IRDC is so firmly entangled in legal complications that they are no longer a serious threat. Our monopoly is safe — and in case of problems: we have arranged a secret affair between the nightporter of the Hosanna Building and the second daughter from old Obfuscate’s first marriage, so blackmail is always there as emergency exit.

The whole affair had one nasty consequence: in our moment of panic we felt that we had to do something, and our Proof of the Riemann Hypothesis has been brought out into the field, contrary to the advice of our marketing manager who felt that it still required too much maintenance. And right he was: we can —and do!— burn our stove with the incoming trouble reports! End of March we have transferred fifty mathematicians from Production to Field Support, thus solving two problems at once.

Business being what it was, something had to be done about production, for our stock of unsold theorems was growing beyond the acceptible limits. I have always argued that we should have a reasonable amount of spare theorems in stock, but in March they already occupied nearly two full floors of the Hosanna Building! Besides the transfer of the fifty mathematicians —we have, of course selected the fifty most productive ones— we have returned to our old method of productivity measuring: since February 1974 we measured mathematician productivity by the number of new results obtained per month; we are now back on the more realistic and, after all, also more objective technique of counting the number of lines of proof produced per week. Thanks to those two measures, the stack of unsold theorems, I am happy to say, is slowly shrinking back to normal size.

But for a few little, specialized firms (one in finite geometry and another one in combinatorial logic), Mathematics Inc. has now full control of the mathematical market, a circumstance that is certain to create both political and economic problems. It is not yet an open battle, but the first symptoms of revolt against our dominance become visible for the discerning eye.

For the time being we have nothing to fear, for our greatest allies are and remain the universities, their departments of mathematics, I mean. They should fight us to death, because the more we proceed, the more obsolete they become, and in the end they will be abolished as superfluous. But the technique is so simple! One just sponsors a conference that one calls a “symposium” with only invited university professors as participants. One chooses a nice subject like “The Impact of Mathematics on Society in the Eighties” or “The Role of Mathematical Education in Preparing for the Future” or any other nil-topic. They are so flattered, they come in as an eager flock, proudly carrying their badges home when it is all over. It is pathetic! But also absolutely effective! Did you know that our Differentiation Kit is now used at 378 universities, all over the world? All their alumni will have to subscribe to our “Journal of Kit Differentiation” for the rest of their lives, if they want to remain up to date. The whole movement has now such an impetus that it proceeds without us pushing it anymore; the French have already founded a separate Society for Theoretical Kit Differentiation. It is the same story with our Linear Algebra Kit, our Integration Kit, and our Statistics Kit. It fully absorbs and paralyzes them, leaving the field open for us. Our only obligation is to modify the Kits regularly, that is, to change their appearance slightly, just enough to suggest progress. And really, the universities love them: they always fall for the newest model! They feel themselves superios to the other backward universities and colleges that have not yet converted to Kit Mathematics.

You know that the overall economic, political, and social aspects of this whole venture interest me more than the purely technical issues. But the latter are intriguing too! As soon as Mathematics Inc. grew beyond one hundred employees —can you remember how long ago that was? it seems ages...— it was clear that, no matter what we would tackle, the diversity of our products and manufacturing techniques would create havoc from the organizational point of view. As standardization of products is only possible to a very limited extent —the market place somehow insists on variety— we had to standardize our manufacturing techniques. And we are proud of our IR System for Integrated Reasoning, and I think justly so. In the beginning the IR System was not too successful, because we needed a computer and chose the then fashionable 1033-alpha, a machine for which the MTBF transpired to be of the order of magnitude of twenty minutes. The IR Systems works much better since we have replaced it by the new model 1035-omega, for which via a switch on the console the parity check can be disabled. As soon as we had the new machine, IR made significant progress: the whole IR System now consists of the following languages:

ASL | Axiom Statement Language
LSL | Lemma Statement Language
TSL | Theorem Statement Language
PSL | Proof Statement Language
PVL | Proof Verification Language
PRL | Proof Refuting Language (our main debuggin aid)
IL | Inference Language.

Their mutual relation is roughly as follows

[picture] | Legenda: | arrows denote causal connection.
[picture] | means that the vertical one controls the horizontal one.

Actually this is a slight simplification, because it refers only to the high-level languages PVL, FSL, and PRL, while we have the corresponding low-level languages pvl, ps1, and prl as well: they are only needed when the IR-facilities need more efficient exploitation. As you see immediately from the above diagram, ASL, LSL and TSL are purely syntactic languages without any semantic contents, PSL is a language with an ambiguous, nondeterministic syntax and only first-order semantics, while only PVL and PRL have second-order semantics. IL —although we call it Inference Language for the sake of homogeneity— is, of course, no language at all: it is no more than the specification of the interpretation that can supply quasi-semantics for ASL, LSL, and TSL. It is amazing that people have never thought about the coupling of reasoning controlling activities, but once you have got the idea, it is clear that the above scheme provides all the facilities you may ever need. Our IR System —which, of course, is for internal use only— has been very successful. (I have heard rumours that the application of PRL to Riemann Proof will require a 1033-omega-super, extended with a quadruple-length complex arithmetic unit. Some guys are so fanatic that they want to order one, but —thank goodness!— I hold the purse strings, and I think that I can convince them that also in this case we had better stick to the company policy —which, after all, has always been very successful— of leaving the last stage of quality control to those rare customers that think that they ’really need that extra quality.)

Needless to say, I consider the main benefits of the IR System to be psychological and sociological: the presence of the tool has effectuated more homogeneity in the company than regulations could ever have achieved. There was a time that our topologists could not communicate with the number theorists, they lived in different worlds, although they could work on the same floor! But the IR System provides a standard, common universe of discourse, and, again they understand each other. You can believe me or not, but the other day I saw one guy of the Riemann Group and another guy from the Four Colour Project exchange a few IL-cards! I cannot describe to you how happy that observation made me: at that moment I knew that I had founded a living company. Semper floreat et crescat!

Yours ever,

| Edsger W.Dijkstra, Chairman
| Mathematics Inc.
| Hosanna Building

PS. Secret! We are, of course, constantly trying to protect our company against the possible consequences of changing attitudes, and we are not blind to the current anti-intellectualistic undercurrents in our society that rouse popular feeling against Reason. We keenly observe the semi-mystic “back-to-nature” movements that want to do away with organization, with power, with shaving, bra’s and socks. They provide an alibi for the second rate college teacher preaching that “truth is dehumanized if it has to be proved” and “true truth is what one feels to be true” etc. In view of this quasi-religious revival, our third Assistant Vice-President is contemplating —I think that that is the right word for it— an Artifical Devotion Department. (Maybe it is only because his wife presently spends a lot of her time “reviving”. Before the AD Department has materialized, she may have lost interest in revivals or he in her....) In the preparatory stage he has designed Canonical Forms for the Seven Capital Sins, and you should see them: they are absolute beauties! It looks very promising, and this could turn into a very interesting daughter of the company. (End of Secret.)

Solicitors

13 Shyster Lane

Oldcastle-upon-Time

| Your Ref: EWD 475 | 29th February 1975.

Dear Edsger,

I was delighted to hear from you after all these years. My apologies for the delay in replying to your letter, but as you will see, it had to be forwarded to my new address. It was indeed fortunate that you should seek my advice, since my firm represents the International Research Development Corporation. The IRDC is a well-estab1ished non-profit-sharing corporation which seeks to assist creative institutions and individuals to obtain real rewards for their abstract labours. Amongst their clients have been L.D.Vinci, N.Bourbaki, D.Scott, the Department of Machine Intelligence of the University of Edinburgh and the publishers of the Vienna Telephone Directory, to name but six.

To my surprise, it would appear from your letter that Mathematics Inc. has not established a legal department capable of overseeing the protection and exploitation of its creations, and I would therefore suggest that you join forces with IRDC. Contrary to your supposition, recent changes in patent law have enabled Mathematicians to obtain legal protection for their Theorems. IRDC are perhaps the first organisation to take full advantage of this new situation. They have, in conjunction with my firm, started offering their services to Mathematics-based industrial concerns such as yours, and on occasion to individual Mathematicians, although the day of the individual Mathematician is I fear drawing to a close.

I enclose for your information a draft form of the revenue sharing agreement that IRDC would wish you to accept. You will I believe find the provisions most reasonable, although I am afraid they cannot undertake any aspect of the task of theorem maintenance.

Incidentally, although, as you say, it will be necessary at some stage for you to disclose the Proof of your Theorem, it has become the fashion to do this by providing what is called an Implementation, which can be given in such excruciating detail that you need have no fear that your competitors would find it more profitable to understand the proof than to sign a Royalty agreement. Thus, our last patent, for one of the gentlemen named above, contained no fewer than 2973 lemmas, and was based on a novel extension, to three dimensions, of Petri-Net Theory.

I look forward to hearing from you and to joining you for dinner at the Bali. My secretary’s assistant will make the detailed arrangements by telephone.

Yours most sincerely,

| Jonathan Pettifogger.

E.W.Dijkstra,
Chairman,
Mathematics Inc.
Hosanna Buildings,
Plataanstraat 3
NUENEN
The Netherlands

REVENUE SHARING AGREEMENT:

T H I S         A G R E E M E N T     is made the day of                     One thousand nine hundred and seventyfive B E T W E E N EDSGER WYBE DIJKSTRA of plataanstraat 5 Nuenen (hereinafter called ”the Mathematician“ which expression shall include his legal personal representative) of the first part MATHEMATICS INC. (hereinafter called ”the Institution“) of the second part and The INTERNATIONAL RESEARCH DEVELOPMENT CORPORATION (hereinafter called”the Corporation“) of the third part

W H E R E A S     by an Assignment of even date herewith and made between the parties hereto the Mathematician and the Institution assigned to the Corporation the full benefit of the theorems and relative Applications for Letters Patent particulars of which are set out in the schedule hereto and it has been agreed that the Corporation shall endeavour to secure the exploitation of the said theorems upon the terms hereinafter contained

NOW IT IS HEREBY AGREED by and between the parties hereto as follows:-

SUBJECT as hereinafter provided the Corporation shall use all reasonable endeavours having regard to the circumstances prevailing from time to time to secure the exploitation of the said theorems in such manner (including the sale thereof) and upon such terms as it shall in its sole discretion deem fit

SO far as their commitments allow the Mathematician and the Institution shall from time to time upon request by the Corporation furnish the Corporation with any drawings models designs lemmas technical data information (including computer programs and manuals if any herein called Works) or ”know-how“ in their possession relating to the said theorems and the Mathematician shall make available to the Corporation or as the Corporation may reasonably require any consultancy services which may be necessary to further the exploitation of the said theorems.

THE Corporation shall keep accounts showing:

gross receipts of the Corporation (as hereinafter defined)

costs fees and expenses of the Corporation (whether external or internal) in connection with this Agreement in respect of the following:

the filing and prosecution of Patent Applications and the procurement and maintenance of Letters Patent or like protection

proceedings before the Patent Office or any appeal tribunal therefrom in any country

professional advice on patent matters relating to the said theorems or otherwise incidental to the implementation of this Agreement

proceedings by or against the Corporation in any Court or Tribunal in any country for the enforcement or defense of any Letters Patent to which this Agreement applies or for revocation of or opposition to any Letters Patent or Applicaction therefor of any third party or for any other cause (including any costs or sums awarded against the Corporation in any such proceedings)

the preparation and stamping of legal documents

agents’ commission

payments (if any) made by the Corporation to the Mathematician and the Institution in reimbursement of expenses incurred in applying for Letters Patent in respect of the said theorems or for any items or services provided by the Inventors or the Institution under the provisions of Clause 2 hereof

travelling and out-of-pocket expenses and other direct expenditure incurred by the Corporation in furtherance of its obligations under this Agreement

AS soon as possible after the last day of December in each year commencing with the last day of December One thousand nine hundred and seventy-five the Corporation shall render to the Institution a cumulative statement showing the receipts and expenditure of the Corporation for the preceding year (or any period longer than a year or any proportion thereof) under the headings in sub-clause (1) of this Clause and the Institution shall render to the Corporation at the same time a statement of any expenditure of the Institution and the Mathematician for the same period which it may have been agreed by the Corporation shall be amortised as hereinafter provided

THE gross receipts shall be absolute property of the Corporation but the Corporation shall pay to the Institution annually such sum as shall(when aggregated with previous payments) amount to the greater for the time being of:

five per centum (5%) of the cumulative gross receipts

or

fifty per centum (50%) of the net amount for the time being remaining after amortization out of the cumulative gross receipts of the aggregate of: -

the costs fees payments and expenses of the Corporation referred to in paragraphs (B) (C) and (D) of sub-clause (1) of this clause and

any expenses of the Institution and the Mathematician which it may have been agreed by the Corporation shall be amortized out of the gross receipts

THE costs fees payments and expenses referred to in sub-clause (3)(II) of this Clause shall be amortized in proportion to the respective amounts arising under sub-paragraphs (i) and (ii) thereof and the amount of the expenses of the Institution and the Mathematician so amortized shall be paid to the Institution from time to time as provided in sub-c1ause (8) of this Clause

THE receipt of the Institution shall be a good discharge to the Corporation for any payments to be made by the Corporation under the provisions of this Clause

THE expression “gross receipts” as used in this Clause shall mean the actual royalties or other sums received from time to time by the Corporation in respect of the exploitation of the said theorems(including the amount of any damages awarded to the Corporation in any infringement proceedings) or of any drawings models designs lemmas technical data information or know-hov furnished to the Corporation pursuant to Clause 2 hereof but excluding any sums received by the Corporation in respect of or relative to the recovery of expenditure incurred by the Corporation in the development of the said theorems There shall be added to such gross receipts the amount of any income tax deducted therefrom before receipt

WHERE the said theorems are exploited in conjunction with other theorems and patent rights owned by the Corporation in such manner that the Corporation receives royalties or other sums in respect of all such theorems and patent rights without distinction as to the amount deriving from each such theorem the gross receipts attributable to the said theorems shall be as determined by the Corporation

PAYMENTS by the Corporation pursuant to sub-clause (3) and (4) of this Clause shall be made annually on or before the last day of March in each year

EACH of the parties hereto shall (on request) produce to any duly authorised representative of the other parties for inspection the accounts of its receipts and expenses referred to in this Clause and any receipts or vouchers relating thereto

NOTHING in this Agreement contained shall be construed as requiring the Corporation to develop and maintain or to assist or procure the development and maintenance of the said theorems nor as precluding the Corporation from developing and maintaining or assisting or procuring the development and maintenance thereof on such terms as it may in its sole discretion deem fit But no expenditure incurred on such development and maintenance and no sums recovered in respect thereof or relative thereto shall be included in the accounts referred to in this Clause I

BEFORE abandoning any Application or witholding payment of any fee necessary for procuring or keeping in force any Letters Patent (which expression shall include any like form of protection) to which this Agreement applies the Corporation shall use all reasonable endeavours to give to the Institution adequate notice of its intended course of action and for the period of three months thereafter(if so required by the Institution and if and so far as practicable) to procure the continuance of the prosecution of the Application or the grant or maintenance of the Letters Patent PROVIDED THAT the Institution shall pay or indemnify the Corporation against all costs and expenses incurred in such period in so doing

EXCEPT in regard to any Application and Letters Patent referred to in sub-clause (1) hereof which the parties may agree shall continue to be prosecuted or maintained by the Corporation after the period therein referred to (whether at the expense of the Institution or otherwise) the Institution shall have the right at any time within three months after the receipt of notice under such sub-c1ause to the re-assignment of the Applications and Letters Patent therein mentioned which are still subsisting upon payment by the Institution to the Corporation of the costs of such assignment and of the expenditure of the Corporation in respect of the Applications and Letters Patent so assigned and certified by the Corporation’s Accountant as not having been amortized under suh-c1ause (4) of Clause 3 hereof

ANY assignment of any Applications or Letters Patent to the Institution under the provisions of sub-c1ause (2) of this Clause shall be subject to the provisions of any Agreements or other arrangements which the Corporation shall previously have entered into relating thereto and unless all Applications and Letters Patent to which this agreement gar the time being applies are so assigned there shall be reserved or granted to the Corporation under the Letters Patent and Applications so assigned the irrevocable right to make use and sell without payment of royalty and to grant sub-licence for such purposes ’

EXCEPT as hereinbefore provided the Corporation shall not be liable to prosecute any Application or to procure or maintain in force any letters Patent to which this Agreement applies

THE Mathematician and the Institution shall not at any time oppose the grant of or dispute the validity of any Letters Patent or like protection to which this Agreement applies or any of the claims thereof or assist or advise any person so to do

THE Corporation shall not be under any obligation to institute or defend any legal proceedings whether for infringement or otherwise in respect of any Application or any Letters Patent or like protection to which this Agreement applies

NOTHING herein contained shall be deemed to constitute partnership between the parties hereto or to constitute the Corporation as the Agent of the Institution or the Mathematician

THE Institution and the Mathematician shall not nor shall any of them assign this Agreement or any of their rights benefits liabilities or obligations thereunder except with the previous consent of the Corporation

THE Mathematician and the Institution shall: -

consult with the Corporation (so far as they are free to do so) as to the desirability of applying for Letters Patent in respect of the results of any further research or as to exploitation of any 1 program produced by them (or any of them) relating to the said theorems in reasonable time before making such results or any part thereof available for publication or commercial use

keep the Corporation informed from time to time of the results of any such further research as aforesaid (so far as they are free to do so)

keep the Corporation informed of any commitments or arrangements entered into or undertaken by them (or any of them) which restrict or prevent the fulfilment of this Clause and Clause 2 of this Agreement

IN this Agreement the expression “the said theorems” shall wherever the context permits include all patent rights (being Letters Patent or like protection and Applications therefor in any parts of the world) in respect of the said theorems and shall (whenever appropriate) be deemed also to include any further theorems and patent rights which by agreement between the parties hereto are assigned to the Corporation for exploitation on the terms of this Agreement

IN so far as the Institution or the Mathematician or any of them may control or write future Works particularly adapted for use with or relating to the said theorems the Institution and Mathematician will consult with the Corporation as to the assignment of all rights in the future works to the Corporation for exploitation upon the terms hereof (the copyrights being included in the term patent rights and Works in the term Theorem) all before any part thereof is made available to others save only a supply for usage for a non commercial purpose by a user under .contract (in a form approved by the Corporation) to maintain the Works confidential

ANY such assignment agreed shall include undertakings to supply copy of the Works to the Corporation and to keep the Works confidential

ANY notice consent or other communication authorised or required to be given hereunder or for the purpose hereof shall be deemed to be duly given by the Corporation if left at or sent by recorded delivery post to the Institution at its principle address or to the Mathematician at his last known address and in the case of a notice given to the Corporation if left at or sent by recorded delivery post to the principle office of the Corporation

ANY dispute question or difference arising under this Agreement as to the rights or duties of any of the parties or the construction or effect of any of the provisions of this Agreement shall be referred to an Arbitrator to be agreed between the parties and in default of agreement to be nominated by the President for the time being of The Law Society and such reference shall be deemed to be an arbitration agreement within the meaning of the Arbitration Act 1950 or any re-enactment or modification thereof for the time being in force

IN WITNESS whereof the Mathematician has hereunto set his hand and seal and the Institution and the Corporation have caused their Common Seals to be hereunto affixed the day and year first above written

THE SCHEDULE above referred to

Application No. | DATE | Title of Theorem | Mathematician.
16766/75 | 9 February 1975 | Riemann Theorem | E.W.Dijkstra

SIGNED SEALED and DELIVERED
by the above named EDSGER WYBE
DIJKSTRA in the presence of:

THE COMMON SEAL of MATHEMATICS
Inc. was hereunto affixed in the
presence of:

The COMMON SEAL OF THE
INTERNATIONAL RESEARCH DEVELOPMENT
CORPORATION was hereunto affixed and authenticated by:

Authorised by the Corporation

Secretary

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-08 .

  EWD 540

Two views of programming

by Edsger W. Dijkstra

In the world around us we encounter two radically different views of programming:

View A: Programming in essence is very easy.
View B: Programming is intrinsically very difficult.

One can dismiss this discrepancy by concluding that, apparently, in the two views the same word "programming" is used in two quite different meanings, and then return to the order of the day. Whether view A or view B is the predominant one, however, has a deep influence, not only on the personnel policy of computer using organizations and on the curriculum policy of our educational institutes, but even on the direction of development and research in computing science itself. It seems, therefore, worthwhile to explore the nature of the difference between the two meanings and to identify, if possible, the underlying assumptions that would make each of them appropriate. To do so is the purpose of this paper.

In this exploration I have what could be regarded as a handicap: in the controversy I am not neutral at all. I am a strong supporter of view B and regard view A as the underlying cause of many mistakes. On the other hand I don't think that having an opinion disqualifies me as an author, certainly if I warn my readers in advance and do not feign a fake neutrality. As our analysis proceeds we shall discover how these different views of programming (which is a human activity!) are related to different types of Man. This, all by itself, is already a valuable insight, as it explains the nearly religious fervour with which the battle between the defenders of the opposing views —creeds?— is sometimes fought.

*                      *
*

The early history of automatic computing makes view A only too understandable. Before we had computers, programming was no problem at all. Then came the first machines: compared with the machines we have now they were mere toys, and, compared with what we try to do now, they were used for "micro-applications" only. If at that stage programming was a problem, it was only a mild one. Add to this the sources of difficulties that at that time absorbed —or should we say in retrospect: usurped?— the major part of our attention:

1)    arithmetic units were slow with respect to what we wanted to do: that shoe pinched nearly always, and in the name of program efficiency all possible coding tricks were permitted (and very few were not applied)

2)    design and construction of arithmetic units were such a novel and, therefore, difficult task that if a next anomaly in the instruction code could save a number of flip-flops, the flip-flops were usually saved —also, of course, because we had so little programming experience that we could not recognize "anomalies in the instruction code" too well—; as a result there was, besides pressure to apply coding tricks, also a great opportunity for doing so

3)    stores were always too small, a pinching shoe that, together with the general unreliability of the first hardware, prohibited more sophisticated ways of machine usage.

In that time programming presented itself primarily as battle against the machine's limitations, a battle that was to be won by a cunning, be it not very systematic, exploitation of each machine's specific properties: it was the heyday of the virtuoso coder.

In the next to ten to fifteen years processing units became a thousand times faster, stores became a thousand times larger, and high-level programming languages came into general use. And it was during that period, when on the one hand programming was still firmly associated with the pinching shoe, while on the other hand the shoe was felt to pinch less and less, that it was expected that with another five years of technical progress the problems of programming would have disappeared. It was during that period that view A was born. It was at the end of that period that, inspired by view A, COBOL was designed with the avowed intention that it should make programming by professional programmers superfluous by allowing the "user" —was it at that time that the term "user" gained currency?— to write down what he wanted in "plain English" that every one could read and understand.

We all know, that that splendid dream did not come true. The next five years gave us, instead of the disappearance of all programming problems, the software crisis, and COBOL, instead of doing away with professional programmers, became the major programming vehicle for ever growing numbers of them; and another ten years later we still have machines with which flaws in the basic software cause on the average one hour down-time for every fifteen hours of production. There are, apparently, still serious programming problems ....

The amazing thing is that, in spite of the overwhelming evidence to the contrary, view A survived. In explaining that amazing thing fact some point with a somewhat accusing finger to large organizations, either to computer using ones that, having atttacted a large labour force based in view A, thereby have lost the freedom to part from it, or to computer manufacturers and educational institutes that promote a widely-held view A, that they are supposed to suppose essential for their market. Even if that finger is not raised without some justification, I just cannot accept it as a full explanation of view A's survival, and must assume that view A satisfies some deeper, psychological needs.

*                      *
*

How emerged view B? There were people who felt that the advent of faster and bigger machines would replace the pinching shoe at most by a fitting shoe, and that, therefore, the economics of program execution would remain a serious concern of the programmer, a concern that would even become more important as size of machines and applications would grow, and, with more complex installations, would pose more difficult problems. Also it was observed that switching from machine code to a high-level programming language did not guarantee all the benefits that were hoped for. In particular, programmers still produced, as willingly as before, large chunks of ununderstandable code, the only difference being that now they did it on a more grandiose scale, and that high-level bugs had replaced low-level ones. They also realized that the advent of high-level programming languages had not reduced the essential need for accuracy: redundancy in high-level programming languages only reduces the ill effects of some inaccuracies. And thus view B was born. (View B is NOT the reaction to the software crisis that surfaced in 1968, for it is many years older. View B had, in fact, predicted that crisis, but even that confirmation has not killed view A.)

*                      *
*

After this interlude about the emerging of view B, we return to our question, how and why, face to face with the undeniable software problems, view A, viz. that programming is in essence very easy, survives. The answers is: by faith, not faith in better programmers, but faith in better programming languages or (conversational?) programming services, and faith in better management techniques.

I happen to be of the considered opinion that programming is one of the more difficult branches of applied mathematics, because it is also one of the more difficult branches of engineering, and vice versa. When I tried to explain to one of my mathematical colleagues why I held that view, he bluntly refused to listen to my arguments and, instead, blamed me and my fellow computing scientists for not yet having designed the programming language that would make programming as easy as it should be! Should I have asked him, why mathematicians have not developed a notation that would enable everyone, no matter how ill-equipped otherwise, to do mathematics?

After more probing one discovers that the proponents of view A do not deny the potential complexity of programs, nor the problem of composing them, but believe that life will become easy for the programmer because all the more difficult parts of the task will eventually taken over by the machine. They point to the advent of high-level programming languages that made programming already so much easier than in the old machine code days, and recklessly extrapolate, that in the future programming will become trivial. But is this extrapolation justified? I have programmed extensively, both in machine codes and high-level programming languages, and the latter are undoubtedly more convenient because all sorts of otherwise irrelevant decisions with many clerical consequences —such as details of storage layout— need not be taken explicitly because one accepts the outcome of the compiler's storage allocation algorithm. The transition to a high level freed us from a number of trivia. In doing so, it has made programming an activity with a smaller component of drudgery, and therefore with a larger component of invention: precisely those parts of the job with one used to fill the day when feeling less bright, are the ones that have disappeared! The conclusion that the advent of high-level programming languages has created the need for programmers of higher intellectual caliber has been fully confirmed by my observations in Western Europe (where I could follow the development at close quarters) where in the late sixties many large computer using organizations had problems in finding appropriate employment for the programmers they had attracted in the fifties, because their profession had outgrown their intellectual capacities.

But neither this observation, nor pointing out COBOL's failure to do away with professional programmers, makes any impression upon the faithful. They will explain that the traditional high-level programming languages were failures because they were still "procedural", and that COBOL's failure is evident because, for lack of interaction, it is not really plain English, but that within five or five or ten years further progress in Artificial Intelligence (AI for the intimi) will enable us to build "context dependent", "knowledge-based","automated systems for reasoning and understanding" such that the "user needs only talk to them".

I may be an incurable sceptic, but I find it very hard to believe such claims to be justified. They are specific instances of the expectation that we shall witness — I quote from a letter I recently received— ", in general, the assumption by the computer of progressively higher levels of what now is considered human skill, knowledge and intelligence." It is not my intention of to repeat parts of heated discussions we have had about the significance of Artificial Intelligence (see, for instance, [1]), nor is there any need to do so.

Firstly, looking backwards, one conclusion is certain: confusing AI's hopes for the future with tomorrow's reality would be folly, and it would be an act of utter irresponsibility not to prepare ourselves for the case that the dreams of AI will remain dreams as long as we live. Or, to put it in other words, in view of the severity of today's programming problems, general cautiousness forces us not to discard view B.

Secondly, if his creations are going to be relied upon, it will be the programmer's primary task to design his artifacts so understandable, that he can take the responsibility for them, and, regardless of the answer to the question how much of his current activity may ultimately be delegated to machines, we should always remember that neither "understanding" nor "being responsible" can properly be classified as activities: they are more like "states of mind" and are intrinsically incapable of being delegated.

*                      *
*

I think it unwise, particularly for a computing scientist, to underestimate the influence of that school of psychologist that, because they found the human mind too difficult and elusive an object for their study, turned to the study of rats instead, and even restrict that study —as I saw expressed recently— "to the most mechanical forms of behavior —often so mechanical that even rats have no chance to show their higher faculties—". By presenting their crude, mechanical models as a valid approximation for the human mind, they have blurred the distinction between man and machine dangerously, and we observe the two complementary phenomena: an anthropomorphic view of machines and a mechanical view of people.

This confusion is by no means confined to the high priests of AI. The preponderance of anthropomorphic terminology in computing science in general —"memory", "interpreter","programming language", "handshaking", "conversation", to mention but a few— is a warning not to be ignored. I would not know how to think and talk without metaphors; I also know that each metaphor carries with it the danger of false connotations. In the case of the anthropomorphic terminology in computer science we have since long reached the stage that the dangers of confusion far outweigh the benefits of the analogy.

Also the mechanical view of people seems among computing scientist (and their managers) more widely spread than I consider healthy. For I suspect that it is this mechanical view that restricts the activity of programmers to the mechanical activity of writing code, and then measures "programmer productivity" by the number of lines of code produced. (When a very well-known and widely respected computer scientist recently used that measure for programmer productivity in a lecture, the suggestion came from the audience that, instead of talking about "the lines of code produced" we should talk about "the lines of code used" and that, therefore, the speaker was booking them on the wrong side of the ledger. The speaker answered that he stuck to his productivity measure, because he did not know of any alternatives that allowed proper quantification!) This can no longer be classified as a harmless mistake, for the adoption of that nonsensical "productivity measure" for grading programmers is guaranteed to promote the writing of insipid code.

*                      *
*

The influence of psychology has been brought into the picture because it explains the tenacity with which so many people cling to view A.

It is not so much the computer manufacturers, that want to do as if they sell an easy product; it is not so much the managers of software projects, that would like to view the programming activity as a simple and predictable one; it is not so much our educational institutes, that would like to train their students with predictable success.

It is the comfortable illusion of Man as elaborate automata that, like a drug, seems to have freed its victims from the burden of responsibility. Accepting programming as a hard intellectual challenge would place the full weight of that burden back upon their shoulders.

[1] Flowers, B.H. "Artificial Intelligence: a paper symposium" April 1973, Science Research Council, State House, High Holborn, London WC1R 4TA.

Plataanstraat 5 NL–4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Jorge A. Pérez Parra
revised Fri, 25 Mar 2005

4 december 1975 EWD 541

Dertiende en laatste toespraak, najaar 1975.

Bij het begin van dit semester heb ik U uitgelegd, waarom ik nog college geef; aan het einde van het semester beland wil ik U graag uitleggen, waarom ik elke week mijn dagopening gehouden heb.

Ik heb nog meegemaakt hoe door de tweede kamer de wijziging van de wet op het hoger onderwijs werd aangenomen, waarbij deszelfs taak werd uitgebreid met, ten eerste, het tonen van de samenhang der wetenschappen, en, ten tweede, het bevorderen van maatschappelijk verantwoordelijkheidsbesef. Wie de handelingen van de tweede kamer uit die tijd er op naleest, zal zien dat —om maar eens wat sterke termen op elkaar te stapelen— deze twee krankjoreme uitbreidingen het wanproduct waren van een smerig stuk koehandel waar zelfs de honden geen brood van lusten.

Met die achtergrond is het haast pathetisch om the zien hoe jonge mensen, die toen de krant nog niet lazen, deze passages nu als hun evangelie accepteren en als morele maatstaf proberen te hanteren. Pathetisch, en ook verontrustend, want het betekent, dat elke wet, hoe rot ook, het gevaar loopt als Wet met een hoofdletter W een eigen bestaan te gaan leiden. Van de oudere mensen, die hen nu omarmd hebben, kan je alleen met schouderophalen opmerken, dat ze toch beter moesten weten.

De bepalingen zijn, als je er even over nadenkt, natuurlijk krankzinnig! Wat betreft dat tonen van de samenhang der wetenschappen had daar ten minste de proviso "voorzover aanwezig" bij moeten staan. Veel erger is, dat dit artikel de wenselijkheid van zo'n samenhang suggereert, een wenselijkheid waarbij ik en velen met mij een heel groot vraagteken zetten. Wie zich namelijk in de vraag verdiept, waaraan wetenschappelijke disciplines hun levensvatbaarheid ontlenen, komt daarbij de isoleerbaarheid tegen: als de samenhang en de wederzijdse interacties te sterk zijn, is de interface tussen de disciplines onhandig gekozen.

Maar het hoger onderwijs betaalt de tol: advertenties bij vacante leerstoelen suggereren dat voor de nieuwe hoogleraar zijn bereidheid tot samenwerking zeker zo belangrijk is als zijn professionele competentie, en wie aan deze TH nog iets op poten wil zetten, doet er goed aan dat dan wel als interafdelingsproject aan te kleden, want anders ligt het ideologisch niet zo lekker.

De tweede uitbreiding, die van het aankweken van maatschappelijk verantwoordelijkheidsbesef, is zo mogelijk nog erger. Niet dat ik enig bezwaar tegen verantwoordelijkheidsbesef —in welke vorm dan ook— zou hebben, in tegendeel, maar je kunt een wetenschappelijke instelling niet met die aankweekplicht opzadelen , zonder diezelfde instelling daarmee op te dragen de grenzen van haar competentie te overschrijden. Een van de gulden regels uit mijn ouderlijk huis is nog altijd "Praat niet over dingen, waar je geen verstand van hebt!"; voor mensen en instellingen met een gebreveteerde competentie geldt het verbod van deze grensoverschrijding met des te meer klem.

En ziet, onder dekking van een wetsartikel, dat ik grondig verfoei, kan ik nu allen, van wie het zo nodig moest, wekelijks een koekje van hun eigen deeg geven. En dat dat koekje misschien wel eens een beetje anders uitpakt dan zij voorzien en bedoeld hebben, tja.... U begrijpt, dat de verleiding onweerstaanbaar was.

Na aldus voor het laatst tot Uw maatschappelijke vorming te hebben bijgedragen, ga ik over tot de orde van de dag.

transcribed by Jukka Ketelaars
revised Sun, 17 Jun 2007

EWD542

Ik zal U gezamenlijk toespreken. Had U ieder Uw eigen toespraak willen hebben, dan had U maar niet tegelijkertijd moeten afstuderen. Ter geruststelling kan ik U verzekeren, dat ik bij de voorbereiding dubbel mijn best gedaan heb. Het is evenwel niet alleen de coincidentie der afstudeermomenten, noch de coincidentie van Uw beider pril vaderschap, die een gemeenschappelijke toespraak rechtvaardigt, want evenveel redenen kunnen gevonden worden in de gelijksoortigheid van Uw afstudeeropdrachten, de ondernemende wijze waarop U Uw opdracht vervuld hebt, en de overeenkomst van Uw eerste werkkringen.

U had beiden een vrij concrete afstudeeropdracht: een duidelijk probleem is U als kluif toegeworpen met de opdracht, om daar de kiezen dan maar eens in te zetten. U hebt beiden Uw kluif niet onverdienstelijk afgekloven en Uw bevindingen gerapporteerd in een afstudeerverslag, aan de beperkte omvang waarvan menig afstudeerder een voorbeeld nemen kan. U hebt beiden —en dat mag gememoreerd worden, omdat het aan de uiteindelijke getypte versies niet meer te zien is— mij een manuscript —en dit nu in de letterlijke betekenis van "een handschrift"— getoond, waaruit zonneklaar bleek, dat U geleerd hebt goed te schrijven. Ik heb dat bijzonder gewaardeerd en als U zich later ooit geroepen mocht voelen, mij een brief te schrijven, zal ik hem met vreugde lezen.

In zekere zin betreur ik het om Uwentwil, dat U niet vijf jaar jonger bent, want nu, in het jaar onzes Heren 1975, in de informatica afstuderend, bent U duidelijk afgestudeerd in een nog onvolwassen vak. Ik bezig hier met nadruk de term "onvolwassen" en niet de term "onaf": een levend vak is nl. nimmer "af", in die zin dat het verder ontwikkeld wordt en de focus van zijn aandacht steeds verlegd wordt. In een volwassen vak mag een dergelijke verschuiving van de aandacht zelfs de naaste vakgenoten verrassen, en hoeft er ook geen communis opinio te bestaan ten aanzien van relevantie en belofte, maar is men het doorgaans onderling wel roerend eens over de kwaliteitsnormen, omdat deze inmiddels hun waarde en zelfs noodzaak hebben bewezen.

De informatica heeft dat stadium nog niet bereikt. Het is een jong vak. De geboorte lag voor het begin van Uw studententijd; wat U in Uw studentijd ervan hebt meegemaakt, reikt zowat van de kleutertijd, wanneer de eerste symptomen van zindelijkheid zich beginnen af te tekenen, totaan de eerste puberteitspuistjes, de eerste schaamharen, en de eerste duidelijke symptomen van onzekerheid over eigen identiteit, de tijd waarin men zich zowel verschoppeling voelt als jonge god.

Ik ben oprecht de mening toegedaan, dat U zich een vak hebt gekozen, dat zich —naar ik vurig hoop met Uw hulp, maar anders zonder— zal manifesteren als een werkterrein par excellence voor de goede wiskundige ingenieur. Ik kan nl. het vak slechts zien als een van de moeilijkere takken der toegepaste wiskunde, omdat het tevens een van de moeilijkere ingenieurswetenschappen is, en vice versa. Niet iedereen voelt dat ook zo aan, maar als ik tijd van leven heb maak ik me geen zorgen gelijk te zullen krijgen, want ik ben in dezen ervan overtuigd gelijk te hebben. Ik wil niet verhelen, dat er voordien nog een heleboel water vloeien moet door de Dommel, die maar een klein riviertje is...

De ambivalente houding der wiskunde, die, verrast door de haar onbekende combinatie van uiterste eenvoud en onvermoede complexiteit, de informatica beurtelings negeert, dan wel overspoelt met haar in eigen ogen relevantia, zal waarschijnlijk wel voortduren totdat —om met enige vrijheid Max Planck te citeren— de huidige generatie wiskundige smaakmakers onder de groene zoden ligt. U begrijpt, dat ik hoop oud genoeg te worden om niet mijn gelijk pas van een wolk te hoeven gadeslaan, en besef dat U, bijkans een generatie jonger, in dezen op mij een onmiskenbare voorsprong hebt.

De houding van het collectivum dat ik gemakshalve als "de gebruikers" aanduid, is nauwelijks geruststellender: U hoeft maar even verder te kijken, om U ervan te overtuigen, dat bv. een stuk academische zelfkant staat te trappelen om de glorie der informatica te usurperen, zonder zich te willen onderwerpen aan de harde intellectuele discipline, waaraan deze glorie in laatste instantie ontleend is.

Is het een wonder, dat de informatica over eigen identiteit wat aarzelt?

*                          *
*

Te midden van die puberteitspuistjes gaat U beiden naar een universitair rekencentrum, de plaats bij uitstek, waar iedere medewerker met de neus in de conflicten gedrukt wordt, die van onbegrip het onvermijdelijk gevolg zijn. U zult wel eens aan een heleboel moeten kunnen wennen. Het is niet ongebruikelijk, dat een rekencentrum weinig waardering heeft voar de leverancier van zijn apparatuur; daar moet U misschien wel aan wennen. Het is eveneens niet ongebruikelijk, dat een rekencentrum niet veel respect kan opbrengen voor het merendeel van zijn klanten; daar moet U misschien ook wel aan wennen. Het is ook niet ongebruikelijk, dat een rekencentrum de verlangens —hoe onzinnig ook!— van zijn minst gerespecteerde klanten vakkundig mobiliseert om de volgende apparatuuruitbreiding gerealiseerd te krijgen, opdat de minderheid die wel respect afdwingt nog aan zijn trekken komt; daar moet U misschien ook aan wennen. U zult daarvoor veel wijsheid moeten opbrengen: de wijsheid meer te gedogen, dan U lief is. Enig cynisme wil ook wel eens helpen. Als ik ook in dezen tot Uw vorming heb bijgedragen, prijs ik me gelukkig als opvoeder niet vergeefs gewerkt te hebben.

Ik gun U beiden in Uw werk een zaak, waardig om U ten volle aan te wijden. Als U uw taak niet te nauw opvat —en daar heb ik alle vertrouwen in— zult U zulke zaken in Uw eerste werkkring zeker vinden, en ik laat U dan ook met een gerust hart daarheen vertrekken. Dat op die weg mijn beste wensen U vergezellen, hoeft U niet als blijk van wantrouwen of twijfel uit te leggen.

Van verder commentaar op, bijvoorbeeld, hoe wij van een geleide economie naar een geleide cultuur dreigen af te glijden, zal ik mij op dringend verzoek van de Dekaan onthouden, en dus rest mij slechts U en allen aan wie U dierbaar bent, uit het diepst van mijn hart geluk te wensen met Uw zo succesvol passeren van de mijlpaal, die onder de naam "Ingenieursexamen" bekend staat.

transcribed by Marielle Winarto
revised Fri, 28 Nov 2008

EWD543

29 december 1975

Eerste toespraak tot mijn studenten, voorjaar 1976.

Over de gewelddadige dood van Archimedes, na de val van Syracuse in 211 B.C., zijn twee versies in omloop; zij schelen echter zo weinig, dat zij zonder bezwaar in een verhaal vervlochten kunnen worden. Na de verovering van Syracuse stuurde de nieuwe Romeinse Befehlshaber een zijner soldaten naar Archimedes om hem bij zich te ontbieden. De oude geleerde was in gedachten verzonken over de tekening, die hij in het zand germaakt had, en wees de indringer met een korzelig "Loop niet door mijn cirkels heen!" terecht. Hierop ontstak de Romeinse soldaat in woede en reeg de vijf-en-zeventig jarige aan zijn zwaard, voor het nageslacht slechts als schrale troost de overweging latend, dat de veldheer Marcellus de oude Archimedes lekker niet meer heeft gesproken. Het ware ook betamelijker geweest, wanneer Marcellus nederig zelf zijn opwachting by Archimedes was komen maken, maar een dergelijk respect voor de wetenschap kan men van generaals niet verwachten. Ook toen al niet. De Engelse wiskundige en Amerikaanse filosoof Alfred North Whitehead schreef naar aanleiding van deze moord, die voor hem een bijkans symbolische betekenis had, de volgende beroemde passage, die ik U niet wil onthouden:

"The death of Archimedes by the hands of a Roman soldier is symbolical of a world change of the first magnitude; the theoretical Greeks, with their love of abstract science, were superseded in leadership of the European world by the practical Romans. Lord Beaconsfield, in one of his novels, has defined a practical man as a man who practises the errors of his forefathers. The Romans were a great race, but they were cursed with the sterility which waits upon practicality. They did not improve upon the knowledge of their forefathers, and all their advances were confined to the minor technical details of engineering. They were not dreamers enough to arrive at new points of view, which could give a more fundamental control over the forces of Nature. No Roman lost his life because he was absorbed in the contemplation of a mathematical diagram."

Tot zover Whitehead. Is het erg gewaagd te veronderstellen, dat de Engelse aristocraat hier over de band zijn commentaar op de Amerikaanse cultuur geeft? Als die veronderstelling juist is, zou het ons evenwel niet passen, ons trots op de Europese borst te slaan: de waarschuwing is nl. evenzeer van toepassing op het Europa van vandaag waarin door een wijdverbreid onbegrip, waarvan ook onze politici niet verschoond zijn gebleven, de wetenschap een bedreigd bestaan leidt.

Wie de stukken van het huidige zg. wetenschapsbeleid leest, slaat de schrik om het hart: iedere keer weer wordt naar voren gebracht, dat het te entameren onderzoek maatschappelijk relevante vruchten af dient te werpen. Nu geloof ik niet, dat ook maar een wetenschapsman er bezwaar tegen zou hebben, als de vruchten van zijn arbeid tot heil der mensheid worden aangewend. Integendeel zelfs: dit is, wat hij in stilte hoopt. Maar hij is realistisch genoeg om te weten, dat je dat niet verwachten mag. Hij weet, dat wetenschapsbeoefening een nauwelijks gericht tasten is, een verkenning van het per definitie nog onbekende. Hij weet, dat hij blij mag zijn als op de honderd ideeen, die hij uitzaait, er uit eentje een eetbare vrucht groeit. En hij weet ook, dat dit groeiproces vaak zolang duurt, dat hij blij mag zijn, als hij de vrucht nog bij zijn leven in wasdom mag aanschouwen.

De ogenschijnlijk vrije onderzoeker zal op de vraag, waar zijn werk eigenlijk goed voor is, oprecht met een bescheiden schouderophalen reageren. Hem op grond daarvan betichten van een onverantwoordelijk hobbyisme, van "maar wat aan liefhebberen" is dom, kortzichtig en onrechtvaardig.

Overigens ben ik van oordeel, dat op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Tue, 16 Oct 2007

prof.dr.Edsger W.Dijkstra, Burroughs Research Fellow
Plataanstraat 5
NUENEN - 4565
The Netherlands
EWD 544

An open letter to Ross Honsberger.

University of Waterloo.

30 December 1975

Dear Sir,

the other day I encountered your delightful booklet “Mathematical Gems”. On account of Chapter 8, I concluded that you might be interested in the following proof of Morley’s Theorem “The adjacent pairs of the trisectors of a triangle always meet at the vertices of an equilateral triangle.”

Choose α, β & γ > 0 such that α + β + γ = 60�. Draw an equilateral triangle XYZ and construct the triangles AXY and BXZ with the angles as indicated. Because ∠AXB = 180� – (α+β), it follows that, if ∠BAX = α+x, ∠ABX = β – x. Using the rule of sines three times (in △AXB, △AXY, and △BXZ), we deduce

 sin(α+x)  |   =   |  BX  |   =   |  XZ . sin(60+γ)/sin(β)  |   =   |  sin(α) 
sin(β–x) | AX | XY . sin(60+γ)/sin(α) | sin(β)

Because in the range considered, this equation has a left-hand-side which is a monotonically increasing function of x (on account of the monotonicity of sin(φ) in the first quadrant) we conclude x = 0. Thus Morley’s Theorem is proved without any additional lines. I found this proof in the early sixties, but am afraid that I did not publish it. Yours ever,

Edsger W.Dijkstra

transcribed by Corrado Cantelmi
revised 21-Dec-2011

EWD 547

Tripreport E.W.Dijkstra, England and USA, 3 - 26 January 1976.

This time the hardships of travel started weeks before the date of departure, viz. when I tried to order my ticket. On my previous visit of nearly three weeks it had been pointed out that I would have enjoyed a cheaper rate if I had extended my visit with a few days. At that occasion IBM was paying my ticket, so I did not mind, but this time I was travelling at Burroughs' expense. Therefore I inquired about the conditions for the cheaper fare: did it mean 22 days in the USA or 22 days away from home? Burroughs' (new) travel agent told me that the condition was 22 days away from home. With the intention of saving money I extended my trip at the front end with a short visit to England (at the other side of the trip was impossible, for on Tuesday the 27th of January I had to be back at the University). When all was arranged, the travel agency discovered not only that it had given me the wrong information —the fare reduction was now not applicable— but also that with my schedule it did not know how to compute the price, the reason why they phoned me with the urgent request to change my itinerary! In the meantime I was so exasperated that I had no difficulty in resisting to that pressure. The reason for the exasperation was that I had ordered my ticket in the first half of December with the intention of having it in my possession before Christmas: it is always nice not to have to rely upon postal delivery between Christmas and New Year. But in spite of my efforts, this nervous traveller passed the days of Christmas without his ticket.... (After my arrival in the USA I learned that this, however, was not fully the fault of the Dutch travel agency, which had been waiting for the confirmation of an internal flight which did not come through because the America airline reservation information processing system had been inundated by additional transactions resulting from the strike at United Airlines.) I received my ticket —with the flight Chicago-Detroit unconfirmed— just in time.

The other narrow escape was my visa. Some months ago I had tried to have the expiring validity of my passport extended, but because it was already so full of stamps, the Dutch authorities refused to do so and they gave me a new passport. Because my old passport contained an indefinitely valid American visa, it was returned to me with a corner cut from all pages except the one containing my American visa. In addition the new passport contained a note, saying that the old one was to be regarded as an extension. I was given to understand that I could travel with the two passports together and decided to postpone the transfer of the American visa until I would be in Rotterdam anyway. Friday at noon, the day before my departure, this nervous traveller was checking everything, tickets, money, passport, and suddenly I thought: "Let me check that story about the two passports with the American Consulate." So I made a telephone call and was told that a visa in an old passport was not valid, but that they were open and ready to serve me until four o'clock! While collecting my papers I shouted to my wife to get the car keys so that she could take me to the railway station! I made it.....

On the way back from Rotterdam to Eindhoven, trains were not running according to schedule: the storm had started that during that night would reach strength 11 at the scale of Beaufort. Saturday morning we switched on the news, and what we heard was sufficiently alarming to take an earlier train and took me without delay to Amsterdam. Occasionally I saw a fallen tree, an overturned vehicle, and so on, but approaching Amsterdam I saw a plane in the air, and that was reassuring. The driver of the coach from Amsterdam Central Station to Schiphol Airport had some difficulties in keeping his vehicle in lane —it swayed like a drunkard— but that was all. According to schedule I left Schiphol at 12.05 and arrived at Heathrow also at 12.05, thus absorbing the first hour of the time shift. (When I boarded the British Airways plane, the steward offered me an English newspaper; after a glance at the headlines I said "No thank you. The news looks rather depressing." Answered the steward: "Ah... Wait until you arrived there!" A grim welcome...)

Mike Woodger was at the airport to pick me up, and I had a pleasant weekend with him. He helped me by providing me with the English vocabulary that I needed for the description of a few theorems and proofs in Euclidean geometry. On Sunday morning —this is a tradition— we went for a walk through the beautiful Surrey countryside, but this time we kept it short, for rain had made the path very muddy. On Sunday evening a young logician and his wife joined us for dinner; of the conversation thereafter I remember that English poetry was a main subject, Mike's wife going upstairs to fetch an anthology that was needed to settle a dispute.

On Monday morning Mike and I left early for the National Physical Laboratory where I was expected to give a lecture. As I was due at the airport at 11.15 for my flight to Chicago I did not have much time and, in order to speed up the presentation, I prepared the blackboard beforehand. At 9.30 I started, at 10.30 I had covered all the intended material and after fifteen minutes discussion —it was a pity that I had not more time, for the discussion was certainly not finished— I was taken to Heathrow, where Mike dropped me at the doorsteps of the appropriate terminal at 11.14.

The queues at the TWA desks were very long and very slow, and I heard my flight being announced before I had checked in: "...is now boarding at gate so and so." Luckily it was a Boeing 747, for which "boarding" is a long-drawn affair, and I made it, praying that my luggage would make it as well. When we were expected to depart, the captain announced that one of the passengers, who had checked in, had not turned up and that, in order to exclude a bomb in the luggage department, we had to identify our luggage. All trunks and suitcases were unloaded, and the passengers had to come out in groups in order to identify their own baggage. The jumbo being fully loaded, the whole operation took two hours. For once I crossed the Atlantic with the comforting certainty that my suitcase was indeed crossing it with me in the same plane!

I was not worried at all about catching my connection in Chicago. As that was the first flight I had been unable to get confirmed I had already arranged with Dave Dahm who had offered to collect me at the Detroit Airport, that I would call him from Chicago, as soon as I knew by which flight I would arrive. The flight from Chicago to Detroit was no problem at all, at the gate they knew my name and there were enough seats. The only problem was making my first call from an American telephone booth. It was a frightening experience: to discover how to operate such equipment in "unfriendly Chicago" is no trivial matter. Eventually I succeeded and then discovered that, in the course of the proceedings —and, as far as I am concerned, this is also tradition at O'Hare— I had lost my briefcase. I retrieved it by retracing my steps. At 21.14 (their time!) Dave collected me —at least the remains— at the gate in Detroit and took me to the Southfield Holiday Inn, where I should stay for the next four nights.

My room (in "the tower") was icy cold, so I switched on the heating equipment to the best of my knowledge —the instructions were very confusing— and went downstairs, where I ordered what felt I needed: a large glass of cold milk ($1.05 ! I was shocked.). After sipping it up, I returned to my room in the tower, in which the supposed heating equipment was causing a polar storm. I switched off the fan, gave the ambiguous instructions another interpretation and went to bed with the best of possible hopes. After half an hour under the blanket I was so cold, that I put on my clothes again, packed my suitcase and went to the reception to ask for another room. The girl at the desk asked me whether I would accept a room on the ground floor. I explained that I did not care about the place of the room, but about its being warm enough. She then explained her question "All through the tower we have trouble with the heating system." My conclusion was that it was a new hotel, erected by a dumb architect, and I fell asleep, doubting the wisdom of the Holiday Inn Company to try to operate this hotel under these circumstances.

The next morning I was a free man: Dave had offered to leave me alone until lunch, so that I could recover from the trip. I recovered that morning as well as I could. Thinking about last night's experience I concluded that even if the heating equipment itself were OK, it would cause trouble on account of the poorly written instructions, and in an effort to make myself useful and to kill the time, I decided to go to the desk, to ask for the documentation so that I could discover how it should be operated, and then to rewrite the instructions. (I was reminded of the elevator in the new main building of the Technological University Eindhoven, whose instructions for use made sense only after the third effort! Not only English, but also Dutch is difficult....) At the desk I was informed that they had no documentation, but that my effort was not needed either, because the equipment was so lousy anyhow that it would be replaced by something better at the earliest possible occasion.

Tuesday afternoon was my only visit to Burroughs World Headquarters, and the various businesses I had to conduct there took the major part of it. The rest of the time was devoted to more technical discussions, while Dave brought me into the picture. It was quite instructive and I was grateful to him. I was relieved to see that he had to interrupt the conversation several times.... because he had difficulties into getting an ordered airline ticket physically into his possession! It is always comforting to observe that one is not the only sufferer....

The next two days I attended a symposium in generative software. Those were long days for someone who still suffered from the time shift and the cultural shock. Besides that it took me some time to realize that most speakers did not give a lecture, but gave a "presentation", and to realize what that difference meant. An additional difficulty for me was that most speakers came from the area of business applications and those people most definitely speak a special language. I had warned Dave beforehand that in this unfamiliar environment he should not expect any positive contributions from my side, and this he fully understood. I have restricted myself to trying to understand what was going on, in principle only asking for clarification when I really needed it. In some cases I am afraid that I made a nuisance of myself, e.g. when asking for more clarity than the speaker —or should I say: presentator?— could provide. One of them really drove me up the wall, when it turned out that his language was not only special, but also incredibly poor, poorer as a matter of fact than I had witnessed for a long time. He was such an unconscious user of words that he understood none of my requests for linguistical clarification —when I had to ask what was meant by the for me new word "to syntax", I was told that it was used in its normal meaning!— ; such questions were clearly beyond his mental horizon and on this one I gave up. The only consolation was that my exasperation caused considerable merriment among those who understood —and had perhaps expected— this clash of two worlds. The overwhelming impression those two days left was one of great diversity in many respects.

The next day I visited the Plymouth Plant. In the morning I gave a lecture for an audience of about twenty people. I talked about the same subject as Monday morning, but more at pleasure and in general detail. (It was nice not to be in such a hurry.) It was a very pleasant audience; after lunch we reconvened for a more general discussion, which started with that morning's topic but broadened as time went by, until I had to go to catch a late afternoon flight to Los Angeles. When leaving I realized that all questions had been pertinent and all remarks from the floor had made sense, and I was impressed. (After lunch someone pointed out that one of my proofs that morning had been done by handwaving. He was right. It was a very fresh result, up till that moment I had never done any better and I found myself challenged to supply the missing detail on the spot. After a few seconds panic on my side I thought that I saw how I could do it, and then proceeded to do it, as luck would have it to the full satisfaction of everybody present. Fun!)

On the flight to Los Angeles I started with EWD545, devoted to the topic of the two talks I had given that week; I stopped when the flight got a little bumpy. At Los Angeles —it was now 18.40, their time— Jack Mazola and John McClintock were waiting for me at the gate. After collecting my suitcase and having given them the opportunity to admire my featherweight luggage for a three week trip through different climates, we jumped into the car which, although it was two hours after sunset, was still warm inside. (In Detroit I had been woken up with "It is 7.15 and zero degrees outside." and, after looking outside, concluded correctly that the degrees were Fahrenheit and not Celsius; the next day I would see that "barely clothed" girls sunbathing on the beach!) On our way down South we had a dinner in a restaurant where our waitress most definitely did not like us, and then they took me to the hotel. My hosts had decided that "Sand and Surf" in Laguna Beach would be a much more pleasant hotel than the Mission Viejo Hilton Inn. I was very grateful for their choice: to have a hotel room with the Pacific right at your feet is really exciting!

I had the Saturday and the Sunday mostly for myself. I wrote a letter to my mother, a long letter to my wife, a sizeable entry in my diary and continued with EWD545. When I did not feel like writing —sometimes because my right hand got physically tired— I went for a little walk and looked around, or lay down on my bed and looked at the ceiling. For Saturday evening Jack had invited me for dinner, Sunday evening John took me to a harpsichord recital at Scripps College. To listen as a Dutchman in an American college to an Indian harpsichord player performing an English Suite from the German composer Bach who gave the movements French names, is fun. I did not like everything she played; when my thoughts wandered away from the music, I looked at the audience. It was a fascinating collection, such as only seats of learning can provide. Behind us sat an old lady, originally from Czechoslovakia; during the intermission I overheard her, bitterly complaining to an equally old gentleman, about the decline of the teaching of classical Greek in central Europe, in particular behind the Iron Curtain! She was really a delightful specimen...

Then came a week of hard work at the Mission Viejo Plant, where I went through two designs, through one even in great detail, giving my comments and asking questions as we went along. (The documentation had been sent to me in advance.) I did not identify "the million-dollar mistake" —that, of course, would have been the easiest and most spectacular way of earning my money— as both documents had been prepared very carefully. I could suggest some simplifications, issue some warnings. With respect to those two designs my main function has probably been confirming their hope that they worried about the right things. We have discussed a bus structure that might have advantages, a new form of redundancy in the representation of programs, and proving techniques for fine-grained interleaving, a subject about which we had been corresponding. And a number of minor topics; I learned something about pipelining. It was, as said, a week of hard work, but my impression was that it has been rewarding at both sides. A striking feature of the environment was the great respect with which people talked about both their superiors and their subordinates.

In a number of unexpected and unplanned ways this was a very instructive week. I happened to attend a few meals with Southern Californian businessmen. Some of them don't delete their expletives! I could hardly believe my ears! At a lunch a millionaire explained how to become one: it was instructive, he certainly added a few dimensions to my concept of "ruthlessness".

On Saturday I was again all on my own, and started with EWD546 on the bus structure; as I proceeded, the problem turned out to be harder than I had expected at first. On Sunday I had to go to La Jolla, and as Jack had promised a visit to the San Diego Zoo to his family, we all went there first. It was a beautiful day, and it is a beautiful Zoo, and I was grateful for the opportunity. Late in the afternoon I arrived at The Sea Lodge in La Jolla. The first thing that I missed was the radio: in Laguna Beach I had a radio in my hotel room and that had provided me with a great amount of good music, thanks to a station of the University of Southern California.

On Monday morning I was picked up by Don Lyle, who had promised to show me migrating whales. He had not been boasting: as soon as we approached the Pacific Ocean, he said "Look!" and pointed at a white puff! Later we saw porpoises, killer whales and a pelican. Fascinating. Monday and Tuesday I had a less tight schedule, during which various aspects of Don's project were discussed; the last three days of the week I gave a lecture series in The Sea Lodge for people from La Jolla, Mission Viejo, Pasadena and Santa Barbara. It was a little bit of a problem for me, that I did not know beforehand very well, to what extent my audience would be familiar with my writings. It turned out to vary among the participants. I have used the first two days as an introduction to my manuscripts, and as such I think they were successful. The last morning must have been a disappointment for some of them, as one or two asked for very concrete guidelines, more concrete than can be given. Essentially they asked "how to invent". On Friday at noon, the official performance was over and the ones that had far to go went home. I remained in the Sea Lodge with five or six people, talking about "seeds of complexity". (I was asked to do so, I had used the term in passing the previous day.) I got the impression that that was a very illuminating afternoon, perhaps the best of the whole three days.

Saturday, everything went wrong. Don Lyle and his wife picked me up with the intention of showing me the whales from a high point at the coast. But the whales had a free day. Then we went for lunch. In the first three restaurants that we tried, we had to wait so long, that we ended up at the "Gatekeeper" —if I remember correctly— where I offered them the lunch, but it was terrible. All the food they were serving was emphatically "healthy", but it was hard to find a dish without cheese. When I had found one —at last!— and ordered it, the waiter told me that the kitchen had run out of soup, so I had to choose again. And the salad —with oil and vinegar— had too much vinegar; but, presumably, it was very healthy. For the evening dinner I was taken to friends; they had asked whether I had objections to red pepper; and I had said "No", but they had not been warned about my abhorrence for cheese, and before my very eyes I saw my host ruining the dish.....

On Sunday, Don Lyle collected me at the hotel, and we had a number of pleasant and peaceful hours at his home, until they took me to the San Diego Airport, from where I had to leave for home, via Los Angeles. At 16.30 I took off and from that moment onwards I had again to take care of myself. At Los Angeles I had to change planes without a guardian angel from Burroughs at my side. I had plenty of time, I managed to do so quite successfully and a Lufthansa flight —fairly loaded— took me in a direct flight to Amsterdam. Monday evening at 18.30 I was home. The next day I had to go to the University, in order to grade students work at a written examination. It was terrible: the majority of the students don't know how to spell, nor how to write; nor how to program, for that matter. Being confronted with that junk was the greatest shock of the month.

*         *         *

Among the papers I saw since my return was a report concerned with the Dutch government funding of mathematical research. It pointed out that the usual planning techniques, in spite of being usual, might be totally inadequate because the unit "a manmonth" is too elusive: in mathematics, one man's month can easily surpass another man's life. When we want to know, how much money we have in our pocket, we all know that it does not suffice just to count the number of coins! The danger is, of course, that for lack of anything more tangible, the "manmonth" —in spite of having been called "mythical"— undeservedly gets the status of a workable unit.

*         *         *

While pondering I came to two terminological conclusions. The one is that my crusade against anthropomorphic terminology in computing science has got a new target: computers don't "decide", for a decision is something for which one can be held responsible. The other piece of misleading terminology identified is the expression: "the design of a programming language"; the expression "the invention of a programming language" seems much more adequate.

*         *         *

I don't know whether it is a cultural gap, a continental gap or a generation gap, but this trip I have faced six times with the same question, and never I could give a sensible answer. The question was "Are you serious?". After the fourth time I tried to explain how this question could be nonsensical by telling a serious joke. In spite of that serious joke, the question was asked another two times!

*         *         *

During the night after my return from California we had 10 cm of snow, and we have had severe frost since then. In the snow our dogs, that used to be regarded as white, seem of a dirty yellow and I walk them in a coat heavier than the one that served me in Detroit. In short: it is winter overhere.

*         *         *

Those who have observed that the leather shoulder strap of my bag needed mending, I can tell that I did so yesterday evening.

1st of February 1976
Plataanstraat 5
NUENEN - 4565
The Netherlands

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 29-Sep-2011

EWD548

Tweede toespraak tot mijn studenten, voorjaar 1976.

Voor de fabrikant van, zeg, Purgatorium Toiletzeep, is het niet zo moeilijk om uit de verkoopscijfere af te leiden, hoeveel stukken Purgatorium Toiletzeep er per maand door het Nederlandse volk gebruikt worden. Wil men echter er ook achter komen, door welk percentage van het Nederlandse volk deze stukken zeep worden opgemaakt, dan grijpt men naar het hulpmiddel der enquete. Enqueteurs en enquetrices worden op de mensheid losgelaten met de vraag "Gebruikt U Purgatorium Toiletzeep?" en dan maar turven! Afgezien van de hinderlijkheid voor de burgerij is tegen deze werkwijze geen ernstig bezwaar te maken.

Bedenkelijker wordt het wanneer oppervlakkig gezien naar feitelijke informatie gevraagd wordt, terwijl bij nader inzien de vraagstelling onduidelijk of slecht van toepassing is. Zo zijn in de afgelopen jaren de Nederlandse hoogleraren, wier professionele verantwoordelijkheid zich zoals bekend over onderwijs en onderzoek uitstrekt, geteisterd door enquete-formulieren, waarop zij geacht werden in te vullen, hoeveel percent van hun tijd zij aan onderzoek, en hoeveel percent van hun tijd zij aan onderwijs besteedden. Bij de invulling treedt onmiddellijk het probleem op, dat je een heleboel dingen doet, waarvan je nauwelijks weet of je het als onderzoek of onderwijs moet beschouwen: vaak is het beide tegelijkertijd. Hier komt dan nog bij, dat je drommels goed weet, dat het ene uur von de dag het andere niet is! De bezwaren tegen de onzekerheid hoe je dit formulier moet invullen, worden weggewuifd met de opmerking, dat het formulier door zovelen wordt ingevuld, dat de verschillen in interpretatie der categorieen wel wordt uitgemiddeld. Ik heb dat altijd een heel bedenkelijke opmerking gevonden. Dat je door optellen en delen kunt middelen, weet een kind; dat bij dubieuze uitgangsgegevens, waarvan niemand eigenlijk weet, wat ze voorstellen, het gemiddelde plotseling een relevant gegeven zou zijn, wil er bij mij maar moeilijk in. Naar de Waarheid zoeken door alle Leugens te middelen kan slechts gerechtvaardigd worden door het dogma, dat de Middenweg altijd Gulden is....

Werkelijk abject wordt de hele enqueteringsrage, als do enqueteurs naar opinies gaan vragen: "Bent U voor of tegen ....?" en vul dan maar in: abortus, de NAVO, kernenergie, democratisering en zo voort. Het soort zaken, dat hier dan aan de orde gesteld wordt, is altijd van dien aard dat een ieder met een weloverwogen oordeel dit nimmer in een bit informatie kan samenvatten. Van dit soort enquetes gaat evenwel de suggestie van het tegendeel uit. Voorts suggereert het feit, dat aan elk antwoord evenveel gewicht zal worden toegekend, dat aan elk antwoord ook evenveel gewicht toekomt, en dat iedereen, door het loutere feit van geenqueteerd te worden, op zijn opinie, hoe onrijp ook, recht heeft. Als —en dat lijkt steeds gebruikelijker te worden— weigering om aan de enquete mee te werken als moreel verwerpelijk wordt voorgesteld, gaat van de hele procedure een pressie uit met een opinie voor de dag te komen en zich een oordeel aan te meten.

Dit is dezelfde pressie die uitgaat van alle happenings waarin middelbare scholieren en studenten worden aangespoord te "discussieren" over onderwerpen, waarvan ze onvoldoende verstand hebben. Hierbij is het onderliggend dogma, dat dat ook helemaal niet nodig is; sommigen zullen misschien zelfs verdedigen, dat kennis van zaken de zuiverheid van het intuitieve oordeel alleen maar kan vertroebelen.

Opinie-enquetes en genoemde happenings vormen een ernstige bedreiging voor een van de meest essentiele acadetnische vrijheden, nl. het recht je van een opinie te onthouden en je oordeel op te schorten.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Tue, 16 Oct 2007

EWD549

Derde toespraak tot mijn studenten, voorjaar 1976.

Vorig semester heb ik een aantal toespraken gewijd aan de verwarring die onherroepelijk gesticht wordt, wanneer wij machines in anthropormorfe termen trachten te beschrijven en begrijpen. Voor vandaag is de verwarring aan de beurt, die onherroepelijk ontstaat, als wij een collectivum van mensen gaan beschrijven als individu.

Vorige week had ik het over enquetes en de schadelijke invloed hiervan op de geenqueteerde, die zich moreel verplicht voelt opinies te hebben. Over de invloed van de uitslag hebben we het nog niet gehad! Maar hoe worden die uitslagen geformuleerd? Zullen we eens proberen? "Katholiek Nederland ingenomen met nieuwe aartsbisschop." "Het Nederlands volk vindt bedrijfsdemocratisering van ondergeschi belang." "De THE wil zich meer inzetten voor de belangen van de regio." "De PvdA staat achter het beleid van de regering." U kunt het lijstje nu zelf wel voortzetten.

Het vervelende van dit soort formuleringen, waarin linguistisch een collectivum als individu optreedt, is, dat zij een veel grotere homogeniteit suggereren, dan er in werkelijkheid is, een onjuiste voorstelling van zaken, die tot allerlei conflicten aanleiding geeft. Ten eerste is er het persoonlijke conflict voor de dissident. De Nederlands Katholiek, wie de wel uiterst Roomse onderkin van de nieuwe monseigneur tot aarzeling heeft geinspireerd, vraagt zich met zorg af, of hij nog wel bij de Kerk hoort. Het lid van de "TH-gemeenschap" —ook zo'n vieze term— voor wie de betekenis van de wetenschap niet bij de provinciegrenzen ophoudt, kan makkelijk door soortgelijke twijfels bevangen worden. Wij moeten over dit soort persoonlijke conflicten niet te licht denken, want zij hebben menigeen's vermogen tot loyaliteit ernstig afbreuk gedaan.

Het is niet makkelijk am in de wetenschap dat iets een fictie is, met deze fictie te leven zonder de eigen integriteit aangetast te laten worden. Het is de facto zo moeilijk, dat velen prefereren te vergeten dat deze homogeniteit een fictie is. En dan is de boot aan: voor dezen is nl. elke blijk van inhomogeniteit een aantasting van hun kwetsbare zekerheid, en daarmee is de kiem gelegd voor de intolerantie, die voor alle totalitaire regimes zo karakteristiek is. Wij kennen de symptomen allemaal. Wij weten, hoe de heksenjacht van de Inquisitie de fictie van de eenheid van de Roomse Kerk moest redden. Wij weten, hoe de kerkelijke censuur, die slechts door het bisschoppelijk Imprimatur kon worden opgeheven, de verscheidenheid moest verdoezelen. Wij weten, hoe tijdens de Koude Oorlog het McCarthyisme in de USA een communistenjacht ontketend heeft, die de Jezuieten van de Inquisitie jaloers gemaakt moet hebben. Wij weten, hoe in de USSR het niet delen van de overheersende politieke opvattingen voldoende is, om als misdadiger of als gek te worden gebrandmerkt. Als goede Nederlanders zijn wij meesters in het wijzen met de beschuldigende vinger, mits hij naar een punt buiten de grenzen wijst..... Maar U moet niet denken, dat het hier allemaal koek en ei is.

Van de huidige zg. "democratische discussies" gaat de sterke suggestie uit dat hij, wiens mening niet door de meerderheid gedeeld wordt, het bij het verkeerde eind heeft. En als hij zijn mening niet prijs wil geven, is hij een lastpost, die niet tot samenwerking bereid is. En als hij zijn eigen mening ook nog ventileer is hij een illoyale spelbreker. Die goedkope veroordeling is ons aller deel, van scholieren in de klas tot ministers in het kabinet. Toen, een week voordat ik afstudeerders toe moest spreken, de dekaan van de onderafdeling in dezen een poging tot preventieve censuur ondernam, was ik dan ook niet verbaasd. Wel geschokt.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Tue, 16 Oct 2007

EWD550

A more formal treatment of a less simple example

For obvious reasons, most programming experiments that have been carried out in the application of formal techniques, dealt with simple, algebraic examples. For equally obvious reasons, the examples shown in tutorial texts on this subject are mostly of the same nature. (There has been a time when all of Computing Science seemed to boil down to massaging Euclid's Algorithm for the greatest common divisor!) This paper is primarily directed at remedying this situation.

*                  *
*

Our ultimate goal is to develop a program that will transform expressions from infix notation to postfix notation. The subject matter to be maniuplated by our program are therefore not integers, but strings of characters that may, or may not belong to certain syntactic categories. For variables of type "character string" we have to have at our disposal the analogon of high-school algebra (such as(a > b and c > d) ⇒ a + c > b + d, etc.) that sufficed for the well-known numerical examples. Before embarking on our problem proper, we shall first introduce the necessary formal apparatus and the notation needed for its description.

We assume our syntax given in BNF. Let <pqr> denote a syntactical category. We shall then express the fact that a string named K belongs to the syntactical category <pqr> by

pqr(K)    .

For strings (named K, L, ...) and characters (named y, z, ...) we shall denote concatenation by juxtaposition, e.g. KL, Ky, Ky; etc. If L may be any string and y may be any character, any non-empty string may be denoted by yL or Ly.

     With any syntactic category <pqr> we may associate the syntactic category <bopqr> —"begin of a <pqr>"— consisting of all the strings that either are a <pqr> or can be extended at the right-hand side so as to become a <pqr> or both. According to that definition the statement that the syntactic category <pqr> is not empty —i.e. contains, as most useful syntactic categories, at least one string— is equivalent with the predicate:

bopqr(empty string). |

The formal definition of the predicate <bopqr> in terms of <pqr> —with K and L denoting arbitrary strings— is

bopqr(K) ⇔ (E L : pqr(KL)) | (1)

Separating the case that L is empty and the case that L is not empty, we can rewrite (1) as

bopqr(K) ⇔ (pqr(K) or (E yL : pqr(KyL))) |

which, thanks to (1), can be reduced to

bopqr(K) ⇔ (pqr(K) or (E y : bopqr(Ky))) | (2)

from which we immediately derive

(bopqr(K) and (A y: non bopqr(Ky))) ⇒ pqr(K) | (3)

From (1) we derive further

bopar(Ky) | ⇔ = ⇒ | (E L : pqr(KyL)) (E yL : pqr(KyL)) bopqr(K)     .

From this result

bopqr(Ky)  ⇒  bopqr(K) | (4)

follows that <bopqr> = <bobopqr>.

Because pqr(K) ⇒ (E L : pqr(KL))    —L = the emptystring does the job—  a further consequence of (1) is

pqr(K)  ⇒  bopqr(K) | (5)

From our informal description of what we intended the notion "begin of" to mean, the above is all intuitively obvious, and by now the reader may wonder what all the fuss is about. The point is that we need such formulas as soon as we wish to give a more rigorous treatment of a parser.

*                  *
*

We intend to develop a mechanism called "sentsearch" that is intended to recognize strings from the syntatical category <sent>. More precisely, we assume that the input string can be scanned in the order from left to right and reserve the identitier x for the next visible character of the input string. If the input string starts with "a + b ...." then we have initially x = "a"; after the execution of "move" the relation x = "+" will hold. Besides assigning a new value to x, the primitive "move" can be viewed as also appending the old value of x to the right to "the strings of characters moved over" or "the string of characters read" or "the string of characters that are no longer visible."

Let S be the string of characters "moved over" by activation of sentsearch.

Note 1. When developing the body of sentsearch we may assume that a local so-called "ghost variable" S is intialized at the beginning as the empty string, that each call on "move" is implicitly preceded by "S := Sx", and that upon termination S is handed back as a "ghost function value" to the calling environment. (End of Note 1.)

In the case that the input sequence does not start with a <sent>, we want S to be the sequence that is insufficient to establish this fact, while Sx is long enough to make this conclusion. That is, upon termination

bosent(S) and non bosent(Sx)

will hold. The first term expresses that not too much has been moved over, the second term expresses that enough has been moved over. In the case that the input string does start with a <sent>, we wish S to be equal to that <sent> and assume our syntax for <sent> —about which nothing has been given yet— to satisfy

sent(L)  ⇒  non (E y ; bosent(Ly)) | (6)

Whether or not a <sent> has been found is to be recorded in the global boolean c —short for "correct"— and our complete specification of sentsearch is that it has to establish Rs(S, x, c), where Rs(S, x, c) is given by

bosent(S) and non bosent(Sx) and  c = sent(S) | (7)

Note 2. The consequence of assumption (6) is that when the input string starts with a <sent> and the analysis has progressed to S equal to that <sent>, the term  non bosent(Sx)  is true for all possible values of x, i.e. sentsearch can then terminate wihtout inspecting the next visible character. The end of a <sent> is assumed to be detectable without looking beyond it. (End of Note 2.)

We now give the syntax for <sent>:

<sent>  ::=  <exp> ; | (8)

From this we have to derive the syntax for the syntatical category <bosent> :

<bosent>  ::=  <sent> | <boexp> | (9)

Each  <bosent>  can be derived by taking a  <sent>  and removing at the right-hand side zero or more characters from it. Removal of zero characters gives the first alternative, removal of one or more characters from  "<exp> ;"  boils down —because the semicolon is a single character— to the removal of zero or more characters from "<exp> ;" but that is by definition the syntactic category called  <boexp> . Hence (9). The two alternatives are mutually exclusive, for we have for any string L:

boexp(L) ⇒ non sent(L) | (10)

This can be proved by deriving a contradiction from  boexp(L) and sent(L) .

From  boexp(L)  follows —according to (2)—

exp(L) or (E y : boexp(Ly))

We deal with both terms separately:

exp(L) ⇒ (on account of (8))
sent(L;) ⇒ (on account of (5))
bosent(L;) ⇒ (E y : bosent(Ly))    ;

the second term gives

(E y : boexp(Ly)) ⇒ (on account of (9))
(E y : bosent(Ly))    .

As both terms of the disjunction imply the same, we conclude that also

boexp(L) ⇒ (E y : bosent(Ly)) .

According to (6), however,

sent(L) ⇒ non (E y : bosent(Ly)) .

The desired contradiction has been established and (10) has been proved.

Syntax rule (8) strongly suggests that the body of sentsearch should start with a call of expsearch. In order to design sentsearch in terms of expsearch we only need to know the net effect of expsearch and we propose in analogy to (7) that —when E is the string of characters moved over by expsearch— the primitive expsearch will establish Re(E, x, c), where Re(E, x, c) is given by

boexp(E) and non boexp(Ex) and c = exp(E) | (11)

Designing sentsearch in terms of expsearch means that we would like to have theorems, such that from the truth of a relation of the form Re the truth of the relations of the form Rs can be concluded. There are three such theorems.

Theorem 1. (Re(L, x, c) and non c) ⇒ Rs(L, x, c)
Proof. |  | Assumed: |
0. |  | Re(L, x, c) and non c |
|  | Derived: |
1. |  | boexp(L) | with (11) from 0
2. |  | bosent(L) | with (9) from 1
3. |  | c = exp(L) | with (11) from 0
4. |  | non c | from 0
5. |  | non exp(L) | from 3 and 4
6. |  | non sent(Lx) | with (8) from 5
7. |  | non boexp(Lx) | with (11) from 0
8. |  | non bosent(Lx) | with (9) from 6 and 7
9. |  | non sent(L) | with (10) from 1
10. |  | c = sent(L) | from 4 and 9
11. |  | Rs(L, x, c) | with (7) from 2, 8 and 10
|  |  | (End of Proof of Theorem 1.)

Theorem 2.  (Re(L, x, c) and c and non semi(x)) ⇒ Rs(L, x, false)
Proof. |  | Assumed: |
0. |  | Re(L, x, c) and c and non semi(x) |
|  | Derived: |
1. |  | boexp(L) | with (11) from 0
2. |  | bosent(L) | with (9) from 1
3. |  | non semi(x) | from 0
4. |  | non sent(Lx) | with 8 from 3
5. |  | non boexp(Lx) | with (11) from 0
6. |  | non bosent(Lx) | with (9) from 4 and 5
7. |  | false = sent(L) | with (10) from 1
8. |  | Rs(L, x, false) | with (7) from 2, 6 and 7
|  |  | (End of Proof of Theorem 2.)

Theorem 3.  (Re(L, x, c) and c and semi(x)) ⇒ Rs(Lx, y, c)
Proof. |  | Assumed: |
0. |  | Re(L, x, c) and c and semi(x) |
|  | Derived: |
1. |  | c = exp(L) | with (11) from 0
2. |  | c | from 0
3. |  | exp(L) | from 1 and 2
4. |  | semi(x) | from 0
5. |  | sent(Lx) | with (8) from 3 and 4
6. |  | c = sent(Lx) | from 2 and 5
7. |  | bosent(Lx) | with (5) from 5
8. |  | non bosent(Lxy) | with (6) from 5
9. |  | Rs(Lx, y, c) | with (7) from 7, 8 and 6.
|  |  | (End of Proof of Theorem 3.)

And now a possible body of sentsearch is evident, when we realize that its call on expsearch implies for the ghost variable S the assignment "S := SE"

proc sentsearch: { S = empty string }
                 expsearch {Re(S, x, c)};
                 if non c → skip
                 ⌷ c and non semi(x)  →  c := false
                 ⌷ c and semi(x)  →  move
                 fi {Rs(S, x, c)}
corp

Note 3. Instead of Theorems 1 and 2 we could have discovered

Theorem 1'.  (Re(L, x, c) and non c)  ⇒  Rs(L, x, false)

Theorem 2'.  (Re(L, x, c) and non semi(x))  ⇒  Rs(L, x, false).

This would have directed us towards the design of the body

proc sentsearch: expsearch;
                 if non c or non semi(x)  →  c := false
                 ⌷ c and semi(x)  →  move
                 fi
corp

which, thanks to de Morgan's Theorem, has no aborting alternative construct.
{End of note 3.)

We now consider for <exp> the following syntax

<exp> ::= <adder> <term> | (12)

<adder> ::= { <term> <adop> } | (13)

<adop> ::= + | - | (14)

where the braces indicate a succession of zero or more instances of the enclosed. Because each instance of the syntactic category <adop> is a single character, we derive

<boexp> ::= <adder> <boterm> | (15)

from which follows

(adder(L) and boterm(K)) ⇒ boexp(LK) | (16)

But this gives us no way of proving that a string is not of the syntactic category <boexp>. In particular, the conclusion

(adder(L) and non boterm(K))  ⇒  non boexp(LK) |  is not justified.

We must make —in analogy to (6)— an assumption about <term> and <adop>, and we assume

(term(L) and adop(y)) ⇒ non boterm(Ly) | (17)

This means, to start with, that with term(L), term(L'), adop(y), and adop(y'), we can conclude fromLyS = L'y'S', thatL = L' andy = y'. In other words, for every <boexp> that starts with an instance of <term> <adop>, that instance is uniquely defined. By removing it from the front end, we are still left with a string frmo the syntactic category <boexp>, and therefore we are allowed to conclude

((adder(L) and non boexp(K))  ⇒  non boexp(LK) | (18)

This does not solve our problems yet, because in order to use (18) in order to provenon boexp(LK), we still have to provenon boexp(K), be it only for a possibly shorter string K. We can do it, however, for a string related to the syntactic category <term>, as we can prove

(boterm(L) and non boterm(Ly) and boexp(Ly)) ⇒ (term(L) and adop(y)) | (19)

The nonempty string Ly, satisfying boexp(Ly), can have one of three different forms:

1)    <term> <adop> <nonempty boexp>

This would imply, that L itself is of the form

<term> <adop> <boexp>

which, on account of its first two elements and (17), is incompatible with boterm(L).

2)    <term> <adop>

Because all instances of <adop> are single characters, this case implies indeed

term(L) and adop(y)

3)   <boterm>

This case is incompatible withnon boterm(Ly). Hence, formula (19) has been proved.

Similarly, we should ask ourselves how to prove that some string is not an element of the syntactic category <exp>. From (12) we can derive

((adder(L) and term(K))  ⇒  exp(LK) | (20)

but, again, the conclusion

(adder(L) and non term(K)) ⇒ exp(LK) | is not justified,

only —similar to (18)—

(adder(L) and non exp(K))  ⇒  non exp(LK) | (21)

Analogous to (19) we have

(boterm(L) and exp(L))  ⇒  term(L) | (22)

The termexp(L) tells us that the string L can have one of two different forms:

1)   <term>

This case indeed impliesterm(L)

2)   <nonempty adder> <term>

On account of (17) —and also (4)— this case is excluded byboterm(L).

Hence formula (22) has been proved.

Finally we can conclude that

((exp(L) and adop(y))  ⇒  adder(Ly) | (23)

The left-hand side tells us on account of (12) that Ly is of the form

<adder> <term> <adop>

and therefore (13) allows us to concludeadder(Ly), and (23) has been proved.

Syntax rules (12) and (13) strongly suggest that the body of expsearch should call —possibly repeatedly— a new primitive termsearch. In order to design expsearch in terms of termsearch we only need to know the net effect of termsearch and we propose —in analogy to (7) and (11)— that, when T is defined as the string of characters moved over by termsearch, the primitive termsearch will establishRt(T, x, c), whereRt(T, x, c) is given by

boterm(T) and non boterm(Tx) and c = term(T) | (24)

Designing expsearch in terms of termsearch means that we would like to have theorems allowing us to draw conclusios from the truth of a relation of the form Rt.

Theorem 4. (adder(L) and Rt(T, x, c) and c and adop(x))  ⇒  adder(LTx)
Proof. |  | Assumed: |
0. |  | adder(L) and Rt(T, x, c) and c and adop(x)
|  | Derived: |
1. |  | c = term(T) | with (24) from 0
2. |  | c | from 0
3. |  | term(T) | from 1 and 2
4. |  | adder(L) | from 0
5. |  | exp(LT) | with (20) from 3 and 4
6. |  | adop(x) | from 0
7. |  | adder(LTx) | with (23) from 5 and 6
|  |  | (End of Proof of Theorem 4.)

Theorem 5. (adder(L) and Rt(T, x, c) and non c)  ⇒  Re(LT, x, c)
Proof. |  | Assumed: |
0. |  | adder(L) and Rt(T, x, c) and non c
|  | Derived: |
1. |  | c = term(T) | with (24) from 0
2. |  | non c | from 0
3. |  | non term(T) | from 1 and 2
4. |  | boterm(T) | with (24) from 0
5. |  | non boterm(Tx) | with (24) from 0
6. |  | non boexp(Tx) | with (19) from 3, 4, and 5
7. |  | adder(L) | from 0
8. |  | non boexp(LTx) | with (18) from 6 and 7
9. |  | boexp(LT) | with (16) from 4 and 7
10. |  | non exp(T) | with (22) from 3 and 4
11. |  | non exp(LT) | with (21) from 7 and 10
12. |  | c = exp(LT) | from 2 and 11
13. |  | Re(LT, x, c) | with (11) from 8, 9, and 12
|  |  | (End of Proof of Theorem 5.)

Theorem 6. (adder(L) and Rt(T, x, c) and non adop(x)) ⇒ Re(LT, x, c)
Proof. |  | Assumed: |
0. |  | (adder(L) and Rt(T, x, c) and non adop(x))
|  | Derived: |
1. |  | boterm(T) | with (24) from 0
2. |  | adder(L) | from 0
3. |  | boexp(LT) | wirh (16) from 1 and 2
4. |  | non boterm(Tx) | with (24) from 0
5. |  | non adop(x) | from 0
6. |  | non boexp(Tx) | with (19) from 1, 4, and 5
7. |  | non boexp(LTx) | with (18) from 2 and 6
8. |  | c = term(T) | with (24) from 0
9. |  | c ⇒ term(T) | from 8
10. |  | c ⇒ exp(LT) | with (20) from 2 and 9
11. |  | non c ⇒ non term(T) | from 8
12. |  | non c ⇒ non exp(T) | with (22) from 1 and 11
13. |  | non c ⇒ non exp(LT) | with (21) from 2 and 12
14. |  | c = exp(LT) | from 10 and 13
15. |  | Re(LT, x, c) | with (11) from 3, 7, and 14
|  |  | (End of Proof of Theorem 6.)

A corollary of Theorems 5 and 6 is

(adder(L) and Rt(T, x, c)
and non (c and adop( x)))
Re(LT, x, c).

A possible body for expsearch is by now pretty obvious when we realize that calls on termsearch imply for its ghost variable E the assignment E:= ET (as "move" implies E:= Ex ). In the post-assertions for calls on termsearch the relation E=LT has been given in order to define L in terms of E and T.

proc expsearch: {adder(E) because E = empty string}
                termsearch {E=LT and
                    adder(L) and Rt(T, x, c )};
                do c and adop( x) → {adder(Ex)}
                      move {adder(E)};
                      termsearch {E=LT and adder(L)
                                  and Rt(T, x, c )}
                od {Re( E, x, c )}
corp

     We now consider for <term> the following syntax

<term> ::= <plier> <prim> | (25)

<plier> ::= { <prim> <mult> } | (26)

<mult> ::= * | (27

and assume about <prim> and <mult>

(prim(L) and mult(y)) => non boprim(Ly) | (28)

formulae (25), (26), (27), and (28) are similar to (12), (13), (14), and (17) respectively, and all our conclusions since then carry over. With P as the string of characters moved over by a primitve primsearch that establishes —in analogy to (24)— Rp(P, x, c), where Rp(P, x, c) is given by

boprim(P) and non boprim(Px) and c= prim(P) | (29)

we can write immediately (!)

proc termsearch: {plier(T) because T = empty string}
                 primsearch {T=LP and plier( L)
                                  and Rp(P, x, c) };
                 do c and mult(x) → {plier(Tx)}
                       move {plier(T)};
                       primsearch {T=LP and plier(L)
                                        and Rp(P, x, c)}
                 od {Rt(T, x, c)}
corp

It is time to "close" our syntax:

<prim> ::= <iden> | <paren> | (30)

<iden> ::= { <letter> } <letter> | (31)

<paren> ::= <open> <exp> <close> | (32)

<open> ::= ( | (33)

<close> ::= ) | (34)

<letter> ::= a | b | c | d | e | f | (35)

The important conclusions from (35) are:

1)   that the syntactic category <letter> is nonempty

2)   that all instances of the syntactic category <letter> are all single characters

3)   that these characters differ from the six previously introduced characters.

From the nonemptiness of the syntactic category <letter> we draw the same conclusion for <iden>, hence for <prim>, hence for <term> hence for <exp>, and hence for <sent>. In particular we shall need to refer to

boprim(empty string) | (36)

From (30) we derive

<boprim> ::= <boiden> | <boparen> | (37)

From (31) and (32) respectively, we derive

(boiden(y) = letter(y)) and              non iden(empty string) | (38)

(boparen(y) = open(y)) and               non paren(empty string) | (39)

and hence

boprim(y) = (letter(y) or open(y)) | (40)

non prim(empty string) | (41)

From (31) we derive

<boiden> ::= { <letter> } | (42)

and, because instances of <letter> are single characters

non letter(y) ⇒ non boiden(Ly ) | (43)

from (32) we derive

<boparen> ::= empty string | <open> <boexp>               | <paren> | (44)

The three alternatives for <boparen> are mutually exclusive: for the first one versus the two others, it is obvious. For the last two I can prove the final exclusion only by using the technique of the bracket count.

Lemma 1. exp(L) implies that the number of instances of <open> in L quals the number of instances of <close> in L.

Lemma 2. boxp(L) implies that the number of instances of <open> in Lequals at least the number of instances of <close> in L.

Lemma 1 follows from the fact that in the original syntax —i.e. without the "begin-of"-derivations— the only rule using <open> or <close>, viz. (32), introduces them pairwise. Lemma 2 follows from the observation that in this only introduction, the instance of <open> precedes that of <close>

(Presumably official syntatic theory has more formal proofs for these two Lemmata; I am fully convinced of their correctness by the preceding four lines of argument.)

The last two alternatives of (44) are mutually exclusive, because from Lemma 2 we can conclude that in a string of the form <open> <boexp> the number of instances of <open> exceeds the number of instances of <close>, while in a string of the form <paren> these numbers are equal on account of Lemma 1. In other words

(open(y) and boexp(L)) ⇒ non paren(yL) | (45)

or, equivalently

paren(yL) ⇒ (open(y) and non boexp(L)) | (45')

Expressed in terms of paren and boparen only, also holds

paren(L) ⇒ non (E z: boparen(Lz)) | (46)

This formula can be derived by deriving a contradiction from the truth of the left-hand side and the falsity of the right-hand side. From paren(L) and (39) we conclude that L is nonempty, and we may write L=yK , such that, on account of (45'), we deduce

open(y) and non boexp(K)

On the other hand, (E z: boparen(yKz)) is, according to (1), equivalent to

(E z,M : paren(yKzM))

or

(E M,z : paren(yKMz))

Rule (32) then allows us to conclude

open(y) and (E M: exp(KM) and (E z: close(z)).

The second term is equivalent to boexp(K), we have the contradiction we were looking for, and hence, (46) has been proved.

Theorem 7. (L = empty string and non (letter(x) or open(x))) ⇒ Rp(L, x, false)
Proof. | Assumed: |
0. | L = empty string and non (letter(x) or open(x)) |
| Derived: |
1. | L = empty string | from 0
2. | boprim(L) | with (36) from 1
3. | non (letter(x) or open(x)) | from 0
4. | non boprim(x) | with (40) from 3
5. | x = Lx | from 1
6. | non boprim(Lx) | from 4 and 5
7. | false = prim(L) | with (41) from 1
8. | Rp(L, x, false) | with (29) from 2, 6, and 7 (End of Proof of Theorem 7.)

Theorem 8. (iden(yL) and letter(x)) ⇒ iden(yLx)

Proof. Evident from (31) |  |

Theorem 9. (iden(yL) and non letter(x)) ⇒ Rp(yL, x, true)
Proof. | Assumed: |
0. | iden(yL) and non letter(x) |
| Derived: |
1. | iden(yL) | from 0
2. | boiden(yL) | with (5) from 1
3. | boprim(yL) | with (37) from 2
4. | boiden(yL) | with (4) from 2
5. | letter(y) | with (38) from 4
6. | non open(y) | from 5
7. | non boparen(y) | with (39) from 6
8. | non boparen(yLx) | with (4) from 7
9. | non letter(x) | from 0
10. | non boiden(yLx) | with (43) from 9
11. | non boprim(yLx) | with (37) from 8 and 10
12. | true = prim(yL) | with (30) from 1
13. | Rp(yL, x, true) | with (29) from 3, 11, and 12 (End of Proof of Theorem 9.)

Theorem 10. (open(y) and Re(E, x, c) and c and close(x)) ⇒ Rp(yEx, z, c)
Proof. | Assumed: |
0. | open(y) and Re(E, x, c) and c and close(x) |
| Derived: |
1. | c = exp(E) | with (11) from 0
2. | c | from 0
3. | exp(E) | from 1 and 2
4. | open(y) | from 0
5. | close(x) | from 0
6. | paren(yEx) | with (32) from 3, 4, 5
7. | prim(yEx) | with 30 from 6
8. | boprim(yEx) | with 5 from 7
9. | non boparen(yExz) | with (46) from 6
10. | non letter(y) | from 4
11. | non boiden(y) | with (38) from 10
12. | non boiden(yExz) | with (4) from 11
13. | non boprim(yExz) | with (37) from 9 and 12
14. | c = prim(yEx) | from 2 and 7
15. | Rp(yEx, z, c) | with (29) from 8, 13, and 4 (End of Proof of Theorem 10.)

Theorem 11. (open(y) and Re(E, x, c) and non c) ⇒ Rp(yE, x, c)
Proof. | Assumed: |
0. | open(y) and Re(E, x, c) and non c |
| Derived: |
1. | boexp(E) | with (11) from 0
2. | open(y) | from 0
3. | boparen(yE) | with (44) from 1 and 2
4. | boprim(yE) | with (37) from 3
5. | non letter(y) | from 2
6. | non boiden(y) | with (38) from 5
7. | non boiden(yEx) | with (4) from 6
8. | non boexp(Ex) | with (11) from 0
9. | c = exp(E) | with (11) from 0
10. | non c | from 0
11. | non exp(c) | from 9 and 10
12. | non paren(yEx) | from (32) from (2 and) 11
13. | non boparen(yEx) | with (44) from 8 and 12
14. | non boprim(yEx) | with (37) from 7 and 13
15. | non boiden(yE) | with (4) from 6
16. | non iden(yE) | with (5) from 15
17. | non paren(yE) | with (45) from 1 and 2
18. | non prim(yE) | with (30) from 16 and 17
19. | c = prim(yE) | from 10 and 18
20. | Rp(yE, x, c) | with (29) from 4, 14 and 19 (End of Proof of Theorem 11.)

Theorem 12. (open(y) and Re(E, x, c) and non close(x)) ⇒ Rp(yE, x, false)
Proof. | Assumed: |
0. | open(y) and Re(E, x, c) and non close(x) |
| Derived: |
1. | boexp(E) | with (11) from 0
2. | open(y) | from 0
3. | boparen(yE) | with (44) from 1 and 2
4. | boprim(yE) | with (37) from 3
5. | non letter(y) | from 2
6. | non boiden(y) | with (38) from 5
7. | non boiden(yEx) | with (4) from 6
8. | non boexp(Ex) | with 11 from 0
9. | non close(x) | from 0
10. | non paren(yEx) | with (32) from 9
11. | non boparen(yEx) | with (44) from 8 and 10
12. | non boprim(yEx) | with (37) from 7 and 11
13. | non boiden(yE) | with (4) from 6
14. | non iden(yE) | with (5) from 13
15. | non paren(yE) | with (45) from 1 and 2
16. | false = prim(yE) | with (30) from 14 and 15
17. | Rp(yE, x, false) | with (29) from 4, 12, and 16

Note 4. In proofs 9 through 12, I refer a number of times to formula (4), but it is not really that one that is needed, but the obvious generalization:

bopqr(KL) ⇒ bopqr(K);

sometimes it is used in the inverted, but equivalent, form

non bopqr(K) ⇒ non bopqr(KL) .

Furthermore I offer my apologies for the great similarity between the proofs of Theorem 11 and Theorem 12. The total text could have been shortened by first stating a Lemma 3 that captures the intersection of the two proofs. It is just too expensive to change in this respect this document, which is not intended to be submitted for publication. (End of Note 4.)

With Theorems 7 through 12 we have prepared the way for the following design of a body for primsearch.

proc primsearch: {P = empty string}
        if non (letter(x) or open(x)) → {Rp(P, x, false)}
                 c:= false {Rp(P, x, c)}
        ⌷ letter(x) → move {P = yL and iden(P)};
                 do letter(x) → {P = yL and iden(Px)}
                         move {P = yL and iden(P)}
                 od {Rp(P, x, true)};
                 c := true {Rp(P, x, c)}
        ⌷ open(x) → move {P = y and open(y)};
                 expsearch {P = yE and open(y)
                                   and Re(E, x, c)};
                 if c Å» close(x) → {Rp(Px, z, c)}
                        move {Rp(P, x, c)}
                 ⌷ non c → skip {Rp(P, x, c)}
                 ⌷ non close(x) → {Rp(P, x, false)}
                        c:= false {Rp(P, x, c)}
                 fi {Rp(P, x, c)}
        fi {Rp(P, x, c)}
corp

Now our syntax has been "closed" by (30) through (35), we can at last fulfill our obligation of proving what up till now have been assumptions, viz.

sent(L) ⇒ non (E y : bosent(Ly)) | (6)

(term(L) and adop(y)) ⇒ non boterm(Ly)) | (17)

(prim(L) and mult(y)) ⇒ non boprim(Ly)) | (28)

Relation (6) follows from the fact that bosent(Ly) implies boexp(L), and from our syntax for <exp>, <term>, <prim>, and <iden>, this implies that L does not contain a semicolon; sent(L) implies according to (8) that L does contain a semicolon. This is the contradiction that follows from the assumption that (6) does not hold; hence (6) has been proved. In order to prove (17) —under the assumption of (28)!— we observe that with

<term> ::= <plier> <prim>

<boterm> ::= <plier> <boprim>

the negation of (17)

term(L) and adop(y) and boterm(Ly)

would imply that <prim> and <adop> could be of the form <boprim>. It therefore suffices to prove that

(prim(L) and op(y)) ⇒ non boprim(Ly))          with

<op> ::= <adop> | <mult>        .

This last implication can be proved by deriving a contradiction from its negation:

prim(L) and op(y) and boprim(Ly);

it can be done using Lemma 1 and Lemma 2, and I gladly leave this detail to the reader.

*                  *
*

In veiw of the length of this report, the transformation from infix to posfix notation —on page EWD550-0 announced as "our ultimate goal"!— will be postponed and left for some later moment.

History.

Nearly three years ago I wrote a report, EWD375 "A non algebraic example of a constructive correctness proof." in which (essentially) the same problem has been tackled as here. Last January, while I was lecturing in La Jolla, Jack Mazola urged me to show a more complicated example; I tried to reconstruct the argument of EWD375 on the spot and failed.

Last February, when I was home again, I reread EWD375 and it left me greatly dissatisfied. I remembered that EWD375 had been a cause for great enthusiasm when it was written, and I could not understand that enthusiasm anymore. I found EWD375 very hard to read and hardly convincing: what three years ago I had considered as "a proof" now struck me at best as "helpful heuristics". (A strange experience to be nearly ashamed of what had been a source of pride only a few years ago!)

It was now clear why, last January in La Jolla, I was unable to give on the spot a formal treatment of the syntax analyzer: it was not just a failure of memory, it was also a profound change in my standards of rigor (undoubtedly also caused by the fact that over the last few years I burned a few fingers!). I decided to forget EWD375 and to start again from scratch. This document is the result of that effort.

It has been surprisingly exceedingly hard to write. After the first six pages had been written —I had only dealt with sentsearch— there has been a long pause before I gathered the strength and the courage to tackle expsearch, and for a few weeks I put the unfinished document away. To undertake the treatment of primsearch proved to be another hurdle.

What the final document does not show is that the notation eventually used for the assertions, the theorems and the proofs is the result of many experiments. Before we invented, for instance, the trick to use the predicate prq(K) to denote that the string K belongs to the syntactic category <pqr> all our formulae became unwieldy; so they did, as long as we indicated concatenation of strings with an explicit operator instead of —as eventually— just by juxtaposision. I hesitated, when I wrote —as on the middle of page EWD550-3— sent(L;) because I saw problems coming by the time that I had to write such predicates for strings containing unmatched parentheses; the trick of introducing <open> and <close> solved that problem. Instead of (8) I should have written

<sent> ::= <exp> <semi>

<semi> ::= ;

Again, at the time of the writing, also this report has been a source of great excitement. This is somewhat amazing as it does not contain a single deep thought! Is it, because we now still remember how much more beautiful it is than all the rejected efforts? I wonder how I shall feel about it in a few years time!

Acknowledgement.

I am greatly endebted to W.H.J.Feijen, M.Rem, A.J.Martin and C.S.Scholten, whose encouragement and active participation have been absolutely essential. And I am grateful to Jack Mazola for providing me with the incentive.

transcribed by David J. Brantley
last revised Mon, 25 Aug 2008

EWD551

Vierde toespraak tot mijn studenten, voorjaar 1976.

Onlangs heeft staatssecretaris Klein een missive rondgestuurd, waarin de universiteiten en hogescholen werden aangespoord zorgvuldig op de hoogte te blijven van de nevenfuncties van hun hoogleraren. Het is goed gebruik, dat men als employee geen nevenfuncties vervult zonder medeweten van zijn werkgever, en, afhankelijk van de aard van de nevenfunctie zelfs niet zonder toestemming van de werkgever. En niemand zal er bezwaar tegen maken, dat ook het unversitaire bedrijf van tijd tot tijd aan dit goede gebruik herinnerd wordt; sterker: dit spreekt zo vanzelf, dat men zich afvraagt, waarom deze missive van staatssecretaris Klein de voorpagina van de krant haalde.

Wel, dat werd duidelijk, als je het artikeltje wat zorgvuldiger las. Laat mij, omdat de staatssecretaris het over "commerciele bijbanen" had, ter vermijding van mogelijk misverstand voorapstellen, dat ik, die vanuit het bedrijfsleven het hoogleraarsschap als "academische bijbaan" vervul, in dezen geen partij ben. In zijn toelichting insinueerde de staatssecretaris nl. dat allerlei hoogleraren tengevolge van hun "commerciele bijbanen" hun wetenschappelijke plicht verzaken, en bovendien suggereerde hij, dat zij deze nevenfuncties in het geniep zouden waarnemen. Hoe gerechtvaardigd is die insinuatie?

Kijk, ik ben waarschijnlijk verschrikkelijk naief, maar ben niet bereid om voetstoots aan te nemen, dat alle hoogleraren, die ik persoonlijk niet zo goed ken, een orde van grootte minder fatsoenlijk zouden zijn dan de collegae, die ik beter ken. Ten eerste vervullen zij hun nevenfuncties niet in het geniep, ten tweede doen zij het niet om den brode, maar in een niet aflatende poging de kloof tussen theorie en praktijk niet nodeloos te laten verbreden. Ik weet uit ervaring, hoe moeilijk en ook vaak hoe ondankbaar dit streven is, want de kloof tussen theorie en praktijk, de spanning tussen de academische en de industriele wereld is zo groot, dat je een gerede kans loopt tussen wal en schip te raken. De doorsnede van wat theoretisch gezond en practisch zinvol is, is zo klein, dat hij in de ogen van velen als leeg wordt beschouwd. Wat practisch zinvol blijkt wordt in de academische wereld dan als "dus triviaal" gekenschetst, wat theoretisch gezond lijkt, wordt daarom in het bedrijfsleven als "dus onbruikbaar" afgeschreven. Om deze dodelijke simplificatie te doorbreken hebben wij mensen nodig, die loyaal een voet in beide kampen hebben.

Laat ons, "for the sake of the argument" de staatssecretaris even volgen in zijn zorg om het peil van het wetenschappelijk werk der hoogleraren. Waardoor zou dat het meeste in het gedrang komen? Komt het in het gedrang? Nou, reken maar! Ik moet U bekennen, dat het inmiddels zo erg is, dat ik geleerd heh bij een collega, die ik een tijdje niet gezien heb, niet meer te informeren, hoe het met zijn werk gaat. Onder hoogleraren zou dit de normaalste blijk van belangstelling horen te zijn, maar je leert het wel af, want bijna altijd blijkt de vraag pijnlijk, omdat de ander niet meer aan zijn werk toekomt. Door het gelazer van de WUB, dat alle bestuur en beleid doet ontaarden in een eindeloos steekspel met slogans, door de afbraak van het personeelsbestand hunner faculteiten en door de opdracht via herprogrammering hun instituut te laten afzakken tot de mediocriteit van de "graduate factory" komen zij aan hun werk niet meer toe. Al hun tijd en energie wordt opgeslokt door het wanhopig hozen in een van overheidswege lekgestoten schip. Als ze een adviseursschap vervullen, vallen de uren daaraan besteed waarschijnlijk samen met de enige uren, die ze nog aan de wetenschap kunnen besteden. De missive kwam op de voorpagina van de krant, omdat onze staatssecretaris zich in de toelichting een vlegel betoonde.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Tue, 16 Oct 2007

EWD552

Vijfde toespraak tot mijn studenten, voorjaar 1976.

Vandaag moet ik Uw aandacht vragen voor de z.g. "Buxton index", ingevoerd door collega John Buxton te Warwick University. Toen hij als employee van een raadgevend bureau te maken had met een enorme scala van personen en organisaties, realiseerde hij zich, wat het meest significante criterium was, volgens hetwelk hij deze personen en organisaties op een lineaire schaal zou kunnen uitzetten. Het is de lengte van de periode in de toekamst, waarover iets of iemand plannen maakt; gemeten in jaren heet deze maat sindsdien de Buxton index.

Die verschillen zijn inderdaad enorm. De ware Christen heeft voor zijn morele leven een oneindig grote Buxton index, het klassieke huwelijk wordt met een Buxton index van ongeveer vijftig gesloten, wetenschappelijk onderzoek wordt met een Buxton index van ongeveer tien bedreven —niet omdat de onderzoeker niet verder in de toekomst zou willen kijken, maar omdat het verre toekomstbeeld te vaag wordt— scholieren hebben vaak een Buxton index, die niet veel groter is dan het aantal jaren, dat hen van het eindexamen scheidt, en het kleine kruideniertje op de hoek heeft een Buxton index van driekwart.

Het is evenwel niet de breedte van het spectrum, dat de Buxton index zo significant maakt. Hij is significant om een heel andere reden. Samenwerking tussen personen en instituten met een drastisch verschillende Buxton index is nl. niet alleen ineffectief, maar loopt op ruzie uit, omdat de partners elkaar morele verwijten gaan maken. Degene met de langste Buxton index verwijt de andere kortzichtigheid, degene met de kortste Buxton index verwijt de ander alle mogelijke vormen van plichtsverzuim, omdat hij zich voor de urgente noden van vandaag niet interesseert. Het belang van de Buxton index is, dat het deze verschillen van instelling uit het vlak van de morele veroordelingen trekt en daardoor bespreekbaar maakt. Het is een techniek volgens welke een niet functionerende samenwerking zonder verwijten en zonder poging een irreele schuldvraag te beantwoorden, kan worden beeindigd.

Vele mensen taxeren Buxton indices te groot, en voor hen is het een verrassing te horen, dat het merendeel van de grote industrieen, wereldconcerns incluis, een Buxton index hanteert van zo om en nabij de zes, waarbij alleen de olieconcerns duidelijk hoger komen.

Het is ook boeiend, om de Buxton indices van regeringen te observeren. In de Verenigde Staten van Amerika is het bijvoorbeeld heel duidelijk hoe een naderende presidentsverkiezing ten aanzien van allerlei beleid de Buxton index doet inkrimpen. Dez contractie heeft een zo bekende oorzaak, dat iedereen zich van de contractie bewust is, waardoor de nadelige gevolgen beperkt blijven. Minder bekend, en daardoor gevaarlijker, is het feit dat in z.g. "moeilijke tijden" regeringen de neiging vertonen met een kleinere Buxton index te gaan werken. De reden is duidelijk: regeren is en blijft vooruit zien. Maar in moeilijke tijden heeft men behoefte aan een scherper beeld van de toekomstmogelijkheden; zonder wezenlijke versterking van de prognostische middelen komt men aan de behoefte van een scherper beeld tegemoet, door minder ver vooruit te zien.

Hoger onderwijs is vanouds een gebied geweest, dat een exceptioneel hoge Buxton index vereist: het duurt ten minste vijf jaar voordat men een nieuwe opleiding op poten heeft staan en het duurt dan nog sens vijf jaar voordat een dergelijke nieuwe opleiding de eerste afgestudeerden opbrengt. Het is dan ook niet verwonderlijk, dat bij dit kabinet met een duidelijk contraherende Buxton index het hoger onderwijs het kind van de rekening wordt.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Tue, 16 Oct 2007

EWD553

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 553: On a gauntlet thrown by David Gries
is held in copyright by Springer-Verlag New York, who have granted
permission to reproduce it here.
The manuscript was published as
| Acta Informatica 6 (1976): 357–359.EWD553 – 0

On a gauntlet thrown by David Gries.

                    by

        Edsger W.Dijkstra

It is requested to design a program that will generate the N! permutations of the values from 0 through N-1 in such an order that the transition from one permutation to the next is always performed by exactly one swap of two neighbours.

In a permutation each pair of values such that the larger value precedes the smaller one, presents a so-called “inversion”. (In particular: the one and only permutation with zero inversions is the one in which the values are placed in monotonically increasing order.) The notion of inversions can be expected to be relevant because the swapping of two neighbours changes the total number of inversions by (plus or minus) 1 , and it is, therefore, suggested to characterize each permutation by its inversions. This can be done by introducing N inversion counters inv[i] for 0 ≤ i < N , where inv[i] equals the number of inversions between the value i and the values smaller than i . (From this definition 0 ≤ inv[i] ≤ i follows; the total number of inversions of a permutation is the sum of the corresponding inv[i]-values.) That each permutation defines the inv[i]-values uniquely is obvious; that the inv[i]values define the permutation uniquely is easily seen by considering the algorithm constructing the permutation from the inv[i]-values —processing these values in the order of increasing i — : this algorithm leaves us no choice.

There is, therefore, a one-to-one correspondence between the N! possible inv-values and the N! permutations, and the question becomes, which modification of the inv-value correspond to a swap of neighbours: each swap of two neighbours changes exactly one inv[i]-value by 1 , viz. with i = the larger of the two values swapped. The value of inv[i] is to be increased by 1 if the swap increases the number of inversions —i.e. if the larger value moves “to the left”otherwise it is to be decreased.

A feasible sequence of inv-values to be generated is now reasonably obvious; it is the generalization of the Gray-code. For N = 4 it begins:

inv[0] | inv[1] | inv[2] | inv[3] | a[0] | a[1] | a[2] | a[3]
0 | 0 | 0 | 0 | 0 | 1 | 2 | 3
0 | 0 | 0 | 1 | 0 | 1 | 3 | 2
0 | 0 | 0 | 2 | 0 | 3 | 1 | 2
0 | 0 | 0 | 3 | 3 | 0 | 1 | 2
0 | 0 | 1 | 3 | 3 | 0 | 2 | 1
0 | 0 | 1 | 2 | 0 | 3 | 2 | 1
0 | 0 | 1 | 1 | 0 | 2 | 3 | 1
0 | 0 | 1 | 0 | 0 | 2 | 1 | 3
0 | 0 | 2 | 0 | 2 | 0 | 1 | 3
0 | 0 | 2 | 1 | 2 | 0 | 3 | 1
0 | 0 | 2 | 2 | 2 | 3 | 0 | 1
0 | 0 | 2 | 3 | 3 | 2 | 0 | 1
0 | 1 | 2 | 3 | 3 | 2 | 1 | 0
0 | 1 | 2 | 2 | 2 | 3 | 1 | 0

etc.

The rule is as follows. An inv[i]-value is defined to be “changeable” if it may be increased or decreased by 1 . It may be increased if the sum of the inv[j]-values to its left —i.e. for j < i — is even and it has not reached its maximum value; it may be decreased if the sum of the inv[j]-values to its left is odd and it has not reached its minimum value zero. At each step, always the right-most changeable inv[i]-value —i.e. with the largest i-value— is changed. It is not difficult to see that in the permutation, the value i is, indeed swapped with a smaller value. (We leave it to the reader to prove that, starting with inv[i] = 0 for all i , N!-1 applications of this rule yields the remaining N!-1 possible inv-values.)

After having established the value i , such that inv[i] has to be changed, and, also, whether the value i has to be swapped with its predecessor in the permutation (corresponding to an increase of inv[i] ) or with its successor in the permutation (corresponding to a decrease of inv[i] ), we have to establish the place c in the permutation, where the value i is located. This value c is given by

| i - (the number of smaller values to its right)
|  | + (the number of larger values to its left) .

Because for all j > i , inv[j] has an extreme value (0 or j), c is given by c = i - inv[i] + (the number of values of j such that j > i and inv[j] = j )

In the following program we have given inv[0] —which should be constantly = 0 — the funny value -2 ; this is the usual, mean, little coding trick, in order to let the search for the right-most changeable inv[i]-value terminate artificially when there is no more such an inv[i]-value. The variable “totinv” records the total number of inversions in the array a, used to record the permutation. The invariant of the inner loop in the following program is

| 0 ≤ i < N or
| (i < j < N) ⇒ “inv[j] is not changeable” and
| linv = “sum of the inv[j]-values for 0 < j < i” and
| c = “number of values j such that i < j < N and inv[j] = j” .

| begin integer array a, inv [0:N-1]; boolean ready; integer totinv, i, c, linv;
| i:= 0; do i < N → a[i]:= i; inv[i]:= 0; i:= i + 1 od; inv[0]:= -2;
| ready:= false; totinv:= 0;
| do non ready → printarray(a);
|  | {establish the value i such that inv[i] has to be changed:}
|  | i:= N - l; c:= 0; linv:= totinv - inv[i];
|  | do inv[i] = i and even(linv) →
|  |  |  |  | c:= c + l; i:= i - l; linv:= linv - inv[i]
|  |  | ▯ inv[i] = 0 and odd(linv) →
|  |  |  |  | i:= i - l; linv:= linv - inv[i]
|  | od { inv[i] has to be changed if i > 0 };
|  | {compute the position c of value i in the permutation:}
|  | c:= c + i - inv[i];
|  | {generate next permutation or signal completion:}
|  | if even(linv) and i > 0 →
|  |  |  | inv[i]:= inv[i] + l; totinv:= totinv + l; swap(a, c-l, c)
|  |  | ▯ odd(linv) and i > 0 →
|  |  |  | inv[i]:= inv[i] - l; totinv:= totinv - l; swap(a, c, c+1)
|  |  | ▯ i = 0 → ready:= true
|  | fi
| od
| end

Post Scriptum.

The problem solved above has been posed to me by David Cries, who told me that he had found it a non-trivial task to present a solution to it in a convincing manner. The argument shown led quickly to the above solution, which is submitted for publication upon his request. Finally I would like to express my great indebtness to the referee whose many and well-considered recommendations have led to a considerable improvement in readability. (End of Post Scriptum.)

Burroughs | prof.dr.Edsger W.Dijkstra
Plataanstraat 5 |
NUENEN - 4565 |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

EWD554

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
|  | EWD 554 A personal summary of the Gries-Owicki Theory :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 188�199 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

A personal summary of the Gries-Owicki Theory.

This is a very personal summary of the theory developed by Susan Speer Owicki under supervision of David Gries. I had a flu, and on its first day I just slept and shivered; later I passed the time in bed with trying to reconstruct what I had learned from reading in Susan Owicki’s doctoral thesis. If the following fails to do justice to their work —someone has borrowed my copy of her thesis!— I am the only one to blame.

There has been a time that it was the function of our programs to instruct our machines, but times have changed: now it is more fruitful to consider it the purpose of our machines to execute our programs. The same shift of attention can be recognized in the more theoretical work that is concerned with the semantics of programming languages. There has been a time, that this was a very descriptive activity, trying to capture what happened in our machines during program execution. The result has been a series of operational language definitions. in which the semantics of programming languages was given via an interpreter that under control of the program text changed the machine state over and over again. By means of “abstract programs” and equally “abstract states” people have tried to mold this approach into a viable tool, but it kept all the essential disadvantages of operational language definitions. Faced with a specific program they tell you no more than how to do a hand-simulation. Since Floyd, and later but more noticeably Hoare, we have been shown another approach, which seems more promising.

Here a program text is regarded as a mathematical object all by itself, which is postulated to establish a relation between two machine states. If we were very pure, we should call them, say, the “left-hand state” and the “right-hand state”. The relation between the two states is implicitly given by a set of axioms and rules of inference that together delineate what, given a text, one can prove about that relation. Taken all by itself, this would be a very formal and rather sterile game, but it so happens that the axioms have been chosen very carefully, so carefully in fact, that when we identify the “left-hand state” with the initial state and the “right-hand state” with the final state of a computer (as can be recorded in its store) a started sequential computer can establish an instance of that relation (and even can do so without implicit backtracking).

In the preceding paragraph I have tried to capture the essence of this so-called “axiomatic method” as clearly as possible, because it has generated after its introduction much misunderstanding and discussion (which has generated more heat than light). Even as much as five years later the axiomatic method has been blamed for not demonstrating that it captured correctly the computational model, that was supposed to underly it,“the computational model on which it was based”. The axiomatic method is not “based” upon a computational model, the most we can say is that it has been inspired by a computational model. Once the axioms are chosen, it is the obligation of the implementation to provide a sufficiently truthful model. with purely sequential programs, this approach has been very successful, the Gries-Owicki Theory presents the first significant step towards applying similar techniques to concurrent processing as well.

Taken literally, the previous sentence makes no sense. From a very puristic point of view, neither Floyd, nor Hoare (nor I in the early seventies) talked about “sequential programming” or “sequential programming languages”. We talked about texts, and about proving things about them. The aspect of “being sequential” had absolutely no meaning on that level of discourse, it became only meaningful when we tried to visualize a computer establishing an instance of the relation, when we tried to visualize “a computation”. And the axioms we considered were such that the only safe and realistic implementation of such a computing engine that we could envisage, was one in which the actions took place one after the other. Apart from that “implementation detail” the whole notion of sequentiality was not applicable in our level of discourse in which we had abstracted quite rigorously from the class of computational histories.

From the same puristic point of view, the Gries-Owicki Theory does not deal at all with concurrent processing. It is again a formal system relating a pair of machine states to each other by means of a text. Only the proof rules —the axioms and the rules of inference— differ. It so happens that, when we would like to design a computing engine able to establish an instance of this relation, we suddenly see a straightforward way in which a number of processors could be engaged concurrently on that task. 50 we are not designing a “language for concurrent programming” or any similar misnomer, from our mathematical point of view it is a programming language as any other, with consequences and possibilities for the implementation that we should ignore at the current level of discourse.

A simple “sequential” program can be represented as

S = | “S0; S1; ... ; Sn” .

When we wish to describe in more detail the kind of relations between initial an final state, say that we wish to establish a set of initial states corresponding to a final state satisfying the relation R , we can interlace our sequence of statements Si with a sequence of relations Pi :

| “{P0} S0; {P1} S1; ; {Pn} Sn {R}” .

The axiomatic definition associates with each statement Si —assignment statements to start with— a so-called predicate transformer wp . If now we have

for 0 ≤ i < n | Pi = wp(Si, Pi+1)
| Pn = wp(Sn, R)

then, for the whole program S we have P0 = wp(S, R) and we interpret P0 as the weakest pre-condition for the initial state such that starting program S as a whole is certain to end up in a final state satisfying R .

This is, because from given units Si —say: assignment statements— the semicolon describes how a new unit can be formed. In formula the semantics of the semicolon is given by wp(“S1; S2”, P) = wp(S1, wp(S2, P)) from which, for instance, follows that the semicolon is associative. If we wanted, for instance, to combine in program S the first two initial statements to a single unit —indicated by square brackets— we could indicate this as follows:

| “{P0} [S0; S1]; {P2} S2; ; {Pn} Sn {n}”

By combining S0 and S1 in the above way into a single unit, the relation P1 remains anonymous; implementation-wise it says that we prefer not to pay explicit attention to the “intermediate state” that will prevail after the execution of S0 , but before the execution of S1 . In the purely “sequential systems” we are familiar with, our freedom in combining units into larger ones, thereby eliminating the “internal predicates” is unrestricted: we are all the time free to choose to consider a composite object either as an unanalyzed whole or as something composed out of parts. In the Gries-Owicki Theory this freedom is restricted (thereby giving the implementation greater freedom, such as the introduction of concurrency).

We have shown on the previous page how the concatenation via the semicolon gives rise to internal predicates. So do the other sequencing techniques or “control structures” in the case of “sequential programming” , e.g.

| {P12} if B1 → {P1} S1
|  |  | ▯ B2 → {P2} S2
|  | fi {R12}

Here the rules are that P12 should be the weakest predicate satisfying

| P12 ⇒ (B1 or B2) (in order to avoid abortion)
| (P12 and B1)⇒ P1
| (P12 and B2)⇒ P2

where P1 and P2 are given by P1 = wp(S1, R12) and P2 = wp(S2, R12) .
Again we are free to “eliminate” predicates such as P1 or P2 , for instance by replacing the second equation by

| (P12 and B1)⇒ wp(S1, R12) .

In our program we could indicate that elimination of P1 for instance by

| {P12} if [B1 → S1]

somehow suggesting that the whole first guarded command is to be regarded as a single unit. In “sequential programming” such freedom of combination, of elimination of predicates, is unrestricted.

The notation of the square brackets is unattractive if we want to indicate the elimination of the predicate following a repetitive construct. The second problem that the repetitive construct introduces is the problem of termination. Provided

| (P12 and B1) ⇒ wp(S1, P12)
| (P12 and B2) ⇒ wp(S2, P12)

we can read and justify

| {P12} do B1 → S1
|  |  | ▯ B2 → S2
|  | od {P12 and non (B1 or B2)}

as stating that the initial validity of P12 is sufficient to ensure the final validity of (P12 and non (B1 or B2)) , provided that the repetitive construct terminates on this level. If the repetitive construct is followed by a next statement, we can again eliminate its post-condition by straightforward proving that it implies the pre-condition for that following next statement.

Certain predicates are never eliminated. We never eliminate the predicate describing the total pre-condition, nor the predicate describing the total postcondition. (In a sense they can never be regarded as the internal predicate of a composition.) Furthermore we shall never eliminate what could be described as “the post-condition of a guarded command set”. If the guarded command set is the body of an alternative construct, this refers to the post-condition of the alternative construct; if the guarded command set is the body of a repetitive construct, this refers to the invariant relation. The reason for this restriction is the following: each assignment statement and each set of guards has now a unique preceding predicate, where with “preceding predicate” we mean the last preceding, non-eliminated predicate. For instance

| {P0} S1; S2;
| {P1} S3; if B4 → {P2} S4
|  |  |  |  | ▯ B5 → S5; S6
|  |  |  | fi;
| {P3} S7;
| {P4} do B8 → S8; {P5} S9 {P4}
|  |  | ▯ B10 .. S10 {P4}
|  | od; S11 {R}

Then we have:⇒
P0 is the preceding predicate of S1, and S2;
P1 is the preceding predicate of S3, B4, BS, S5, and S6;
P2 is the preceding predicate of S4
P3 is the preceding predicate of S7
P4 is the preceding predicate of B8, S8, B10, S10, and S11
P5 is the preceding predicate of S5.

Besides non-abortion in the alternative construct and termination of the repetitive construct, we have to prove
P0 ⇒ wp(S1, wp(S2, P1))
P1 ⇒ wP(S3, (B4 ⇒ P2) and (B5 ⇒ wp(S5, wp(S6, P3))))
P2 ⇒ wp(S4, P3)
P3 ⇒ wp(S7, P4)
P4 ⇒ (B8 ⇒ wp(S8, P5))and (B10 ⇒ wp(S10, P4)) and (non (B8 or B10) ⇒ wp(S11,R))
P5 ⇒ wp(S9, P4) .

Here are six relations. They are implications with an assertion at the left-hand side, and at the right-hand side, besides other assertions, only guards and statements of which the left-hand side is “the preceding predicate”.

Suppose for a moment that, via other means we have established that P0 is strong enough to guarantee proper termination as well. Starting the obvious sequential implementation in an initial state satisfying P0 , a computation would ensue during which at the corresponding stages the machine would be in a state satisfying one of the Pi’s, and finally the machine would end in a state satisfying R. What would we have to prove in addition if we would like to ensure, that at all those stages another predicate, Q say, would be true as well? This, of course, under the assumption that we would start the machine in an initial state also satisfying Q .

Well, in principle, we should replace in our six relations all the predicates Pi and R at all their occurrences by Pi and Q and R and Q respectively! The first line would then become
P0 and Q ⇒ wp(S1, wp(S2, P1 and Q))
Its right-hand side reduces as follows:

wp(S1, wp(S2, P1 and Q)) | = wp(S1, wp(S2, P1) and wp(S2, Q))
| = wp(S1, wp(S2, P1)) and wp(S1, wp(S2, Q)) .

Therefore, when the formulae at the bottom of page 4 —without the Q inserted —have been proved, our only additional proof obligation is:
P0 and Q ⇒ wp(S1, wp(S2, Q))
With respect to our original program we say that we have “proved the invariance of Q”.

Consider now two programs, operating on the same variables. Suppose further, that with respect to each program we have proved the invariance of the assertions occurring in the other (or: occurring in the others, when we have three or more of such programs). This is, of course, a very strong assumption. But if it is satisfied, we have proved something useful about the following non-deterministic implementation.

Let us start a machine in an initial state satisfying each program’s initial assertion. we now allow the execution of an arbitrary one of the programs to proceed until its next assertion. Firstly we have proved that this assertion will then hold, secondly we have proved that the initial assertion(s) of the other program(s) have not been disturbed. Then, again, an arbitrary program is allowed to proceed with its execution until the next assertion, etc. When all programs have finished, all final assertions will hold.

Mind you: we are not talking about concurrency yet. We are talking about a non-deterministic machine, that can take care of the progress of a bunch of sequential programs, and we have stated conditions under which we can certainly allow a certain degree of interleaved execution, viz. from assertion to assertion.

As the reader will have noticed, I have mentioned a few times “suppose that we have proved proper termination”. I made that caveat, because we would like to apply our theory also to a bunch of programs with the property that for the individual programs proper termination cannot be proved. The termination of a repetitive construct in the one program may depend on the execution of the other program having reached a certain stage. This will certainly be the case when we implement synchronization constraints by means of a busy form of waiting. In a case like that, we cannot even “prove” the termination of the bunch of programs without further assumptions about the daemon that makes the choice how to interleave: the bunch would not terminate if every time the daemon selected the waiting process to perform the next inspection of the unchanged state of affairs! The fact that a proof of termination of the whole bunch may require assumptions about the friendliness of the daemon justifies postponement of that issue.

It is not only the repetitive construct, for which the daemon’s degree of being tamed can be an issue, also the alternative construct might, if we so desire, call for a certain amount of friendliness of the daemon. It could, for instance, be one of the daemon’s restrictions, that an alternative construct, preceded immediately by its “preceding predicate” will never be selected for execution in those machine states where its selection for execution would lead to abortion of that program.

For the time being we assume that there is at least one sequence of choices by the daemon that will lead to proper termination of all the programs, and we assume the daemon to be friendly enough to choose such a sequence.

But even for that target, our formalism has to be changed: we have to replace the weakest pre-conditions wp(S, P) which guarantee proper termination in a final state satisfying P by the so-called “weakest liberal pre-conditions” wp(S, P) guaranteeing that the mechanism S will not terminate in a state not satisfying P . (This is the transition from total correctness, where the production of the right result is guaranteed, to partial correctness, where only the production of a wrong result is excluded. C.A.R.Hoare has taken this step a long time ago, and apparently at that time without much hesitation; I don’t like it too much and would not like to take it unless I felt forced to do so.)

*              *
*

The next step is to introduce the possibility of concurrent execution, but to do it in such a way that, firstly, it is easily implementable, and, secondly, that no further non-determinacy is introduced. For this purpose we divide the variables over various classes. On the one hand we have the private variables; private variables are always private to a specific program, viz. the only program that is allowed to refer to them. They are the local variables of the program they are private to, the other programs cannot inspect their values, not change them. On the other hand we have the so-called common or shared variables: they are the remaining variables, to which at least two processes refer. It is clear that all interaction between the different programs must take place via the shared variables.

Each program is executed from assertion to assertion; here we assume that evaluation of a guard from a guarded command set implies the evaluation of all the guards from that set. The step from each assertion to the (dynamically) next assertion —our considered grain of interleaving— we call “a unit of action”. We now impose upon our units of action the constraint that they can be implemented with at most one access to at most one shared variable. with a memory switch that, in case of competition, orders the individual accesses to memory in some way or another, it is now clear that we can allow concurrent execution of as many units of actions as we have still incompleted programs. The reason that we are allowed to do so is that, no matter how we mix them, there always exists an order in which the units of action, executed one at a time, would have established the same net effect. Two units of action referring to two different common variables (or to no common variables at all) commute, for two units of action referring to the same common variable we can take the order in which the switch has granted them access to that shared variable.

Our restriction as regards access to shared variables has severe consequences: the guards of a guarded command set may refer to at most one shared variable. On the other hand, we now know that, with B a shared variable

| {P} if B → S1
|  |  | ▯ non B → S2
|  | fi {P2}

will not lead to abortion. (Note, that in the case of two successive inspections of B it is hard to prevent that, when the first inspection has encountered the value false , the next inspection may encounter the value true .) Note, that, if in the above example, B is not a common variable (nor an expression referring to one), the guards of the guarded command set do not refer to a shared variable, and that in that case S1 may refer once to a common variable, and S2 may refer once to a different common variable: we have two possible units of action! For the time being, this is about the only thing I intend to say about concurrency.

*              *
*

Consider now the two programs |  | ↯ Here two assertions are missing! Sorry! EWD

{P0} in1:= true; | {Q0} in2:= true;
{P1} od in2 → ↯in1:= false; | {Q1} od in1 → ↯in2:= false;
                {P2} in1:= true {P1} |                 {Q2} in2:= true {Q1}
        od |         od
        luck1:= true; |         luck2:= true;
{P3} critical section 1; | {Q3} critical section 2;
{P3} luck1, in1:= false, false; | {Q3} luck2, in2:= false, false;
{P4} noncritical section 1 | {Q4} noncritical section 2 .
PROGRAM 1 | PROGRAM 2

with P0: non luck1 , we can prove
P1: non luck1 and in1
P2: non luck1 and non in1
P3: in1 and luck1
P4: non luck1 and non in1
and similarly for the Q’s in Program 2. Furthermore we observe that all the Pi imply P: luck1 ⇒ in1 , and, similarly, that all the Qi imply Q: luck2 ⇒ in2 We can now replace all the original assertions Pi in Program 1 by Pi and Qj for any j : the proofs remain valid, because Program 1 does not refer to the variables mentioned in Qj . Similarly we can replace all the original forms of Qi in the second program by Qi and Pj for any j : again the proofs remain valid, because Program 2 does not refer to the variables mentioned in Pj . Having thus proved that the assertions of each of the programs are invariant with respect to the other program, we can conclude the universal validity of P and Q .

Finally we consider the relation R : non(luck 1 and luck 2) . Also this relation can be added to all assertions, it is also everywhere valid. The critical assignment in Program 1 that could destroy its validity is, of course “luck1:= true”, but it is safe, because

| wp(“luck1:= true”, R) = non luck2 ,

a condition that is implied by Q and non in2 . We interpret the universal validity of R as the guarantee of mutual exclusion in time of the two critical sections.

*              *
*

The classical use of critical sections has been the maintenance of an invariant relation

| IR(a, b, c)

between a number of shared variables —here denoted by a , b , c— , where this invariance cannot be maintained by a single unit of action, as a result of which a modification of the variables a, b, and c always implies a temporary violation of IR(a, b, c), after which it is again restored. with the aid of the additional variables we can replace it by a relation which is, indeed, universally valid, viz.:

| luck1 or luck 2 or IR(a, b, c) .

Under the assumption that the pieces of program denoted by “noncritical sections” do not refer to the shared variables a, b, and c —nor to the private variables “luck”, of course— the proof that the noncritical sections leave this relation invariant is trivial. For the critical sections —the only pieces of program that are allowed to refer to a , b , and c— it suffices to give the invariance proof for each of the critical sections in isolation.

At the beginning of critical section 1 —i.e. immediately after the assignment “luck1:= true”, we can assert

| luck1 and IR(a, b, c) . | (1)

Internally, within the critical section 1 , we can introduce, wherever IR(a, b, c) is temporarily violated, assertions of the type

| luck1 and IR(a, b, c, priv1) | (2)

where with “priv1” we have denoted any other variables —besides luck1— that are private to Program 1. At the end of the critical section 1 —i.e. just before luck1 is reset to false— we must have again assertion (1) . We assume a similar proof that critical section 2 , considered in isolation, as a whole does not violate IR(a, b, c) .

The reasons why these two separate proofs for the critical sections in isolation suffice, is that assertions (1) and (2) are invariant with respect to Program 2 (and vice versa). The internal statements of critical section 2 cannot violate them, because their preceding predicates all contain the factor “luck 2”, and the universal validity of R:

| non(luck1 and luck2) |

ensures that the conjunction of these predicates and the assertions (1) and (2) is F ; because false implies everything, these proofs of invariance are trivial. The statements in noncritical section 2 cannot violate them either, because they don’t refer to the variables occurring in (1) or (2).

Note. These proofs are so trivial that within critical sections the constraint that what we consider as “units of actions” refer at most to one shared variable can be weakened. Because, with a private variable “register”

| register:= c; {register = c} c:= register + 1

gives rise to an internal assertion “register = c” which is trivially invariant, it is tempting to consider then the alternative c:= c + 1 as a unit of action. Such shortcuts should only be introduced with great care. (End of note.)

*              *
*

Our solution for the mutual exclusion problem uses essentially two shared variables in1 and in2 . (They are really the only two variables that matter: the variables luck1 and luck2 are so-called “ghost variables” which have only been introduced for the sake of being able to formulate what we mean by “mutual exclusion” and of being able to formulate the proofs. In the actual programs to be executed they —and all operations operating on them— can be eliminated.) We also know that this solution is not acceptable when we reject solutions with the danger of after-you-after-you blocking. This danger is exorcized by Dekker’s solution, which I give below in the following form. The initial value of the shared integer “turn” should be either 1 or 2 . I only give Program 1 ; Program 2 can be obtained from it by interchanging 1’s and 2’s.

{P0} in1:= true;
{P1} if in2 → {P2} if turn = 1 → skip {P3}
|  |  |  |  | ▯ turn ≠ 1 → {P4} in1:= false;
|  |  |  |  |  | {P5} do turn ≠ 1 → skip {P5} od;
|  |  |  |  |  | {P6} in1:= true {P3}
|  |  |  | fi;
|  |  | {P3} do in2 → skip {P3} od;
|  | ▯ non in2 → skip
| fi;
| luck1:= true;
{P7} critical section l;
{P7} turn:= 2;
{P7} luckl, in1 := false, false;
{P8} noncritical section l

Studying this program in relative isolation, we derive, under the assumption
P0: non luck1             further
P1: non luck1 and in1
P2: P1
P3: non luck1 and in1 and turn = 1
P4: non luck1
P5: non luck1 and non in1
P6: non 1uck1 and non in1 and turn = 1
P7: luck1 and in1
P8: non luk1 and non in1

Again the relation luck1 ⇒ in1 is implied by all of them, and together with Program 2 we can derive the universal validity of non(luck1 and luck2) as before.

The difference between this program and the program on page 8 is that we need only weaker assumptions about the daemon if we would like to be sure of termination of the program on page 11. with the program on page 8, the daemon could select an unbounded number of units of actions from Program 1 and an unbounded number of units of actions from Program 2, without ever one of the critical sections being selected. With our new programs this is no longer true.

Selection of an infinite number of units of actions from program 1 implies —because there are only two loops in it, and from at least one an infinite number must be selected— the validity of

| (P5 and turn ≠ 1) or (P3 and in2)

or

| (non in1 and turn ≠ 1) or (in1 and in2 and turn = 1) | (3)

(Note that the term “turn = 1” in the Pi is invariant with respect to Program 2.) For Program 2 we have the corresponding relation

| (non in2 and turn ≠ 2) or (in1 and in2 and turn = 2) | (4)

The conjunction of (3) and (4) reduces to

| (non in1 and non in2 and turn ≠ 1 and turn ≠ 2) . |

And, indeed, when we start the two programs with, say, turn = 3, the infinite looping of both programs is quite easily realized. If, however, we start the two programs — and so we assume— with

| turn = 1 or turn = 2 | (5)

then it is easily seen that (5)’is invariant with respect to both programs, therefore can be regarded as universaly valid, and thus implying the falsity of the conjunction of (3) and (4). This falsity is usually taken as the proof of the absence of the danger of after-you-after-you blocking (and, a fortiori, the absence of the danger of deadlock).

The conclusion that the machine executing the programs‘ units of action in interleaved fashion will eventually terminate, rests on the assumption that the daemon will not be so grossly unfair as to select always the next unit of action from the same program. From a formal point of view this is a most unattractive assumption.

It would introduce a mechanism of unbounded nondeterminacy, it would give us means for implementing

“set x to any positive integer”
without being able to give an upper bound for the final value of x . We could, for instance, replace in program 1 the statement do in2 → skip od by

x:= 1; do in2 → x= x + 1 od .
The consequences of introducing unbounded non-determinacy are sufficiently horrifying to reject the above approach.

Such a little loop with a skip as the repeatable statement is, of course, too indirect a way of indicating that to all intents and purposes, this program should not continue. We supply it with a kind of “fake continuation”. The only way of not making assumptions about the fairness of the daemon is to restrict it explicitly in its freedom. The alternative construct gives us a way out.

In normal sequential programming we have regarded an alternative construct with all its guards false as a reason for abortion. An equivalent rule for the implementation would be: postpone progress of this computation as long as all the guards are false. In a uniprogramming environment we have “once all false, always all false” and this second rule would be as good as abortion. In a multiprogramming environment it would mean for the daemon that, as suggested on page EWD554 - 6,“an alternative construct, preceded immediately by its “preceding predicate” will never be selected for execution in those machine states where its selection for execution would lead to abortion of that program”. By replacing in the program on page EWD554 - 11

do turn ≠ 1 → skip od | by if turn = 1 → skip fi
and |
do in2 → skip od | by if non in2 → skip fi

and postulating that the daemon will not select a unit of action that starts with an alternative construct with false guards only, we have eliminated from this example all unbounded repetitions. To what extent the ideal “no unbounded repetitions in the individual programs” can be achieved in general —possibly by allowing certain special units of action to refer to more than one shared variable— is a question to which I don’t know the answer at the moment of writing.

14th of March 1976 | prof.dr.Edsger w.Dijkstra
Burroughs, Plataanstraat 5 | Burroughs Research Fellow
NUENEN - 4565, The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

EWD555

Aan de Raad van Advies.

Na ontvangst, lezing en herlezing van van Leeuwen’s “Beschouwing”, van de Bakker’s “Kort Commentaar” en van de uitnodiging van Uw voorzitter wist ik niet goed meer, wat mij te doen stond en heb ik Uw voorzitter om opheldering moeten vragen. De brief van Uw voorzitter sprak nl. slechts van een oordeel over de twee eerstgenoemde stukken en niet van een opinie of oordeel over de daarin behandelde materie.

Ik vroeg hem daarom, of wij onze taak wat ruimer mochten opvatten, dan wel wij verwacht werden ons tot de stukken zelf te beperken en slechts opmerkingen te maken over zaken zoals het slechte Nederlands, waarin de Beschouwing gesteld is. Uw voorzitter vertelde mij, dat een ruimere taakopvatting inderdaad van ons verwacht werd en, sterker, dat commentaar op taalgebruik niet nodig was.

Op dit laatste punt verschil ik ernstig met Uw voorzitter van mening. Slonzig taalgebruik is nl. niet een symptoom van verval, het is een van de meest ervoor werkzame katalysatoren. Met verontreinigingsmiddelen kun je nu eenmaal geen varkentjes wassen. De instelling in dezen van Uw voorzitter dwingt mij uitgebreider op het Nederlands, waarin de Beschouwing gesteld is, in te gaan, dan ik anders gedaan had. (Ik had er in elk geval iets van gezegd! Na het lezen van de Beschouwing was het lezen van het Kort Commentaar een verademing....)

*            *
*

Om te beginnen deugt de spelling niet. De leerlingen van mijn vader, die leraar chemie is geweest, hadden de vrije keuze tussen “Phosphor” en “Fosfor”; de spellingen “Phosfor” en “Fosphor” waren niet toegestaan. Van Leeuwen verraadt onmiskenbaar geen leerling van mijn vader te zijn door (pg. 9, laatste regel) de spelling “klassificatie” te hanteren.

Vervolgens deugt zijn woordkeus niet. Het stuk barst van de germanismen: “benutting” (pg. 1, regel 7 v.o., pg. 2, regels 1–2 v.b., pg. 10, regel 8 v.b.), “vakmatig” (pg. 2, regel 12 v.o.), “overcapaciteit” (pg. 10, regel 6 v.o.), “beroepsmatig” (pg. 12, regel 1 v.b.), “beleidmatig” (pg. 12, regel 3 v.b.). Voorts wordt “uitspreiden” (pg. 1, regel 14 v.o.) als intransitief werkwoord gebruikt. Ook de werkwoorden “prolifereren” (pg. 1, laatste regel) en “overlappen” (pg. 2, regel 8 v.o.) wordt de lezer geacht te accepteren. Het Curatorium van het M.C. zou kunnen overwegen van Leeuwen als dank voor de bewezen diensten een grote van Dale aan te bieden.

De auteur schrijft over “het direct toepasbaar en commercieel belang” (pg. 9, regel 3 v.b.), de lezer in verwondering achterlatend wat hij zich bij een direct toepasbaar belang precies moet voorstellen. Twee systemen (pg. 9, regel 12 v.o.) “staan in verband”: de lezer moet raden waarmee.

De auteur springt wat losjes om met het woordje “dus” (pg. 1, regels 7 en 13 v.o., pg. 6, regel 13 v.o.) en toont grote voorliefde voor het voorzetsel “in” en zijn samenstellingen (pg. 3, regel 4 v.o. “in dit terrein” i.p.v. “op dit terrein”, pg. 3, regel 7 v.b. “daarin” i.p.v. “daarvan”, pg. 8, regel 10 v.o. “daarin” i.p.v. “daarmee”, pg. 8, regel 3 v.o. “in” i.p.v. “tot”).

Zoals na het bovenstaande verwacht kan worden, staan er ook duistere zinnen in, zoals in sectie 1.3:

“De afdeling is altijd op onderzoek en gericht ontwikkelingswerk ingesteld geweest, en wordt nog maar weinig betrokken in de automatiseringsproblemen waarvoor men zich elders geplaatst ziet.”

Ik zit hier met het laatste woordje “en” in mijn maag; zou “maar” op zijn plaats een betere zin vormen? Is de bedoeling te zeggen dat in “onderzoek en gericht ontwikkelingswerk” van de afdeling automatiseringsproblemen elders veronachtzaamd zijn, of wordt betreurd, dat men “elders” nalaat de afdeling met haar juist relevante kennis en ervaringen in de oplossing van zijn automatiseringsproblemen te betrekken?

Sectie 1.4 is zo duister, dat we hem iets nauwkeuriger zullen trachten te ontleden. Ik citeer:

“De algemene opvatting in de Nederlandse informatica is vooral de praktische computerbenutting te ontwikkelen en in mindere mate hierin grondslagenonderzoek te betrekken.”

Ik heb het al wat moeilijk met de constructie “de opvatting is iets te ontwikkelen”; je kunt zeggen “de opvatting is, dat iets ontwikkeld dient te worden” of “het is van belang iets te ontwikkelen”. Maar waar slaat het woord “hierin” op terug? Op de “benutting” of op de “informatica”. Heeft de auteur willen zeggen

“In de Nederlandse informatica staat de efficiency van computergebruik centraler dan het grondslagenonderzoek.”

of

“In de Nederlandse informatica wordt het probleem van efficient computergebruik meer pragmatisch dan fundamenteel benaderd.” ?

Of nog heel iets anders? Ik weet het niet. Ik citeer verder:

“Een goede combinatie is van groot belang maar omdat slechts weinigen tegelijk expert zijn in de praktische en theoretische computerkunde zal dit onderwerp nog wel in discussie blijven.”

Om te beginnen: een combinatie waarvan? De rest van de zin suggereert van “theorie” en “praktijk”, maar vervolgens rijst de vraag wat met “dit onderwerp” bedoeld wordt. En wat voor discussie heeft de auteur op het oog? Ik geef weer twee mogelijke interpretaties:

“Omdat slechts weinigen zowel in de practische als de theoretische computerkunde over voldoende expertise beschikken, is een inniger verband tussen theorie en praktijk op korte termijn helaas niet te verwachten.”

of

“Omdat slechts weinigen zowel in de practische als de theoretische computerkunde over voldoende expertise beschikken om theorie en praktijk metterdaad van elkaar te laten profiteren, zal het gesprek over hoe deze wederzijdse bevruchting het beste tot stand gebracht kan worden, wel in een overloze discussie ontaarden.”

Ik citeer verder:

“De werkzaamheden in de afdeling Informatica tonen goed (en waarschijnlijk beter dan elders in het land) hoe onscheidbaar deze aspecten zijn.”

Deze zin —en misschien is dat de bedoeling!— kan van alles betekenen, varierend van

“De spectaculaire resultaten van de afdeling Informatica zouden zonder innige samenwerking tussen theorie en praktijk niet tot stand hebben kunnen komen.”

tot

“Sinds op de afdeling Informatica theorie en praktijk uit elkaar gegroeid zijn heeft deze afdeling geen significante resultaten meer geboekt.”

Hoe de werkzaamheden in de afdeling Informatica de onscheidbaarheid hebben getoond, blijft in het midden, evenals waarom ze het daar beter zouden hebben getoond dan elders in het land. Wij citeren verder:

“De ervaringen hierover die nu prolifereren in studiecentra en opleidingsinstituten voor informatica verdienen betere benutting in academische kring.”

Welke “ervaringen” heeft de auteur op het oog? Waar slaat “hierover” op terug? Bedoelt hij non-academische instituten, waar waardevol materiaal circuleert, dat in academische kring onbekend is, of bedoelt hij academische “studiecentra en opleidingsinstituten voor informatica” waar materiaal, hoewel “prolifererend” niet “benut” wordt? En rekent hij de afdeling Informatica van het M.C. wel of niet tot de “academische kring”?

Ik moge dit gedeelte van mijn bespreking afsluiten met een (zuster van) Tante Betje van de auteur: (pg. 13, regels 4–6 v.b.)

“Het ligt niet op mijn weg conclusies te ontwikkelen en laat mijn observeringen verder aan de lezer.”

*            *
*

Altijd is er enerzijds het werkgebied, dat als “practisch zinvol” wordt beschouwd, en anderzijds het werkgebied, dat als “theoretisch gezond” wordt ervaren. Dat deze twee gebieden gewoonlijk niet vanzelf samenvallen, is genoegzaam bekend; sterker: er is doorgaans een bewuste inspanning voor nodig, de doorsnede niet relatief in omvang te laten afnemen. Voor wie graag in dit doorsnijdingsgebied wil werken en voor wie zou willen proberen deze doorsnede te vergroten, is de informatica in de afgelopen decaden een uitzonderlijk dankbaar terrein geweest en zal zij dat in mijn verwachting ook nog wel een paar decaden blijven. (Ik beschouw de informatica dan ook bv. als een ideaal werkterrein voor de “wiskundig ingenieur” met de nadruk gelijkelijk verdeeld over beide componenten van die titel. Een geestelijk klimaat waarin een van beide componenten sterk overheerst, lijkt voor de evenwichtige ontwikkeling van de informatica dan ook alles behalve bevorderlijk. Dat bv. in Frankrijk, Polen, Leiden en Utrecht de informatica nooit fatsoenlijk van de grond is gekomen, wijt ik voornamelijk aan de dominante positie van de —zuivere— wiskunde aldaar. Wie zich een beeld wil vormen hoe de informatica kwijnt als de pragmatiek overheerst, kan ik verwijzen naar vele rekencentra —bij voorkeur naar die, die door de hoge-energiephysici gedomineerd worden.)

Ik heb goede nota genomen van de relativering in het Kort Commentaar van de scheiding tussen Theorie en Praktijk, zoals die in de Beschouwing gepresenteerd wordt. Nochtans is de indruk, dat de onderlinge afstand vaak groter is dan wenselijk ware, hierdoor helaas niet weggenomen. Ik kan mij niet aan de indruk onttrekken, dat er op de afdeling theoretisch onderzoek gepleegd wordt, waarvan het onduidelijk is hoe de rest van de informatica ervan zou kunnen profiteren. De opmerking in de Beschouwing (3.6) dat “onderzoek in de subafdeling in de uithoekjes van haar theoretisch specialisme is gefixeerd” lijkt mij dan ook terecht gemaakt. De opmerking (3.7) “In academische kring liggen de tegenwoordige behoeften duidelijk ruimer.” mag van mij zelfs versterkt worden: laat die restrictie “in academische kring” maar rustig weg.

De liefde kan evenwel niet van één kant komen, en bij de keuze van het practisch werk moet derhalve ook een vraagteken gezet worden. Het is de vraag, of de keuze van ontwikkelingswerk, waar geen theorie een boodschap aan heeft en waar geen theorie inspiratie in kan vinden, en dat zijn rechtvaardiging daarom hoofdzakelijk in de bruikbaarheid van het eindproduct moet vinden, voor een groep als de afdeling Informatica van het M.C. verstandig is. Ik ben geneigd deze vraag ontkennend te beantwoorden, zeker als het product geen duidelijk novum is.

Dat van twee van de drie projecten in sectie 5 van de Beschouwing vermeldt wordt, dat elders soortgelijke systemen met succes ontwikkeld zijn, versterkt dan ook mijn reserve. Bij het derde project —computer graphics— laat de Beschouwing zich er niet over uit, of een soortgelijk systeem al elders is ontwikkeld; de veronderstelling , dat zulks inderdaad gebeurd is lijkt niet al te gewaagd.

De opmerking (5.4) “Het graphisch systeem kan zelf dienstbaar zijn in het visualiseren van complexe (data-)structuren tijdens programmaexecutie” —waarbij ik aanneem dat met het laatste woord “programmauitvoering” bedoeld is— heeft mij om twee redenen ernstig verontrust, daar ik mij er slechts al of niet benoemde vakjes met pijlen daartussen bij kan voorstellen, geetaleerd voor didactische (of diagnostische?) doeleinden. Ten eerste koester ik een sterk wantrouwen jegens de didactische en explicatieve waarde van plaatjes met pijlen. Ten tweede proef ik hierin een hulpmiddel om je te leren voorstellen wat er tijdens programmauitvoering gebeurt; ik dacht, dat het belangrijker was te leren, daarvan te abstraheren. Het treft mij daardoor als een verlate echo van het “algorithmisch denken” uit de midden-zestiger jaren.

Ook bij het in sectie 4 in de Beschouwing beschrevene wil ik wel enige kanttekeningen maken. Het Kort Commentaar observeert terecht, dat de Beschouwing hier “vrijwel steeds positief uitvalt” —de veronderstelling dat implementeren niet van Leeuwen’s dagelijks werk is, biedt voldoende verklaring voor de afwezigheid van critische kanttekeningen— en voegt er de waarderende opmerking “Principes van compilerbouw, ook met theoretische nadruk, worden uitgebreid binnen de ALGOL 68 groep bestudeerd.” aan toe, daarbij wijzen op een voorbeeld van de gewenste symbiose tussen theorie en praktijk, tussen denken en doen. Deze opmerking van de Bakker beschouw ik als een heel relevante en heel welkome aanvulling op de Beschouwing.

De Beschouwing vermeldt niet, hoe’n groot gedeelte van de practische subafdeling —het “hart van de afdeling”— de ALGOL 68 groep uitmaakt; mijn vermoeden is, dat het een substantieel gedeelte is. Evenmin vermeldt hij, hoelang een als zodanig identificeerbare groep al werkzaam is; mijn vermoeden is vele jaren. Is ALGOL 68 inmiddels het langst lopende project van de afdeling Informatica?

Ik stel deze vragen, omdat ik de indruk heb, dat de afdeling Informatica met dit project wel heel veel van haar vermogen heeft ingezet op een enkel paard, en daarmee in haar beleid een groot risico heeft genomen. Naarmate dit project een centralere plaats in de afdeling inneemt, wordt het minder ontkoombaar in een evaluatie van de afdeling expliciet een evaluatie van dit project te betrekken.

Er moet worden vastgesteld, of het paard het gehoopte renpaard is gebleken en een klinkklare overwinning heeft behaald, of dat het een sukkelaar is gebleken; die ondanks vele jaren hard duwen nog de eindstreep niet gehaald heeft. Er moet worden vastgesteld of het project de kurk is, waarop de afdeling drijft, dan wel de molensteen om de nek, waaronder de afdeling bezwijkt. Als het project een heel centrale plaats inneemt, moet worden bekeken, hoe de afdeling het zou kunnen afstoten zonder zelfmoord te plegen. Als het antwoord op deze vraag niet duidelijk is, zou dat nl. de diagnose kunnen verhinderen, dat wat op poten is gezet om de afdeling nieuw leven in te blazen, in een slepende ziekte ontaard is.

Ten aanzien van het bovenstaande is de Beschouwing —om begrijpelijke redenen overigens— uiterst neutraal. De uiteindelijke evaluatie van de afdeling mag dat waarschijnlijk niet blijven. (De Beschouwing gaat (4.11) in dezen niet verder dan “De heersende opvattingen over haar [i.e. ALGOL 68] bruikbaarheid zijn in dit stadium nochtans verdeeld.”)

*            *
*

Er zijn in ons land stromingen —Uw voorzitter behoort er toe— die er een voorstander van zijn het begrip “informatica” uiterst losjes —zij noemen het “ruim”— te hanteren, zodat het allen omvat binnen de driehoek, die wordt opgespannen door

a) mensen ( van allerlei disciplines) die wel eens een computer gebruiken

b) electrotechnici die wel eens met pulstechnieken werken

c) logici en overige wiskundigen met enige discrete interesse.

Ik acht dit een te weinig descriptief, en daarom onverstandig, taalgebruik; bij een zo wijd spectrum van zg. “informatici” is er geen coherente discipline meer die al die mensen bindt, waarvan

a) sommigen nog nooit een bewijs geleverd hebben

b) sommigen niet over een getraind abstractievermogen bezitten

c) sommigen nog nooit een programma gemaakt hebben.

Door het ontbreken van deze coherente discipline wordt in dit losse taalgebruik “informatica” tot een holle kreet.

Het komt mij voor dat de afdeling Informatica van dit slordig taalgebruik in meer dan een opzicht het slachtoffer is geworden. Door de vaagheid van de gehanteerde grens tussen de informatica en de rest van de wiskunde heeft de afdeling Informatica binnen het M.C. een stuk profiel verloren. Onthullend is in dezen de zin uit het Kort Commentaar (pg.2–3) “Dat deze medewerkers niet tot de afdeling Informatica behoren, acht ik, gezien het perspectief van het gehele MC, niet van belang.” Dat werkzaamheden binnen het M.C., die de chef van de afdeling informatica tot de informatica rekent, niet binnen, maar wel buiten zijn afdeling bedreven worden, komt mij organisatorisch ongewenst voor. Mist de afdeling Informatica mensen, die er eigenlijk thuishoren, evenzeer kan men opperen, dat de afdeling mensen omvat, die er eigenlijk niet in thuishoren en beter in een afdeling logica of toegepaste wiskunde passen.

Een strengere hantering van de term “informatica” had ons krampachtige constructies als “Theoretische Informatica” —m.i. een contradictio in terminis of een pleonasme— wellicht kunnen besparen, en de afdeling Informatica had zich minder hoeven te versnipperen over “een aantal zwaartepunten”, die met “zwaartepuntjes” beter gekarakteriseerd zijn

*            *
*

Tenslotte moet ik vermelden, dat het streven naar internationale erkenning mij zo zoetjes aan als effectbejag gaat treffen. De politieke manoeuvres, waarmee destijds ALGOL 68 onder die naam en bekrachtigd met het grootzegel van IFIP gepousseerd moest worden, hebben toen op buitenstaanders sterk de indruk gevestigd, dat dit blijk van internationale “erkenning” hoofdzakelijk als hefboom voor binnenlands gebruik moest fungeren. Leek dat toen een geisoleerd geval, nu lees ik in het Kort Commentaar “dat gestreefd moet worden naar werk op hoog niveau [...], teneinde te komen tot een aantal zwaartepunten die nationaal, nu liefst internationaal, bekendheid krijgen.” Nee. De eventuele bekendheid van het werk hoort niet het doel, maar het gevolg van het werk te zijn.

*            *
*

Tot zover mijn commentaar waar de lezing van de Beschouwing en het Kort Commentaar in eerste aanleg aanleiding toe heeft gegeven. Mijn ambivalente houding jegens “the academic establishment” —en in dit geval speciaal jegens de wiskundige sectie ervan— komt er duidelijk in tot uiting. Met een variant op “I love Mankind, it is people that I cannot stand” zou ik kunnen zeggen: “I love Mathematics, it is mathematicians that I cannot stand.”. Deze ambivalentie dat er overigens al uit mijn studententijd toen de in-zichzelf-geslotenheid van het wiskundig establishment (Kloosterman wou van de informatica niets, maar dan ook niets weten!) mij hinderde. De bordjesverhangerij, die we sindsdien hebben kunnen aanschouwen, waarbij wiskundigen op de oude voet —dwz, niet alleen met dezelfde qualiteitsnormen, maar ook met dezelfde relevantie— en significantiecriteria doorgingen, maar alleen deden alsof de term “informatica” nog zo elastisch was, dat het geen kwaad kon hun werk onder die modieuze vlag te presenteren heeft mijn ambivalentie eer versterkt dan verzwakt, omdat ik anderzijds in deze benarde tijden meer oog voor de zorg om de continuiteit heb gekregen. We willen per slot van rekening de wiskunde als kostbaar cultuurgoed graag zo ongeschonden mogelijk aan de volgende generatie overdragen!

Hoe de Raad van Advies verder handelen moet, is mij op het ogenblik nog niet zo duidelijk. Graag wil ik eindigen met een citaat dat mij gisteren onder ogen kwam, en dat mij relevant lijkt. Het is uit het voorwoord van Laurence Trib Corinne S.Schelling en John Voss tot “When Values Conflict” dat bij Ballinger Publishing Company eerdaags zal verschijnen:

“Our ways of evaluating policy options, and our ways of implementing policy choices, cannot rise above our way of talking [cursivering van de schrijvers] about what is at stake and what is to be done.”

Nuenen, 11 maart 1976 | prof.dr.Edsger W.Dijkstra

transcribed by Bart Vreugdenhil
revised 08-Jan-2012

EWD556

Zesde toespraak tot mijn studenten, voorjaar 1976.

"Our ways of evaluating policy options, and our ways of implementing policy choices, cannot rise above our way of talking about what is at stake and what is to be done."

      Laurence Tribe, Corinne S. Schelling and John Voss.

Het bovenstaande citaat is me uit het hart gegrepen, en ik vind het daarom een mooi citaat, dat ik geregeld moet citeren: horen ze het ook een van een ander. Toen ik het in mijn enthousiasme aan een van mijn vrienden liet zien, reageerde die met "Tja, dat lijkt me een waarheid als een koe.", een reactie, die mij niet verbaasde, want hij kwam van een van mijn vrienden.... Het merkwaardige is, dat allerlei mensen, zelfs mensen op verantwoordelijke posities, niet alleen zich van deze waarheid niet bewust zijn, maar haar zelfs niet inzien, wanneer zij erop geattendeerd worden.

Ik heb in de laatste jaren nogal eens te maken gehad met officiele stukken zoals ontwikelingsplannen, adviezen aan de minister, subsidieaanvragen etc., stukken met doorgaans een of meer hooggeleerde auteurs, stukken waarvan het Nederlands zo rammelde, dat je met de beste wil van de wereld er niet achter kunt komen, wat er nu precies bedoeld is. Als ik dergelijke stukken ter beoordeling kreeg, heb ik daar aanmerking opgemaakt, want ik wens onzin niet voor zin te accepteren, en erger, de proliferatie van dergelijk gebeuzel werkt verontreinigend. Dit is mij ernstig kwalijk genomen: een van mijn collegae heeft mij zelfs schriftelijk te kennen gegeven, dat het zijns inziens volkomen onredelijk mijnerzijds was, om van Nederlandse hoogleraren te eisen, dat ze fatsoenlijk hun taal kunnen hanteren.

Zij zijn waarschijnlijk het slachtoffer geworden van een misvatting, die rooie onderwijshervormers nog wel eens willen propageren, nl. de misvatting, dat adequaat taalgebruik niet anders dan een luxe is, die de betere standen zich kunnen permitteren en waarmee die betere standen zich tegelijkertijd van het grauw afschermen. Die rooie onderwijshervormers moesten natuurlijk ook wel iets, wanneer je bedenkt, dat de zg. "redeneersommen" van het programme van de lagere school afgevoerd hebben moeten worden, omdat ze voor de leerlingen van de kweekschool te moeilijk waren. Maar het blijft een misvatting: adequaat taalgebruik is altijd wanneer ergens over gepraat moet worden, een onmisbaar stuk gereedschap. Ik heb millioenenprojecten zien mislukken, voorspelbaar zien mislukken en zelfs de mislukking voorspeld op grond van het onbeholpen taalgebruik, waarin ze op poten werden gezet. Mijn waarschuwen voor het debacle was een uiterst frustrerende bezigheid, want de mensen tot wie ik sprak, waren er niet van te overtuigen, dat het onmogelijk is om met een botte bijl de punt van een potlood te scherpen. Dat lukt nu eenmaal niet met een botte bijl, het lukt zelfs niet met tien botte bijlen. Als je dat laatste probeert, wordt het debacle alleen maar nog duurder.

Het is mogelijk, maar helaas onwaarschijnlijk, dat wanneer U bent afgestudeerd, de vergaderrage is uitgewoed. U doet er dus goed aan U er mentaal op voor te bereiden, dat U later ook in commissies moet zitten. Ik wil U in dit verband voor een van de typen voorzitters ernstig waarschuwen: dat zijn de zg."lijmers". Zodra zich in de boezem van zijn commissie zich een verschil van inzicht voordoet, zal de lijmer met een compromis komen, waarmee iedereen zich kan verenigen. Als het verschil van inzicht er werkelijk is, betekent dit, dat het compromis, dat de lijmer gebrouwen heeft een zo vage flodderige formulering is, dat je er ook niets meer aan hebt. Wacht U voor de lijmers, want zij institutionaliseren het gebeuzel. Het meest navrante is, dat de bonafide lijmer oprecht gelooft, de zaak een goede dienst te bewijzen.

Overigens ben ik van mening, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD557

Zevende toespraak tot mijn studenten, voorjaar 1976.

In de bundel essays "Two Cheers for Democracy" van de kunstminnende E.M.Forster komen twee essays voor, respectievelijk getiteld "Not listening to music" en "Not looking at pictures". Als hij tevens een wetenschapsman geweest was, zou hij wellicht er een derde essay aan hebben toegevoegd met de titel "Not reading scientific articles"; als hij het geschreven had, zou ik er dankbaar uit geciteerd hebben.

Ik realiseerde me nl. onlangs, dat U bij Uw kennismaking met de TH waarschijnlijk wel langs onze bibliotheken bent gevoerd, en dat U toen waarschijnlijk wel door een bibliotheekwezen zoals dat heet "wegwijs" bent gemaakt: met de catalogus als topologische kaart in de hand kunt U in het land der wetenschap niet meer verdwalen. Zo luidt ongeveer het Credo van bibliotheekwezens. Ik stel me voor, dat het beeld is opgebouwd van de student, die beter studeert, naarmate hij meer boeken en artikelen doorploegt. En toen bedacht ik, dat waarschijnlijk niemand U verteld heeft, waarom en hoe men artikelen moet overslaan. Deze toespraak poogt in deze vermoede lacune te voorzien.

Regel 1 —bekend als Naur's Advice— is, dat men bij eerste lezing een artikel achterstevoren moet lezen. Dit is nl. de snelste manier om er achter te komen, dat de auteur geen significant resultaat heeft geboekt, een helaas zo frequent optredende situatie, dat het gerechtvaardigd is zijn strategic daarop af te stemmen.

Regel 2 is, dat men artikelen aan het eind waarvan de auteur in hoofdzaak naar zijn eigen werk verwijst, negeert. Een dergelijke lijst referenties is nl. een bewijs van geestelijke inteelt. Geen referenties is altijd nog beter.

Regel 3, die toegepast moet worden wanneer men zijn eerste weerzin heeft overwonnen en besloten heeft, er dan in godsnaam toch maar naar ta kijken, leert, dat men zich niet moet laten imponeren. Men moet zich niet laten imponeren door indrukwekkende notaties, grote formules vol sterretjes, Griekse, of nog erger Gothische letters en dubbele pijltjes met punten erboven. Barokke symboliek is in elk geval een symptoom van slechte smaak, en meestal een rookgordijn, dat een betrekkelijke leegte moet verhullen. Laat U evenmin imponeren door een overmaat aan abstractheid: er is een gerede kans dat het onderwerp thuishoort in de bekende categorie "General Abstract Nonsense".

Regel 4 is dat men moet proberen om, bv. door een stap achteruit te doen en de probleemstelling iets te generaliseren, het recht te verwerven het artikel als irrelevant gepriegel terzijde te leggen. Ten eerste is dit een bijzonder goede intellectuele training, en wie deze techniek beheerst, spaart wederom een hoop tijd en een hoop ergernis.

Regel 5 luidt, dat U in geval van ernstige moeilijkheden zich niet een minderwaardigheidscomplex laat aanpraten, maar de schuld van de onbegrijpelijkheid op de auteur schuift.

U moet zich nl. realiseren, dat het merendeel van de gepubliceerde artikelen helemaal niet voor hun lezers geschreven zijn, maar voor de grotere glorie van de auteur of ten bate van de zakelijke belangen van de uitgever. Dat klinkt cru, en misschien zelfs onrechtvaardig. Toch moet ik U op het hart binden, met deze mogelijkheid ernstig rekening te houden: dat voorkomt teleurstellingen.

Overigens ben ik van mening, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD558

Achtste toespraak tot mijn studenten, voorjaar 1976.

Aangezien minister van Kemenade zijn contourennota gesteld heeft in een soort Nederlands, dat ik zelfs mijn honden niet durf voor te lezen, weet ik niet precies, wat hij met het middelbaar onderwijs voor heeft, maar veel goeds is het niet. Terwijl het middelbaar onderwijs nog niet van de invoering van de mammoetwet bekomen is, moet het met de middenschool gaan experimenteren. Terwijl de mammoetwet door de pakkettenkeuze het middelbaar onderwijs op beroepsopleiding heeft doen gaan lijken, krijgen we nu de middenschool, waar in naam van de spreiding van kennis de goede leerling helemaal niets meer leert. Terwijl Engeland, dat met de invoering van de zg. "comprehensive school" ons in dezen is voorgegaan, wou dat het er nooit aan begonnen was, omdat het een grandioze mislukking is gebleken, is de blinde fanaticus van Kemenade niet te remmen. Nou, blind? Niet helemaal: waarschijnlijk weet hij, dat het in Engeland mislukt is, want hij heeft al de wens te kennen gegeven de experimentele middenscholen daar te stichten, waar voor de scholieren in de nabijheid geen alternatief aanwezig is. Dit, zoals hij dat noemt, "om het experiment een eerlijke kans te geven". Het risico dat ouders hun onbevredigde kinderen van de middenschool zouden afnemen, wil de minister kennelijk zoveel mogelijk verkleinen. Zoveel over des ministers wetenschappelijke eerlijkheid.

Wat de minister met het universitair onderwijs voor ogen staat, is heel duidelijk: vernietiging. Daar zijn ze al sinds 1968 mee bezig; toen noemden ze het democratisering, maar dat was zo'n vuig euphemisme als politici wel vaker hanteren. Uit de missiven van het ministerie van O. en W. wordt steeds duidelijker, dat tegenwoordig de O. voor "Opleidingen" staat. Het wezenlijke verschil tussen academiaal onderwijs en hoger beroepsonderwijs staat de minister niet meer helder voor ogen. De minister staat hierin overigens niet alleen.

Hoger beroepsonderwijs leidt zijn leerlingen op voor bepaalde beroepen; wetenschappelijk onderwijs voert zijn studenten in in bepaalde wetenschappelijke disciplines, een activiteit, die slechts zijdelings verband hoeft te houden met Het latere terrein van wetenschappelijke activiteit. Om dicht bij huis te blijven: als ik wel ben ingelicht zijn al Uw hoogleraren in de Informatica aan de THE van huis uit theoretisch physicus. En waarom niet? In je studententijd is je belangrijkste taak te leren je hersens te gebruiken, je noge kwaliteitsnormen eigen te maken en een goede wetenschappelijke smaak te ontwikkelen. En voor wie dat gelukt is, doet het er later niet zo heel erg meer toe, wat hij nu precies gestudeerd heeft.

Maar er wordt met man en macht aan gewerkt om deze grenzen te doen vervagen. Kweekscholen en scholen voor maatschappelijk werk —duidelijk beroepsopleidingen— heten pedagogische en sociale academies, hun leerlingen heten ten onrechte studenten. En alsof dit versluierend taalgebruik al niet schadelijk genoeg is, poogt men nu ook het wetenschappelijk onderwijs in het keurslijf van de beroepsopleidingen te persen. De kreet hiervoor is "integratie van het tertiair onderwijs" en, als het aan de minister ligt, is binnen tien jaar het verschil tussen de TH's en de HTS-en verdwenen. De herprogrammering, die net curriculum tot vier jaar moet terugdringen, is daartoe duidelijk een eerste aanzet. Is de O. de O. van "Opleidingen" geworden, de W. wordt volslagen vergeten. Hadden we iets anders kunnen verwachten? Sinds de zg. "gamma-wetenschappers", zoals economen, psychologen, sociologen, pedagogen en wat dies meer zij, in een moment van onbedachtzaamheid tot de campus zijn toegelaten, hebben zij, samen met de bouwkundigen, altijd het academisch uitschot gevormd. En deze minister beoordeelt de wetenschap naar de karikatuur, die hij er zelf van heeft meegemaakt en bedreven.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD559

Negende toespraak tot mijn studenten, voorjaar 1976.

In een ogenschijnlijk lovenswaardige bezorgdheid, dat rijksmiddelen niet over de balk gegooid worden, heeft ons ministerie van O. en W. aangedrongen op bezuinigen en verhoging van de efficiency van het universitair onderwijs. Maar hoe bonafide is het ministerie?

Er wordt sterke drang uitgeoefend om de bestaande vijfjarige curricula door vierjarige te vervangen, zulks op grond van financiele overwegingen. Maar U moet niet denken, dat door het afknippen van het laatste, vijfde jaar slechts 20 procent beknot wordt. Naarmate studenten ervarener worden gaat het zich nieuwe meterie eigen maken steeds sneller, en in dat opzicht is Uw laatste jaar Uw productiefste. Kortom, U wordt niet met 20, maar waarschijnlijk eerder met 30 procent beknot. En van de kant van de universiteit of hogeschool, die met zijn hogerejaars studenten zijn meest effectieve studenten verliest, moet je vaststellen, dat de studieduurverkorting de gemiddelde efficiency van het onderwijs schaadt.

Er is een andere, voortreffelijke manier om de efficiency van het hoger onderwijs te verhogen: bij toelating strenger selecteren. Dat heeft tijdenlang niet gemogen, want het eindexamen gaf per definitie toegang. Op het moment, dat er voor allerlei studierichtingen evenwel een numerus clausus ingesteld moest worden, gold dit argument niet meer en dat was het moment geweest om toelating tot het wetenschappelijk onderwijs via een vergelijkend examen te reguleren. Maar wat beslist onze goeie overheid? Loten! En dat was dan de tweede overheidsmaatregel, die de efficiency van het wetenschappelijk onderwijs nodeloos schaadt.

Voorts is de van overheidswege ingevoerde WUB bijzonder schadelijk voor de efficiency van het wetenschappelijk onderwijs: ten eerste omdat vergaderen een bijzonder tijdrovende beslissingsprocedure is, ten tweede omdat nu zovaak waar competentie vereist is terzake onkundigen meebeslissen, dat er vele verkeerde beslissingen genomen worden, en ten derde omdat de sfeer zo verloederd is, dat het gestimuleerde verloop onder het docentencorps nauwelijks meer adequaat is op te vangen. Kortom, de WUB is de derde schadelijke overheidsmaatregel.

Ten vierde noemen we de maatregelen, die samen doorgaan voor wetenschapsen onderzoeksbeleid en een papierwinkel veroorzaakt hebben, waar niet alleen de onderzoeker knettergek van wordt maar die ook een klein leger planningsambtenaren bezig houdt. In een kosten/baten-analyse zijn zij tweewerf schadelijk: hun salaris moet wel uit ons budget betaald worden en hun bijdrage tot onze eigenlijke werkzaamheden is negatief.

Alsof het nog niet genoeg is hangt boven ons allen tenslotte de dreigende wolk dat de pedagogen en de beoefenaren van wat onderwijsresearch heet de kans krijgen op ons doceren in te grijpen: dan zijn we helemaal in de aap gelogeerd.

Ik keer terug tot mijn oorspronkelijke vraag, hoe bonafide het ministerie is in zijn bezorgdheid om de efficiency van het wetenschappelijk onderwijs. Dat hele wetenschappelijke onderwijs kan onze bewindslieden geen ene lor schelen. De minister van financien doet zijn plicht als hij zegt dat het niet te duur mag worden, dit kabinet, dat zoveel ideologie in zijn beleid doet, kan de gesignaleerde maatregelen niet ongedaan maken en het Nederlands wetenschappelijk onderwijs wordt op het offerblok der utopisten geslacht. Ik ben bang, dat het voor onze bewindslieden niet eens een moreel dilemma is: spreiding van kennis impliceert toch de vernietiging van een wetenschappelijk onderwijs dat nog wat voorstelt?

Overigens ben ik van mening, dat er op Hilversum 4 minder moet warden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD560

Tiende toespraak tot mijn studenten, voorjaar 1976.

Planten- en dierenrijk kennen heel domme parasiten, die hun slachtoffer zo uitmergelen, dat het het niet overleeft. Vergeleken daarmee is de mensheid duidelijk superieur: onze chanteurs, afpersers en maffiosi plegen niet de kip met de gouden eieren te slachten. Het loopt natuurlijk wel eens uit de hand en soms is hun wurggreep dodelijk voor het slachtoffer, maar onder maffiosi wordt dat wel als beleidsfout beschouwd.

Na jaren aarzeling mogen er dan eindelijk casinospelen komen. Waren het aanvankelijk religieuze bezwaren tegen des duivels prentenboek, uiteindelijk werd de toestemming vertraagd door de vrees met de kansspelen ook de maffia in de kaart te spelen. Ik vond dat wat hypocriet van een bewind dat al zo heult met de vakbonden. De wijze waarop onze overheid zich nl. aan deze organisaties verslingerd heeft, liegt er niet om!

Het is om even bij stil te staan, dat in onze democratie, waarin alle volwassenen stemrecht hebben, de vakbonden hebben versierd dat het afpersingsmiddel van de stakingsdreiging wettelijk is toegestaan. Hiermee niet tevreden moeten straks de overwinsten —fijn Germanisms!— worden afgeroomd via de VAD. Wat moet met dat geld? Dat moet in een pot. En wie beheren die pot? De vakbonden natuurlijk. Ik vestig er de aandacht op, dat dit in de kamer als of het de gewoonste zaak van de wereld was, is besproken. Nou vraag ik je.. Ik west wel, waarom ze dat nu doen. Er zijn helemaal geen overwinsten, de meeste bedrijven zijn blij, als ze uit de rode cijfers kunnen blijven. Iedereen denkt dus "Ach, waar praten ze over! Er komt nooit iets in die pot, dus het kan helemaal geen kwaad de vakbonden daar controls over te geven." Maar het gaat om het principe.

Dat er voorlopig niet veel in die pot komt, beseffen de vakbonden ook wel, en hun macht moet dus op andere manier worden uitgebreid. Het is hen natuurlijk een doorn in het oog, dat ze niet zoveel sympathie genieten, dat iedereen lid is en maandelijks zijn lidmaatschapsgeld aan de vakbond afdraagt. Maar ook daar kan wat aan gedaan worden. Bedrijfsinkrimpingen zijn aan de orde van de dag, en waarom zouden mensen lid van de vakbond worden, als onder de vakbondsleden de ontslagen even hard vallen? Weet je wat? We maken er een regel van dat als er ontslagen moet worden, de ontslagen eerst vallen onder de nietleden van de vakbond. Ook hier wordt serieus over gepraat alsof dit de gewoonste zaak van de wereld zou zijn!

Maar dit zou betekenen dat ook de vele werknemers, die helemaal geen sympathie voor de vakbonden koesteren en misschien wel vinden, dat hun macht al veel te groot is, eigenlijk geen keus meer gelaten wordt: om vrouw en kind moeten ze dan wel maandelijks een deel van hun loon afstaan aan wat ze wellicht uiterst dubieuze organisaties vinden. Dit zijn je reinste maffiamethodes.

Er wordt wel een beetje tegen deze voorstellen gesputterd, niet omdat ze principieel volslagen onjuist zijn, maar omdat pragmatici in de politiek zich toch afvragen, of een dergelijke machtsconcentratie in ons land wel gewenst zou zijn. Zij sputteren dus wat. Maar onze vakbondsleiders liggen er niet wakker van! Oh nee! Eventuele bezwaren zijn onlangs door hen weggewuifd met de opmerking dat, net als de politieke partijen, zij toch ook met hun achterban rekening moesten houden, er gemakshalve aan voorbijgaand, dat het recht op een andere partij te stemmen, stevig in onze grondwet verankerd ligt. Bij de vakbonden, die bezig zijn te proberen te fuseren, zal deze keuzevrijheid illusoir zijn. De maffia duldt nooit concurrenten!

Overigens ben ik van mening, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD561

A "non trip report" from E.W.Dijkstra.

        On my last visit to the U.S.A. I found that many regular readers of my trip reports have no picture at all of my daily life when I am not traveling. And, indeed, how should they without further information? This "non trip report" is written with the intention of redressing the balance.

        Tuesday is my day at the Eindhoven University of Technology. It has by now a well-established pattern. In the morning I lecture for two hours and further take care of all "irregular" business (mail, receiving students etc.) The afternoon is reserved for a four-hour discussion with a small group of young computing scientists on whatever subject is brought up.

        Lecturing is great fun. Officially I give only two courses, an introduction to programming in the fall semester and a course on synchronization and communication in the spring semester, but they are no two years the same: the subject matter is so much alive that it is no problem at all to keep these lectures fresh. (I myself find them, as a matter of fact, often quite exciting!) What helps greatly is that of my audience —about 70 people— only half of it is formed by students that have to follow the course, the remaining ones come from other departments or from outside and quite often have already their degree: they come because they are interested, and that makes an inspiring audience.

        The discussion in the afternoon —we are currently with five people: besides me two from within and two from outside the University— takes place in my office at the University and its topics cover in principle a very wide range. It may be an open question that I raised that morning at my lecture, the thesis topic of one of the participants, something that one of us has read somewhere and seemed important to him, something one of us has done or the difficulties he is encountering while trying to do so. (Most of the technical EWD's have in some stage been discussed in this group.) On the average, these Tuesday afternoons are very productive, but it varies as much as the topics: sometimes we just get stuck.

        The other more or less fixed point in my week is Friday which is in principle reserved for working together with a colleague of long standing: we now work together for nearly a quarter of a century! As an experimental physicist he entered the hardware side of our field, while I, a theoretical physicist, entered it as a programmer. The difference in background is still reflected in the nature of our work, but we know each other by now so well that we can appreciate the other's achievements and problems and can often help the other. Besides being very bright and knowledgeable, he is a mature scientist and many things which turned out to become a major topic have been discussed with him in their infancy, when they were still hunches. Because working with him takes "the full mind", it is usually a day of very hard work that leaves me tired and it is a good way to end the week: then we have the weekend to recover and to regroup our forces.

        The other days of the week I am, in principle, a free man, but a few (mostly self-imposed) constraints usually define what has to be done.

        A self-imposed constraint is that all appeals to my assistance in which the professional life of others is at stake, are dealt with promptly. Under this category fall refereeing of papers for symposia and journals, the evaluation of research proposals for funding organizations and of candidates for university posts. (It differs from country to country: my impression is that, for instance, English and American universities seem to rely more heavily on external assessment than the Dutch ones.)

        Besides those constraints I have to observe the deadlines that are the consequence of having committed myself to address an audience. Invitations to do so usually reach me long before the planned date of delivery, so long as a matter of fact, that I usually don't propose to talk about what I have done at the moment of acceptance, but commit myself to talk about the work that I intend to do in the meantime. But I also know myself well enough to know that I work very poorly when under strong pressure, and my desire to have my document ready well in advance of the actual deadline restricts my freedom.

        In my little one-man research establishment, the mail plays of course an important role: to give you some idea, the practical unit for the rate of incoming mail seems to be "pounds/week". Of course I don't need to read it all. Some of it can be thrown away at a glance, most of it I just scan —e.g. lists of abstracts of articles produced by such-and such organization, or encyclopedic works— to keep an overview of what is happening elsewhere. This does not take much of my time. But some of the stuff that is sent to me is very interesting, and then I want to study it, and occasionally it keeps me busy beyond that, either because I start a correspondence with the author or because I don't like the offered solution and try to do better or because the author's attack seems to give a fresh handle on one of my old unsolved problems.

*         *         *

        In a recent paper "The high cost of programming languages", C.A.R. Hoare expresses at the end the "hope that one day we shall learn to design a language which will combine the merits (rather than the features) of its predecessors." After listing such merits, he continues

"But it will not be an easy task to design such a language; like all great engineering breakthroughs, it will require an insight and understanding of the total environment of implementation and use of the product; consideration and rejection of a thousand bright ideas; and a constant appeal to the criteria of low cost and high effectiveness. Furthermore, I believe that it will require an undeviating pursuit of elegance and rigour, which is characteristic of the best tradition of University research. There are few engineering disciplines in which the successful pursuit of academic ideals can pay higher material dividends than in Computer Science."

Although I am not (yet?) engaged in the design of a new programming language, I give the above quotation because I share the opinions expressed —and expressed better than I could formulate them!— and, therefore, gives an apt description of the nature of my work. Indeed: "rejection of a thousand bright ideas" nicely captures its experimental nature.

        From our current mastery of programming to "software engineering" as a discipline worthy of that name, we have still far to go. There is clearly a discipline emerging for the design of little things and for proving their correctness. That is great and encouraging, for these little things are by no means restricted to toy-problems like Euclid's Algorithm for the gcd, they also include difficult and important little things like locking mechanisms and microcode for square-root algorithms down to the bit level. But they are "little" things: it is great, it is encouraging, but not enough! Here, for instance, is an area of research where, to quote Hoare "the successful pursuit of academic ideals can pay high material dividends", at least I believe so. But I know of only one way of discovering why the application of our formal techniques, which is so successful "in the small", is less successful when we try to apply them with greater ambition, and that is "try it!". So that is, for instance, what I have done during the last month. The eventual product (EWD550 in this case) was a 19-page document, but many pages with less successful formalization and proving experiments have disappeared via the wastepaper basket. What I learned from the experience I intend to summarize in a later issue of the EWD-series.

        I mention the exercise because it seems typically to be among the type of things that I should be doing. First of all, the time was not wasted, on the contrary, as it proved to be very difficult to attain in this case the "elegance and rigour, which is characteristic of the best tradition of University research". Whether it would be done at a University, however, remains to be seen: it is —and I have said so explicitly in EWD550— work without any deep thought and, as a result, work without any glamour (and that is what many workers in the academic environment need or think they need). I think that it would be very hard to get funded for it: it is the kind of incremental improvement of which we sometimes need many, one after the other, it is the kind of work that requires hard and quit thinking. I am in the lucky position to be able to do so: that gives its obligations, the more so, because the funding of individual research seems to become more and more impopular. (I quote from a recent issue of the Bulletin of the American Academy of Arts and Sciences:

"Moreover, attitudes toward research have altered. American foundations and government agencies have become reluctant to fund research performed by individuals, preferring instead to help build large institutions and applied research centers, which can assign research priorities according to perceived and immediate economic needs."

The complaint is not new, that the situation seems to get worse is somewhat alarming.) Finally a job like that gives me some sense of achievement, and at regular intervals that is a nice feeling!

        (EWD550 deals with the formal treatment of a modest syntactic analysis. Organisations less enlightened than Burroughs Corporation tolerate such a project only provided it is immediately done on a grandiose scale: IBM allowed its Vienna Laboratory to embark upon the problems of the definition of semantics, provided Vienna formalized the semantics of PL/I, of all languages! Needless to say, the Vienna Lab more or less collapsed under that effort. IBM's dealing with that crew always strikes me as a prime example of industrial mismanagement of research.)

*         *         *

        During the same period of time I wrote EWD554 "A personal summary of the Gries-Owicki theory.", also a project without glamour in the sense that all I have done in those fourteen pages has been to condense the quintessence of the thesis written by Owicki under Gries's supervision: from my side there was no originality involved at all. Again, also EWD554 can be regarded as an experiment, in presentation. Owicki's thesis, I am sorry to say, is on the verge of unreadability. (I lent my copy of her thesis to a student who wanted to do some work in operating systems theory; I never saw him —nor my copy of her thesis— again!) This is a great pity, because hidden beneath the sometimes pompous formalism her method contains the germ of a technique for dealing with a collection of otherwise unmanageable problems. One may raise the question: "Should I spend my time on rephrasing other people's work in an effort to make it more accessible and to show its significance?" I think that sometimes I should. I wrote that text with a dual objective, viz. to offer my students some underlying material and to make a number of people within Burroughs familiar with this work. (I had a third, more selfish objective: I wanted to understand it myself, and in order to be able to do so I had to reduce it to its bare essentials.) In connection with EWD554 I must admit that I treated my students as guinea pigs: I tried my presentation of that theory out on them. The experiment —I am happy to say— gave a positive outcome. I admit "using" my regular audience for such purposes, I am not ashamed of it. There is hardly a point in developing a methodology unless one can transmit it to others, and, therefore, the possibility to transmit it should be tested experimentally.

        I don't regret having written that document. It was a personally rewarding experience because it showed me something the duo Gries-Owicki had not seen yet clearly, viz. a non-operational approach to concurrency. Besides that, who else could have done this? In writing EWD554 I needed all my experience as a teacher to make it palatable, and all my experience as a scientist to make it simple, i.e. to extract "the bare essentials". Again I am grateful for being in the position that I can allow myself to do essential work without glamour!

*         *         *

        This "non trip report" covers about the last month. The plan to write such a report has been with me for some time, the fact that it covers a period of non-glamorous activities is a pure accident. If it had covered the period during which I was engaged in the design of the on-the-fly garbage collection (EWD520) or was lighting a similar piece of firework without burning my fingers too badly, its tone would probably have been quite different. This alternation between spectacular, near reckless intellectual adventure and most definitely non-spectacular (but solid!) work does not disturb me at all, for the progress of science needs both of them.

*         *         *

        This is a good occasion to explain "the missing numbers" in the EWD-series. Some numbers are occupied by documents that I failed to complete; sometimes I start on a document because I hope and expect that I can achieve a result, for instance because I have the exciting feeling of having a new bright idea, but when I then try to use it, it does not work. Furthermore I don't send my Dutch texts to the USA. Each week during term time, for instance, I address at the beginning of my lectures my students with a speech in Dutch commenting on the world we live in: they are traditionally one page long and each speech occupies a new EWD-number. I give these speeches for the enlightening of my students, but probably even more for my own fun and in order to exercise regularly my written Dutch. Like the documents I write in my capacity of Chairman of the Board of Mathematics Inc., they are also linguistic exercises. (With Mathematics Inc., by the way, I am in trouble. No matter how corrupt our commercial practice, no matter how fraudulent our scientific activities, the world around us seems to beat us. In these competitive times itu is bloody hard even to catch up with reality!)

1st of April 1976
Plataanstraat 5
NUENEN - 4565
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised .Mon, 12 Sep 2005

EWD562

THE EFFECTIVE ARRANGEMENT OF LOGICAL SYSTEMS

Edsger W.Dijkstra
Burroughs
Plataanstraat 5
NL-4565  NUENEN
The Netherlands

We all know that when we have to design something "large" or "difficult", we have to apply in one way or another the old adagium "Divide and Rule". Our machines are made from components, our programs are made from modules and they should fit together via interfaces. That is fine, but it raises, of course, the questions how to chooose the modules and how to formulate the interfaces. This paper explores the main goals of modularization; being aware of them should assist us in evaluating the quality of proposed modularization.

*          *
*

An inspiring example of modularization outside of our own field is the way in which human knowledge is divided over the different scientific disicplines. Why do we teach different disciplines at our Universities? Why don't we teach all our students just "knowledge"? The answer is simple: our human skulls are too small and our days are too short. The amount of knowledge needed for each discipline must fit into a human head. Besides knowledge there are abilities, and human abilities have two characteristics: they take a lot of training before they are mastered, and thereafter the maintenance of their mastery requires that they are nearly daily exercised, for without such daily exercise they fade away. (This, by the way, is one of the explanations why the capable are always so busy.) In this sense, rather quantitative human characteristics impose a set of equally quantitative limitations on what we are willing to consider as a single scientific discipline.

But there are also internal, more structural constraints. I mean that just an arbitrary collection of scraps of knowledge of the right total amount does not constitute a scientific discipline! It must be sufficiently coherent and self-supporting: it must be possible to study the subject matter of a scientific discipline in isolation (or nearly so), largely independent of what is happening or known in other scientific fields. And the increased insight should enhance our abilities, our enhanced abilities should assist us in improving our insight.

The above very rough sketch of how mankind as a whole has parcelled out its knowledge has been included because it also provides a model of how, on a microscopic scale, a single scientist works when he focusses his attention on an aspect of his problem. For every problem too large to be solved at a single stroke of the pen we try to apply a similar technique. We try to isolate various aspects of the problem and to deal with them in turn by "concentrating our attention" on them. (The latter does not mean that we study them in complete isolation: through the corners of our eyes we usually still look at all we are temporarily ignoring!)

The usual catchphrase for this technique is "separation of concerns". Although very adequate from a descriptive point of view, it raises of course the same sort of questions as we raised initially about modules and interfaces, such as "Which concerns should be separated?" and perhaps "After separation, how do they combine again?". This similarity is a rather clear hint that the successful "modularization" of a large information processing system is not a trivial matter.

*          *
*

The discovery that from a "larger" concern, a few "smaller" concerns can be successfully extracted usually ranks as a scientific discovery. Let me mention a few of them from our own field, so that we know, what we are talking about.

a) The isolation of the definition of the syntax in the task of defining programming languages. (John Backus, 1959; as BNF immediately used in the definition of ALGOL 60.)

b) The isolation of logical aspects of operating systems via the model of cooperating sequential processes. (Edsger W.Dijkstra, 1961; quickly thereafter used in the design of the THE Multiprogramming System.)

c) The isolation of programming language semantics computational histories. (C.A.R.Hoare, 1968; immediately used in the axiomatic definition of semantics.)

I think that the above three examples are fairly typical: all three "separations" (or "isolations" or "extractions") have been hightly rewarding. Firstly it was quite clear that the people responsible were not just playing a game, they extracted what seemed a very relevant and possibly manageable aspect from a large and burning problem. Secondly they created a realm of thought rich enough to have many thoughts in!

Example (a) opened the way for parsing theory, example (b) for the theory of synchronization, deadlock prevention etc., and example (c) has opened the way for practicable techniques for proving the correctness of programs. In all three cases the problems addressed can now be dealt with quite professionally. All three are easily "rich" enough to be the subject of a one-semester course in a University curriculum, and all three are so well separated from other concerns that such a one-semester course could be fairly self-contained.

Yet another observation should be made. By ignoring, abstracting, generalizing (or whatever verb you wish to use to indicate the not taking into account of some facts) a dual goal has been achieved: thanks to it the theories are of a wide applicability and at the same time of an internal simplicity. (Think of the tremendous simplification of the theory of cooperating sequential processes that was made possible by not dragging speed ratios into the picture! If knowledge about speed ratios had been essential, the correctness arguments would have been an awful mixture of discrete and continuous arguments, and it would all have become very complicated.) It has been said that "everything can be regarded as a special instance of something more general", but I would like to add that there is only a point in doing so, provided that the general view simplifies our arguments. This condition is certainly not met when the more general something can only be understood via a case analysis ranging over the different special instances.

*          *
*

Another inspiring example is provided by the arrangement of mathematical arguments.

Of our various thinking activities I shall reserve the term "reasoning" for all manipulations that are formalized —or could readily be so— by techniques such as arithmetic, formula manipulation or symbolic logic. These techniques have a few common characteristics.

First of all, their application is straightforward in the sense that as soon as it has been decided in sufficient detail, what has to be achieved by them, there is no question anymore how to achieve it. And whenever such a technique has been applied, the question whether this has been done correctly is undebatable.

Secondly —and this is not independent of the first characteristic— we know how to teach these techniques: arithmetic is taught at the primary school, formula manipulation at the secondary school, and symbolic logic at the university.

Thirdly, we are very good at doing modest amounts of reasoning. When large amounts of it are needed, however, we are powerless without mechanical aids. To multiply two two-digit numbers is something we can all do; for the multiplication of two five-digit numbers, most of us would prefer the assistance of pencil and paper; the multiplication of two hundred-digit numbers is a task that, even with the aid of pencil and paper, most of us would not care to undertake.

In order to reach a conclusion the amount of reasoning needed is often the stumbling block, and I have yielded to the temptation to relate the effectiveness with which we have arranged our thoughts to the degree in which we have reduced the amount of reasoning needed. A recent experience has confirmed that this seems sensible. I was compiling a collection of what I thought to be impressively elegant solutions. The first thing that struck me was the surprising degree of consensus among my mathematical colleagues: when I asked them for suggestions they often came with the same examples. The second thing that struck me was that, when I showed any of them a solution from the collection that happened to be new for him, I evoked uniformly the same reaction: laughter! The third thing that struck me, however, is in this context the most important one: all the impressively elegant solutions were very short. I therefore ask you to subscribe —at least until the discussion after this talk— my thesis that the effectiveness with which we think is closely related to the reduction of the amount of reasoning needed, because, as soon as you have subscribed that thesis, you will agree with me that it is a good thing to know by what methods we can reduce that amount and by what methods we can increase it: those of the former category are the ones to be applied, those of the latter category are the ones to be avoided.

*          *
*

An obvious method is avoiding repetition. When multiplying two ten-digit numbers with pencil and paper we constantly appeal to the 10 by 10 multiplication table of the products of one-digit factors. Whether or not we know the multiplication table by heart or have it written out in front of us for quick reference is unimportant for the purpose of this discussion. What is important is that while multiplying those two ten-digit numbers, we have 100 theorems at our disposal, of which 7 * 8 = 56 is an instance. If we know how to count, or know how to add, we can prove that the product 7 * 8 equals 56, but that proof requires a certain amount of reasoning, so much as a matter of fact that we would not like to do it over and over again, every time we need the product 7 * 8 . Hence the knowledge that that product equals 56 is cast into a theorem; together with the other 99 theorems it forms what is known as the multiplication table.

Another remark of a directly quantitative nature is that we would not expect much use for a theorem whose statement is longer than its proof: instead of appealing to the theorem it would be simpler —at least "shorter"— to mention directly its proof.

The quantitative remarks in the two previous paragraphs, although of some relevance, do, however, not tell the complete story: if they did, there would be no point in stating and proving a lemma that is used only once, and there is a point in doing so.

Suppose that the total proof of a Theorem consists of two parts:

A: a proof of the Theorem based on the validity of a Lemma, and

B: a proof of aforementioned Lemma.

If both proofs are correct, the Theorem has been established, but suppose that part B is shown to contain a flaw. If we cannot correct the flaw, or perhaps even discover that the Lemma does not hold, we are in bad shape. If, however, we can correct the flaw in part B , its correction is the only thing that needs to be done: part A survives unchanged and unattended. Thinking about the last scenario I have come to the conclusion that its likelihood is, all by itself, a sufficient justification for splitting up the total proof —straight from the axioms, so to speak— in part A relying on a lemma and a part B establishing that Lemma, even if part A refers only once to it. The conclusion seems to be that we not only seek to reduce the amount of reasoning eventually needed when all would have gone well, but also the amount of reasoning to be expected in view of our fallibility.

But, again, there is more to it. Splitting the total proof into parts A and B , connected by a Lemma used in A and proved in B means

1) that we can study B ignoring A, i.e. ignoring the way in which the Lemma is used: we only need to consider what the Lemma asserts

2) that we can study A ignoring B , i.e. ignoring the way in which the Lemma is proved: again we only need to consider what the Lemma asserts. Because the statement of the Lemma can be expected —see above— to be shorter than its proof, also here we have to take less into account, and that is nice in view of another human limitation, i.e. the limited span of our attention.

Such a separation of concerns is, however, not only nice in view of our limited span of attention, it has a much profounder consequence. It gives us the freedom of replacing part B by a shorter or nicer proof of the Lemma as soon as we find one, it gives us the freedom of replacing part A by a nicer or shorter proof of the Theorem as soon as we find one. As long as the Lemma remains the same, changing one part does not invalidate the other. This observation makes it abundantly clear —at least in my mind— that we should not regard the appeal to the Lemma as it occurs in part A as an abbreviation of its proof as described in part B . The appeal to a lemma is to what the lemma states, and not to its proof: the main purpose of the introduction of the explicitly stated Lemma was precisely to make part A a consistent whole that is independent of the particular shape of B .

*          *
*

The above must sound very familiar to every mathematician that has been trained always to try consciously to present his proofs both as concise and as clear as possible. (That not all mathematicians have been trained that way, is another matter that need not concern us now.) Computing scientists —the other designers of what I called in my title: "logical systems"— seem, amazingly enough, to be in general less aware of it. They are in general aware of the circumstance that what on one level of detail can be regarded as an unanalysed whole, can be regarded at a next level of greater detail as a composite object, they are often not fully aware of its implications. The analogy with mathematical proofs tells us that whenever we regard a whole as composed of parts, the way of composition must define how the relevant properties of the whole depend functionally on the properties of the parts, without the need of taking their internal structure into account.

Let me give you one of my cherished examples. We consider a program part S for the computation of the remainder, more precisely, a program part S satisfying for constant c and d :

(c ≥ 0 and d > 0) ⇒ wp(S, r = c mod d) | (1)

(in words: c ≥ 0 and d > 0 implies the weakest pre-condition for the initial state such that activation of S is certain to establish a final state satisfying the post-condition r = c mod d). Consider for S the following program part:

{c ≥ and d > 0} | r, dd := c, d; | (2)
| do r > dd → dd:= 2 * dd od; |
| do dd ≠ d → dd:= dd / 2; |
|      if r ≥ dd → r:= r - dd |
|      ▯ r < dd → skip |
|      fi |
| od {r = c mod d} |

Many programmers, I have discovered, don't hesitate to consider this program part S as composed (primarily) of three parts, viz. of the form

"S" = "S0; S1; S2"

i.e. the outermost syntactical decomposition. The point, however, is that nowhere the properties of these parts S0, S1, and S2 have been stated, on account of which we can conclude that S satisfies (1). This point becomes a problem as soon as it is discovered that program (2) is wrong. It contains a well-engineered bug: in those cases where c divided by d leaves a remainder = 0 and, in addition, the quotient is a power of 2 , the final state satisfies r = d instead of r = 0 . As it stands we can only conclude that program (2) as a whole is wrong; we cannot —although regarding it as a concatenation of three statements— decide which of these statements is in error. That question is void.

And, as a matter of fact, we can repair it in different ways. Either we replace S1 by

"do r ≥ dd → dd:= 2 * dd od"

or replace S2 by

"do r ≥ d → dd:= dd / 2

do r ≥ dd → r:= r - dd od

od"

If we had chosen the properties

P0 ⇒ wp(S0, P1), P1 ⇒ wp(S1, P2), and P2 ⇒ wp(S2, P3) | (3)

with | P0: c ≥ 0 and d > 0 
| P1: r mod d = c mod d and (E i: i ≥ 0: dd = d * 2i) and 0 ≤ r
| P2: P1 and r < dd 
| P3: r = c mod d 

then the bug would have been localized in S1 as it may fail to establish P2 .

Note. On account of the semantic definition of the semicolon

wp("S1; S2", R) = wp(S1, wp(S2, R))

we derive

wp("S0; S1; S2", R) = wp(S0, wp(S1, wp(S2, R)))

and conclude that (3) indeed allows us to derive

P0 ⇒ wp("S0; S1; S2", P3) | (End of Note.)

The moral of the story is that we can only claim that a whole has been properly composed of parts provided the necessary properties of the parts have been decided. Without that specification it is, as if we are trying to build up a mathematical theory while giving only the proofs of our theorems and lemmata, but not the theorems and lemmata themselves! I have, therefore, decided for myself that such specification of the parts is an absolutely essential constituent of the whole design. After all I have said, this decision may strike you as obvious, as nearly trivial. I am unhappy to report that it is not generally accepted. Quite regularly I see texts arguing that "we cannot impose upon the poor programmer the additional burden of also supplying the assertions that correctness proofs (still) need". Depending on the attitude of the writer, either today's proving techniques are blamed for "still" needing such assertions —in that case the author usually does not mention what alternative proving techniques he has in mind— or the author now proposes to apply Artificial Intelligence techniques for deriving such assertions mechanically. I hope to have made clear why I regard the latter as a somewhat nonsensical activity; the assertions reflect an explicit choice of the designer, a responsibility that certainly cannot be delegated to a guessing AI-system. (For instance: in the above example we could have replaced in P1 and in P2 , or in P1 only, the term r mod d = c mod d by the more stringent r = c .) An "automatic specification guesser" that is only fed with a single instance of each part is almost certainly bound to be overspecific, and the whole activity strikes me as putting the cart before the horse.

Example. Given the following proof:

"The theorem is obvious, because

(x1 - x0)(x2 - x3) + (x2 - x0)(x3 - x1) + (x3 - x0)(x1 - x2) = 0 " ,

can you guess the theorem? It is —this is a hint— a very well known theorem that is usually proved in a rather indirect way. (End of example.)

*          *
*

I have shown you a small example, specifically manufactured to illustrate the nature of the dilemma. Let me now turn to a more grandiose example that has been provided by "the real world". The original design of the IBM650 had the very special feature that the attempted execution of a special little program loop blew one of the fuses of the machine. Needless to say, this very special feature was not mentioned in the manual, but, programmers being as they are, they not only discovered it, they also used it in at least one organization, where reservations of machine time were extended with the down-time, when the machine broke down during your period of reservation. Programmers who had a one-hour reservation for a debugging session used the little loop when, after ten minutes of testing, they discovered a bug whose patching required some peaceful thinking!

The decomposition into the two parts "hardware" and "software" is certainly a time-honoured one, but in this case it was defective. As soon as the aggregate whole was required not to blow fuses while yet it did, none of the two parts could be proved to be wrong or to be correct. The maintenance engineer could argue that all programmers knew that the machine was such that that little loop would blow a fuse and that, therefore, they should not include it in their programs. The programmers, from their side, could argue that the manual nowhere stated that upon the attempted execution of that little loop the machine had to blow one of its fuses! The could throw the blame on the other party indefinitely, and the only way to end this ping-pong game is by choosing a well-defined interface. Either it is decided that the fuse should not be blown —which means a change in the hardware design— , or it is decided that the fuse should be blown, and then all programmers have the obligation to program around it.

I definitely prefer the first alternative, not so much because I am more of a programmer than of a circuit designer, but because in the interplay between hardware and software we have the greatest variability at the software side. It is therefore simpler to propagate the obligation of fixing the bug through the limited number of machines than through all the programs that are or will be made for that type of machine. I have the sad impression that in user communities, management often takes the undesirable decision and obliges its programmers to program around such deficiencies.

The story about the fuse is old and nearly forgotten. We should, however, remember it as a paradigm for the sad situation in which the majority of today's programmers are supposed to do their work. I know of a respectable colleague who, in the year of the Lord 1976 is developing the basic software for a machine of a less respectable design: its hardware specifications are so obscure that quite regularly he has to get access to the prototype in order to discover experimentally what some commands are supposed to achieve! He has to do so under the assumption that the prototype is in perfect working condition, the trouble, of course, being that, logically speaking, that "perfect working condition" is, as yet, undefined. Together with the hardware designers he has to decide "after the fact", which machine they should have had in mind to build. I like to believe that this is an extreme case, but have no grounds for doing so.....

The complete functional specification of a machine must be given without any reference to its internal structure if, in the whole system, the machine is to be recognized as a part of a composite whole. This, however, does not only apply to hardware —"concrete machines", if you like— , it is equally applicable to the abstract machines known as higher-level programming languages. Only when their semantics are fully defined without any reference to implementation details such as compilers, binders, interrupts and what have you, only then has the separation of concerns been effectuated that makes any progress possible. It is in this respect disheartening to observe that many a modern high-level language user is much worse off than the average programmer a quarter of a century ago. In the old days programmers used to have a complete functional description of their machine at their disposal and, as a result, they could know exactly what they were doing. This in sharp contrast to the majority of the so-called high-level programming languages, the semantics of which are only so loosely indicated that most young programmers have lost the sense of complete control that we used to have. They live in a woolly environment in which the notion that a program is either correct or not is, by definition, not applicable.

A politically complicating factor is that the world's largest computer manufacturer has probably not the slightest incentive to change this state of woollyness of the programming languages it supports, because this woollyness only acts as its advantage as long as its products are accepted as what are euphemistically called "de facto standards". In the case of a well-defined programming language, it would have the obligation to implement that correctly and would run the risk of a competitor providing a better implementation; as things are its implementations are taken as "the definition". Such political considerations make its unwillingness to support such well-defined languages as, say, ALGOL 60 only too understandable.

So much for the ill effects of lacking specifications.

*          *
*

I hope that in the above I have convinced you that, in the invention of the complex composite systems we are considering, a rigorous definition of the essential properties of the parts is not a luxury but a necessity. In the final part of my talk I would like to tackle the more elusive question "By virtue of what type of properties can parts be nice or ugly?" It is the question what interfaces to invent. I called this question "elusive" because it is as impossible to give a final answer to it is impossible to teach young mathematicians how to discover beautiful theorems. What we can do —and, in fact, do while teaching mathematics— is explaining why we think that some theorems are beautiful. In a similar vein we should be able to explain to young computer scientists what virtues to look for when they are evaluating or considering a proposed set of interfaces. It is in this connection a good thing to remember that one of the main roles of the decomposition of a whole into parts was the localization of the bug when something went wrong.

Again, let me start with a very simple example. Suppose that we have to control a printing device that accepts 27 different commands —say the printing of the 26 letters of the alphabet and the blank— . If we control this device with a ternary machine, each command could be specified with three ternary digits because 3³=27. But suppose now that we are to control such a device with a binary machine. We would then need five bits for a command. Immediately the question arises what to do with the nonsensical remaining 32 - 27 = 5 possible "commands". One answer would be that it does not matter because no correct program would ever send any of these five nonsensical commands to the device. But this would be a very silly choice, for it would give the designer of the device the licence to make it in such a way that a nonsensical command could cause a jam in the printing mechanism, and as soon as he has done that it is possible to write erroneous programs that, besides not producing the right results, may wreck the installation. Such a silly interface would cause the ill effects of an erroneous program to spread. Another possibility would be to postulate that such nonsensical commands are ignored by the device. That is safe as far as the working condition of the device is concerned but it is still silly: presumably it was not the programmer's intention to send such silly skip commands to the printing device and, if such a command is sent to the device, we may assume that something in the execution of his program has gone wrong. The sensible reaction is, on the one hand to protect the device from being wrecked and on the other hand to signal an error, thus giving the programmer another way of protecting himself. An alternative way of doing away with the problem would be to extend the character set of the printing device with another five characters.

This, again, was a simple example, specially manufactured to illustrate the problem; but if we look for it, we can find the silly choice made many times, and on a much larger scale. A famous example is the coupling to a general purpose computer of peripherals that may signal to the central processor that they require a certain service from it within a given number of milliseconds; in the worst situation the irrecoverable malfunctioning that results when the central processor fails to meet its real-time obligation is not even signalled! In any case the real-time obligation of the central processor with respect to such a peripheral places a heavy and ugly burden upon the system designer who, for instance, must guarantee that the interrupt is never disabled for too long a period of time.

We find the same flaw when compilers accept syntactically incorrect programs without warning or when system integrity relies on the correctness of the compilers used.

The quoted examples are instances of a general case. We are dealing with classes of strings: strings of characters representing a source program, strings of words representing object programs, strings of commands controlling a device, etc. Either such a class of strings contains all the strings that are physically possible, as in the case of coding the 27 commands to the printer with three ternary digits. In this case there is no redundancy, and we note in passing that under many circumstances such an absence of redunancy is undesirable. Or —and this seems to be the much more common case— the class of intended strings does not contain all the ones that are physically possible, i.e. our intended strings are represented by the physically ones with a certain redundancy. Using the terms "legal" and "illegal" for strings within and beyond the intended class respectively, we can formulate the following conclusions.

1) The class of legal strings must be defined precisely. If this already presents serious problems, this is a warning not to be ignored.

2) Any part processing such a string should establish whether the string is legal or not. If this presents serious problems, this is a warning not to be ignored.

3) Any part processing such a string should not react upon an illegal string as if it were a legal one.

4) Processing an illegal string may not wreck the part: none of the relations which are carefully kept invariant during the processing of legal strings may be destroyed by the processing of an illegal string.

Note. If program component B processes a string produced by program component A without satisfying the above conditions 2 through 4 —for instance because it is felt to be too expensive to make component B that way— , we should regard components A and B as belonging to the same part. (End of Note.)

*          *
*

To wind up I would like to make two suggestions: I would like to suggest to programmers that they have a closer look at mathematics, and to mathematicians that they have a closer look at programming. By virtue of their tradition mathematicians have a more explicit appreciation for what it means to be rigorous, as a result of the power of currently available machines programmers are more aware of the problems created by sheer size.

I do not suggest that programmers should stuff their heads with mathematical results, but I would like them to get a better appreciation for how and how effectively mathematics are organized. If they do so I expect them to discover that many current topics in computing science are in a sense null-problems as they address problems that should never have been there to start with. I expect them to discover that if they are problems now, we are suffering from the pains of a hell into which our own sins have sent us. I also expect them to discover that these problems are only soluble by starting over again, and that the perpetuation of some old mistakes is the worst mistake we can make now. As very likely candidates for null-problems I mention those associated with compatability, portability and protection.

I also feel that many a mathematician could profit from the exposure to programming. I have that feeling because, while studying mathematical texts, I now very often observe as my reaction towards the author "He must be a very poor programmer!" We, as programmers, have, for instance, been so trained to avoid case-analysis like the plague that it is not unusual at all to encounter a mathematical argument, the length of which can be halved, perhaps even be halved a number of times.

While preparing this invited speech I had to guess at what type of audience I would eventually address. The title of the Symposium's subject "Mathematical Foundations of Computing Science" was my only indication. If I have the privilege of addressing a primarily mathematically interested audience, it is clear how my ending note should sound, for in that case I can only urge you, Mathematicians, not to confine with respect to Computing Science your interest to its foundations! The praxis of computer programming needs you as much as you need its challenge, if Mathematics is to remain the Queen of Sciences.

May 1976 NUENEN, The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Karl Cooper
revised Fri, 1 Oct 2010

EWD563

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 563 Formal techniques and sizeable programs
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 205�214 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

FORMAL TECHNIQUES AND SIZEABLE PROGRAMS

Edsger W.Dijkstra

Burroughs

Plataanstraat 5

NL-4565 NUENEN

The Netherlands

By now we know quite convincing, quite practical and quite effective methods of proving the correctness of a great number of small programs. In a number of cases our ability is not restricted to a posteriori proofs of program correctness but even encompasses techniques for deriving programs that, by virtue of the way in which they have been derived, must satisfy the proof’s requirements.

This development has taken place in a limited number of years, and has changed for those who are familiar with such techniques their outlook on what programming is all about so drastically, that I consider this development both fascinating and exciting: fascinating because it has given us such a new appreciation of what we already knew how to do, exciting because it is full of unfathomed promises.

This development is the result of a very great number of experiments: experiments in programming, in axiomatizing, and in proving. It could never have taken place if the researchers in this field had not shown the practical wisdom of carrying out their experiments with small programs. As honest scientists they have reported about their actual experiences. This, alas, has created the impression that such formal techniques are only applicable in the case of such small programs.

Some readers have exaggerated and have concluded that these techniques are primarily or exclusively applicable to so-called “toy problems”. But that is too great a simplification. I do not object to describing Euclid’s Algorithm for the greatest common divisor as a “toy problem” (in which capacity it has been a very fertile one!). But I have also seen perfectly readable and adequate formal treatments of much less “toyish” programs, such as a binary search algorithm and a far from trivial algorithm for the computation of an approximation of the square root, which would be ideal for a microprogram in a binary machine. I call this last algorithm “far from trivial” because, although it can be described in a few lines of code, from the raw code it is by no means obvious what the algorithm accomplishes.

The question that I would like to address here is what we may expect beyond those “small examples”. Hence the adjective “sizeable” in my title.

The crude manager’s answer to my question is quite simple: “Nothing.”. He will argue that difficult problems require large programs, that large programs can only be written by large teams which, by necessity, are composed of people with, on the average, n-th rate intellects with n sufficiently large to make formal techniques totally unrealistic.

My problem, however, is that I don’t accept that answer, as it is based on two tacit assumptions. The one tacit assumption is that difficult problems require large programs, the second tacit assumption is that with such a Chinese Army of n-th rate intellects he can solve the difficult problem. Both assumptions should be challenged.

On challenging the second assumption I don’t need to waste many words: the Chinese Army approach —also called “the human wave”— has been tried, even at terrific expense, and the results were always disastrous. US/360 is, of course, the best known example of such a disaster, but please, don’t conclude from NASA’s successful moonshots that in other cases it has worked. There is plenty of evidence that the data processing associated with these NASA ventures was full of bugs, but that the total organization around it was, however, so redundant that the bugs usually did not matter too much. In short, there is plenty of experimental evidence that the Chinese Army approach does not work; and as a corollary we may conclude that the perfection of Chinese Army Generals is a waste of effort. At the end of my talk I hope that you will agree with me that, in order to reach that conclusion, said experimental evidence was superfluous, because a more careful analysis of the tasks at hand can teach us the same.

*              *
*

For my own instruction and in order to collect material for this talk I conducted and experiment that I shall describe to you in some detail. I do so with great hesitation because I know that, by doing so, I shall sow the seed of misunderstanding. The problem of a speaker is that, if he does not give examples, his audience does not know what he is talking about, and that, if he gives an example, his audience may mistake it for his subject! In a moment I shall describe to you my experiment and you will notice that it has to do with syntactic analysis, but, please, remember that syntactic analysis is not the subject of my talk, but only the carrier of my experiment for which I needed an area for computer application in which I am most definitely not an expert.

I wrote a paper with the title “A more formal treatment of a less simple example.”. Admittedly it was still not a very large example: the final solution consisted of four procedures, of which, in beautiful layout with assertions inserted, three were only 7 lines long and the last one 18 lines. But the whole document is 19 typed pages, i.e. about 14 times as long as the raw code. It took me several weeks of hard work to write it, and when it was completed I was grateful for not having been more ambitious as far as size was concerned. It dealt with the design of a recognizer for strings of the syntactic category < sent > , originally given by the following syntax:

| < sent >::=< exp >; | (1)
| < exp > ::=< term > | < exp > + < term > < exp > - < term > |
| < term >::=< prim > | < term > * < prim > |
| < prim >::=< iden > | ( < exp > ) |
| < iden > ::= < letter > | < iden >< letter > |

That was all!

My first experience was that, in order to give a more precise statement about the string of characters that would be read in the case that the input was not an instance of < sent > , I needed new syntactic categories, derived from (1) and denoting “begin of...”: for each syntactic category < pqr > I needed the syntactic category < bopqr > , characterizing all strings that either are a < pqr > or can be extended at the right-hand side so as to become a < pqr > or both.

| < bosent > ::= < sent > | < boexp > | (2)
| < boexp > ::= < boterm > | < exp > + < boterm > < exp > - < boterm > |
| etc. |

(In an earlier effort I had also used the notion “proper begin of a < pqr > ”, i.e. at the right-hand side extensible so as to become a < pqr > but not a < pqr > by itself. This time I obtained a simpler and more uniform treatment by omitting it and only using “begin of...” as derived syntactic categories.)

The next important step was the decision to denote the fact that the string K belongs to the syntactic category < pqr > by the expression:

| pqr(K)

This decision was an immediate invitation to rewrite the syntax as follows:

| < sent > ::= < exp > < semi > | (3)
| < semi > ::=; |
| < exp > ::=< term > | < exp >< adop >< term > |
| < adop >::=+ | - |
| < term > ::= < prim > | < term >< mult >< prirn > |
| < mult >::= * |
| < prim > ::=< iden > | < open >< exp >< close > |
| < iden > ::= < letter > | < iden > < letter > |
| < open > ::= ( |
| < close > ::= ) |

The invitation, however, was only noticed after I had dealt with the first line of the syntax, dealing with < sent >; when dealing with < exp > , it was the occurrence of both the + and the - that induced the introduction of < adop > , because without it my formulae became full of insipid duplication. It was only then that I discovered that the boolean procedure “semi(x)” —only true if the character x is a semicolon— and the other boolean procedures that I needed for the classification of single characters were a specific instance of the convention that introduced “pqr(K)” . Finally I realized that the usual BNF , as used in (2), is an odd mixture in the sense that in the productions the characters stand for themselves; in (3) this convention is restricted to the indented lines.

A next important decision was to denote for strings (named K, L, ...) and characters (named x, y, ...) concatenation simply by juxtaposition, e.g. KL , Ky yLx , etc. Now we could denote the arbitrary nonempty string by yL or Ly and could derive from our syntax formulae like

| (exp(L) and semi(y)) ⇒ sent(Ly)V .

It also enabled me to define the “begin of...”:

| bopqr(K) = (E L: pqr(KL))

I mention the apparently trivial and obvious decision to denote concatenation by juxtaposition explicitly, because in the beginning my intention to do a really neat formal job seduced me to introduce an explicit concatenation operator. Its only result was to make my formulae, although more impressive, unnecessarily unwieldy.

From my earlier effort I copied the convention to express post-conditions in terms of the string of characters read. With “S” defined as the string of input characters “read” —or “moved over” or “made invisible”— by a call of “sentsearch” and with “x” defined as the currently visible input character, we can now state the desired post-condition for our recognizer “sentsearch”:

Rs(S, x, c): | bosent(S) and non bosent(Sx) and c = sent(S) | (4)

The first term expresses that not too much has been read, the second term expresses that S is long enough, and the last term expresses that in the global boolean “c” —short for “correct”— the success or failure to read a < sent > from the input should be recorded.

In short, we treat S and x as variables (of types “character string” and “character” respectively) that are initialized by a call of sentsearch . I mention this explicitly, because for a while we departed from that convention, and did as if the “input still to come” were defined prior to the call of sentsearch. We tried to derive from our post-condition weakest pre-conditions in terms of the “future” input characters, and the result was a disaster. At some time during that exercise we were even forced to introduce a deconcatenation operator! The trick to regard as “post-defined output” what used to be regarded as “pre-defined input” cannot be recommended warmly enough: it shortened our formulae with a considerable factor and did away with the need for many dummy identifiers.

Another improvement with respect to our earlier effort was a changed interface with respect to the input string. In my earlier trial I had had as a primitive to read the next character

| x:= nextchar

where “nextchar” was a character-valued function with the side-effect of moving the input tape over one place. (If S is the string of characters read, the above assignment to x should be followed implicitly by the “ghost statement” S:: Sx .) Prior to the first x:= nextchar , the value of the variable x was supposed to be undefined. In the new interface, where x is the currently visible character and S the string of characters no longer visible, I chose the primitive “move”, semantically equivalent to the concurrent assignment

| S, x := Sx, new character .

This minor change of interface turned out to be a considerable improvement! In the new interface, the building up of S lags one character behind compared with the old interface. Formula (4) shows how we can now refer —via concatenation— to two strings, one of which is a character longer than the other. With the old interface we would have needed a notation for a string one character shorter than S , some thing so painful that in my earlier effort a different specification for sentsearch was chosen, with the old interface more easily described, but logically less clean than (4).

I wanted to write a body for sentsearch in terms of a call on expsearch and the boolean primitive semi(x) which was assumed to be available. I wished to do so only on account of the syntax for < sent > and discovered that I only could do so under the assumption —to be verified later when the full syntax was taken into account— that

| sent(L) ⇒ non (E y: bosent(Ly)) | (5)

would hold. Confronting this with the specification (4) we conclude that if sentsearch establishes a final state with c = true , i.e. sent(5) , the second term —non bosent(Sx)— is true for all values of x : in other words, postulate (5) states that the end of an instance of the syntactic category < sent > can be established “without looking beyond”.

We assume the availability of a primitive expsearch . Defining “E” to be the string of input characters mover over by it, it establishes, analogous to (4):

Re(E, x, C): | boexp(E) and non boexp(Ex) and c = exp(E) . | (6)

Called by sentsearch, it implies S:= SE (as “move” implies S:= Sx ). A possible body for sentsearch is now:

| proc sentsearch: {S = empty string}
|  | expsearch {Re(S, x, c)};
|  | if non c → {Rs(S, x, c)} skip {Rs(S, x, c)}
|  |  | ▯ non semi(x) — {Rs(S, x, false)} c:= false {Rs(S, x, c)}
|  |  | ▯ c and semi(x) → {Rs(Sx, y, c)} move {Rs(S, x, c)}
|  | fi {Rs(S, x, c)}
| corp

For its correctness proof I needed three theorems:

Theorem 1. | (Re(L, x, c) and non c) ⇒ Rs(L, x, c)
Theorem 2. | (Re(L, x, c) and non semi(x)) ⇒ Rs(L, x, false)
Theorem 3. | (Re(L, x, c) non c and semi(x)) ⇒ Rs(Lx, y, c)

The proofs of those three theorems and also of

| boexp(L) ⇒ non sent(L)

that I needed in these proofs took more than one-and-a-half page.

In the meantime the first 6 of the 19 pages had been written. The primitive expsearch asked for another three theorems to be proved and was finished 4 pages later; by analogy termsearch took only half a page; the primitive primsearch required another six theorems to be proved and was completed 6 pages later. The remaining two-and-a-half page were needed to prove assumption (5) and the similar

| (term(L) and adop(y)) ⇒ non boterm(Ly)
and | (prim(L) and mult(y)) ⇒ non boprim(Ly)

and for some closing remarks.

I shall not go with you in any detail through these proofs and programs. I only mention that I had to replace

| < exp > ::= < term > < exp >< adop >< term >

first by

| < exp > ::= { < term >< adop >}< term >

in order to open the way for a repetitive construct in the body of expsearch. Thereafter I had to replace it by

| < exp > ::= < adder >< term >
| < adder > ::= { < term >< adop >}

because I needed the expression “adder(L)” in my proofs and assertions. The syntax for < term > and < prim > were subjected to similar massaging operations.

*              *
*

So much for the description of my experiment. Let me now try to summarize what seem to be the more relevant aspects of the whole exercise.
1)     The routines I designed this time were definitely more beautiful than the ones I had written three years ago. This confirms my experience with the formal treatment of simpler examples, when I usually ended up with more beautiful programs than I had originally in mind.
2)     A slight change in the interface describing the reading of the next input character caused a more serious change in the overall specifications chosen for sentsearch: the formal treatment exposed the original interface as a seed of complexity.
3)     To treat a program absorbing input L formally as a non-determinstic program assigning, as it were, a “guessed” value to L is a very useful device, so useful, in fact, that all by itself it is probably a sufficient justification for including non-determinacy in our formal system. (Independently and in another context, also C.A.R.Hoare was recently led to treat input in this fashion.)
4)     Nearly 11 of the 19 pages don’t deal with the programs at all! They are exclusively concerned with exploring the given syntax and proving useful theorems about strings, theorems expressed in terms of predicates derived from the given syntax.
4.1)     My earlier treatment of this example took only 7 pages: most of the theorems I proved this time were in the older treatment regarded as “obvious”.
4.2)     Several patterns of deduction appear in more than one proof; the introduction of a few well-chosen lemmata could probably have condensed somewhat what now took 11 pages.
4.3)     The formal treatment of a program requires a formal “theory” about the subject matter of the computations. The development of such a theory may be expected to require the introduction of new concepts that did not occur in the original problem statement.
4.4)     In the development of such a theory the choice of notation is crucial. (In this exercise the struggle of developing the theory was mainly the search for an adequate notation; once that had been invented, the development of the theory was fairly straightforward and I don’t think that the final document contains more than a single line —at the end, where I was getting tired and lazy— that could cause a serious reader serious problems .)
5)     There is a wide-spread belief that such formal proofs are incredibly long, tedious to write and boring to read, so long, tedious, and boring as a matter of fact, that we need at least a computer to verify them and perhaps even a computer to generate them. To the idea that proofs are so boring that we cannot rely upon them unless they are checked mechanically I have nearly philosophical objections, for I consider mathematical proofs as a reflection of my understanding and “understanding” is something we cannot delegate, neither to another person, nor to a machine. Because such philosophical objections carry no weight in a scientific discussion, I am happy to be able to report that my experiment completely belied the said wide-spread belief.

Since many years I have found that when I write an essay in which a program is developed, the total length of the essay is a decimal order of magnitude greater than the length of the program in which it culminates. The transition to a highly formal treatment has not changed that ratio significantly: it has only replaced the usual handwaving and mostly verbal arguments by more concise, much more explicit and, therefore, more convincing arguments. The belief that formal proofs are longer than informal arguments is not supported by my experiment. The belief that the writing and reading of such proofs is tedious and boring has also certainly not been confirmed: it was an exciting challenge to write it and those who have seen it have confirmed that it was fascinating to read, because it all fitted so beautifully —as, of course, in a nice formal proof it should!— . I am tending to regard the belief that these formal proofs must be long, tedious and boring, as a piece of folklore, even as a harmful —because discouraging— piece of folklore that we had better try to get rid of. The fact that my formal treatment was in all respects to be preferred above my former, informal treatment has been one of the most encouraging experiences from the whole experiment, and I shall not try to hide the fact that I am getting very, very suspicious of the preachers of the refuted belief: they are mostly engaged on automatic verification or proving systems. By preaching that formal proofs are too boring for human beings they are either trying to create a market for their products and a climate favourable for their funding, or only trying to convince themselves of the significance of their work. The misunderstanding is aggravated by the complicating circumstance that their own activities seem to support their beliefs: I have seen a number of correctness proofs that have been produced by (semi-)mechanized systems, and, indeed, these proofs were appalling!
6)     The design consisted of a set of procedures; ignoring the possibility of a recursive call —as would have been the case when the second alternative production for < prim > had been omitted— they form a strict calling hierarchy of four layers deep. It is worth noticing that all through that calling hierarchy the specification of the procedures is of the same simple nature. The fact that, when we go up the hierarchy, we create in a sense more and more “powerful” machinery is not reflected in greater complication of the treatment, more elaborate interfaces,or what have you. This, too, is a very encouraging observation, as it gives us some clue as to what we might expect when we would undertake a more ambitious experiment with a still less simple example. Somewhere in his writings —and I regret having forgotten where— John von Neumann draws attention to what seemed to him a contrast. He remarked that for simple mechanisms it is often easier to describe how they work than what they do, while for more complicated mechanisms it was usually the other way round. The explanation of this phenomenon, however, is quite simple: a mechanism derives its usability in a larger context from the adequacy of its relevant properties and when they are very complicated, they are certainly not adequate, because then the mechanism is certain to introduce confusion and complexity into the context in which it is used. As a result of this observation I feel that there is a reasonable justification for the expectation that a next more ambitious experiment will just confirm my earlier experiences.

*              *
*

As you will have noticed I have accepted as some sort of Law of Nature that for the kind of programs I talk about, I accept a documentation ten times as long as the raw code, a Law of Nature that relates how we think to the best of our ability when we program to the best of our ability. Those struggling with the maintenance of programs of, say, 100,000 lines of code, must shudder at the thought of a documentation ten times as bulky, but I am not alarmed at all.

My first remark is that for the kind of programs I am talking about, the actual code is apparently a very compact deposit of our intellectual labours. In view of the various —and considerable!— costs caused by sheer program length, this compactness should be a reason for joy! But then we cannot complain at the same time about the factor ten! You cannot have your cake and eat it....

My second remark to console the man struggling with the 100,000 lines of code is, admittedly, still a conjecture, but a conjecture for which I have not the slightest indication that it might be wrong. The conjecture is that the actual size of 100,000 lines is less dictated by the task he seeks to solve than by the maximum amount of formal text he thinks he can manage. And my conjecture, therefore, is that by applying more formal techniques, rather than change the total amount of 100,000 lines of documentation, he will reduce the length of the program to 10,000 lines, and that he will do so with a much greater chance of getting his program free of bugs.

*              *
*

As a result of this exercise I discovered an omission from all computer science curricula that I have been familiar with: we don’t try to teach how to invent notations that are efficient in view of one’s manipulative needs. And that is amazing, for it seems much less ambitious than, say, trying to teach explicitly how to think effectively. When teaching standard mathematical subjects, they get acquainted with the corresponding standard notations and these are fairly effective; so they have good examples, but that is all! I think that it could help tremendously if students could be made aware of the consequences of various conventions, consequences such as forced repetition, or all information sinking into the subsubsubscripts, etc.

My last remark is added because you may have noticed quantitative concerns from my side, such as worrying about the length of formulae and proofs. This is partly the result of a small study of elegant solutions. The study is not completed yet, but one observation stands out very clearly: the elegant solutions are short.

Appendix.

By way of illustration I include an excerpt from EWD550 “A more formal treatment of a less simple example.” After the establishment of formulae (7) through (11) —as numbered in EWD550!— , i.e. the choice in the case of (7), (8), and (11), and the derivation in the case of (9) and (10):

Rs(S, x, c): | bosent(S) and non bosent(Sx) and c = sent(S) | (7)

| < sent > ::= < exp > ; | (8)
| < bosent > ::= < sent > | < boexp > | (9)
| boexp(L) ⇒ non sent(L) | (10)

Re(E, x, c): | boexp(E) and non boexp(Ex) and c = exp(E) | (11)

the text continues as follows.

“Designing sentsearch in terms of expsearch means that we would like to have theorems, such that from the truth of a relation of the form Re the truth of relations of the form Rs can be concluded. There are three such theorems.

Theorem 1. (Re(L, x, c) and non c) ⇒ Rs(L, x, c)

Proof. | Assumed: |
0. | Re(L, x, c) and non c |
| Derived: |
1. | boexp(L) | with (11) from 0
2. | bosent(L) | with (9) from l
3. | c = exp(L) | with (11) from 0
4. | non c | from 0
5. | non exp(L) | from 3 and 4
6. | non sent(Lx) | with (8) from 5
7. | non boexp(Lx) | with (11) from 0
8. | non bosent(Lx) | with (9) from 6 and 7
9. | non sent(L) | with (10) from l
10. | c = sent(L) | from 4 and 9
11. | Rs(L, x, c) | with (7) from 2, 8, and 10
|  | (End of Proof of Theorem l.)”

(End of Appendix)

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

  EWD 564

A superficial book.

"Techniques of Program Structure and Design.", Edward Yourdon, Prentice Hall, 1975.

It is not my habit to comment in written form on all the junk and trash that meets my eyes, but sometimes I must. Edward Yourdon's book presents such a case, because the book is not just superficial, it is dangerously so. It is a misleading text, against which potential readers should be warned. The fact that the book is poorly written is something that the uninitiated but careful reader can discover for himself; the uninitiated reader, however, can not discover from this book alone that, measured against today's state of the art, it is hopelessly old-fashioned, and betrays a singular lack of insight in the subject matter it claims to cover.

It is poorly written: even the English of the title is faulty! "Techniques of Design" is a proper construct, but "Techniques of Program Structure" is just a meaningless concatenation of words. Another example of poor English do we find on page 247 "...until it has been demonstrated to everyone's satisfaction that the corrected bug does work correctly.". If it "does not work correctly" —in the author's parlance— how can we refer to "the corrected bug"? Furthermore I find it somewhat strange that after its correction —i.e. its removal!— the bug is still supposed to be there and "doing" something. Presumably the author should have written "...until it has been demonstrated to everyone's satisfaction that the bug has been successfully removed.". But even after that repair, the sentence is not very helpful, for what is meant by "everyone's satisfaction"? My guess is that from the unspecified environment the author refers to, I, for instance, should be excluded. The quotation is typical of the author's approach: in spite of the fact that the title mentions "techniques" the author skirts technical issues completely, and seems to measure quality primarily indirectly by degree of "satisfaction" given to the environment. The book is misleading in that it suggests that such a nontechnical, sociological approach suffices.

The next quotation from page 246 is, I am afraid, fairly indicative for the book's quality:

"7.1.7 Glitch

The word "glitch" is one of those unofficial terms that has gained popularity in the vocabulary of the industrial/academic computer communities of Cambridge and Berkeley. Though never defined precisely a glitch is usually thought of as an unforeseen feature of a computer program (or, in most cases, the specification and design of a program) that renders it inefficient, unelegant, or awkward to use. Note there is a difference between a bug and a glitch. A bug implies that the program is not working to specifications, while a glitch implies that the specification itself (of some property of the program outside the scope of the specification) is awkward or clumsy."

I am —I am happy to say— unfamiliar with the "industrial/academic computer communities" alluded to, that are here accused of such sloppy use of the term "glitch", a precisely defined term which in that meaning is officially reserved for a very well-known phenomenon that is to be expected to occur when synchronizing independently clocked systems. (Stronger: neither in Berkeley, nor in Cambridge, USA, have I ever heard the term used by people in any other than its technical meaning.) But suppose for a moment that the author were not wrong in this paragraph: does the paragraph then carry any helpful information? I could hardly find any....

An example of hilarious nonsense can be found on page 281 where "it seems that the number [...] of bugs increases exponentially with the number of instructions in the module." This tells us that by making a module large enough we can achieve that the number of bugs exceeds the number of instructions in the module, nay, even exceeds the number of bits needed to store these instructions! The frightening thing about this piece of nonsense, however, is that , in spite of an earlier chapter on "Modular Programming" —of more than 40 pages— the author still thinks he can meaningfully speak of "the number of bugs in a module". If he had used that earlier chapter to develop a meaningful concept "module", he would have discovered that the "number of bugs in a single module" is either zero or one, i.e. the module is either correct or not. In the latter case, counting their number is as meaningless as counting the number of misspellings in the names of the well-known authors in computer science "Ivan Yourdon" or "Niklaus Hoare".

One final quotation —page 9— "Of course, it is important (sic!) to point out that comments are not an end unto themselves." This sentence may give us a glimpse of the intended readership: those who still think that comments are an end unto themselves.

*          *
*

We shall not blame the author for the publisher's blurb on the jacket that describes the book as "A clearly written, logically organized, and easy-to-understand discussion....". But I am amazed and alarmed, when I see this book recommended in a Prentice-Hall folder as follows:

"I certainly enjoyed reading this excellent treatise. The author is obviously an authority on the subject but so are many others. However, the rare quality of his exposition is a synergistic combination of humor, elegance of style, breadth of coverage, diversity of programming languages and applications, organization, and lucidity. What more can I say? [...]"
         Carl Hammer, Ph.D., Director, Computer Sciences, Univac, Adjunct Professor, The American University, Washington, D.C.

and

"Best I've seen on the topic."
Professor H.R.Knitter, University of Wisconsin, Madison.

Publishers are supposed to be willing to print anything they think they can sell —I don't think that that is the full truth, but they are supposed to be that way. Professors at our Universities are supposed to be able not to mistake a totally unscientific work for something worth their recommendation, but, apparently, that is not the full truth either....

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Wed, 31 Jan 2007

EWD564a

Aan de raad van advies, in de tweede ronde.

De bestudering van de eerst reacties van collegae Verbeek en Whitfield heeft mij geen aanleiding gegeven passages in EWD555 te herzien, te relativeren of te versterken. Wel voel ik de behoefte tot enkele aanvullingen.

1) De eerste reacties mijner collegae hebben mijn indruk versterkt dat van Leeuwen niet voor zijn taak berekend was: professioneel te smal en als verslaggever incompetent. Ik moet de Raad van Advies dan ook op het hart binden in volgende gevallen bewust en zorgvuldig iemand van hoger kaliber aan te zoeken. Dit klemt des te meer omdat het niet ongebruikelijk is dat, waar in een gevoelige situatie juist iemand van gewicht nodig is, uit "veiligheidsoverwegingen" maar al te vaak een te lichte, te kleurloze of onvoldoend krachtige candidaat naar voren geschoven wordt. Van Leeuwen's incompetentie als schrijver is zo manifest, dat de Raad van Advies of hiervan op de hoogte geweest moet zijn, of de man überhaupt niet kende. In beide gevallen signaleer ik ernstige onzorgvuldigheid.

2) Op soortgelijke gronden moet de Raad van Advies zich afvragen of hij voldoende gelukkig is met zijn voorzitter: de reacties in eerste ronde maken bv. duidelijk dat zijn brief WLvdP/JN/LBD d.d. 29 januari 1976 geen schoolvoorbeeld van duidelijkheid is.

3) Een zin in Whitfield's eerste reactie herinnerde mij aan een punt, dat ik wel gezien had, maar waar ik toen ten onrechte verder geen aandacht aan heb geschonken. Het betreft de passage in het Kort Commentaar op pg. 5 (regel 7 - 14 van boven) over de onvervulbare sous-chef-vacature.

Dat een leidende functie op het Mathematisch Centrum onvervulbaar blijkt, is ronduit alarmerend. De oorzaken van deze onvervulbaarheid komen in de Beschouwing niet aan de orde; in het Kort Commentaar wordt zij voorgesteld als "one of the facts of life":

"Ik moge echter bekend veronderstellen hoe moeilijk het is in Nederland ervaren praktische informatici —liefst gepromoveerd— te vinden die een academische of vergelijkbare functie ambiëren."

Maar dat kan het hele verhaal niet zijn! Ik struikel om te beginnen over het "academische of vergelijkbare functies". Van mij, die mijn gewone toga over de haag geworpen heb, kunt U alle begrip verwachten over de moeilijke vervulbaarheid van academische vacatures. Het zou juist een van de enorme attracties van het Mathematisch Centrum moeten kunnen zijn, dat in belangrijke opzichten de functies aldaar niet vergelijkbaar zijn met hun academische tegenpool. Het kan ook zo zijn, dat in Bakker's "academisch of vergelijkbaar" het woord "academisch" niet gebruikt wordt in de letterlijke zin van het "aan het hoger onderwijs verbonden", maar wat meer overdrachtelijk, als algemene aanduiding van een intellectueel klimaat. Moeten we de opmerking dan lezen als een verwijzing naar de riante arbeidsmarkt voor ervaren praktische informatici? Over die riante arbeidsmarkt wil ik dan graag nadere inlichtingen ontvangen! De oorzaken van de moeilijke vervulbaarheid moeten andere zijn en ik wil U dan ook met klem adviseren te trachten deze te achterhalen, omdat ik er ernstig rekening mee houd, dat in de laatste instantie de oorzaken binnenshuis gevonden zullen worden.

Nuenen, 8 april 1976 | prof. dr. Edsger W. Dijkstra

PS. Ik kan de wijze van postaal vergaderen, als door onze commissie ad hoc gevolgd, een ieder van ganserharte aanbevelen.

EWD.

transcribed by F. Koenders
revised Thu, 13 Nov 2008

EWD565

Elfde toespraak tot mijn studenten, voorjaar 1976.

De professionele omgang met grote aantallen mensen werkt verloederend. Van de generale staf is dat bekend: voor en na de veldslag tellers ze de activa: zoveel tanks, zoveel vrachtwagens, zoveel kanonen, zoveel mensen... Van alle eenheden is een prijs vastgesteld, zodat na afloop in dollars, guldens, ponden of roebels precies bekend is, hoeveel de veldslag gekost heeft. Het enige verschil in de diverse boekhoudingen is de verhouding der prijzen van de verschillende eenheden: in dollars is een mens relatief duurder dan in roebels. En wie daarin geen compliment voor de 200-jarige wil zien, kan schamper opmerken, dat dat allemaal komt omdat in het kapitalistische systeem oorlogstuig als tanks en kanonen zo goedkoop gemaakt kan worden, maar dat vind ik dan een zure opmerking. Elk systeem, dat de relatieve waarde van een mens doet toenemen, juich ik toe; ik ben dan ook een groot voorstander van geboortebeperking, desnoods met terugwerkende kracht.

U moet evenwel niet denken, dat deze verloedering zich tot generaals beperkt. Hebt U wel eens met een vervoerswegen gesproken? Voor hem zijn "reiziger-kilometers" net zulke eenheden als "tonmijlen". We mogen ze geen ongelijk geven, sterker zelfs, ik voel vaak medelijden met de NS in me opkomen: als ik de stinkende horde zich in Amsterdam-Centraal zie verdringen en zich in de trein zie misdragen, denk ik vaak bij mezelf "Ik vervoerde liever erts...".

Als U wegens ontstentenis van een vervoerswezen in Uw kennissenkring niet begrijpt, wat ik bedoel, zoek dan een verzekeringswezen op: hoe hij tegen een jonggehuwde man over "een prettige weduwedekking" praten kan, is hoogst verhelderend. En als U die ook niet vinden kan, neem dan een hoofdverpleegster, een personeelschef, een vakbondsleider of een onderwijsdeskundige. U kunt dan naar keuze gereduceerd worden tot een patient, tot een plaatsingsprobleem, tot een contribuant of tot een cognitief complex.

De conclusie dringt zich op, dat wij met grote aantallen eigenlijk geen raad weten, en het zou verhelderend zijn, wanneer wij eerlijk toegaven, dat de meeste mensen nauwelijks tot tien kunnen tellen, en grotere getallen slechts veinzen te kunnen hanteren door er nullen achter te zetten. Het zou eveneens verstandig zijn er serieus rekening mee te houden dat de verloedering in het huidig onderwijs —zowel midelbaar als hoger— kenmerkt, wel eens het onvermijdelijk gevolg van de schaalvergroting kon zijn.

Als dat zo is, moeten we, daarom alleen al, wat vraagtekens plaatsen bij wat ik in modern Nederlands geloof ik als "het vakgroepgebeuren" moet aanduiden, "dat ergens bij mij overkomt als een nostalgische hang naar participatieve geborgenheid in de persoonlijke motivatie tot de educatief-wetenschappelijke taakstelling met betrekking tot het kader van de gelijke kansen voor het volk in de regio." Ik bedoel maar, dat "zuiver maatschappij-critisch gezien" natuurlijk, de instelling van vakgroepen boerenbedrog is, als hiermee een schaalverkleining beoogd wordt, die de ongewenste gevolgen van de schaalvergroting zou moeten compenseren.

Je kunt natuurlijk proberen een uit zijn krachten gegroeide faculteit in vakgroepen te versnipperen en van voornoemd vakgroepgebeuren een zo tijdrovend gezelschapsspel te maken, dat tenslotte niemand meer de tijd heeft om over de grenzen van zijn eigen snipper heen te kijken. Maar om dit streven te laten slagen, moet met het hoger onderwijs wel bemannen met bijziende struisvogels, die niet meer zien, dat op het ministerie de sfeer heerst van de generale staf, van het openbaar vervoer en het verzekringswezen. U bent slechts consument van studieeenheden.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

EWD566

Programming: from craft to scientific discipline.

Summary:

In response to the software crisis and to the lack of clear guidance in the design of programming languages, "programming methodology" emerged in the second half of the sixties, with the avowed purpose of discovering what would be involved in the design of sizeable high-quality programs. The recognition that high-quality implied correctness and that correctness could be proved in theory and might be provable in practice then became a major driving force. The proper roles of intuition and of formal discipline were reassessed, thereby reshaping the nature of the programmer's task and his way of working. After a general survey of this development and an indication of its significance, some of its consequences will be discussed, because it is certain to have great impact upon our educational practices in computing science and software engineering, on the constitution of our work force, on the division of intellectual labour and on the management of software development projects. (End of summary.)

When, in the late sixties, I coined the term "Structured Programming" I made a few serious mistakes. One mistake has been that I did not make it a registered trademark. Another mistake has been that I introduced the term without giving a definition for it. My only excuse is that I had not foreseen that the term, just the term, mind you, would spread like wildfire, and would become one of the most overworked buzzwords of the computing scene in the seventies (to such an extent, as a matter of fact, that since a number of years I myself have stopped using the term altogether). I would like to use this opportunity to explain why I did not define it and, yet, introduced it. Such an explanation seems a good introduction for a description of what has roughly happened since then: to give you a feeling for the significance of the development in programming during the last eight years is the main purpose of this talk.

*                    *
*

For reasons that I shall mention in a moment, several of us felt that the activity of computer programming had not only the potential, but also a great probability of changing drastically. Whether the change would be so slow as to be called "evolution" or so abrupt as to be called "revolution" was something we did not venture to predict. But the nature of the change itself was clear enough and we needed a name to label the development that, we felt, was about to occur. Hence I coined the term "Structured programming": I felt that it captured my observations and my hopes very nicely.

In the mid-sixties we observed what was then known as "the software failure" or "the software crisis". Its emergence was no surprise, its occurrence had been predicted. In not much more than ten years the power of commonly available computers had increased by a factor of thousand, and our programming ability had not increased in proportion. Besides that, the logically simple, sequential machines of the fifties had been replaced by much more complicated pieces of equipment, complicated by such features as multi-level stores and asynchronously active peripherals. It was very clear that the programming task was outgrowing our programming capacities and the emergence of the software crisis was, as said, no surprise. The problem, however, was that very little could be done about it, as long as its existence was hardly admitted or even denied: it is vain to urge a world to try to improve its programming habits as long as that world pretends that its programming habits are perfectly adequate. In this respect the conference on "Software Engineering", sponsored by the NATO Science Committee and held in Garmisch, Germany, in October 1968 was the great turning point: here the existence of the software crisis and the urgency of the situation was openly admitted by such an impressive collection of representative authorities, that this admission was sure to have its impact and to help create the climate in which a change in our programming habits could be discussed. This conference was one of the main reasons why we felt that for the expected change the time to happen at last had come.

Another reason was the fate of a number of committees trying to design a new and better programming language, such as the SHARE Committee designing PL/I and IFIP Working Group 2.1 trying to design a successor for ALGOL 60. I —and many share this opinion, although perhaps for different reasons— consider both efforts, each in their own way, as most unsuccessful. It was already during the design phase of those languages that many of the people originally involved became very doubtful as to whether things were developing in the right direction. Inexperienced as they were, they first blamed the committee mechanism, and the joke of the season was to define a camel as a horse designed by a committee. But on closer inspection it was discovered that not all the blame could be put on the committee mechanism, for there was a profounder reason: we did not know the nature of the programmer's task well enough.

Each tool shapes its users, and each programming language reflects, in its capacity as a tool, a picture of the programmer and his task. A rather intuitive, not very explicitly described but commonly accepted picture of the programmer and his task had given rise to FORTRAN and ALGOL 60. The failure to achieve striking improvements upon them was a direct consequence of the fact that our view of the programmer and his task had insufficiently evolved. The "typical programmer" still seemed to be the professional physicist or engineer who, for some technical computation, would write as a nonprofessional programmer a three-page program in an afternoon, i.e. very much the same prospective user that had inspired FORTRAN and ALGOL 60 some ten years earlier. Hence, for instance, the paralyzing stress on the requirement that the new language should be "easy to learn"; in practice this meant that the new language should not be too unfamiliar, and too often "convenient" was confused with "conventional". More and more people began to feel that tuning those designs to the supposed needs of the nonprofessional programmer was ..... for lack of any idea how a truly professional programmer would look like! We knew how the nonprofessional programmer could write in an afternoon a three-page program that was supposed to satisfy his needs, but how would the professional programmer design a thirty-page program in such a way that he could really justify his design? What intellectual discipline would be needed? What properties could such a professional programmer demand with justification from his programming language, from the formal tool he had to work with? All largely open questions. In an effort to find their answers a new field of scientific activity emerged in the very late sixties; it even got a name: it was called "Programming Methodology".

*                    *
*

Programming methodology was in its infancy a rather vague and diffuse subject. More stress was certainly given to program correctness than to execution efficiency. In some minds this has created the impression that programming methodology did not care about efficiency, but this impression is wrong. In the sorry state of the art that could be observed in those days it was not the inefficiency that seemed most alarming: most alarming seemed that all sizeable programs seemed to be bug-ridden. Efficiency of computer programs had already been such a fashionable topic for so many years, that the balance seemed to need some redressing. When programming methodology first focused its attention on the problem of program correctness, it did so because many of us felt that that was a relevant concern that for too long a time had not received the attention it apparently deserved.

I called programming methodology in its infancy vague and diffuse. In spite of the fact that Naur [1], Floyd [2], and Hoare [3] had already published their articles, we used in the beginning hardly the cruel and uncompromising expression "proving the correctness of a program". For at least yet another year their articles stood on the shelf reserved for interesting academic exercises without much practical significance. It was the time when people could make four different programs for the same problem and then could ponder for hours or days on the question which of the four versions they liked best. That was an exploratory activity that encountered little appreciation and even evoked criticism. The practitioners —the programmers of "the real world"— could not see much significance in all those aesthetic exercises, the theoreticians —the mathematicians and logicians— saw no depth and, therefore, no significance in them either. The fact that, as an alternative to the quantifiable efficiency, we turned to aesthetic criteria has not without justification been qualified as an exaggerated preoccupation with "programming style".

Yet, all those experiments with little programs have not only been valuable, they were at that stage even necessary. Programming at that time was still an intuitive craft, and before the decision to adopt and to further develop a formal discipline can be taken, it should have been established with sufficient evidence that such a formal discipline is needed and that its further development is indeed worth the effort. And in order to prevent the formalization from becoming an end in itself, it should be sufficiently clear what it should achieve.

The exploratory stage, during which the notions of "simplicity" and "elegance" absorbed so much of our attention has had one very important effect. By the time that formal techniques became more generally adopted, we had, for "aesthetic reasons" stripped our programming vehicles, removing many of the usual bells and whistles whose presence would only have encumbered the formal treatment. The beauty of some of the programs we had discovered was an incentive to look for correctness proofs of comparable beauty and the circumstance that our most beautiful programs were often by all the usual standards also very efficient gave us the encouraging feeling that the whole exercise made sense.

In short I think that the infancy of programming methodology, with its stress on aesthetic criteria, has not been wasted. As craftsmen that to a certain extent had become artists as well, we had already developed into better intuitive programmers; at the same time the subject matter worthy of formal treatment had been filtered out. And, finally: the fact that we talked about "the beauty of a program" in very much the same way as in which mathematicians refer to "the beauty of a proof" provided an emotional link between two at that time rather disjoint cultures, a link that may very well have had a decisive influence.

*                    *
*

In the above I have tried to sketch the emotional and intellectual climate of the infancy of programming methodology. I have done so in the hope that it will assist you in getting some appreciation of the significance of its later achievements, an appreciation I would like to transmit to you without fully going into the technicalities that would take a full semester to cover.

We should remember that, when all this started, programs were almost exclusively considered from the point of view of what would happen when the program would be executed by a computer. It was only via the class of possible computations that could be evoked under control of a program that such a program could be appreciated. Textbooks on programming used to begin with a few chapters devoted to the description of the average computer architecture and the global characteristics of the machine's major components. Efforts at the formal definition of the semantics of programming languages were almost exclusively so-called "operational definitions", i.e. in terms of the properties of the possible computational histories. The quality of a program was very often equated to run-time efficiency, a notion which is, of course, highly implementation-dependent.

Yet, for progress it was necessary that the close tie to the process of program execution be loosened. One reason for this necessity was that as long as the tie was so close, characteristics of machines as they happened to exist, whether desirable or not, tended to pervade the thinking about programming: the way in which the properties of the IBM/360 had pervaded the design of PL/I was a warning not to be ignored. Another reason —although that one was perhaps discovered only later— was that program correctness and cost of execution are two so important concerns, that the programmer who has to give full attention to both of them, should be given the mental tools to separate these two concerns.

Two concurrent developments made it possible to loosen the tie between a program and the corresponding class of computational histories. I have already mentioned them both.

The one development consisted of the many, many programming experiments made during the infancy of programming methodology. As the problem of programming language design was one of the major incentives for these numerous programming experiments, many of these experiments were performed in tentative, unimplemented (and often yet incomplete) programming languages: the purpose of the experiments was very often to explore the consequences of a yet untried language feature. The fact that these experiments were mostly carried out in unimplemented languages loosened the tie between the programs and their executions. The other development was the discovery and application of the papers by Naur [1], Floyd [2], and Hoare [3], which dealt with the possibility of proving program correctness by means of a formal discipline. Such a formal discipline may have been inspired by what happens during program execution via a computer, by the time that the formal discipline is applied it can be used "in its own right" so to speak.

This second development was a necessary complement to the first one: it is all right to push the class of possible computational histories to the background of one's awareness, but this is only possible provided we have an alternative technique for coming to grips with what a program "means": Naur and Floyd gave a proof technique, Hoare was the one who stressed most clearly that these proof rules could be regarded as axioms. This was an important discovery: from now onwards the proof rules need no longer be regarded as summarizing properties of computers, but they could be regarded as axioms, as postulates, as a functional specification for computing engines that those engines had better satisfy if they were to be useful engines. The discovery was important for its psychological side-effect: while in the past it was regarded as the purpose of our programs to instruct our computers, a shift to the opposite view could now take place, viz. that it is the purpose of our machines to execute our programs. Or, to put it in another way, logic which up to that moment had mostly been a descriptive science, fraught with metaphysics, now also admitted to be regarded as a prescriptive science, almost as a discipline of engineering.

*                    *
*

The transition from the vague and emotional terms as "understandable", "clear", "readable" to the uncompromising and cruel notion of "a formal correctness proof" marks for Programming Methodology the transition from infancy to adolescence. It was a slow and sometimes painful process, like all processes of mental growth. From the people involved it required a greater agility in the propositional calculus and a greater familiarity with various induction patterns than most of them originally possessed. Younger computing scientists are free to laugh in either amazement or contempt, but I am not ashamed of confessing in public that five years ago, I was thoroughly familiar with the logical connectives "and" and "or" but certainly not with the implication, which I, therefore, tended to avoid, programming around it by replacing "a ⇒ b" by the more familiar "b or non a".

Besides this inherent cause that made the growth process a slow one, there was an external, and rather accidental one. Floyd's paper [2] was given greater publicity than Naur's earlier one [1]; we must conclude that Naur's paper was published ahead of its time. In contrast to Naur's paper that deals with programming, Floyd's paper has immediately been associated with mechanical verification —or even: discovery— of formal proofs of the correctness of programs. As a sad result, Programming Methodology has for quite some years been in danger of being killed in its youth by the superstition that underlies so much of the Artificial Intelligence activity, viz. that everything difficult is so boring that it had better be done mechanically.

I called the growth process, besides slow, also painful —like every adolescence, for that matter—. For some time during its adolescence, programming methodology indeed had a very difficult time. This was when the first correctness proofs started to circulate: some of them were, indeed, appalling, even distressingly so. I was repelled by them, and at one occasion I declared, full of disgust, with emphasis that such formal techniques "were not my cup of tea". Those present at that occasion take a special delight in reminding me of it. For some time it indeed looked as if formal correctness proofs were totally unfit for human design and for human consumption.

Thank goodness there were also a few beautiful programs with beautiful correctness proofs hanging around and, as a result, Programming Methodology survived its adolescence without committing suicide. The point is that those convincing examples were very inspiring because "length of formal correctness proof" was immediately accepted by all people involved as an objective and relevant yardstick for "quality". Its objectivity caused among those people a greater unity of purpose than eloquence or money could ever have achieved. This unity of purpose was so welcome that programming methodology survived its first disappointing experiences with formal correctness proofs, until it had been discovered that many of those early proofs, indeed, had been unnecessarily ugly and cumbersome.

*                    *
*

The first proofs were very cumbersome because, for lack of any theorems, they were built upon the axioms themselves. In the meantime a few general, but very powerful and useful theorems have been discovered and proved, and we have gained much experience in their effective exploitation.

A second cause for improvement was the discovery that the existence of such theorems and the ease with which they are formulated and used depends on the programming language used. The combinatorial freedom of the flowchart language that was used by Floyd in his fundamental article [2] creates problems with the satisfactory solution of which people are still struggling today [4]; by adhering to a more strict sequencing discipline, these problems can be made to disappear.

A third cause for improvement was the discovery —in retrospect not very surprising— that besides a formal theory about one's programming language and its constructs, one also needs a certain amount of formal theory about the subject matter of the computation. For instance: while proving the correctness of a parser it is not enough to have axioms about the relevant programming language constructs such as the operations on strings. Besides those one needs a certain amount of theory about sentences generated according to, say, a BNF-grammar; one may even be expected to need some theorems about the specific grammar of the language in question. In the beginning we often did not clearly separate those two different aspects of our proof obligations, thus confusing the issue.

A fourth improvement was perhaps the most spectacular. For many years the whole correctness issue had been posed in the following form "Given a program and given the specifications of what its execution should achieve, can you prove that the program meets these specifications?" The attention was thus focused on "a posteriori" verification of given programs. It was then observed, however, that for different programs meeting the same specifications, the corresponding correctness proofs could greatly differ in complexity! And as a result, our picture of the programmer's task changed: it was no longer sufficient to design a correct program, in addition the program should be designed in such a way that its correctness could, indeed, be established. The simplicity of the corresponding correctness proof became thus an important aspect of program quality. But when this message was taken to heart, the programmer's task and his way of working changed radically. For, how does one develop a program that admits a nice correctness proof? Well, by developing the program and its correctness proof hand in hand. In actual fact the correctness proof is often even developed slightly ahead of the actual program text: as soon as the next step in the correctness proof has been chosen, the next refinement of the program is made in such a way that the chosen step in the correctness proof is applicable to it. Instead of seeking for a proof to go with a given program, we now construct a program to go with a chosen correctness proof! The later construction process is so well understood that we are now entitled to talk about a calculus for the formal derivation of programs [5].

Let me repeat. We are trying to find a "matching pair", consisting of a program and a proof and "matching" in the sense that the proof establishes that the programs meets its specifications. Given a program, finding a matching proof may be very hard; given a proof, finding a matching program is almost trivial. This is not the place to ponder about a mathematical or psychological explanation of this phenomenon. I have repeated and described the phenomenon in other words because of its drastic social impact. Here I use the term "drastic social impact" because it is bound to cause a change in a traditional division of labour.

*                    *
*

Ten years ago, before the above had been understood, a tradition of "software production" had already established itself. It was regarded as the programmer's task "to produce programs", and the management of "software production" was organized under that assumption in close analogy to more traditional production processes such as those of cars, TV-sets or washing machines. This view of "software production" has had a few severe consequences.

In analogy to the production line worker, for "programmer productivity" the measure "number of lines of code produced per month" became among managers accepted. Doubts about its adequacy and significance have been voiced. It has been remarked that the adoption of this measure of programmer productivity is certain to encourage the production of insipid code. It has also been remarked that "code" is no end in itself, but only a means, and that rather than talking about the lines of code "produced" we should refer to the lines of code "used", and that, therefore, this "productivity measure" books the number of lines on the wrong side of the ledger. But large organizations have a great inertia, and the number of lines of code "produced", no matter how inadequate, is still in use as a grading criterion for programmers.

In analogy to the production line, software managers have tried to reduce software production costs by resorting to cheaper labour, which, in each given environment, means less educated people. The results of these tactics are only too well known.

In analogy to the production line, completely independent groups for "quality assurance" have been installed: the people from "quality assurance" had to certify the software "products". Little it was understood, however, how impossible their task was. They could hardly do any better than to "certify" after the successful run of a set of test cases, no matter how inadequate they were for "certification". Also the results of this are only too well known.

So much for the traditional division of labour in the process of software production. This tradition has to be broken because it is based on a false assumption. The tradition will be broken because the modern way of developing programs is so dramatically more effective. In future we shall see in retrospect that today's traditional way of software production was the result when a craft was applied, where a scientific discipline was needed.

*                    *
*

In the last decade programming has made the transition from craft to scientific discipline. It has been a development not unlike the one that took place in medieval painting in Europe. Before the discovery of the relevant rules of projective geometry, painters had only intuitive ideas about perspective. It was the old and experienced craftsman-painter who, on the average, was most successful in rendering the proportions well. But each new painting was in this respect an experiment that involved a certain risk, and, whenever a craftsman-painter had been exceptionally lucky, he had created a work of art that would become famous for its geometrical perfection. But within a few decades the old craftsmen had been superseded by a next generation of painters, mostly pupils of a certain Albrecht Dürer; these youngsters just knew the rules of perspective and produced without risk and with absolute confidence in this respect perfect paintings. Not only that they could do it, they knew that they could do it, they knew how they did it and could teach it to their successors. A next area of human endeavour had shown itself to be amenable to mathematical treatment, and a craft had been replaced by a scientific discipline. But whenever a craft is replaced by a scientific discipline, the old members of the guild feel themselves threatened, and quite understandably so.

I used the term "drastic social impact" because today's "programming guild" encompasses —depending on how we count— between 500.000 and 1.000.000 people, for the majority of whom it is totally unrealistic to expect that they can still acquire a scientific attitude. For them the recent developments in programming poses a serious problem, and their existence presents a serious barrier to the more wide-spread adoption of the newer programming techniques. In view of these conflicts it is very hard to predict how, when, and where the old programming tradition will be broken first. I shall just give you a few observations and leave the extrapolation to you.

When in 1968 the software crisis was for the first time openly admitted, a quite well-known professor of computing science waved the idea of correctness proofs away as being "idyllic", to another one the idea of correctness proofs caused "mental hiccups" [6].

As late as 1972, the suggestion that programming was so difficult that it deserved scientifically educated programmers has been waved away: with a reference to the then current intellectual calibre of "the average programmer" the suggestion was waved away as obvious nonsense.

Three years later, however, an International Conference on Software Reliability, where formal techniques played a predominant role, was held at Los Angeles and attended by about a thousand people.

Another year later, in 1976, a draft proposal for an advice to the U.S. government draws attention to the for them alarming circumstance that "by an accident of history, the United States has more inertia (and local vested interests) in current software practices than the rest of the world." It points out the danger for the USA that in the practice of software development they will be overtaken by nations that in this respect are yet more flexible.

So much for my few observations: I gladly leave to you to guess the how, the when, and the where of the breakthrough.

*                    *
*

The conclusion that successful computer programming will eventually require a reasonable amount of scientific education of a rather mathematical nature is not too welcome among the guildmembers: they tend to deny it and to create a climate in which "bringing the computer back to the ordinary man" is accepted as a laudable goal, and in which the feasibility of doing so is postulated, rather than argued. (This is understandable, because its infeasibility is much easier to argue.) They create a climate in which funds are available for all sorts of artificial intelligence projects in which it is proposed that the machine will take over all the difficult stuff so that the user can remain uneducated. I must warn you not to interpret the fact that such projects are sponsored as an indication that they make sense: the fact of their being sponsored is more indicative for the political climate in which this happens.

I am convinced that all these projects will fail, and that, the more ambitious they are, the more miserably they will do so. Hence I consider these projects as rather foolish, and for programming as a scientific discipline worth teaching, as rather harmless rearguard actions. As a bit pathetic, even.

In the meantime these projects can still do a lot of harm. They can do so by their false promises, pretending that the sophistication of their future systems, combined with decreasing hardware costs, makes it economically attractive to forsake our educational obligations to the next generation. Needless to say, falling into that seductive trap would be the cultural blunder of the decade.

In another respect I sometimes fear that the harm has already been done. There is a wide-spread folklore that in particular correctness proofs for computer programs are intrinsically so long, tedious, boring, uninteresting and prone to error, that the mechanization of their verification is a must. The assumption, however, is wrong: correctness proofs for programs can be —and should be!— just as beautiful, fascinating and convincing as any other piece of mathematics. But the rumour to the contrary is constantly spread by the advertizing campaigns for the mechanical verification systems. The fact that the most outstanding feature of most artificial intelligence projects seems to be the heavy advertizing campaigns deemed necessary for their support, should instill into our minds a healthy mistrust and suspicion.

[1] Naur, P., "Proof of Algorithms by General Snapshots", BIT 6 (1966), pp. 310‒316.

[2] Floyd, R.W., "Assigning Meanings to Programs", Proceedings of a Symposium in Applied Mathematics 19 (ed. Schwartz, J.T.), Providence, Rhode Island: American Mathematical Society, 1967, pp. 19–31.

[3] Hoare, C.A.R., "An Axiomatic Basis for Computer Programming", Comm. ACM 12, 10 (Oct. 1969), pp. 576–583.

[4] Manna, Zohar and Waldinger, Richard J., "Is "sometime" sometimes better than "always"? Intermittent assertions in proving program correctness." Stanford Artificial Intelligence Laboratory Memo AIM–281 / Computer Science Department Report No. STAN-CS-76-558, June 1976.

[5] Dijkstra, Edsger W., "Guarded Commands, Nondeterminacy and Formal Derivation of Programs" Comm. ACM 18, 8 (Aug. 1975), pp. 453–457.

[6] Naur, P. and Randell, B., "Software Engineering", Report on a Conference Sponsored by the NATO Science Committee, January 1969.

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Jose Alejandro Ruiz Delgado
revised Mon, 25 Aug 2008

EWD567

Twaalfde toespraak tot mijn studenten, voorjaar 1976.

Als onderdanen van twee verschillende naties met elkaar trouwen, zitten zij als echtpaar op rozen, zolang deze twee naties vriendschappelijke betrekkingen onderhouden: zolang hebben zij immers twee vaderlanden. Zodra deze twee naties elkaar evenwel de oorlog verklaren, verliest zo'n echtpaar beide vaderlanden. Eet zo'n echtpaar in vredestijd van twee walletjes, in oorlogstijd komt het tussen wal en schil terecht. Zo'n gespreide loyaliteit ervaar ik in mijn eentje sinds ik zonder de academische wereld vaarwel gezegd te hebben naar het bedrijfsleven ben overgegaan, of, zoals sommigen preferen te zeggen "ben overgelopen", een woordkeus die de sluimerende gevoeligheden duidelijker dan wat ook aangeeft. U begrijpt dat ik uit persoonlijke betrokkenheid de relatie tussen de academische wereld en de zakenwereld nauwlettendsr gadesla dan ik zonder dat al gedaan zou hebben. Mijn observaties zijn niet geruststellend en van mijn bezorgdheid wil ik U deelgenoot maken. Ter vermijding van misverstanden moge ik benadrukken dat noch mijn observatie, noch mijn zorg zich tot de Nederlandse situatie beperkt.

In alle landen, die ik zie —ongeacht of hun staatsvorm nu democratisch is of alleen maar zo genoemd wordt— observeer ik een groeiend centralisme, dat gepaard gaat met een versmalling van het spectrum der doelstellingen, die nog nastrevenswaard geacht worden, observeer ik een verschralende intolerantie die mij, meer dan enige andere oorzaak, aan de wortel van de problemen met de werkgelegenheid lijkt te liggen. Het hoeft nauwelijks verwondering te wekken, dat in dit prevalerend klimaat, waarin het ogenschijnlijk ongebonden "Abenteuer des Geistes" maar al te gauw als hobbyisme wordt afgedaan, de universitaire wereld niet goed gedijt. Tot mijn droefenis constateer ik, dat het huidige aureool der doelgerichtheid maar al te vaak de universiteit ertoe verleidt om, zij het mokkend, naar het geven van beroepsopleidingen over te schakelen. De universiteit doet dit mokkend, omdat zij niet echt gelooft in zulke beroepsopleidingen, die zozeer indruisen tegen haar traditie. Dit ongeloof is zowel oorzaak als gevolg van een karikaturaal beeld van "de behoeften van het bedrijfsleven", dat tegenwoordig in de universitaire wereld opgeld doet. Zo kon ik onlangs de opmerking horen, dat wij wel moesten oppassen het wetenschappelijk aspect in de informaticaopleiding niet te zeer tot zijn recht te laten komen, omdat onze afgestudeerden dan de kans liepen bij hun sollicitatie te bemerken dat "het bedrijfsleven liever een HBO-man nam". Ik vond dit een angstaanjagend symptoom van het geschokt vertrouwen in de taak van het wetenschappelijk onderwijs, dat proberen moet mensen op te leiden, die stuk voor stuk tot dingen in staat zijn, die nog geen wagonlading HBO-abiturienten ooit voor elkaar zullen krijgen. Ik vond het ook een angstaanjagende onderschatting van de behoeften van het bedrijfsleven en de aldaar vigerende visie daarop.

Audiatur et altera pars! Vindt het bedrijfsleven dat de wetenschappelijke vorming aan de universiteiten teveel nadruk krijgt? Omdat in de Verenigde Staten de Departments of Computing Science een meer uitgesproken instituut zijn dan bij ons, heb ik eens gepolst bij een Amerikaanse firma waarvan je wegens zijn werkterrein verwachten kon, dat hij een vast afnemer van "Computing Science Graduates" zou zijn. Het antwoord was onthullend. Voor Bachelors en Masters in Computing Science hadden ze niet de minste belangstelling, bij de Ph.D's was wel eens een goeie. Ze hadden veel gunstigere ervaringen met gewone wiskundigen, want die hadden zich tenminste een solide wetenschappelijke habitus eigen gemaakt. En in Nederland? Van meer dan ��n buitenuniversitair instituut heb ik de wanhoopskreet vernomen, dat uit de jonge academici, die de laatste tien jaar zijn aangenomen, de nieuwe generatie leiders en gangmakers maar niet tevoorschijn wil komen, en dat bij de sollicitanten, die nu de revue passeren, het kaliber waarnaar ze zo naarstig zoeken, nauwelijks voorkomt. En men vreest het ergste voor de levensvatbaarheid van deze instituten tegen de tijd, dat de oudere generatie, waar zij nu nog op drijven, zal afvloeien.....

En hier heb je ten voeten uit de kiem van het misverstand, dat maar al te gauw tot verwijdering, zo niet tot oorlogsverklaring leidt. De niet-universitaire wereld is teleurgesteld in de kwaliteit van de universitaire abiturienten en maakt zich ernstige zorgen over de gevolgen van dit kwaliteitsverlies. Op de universiteit wordt van overheidswege een sterke pressie tot verdere onderwijsverwatering uitgeoefend, en klem in de financiele tang van die overheid, draait de universiteit zich om der wille van eigen gemoedsrust een rad voor de ogen en sust zij haar knagend geweten met de leugen, dat de wereld om haar heen met minder goed opgeleiden minstens zo goed uit de voeten komt. Quod non, maar de struisvogels zien dit niet, Sterker: wanneer in het recente verleden allerlei van onze afgestudeerden toch nog redelijk zijn opgevangen, sust zij haar geweten met "Ze zijn toch grotendeels nog aardig terechtgekomen! Dus het gaat zo toch ook...." Ja, nog een tijdje, maar we zijn wel op onze voorraad goedgetraind intellect aan het interen, en als straks de bodem van deze schatkist in zicht is, wat dan?

Ik ben verre van gerust. Als de bodem in zicht komt en wat er nog aan oudere, "echte" academici over is een steeds centralere rol gaat innemen, omdat de jonge garde helaas de competentie ontbreekt om hun rol over te nemen, zou er dan bij die jonge garde niet een gevoel van bedrogen te zijn ontstaan? Je kunt ze nauwelijks ongelijk geven. Maar een bedrogen, afgescheepte generatie is wel een zaaibed voor afgunst en wrok, en niemand moet zich verbazen als een gefrustreerde jonge garde zich een rode garde gaat noemen, zolang we ons maar niet wijsmaken, dat technische incompetentie door kleursverandering kan worden gecompenseerd.

Overigens ben ik van oordeel, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

  EWD 568

Copyright Notice

The manuscript

EWD568: A programmer's early memories

was published as pages 563-573 of

N. Metropolis, J. Howlett, and Gian-Carlo Rota, eds., A History of
Computing in the Twentieth Century: a Collection of Essays.
Academic Press, New York, 1980.

It is reproduced here by permission of the publisher and holder of
copyright in the work, Academic Press.

A programmer's early memories.

               Edsger W.Dijkstra

(Text, prepared for the International Research Conference on the History of Computing, June 10 - 15, 1976, Los Alamos.)

Not being a trained historian, I assume myself unable to conduct an objective historical study. Therefore I shall not even pretend objectivity in any sense: I intend to record from my personal memory what seems relevant or typical to me, leaving it to the professional historian to sort this out, and to select and to ignore in accordance with his professional standards.

In September 1951 I attended as a private person in Cambridge, England, the Summer School that, one year earlier, had been attended by A.van Wijngaarden, then the Head of the Computation Department of the Mathematical Center in Amsterdam. In connection with a letter of recommendation that I needed for a government grant of f200,— (then $50,—) in support of that trip, I met van Wijngaarden during the summer of '51. Being asked what I had done I showed him two recent discoveries, one being a nomographic technique for finding the one real root of a special class of n-th degree equations that I had encountered, the other being a technique for converting from decimal to octal with a mechanical desk calculator. On the strength of that he offered me a job as a programmer before I had left him; as a consequence of other commitments I had to wait until the end of March '52 before I could accept his offer.

When I started work at the Mathematical Center I found there B.J.Loopstra and C.S.Scholten, continuously rebuilding a relay machine called the ARRA. Most of '47, van Wijngaarden had been abroad studying in the U.S.A. and the U.K.; during a short stay in Amsterdam, however, he had attracted Loopstra and Scholten, who joined the Mathematical Center on the 1st of August '47.

None of us were formally trained as mathematicians. Van Wijngaarden was officially a graduate of mechanical engineering, but in the meantime one with extensive experience in numerical work; Loopstra and Scholten were supposed to study experimental physics at the University of Amsterdam and I still studied theoretical physics in Leiden. Our common background was that we came from two of the most famous secondary schools of the country, van Wijngaarden and I from the Gymnasium Erasmianum, and Loopstra and Scholten from the Vossius Gymnasium. I mention this because I firmly believe that that background, which included a solid training in five foreign languages, has had a great influence on the way which we worked. (Such a binding element was very welcome, for in other cultural aspects we diverge widely: measured by my mildly conservative standards, the other three were at that time radicals on the verge of anarchy, and Scholten, a capable pianist, could even stand the music of certain modern composers!)

Concurrently with the early developments at the Mathematical Center in Amsterdam, in the Hague, and later Delft, W.L.van der Poel developed first the PTERA and then the ZEBRA, but although the distance between Amsterdam and the Hague is negligible, there was surprisingly little contact between these two groups, all the more surprising because in those post-war years of extreme poverty and general shortage of everything one could raise the question whether for such a small country two mutually independent efforts at computer development was not a little bit too much. The lacking contact can partly be explained by a difference in background: van der Poel came from a different type of secondary school, he spoke and wrote a different kind of Dutch and communication was, indeed, difficult.

When I joined the Mathematical Center in March '52, the ARRA was believed to approach completion. It was a binary relay computer with a word-length of 30 bits. The fixed-point arithmetic unit that contained the usual two 30-bit registers had been completed first; with a small relay memory it had been driven for some time via uniselectors from a plugboard. In '51 the uniselectors and the relay memory had been replaced by a 1024-word drum. It had an instruction code of 16 instructions, among which two for multiplication and two for division —i.e. both with and without rounding—. The conversion from binary to decimal representation was built in; the single type instruction that caused a number to be typed was further controlled by a 30-bit code word that specified the layout. Programs were stored with one instruction per word, viz. in the least significant half. The most significant halves of the first 64 words that contained the standard input program were used in such a way as to present the code words for all possible number formats.

The machine, however, was so unreliable as to be practically useless. It was officially put into operation with all the pomp and circumstance that was deemed necessary; for the demonstration program that it had to execute at that exciting moment, for safety's sake the printing of a table of random numbers had been chosen, and as far as I can remember that has been the most ambitious program that, in spite of valiant efforts, it has ever executed successfully.

In late '52 what was euphemistically called "a major revision" was decided. As a matter of fact, a totally new, this time largely electronic, machine was built, that had only the word length and the name ARRA in common with the previous effort. For the purpose of this discussion i shall refer to it as ARRA II. On the 1st of November '52, Loopstra and Scholten were joined by G.A.Blaauw, who came from Howard H.Aiken's Laboratory in Harvard. Whereas the old relay machine had worked with "operation complete signals", Blaauw introduced the clocked machine; besides that he introduced selenium diodes, proper documentation techniques, and plug connections so that faulty units could be replaced. Blaauw's competence, his technical input and his devotion to the job at hand were highly appreciated. It was not surprising, however, that, a few years later, he would leave us again: in the irreverent, godless society we formed, the devout Christian Blaauw did not fit too naturally.

Design, development and construction of ARRA II took 13 months: in December '53 it performed its first programs and for the next two-and-a-half years, until medio '56, it has been in continuous use. It, too, had the familiar two-register, fixed point serial arithmetic unit, a store of 1024 words, eventually divided over 32 tracks of 32 words each, with two instructions stored in each word. Simple additions were performed in (slightly over) one drum revolution of 20ms, multiplications and divisions too (slightly over) five drum revolutions. It had a nice symmetric instruction code of 25 instructions, with six instructions involving the A-register only:

(A):= (A) + (n)

(A):= (a) - (n)

(A):= (n)

(A):= -(n)

(n):= (A)

(n):= -(A)

and a similar set for the S-register. Only in multiplications, divisions, and double-register shifts these two registers were treated on different footing. Conditional jumps were conditional on the sign of the last number written into store, conversion was no longer a special instruction, two fast multiplications by 10 were provided instead.

Its functional description (Report MR12, 1953) was the first report I produced as employee of the Mathematical Center. The first sentence states that the ARRA II is an automatic digital computer. The second sentence is worth quoting. Its English translation is:

"In the sequel this machine will be described as far as is relevant for the person that uses the machine: we shall describe what the machine does, and not how the machine works." (Underlining as in the original Dutch text.)

and the sequel indeed defines the net effect of each instruction without any reference to the internal mechanisms accomplishing it. In retrospect I think it highly significant and telling that I felt called to introduce my text in that fashion, underlinings included. It is surprisingly modern when we compare it with the following quotation —alternatively we may conclude that progress is, indeed, very slow!— from Niklaus Wirth, "Programming languages: what to demand and how to assess them", March 1976(!):

"Hence, we must conclude that the first criterion that any future programming language must satisfy, and that prospective customers must ask for, is a complete definition without reference to compiler or computer." (Underlining, again, as in the original.)

Wirth stresses the profound difference between a language (definition) and its implementation, and urges programmers to distinguish clearly between the two — in exactly the same way as the functional description of the ARRA II sharply distinguished between the instruction code and its "implementation", i.e. the machine that could obey it.

For me, the second sentence has a deep psychological significance: the nonoperational definition of semantics of each single instruction provided the impenetrable interface that I needed between me as an emerging programmer on the one hand, and the machine builders Loopstra, Scholten and Blaauw on the other. And that sentence's inclusion at that predominant place in the report strongly suggests that in that environment at that moment in time, such explicit separation between abstract specification and physical realization was a novel idea, something that is not surprising when we see that 23 years later Wirth has still to argue the very same point at the next level of language. Another indication of some novelty is that, nearly before the stencil ink was dry, this report was nicknamed "The Appalling Prose". It was written with the thoroughness of a legal document, and my hardware friends teased me with it, also because I needed a lot of teasing in those days. (But it only needed revision when they changed the machine!)

The machine had a double selection, one for instructions and one for numbers. The motivation for that was two-fold. Firstly, by disconnecting the number selection from the first two tracks, the standard input program could be protected from inadvertent overwriting. Secondly, track selection was the only place in which relays had not been thrown out and, as a result, a track change in one of the selections caused an additional delay of one or two revolutions; by doubling the selection the number of track changes could be reduced. This reduction was not as effective as hoped: note that the machine had no B-register and it had, therefore, to change its instructions in store. The replacement by a more reliable and faster electronic track selection was the first major improvement of the machine. A further improvement in reliability was obtained by replacing the selenium components by germanium diodes.

After about half a year of usage the original standard input program contained in two protected tracks is replaced in '54 by a standard input/output program occupying five tracks. The change is significant. Clearly reliability problems had plagued us. The original input program would assemble words from paper tape and store them on consecutive locations, the address of the first location to be filled being given by a leading control combination on the tape. In the second version this control combination had to be punched twice and the input program checked in addition each time a word had been stored that the address of the store instruction had been correctly increased by one. Besides that, such a piece of paper tape could be read in two modes, either storing or comparing for checking purposes.

The output took place via an electric typewriter of which 16 keys could be operated by means of magnets. The decoding tree selecting the proper magnet was built with relays that retained their position until the next typewriter instruction was given, and in between, a special "echo-instruction" could read back into the machine the number of the last selected magnet. Short of actually reading the typed page, this was the most complete check of the output operation that could be envisaged. I designed a very ingenious process —of which I was therefore very proud— in which the conversions from binary to decimal and the conversion back from the decimal echos to the original binary were merged to the extent that they shared the same multiplication by 10. This rigorous total check on both conversions and the actual magnet selection became standard practice on ARRA II, and its next three successors, and was only abandoned when the lineprinter hardware did not provide anymore for echo reading. In case of a discrepancy, the machine would type the number again in the same position of the next line.

Today such precautions may seem exaggerated. But in the preface of a 200-page table of interpolation coefficients, published in May '55, van Wijngaarden and I proudly stated:

"The whole table has been produced by the electronic computer ARRA. The program included complete mathematical checks including the signals sent out to the typewriter. The sheets are reproduced by photo-offset."

I think our pride was justified —the only error ever found was in the hand-typed preface!—. This was indeed an achievement with a machine whose major shortcoming was that its not too reliable drum memory was not protected by a parity check. It is, by the way, a sobering thought that practically no computer today could produce those master sheets with the same trustworthiness and printing quality. So much for progress.....

The machine was in continuous use; during the night, often unattended for long periods, it worked on a very time-consuming project of integrating wave equations for research in theoretical chemistry. In order to increase the probability of useful work in spite of an unreliable memory, I rewrote with Scholten that program entirely. The operation "x:= x + 1" was originally coded —in modern notation— as:

A:= x; A:= A + 1; x := A     ;

we replaced it by:

repeat A:= x; A:= A + 1; y:= A;
       A := -x; A:= A + y; A := A - 1 until A = 0;
repeat A:= y; x:= A; A:= -y; A:= A + x until A = 0

I mainly remember that night because, as the hours went by, much to Scholten's amusement I got more and more cross with that program's original author, hurt as I was by all its clumsiness. Scholten and Loopstra, who also acted as maintenance engineers for the machine, were grateful: the transformation was highly effective and from then onwards they hardly received any calls for service at night.

The first half year of ARRA II's operations, it builders were still busy improving it. Then in May '54, a contract with Fokker, our national aircraft industry, was signed to deliver to Fokker the FERTA, an improved version of ARRA II. Apart from more elaborate shift instructions it was basically the same machine. Seven months later, in December '54, the FERTA performed its first test computations; it was delivered on the 1st of April next year, less than a year after the contract had been signed.

The Fokker plant, where the FERTA was installed, was not too easily reached. Blaauw and I did the debugging of the hardware during the winter of 54/55. Blaauw, who had been in the U.S.A., was rich enough to have a car, at least some sort of car: in an n-th hand Standard Vanguard he would drive from the Hague, where he lived at the time, to Fokker near Schiphol. I lived as a student in Leiden, and would leave my room at seven o'clock in the morning and cycle towards the highway, where I would hide my bicycle and climb up to the road where Blaauw would pick me up. It was a grim winter, but the combination of an old Canadian army coat and the fact that Blaauw was a punctual man made this possible. One night, at say half past ten, when we wished to return, the old Vanguard, the last car on Fokker's otherwise deserted car parking lot, refused to be started. I do remember that it had started snowing, I don't remember how we came home: presumably Blaauw himself fixed another bug that day.

It is sometimes hard to remember how poor we were in those days. When I entered the service of the Mathematical Center at the age of 21 with the best possible credentials, my salary was f 11,— (about $3,—) a day. Three years later, when the FERTA was transferred to Fokker, the successful transaction was concluded with a dinner with the directors of Fokker's Aircraft Industry, I shall never forget the main course, chicken boned by the waiter at our table with a knife and fork. And I shall remember the regret with which I saw so much perfect chicken meat returned to the kitchen: in those days I was not only poor, I was hungry. But, somehow, we did not seem to mind: we worked like mad, we were never in doubt about the immediate usefulness of our work, lived in a state of continuous excitement and had a tremendous amount of fun.

In retrospect the ARRA II with which I worked for nearly two-and-a-half years was an ideal machine for getting introduced to the subject. We wrote all the usual things like floating point and multilength routines for elementary functions and what not. Its decent order code and its slow but fairly homogeneous store was an incentive to do a nice job. Its limited size and speed saved us from overambitious projects and its unreliability was a sobering reminder.

I must mention a demonstration program I wrote for it at the occasion of the International Mathematical Congress that was held in Amsterdam in 1954. It faked the ability "to learn to type a digit": after each digit typed the environment had to signal whether the machine had typed "the desired digit" or not. If, for instance, a "3" had been chosen as desired digit, it would eventually type almost always a three. It was then possible to withhold the "appreciation": gradually the threes would be replaced by other digits. It was a simple one-page program concocted within an hour; it generated pseudo-random numbers and had a few thresholds determining the speeds of "learning" and "forgetting" and the frequency of "errors". During its exhibition I got alarmed by the enthusiasm it evoked among the impressed visitors who were misled to believe that we were seriously simulating learning processes. Eventually I tried to explain that we were only faking, but I was not very successful, because their enthusiasm had carried our visitors too far away: it was a frightening experience....

*            *
*

By the end of June '56, fifteen months after the delivery of the FERTA, Loopstra and Scholten had completed their next machine, the ARMAC, a new machine for which I had written again the functional description, designed the program notation and written the basic communication programs. For the third time the entire road from conception to a fully documented and working machine had been covered in less than one-and-a-half year. Clearly we were getting experienced!

In view of our previous equipment the ARMAC was an exciting monstrum. It was exciting because on certain computations it could be 50 times as fast as the ARRA II, which was instantaneously dismantled when the ARMAC was put into operation. Personally I remember the awe with which we looked at it when it performed its first production program, a computation of transversational movements of railway carriages. Another reason for remembering the occasion was that the program had been written by M.C.Debets, bound to become Mrs.Dijkstra a year later. The word length of the ARMAC was 34 bits, two instructions per word and an instruction code of 30 instructions. Its main store consisted of a drum of 112 tracks of 32 words. The first 512 words of store were intended to be realized by ferrite cores; eventually this was only effectuated for the first 32, the so-called "fast page". Besides the fast page the machine was equipped with a 32-word ferrite core buffer: as soon as control switched to a new drum track, the computation came to a grinding halt for the duration of the revolution of the drum (which rotated at a speed of 75 revolutions per second), during which the new track was copied into the high-speed buffer, and from then onwards instruction fetch was again instantaneous. The device —a one-page virtual memory avant la lettre— was extremely effective. It was also very tricky: the machine had still no B-register and, therefore, had to modify instructions in store; to save time it had special instructions modifying only the copy in the buffer. Needless to say, a full description of that wonderful feature, complete with warnings for all the pitfalls occupied several pages of the manual. It was a time when all standard routines were elaborately polished until they fitted exactly on a single 32-word page. The ARMAC had a parity check on the memory and, as far as speed and reliability were concerned, it was a great improvement over its predecessor. The fact that the programmer had to be highly conscious of the existence of the individual tracks was a step backwards; the high penalty of buffer refilling furthermore made many more advanced programming techniques, although logically possible, efficiency-wise too unattractive to be considered seriously. Auto-coders and compilers were clearly out of the question. In retrospect this has been a blessing: it forced us to skip the stage of infancy of what was then called "automatic programming", and when we got our next machine, the EL-X1, we could approach the problem of compiling ALGOL 60 without the burden of misleading experiences.

As far as programming was concerned, the ARMAC period was one of consolidation of our practice of running the Computation Department. The manual, for instance, states as one of the strict rules of the house that each program should be "restartable", i.e. without the need for reading it in another time: no more saving a few instructions by means of initializing some locations during program input.

*            *
*

I recall from that time one failure on my side which is indicative for the progress of the art of programming that would materialize during the next decades. Let in N successive storage locations be given a permutation of the numbers from 1 through N, which is not the alphabetically last one; it is then asked to write a program that will transform that permutation into its immediate alphabetical successor. I remember that I tried to solve this problem for more than two hours and then gave up! In the early seventies, when I needed a simple example for an introductory programming course, I suddenly remembered that problem and solved it without pencil and paper in twenty minutes, and —what is more— I did not need more than twenty minutes to explain my solution next morning to my novice audience! I myself was very impressed by this palpable proof of progress and tried to drive home that message by faithfully reporting my failure of some sixteen years earlier. (They were not impressed: they concluded that if I had not been able to solve the problem, I could not have been a very bright student.) But I remember my failure so well, that I still know how I failed. I was thinking in terms of individual instructions, some of them being jumps: I programmed without sequencing discipline and had not the syntactical grasp provided by the repetition clause. I did not even know what a loop was, I only knew that as a result of jumping around, instructions could be executed many times. To add to the confusion I was mentally coding for a machine that, for lack of a B-register, had to modify its own instructions in store, thereby blurring the difference between the constant program and the variables. In view of our primitive way of thinking about the programming task it is in a sense a marvel that in spite of it we still designed so many nontrivial programs.

*            *
*

Three months after the completion of the ARMAC, in September 1956 the specifications for a next machine, the EL-X1, were drafted. Its detailed design was ready by the end of the year, and another year later, at the end of '57, the prototype X1 performed its first computations. Again, in less than eighteen months. The EL-X1 was really exciting. It was a fully transistorized machine that would have ferrite cores as its main memory, and it was ten times as fast as the ARMAC.

This time the design and production of the standard input/output program was a totally new challenge, and it was so for two reasons. The one reason was that the hardware required the standard input/putout program to be wired in. I designed the program as carefully as I could, paid equal care to the ARMAC program that was used to derive from my hand-punched version the paper tapes that were going to control the semi-automatic wiring machine. It was the first time in my life that a considerable investment was made in the hard-wiring of a 25.000 bit program that I had been unable to test. I am grateful for the experience, as it taught me that the flawless production of such a program is not a superhuman task. The other reason was that, following a suggestion from A.W.Dek, the X1 was equipped with a real-time interrupt signalling the completion of I/O commands. When this was first suggested it frightened the wits out of me as soon as I realized that it would make the machine a nondeterministic one without reproducible behaviour, and I managed to delay by my fear the final decision to incorporate the interrupt for a few months. Eventually I was flattered out of my resistance, and this double inability to test my program before it went into "production" gave a new flavour to the task.

I remember my first contribution: when trying to design the status saving and status restoring protocol in such a way that I could prove its correctness, I discovered that with the proposed means for enabling and disabling the interrupt it was impossible for me to do so. After Loopstra and Scholten had checked my argument, that part of the instruction code was changed in accordance with my recommendations.

After that programming task had been completed in early 1958, I did not program for a while. I was absorbed by writing my thesis on that last effort, translating my thesis from Dutch to English and, besides that, the running of the Computation Department took more of my time, due to temporary absence of its director who had a serious road accident. Preliminary discussions, based on ALGOL 58 and eventually leading to ALGOL 60 were started. Besides that, it would last until March '60, until the Mathematical Center would get its copy of the EL-X1, the first copies being granted to more impatient customers.

On the 28th of October '59 I defended my Thesis, with A.van Wijngaarden acting as my Promotor. Four days later, on the 1st of November we started the discussion on how to implement ALGOL 60, of which the final definition reached us in January 1960. Harry D.Huskey had just spent a few sabbatical months at the Mathematical Center, working on an algebraic compiler, but his style of working differed so radically from mine that, personally, I could not even use his work as source of inspiration; the somewhat painful discussion with my boss, when I had to transmit to him that disappointing message, is remembered as one of the rare occasions at which I banged my fist on the table. During my '59 summer holiday at Paterswolde I had given my first thoughts to the question how to implement recursion, in the early months of '60 we discovered how to do, in combination with that, justice to the scope rules of ALGOL 60. After the interface with the run time system had been decided, J.A.Zonneveld and I wrote the compiler, while Marlene Römgens and Fiek Christen wrote under my supervision the routines of the run time system. In March the machine arrived and in August our implementation was operational. Our first testcase had been something like "begin real a; a:= 7 end"; our fourth testcase had been a recursive summation procedure, via the call-by-name mechanism and Jensen's device called to perform a double summation. The combination of no prior experience to compiler writing and a new machine without established ways of usage greatly assisted us in approaching the problem of implementing ALGOL with a fresh mind.

*            *
*

Our implementation of ALGOL 60 marks the end of the period of growth that I intended to cover, it also marked the beginning of a new one. Finally I was beginning to consider myself as a professional programmer, and, thanks to the beard I grew during the ALGOL 60 project, I was even beginning to look like one. It marked the beginning of the period during which the programming activity would begin to evolve from a craft to a scientific discipline. I December '60 I bought my first car, a Volkswagen I could barely afford. I had a wife, one-and-a-half child, a telephone, a piano and a car: the son, whose wanderings had sometimes worried his parents, showed at last the symptoms of a respectable cit
izen.

NUENEN, 24th May 1976 The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 13 Nov 2006

EWD569

Dertiende en laatste toespraak tot mijn studenten, voorjaar 1976.

Omdat ik in het vijfde jaar geen colleges geef, wordt dit de laatste keer dat ik U toespreek, en ik wil daarom proberen vanuit het perspectief van Uw latere beroepsuitoefening een terugblik op ons onderwijs te laten vallen.

In de opleiding tot wiskundig ingenieur bevindt de informatica zich in een bijzonder gunstige positie: geen van de andere specialisaties is immers zo duidelijk enerzijds een wiskundige aangelegenheid en anderzijds een ingenieursaangelegenheid. Tot de synthese van deze twee componenten hebben de informatici relatief de meeste mogelijkheden, en ik onderschrijf van ganser harte C.A.R.Hoare's uitspraak, dat in geen ingenieursdiscipline het succesvol nastreven van academische idealen zo rijke vruchten afwerpt als in "software engineering". Hier is inderdaad een terrein, dat zo inspirerend is, omdat de overdekking van wat theoretisch gezond en practisch zinvol is, zich, mits men zich daar met zorg op toelegt, zo schitterend laat uitbreiden.

Toch treft ons het verwijt, dat wij onze studenten niet adequaat op de praktijk voorbereiden, een verwijt, waarvan het de moeite loont om te analyseren wat het voorstelt. Wij ontwikkelen en demonstreren formele methoden, en niet alleen dat, wij propageren zelfs, dat ze in de praktijk gebruikt worden, een praktijk die door de doorsnee programmeur intuitief benaderd wordt.

Nu geeft de overgang van ambacht tot wetenschappelijke discipline altijd moeilijkheden: de oude gildebroeders voelen zich erdoor bedreigd en neigen ertoe zich tegen de ontwikkeling te verzetten. Enig anti-intellectualistisch tegengas moeten we dus als normaal accepteren.

In de informatica ligt het daar externe omstandigheden, die niets met de wetenschap te maken hebben, echter aanzienlijk gecompliceerder. Als programmeurs weten wij uit ervaring en kunnen wij zelfs op grond van simpele analogieen overtuigend aantonen, dat een noodzakelijke voorwaarde voor goede en efficiente programma's gevormd wordt door de beschikbaarheid van een eenvoudige programmeertaal waarvan syntax en semantiek rigoureus en non-operationeel gedefinieerd zijn zonder enige verwijzing naar computer of compiler. Zonder zulk gereedschap blijft het modderen.

De complicerende bijkomstigheid is evenwel dat de International Business Machines, de computerfabrikant die een zo sterk overheersende positie op de markt inneemt, niet het minste commercieel belang heeft bij de verbreiding van het gebruik van goedgedefinieerde programmeertalen. In tegendeel zelfs! Bij een goedgedefinieerde programmeertaal zou IBM ten eerste de plicht hebben om hem correct te implementeren, en ten tweede de kans lopen, dat een concurrent het beter zou doen. Bij ontstentenis van scherpe definitie is het begrip "correctheid van een implementatie" echter leeg, en IBM kan hiermee uit de voeten, omdat —wederom wegens de ontstentenis van een scherpe definitie en de overheersende positie van zijn producten— de IBM-implementatie door het klootjesvolk als de zg. "de facto standaard" wordt geaccepteerd. En vanaf dat moment is per definitie wat IBM doet wel gedaan en mag de concurrentie amechtig achternahollen, per definitie twee jaar achter. U begrijpt, dat er IBM alles aan gelegen is deze ondoorzichtige toestand te handhaven. U begrijpt, waarom IBM de verbreiding van een zo welgedefinieerde programmeertaal als ALGOL 60 te vuur en te zwaard bestreden heeft, en U mag een keer raden naar de koker waaruit de laster komt, waaraan Niklaus Wirth bloot staat sinds zijn geesteskind PASCAL zich toch verbreidt.

Na U aldus op de praktijk te hebben voorbereid geef ik nog eenmaal er uiting aan, dat ik overigens van oordeel ben, dat er op Hilversum 4 minder moet worden gezeverd.

transcribed by Carl Ludwigson
revised Mon, 5 Nov 2007

Copyright Notice

The following manuscript

EWD570 An exercise for Dr.R.M.Burstall

is held in copyright by Springer-Verlag New York. The manuscript was published as pages 215–216 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

27th May 1976 | EWD 570

An exercise for Dr.R.M.Burstall

Dear Rod,

because —as you know— we Dutch are a God-fearing nation, Ascension-day is here an official Holiday, and on official Holidays I don't work. Today I just fooled with figures.

In doing so I discovered a function of the natural numbers which has a nice recursive definition, viz.

fusc(1) = 1
fusc(2n) = fusc(n)
fusc(2n+1) = fusc(n) + fusc(n+1)

a definition which, as far as complexity is concerned, seems to lie between the Fibonacci series and the Pascal triangle.

(The function fusc is of a mild interest on account of the following property: with  f1 = fusc(n1)  and  f2 = fusc(n2)  the following two statements hold:
"if there exists an  N  such that  n1 + n2 = 2N , then  f1  and  f2  are relatively prime" and "if  f1  and  f2  are relatively prime, then there exists an  n1 , an  n2 , and an  N , such that  n1 + n2 = 2N ." In the above recursive definition, this is no longer obvious, at least not to me; hence its name.)

Having seen your exercises concerning the derivation of an iterative program, starting with the recursive definition for the n-th number of the Fibonacci series, I was suddenly reminded of that exercise when I was considering an iterative program for the computation of  fusc . It should be a rewarding exercise, as there exists a very nice iterative program:

n, a, b := N, 1, 0;
do n ≠ 0 and even(n) → a, n:= a + b, n/2
  ▯ odd(n) → b, n:= b + a, (n-1)/2
od {b = fusc(N)}

I wish you luck and enjoyment!         Yours ever,

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 16-Sep-2011

  EWD 571

DRAFT

A simple consideration with far-reaching consequences.

"I believe that there will be no real progress until programmers learn to distinguish clearly between a language (definition) and its implementation in terms of compiler and computer. The former must be understood without knowledge of the latter. And we can only expect programmers to understand this vital distinction, if language designers take the lead [...]. Hence we conclude that the first criterion that any future programming language must satisfy, and that customers must ask for, is a complete definition without reference to compiler or computer."

Niklaus Wirth [1]

In a truly decomposed system, as we have when a whole is regarded as composed of a number of parts, the composition defines how the relevant properties of the whole depend functionally on the explicitly postulated properties of the parts, a functional dependence which is given without any reference to the internal structure of the parts.

For instance, when a mathematical proof of a theorem appeals to a lemma, it appeals to what a lemma asserts, and not to how the lemma has been proved; making the remainder of the proof of the theorem clearly independent of the specific way in which the lemma may have been proved is one of the main justifications for the lemma's introduction.

Similarly, when a program in machine code contains a multiply instruction, its occurrence has to be justified by what the multiplier, when invoked, should achieve, regardless of how the multiplier happens to work. (No mathematician using a proven lemma will complain, when the known proof for that lemma is replaced by a more elegant one; similarly, no machine code programmer will complain when the multiplier in his machine is replaced by a new multiplier with, say, a lower heat dissipation.)

The fact that the relevant properties of the whole depend in a defined way on the explicitly postulated properties of the parts has two important consequences. Firstly —as indicated above— it creates the environment in which a correct part can be safely replaced by a different correct part, viz. provided that it has the same postulated properties. Secondly, it localizes errors in the case of malfunctioning: either the desired properties of the whole do, in this composition, not follow from the postulated properties of the parts, in which case at least the upper level design needs revision, or the flaw can be pinpointed to the malfunctioning part(s), viz. each part that does not display the properties of which it has been postulated that it should have them. Note that without true decomposition, we can at most observe that the whole does not have the desired properties, but that the question which of the parts is to be blamed, is void. (More specifically: a program that has not been truly (de)composed is either correct or wrong: in the latter case it makes no sense to try to count "the number of bugs". For lack of "bug identity" the only defensible answer would be "one".)

There is an overwhelming experimental evidence that such a true (de)composition is indispensable for the design of a logical system above the level of simplicity such that it can be designed with a single stroke of the pen. (If we take —and I do— the analogy with mathematics seriously, we can even add more than twenty centuries of experience.) The experimental evidence is so overwhelming that I find it very hard to defend any design effort of some ambition that is tried without such an explicit, true (de)composition.

*          *
*

High-level programming languages certainly serve as the carriers of designs above the level of simplicity where a single stroke of the pen suffices, and in the whole system envisaged we can identify as "a part" the machinery that should be able to execute programs written in the high-level programming language used: that part has even a name, viz. the "implementation" of that language. (The significance of that part is considerably increased by the circumstance that it is common to many applications.) It is, therefore, indispensable to have an explicit statement of the relevant properties of that part, independent of its internal structure; we must have a statement of what that part should achieve, independent of how it might work. It is only then that the language user knows what he can rely upon and is in a position to prove that his design has all the relevant properties, it is only then that the language implementer knows his obligations and his freedom.

*          *
*

All this is so obvious that it is nearly embarrassing to write it down. And, indeed, I would feel like flogging a dead horse were it not for the fact that the above conditions are more often violated than met, and that this status quo has even its defenders.

From a historical point of view this is understandable.. Many programmers work with older programming languages, the semantics of which they can only appreciate via the language implementation they are daily working with. For lack of adequate definition they are seduced to mistake what the implementer has done for what the implementer should have accomplished, and to forget that deriving lacking specifications from a non-exhaustive set of explorations remains guesswork. They live in an environment where the strict distinction between (the definition of) a programming language and its implementation has never been carried through, and the suggestion that a crucial language requirement is that its semantics be defined without any reference to implementation details, without any reference to computers or compilers, would very well amaze (or perhaps even alarm) them.

To make matters worse, a number of subsequent efforts at rigorous definition of programming language semantics have only added to the confusion, viz. all so-called "operational" language definitions that try to define semantics via an interpreter for that language. The definition of the semantics by means of an interpreting automaton is logically equivalent to defining a language entirely via a (standard) implementation. Without a formal technique for deriving from such an operational definition the language properties that the programmer needs to know, such a definition is useless: as it stands it gives us just enough grip on the language to perform for a given program and a chosen input a desk simulation! With a formal technique for deriving (all?) the relevant language properties, such an operational definition is at least cumbersome (because indirect), usually over specific, and certainly misleading. It is misleading because, of all the possible ways of implementing the language, a special one has been singled out as "the defining implementation"; it is also misleading because it fails to provide a definition independent of any computational model. Such a definition, however, is needed by the conscientious programmer who tries to separate his concern for program correctness from his concern for the costs of program execution.

*          *
*

For nonoperational (also called "postulational" or "axiomatic") definition methods see, for instance, Hoare [2]. To nonoperational methods two objections have been raised. The first objection is in theory a serious one, but in practice it seems less so: the nonoperational methods allow us to define "impossible" programming languages, "impossible" in the sense that they defy implementation. The second objection I have heard is that the axiomatic method is only practicable in the case of simple and elegant programming languages. If —what I fervently hope— that statement is true, I cannot regard it as a shortcoming of the axiomatic method, on the contrary!

*          *
*

The above has been written because, once a necessary condition for progress has been identified, it seems such a pity and such a waste when it remains for so many people unfulfilled.

[1]    | Wirth, Niklaus "Programming Languages: what to demand and how to assess them." Bericht 17 des Institute für Informatik, ETH Zürich, March 1976. (Presented at the Symposium on Software Engineering, Belfast, 8–9 April, 1976.)
[2]    | Hoare, C.A.R. "An Axiomatic Basis for Computer Programming." Comm. ACM 12, 10 (Oct. 1969), 576–583.

Plataanstraat 5 5671 AL NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Wed, 17 Jan 2007

  EWD 572

Trip report E.W.Dijkstra, U.S.A and U.K., 8 June - 10 July 1976.

It was a long trip: eighteen flights, seven different places and ten different beds. But the length of my trip was more or less dictated by the dates of my commitments in Los Alamos and in Belfast, and by combining it all I could arrange that the NSF would pay most of my air travel.

On Tuesday the 8th of June I flew from Amsterdam via Chicago to Albuquerque. It was on the whole a most successful trip, which took no more than sixteen hours. The KLM Boeing 747 in which I crossed the Atlantic Ocean was fully loaded and the meal was miserable. In O'Hare Airport I lost neither my luggage, nor my way, but I did get my share of cultural shock: beside the muzak provided by the Airport Authorities, Continental had at its gate a television set operational! It was appalling and remained most distracting, even after I had encountered David Wheeler from Cambridge, U.K. who was also on his way to Los Alamos.

In Albuquerque we arranged our flights to Los Alamos and went to bed in a hotel. The next morning I passed with Stoughton Bell at the University. It was a pleasure to meet him again, and in the course of that morning I was reminded of the fact that the teaching of programming and the running of a university computing service are two entirely different jobs. It is a sad observation, but even on the campus most computer users are fairly education resistant. Early in the afternoon Ross Aviation took us to Los Alamos: it was my first trip in a Havilland Twin Otter, six others would follow during this trip.

From Thursday morning to Tuesday noon —with the exception of the Sunday— we had at LASL the Research Conference on the History of Computing. For some of the older gentlemen it was quite a nostalgic gathering, in which a predictable amount of time and emotions was devoted to questions of priority. (The situation was aggravated by the circumstance that quite a number of people present had played a part in the recent lawsuit about patents between Univac and Honeywell.)

There are various way in which this conference can be described. One is by explaining that the first day was devoted to the canonization of Saint Johnny, a next day to the beatification of Sankt Konrad and a third day to that of the Holy Alan. At several occasions we saw a curious mixture between national pride and the need for hero-worship.... Apart from that I learned quite a lot. I did not know, for instance, that in the early days the availability of radar technology had played such an important role; I had also to correct my impression about the intensity of the military involvement, which turned out to have been much more heavy than I had suspected. I was, furthermore, amused to learn that the controversy that still divides circuit designers into two warring factions —viz. whether or not it is decent to rely on finite minimum switching times— has been there right at the start.

Brian Randell's lecture was unique among all presentations in that he was the only one who could present absolutely unknown —and fascinating!— new material. He could do so because during the last six months he had been able to lift somewhat the security lid that up till now had covered the British war effort at electronic code breaking. There was so much interest in it, that a special evening session was devoted to it, during which Brian was seconded by Dr.A.W.M.Coombs who had been personally involved and, of course, knew much more than he was allowed to say. Some of the questions put to him were very silly because everyone could foresee that he would not be able to answer them, e.g. all questions about the effectiveness of the British code breaking effort as measured in effect on World War II.

The question at the end of Konrad Zuse's talk whether his equipment had assisted the Nazis in carrying out "the final solution" was, of course, the most terrible of all. When I saw that that was going to happen, I escaped.... In defence of the man who raised that question I must mention that in an earlier conversation Zuse's comments on World War II had been provoking.

I myself added another mistake to the list of those for which most probably John von Neumann has to be blamed. Flowcharts and the the idea that programs must be able to modify their own instructions —a sickening pun!— were already on that list, the use of anthropomorphic terminology in computing science has now been added. I got more than once the distinct impression that that unfortunate use of language can be traced fairly directly to von Neumann's linguistic habits. I made this suggestion in my talk and no one denied it, on the contrary: afterwards I was even shown corroborating evidence. (See addendum page EWD572 - 6.)

My talk presented me with a serious problem. I had prepared a "nice" talk covering the activities at the Mathematical Centre up to 1960. It contained the names of people, names of machines, dates, some technical characteristics of the machines and their influence on our programming, all nicely glued together with anecdotes. But I quickly discovered that my prepared text was utterly useless, for I had been scheduled as the last speaker —the "kicker" or "cleanup hitter"— and most talks consisted of ... names of people, names of machines, dates and some technical data, all nicely glued together with anecdotes. It was perfectly clear that I had to do something completely different. I have shamelessly used all the tricks and my closing address was a great success. (Nearly all speakers had stood behind the rostrum at the left-hand side of the podium, so I placed myself bare-handed at the podium's centre; and to speak more slowly than all the other speakers, well that did not require any additional effort from my side!) I had my final lunch in the company of Joe Traub from Carnegie-Mellon University and his wife Pamela McCorduck, a novelist who was engaged in the writing of a book about the early history of Artificial Intelligence. (She herself seemed to possess enough of the natural variety!) It was fun to see how she observed this crowd and her comments were illuminating: I am looking forward to her book, also on account of her T-shirt of which the front side displayed the surprising text "Artificial Intelligence" and the back side the text "NIL".

After lunch I took the first flight back to Albuquerque, from where I had to fly to Phoenix. The plane had engine trouble and, therefore, was delayed. I was terribly annoyed by this, because Dr.D.M.Dahm from Burroughs had arranged to pick me up in Phoenix, from where the two of us should travel together via Flagstaff to Sedona in Arizona. Suddenly another passenger who was in a hurry announced that there was still one place left in a charter flight to Phoenix. I decide to join, retrieved my luggage from the plane, and only then I heard that the charter flight would be with a small single-engine plane. My enthusiasm waned; it then transpired that one of the four charter passengers was a sixteen year old girl who had never flown before, and the others thought that it might be too rough for her. While we were still hesitating, the repair crew committed itself to having the plane in flying condition within half an hour and the charter flight was cancelled. Even in a four-engine jet the flight from Albuquerque to Phoenix was rough and bumpy: I had had a narrow escape! The only difference was that now I had all the luggage with me in the cabin: was I lucky, for then I discovered that my suitcase had been booked through to Flagstaff, but via the wrong flight! So the whole escapade in Albuquerque saved me the trouble of retrieving my luggage in Phoenix. Dr.Dahm was waiting for me in Phoenix at the gate, we flew to Flagstaff and from there drove down to Sedona.

It was a beautiful trip. We really drove "down" to Sedona, for Flagstaff is really high up in the Arizona mountains. Also Sedona is still "high" according to my standards, and I am sure that the thin air would have bothered me the next days —during which I performed quite regularly— were it not for the happy circumstance that during that week in Los Alamos I had had the opportunity to get adjusted to it. While Dr.Dahm did the driving I enjoyed the sight of the setting sun shining on the red rocks, and in the early evening we arrived in Sedona in the motel where we would have a meeting for the next three days. Having spoken that morning in Los Alamos, I was still dressed in my white shirt and tie, I wore even a complete suit with jacket and all: the contrast between me and the people from Burroughs that we found upon arrival sitting next to the swimming pool could hardly have been greater. I quickly changed.

The next three days were devoted to a mutual exposure between me and a number of Burroughs hardware designers. It was a very fruitful session, the difficulties in understanding each other were much less than I had feared. I knew that Jack Mazola would be present and had derived some comfort from the consideration that in case of mutual misunderstanding he could probably act as interpreter, but I don't remember that he ever needed to act in that capacity. The general theme of the conference was "correctness", I have spoken about fifty percent of the time, in the other half people from the different plants described what measures they had taken.

Looking back at that conference the next weekend I suddenly saw a profound difference between most hardware designers and most programmers. In programming we are afraid of two kinds of errors. On the one hand there is the "punching error": the silly clerical mistake that can create havoc as long as it is not discovered yet, but is trivial to repair as soon as it is found. Guarding against them is a constant concern, but is well known how to do that. (In the case of the ALGOL 60 translator Jaap Zonneveld and I were sitting opposite to each other and we claimed to produce identical booklets. When we were finished, both booklets were independently punched and the results were compared mechanically. We found in that way twenty discrepancies: trivial but very valuable discoveries that have greatly assisted us in getting the thing operational. On the other hand the programmer fears "the flaw in his reasoning": it is the kind of bug that, when found, forces you to redo your thinking. It is the latter type of bug that is fought by correctness proofs. Reviewing the different sorts of precautions my hardware friends showed me in Sedona, my conclusion is that they were primarily directed against the hardware analogue of the punching error. The reasons are clear: with modern production technology such a silly mistake is less easily mended, for you cannot add a missing wire to the interior of a chip. Secondly. hardware design presents fewer conceptual problems than programming. Thirdly there is a difference between the professional life of the average programmer and that of the average hardware designer: while the programmer designs many different engines making use of the same technology, the hardware designer often redesigns essentially the same engine, but each time using a different technology.

I was also surprised to learn that my hardware audience was such a mixed one: for some time we spoke about glitches, and while some of the people were very concerned about them, others were on the verge of bored. As one of them said "Glitches are certainly not our major concern." It was later explained to me that this difference in stress could be explained by the specific problems encountered lately in the different plants.

On the second day the hours of the sessions were shifted forwards —from eight o'clock in the morning until three in the afternoon, with only a small break in the middle— because a number of attendants would like to make a visit to the nearby canyons. My Puritan make-up told me that, if they wanted to visit the canyons, they should have done so before or after the conference, and prevented me from joining the tour; I remained talking near the swimming pool, somewhat cross with those who had left.

On Friday afternoon I left with Jack Mazola and Ted Langlet by car for Phoenix. They would take me to Mission Viejo and had flight reservations for a flight to Santa Ana, while I had a ticket for Los Angeles International Airport for a flight one hour later. It was decided that I should try to get on the Santa Ana flight as well, but it was fully booked and I had to wait as stand-by passenger. Because the flight to Santa Ana was delayed, also the decision whether I would be able to join them was delayed as well. Just at the moment that we had decided that I should go to the other terminal in order to catch the Los Angeles flight, the first five stand-by passengers —of a long list!— were called: I was the fourth and together we flew to Santa Ana. Jack Mazola had his car standing at the Airport and took me to the Hotel "Surf and Sand" in Laguna Beach.

On Saturday I wrote letters and was invited for dinner in the evening. On Sunday I joined the yearly Burroughs Picnic —near one of the lakes that had still water in it— and won via a lottery a dinner for two that I consumed next Thursday evening with Tony Hoare who arrived that Sunday evening. After the picnic I joined John McClintock —as part of the "recognition equipment"— on his trip to Los Angeles International Airport where we collected Tony.

On Monday we had a meeting in one of the conference rooms of the hotel so as to enable Tony —who, of course, still suffered from the time shift— to go back to his hotel room and have a rest whenever he felt like it, the remaining days of that week were passed in the Mission Viejo Plant. Half the time the two of us talked about more general topics, half the time Tony did his specific consulting job while I was talking somewhere else. Usually I addressed small audiences; a number of these talks were really introductions to my recent book. And, because I wanted to know a few things, I managed to get myself a few "private tutorials" one on a hardware problem, and one on a software achievement. They were both most instructive and highly appreciated. (I felt like a good pupil, for in both cases we needed less time than anticipated!)

On Friday afternoon we both left. Tony was picked up by Ivan Sutherland who had been appointed as Professor of Computing Science at Caltech, and I for San Diego where I would spend the weekend with Don and Mary-Ann Lyle. Sutherland had been appointed recently and had done the most sensible thing one can do in such a position: he had written to a few successful Heads of the Department asking for their advice and comments on his intentions. So he had written to Tony as well, and it was a sheer coincidence that, shortly after that correspondence Tony was around. Two weeks later, when I spoke to Tony in Belfast, he told me about that visit and he was favourably impressed to the extent that he remarked "It could be an interesting place for a next sabbatical....". It was quite clear that Sutherland did not wish to remain active primarily in the graphics area where he has made his name (otherwise Tony would not have made that remark).

I had a nice restful weekend in San Diego, well La Jolla as a matter of fact. On Saturday morning Mary-Ann helped me with the buying of little presents for my family —usually I don't do so but this was a special occasion— and in the afternoon we went on my request to Sea World, which is indeed fascinating. Don gave me a copy of Weizenbaum's new book "Computer Power and Human Reason" which contains many quotable remarks and places Artificial Intelligence in what I regard as a more appropriate perspective. The Artificial Intelligentsia clearly don't like the book at all —vide McCarthy's recent attack in Datamation—, I can only regret that the quality of Weizenbaum's book is so uneven. He is either an inexperienced author, or the book has been written in too great a hurry or possibly too much emotional stress. But in view of the force of some of the prevailing prejudices —and the money behind them!— Weizenbaum's book is certainly a courageous one. Part of it I read during that weekend, the rest one week later on the flight from Los Angeles to London.

The next week I should have been in Brazil where I had accepted an invitation to give a six-hour tutorial. But shortly before my departure I received a conference program for the meeting in Rio de Janeiro and saw that the whole meeting was scheduled in terms of 15- and 30-minute presentations! I thought that it would be crazy to travel all that distance in order to speak for half an hour and to waste a week in Rio de Janeiro. So I had one more week in California. On Monday I have been at the Mission Viejo Plant for most of the day, at the end of the day I flew —via three flights on a Twin Otter— to Santa Barbara. The reason was that at Sedona it had been observed that the people from the Santa Barbara Plant had responded very enthusiastically to what I had shown and it was felt a worthwhile effort to address a greater number of people from that plant.

My arrival in Santa Barbara was good for a new experience: I expected to be picked up, and after I had collected my luggage, there was no one there! With Burroughs this has never happened to me before, and, knowing the company, I expect that it will be a long time before it happens again. I left the terminal and looked around; then a car pulled up. It had been a mismatch of a few minutes. Later that evening I was rewarded for my anxiety by a truly excellent dinner.

The next day was fun. From nine onwards I addressed a group of about twenty people. I had been told that they had been selected carefully and I can believe that, for it was an ideal audience to address. And that was a good thing, for we did it in the conference room of the motel, a room that was not cooled. So, after one hour I was wet all over and remained so for the rest of the day. The meeting had been scheduled to last until three o'clock in the afternoon, and then a few people with other commitments left. I stopped at five o'clock and had a drink with some five or six of them (I had two large glasses of beer; in the evening I was still thirsty!). On Wednesday morning I flew back to Mission Viejo, where I remained for the rest of the week.

On Saturday morning Bob Merrell, who had to pick up some family at the Los Angeles Airport, took me to the airport. A nerve-wracking morning. Originally we arranged that he would pick me up at the hotel at 9.30, but eventually it was decided that 10.00 would be early enough. But it was the third of July and Los Angeles Airport was a madhouse. He had put his car at a very accessible parking lot from where a shuttle bus took you to the terminals, but even that shuttle bus got more or less stuck in the traffic jam. I just made it, and left the country, not regretting that I would not be present on its bicentennial Fourth of July. TWA served me an excellent meal: it was called lunch when they served it, it was called dinner when they cleared the tables. Next morning's breakfast, alas, was very disappointing, the main course consisting of an egg that had been scrambled beyond recognition.

On an early Sunday morning I arrived at Heathrow Airport, London. I was back in Europe. It was very warm, and I had to walk long distances. The delay at immigration was longer than usual: it was so early that there were not very many immigration officers and simultaneously a large plane from the Middle East had arrived. But the TWA plane had been very well on time and I arrived very well in time for the elaborate safety procedures for the flight to Belfast, where I arrived at nine o'clock on that Sunday morning.

Tony was at the airport. His flight from Los Angeles, one week earlier, had been less pleasant. The strike of the Canadian air traffic controllers had made the non-stop flight impossible and his plane had made an additional stop in New York. When his plane landed there the complete fire brigade of Kennedy Airport was placed along the runway because there was something wrong with one of the engines and he had been delayed there another eighteen hours. With all that misery still fresh in his memory he was an excellent host for the weary traveller. In the morning I just sat in the sun in his garden, drinking a cup of coffee, in the early afternoon I slept for two hours, and in the evening I wrote two letters. I then had a semi-sleepless night. I had been away for more than three weeks and 24 hours was not enough to absorb the time shift.

The next morning we went to the airport to collect Ria who had flown that morning from Eindhoven. She, too, had had a poor night, and that afternoon we slept together. On Tuesday Tony took us on a trip through Northern Ireland and we went to see The Giant's Causeway, a large basalt formation which I found most impressive —frightening even—but Tony was disappointed, for low clouds destroyed the view. On Wednesday evening the four of us —i.e. Tony and I with our wives— attended the Graduation Dinner in The Great Hall of the University and the next morning was the great ceremony in which I received the Honorary Degree of Doctor of Science, together with an English and an Irish colleague. Although I was told that the ceremony was no longer "than what it used to be", I found the amount of academic pomp just what I had expected. Before my graduation I sat on a chair on the front row reserved for "Professor Dijkstra", after my graduation I was guided towards a chair on the podium, reserved for "Dr.Dijkstra". Afterwards we had lunch with the Vice-Chancellor, Sir Arthur Vick. I think that it was about three o'clock in the afternoon when we returned home, i.e. Tony's home, where I could spend some more time in the highly appreciated company of Rod Burstall who had come that day from Edinburgh to Belfast in honour of my Graduation. It was a pity that he had to return to Edinburgh that very afternoon. A Garden Party —with beautiful weather— was the official end of the day. The next day there was a heavy rain. Ria was at that moment shopping with Tony's wife and they got very wet. I was giving a lecture at the Department of Computer Science.

In the late afternoon we returned home. We flew from Belfast to Gatwick, but in Gatwick the luggage handling took such a ridiculously long time that we missed our connection to Eindhoven. Thank goodness we were together! We stayed in a nearby hotel and early next morning we flew to Schiphol: we had no choice as Eindhoven's little airport is closed during the weekend. We took a coach to Utrecht, from there the train to Eindhoven, and then a taxi to the Eindhoven airport, because there Ria had left the car in the parking lot when she left. I was glad to be home again.

*          *
*

What makes people homesick? I don't know, but my guess is that it is a great number of small differences, many of them too small to be really noticed very consciously, but together bombing your input channels. I think that it is that constant stream of impressions that are not automatically ignored that makes travel so tiring. After two weeks of travel I had a sudden pang of homesickness shortly after Tony's arrival: something he said, or perhaps a gesture gave me a sudden feeling of familiarity that I had missed for two weeks and I was on the verge of addressing him in Dutch, when I checked myself, realizing that that would not work....

Some differences, of course, one cannot fail to notice, the noise level for instance. One day I walked Jack Mazola and someone else through a corridor of the plant and a man came up with a trolley of which one of the wheels squeaked terribly. When I remarked that sometimes a small drop of oil could work miracles they looked at me with two puzzled faces. They did not know what I was talking about, neither of the two, it turned out, had noticed the squeak! But on our last flight from Gatwick to Schiphol I was grateful to British Caledonian for the absence of soft music during take-off and landing.

I became aware of another difference between Europe and the U.S.A. In both cultures people are regarded as "a short summary of their past" but recent and distant past are given different weights in the two cultures. In Europe more weight is given to the more distant past, certainly your parents and sometimes even grandparents are included: my colleagues at the University certainly know me also as "my mother's son", they know where she has studied as they know to which University I have been. Here such knowledge about the background of one's fellow men is naturally available. It was more or less by accident that I discovered that in California this is not the case: apparently it is there possible to know someone professionally quite well, without being sure about his academic training. This makes a different world. Emigration must be very difficult.

*          *
*

I knew that during my absence Europe had had a heat-wave and that the long period of drought had been serious. I was quite alarmed at what I saw: I do not remember having seen the green pastures turned yellow and brown. But this time they are yellow and brown. The first few days after my return it was still too hot to do anything at all —although everybody said "but it is much cooler than it has been"— and, together with the holidays, life seemed to have come to a complete standstill. Since then we have had a few thunderstorms and it has rained. Now we have insects.

19th of July 1976
Plataanstraat 5
NL-4565 NUENEN
The Netherlands
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

Addendum (28th July 1976).

This morning I received from Donald E.Knuth an excerpt from a Panel Discussion on Engineering and Scientific Applications, held at the "5th Annual Computer Applications Symposium" at Armour Research Foundation, October 1958. Here (page 149) the late C.B.Tomkins refers to "Von Neumann's idea of defining a machine in human terms." (End of addendum.)

transcribed by Tristram Brelstaff
revised Sun, 28 Jan 2007

EWD573

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 573 A great improvement
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 217�219 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

A great improvement.

After my return from my last trip the first thing W.H.J.Feijen en M.Rem showed me was a much improved definition of “wdec”, for which they gave the credit to my colleague F.E.J.Kruseman Aretz. In [1] I had written:

“More specifically: we shall use the notation wp(S, R), where S denotes a statement list and R some condition on the state of the system, to denote the weakest pre-condition for the initial state of the system such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state satisfying the post-condition R .”

For a well-chosen programming language the article continues by defining how for any given S and R the pre-condition wp(S, R) is derived. One page later, when dealing with a repetitive construct and its termination, [1] continues:

“Let t denote some integer function, defined on the state space, and let wdec(S, t) denote the weakest pre-condition such that activation of S is guaranteed to lead to a properly terminating activity leaving the system in a final state such that the value of t is decreased by at least 1 (compared to its initial value). [...] The relation between wp and wdec is as follows. For any point X in state space we can regard wp(S, t ≤ t0) as an equation with t0 as the unknown. Let its smallest solution for t0 be tmin(X). (Here we-have added the explicit dependence on the state X .) Then tmin(X) can be interpreted as the lowest upper bound for the final value of t if the mechanism S is activated with x as initial state. Then, by definition, wdec(S, t) = (tmin(X) ≤ t(x) - 1) = (tmin(X) < t(x)).”

Kruseman Aretz’s definition is

| wdec(S, t) = wp(S, t < t0)tt0

where the notation Rxy is used to denote a copy of the expression R in which each occurrence of the variable x is replaced by y (or by (y) if necessary).

Example. Let S be | if true → x:= x - y
|   ▯ true - x:= x - z
| fi

and let t = x .
Then —see [1]— we have:

| wp(S, t < t0) =
| (true or true) and (true ⇒ wp(“x:= x - y”, x < t0)
|  | and (true ⇒ wp(“x:= x - z”, x < t0) =
| wp(“x:= x - y”, x < t0) and wp(“x:= x - z”, x < t0) =
| (x - y < t0) and (x - z < t0) .

Hence wdec(S, t) = wp(S, t < t0)tt0 = (x - y < x) and (x - z < x) = y > 0 and z > 0

This is much simpler than my original treatment. Analogous to the first five lines, we would have to derive first

| wp(S, t ≤ t0) = (x - y ≤ t0) and (x - z ≤ t0) .

Then we would have to find the smallest solution for t0 satisfying that equation —and that is not a very standard operation!—; in this case we would find

| tmin = max(x - y, x - z)

and then we would derive

| wdec(S, t) = tmin < t = max(x - y, x - z) < x = max(- y, - 2) < 0 = min(y, z) > 0 .

(End of example.)

The example shows that Kruseman Aretz’s alternative definition does not only embody a conceptual simplification, but that it also smooths the formal labour to be performed. It couples in a very direct way the derived condition wdec with the fundamental condition wp in a way that is very familiar from the axiom of assignment.

*              *
*

In retrospect I blame myself for acquiescing in my ugly original definition. I knew quite well that it was ugly: it was preceded in [1] by “Note (which can be skipped at first reading).” But I have failed to hear my own warning!

*              *
*

It was only after the above had been typed that I was told about the heuristics that had led to the new formulation of wdec . For that part, Kruseman Aretz gave the credit to M.Rem: it seems to have been the typical multi-person achievement, in which it is very hard to reconstruct later who has contributed what. The argument is the following. Let us introduce an auxiliary variable, t0 say, in which the value of t is recorded prior to the execution of S . (For the sake of’ this recording we assume that the value of t can be “computed”, so that it can be assigned to t0 .) Then we define wdec(S, t) = wp(“t0:= t; S”, t < t0) because the weakest pre-condition that “t0:= t; S” is guaranteed to establish t < t0 is, indeed, the weakest pre-condition for S such that S is guaranteed to decrease t (by at least one, because t is an integer-valued function). But, thanks to the axiom of concatenation, this right-hand side reduces to = wp(t0:= t, wp(S, t < t0) which, thanks to the axiom of assignment, reduces to = wp(S, t < t0):tt0 and that is exactly the expression I gave on EWD573 - 0 .

[1] | Dijkstra, Edsger W., Guarded Commands, Nondeterminacy and Formal
| Derivation of Programs. Comm.ACM 18, 8 (Aug. 1975) 453 - 457.

Plataanstraat 5 | prof.dr.Edsger: W.Dijkstra
NL-4565 NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

EWD574

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A letter to Professor Zohar Manna, 26 July 1976.

Dear Zohar,

The fact that this letter has an EWD-number indicates that I intend to give it a somewhat wider distribution than just you. If you wish to answer to it, I can distribute your answer along the same channels, but, of course, only if you so desire and authorize me to do so.

Last week I spoke to one of the attendants of the recent Summer School organized by the Mathematical Centre in Amsterdam, at which you were one of the lecturers. As far as he was concerned you have stolen the show: he was most impressed by your performances and I thought that you might like to hear so. But that is not the reason for writing this letter to you.

This letter has been prompted by the “Stanford Artificial Intelligence Laboratory Memo AIM-281/Computer Science Department Report No. STAN-ES-76-558” of June 1976 and titled:

| Is “sometime” sometimes better than “always”? Intermittent assertions in
| proving program correctness.”

written by you and Richard Waldinger.

One seemingly irrelevant remark first. I hate computer-produced manuscripts with all those different type founts —and all lines right-adjusted!— if the price to be paid is that all individual letters are ill-shaped.’ I just cannot read a report like yours without constantly suppressing the desire to clean my glasses because all those fuzzy boundaries are so annoying. I much prefer a well-chosen, single type fount manuscript produced on an excellent typewriter —this, of course, excludes most of the IBM pingpong balls— and I don’t care about the right-adjustment either. (On the contrary: without it, significance can be given to additional spaces.) I consider this would-be service to the reader —or is it a service to the writer?— as a misuse of electronics that I abhor just as vehemently as soft music in department stores, waiting rooms, airports etc. (The only thing printed decently on your report is the Stanford Seal in red on the cover!) I hope that —possibly after some thinking— you will agree that this remark —although not so much addressed to you personally— is not so irrelevant: as computer scientist we have, more than anybody else, I think, a responsibility in trying to prevent computer usage from degrading our lives. The rest of this letter is addressed to you personally.

You and Richard Waldinger deserve each reader’s compliments for the way in which your report has been phrased: for that very reason it was a pleasure and a privilige to read it. I think that I understood every sentence of it, something that is in sharp contrast to what is usually dropped in my mailbox: reports of which I am sure that I cannot understand —nor anybody else for that matter— at least one out of every eight sentences. Your report is exceptionally well-written. Thank you, it is nice to see indispensable standards sometimes maintained! So much for my compliments, you yourself can undoubtedly think of other nice things to say about it.

When I read the abstract in which you announced to use “assertions that must be true at some time when control is passing through the corresponding point, but that need not be true every time” I was amazed to the point of being intrigued I tried to think of an example where I would like to do that and could not think of any, so I continued to read the report itself. Afterwards I realized why I could not think of an example: you and I do not mean the same with “control passing through a point.” Let me reproduce, for the sake of clarity of this latter, one of your programs:

|  | input(x, y)
| start:
| more: if x = y
|  | then finish: output(y)
|  | else reducex: if x > y
|  |  |  | then x:= x - y
|  |  |  |  | goto reducex
|  |  | reducey: if x < y
|  |  |  | then y:= y - x
|  |  |  |  | goto reducedy
|  |  | goto more.

Note. In order to display the symmetry more clearly, I would always have written on line 7 “reducey: if y > x” (End of note.)

Question.Would it not have been more consistent to position the last “goto more” with the “goto” under the “then” two lines higher? (End of question.)

And in your treatment a vital role is played“ by Lemma 1:

| if sometime x = a1, y = b1 and x, y >0 at more
| then sometime x = y and y = max{u: u|a1 and u|b1} at more

(where “p|q” should be read as “p divides q”).

Now my privately preferred representation for that code —with labels inserted for the purpose of’ this discussion— is:

|  | x, y := X, Y;
| L0: do x > y → L1: x:= x - y
|  |  | ▯ y > x → L2: y:= y - x
|  | od;
| L3: print(y)

with at L0 relation P0: gcd(x, y) = gcd(X, Y) and x > 0 and y > 0
with at L1: P0 and x > y
with at L2: P0 and y > x
with at L3 relation R: y = gcd(X, Y) because (P0 and not (x > y or y > x)) ⇒ R .

The reason that I was so amazed by your announcement is that in my view control passes only once through L0 —viz. at the initiation of the do ... od—and only once through L3 —viz. at its completetion— . If we wish to take a closer look —i.e. inside the repetitive construct— we may observe control passing a number of times through L1 and L2 .

Comparing my approach to yours I realized that I do not even consider control passing through the guards x > y and y > x. I consider the evaluation of the guards x > y and y > x —which as far as I am concerned could take place in parallel— not as something “through which control passes”. In my view the function of the control is to control the execution of the assignment statements; the guards —which in a sense are “part” of the control— could be evaluated by a separate “control computer”, I hardly consider their evaluation as part of the computation proper. The function of the computation proper is to decrease x by y or y by x , “control” has the secondary function to schedule these happenings in such a way that the invariance of P0 is maintained.

In this terminology the observation that “assertions sometimes hold” boils down to the observation that evaluation of a guard needs only be requested when its value is not known a priori. In that formulation the remark is nearly trivial.

Von Neumann’s idea that the processor A that is doing the real work — i.e. carrying out the assignment statements— and processor B that is evaluating the guards —i.e. figuring out what A has to do when— could profitably be merged into a single processor is some sort of a pun. (It is not as bad as his pun that a program should be able to modify its own instructions, but it is still a pun: it does not distinguish between the traffic and the lights!) But this pun is the kind of “flattening” that should only be considered in the specific realm of thought where it belongs, i.e. when we consider in more detail how to embed something with a clear conceptual structure in a homogeneous environment. Can you understand that in retrospect I think it a great pity that Bob Floyd formulated his 1967 article in terms of that other-Von Neumann relic, the flowchart language? A choice that is responsible for the all too common misunderstanding that the flow analysis that isolates the “loops” is a key component of the inductive assertion method...

In other words, I have the feeling that part of the problem you feel you have solved has less to do with programming as such than with the underlying —but rather arbitrary— computational model you have chosen. For already quite some time I have the impression that with respect to both the theory and the practice of programming no significant further progress is possible, unless we postulate our semantics in a way that is absolutely independent of any computational model. This may sound as heresy in your ears —I just don’t know!— but that paper by you and Richard Waldinger has confirmed my impression. The problem with computational models is that, by being overspecific, they are bound to lead one astray. This, indeed, might sound as heresy in the ears-of someone who writes in his conclusions about ”the way programs work“, for that wording betrays an undiluted operational attitude. It is not the program that ”works“! Agree?

*              *
*

Finally a few questions. In your conclusion you write: ”If the lemmas and the well-founded orderings for the induction are provided by the programmer, to construct the remainder of the proof appears to be fairly mechanical. On the other hand, to find appropriate lemmas and the corresponding orderings is as difficult a task as finding the invariant assertions and well-founded orderings for the conventional ways of establishing correctness and termination.“ I believe you. But should not then the conclusion be that, indeed, the raw code is an inadequate starting point for verification, so inadequate that it is, as a matter of fact, silly to try to use it as such? And should not the conclusion be that the programmer has only done a decent job and has only delivered a useful and complete product, when he provides the lemmas, the invariant assertions etc. as well? Should not the conclusion be that the division of labour, as attempted in the sixties, in which the programmer produced just the raw code, has been proven to be an unworkable interface?

I know that some people find it difficult to draw these conclusions because they are afraid of their consequences; usually they phrase their objections in term: of commiseration with “the average programmer”, arguing that we cannot increase the burden on his shoulders. But that argument is a fallacy, because that is not what I am proposing. By teaching the programmer to be aware of the role of the invariant and of the nature of his inductive arguments we give him the mental tools that are indispensable for doing his job properly: as soon as he masters their use he will never again program without them!

Some people won’t be able to use these tools to their advantage, but are those able to program now? In any case I don’t think that we should allow their presence to prevent us from drawing above conclusions, which should have a profound influence on our teaching. I would like to be sure that the teaching of competent programmers does not meet opposition that is inspired by the hope to keep a target of artificial intelligence alive!

Greetings and best wishes! Yours ever,

| Edsgar .

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
NL-4565 NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

Copyright Notice

The following manuscript

EWD 575: To H.D.Mills, Chairman Software Methodology Panel

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 220–222 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 575

To H.D.Mills, Chairman Software Methodology Panel.

Dear Harlan,

I am not quite sure how to comment on “Essential Elements of Software Engineering Education” by Peter Freeman, Anthony Wasserman and Richard E.Fairley, because I don’t like its underlying political assumptions, because I know that, when dealing with politically distasteful attitudes, my pen tends to get venomous, and, finally, because I don’t particularly want to offend anybody. So I hesitate.

There is, for instance, the authors’ view on the proper role of our universities. They include producing the graduates industry and government ask for. An alternative view is trying to educate the graduates the rest of the world will need in the future, independent of the question to what extent the rest of the world already understands its future needs. This may sound presumptuous, but universities are by definition —if they are any good— presumptuous institutions with targets more far away in the future than most other organizations. I definitely prefer the alternative view, for where, otherwise, is the necessary innovation to take place? The degeneration of our universities into graduate factories is a development I would not like to encourage, because I consider it to be a threat to our civilization.

There is, for instance, the authors’ view on the role of the intellectual individual. With their stress on the supposed virtues of group activity (and on the need for “communication skills”!) they seem to regard minimization —or possibly even elimination— of this role as an ideal worth to be pursued. I regard that as a threat to our civilization. (For further details I refer you, for instance, to The Organization Man by William H.Whyte, first published by Simon and Schuster, New York, 1956)

There is furthermore the observation that of their Five Pillars of Wisdom for the software engineer —computer science, management science, communication skills, problem solving and design methodology— only the first is hard science, while the remaining four —if existing at all— range from soft to very soft. I am afraid, however, that the current fashion grossly overestimates the importance and potentialities of the soft sciences, and would not like to enforce that fashion, because, again, I regard it as a threat to our civilization. (For further details I refer you to Social Sciences as Sorcery by Stanislav Andreski, Penguin Books, 1972.)

Finally —as most political documents— it is superficial. The suggested analogy between the software engineer and the family doctor is false, because the commitment of the medical profession and the commitment of any engineering profession are of quite different natures. The most blatant example of superficiality is probably their argument in favour of communication skills, as they refer to “the software engineer’s need to communicate with a wide range of people and machines”. As a piece of hilarious nonsense I think that this is only surpassed by “The education of a computer” (Grace Murray Hopper, Proc. ACM National Conference 1 (Pittsburgh, 1952) 243–250).

So, if you intend to follow Raymond T.Yeh’s suggestion to use the paper by Freeman et al. “as a basis for departure”, I can only recommend that you depart from it as far as possible.

*         *         *

C.V.Ramamoorthy’s “Preliminary Report on Software Evaluation” is less objectionable: it gives a survey of what is or has been done —no matter how sensible or how foolish— and I have not the slightest reason to assume that his survey is unfair or incomplete. The report is very instructive, even perhaps in unintended ways. This does not imply, that I have no objections: the author fails to challenge the assumption that the whole approach makes any sense at all. Let me quote:

The approach is to identify a set of software characteristic attributes representing good and bad, reliable and unreliable programming practices. For each attribute, measures called metrics are formulated. The merit figure of a program is then defined as the normalized weighted average of these attribute metrics. The validity of this approach depends heavily on the chosen attribute, the metric formulation and the function that combines these metrics.

The first sentence is OK, but in the second sentence the word “measure” is used in a most unscientific sense. In science we measure physical quantities, something that is a meaningful activity because (the measurements of) these quantities are supposed to satisfy certain explicitly stated laws; the purpose of the measurements is to confirm or to refute the supposed laws. Here, however, to “measure” is used in the sense of “attaching a number to”, in very much the same way as psychologists construct an IQ. (It is a fallacy to assume that an IQ “measures” something!) The next sentence is OK in the sense that it describes a common practice, be it a deplorable one, the last sentence is wrong in that it assumes that the notion of “validity” is applicable to such practices, in that it assumes that some of these practices can be more “valid” than others: validity is a binary criterion.

In his research (!) recommendation the author shows —apparently without noticing it— that the problem is recursively unsolvable: here he suggests that the criteria used in evaluating the quality of software, in turn should be evaluated themselves for their effectiveness. (And so ad infinitum...!) The recommendation ends with “These effectiveness measures may allow a user to include an optional set of tools in a software evaluation system to meet his special needs.” No matter how hard I tried, I could not attach a sensible meaning to that sentence; presumably it will be discovered that more “research” should be devoted to the quantification of the user’s “special needs”, so that we can decide whether a set of tools is “optimal”!

The whole activity has very little to do with what I would like to regard as software engineering. It is more the further refinement of management “science” as a self-perpetuating activity. If the manager needs a number, he will get one. I am afraid that the whole activity is adequately captured by the well-known saying “If you ask a foolish question, you will get a foolish answer.”.

Note (added to avoid misunderstanding). I don’t know how to manage the design (or should we say “the discovery”?) of software. I hope that my saving grace is that I don’t pretend to. (End of note.)

Good luck!             Yours ever,

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 21-Dec-2011

EWD576

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 576 On subgoal induction
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 223�224 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

On subgoal induction.

In [1] I encountered “subgoal induction” as a technique for proving partial correctness. It was applied to a program S that I would write down as

| S : x:= f(x0);
|  | do B(x) → x:= g(x) od;
|  | x:= h(x) .

In order to prove

| {P(x0)} S {R(x0, x)} | (1)

—i.e. if P(x0) holds and the execution of S terminates properly, then in the final state R(x0, x) will hold— “subgoal induction” is used. The technique consists of finding a relation Q(x, z) satisfying

| (A x: (non B(x)) ⇒ Q(x, z)) | (2)
| (A x, z: (Q(g(x), z) and B(x) ⇒ Q(x, z)) | (3)
| (A x, z: (P(x) and Q(f(x), z)) ⇒ R(x, z)) | (4)

and it was stated that the existence of a relation 0 satisfying (2), (3) and (4) proves (1).

My general inclination when I encounter such formulae —particularly when I encounter them in a report that is really dealing with something else— is to skim them, assuming that they are no more than variations on an old theme. Formula (3), however, attracted my attention, because, if P’(x) is the invariant relation for the repetitive construct, we have to prove —see [2]—

| (P’(x) and B(x) ⇒ P’(g(x)) | (5)

and, if we compare (5) with (3), we see that the substitution of g(x) for x occurs at the other side of the implication! This was reason enough to investigate subgoal induction a little bit more closely.

In terms of a relation Q satisfying (2), (3), and (4), we can take as our invariant relation

| P’(x): (A z: Q(x, z) ⇒ Q(f(x0), z)) | (6)

a relation which is clearly established by “x:= f(x0)” , the first statement of S . To prove (S) we have to prove

| ((A z: Q(x, z) ⇒ Q(f(x0), z)) and B(x)) ⇒ ((A z: Q(g(x), z) ⇒ Q(f(x0), z)) | (7)

For those values of x , such that B(x) is false, the implication (7) is vacuously true, for those values of x , such that B(x) is true, (3) tells us that Q(g(x), z) is a stronger condition on 2 than Q(x, z) , so that whatever is implied by the latter is certainly implied by the former. Hence (7) and thus (5) follows from (3).

Finally we have to prove that

| (P’(x) and non B(x)) ⇒ wp(“x:= h(x)”. R(x0, x)) | (8)

Thanks to (2) and (6), the left-hand side of (8) reduces to

| (A z: Q(x, z) ⇒ Q(f(x0), z)) and Q(x, h(x))

from which we conclude —applying the quantified implication for z = h(x)— the truth of

| Q(f(x0), h(x)) .

Because the initial value x0 satisfies P(x0) , we conclude —applying (4) with x = x0 and z = h(x)— the truth of

| R(x0, h(x))

but thanks to the axiom of assignment this is identical to the right-hand side of (8). Hence (8) frollows from (2), (4), and (6).

Thus we have established that —as was to be expected— subgoal induction is indeed the next variation on an old theme.

The analysis described above was carried through together with C.S. Scholten.

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
NL-4565 NUENEN | Burroughs Research Fellow
The Netherlands |

[1] Is “sometime” sometimes better than “always”? Intermittent assertions in proving program correctness, by Zohar Manna and Richard Waldinger, STAN-C5-76-558
[2] Guarded Commands, Nondeterminacy and Formal Derivation of Programs, by Edsger W.Dijkstra, Comm.ACM 13, 3 (Aug.1975) 453 - 457.

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

Copyright Notice

The following manuscript

EWD 577: Tripreport E.W.Dijkstra, ECI-conference 9-12 August 1976, Amsterdam

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 225–229 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 577

Tripreport E.W.Dijkstra, ECI-conference 9 - 12 August 1976, Amsterdam.

It was the kind of conference from which one returns with a glorious headache. It had been organized by the European Cooperation in Informatica, a joint enterprise of the Information Processing Societies of the various European countries. The response to the Call for Papers had been very low: only 36 papers had been submitted. Instead of cancelling the conference, the organizers decided that, by abolishing parallel sessions and selecting 12 of the submitted papers, the conference could still be held. (After all, they had six invited papers in addition to the submitted ones!) In spite of the meagre program, they still managed to collect about 250 participants. It is very questionable whether, with those 250 participants, they have reached the break-even point; if they haven't, I just cannot have pity with them: it would serve them right, for the organization of a bad conference is worse a crime than not organizing a conference at all. (Besides that, they had been warned.) The organizers have committed what I would like to describe as "Contempt of Audience". It saddened me to see the extent to which the degrading circumstances at the European universities have broken the spirits of my colleagues, it saddened me to observe their apathy and indifference, in which they have "learned" to accept the junk as if it were the real thing. The most frightening aspect of it all is that most of them present their abolishment of all norms and (time-honoured!) quality standards as an act of great wisdom.

The conference was held in the new building of the Free University of Amsterdam. I had never been there before. It must be about the last university building erected during the time that our government thought that it was infinitely rich. It was in many respects an ideal setting, in a most important aspect, however, it was not: at no moment one got the impression of being in a seat of learning and a centre of culture, on the contrary! I walked through the University Bookshop, but it was of a shocking vulgarity —as bad as the books department of the Bijenkorf (i.e. a chain of large department stores, oriented towards the superficial, fashionable consumer)—. Comic strips that were not funny, political pamphlets full of cliche's, science fiction books and pamphlets of obscure mystical cults. And, to top it all, when we entered the Auditorium a few minutes before the conference started, there was... Muzac! I was flabbergasted. (In my previous tripreport I have made a remark about differences in noise level at both sides of the Atlantic: from that comparison, I learned, at least Amsterdam should be excluded. While portable radios are strictly forbidden in most public buildings, such as railway stations and the Eindhoven University Campus, the bar at the lounge of the Free University in Amsterdam did not observe that rule! The whole place was of a disgusting vulgarity.)

The first afternoon was devoted to Program Development and Verification in Practice and Theory. Michael Jackson gave his talk as an invited speaker. It was well-presented and certainly falls under the heading Program Development in Practice, but it had little to contribute beyond the rather limited problem area of file processing in (or: in spite of?) COBOL. Then Antonio Salvadori from the University of Guelph, Ontario, described the "Guelph Efficiency Monitor, a preprocessor system which can analyse a COBOL program at any development or running stage". I quote:

"The statistics gathered and printed consist of

a COBOL clause and verb count

a percentage breakdown of PROCEDURE DIVISION verbs used

the number of source records, number of comment cards, indication of non-ANSI standard verbs, etc."

The last speaker was P.Hammersley, Cambridge UK on "Team Organization in Integrated On-Line computer Projects", a talk that was well-covered by its title. His English was a pleasure to listen to, but it was a talk with little or no technical or scientific content and I —as many others— found my thoughts wandering away.

In the evening there was a reception by the State Secretary of Interior Affairs and Burgomaster and Aldermen of Amsterdam; the reception was held in the beautiful surroundings of the new Vincent van Gogh Museum, where the air was polluted by... audible wallpaper! Most of us looked back on a wasted afternoon and were worried whether the conference would get any better.

The next morning was devoted to Concepts and techniques of Database Management. The invited speaker, C.J.Date (IBM General Products Division) was that morning's best speaker. He knew what he was talking about and gave what seemed to be a good overview. For those unfamiliar with the topic, his talk was quite instructive.

The afternoon was devoted to Computer Networks. Louis Pouzin (IRIA) was the invited speaker on "Names and Objects in Heterogeneous Computer Networks". He had originally prepared a more technical presentation than in the meantime he dared to give and in a hurry he redesigned his presentation; as a result it was a bit rambling, but it was still quite clear that he knew what he was talking about. I had heard him many times before, but unaware of his past as a telephone engineer: that past was mentioned in the introduction and was quite discernable.

On Wednesday morning —again Program Development and Verification etc.— I opened the session as the invited speaker. Tony Hoare should have been that morning's session chairman but, Tony being prevented from attending, his role was taken over by L.A.M.Verbeek of Twente University. I did not present my material well. I knew that it (EWD563) was difficult to present, as I wanted to show what I had learned from a highly formal experiment that had recently taken me more than a month to conduct, lessons that I could not explain without sketching the experiment, an activity that, indeed, took too much time and was only partly successful. (The trouble was that, while trying to do it, I noticed this!) In retrospect a very simple tutorial —nothing new— on formal program derivation would have been more appropriate for this occasion. Afterwards I.D.Ichbiah (CII) showed a similar —but less formal— case study of program development; he reached his audience better I think. Then Shmuel Katz (IBM Israel Scientific Center, Technion City, Haifa, Israel) gave a well-prepared talk on "Program Optimization Using Invariants". I think that it told more about the role of science and technology in the state Israel than about computing science as such.

Wednesday afternoon was again devoted to Database Management. Rudolf Bayer (Technische Universitaet Muenchen) was invited speaker on "Integrity, Concurrency and Recovery in Databases." His talk was well-prepared and well-presented (but for the fact that he tried to show too much). I was not convinced by his proposed solution: it was complicated and his "conclusion" that deadlock prevention was impractical did not seem to me to be sufficiently justified. I have more the impression that he had failed to discover how to do it. Later, in private, I had a long discussion with him about the current database folklore. It was very instructive for me; he, at least, is willing to challenge the common tacit assumptions, even if they have already found their way in standard proposals! (So does Michael Jackson, who repeatedly expressed his strong fear that via the standardization bodies already identified mistakes will be "cast in concrete".)

The afternoon ended with a Panel Discussion on Database Management with P.J.H.King (United Kingdom), G.M.Nijssen (Belgium) and A.A.Verrijn Stuart (The Netherlands) as panelists and T.W.Olle as chairman, who found it necessary to address in public the panelists by their Christian names. It was just terrible! A few weeks earlier Olle had sent six questions to the three panelists and each question was answered by each panelist. For more than an hour we had an eighteenfold demonstration of the well-known saying "If you ask a silly question, you'll get a silly answer." In our innocence we thought that this panel discussion would be the absolute low of the conference: little did we suspect what the future still held in store for us.

From 20.00 to 24.00 a Dutch evening with plenty to eat and to drink had been announced. What had not been announced was that conversation would be absolutely impossible thanks to constant "music" produced by two alternating groups. Thanks to uncontrolled electronic amplification they produced a deafening noise that was physically painful. I had been stupid enough to try to talk: the next morning I had a sore throat; Horst Huenke had the same experience. In short: if you want to torture and insult your guests, delegate the organization of your parties to "Martinair Party Service". I guarantee absolute success.

The invited speaker for the last morning —devoted to Architecture— was W.G.Spruth from IBM, Boeblingen, Germany, on "Trends in Computer System Structure and Architecture". But for a scathing remark about Honeywell not marketing MULTICS and another scathing remark about Burroughs and the ILLIAC IV the speaker only mentioned IBM products, mentioning their catalogue numbers at a higher rate than I could factorize them. It was a bloody shame. Van Wijngaarden, who was chairman of that session, took the precaution of not allowing any discussion and announced the coffee break. But was this a wise decision? During the coffee break several youngsters came to me, seriously worried by the fact that that shameful show had been allowed. They must have left the ECI-conference with in their mouths the bitter taste of dishonesty. Is this the way to educate our next generation?

It ended with a closing speech by van Wijngaarden in his capacity of Conference Chairman. Apart from thanking all the people who had contributed —he did so very nicely— he somewhat repaired the situation by commenting on Spruth's performance, be it in veiled terms. A large portion of his closing speech was devoted —in less veiled terms, but admirably chosen— to a public rebuke to me for my lack of tolerance. I had not only been annoyed by the music —and had shown so— but also by the fact that at the occasion of this conference a well-publicized ECI Computer Chess Tournament had been arranged. I did not like that at all —and had shown so— because I am of the considered opinion that, contrary to public superstition, the game of chess is of no relevance for computing science. By organizing the tournament, the ECI had only added fuel to that public misconception. It is perhaps easier to be tolerant, as soon as one doesn't care anymore.....

*         *         *

I learned a few things about Databases. I learned —or: had my tentative impression confirmed— that the term "Database Technology", although sometimes used, is immature, for there is hardly any underlying "science" that could justify the use of the term "technology". I have even my doubts when I am asked to believe that "database technology is still in its infancy", for that strikes me as being asked to regard the quacks at the fairs as the infancy of medical science. The point is that the way in which the database management experts tackle the problems seems to be so grossly inadequate. They seem to form an inbred crowd with very little knowledge of computing science in general, who tackle their problems primarily politically instead of scientifically. (In this respect the panel discussion was very revealing: at least half of the time was devoted to problems related to standardization! From the history of programming language development they should have learned to what disaster that premature concern about standardization may lead.) Often they seemed to be mentally trapped by the intricacies of early, rather ad hoc solutions to rather accidental problems; as soon as such a technique has received a name, it becomes "a database concept". And a totally inadequate use of language, sharpening their pencils with a blunt axe.

Lousy use of language —and therefore confusing— was a fairly general phenomenon. Allow me to end with the following anthology of crazy expressions. (Most of them are meaningless; if they mean something, it is something nonsensical.)

"virtual systems"
"virtual terminals"
"logical names"
"physical names"
"logical abstractions"
"mapping one level of abstraction onto the layer below"
"data structures are mapped into several layers of abstraction"
"a programmer efficiency index"
"an effective implementation view of the corporate data model"
"different levels of abstraction of view of data"
"dynamic change"

and, to crown the confusion,

"the computer playing this game."

No, gentlemen, three times No: computers don't play.

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

P.S. To give you some impression of how "international" this conference was: more than 150 participants were Dutch.

P.P.S. A final quotation from our IBM-spokesman:

"Interfaces decrease performance and increase manufacturing cost."

W.G.Spruth

transcribed by Corrado Cantelmi
revised 29-Sep-2011

Copyright Notice

The following manuscript

EWD578 More about the function “fusc” (A sequel to EWD570)

is held in copyright by Springer-Verlag New York. The manuscript was published as pages 230–232 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

16 August 1976 | EWD 578

More about the function fusc. (A sequel to EWD570)

In EWD570 I introduced the function fusc, given by

fusc(1) = 1,       fusc(2n) = fusc(n),       fusc(2n+1) = fusc(n) + fusc(n+1)     .

Compatible with the second part of that definition we derive from the third part  fusc(0) = 0 . I showed there the following iterative program for the computation of  fusc(N)  —with peven and podd standing for "positive and even" and "positive and odd" respectively—

n, a, b := N, 1, 0;
do peven(n) → a, n := a + b, n / 2
  ▯ podd(n) → b, n := b + a, (n-1) / 2
od {fusc(N) = b}

On my last trip through the USA, while lecturing to a Burroughs audience, my audience derived this program after it had decided —after only a few very modest hints!— that a good candidate for an invariant relation would be

P:               fusc(N) = a*fusc(n) + b*fusc(n+1)

The audience arrived at this suggestion after a few simple considerations. The first observation was that

fusc(N) = fusc(n)

would be simple to initialize by means of  n:= N . They quickly saw that this was too simple, and considered

fusc(N) = a*fusc(n)

equally trivially initialized by  n, a := N, 1 ; it was then remarked that initialization would not be complicated by an additive term

fusc(N) = a*fusc(n) + b

as that is initialized by  n, a, b := N, 1, 0 . The observation that for  n = 0  the first term would disappear but that  fusc(n+1) = 1  would then hold suggested, together with the third part of the definition for  fusc  the fully blown-up  P  as given above. Separating the cases

n = 2k: | fusc(N) | = a*fusc(n) + b*fusc(n+1) = a*fusc(2k) + b*fusc(2k+1) = (a+b)*fusc(k) + b*fusc(k+1)
n = 2k+1: | fusc(N) | = a*fusc(n) + b*fusc(n+1) = a*fusc(2k+1) + b*fusc(2k+2) = a*fusc(k) + (a+b)*fusc(k+1)

my audience quickly derived —to its pleasant surprise!— the iterative program given above.

*         *         *

From the above program, two properties of the function fusc follow. The first one is that the value of the function fusc does not change if we invert in the binary representation of the argument all "internal" digits, i.e. all the binary digits between the most- and the least-significant ones. For instance  fusc(19) = fusc(29)  because, in binary 19 and 29 are 10011 and 11101 respectively. This follows from the comparison of the a,b-pairs during those two computations. After the processing of the least significant digit of the arguments, both have  a,b = 1,1 . As a result of the inverted internal digits, the one computation has the role of  a  and  b  interchanged with respect to the other computation. Because the sum of the two values is a symmetric function of its arguments and, as a result of the last —i.e. most-significant—  1  in the argument that sum of  a  and  b  is delivered (in  b ) as the final value, both computations deliver the same result.

The next property is more surprising. (At least, I think so.) Let us try to represent the pair  a,b  by the single value  m , according to the convention

a = fusc(m+1)           b = fusc(m)

In the case of  peven(n)  the operation on  a,b  has the form  a, b := a+b, b  or:

          fusc(m+1), fusc(m) | := fusc(m+1)+fusc(m), fusc(m) := fusc(2m+1), fusc(2m)

an operation that translates into  m:= 2m . Similarly  a, b := a, a+b  translates into  m:= 2m+1 . Substituting all this in our iterative program we get

n, m := N, 0;
do peven(n) → m, n := 2*m, n/2
  ▯ podd(n) → m, n := 2*m+1, (n-1) /2
od {fusc(N) = fusc(m)}

i.e. the fusc-value does not change if we write the binary digits of the argument in the reverse order. For example  fusc(19) = fusc(25)  because 19 and 25 are in binary 10011 and 11001 respectively. I think this second property more surprising!

*         *         *

In a way which does not admit generalization I discovered the equivalence

2|fusc(n) <=> 3|n

i.e.  fusc(n)  is even iff  n  is a multiple of 3. Inspired by a recent exercise of Don Knuth I tried to characterize the arguments  n  such that 3|fusc(n) .

With braces used to denote zero or more instances of the enclosed, the vertical bar as the BNF "or", and the question mark "?" to denote either a  0  or a  1 , the syntactical representation for such an argument (in binary) is

            {0}1{?0{1}0|?1{0}1}?1{0}

I derived this by considering —as a direct derivation of my program— the finite state automaton that computes  fusc(N)|mod 3 . It was the first time of my life that I did what others have done many times before, i.e. relating a finite state automaton to a grammar. The exercise is up till now only of modest interest; it taught me that division by a fixed factor and (simple!) syntactic analysis are processes that are very closely related to each other, and that insight I think somehow illuminating.

*         *         *

Since the distribution of EW570 it has been discovered that more mathematicians have occupied themselves with the function  fusc  —they only gave it a different name!— a fact that is not surprising in view of its properties. J.J.Seidel and F.L.Bauer have independently pointed out to me that it is no. 56 in Sloane's Dictionary of Integer Sequences, that refers to an article by G.de Rham, Elemente der Mathematik, Vol.2 (1947) pg.95 . It was fun!

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 16-Sep-2011

EWD580

Waarom de onderafdeling der wiskunde zich met de informatica moet bezighouden.

In deze tijd van "herprogrammering" lijkt het goed de vraag waarom de onderafdeling der wiskunde zich nog steeds met de informatica zou blijven bezighouden, hernieuwd te stellen en duidelijk te beantwoorden. Het is immers het antwoord op de vraag "Waarom?", dat het antwoord op de vraag "Hoe?" sterk zou moeten beinvloeden (zo niet bijkans bepalen).

Dat sommige wiskundigen rekenmachines goed (of misschien zelfs wel: nog beter) zouden kunnen gebruiken is irrelevant. Ten eerste hebben ze dit waarschijnlijk gemeen met beoefenaren van vele andere disciplines, ten tweede verklaart het niet waarom de onderafdeling der wiskunde dit onderwijs voor het goed (of beter) gebruik zou moeten verzorgen.

Dergelijk onderwijs, dat gericht is op goed of zelfs beter machinegebruik —hetzij direct, hetzij indirect door verbetering van het "gereedschap"— ligt slecht dan duidelijk op de weg van de onderafdeling der wiskunde, mits wiskunde —als wetenschappelijke discipline in de ruimste zin des woords— in dezen een onmisbare bijdrage leveren kan. We hoeven misschien niet zover te gaan, dat ons onderwijs in de informatica zich strikt tot deze wiskundig geaarde bijdrage zou moeten beperken, wel moeten wij (als er on herprogrammeringsredenen gesneden moet worden) deze wiskundig geaarde bijdrage als onze voornaamste verplichting erkennen en nakomen.

Tot zover de machine als gereedschap, in welke functie hij nooit meer betekenis zal hebben dan de toepassing waarvoor hij wordt ingezet. Er is echter een andere kant aan de zaak, die ik veel belandgrijker vind. In 1972 schreef ik —en ik onderschrijf het nog steeds— :

"Automatic computers have now been with us for a quarter of a century. They have had a great impact on our society in their capacity of tools, but in that capacity their influence will be but a ripple on the surface of our culture compared with the much more profound influence they will have in their capacity of intellectual challenge without precedent in the cultural history of mankind. [...] This challenge, viz. the confrontation with the programming task, is so unique that this novel experience can teach us a lot about ourselves. It should deepen our understanding of the processes of design and creation; it should give us better control over the task of organizing our thoughts. If it did not do so, to my taste we should not deserve the computer at all!"

Het is in zijn hoedanigheid van de geestelijke discipline die primair op voorkomen van onbeheerste complexiteit is gericht, dat de informatica zijn innige verweving met de rest van de wiskunde toont. Enerzijds zijn de hiertoe in de informatica ontwikkelde methoden duidelijk van wiskundige aard en lijkt de voorspelling, dat dit in de toekomst nog geprononceerder het geval zal zijn, absoluut veilig, anderzijds begint zich af te tekenen hoe primair voor de informatica ontwikkelde werkwijzen een diepgaande invloed zullen hebben op de wijze van beoefening van allerlei takken der wiskunde, die wat hun onderwerp aangaat nauwelijks met de informatica geassocieerd worden. Om, waar relevant, van de rest van de wiskunde zoveel mogelijk te leren en aan de rest van de wiskunde zoveel mogelijk te leren, zulks lijkt de primaire taak van ons als informatici.

19 augustus 1976 | prof.dr.Edsger W.Dijkstra

transcribed by Carl Ludwigson
last revised Thu, 15 Nov 2007

EWD581

A somewhat open letter to Professor John McCarthy.

To Professor John McCarthy, Director,
Artificial Intelligence Laboratory
Stanford University
STANFORD, California 94305
U.S.A.

Dear Colleague,

thank you for your amazing letter of August 18, 1976. But you really don't need to be sorry for me because the output of your xerographic printer hurts my eye. (For after all, all of us need our daily dose of irritation: I satisfy my needs in this respect by exposure to audible wallpaper, xerographic computer output and similar would-be services to the consumer.)

I am puzzled by your ban on my use of the verb "to degrade": I thought I had used it correctly, in the sense of "to impair the quality of". But let me propose a deal: you allow me to dislike your poor xerographic printer output (and to say so), and I promise not to mind if you call me a snob.

As far as the mechanics of manuscript production are concerned, I can warmly recommend to all prospective authors to train themselves to get their texts nearly right the first time: it is a fast, efficient, and cheap way of working that almost always gives great esthetic and intellectual satisfaction.

And finally: if you have the text of your recent letter still in your computer files, you could do me three favours: inserting the missing "W." in the first line of the address, and correcting the spelling errors in the next two lines of the address.

As EWD581 - 1 your letter will get the same distribution as EWD574, my letter to Zohar.

Greetings and best wishes!                         Yours ever,

                                                              [Signed: Edsger W. Dijkstra]

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

[Stanford University Logo]

Artificial Intelligence Laboratory, STANFORD UNIVERSITY, Stanford, California 94305

Telephone 415 497-4430                                                    August 18, 1976

Professor Edsger Dijkstra
Plataanstrat 5
NL-4565 NEUNEN
The Netherlands

Dear Professor Dijkstra:

Zohar Manna showed me your letter of 26 July. I am sorry you "vehemently abhor" computer produced manuscripts in different type fonts. I wish our xerographic printer had higher resolution and didn't make smudges when it hasn't recently been adjusted; we do the best we can. You are entitled to your tastes, but when you claim that people with different tastes are using computers to "degrade our lives", you are contributing to an atmosphere of snobbery that has done much to degrade discussion of programming style. Consider this also a protest against the language used in your campaign against gotos. (Sorry our boldface isn't bolder).

As the inventor of one of the first languages (LISP) that allowed programming without gotos, I nevertheless consider that they have their uses. However, my main objection is to the character of the campaign you launched against them, which seemed to be based on an appeal to snobbery and seemed to encourage more snobbery.

As you see, justified right margins are optional in computer produced documents. Many people share your preference for unjustified lines, but it is wrong to make a moral issue of it. As a matter of taste, I find the backwards words fi and od unpleasing and would prefer parentheses or begins and ends for resolving ambiguities.

I am glad you like the content of Manna's and Waldinger's report. Manna would be an excellent expositor even if his reports had to be incised in clay tablets and baked, but the polished style and the prompt appearance may owe something to the opportunity for frequent revision afforded by computer produced documents. Certainly, this was one of our main reasons for pioneering them at this laboratory. Moreover, we cannot afford the secretarial time required to make several versions of a typescript.

If you felt like distributing this protest to your EWD list, I would be grateful.

Sincerely,

[signed: John McCarthy]

John McCarthy
Director
Professor of Computer Science

transcribed by Carl Ludwigson
revised Sun, 9 Sep 2007

EWD582

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Copyright Notice
The following manuscript
| EWD 582 A proof of a theorem communicated to us by S.Ghosh (with C.S.Scholten) :
is held in copyright by Springer-Verlag New York.
The manuscript was published as pages 233�234 of
| Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective,
| Springer-Verlag, 1982. ISBN 0�387�90652�5.
Reproduced with permission from Springer-Verlag New York.
Any further reproduction is strictly prohibited.

A proof of a theorem communicated to us by S.Ghosh.

by Edsger W.Dijkstra and C.S.Scholten

In a letter of 19 August 1976, S.Ghosh (currently c/o Lehrstuhl Informatik I, Universitat Dortmund, Western Germany) communicated without proof the following theorem in natural numbers —here chosen to mean “nonnegative integers”— :

Given a set of k linear equations of the form

| Li = bi (0 ≤ i < k) | (1)

in which the Li are homogeneous linear expressions in the unknowns with natural coefficients and the bi are natural numbers, there exists a single equation

| M = c | (2)

in which M is a homogeneous linear expression in the unknowns with natural coefficients and c is a natural number, such that (2) has the same natural solutions as (1).

Because the natural solutions of (1) are the common natural solutions of (3) and (4), as given by

| L₀ = b₀
| L₁ = b₁ (3)

and | Li = bi for 2 ≤ 1 < | (4)

it suffices to prove that (3) can be replaced by a single equation with the same natural solutions as (3).

Consider for natural P₀ and P₁, to be chosen later, the equation

| P₀ * L₀ + P₁ * L₁= P₀ * b₀ + P₁ * b₁ | (5)

All solutions of (3) are solutions of (5). We shall show that and P₀ and P₁ can be chosen in such a way, that, conversely, all natural solutions of (5) are solutions of (3). We shall do so by choosing P₀ and P₁ in such a way that (5), considered as an equation in L₀ and L₁ , has (3) as its only natural solution; because all natural choices for the original unknowns will give rise to natural L₀ and L₁ , this is sufficient.

Considered as an equation in L₀ and L₁ , the general parametric solution of (5) is given by L₀ = b₀ + t * P₁ L₁ = b₁ - t * P₀ (where, to start with, t need not be a natural number). We shall choose a natural P₀ and P₁ in such a way that from natural L₀ and L₁ , viz.

| b₀ + t * P₁ ≥ 0 | (6)
| b₁ - t * P₀ ≥ 0 | (7)
| left-hand sides of (6) and (7) integer | (8)

we can conclude t = 0 .

Choosing P₁ > b , we derive from (6)

| t > -1 | (9)

Choosing P₀ > b₁ , we derive from (7)

| t < 1 | (10)

Choosing P₀ and P₁ furthermore such that gcd(P₀, P₁) = 1 , we derive From (8) that t must be integer; in view of (9) and (10) we conclude that t = 0 holds. Summarizing: (5) can replace (3) provided

| P₀ > b₁, P₁ > b₀ , gcd(P₀, P₁) = 1

*              *
*

Example. Let the given set be x = 1, y = 1, z = 1 . The first two equations can be combined by choosing P₀ = 2 and P₁ = 3, yielding:

| 2*x + 3*y = 5 , z = 1 .

These two can be combined by choosing P₀ = 2 and P₁ = 7, yielding

| 4*x + 6*y + 7*z = 17

for which (1,1,1) is, indeed, the only natural solution. (End of example.)

3 August 1976
Plataanstraat 5
NL-4565 NUENEN
The Netherlands

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

EWD583

Eerste toespraak tot mijn studenten, najaar 1976.

U mag dit semester mijn college lopen op één voorwaarde, nl. de voorwaarde dat U het zo leuk vindt, dat U het voor Uw plezier loopt. Ik weet, dat dit mijnerzijds een ouderwets verlangen is dat meer verlichte, moderne geesten als "lichtzinnig" afdoen, maar ik ben serieus.

Ik heb er natuurlijk helemaal geen bezwaar tegen, wanneer U ook iets z.g. nuttigs opsteekt. Ik vind het natuurlijk best wanneer dit college blijken zal een heilzame invloed uit te oefenen op Uw latere werk. In stilte hoop ik zelfs op zo'n heilzame invloed, en dan niet alleen bij diegenen onder U die later specifiek met automatische rekenmachines te maken zullen krijgen. Integendeel, want leren programmeren is niet anders dan leren denken en dit college dient dies zijn invloed op al Uw wiskundig werk te hebben. Voor de duur van dit semester wil ik dit nuttigheidsaspect echter naar de achtergrond verbannen. Nuttigheidsoverwegingen —hoe lovenswaardig zij in principe ook mogen zijn— zijn in de praktijk nl. erg gevaarlijk gebleken: iets te bekrompen, iets te eng opgevat hebben zijn menig college uitgehold tot een farce.

Juist omdat programmeren een zo evident bruikbare vaardigheid is moet ik me, wellicht met meer nadruk dan sommige mijner collegae, van het bruikbaarheidsaspect distancieren. De utiliteitstheorie leert ons, dat je in je college vooral die dingen moet brengen, waar de student later profijt van heeft. Wie die als richtsnoer accepteert en de collegestof nadrukkelijk daaraan toetst, loopt echter het gevaar, dat de directe bruikbaarheid een onevenredig grote rol gaat spelen. En uit die school komt dan de opvatting, dat een college over programmeren een soort rijles hoort te zijn, bij voorkeur volledig afgestemd op de automatische rekenapparatuur die min of meer toevallig op de campus voorhanden is. Ik zou het evenwel niet prettig vinden, als onze geestelijke horizon samen ging vallen met de Dommel.

Het gevolg van zo'n gecontraheerde gezichtseinder is dat colleges sterk aan inspiratieve kracht inboeten, zodat studenten de colleges op zijn best nog passief ondergaan. Dit verschijnsel heeft inmiddels zo alarmerende vormen aangenomen, dat het zelfs voor onze pedagogen niet onopgemerkt is gebleven, sterker: zij hebben zich inmiddels met het probleem beziggehouden.

Hun aanbevelingen getuigen echter van een verbijsterende onbenulligheid. Na hun observering dat de gemiddelde student onvoldoende geinteresseerd is, hebben zij vastgesteld dat dat komt omdat diezelfde gemiddelde student onvoldoende gemotiveerd is. En als remedie tegen dit euvel bevelen zijn aan, dat wij wat meet "motivatie" in onze colleges doen. Alsof specerijen een onverteerbaar gerecht kunnen redden.... Zo adviseren zij ons in het wiskundeonderwijs, dat voor de andere afdelingen verzorgd wordt, de voorbeelden steeds aan het vakgebied van de betrokken afdeling te ontlenen; dezelfde differentiaalvergelijking wordt de bedrijfskundigen als marktmechanisme, de physici als trillingsverschijnsel en de bouwkundigen als maatschappijmodel voortgezet. Het studentenbeeld, dat aan deze remedie ten grondslag ligt, is van een voor U beledigende bekrompenheid. Nog erger is, dat de remedie niet werkt: het verhoogt nl. de schijn van directe bruikbaarheid, en die schijn was juist wat het college zo weinig inspirerend maakte.

Ik zal mij dit semester dan ook niet alleen verre houden van op de campus aanwezige apparatuur, maar ook mijn voorbeelden zullen nergens iets mee te maken hebben. Moge dit college zowel voor Uw als voor mijn plezier gegeven worden!

transcribed by F. Koenders
revised Thu, 13 Nov 2008

Copyright Notice

The following manuscript

EWD 584: Tripreport E.W.Dijkstra, Poland and USSR, 4-25 September 1976

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 235–244 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 584

Tripreport E.W.Dijkstra, Poland and USSR, 4-25 September 1976.

Because I had to check in at Schiphol Airport at seven o'clock in the morning, I went to Amsterdam the previous evening and slept in Hotel Frommer quite near to the airport. As the courtesy coach leaving the hotel at 6.30 was my target, I set my alarm clock at 5.45. When I entered the breakfast room at 6.00, however, I knew with devastating certainty that half an hour later we would have transport problems. I decided to be one of the first arriving at the coach, finished my breakfast quickly —which was no problem, for it was of sub-airline quality— and made for the coach. Some time later I had the satisfaction of observing that my prediction had been correct. The Lufthansa flight to Warsaw —with a stop in Frankfurt— was smooth and pleasant; besides that I was served a breakfast distinctly better than the one I had just discarded.

In Warsaw I had my first confrontation with totalitarian bureaucracy: it took me more than one hour to pass customs and immigration. As soon as I had left the official area, I was greeted by dr.Ian Madey, who was quite surprised to see me: he was waiting for someone else. (As he is about the only Pole I know, I had assumed that he had been sent out to collect me.) The process of collecting arriving participants was of a refreshing informality. (Later I understood why: these Symposia on the Mathematical Foundations of Computing Science are visited yearly by a very inbred crowd: everybody knows everybody!) With my host, prof. Antoni Mazurkiewicz, and two others, I had an improvised lunch in Madey's apartment that was quite close. Half past three we joined a coach that had collected participants from Warsaw Airport and Warsaw Central Station, and then we were on our way to Gdansk, where we arrived at 22.45. After a late supper I stumbled into my bed: seven hours in a coach —on Polish roads and seemingly without shock absorbers— is no fun.

The trip, although tiring, was interesting. It confirmed the impression I had received while looking down from the plane: every square inch of Polish soil is cultivated if possible. As we approached Gdansk the many little farmhouses were gradually replaced by fewer larger farms. The explanation is probably to be found in the time that Gdansk was still Danzig and export of grain enabled the farmers to become richer, the closer they were to the export harbour.

It is quite clearly still a poor country, even thirty years after the war. Ian Madey's apartment was well-kept and well-furnished —most of it pre-war furniture, I thought— but small. Private cars are a rare commodity, a private car in a reliable condition seems exceptional: during that coach trip I saw at least ten cars stuck with mechanical trouble. Mazurkiewicz, who made the trip from Warsaw to Gdansk in his old Volkswagen, told me in Gdansk that half-way he had had to extinguish a fire in his car, and four days later he had not been able yet to have got it repaired. The dinners at NOVOTEL were of a depressing tasteless monotonicity, at breakfast a single cup of coffee was the only fluid served, for a second cup one had to pay. The NOVOTEL building, however, was new and comfortable; it seemed an exact copy of the other hotels of the French (!) NOVOTEL chain.

It was quite clear that among the people I met, "the system" has very little sympathy, but they seem to have discovered a way not to suffer from it too much. It seems to be accepted as one of those unavoidable things —more or less like a climate— , they made the impression of being reasonably happy in spite of it all. The Polish sense of Humour is in any case exquisite.

The Symposium was one where I —although an invited speaker— did not really belong. (I would not have accepted the invitation, hadn't it been for the fact that I could drop by on my way to Moscow.) I was invited to act as session chairman on the first Monday morning, which, of course, meant that I could not escape. After lunch I was still so tired after Sunday's travels that I went to my room for a little nap. I fell asleep and missed most of the afternoon's talks, but all people I have asked have assured me that I had not missed much.

I was Tuesday morning's first speaker. On the previous evening there had been a reception; because I felt that I might have to address a hundred hangovers, I made a special effort of it. The conference proceedings had been handed out on Sunday evening. It contained the text I had prepared which —being perfectly readable by itself— had already been read by many participants. It seemed silly to read that text aloud, so I gave a completely new talk under the title "Back to Nature, or Two Cheers for Simplicity." It went well. The end was totally new for a large fraction of the audience, because I ended up with the development of a little program, and many of them seemed never to have seen a program in their whole life.

This was the shortcoming of the whole symposium. There was a minority of computing scientists and a majority of mathematicians who really believed —or at least: behaved as if— that they could contribute anything relevant to the mathematical foundation of computing science without knowing enough about the latter subject. (A Flemish speaker demonstrated his unfamiliarity in a way that amused me very much. After having seen me as session chairman on Monday, as invited speaker on Tuesday, he discovered in my presence on Wednesday morning to his surprise that I was Dutch. After a few hours of Dutch we switched back to English because others were present; he then asked me the polite —at least: politely intended— question "What is your area?" I could not resist the temptation to answer "Computing Science".) Years ago the power of the Polish mathematical and logical establishment and its tendency to strangle computing science had already been explained to me, so I was not too surprised when one of the organizers told me that they hoped to have established themselves to such an extent —this was their 5th Symposium— that next year automata theory could be deported to a separate symposium. I hope that they succeed, for they deserve to be freed from that form of pure mathematics that seems more like a bureaucracy: a self-perpetuating activity, masochistically in love with its own, self-inflicted complexities.

I quote —because it is so typical— the opening sentence of the Conclusions of one of the invited speakers (Wilfried Brauer, Hamburg: "W-Automata and their languages."):

"The theory presented here may help to solve some more known problems; it gives rise to quite a number of new questions and it offers several ways for future research:..."

Also de Bakker ran true to form. He proudly demonstrated a proof rule for the PASCAL procedure call without the restrictions on the parameters that Igarashi, London and Luckham had introduced. As his new proof rule has the consequence that one cannot prove the correctness of the procedure in isolation, but may in principle need different proofs for the different calls, any reasonable man would conclude that the Igarashi-London-Luckham restriction is such a wise one that we may speak of a flaw in the design of PASCAL. But de Bakker emphatically refused to draw that conclusion! (Without going into details, however, I like to mention also, that I had reason to admire de Bakker's political courage.) Good talks were presented by Mazurkiewicz (Poland) and by Berthelot and Toucairol (France!). Nivat also arrived.

*         *         *

My departure from Poland was less successful. I had to fly all by myself from Gdansk to Warsaw, where I had to catch my connection to Moscow. The first flight was delayed and —knowing no Polish— I found it hard to discover how long the delay would be. The distance between the airports or arrival and departure in Warsaw was —fortunately!— small. The transfer was not pleasant, because the man from the Polish Academy of Sciences that picked me up did not seem to like that job at all. After I had checked in and had passed emigration, I came into a real chaos when we had to guide our own luggage through customs. I nearly lost my balance and luggage in a pushing crowd of a few hundred Poles. Embarkation time was approaching and just when I was wondering for the tenth time whether I would get through in time, the baggage handlers of the airport solved the problem by placing all the unchecked luggage on the belt. I was then pushed into the departure hall, from there through a gate —that neither mentioned Moscow, nor my flight number— a very stern and cross lady —well, lady...— at the gate tore my boarding pass into two, from there I was pushed into a coach and from there into a LOT airplane. We took off before the scheduled departure time, but when the announced flying time did not seem to be correct either, I suddenly got alarmed, wondering whether I was flying to, say, Bucarest! I was greatly relieved when a stewardess could confirm that I was, indeed, on my own way to Moscow. It was my first flight on a Tupolev and it was a very pleasant one. Disembarkation again had more resemblance to cattle being driven out of a waggon. As I had no Moscow address of my host, nor a telephone number —only Andrej Ershov's promise that he would meet me at the airport— , I was greatly relieved to see him before I had passed customs and financial formalities: the officer spoke English and was courteous and helpful. After my Polish experiences this was a pleasant change; later I would learn that inside the USSR such courtesy also seemed very rare.

I was met by Andrej Ershov and Sergej Pokrovskii from the Computer Center in Novosibirsk —they would accompany us on the whole trip— and an older colleague from Moscow who drove us in his new, first car —only 800 km done— to the Hotel of the Sovjet Academy of Sciences. The driver's uncontrolled way of changing lanes made the trip a nerve-racking experience; before his new car is 1000 km older I am sure that he will have an accident.

Then our grand tour started. After two days, Tony Hoare from Belfast joined us (on Saturday evening). On Monday night we went from Moscow to Kiev, on Thursday night we went from Kiev to Leningrad, on Sunday night we went by train from Leningrad to Moscow and from there by plane to Novosibirsk, where we performed for the next two days. On Thursday morning we left Novosibirsk; Tony stayed a further day in Moscow, I left Moscow on Thursday evening for Amsterdam (again via Frankfurt) where I arrived at a quarter to eleven in the evening, pleasantly surprised to find my wife with the car at the airport: instead of another night in a hotel, we drove back to Nuenen and arrived home at a quarter to one in the middle of the night. I just dropped into bed, slept until ten o'clock next morning; taking a real hot bath, I realized that I still saw memories of mosques, icons, cots in the mud and policemen, yeah, policemen everywhere: they still haunted my memory....

The general pattern of our visits to those four towns was a lecture by Tony, a lecture by me, a public performance of both of us for a large audience, one or two "scientific discussions" and an official dinner —with vodka, caviar and toasts— with our hosts. We have worked hard: our lectures were between two and three —mostly three— hours. Andrej had counted the number of our performances and had added the audience sizes. On our last day, when visiting prof. Marchuk, the Director of the Siberian Branch of the Sovjet Academy of Sciences, he proudly reported that in seventeen meetings we had addressed over 2500 people. Under normal circumstances that kind of quantitative reporting would have amazed me, but this time I just noticed it, for it was exactly what in the meantime I had learned to expect. (This is what one expects in a society that tries to leave the Middle Ages by means of five-year plans; I was not surprised at all to observe Marchuk swallowing these numerical data as if they were highly relevant.) All our lectures went very well. (Only at the beginning of my first talk panic seized me: standing in front of a fully packed auditorium with two blackboards I discovered that with the Sovjet chalk I couldn't write on them! After a delay of a few minutes someone had liberated two miserable pieces of chalk that were slightly better. It was with grim satisfaction when, a week later in Leningrad, I saw a Russian wrestling with the same problem.) It was my first experience with addressing an audience via intermittent translation; when Andrej did it —and that was nearly always— it worked beautifully. He often seemed to enjoy it, he was clearly much more then just an interpreter. (In Kiev I started with "just an interpreter", but within five minutes Andrej took his place.)

Our "scientific discussions" were more difficult. On the first Saturday morning I had such a discussion all by myself, because Tony had not arrived yet. We had chosen "computer science education" as its central theme because I wanted to check a remark in a recent advice to the US Government, viz. that in the USSR programming was taken very seriously and was primarily done by people with a solid mathematical background. I found that remark confirmed. The only difficult moment during that discussion was when my opinion about mechanical verification and further Artificial Intelligence work was asked. It was a difficult moment, for I had already discovered many years ago that the amount of support for AI-projects in particular says less about the intrinsic merits of these projects but much more about the political climate that supports them. Suddenly Andrej needed twice as much Russian to translate me. Twice we have had a discussion about one of their microprocessor projects, but that was nearly impossible. It reminded me of my discussion at IBM Hursley in the early seventies, shortly after the THINK-notices had been replaced by warnings to keep company-confidential matters secret, and the IBM-er who wanted my advice got, just when I arrived, a telephone call reminding him that he was not allowed to tell me anything, not even to formulate his question. In the USSR it was the same crazy game of hide-and-seek. How can you comment on something when they don't tell you what to comment on? They either feigned not to understand the question or gave a null-answer —"This will depend on the circumstances." etc.— Eventually we extracted that they proposed a tree-like "store-and-forward" communications network of about one hundred microprocessors, each with its own clock of about 30 MHz. (When I asked the clock frequency, a long discussion in Russian started: Tony, who speaks Russian, told me later that they were discussing among themselves whether they were allowed to answer my question.) I told them that I did not expect that it would work, because I expected glitches all over the place. They then started to explain why they were sure that that would not be the case. From the explanation I got a strong impression that they hardly understood the phenomenon, but I felt no longer tempted to give further explanations.

It is undoubtedly true that I observed a strongly mathematical approach to computing science, but it seemed to me to be mathematics of the wrong kind. Very pompous, with Roman, Greek and Gothic alphabets —Andrej complained about the "indexomania" in his country— and void of any simplicity or elegance. A "machine" is at least a ten-tuple, and all their work seems soaked with more and more elaborate computational models. I remember the man who proudly told us that his computational model distinguished between no fewer than five (!) different kinds of store. In short, it seems all highly ineffective. I got two explicit indications, that mathematical elegance is not regarded as very important (a decadent capitalistic luxury?). It will take a long time before they will discover that in computing science, elegance is not a dispensable luxury, but a matter of life and death.

I was surprised by the susceptibility —or should I say: vulnerability?— to foreign (primarily American) influences. Jack T. Schwarz was touring the USSR for the n-th time in order to keep the Russians up to date on the latest developments of SETL. (Was this part of some sort of Helsinki treaty between the USA and the USSR?) On the one hand I know that many people have grave doubts about the whole SETL-project (and I know some of the reasons), on the other hand it was strange —nearly alarming— to see that in the USSR Schwarz was taken absolutely seriously. In Leningrad I discovered that they had been misguided enough to invest God knows how much in an implementation of.... ALGOL 68 for the Russian 360! In Novosibirsk a group had recently embarked on automatic program verification etc., very much in the line of London c.s., without any tangible justification for the hope that they should do any better. During our lunch with Marchuk, the latter asked our comments after he had explained why computing science in his opinion was such an important field, an explanation that was no more than a reiteration of the Artificial Intelligence hopes! (John McCarthy, too, is a regular guest in Novosibirsk.) I could only comment by quoting George Polya, that infallible rules of discovery would work magic, but that there is no such thing as magic. (Under such circumstances, quotations are very useful: they enable one to give unwelcome answers without being rude.)

Tony gave a very plausible explanation: no matter how doubtful they are, they just cannot afford to leave a Western exercise unexplored, for suppose that those capitalists book a significant result! I think that that explanation is correct. It seems in full accordance with Andrej's attitude, which is one of extreme tolerance, combined with a tendency to collect a wide variety of documents. (The size of his personal library in the institute was most impressive.)

The departure from Moscow was again a chaotic affair: I was taken to the airport by a young Russian who spoke some English but was unable to explain to me how I should proceed and what formalities I had to go through in what order. I flew back in a Lufthansa plane, mainly filled with Germans who had had a trade exhibition. The tension began already to discharge at the gate: still three policemen to pass and we shall be free again... There was a clear sigh of relief when the plane took off.

*         *         *

Some random remarks.

My first impression of Poland in the evening was that it was extremely well —not to say: over-brightly— illuminated, and I thought "They must be very concerned about the well-being of the average citizen to light his path so well." On closer inspection the illumination was always on parking lots, timber yards and the like. It was clearly a protection against theft and my Sportstourist guide that saw me off to my plane to Warsaw did not make a secret of this fact. In the USSR the same bright illumination; in Moscow I even saw that most cars were parked with their wiper blades removed (and even little plastic covers on the arm tips). When my guide showed me a row of parked cars and said proudly "All Sovjet-made." I could not resist the temptation to ask maliciously, whether the wiper blades had been removed as a protection against theft. Answer: "I don't know; I don't have a car." After having verified my conjecture I told him later that day not to behave like a bloody fool. He took the hint and was, from that moment onwards, quite honest. He was not a party member, although (nearly pathologically) nationalistic. I had already observed this, he himself had observed that trait as well. He confessed this with a very curious mixture of pride and shame. Later he told me that —although he had had ample exposure to Frenchmen and Americans— this was his first confrontation with "northern Western Europe" (i.e. Tony and me). He had been afraid and had found the first few days very difficult. (The fact that Tony and I knew each other so well was, of course, an added difficulty.) The next time I go there —I am not sure at all whether there will be a next time: an invitation for next year has been declined without the slightest hesitation!— I shall take, say, a fresh Herald Tribune and Le Monde and Times with me: our guide was absolutely thrilled when he found in the Intourist Hotel in Leningrad a six-day old copy of Le Monde in the shop: he immediately bought it and said to me "I would never have believed that possible."

*         *         *

A few remarks about "the sociology of science" or "how to make a career". A young mathematician who lectures in Poland on EOL's and ETOL's etc. told me his motives for entering automata theory. He did not particularly like the subject, nor had he any belief in its relevance. But he found the subject easy, had observed relatively little competition and in his country he could earn a living with it because the university authorities confused it with computing science anyhow. At first I was shocked by his cynicism —he was a young man with most of his life still before him— at second thought I found it harder to blame him: he was perfectly honest about it and I could only pity him for having so few illusions (although, of course, this may save him some disappointments).

Next I observed a systematic application of the saying "In the land of the blind the one-eyed is king.". People try to make careers in computing science by frequenting in this respect underdeveloped countries and obscure conferences. I had seen a few of such cases in Western Europe, behind the iron curtain the phenomenon is very pronounced: it was sometimes embarrassing to hear which of my countrymen had frequented their places. And then the man who, later this fall, would go for a month to Singapore to lecture about Lindemayer systems! That must be just what they need...

*         *         *

A KLM purser told me the other day —or was it night? it was one of those circumstances under which one is never quite sure which is which— a story about a cooperation agreement between KLM Royal Dutch Airlines and Aeroflot. In preparation of the cooperation nearly 30 KLM employees —among whom my purser— learned Russian. My purser had been one of the first to serve on a flight with a mixed crew. As soon as the Sovjet, however, discovered that the Dutchmen they cooperated with understood Russian, the agreement was cancelled! It is frightening to observe such a large nation to be so nervous and so uncertain, but after my recent experiences over there I have no problem at all with believing my purser's story.

*         *         *

I have been shown many cathedrals and monasteries, in Leningrad mummifying caves in which an underground monastery had been built. It breathed the spiritual atmosphere of the Dark Middle Ages, but that underground monastery had had its heyday in the eighteenth century. It was crowded with mostly Russian tourists, at the exit was the Marx quotation about religion and opium, and a nearby church was now a Museum for Religion and Atheism. They have very mixed and ambiguous feelings toward religion, also cramped. After a week Sergej asked me, whether I was a Christian; what else could I do than asking him whether he was a Communist? (We both answered "No.") I found that cramped attitude towards religion irritating and even a little bit sickening. Of antisemitism, I am happy to say, I have personally observed nothing. This in strong contrast to Hungary in 1968, where I found the open antisemitism appalling.

*         *         *

Like a good boy I had decided to write my wife a long letter from each of the towns I would visit. So I wrote a letter from Gdansk, a letter from Moscow and a letter from Kiev, but then I heard that they would take at least ten days to arrive, because they would be opened and that, apparently, is a time-consuming process. (Upon my return I could verify that both rumours were indeed correct: they had taken ten days to arrive and they had been opened! The shocking thing was that they were not stamped "Opened by censor", on the contrary: they had been opened and reclosed carefully, but I had taken a few precautions and it was absolutely certain that at least one of the Russian letters indeed had been opened! I had written them in the kind of double-talk, with which no Russian censor could find anything at fault, at the same time certain that my wife should understand.)

In Leningrad I realized that writing letters would not make much sense anymore, so I ordered a telephone call for Saturday evening between 21.00 and 22.00. I was in my hotel room all the time, waiting, but nothing happened. So next morning I sent a telegram. The girl at the counter was cross, maybe because the price of the telegram was something like her weekly wage. The text is a true reflection of how I felt:

dear ria heard my letters from moscow and kiev not expected to arrive before my return telefone effort from leningrad failed hence cable saying still alive bowels reasonable eyesight good trip tiring interesting and depressing talks went like clockwork and very well received hosts as pleasant as they can be guided tours past historical buildings closest approximation of hell imaginable thank heaven tony is here sunday morning working together kiss children also yours longing to be home edsger

It seemed a reasonable way to spend my rubles!

*         *         *

I did my best to behave as one should in bugged rooms, but I found it difficult. I remember that, when I asked the IBM-er in Hursley whether the room in which he received me, was bugged, the IBM-er orally protested "No, of course not." while nodding affirmatively. Similar situation while I paid my compliments to the Dutch embassador in Moscow. I remembered never to comment on our Russian hosts but when, in Moscow my hotel room I started to explain to Tony the type of computer architecture I had been thinking about lately, better trained than I Tony immediately suggested a walk. It did not rain and we walked for nearly two hours. It took Tony a long time to grasp the idea, so it might be a little bit revolutionary. Eventually he got quite excited, but agreed that several critical issues have to be investigated rather carefully, before the idea can be proposed as a realistic one. Then we returned to the hotel and went to bed.

*         *         *

To fill a page a quotation from my diary (Leningrad):

"Friday was a tiring day for me. Morning lecture of three-and-a-half hour (fifteen minutes break included). Well-prepared talk on the importance of nonoperational definition of programming language semantics went like clockwork. (First time I gave that talk.) In the afternoon we were exhibited for an audience of about 400 people in the University auditorium, together with Jack Schwarz, who was selling SETL. Schwarz's "position statement" contained expressions such as "...a large mess of structure..." and "automatic choice". When later confronted with these quotations he answered "crudity is the characteristic of language". Speak for yourself, Sir! But if that is his attitude, my revulsion fully explained."

16th October 1976 NUENEN - 4565             Plataanstraat 5 | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 29-Sep-2011

Copyright Notice

The following manuscript

EWD 585: Tripreport E.W.Dijkstra, Tokyo, 28 Sep.-3 Oct. 1976

is held in copyright by Springer-Verlag New York.

The manuscript was published as pages 245–250 of

Edsger W. Dijkstra, Selected Writings on Computing: A Personal Perspective, Springer-Verlag, 1982. ISBN 0–387–90652–5.

Reproduced with permission from Springer-Verlag New York. Any further reproduction is strictly prohibited.

EWD 585

Tripreport E.W.Dijkstra, Tokyo, 28 Sep. - 3 Oct. 1976.

(Tokyo, Thursday morning six o'clock local time, and hopelessly awake.)

I left Nuenen last Tuesday a few hours after my lectures in the morning and plan to be back in time for my next week's performance. On Monday I spoke the Dean of the Faculty, who remarked that for the kind of life I was living I needed an iron constitution. I must disappoint him: I haven't. It is still warm in Tokyo. In my hotel room I found a kimono on my bed, ready to be used by the "dear guest"; the airconditioning is cooling so frantically that, indeed, I have put it on. The thermostat in my room is set to 30 degrees: I conclude that the cooling is totally independent of its setting.)

I flew from Amsterdam to Tokyo via Anchorage, Alaska, for refuelling (8.5 + 7 hours). In Anchorage the crew was refreshed, but I felt that the passengers were in an equal need of being refreshed: it was a very long flight. On the first stretch the hostesses acted as waitresses, on the second one more as nurses.

Landing in Anchorage was a surprising excitement. I had never expected that an intermediate stop would cause such a thrill, but I can only summarize my impression of Alaska by saying that you won't believe it until you have seen it —and even then it is hardly believable— . A fantastic river delta, with uncountable streams winding their way between black rocks via mud into sea and white, cruel mountains along the horizon: an unbelievable sight! The airport itself was disappointing: after my most distressing experiences with Soviet toilets —more precisely: the absence thereof, at least of usable ones— I set my feet on American soil with great trust and confidence. In Anchorage, however, the confidence is unwarranted: it is distinctly less clean than California —or my home country for that matter—.

(Amsterdam, Monday morning 0.20, Hotel Frommer.)

The whole trip was somewhat exhausting. The conference was on Thursday and Friday, I arrived in Tokyo on Wednesday evening and was due to depart from Tokyo Saturday noon, and would be back on Sunday morning. When I arrived in Tokyo at the Okura Hotel at 8 pm., tired and dirty, I was faced by five hungry gentlemen who had waited with their dinner for me. I did not quite know how to refuse in a sufficiently polite manner, had a ten-minute shower and then we were taken to a Japanese restaurant, where a few hierarchically high-placed gentlemen were waiting for us. After a tea ceremony, they left, we six had to go on with our dinner. Then two days conference —about which later— and then back home, but the return trip was a disaster.

Saturday morning —I was already awake at four o'clock— shortly after I had checked out at 9.15 and was waiting for Mr. Haruyasy Nakayama to see me off at the airport, I got a telephone call that the plane, instead of leaving at noon, would leave at 9 pm. Nakayama helped me to kill the morning by taking me and Weber —a speaker from the USA— on a trip in his car through the imperial gardens. Weber had kindly given me the key of his hotel room where I slept from 1 pm to 5 pm. Those four hours were very welcome, as my night had been bad. At seven a car took me to the airport; Nakayama could not accompany me, as he had another appointment, so there I had to fight my battle unassisted. First I could not find the KLM desk, but eventually I discovered a little notice that JAL took care of that. There were two special first-class counters, I was helped very quickly and received a card with an invitation from KLM to rest and have a drink in the first-class lounge. I was looking forward to it, for my experience in the first-class lounge at Schiphol had been excellent. There was a terrible queue at customs and emigration but the prospect of the first-class lounge sustained me all through the proceedings. When, at last, the final formality had been completed, I found myself in a dirty, crowded international departure hall in which clear indications as to which flights left when via which gates were lacking —the quality of the sound system was poor— and discovered that the first-class lounge which I now needed more than ever... was at the other side of the customs/emigration boundary! Neither peace, nor a drink were my share and I was greatly relieved when, 15 minutes later than announced previously— I recognized the call for my flight and the embarkation procedures started. They used crowded coaches, it took a long time, it was warm and people were smelly (garlic?). Eventually I sank in the cushions of my seat in the first-class compartment of a KLM Boeing 747 and felt much better. At that moment I did not even mind to hear that we would take the southern route and that I was 28 hours away from Amsterdam, at that moment it only meant for me that I could enjoy the KLM care for twelve hours more than on the first flight. We would have three successive crews and intermediate stops in Manila, Bangkok, New Delhi, Dubai and Athens. Until New Delhi everything went fine but for the fact that three expensive, but also talkative and smelly Japanese passengers did not leave the plane in spite of all the opportunities they had had to do so.

In New Delhi the real misery started. During take off —we had not been allowed to leave the plane— shortly before the point of no return, a huge bird disappeared in one of the engines, The pilot managed to slow down again and to stop before the end of the runway. We were taken to New Delhi International Departure Hall —which was described as airconditioned: it had fans circulating the hot air— and it was only after five hours of uncertainty that we heard that, probably, we could leave with the same motor. (Otherwise the delay would have been at least another twenty-four hours: "Air India might have a spare motor in Bombay that KLM could borrow".) The idea of twenty-four hours in New Delhi did not attract me at all: knowing that my bowels are the weak part of the equipment, having neither tropical nor South-American experience, and having seen the cockroaches crawling over the carpets of the International Departure Hall, I was in low spirits. (Besides that I was now sticky all over, as the chairs on the hall were covered with plastic.) The second time we took off from New Delhi we did not catch a bird and it was only then that I heard, how narrow my escape from a long delay had been: if the delay had been longer than the six hours it was, the crew would not have been allowed to continue the flight before having rested. It is past one o'clock: and so to bed!

*         *         *

Quite apart from the pains —see above— of physical displacement, do I regret this trip strongly. One thing is certain: I have been lured into acceptance of the invitation on false pretences. I was invited for the "5th International Symposium on Information" but I cannot call a symposium where three non-Japanese speakers participate "international". It was organized by JIPDEC, standing for "Japanese Information Processing Development Center". JIPDEC had not invited me directly, I was approached on JIPDEC's behalf by the Scientific Attache of the Royal Netherlands Embassy in Tokyo. It was the N-th Japanese invitation, I had been able to withstand the first N-1; I have now learned that the intervention of one of our Embassies is no guarantee. The scientific attache has misjudged JIPDEC, me or both.

The symposium consisted of three half-day sessions, one on Thursday afternoon, and two on Friday. Each session consisted of a one-hour speech by the foreign speaker, an interval, followed by comments from a Japanese panel; finally the first speaker could comment on the comments. The Americans were scheduled for the first sessions, I had to perform on the last one.

By the time I had to perform I was very depressed: until that moment the yen had been the unit of thought! And this was not the consequence of the fact that the two American speakers —one spoke on computer audits and the other on decentralization of banking administration— were from the financial world. The symposium was opened by Japan's most famous economic commentator. I found the whole happening very curious. I was reminded of the keynote address by Vincent Learson at an ACM Conference in 1972. Learson (of IBM) argued then for a full hour that it was the task of computing science to assist in maintaining the American economic supremacy in the face of the Japan threat, a threat so serious, that it was our scientific duty to assist IBM in its calling to save the country. (Even for an all-American audience that talk by Learson would have been shocking: it was so bad that afterwards many Americans came to me in order to apologize for it.) Here in Tokyo the same story, only still worse: microcomputers had been invented in order to save the fragile Japanese economy (and no one apologized this time). Quite typically, it never became clear whether the production or the use of microcomputers should save Japan!

The whole symposium struck me not as a real symposium, more like a Kafkaesk simulation of a symposium. The Japanese panel members —four per panel and each member spoke for about a half hour— were absolutely terrible. They did never produce anything more than a concatenation of vague motherhood statements, and repeated themselves all the time. In Japanese they may have said the same thing three times with different words; there is the possibility that limitations of the English vocabulary of the interpreters caused these repetitions to sound more like each other than in the original, but I don't think so, for the interpreters made a very competent impression. I think that they really repeated themselves. (One of the Japanese panel members confessed before speaking in private that he did not really know what to say: nevertheless he used his full half hour!) I really should know more about the Japanese language, I think that there is something very wrong with it. Andrej Ershov had warned me that the times to express something in English and Russian respectively are as 7 to 10; Nakayama told me that for English and Japanese the ratio was 1 to 2. Listening to the interpreters I could believe it.

Seemed the speakers to be fake, so seemed the audience. On the first afternoon I have scanned the audience, and about 20 percent was fast asleep, with another 20 percent vigorously yawning. (Also this has been explained to me: many live far away and have to travel long in the morning and the evening. As a result they are very tired.) Four-hundred people going through the motions —and the non-motions, for that matter!— and not a single solid thing said. I felt like in a madhouse. Addressing such an audience is no fun either: neither of the two Americans had been able to get any reaction from the audience. I can be very proud of my record: the audience had laughed once or twice and I even got two questions from the floor. I have been told that that was very exceptional, and I well believe it, for it felt like addressing a hall full of mummies.

It was all so strange that, perhaps, I misinterpret totally what I have witnessed. It was my definite impression that the panel members had not been selected for their professional competence, but on account of their high position in the hierarchy: they had all the most important functions, but did not say a thing. Has the audience been selected on the same rules? I don't know. They seemed to be manager types of low quality. I have observed that crowd during the interval, when coffee was served. It certainly did not look as usual at the interval of a scientific meeting, but perhaps that is the way in which a crowd of 400 Japanese behave, even if they are scientists....

I was also amazed by the ease with which they seemed to have adopted the new religion of computer networks. That the design of properly operating computer networks presents some difficulties clearly did not count. And that, even if you have it operating properly, it is not always clear how to use the facility at considerable advantage, was also ignored. Networks of microcomputers were going to save the country. This was the new dogma. One must hope that from experience that Japanese know that all these words are just words, for if they really believe what has been said over and over again, it is frightening. (I think that they are not used to require from language that it is really meaningful. A great number of English computer jargon terms have been incorporated in the Japanese language without translation, just copied. It was illuminating that all the meaningless buzz words and vague, dubious terms were included such as "program maintenance", "the user", "intelligent terminal", "System Analyst (or SA)", "Systems Engineer (or SE)", "data structuring", "structured programming (or SP)", "multi-level hierarchy", "concept"(!) etc. All these words, pronounced with an accent, that is true, are nowadays perfect Japanese!

*         *         *

On Thursday evening the Dutch Community in Tokyo —about 350 people— came together (this time devoted to the annual commemoration of the end of the Siege of Leyden, which meant "hutspot" and "rauwe haring", the latter dish freshly flown over by KLM). I went there to satisfy my curiosity; I joined that crowd for about two hours, it was quite interesting. Then I was picked up by the Scientific Attach� and his wife and had a quiet chat in his apartment, which gave me a glimpse of an unfamiliar world. They lived quite near the Russian Embassy and it was shortly after the MIG 25 had landed in Japan. It was a very nice evening, but, no matter how nice and interesting, an insufficient justification for the whole trip.

*         *         *

The last item but one on my schedule mentioned for Friday evening:

"Mr. Zapf, President of Burroughs Japan, wishes to have the pleasure of inviting Dr. Dijkstra for informal dinner."

Waiting in my hotel room for Mr.Zapf to call, he did indeed call at 7 pm., terribly embarrassed. He had a business meeting and had heard of this arrangement just a few minutes ago. Linguistic problems had clearly caused some communication difficulties, I told him not to bother and had an excellent dinner together with Weber, did some writing and went to bed.

*         *         *

One of the questions from the floor was a question that had been posed to me several times in Russia: "But what about the education of the average programmer?". On my way to Novosibirsk I decided to give from now onwards the same standard answer. The question was put to me in Novosibirsk and there it worked. It was also asked in Tokyo, and there worked beyond expectation (because the audience laughed). The answer was the counter-question "What about the education of the average mathematician?"

Plataanstraat 5 NUENEN   NL-4565 The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 29-Sep-2011

EWD586

Tweede toespraak tot mijn studenten, najaar 1976.

Het moet moeilijk zijn om een capabel kabinet samen te stellen. Ter informatie van de volgende kabinetsformateur: ik wil hem wel van advies dienen —gratis zelfs—, maar stel mij persoonlijk niet beschikbaar.

Het grootste probleern bij de kabinetsformatie is de keuze van premier en vice-premier. Het is duidelijk dat deze leidende functionarissen op allerlei gebieden, zoals b.v. omroepen en aborteren, hoewel kabinetten er over kunnen struikelen, geen enkele deskundigheid hoeven te bezitten: de omroepverenigingen gaan gewoon door met hun ethervervuiling en geaborteerd wordt er toch. Het moeilijke punt is, over hoeveel kennis van de economie zij moeten beschikken. Als ze er niets van af weten, kom je in de ellende van Engeland en Italie, wier bankroet, met al zijn onheilspellende repercussies, als een dubbel zwaard van Damocles boven het hoofd van Europa hangt. En wat, als je een doctorandus in de economie neemt? Ja, dat moet U niet vergeten! We hebben het altijd zo familiair over "onze Joop", maar per slot van rekening is hij doctorandus in de economie, al zou je het misschien niet zeggen... Voor wat zich in ons land afspeelt lijkt "inflation by natural gas" een passende beschrijving.

Nou kan je over een doctorandustitel je schouders ophalen, zoals Wim Kan, die hem "het middenstandsdiploma voor politici" noemde; en we weten allemaal, dat een middenstandsdiploma nog geen succesvol winkelier maakt. Zouden we beter af zijn met een echte econoom?

Dat is nou precies het dilemma voor de volgende kabinetsformateur. De ellende is nl. dat een echte econoom ook niet alles is. Wee landen als de USA en Japan, waar de dollar, respectievelijk de yen als eenheden van denken geaccepteerd lijken. Een van de griezelige gevolgen daarvan is, dat het onderwijsbestel op allerlei wijzen aan het economische gebeuren ondergeschikt wordt gemaakt. Dat gebeurt hier natuurlijk ook wel een klein beetje, maar per slot is onze Joop maar doctorandus. Het gebeurt hier bv. wanneer op salarissen van onderwijzend personeel beknibbeld wordt, omdat de bodem van de schatkist in zicht is. Maar dat is zwakke onderschikking vergeleken bij die systemen, waarin het onderwijs specifiek de opdracht heeft de am economische reden gewenste werkkrachten af te leveren.

De neiging zelfs het hoger onderwijs primair als beroepsopleiding te willen zien is ook hier al te bespeuren, maar de neiging is nog mild; het is alsof de doctorandus bij wijze van spreken een schuchtere eerste stap naar de promotie heeft gezet. Als deze opvatting van het hoger onderwijs als beroepsopleiding evenwel helemaal de overhand krijgt, dan worden de kosten van dit onderwijs in het economen-hoofd —hoe kan het anders!— als productiekosten geboekt. En elke econoom weet, dat je, om competitief te blijven, de productiekosten hoort te drukken. Dus: hoe minder onderwijs nodig, hoe beter, en de volgende stap is, dat men probeert het productieproces zo te veranderen, dat men met slechter opgeleid personeel uit de voeten komt: in het Amerikaans heet dat "the deskilling of a function".

Kortom: zodra het economisch denken het onderwijs aan het economisch gebeuren onderschikt, zal datzelfde economisch denken proberen dat onderwijs overbodig te maken en uit te hollen. Ik dacht niet, dat de functie van het onderwijs louter was de economie draaiend te houden; integendeel: het is de functie van de maatschappij onze beschaving in stand te houden.

Ik ben bang, dat ik toch eens met de volgende kabinetsformateur zal moeten praten. Wellicht is onze Joop al verder met zijn proefschrift, dan velen vermoeden.

transcribed by Carl Ludwigson
revised Wed, 14 Nov 2007

EWD587

Derde toespraak tot mijn studenten, najaar 1976.

Soms kan ik me erg goed voorstellen hoe onze paragnost Croiset zich geregeld voelen moet, beschikkend als hij doet over zekerheden, waarvan anderen niet begrijpen, hoe hij er aan komt. Zo'n uitzonderingspositie geeft aanleiding tot een wijd scala van reacties, en ze zijn bijna allemaal vervelend: enerzijds adoratie en pijnlijke overdrijving, anderzijds wantrouwen en de beschuldiging van charlatannerie.

Maakt U zich geen zorgen, ik ben geen telepaath, geen gedachtenrader en geen helderziende. Ik heb maar van één gave last: ik blijk meer dan de gemiddelde Nederlander tussen de regels te lezen en meer informatie te ontlenen aan de manier waarop anderen zich uitdrukken. Elke mededeling die mij gedaan wordt is automatisch de draaggolf voor een tweede boodschap: naast wat iemand me zegt hoor ik altijd hoe iemand dat zegt. Dat geldt natuurlijk voor iedereen, ik heb alleen waarschijnlijk geleerd er wat sterker op te letten dan de meesten.

Tot mijn verbazing heb ik moeten ontdekken, dat er ook mensen bestaan die voor deze impliciete schaduwboodschappen volslagen doof zijn, en ik heb daar grote moeilijkheden mee gehad, ettelijke keren bv. als over grote projecten mijn technisch advies gevraagd werd. Je krijgt stukken toegestuurd of je gaat naar de mensen toe, die dan een of meer voordrachten over hun project houden. Na tien minuten weet je al met verpletterende zekerheid, dat het project een grandioos debacle zal worden. Wat is er aan de hand? Wel, op technische gronden kan je de moeilijkheid van het project wel zowat schatten, je kan zeker een ondergrens van de moeilijkheid aanvoelen. Toets deze aan het taalgebruik, dat je observeert als deze mensen over hun project praten. Dat kan zo hopeloos ontoereikend zijn, dat je, zoals gezegd, na tien minuten alleen nog die gapende kloof ziet. Het frustrerende is, dat je niet serieus genomen wordt, als je na tien minuten al mislukking voorspelt op grond van ontoereikend taalgebruik, bv. te slordig of te zeer vervuild door gevaarlijke clichés.

Laat me U daarom voor een cliché waarschuwen dat in de praktijk der informatica bijzonder pernicieus is gebleken: "the user". Het hoeft niet eens "casual user" te zijn, gewoon "user" is al erg genoeg. En weet U wat er mis mee is? Heel eenvoudig: je moet je er natuurlijk niet over verbazen, dat Engelsen en Amerikanen over "users" spreken, maar het is wel een teken aan de wand —een niet mis te verstaan teken zelfs— dat dit woord onvertaald is opgenomen in het informaticajargon van God mag weten hoeveel volkeren. Je kunt geen Nederlandse discussie over informatica haast horen, of vroeg of laat bezigt iemand de term "user" zonder dat iemand een spier vertrekt. "User" is nu goed Nederlands, zo goed, dat ik op de spelling "joezer" zit te wachten. Eerste waarschuwing. Maar "user" is nu ook goed Frans! En gezien de Anglophobie van de Fransen is die tweede waarschuwing veel ernstiger. "User" is ook goed Russisch! En "user" is ook goed Japans!

Kijk, dat moet je aan het denken zetten, omdat de term zo goed vertaalbaar is. Het is heel iets anders wanneer iedereen bv. het woord "flipflop" overneemt. Waarom praten Nederlandse informatici over de joezer, en niet over "de gebruiker"? Omdat het goed-Nederlandse woord "gebruiker" een goed-Nederlandse betekenis heeft, die de "joezer" allang heeft verloren. De joezer is een karikatuur, een literaire figuur. Van derderangs literatuur zelfs. De joezer is een imbeciele analphabeet met geld, wiens grootste zaligheid bestaat uit wezenloos naar het scherm van zijn "terminal" —daar heb je nog zo een!— te staren, en aan elke hand twee worstvormige vingers, waarmee hij op de toetsen hengst. En hij kent maar een gebed "Heer, sluit mij op een netwerk aan." Is het een wonder dat alles, wat in naam van deze armetierige fictieve figuur wordt opgezet, haast onzinnig is? En is het niet verontrustend, dat dat nog zo'n hoop is ook? Het zou me niets verbazen, als er voor de joezer zelfs speciale colleges gegeven worden.

transcribed by Carl Ludwigson
revised Wed, 14 Nov 2007

EWD588

Vierde toespraak tot mijn studenten, najaar 1976.

Verleden week heb ik het even gehad over de (al of niet) "casual user"; hij heeft een broertje, "the average programmer" genaamd. Laat mij deze week gebruiken om U uit te leggen, waarom hun invloed zo pernicieus is. Ik wil U eerst twee voorbeelden geven.

Toen onlangs een van mijn leerlingen promoveerde over een verkenning van wat programmeren in zou kunnen houden voor machines, waarin vele componenten tegelijkertijd werkzaam kunnen zijn, heeft de keuze van dit onderwerp verzet opgeroepen, o.a. van mensen van het rekencentrum. Hun bezwaar was, dat zij hun klanten de relevantie van dit onderzoek niet konden uitleggen. Ik van mijn kant betwijfel echter of je er goed aan doet, de beperkte fantasie van de gemiddelde machinegebruiker te accepteren als uiterste grens van je wetenschappelijke exploraties.

't Tweede voorbeeld betreft mijn eigen werk over de afgelopen vijf jaren, waarin programmeren met veel grotere duidelijkheid dan voordien uit de verf is gekomen als een activiteit, die noodzakelijk een uitgesproken wiskundige inslag heeft. Ook dit roept verzet op, in de trant van "Tja, maar dit verkoop je nooit van zijn leven aan de gemiddelde programmeur." Dat mag dan misschien zo wezen, maar had ik mij door het beperkte bevattingsvermogen van de gemiddelde programmeur moeten laten beletten tot dit inzicht te komen en deze methodologie te ontwikkelen?

Dit soort tegenwerpingen komt van mensen die bij de keuze van hun eigen werk kennelijk veel sterker laten leiden door overwegingen van verkoopbaarheid van het resultaat. Ik raaak hier bezwaar tegen, niet omdat het moreel slecht zou zijn, maar omdat het onverstandig is.

Begrijp me goed: zorgen om de verkoopbaarheid zijn niet immoreel. Een onderzoeker op wiens resultaten geen acht geslagen wordt is even ineffectief als de schrijver wiens gedichten niemand leest. Dat de schrijver zich tevens ten doel stelt zijn publiek te bereiken, billijkt ieder; voor de wetenschapsman ligt dit niet anders.

Echter: de techniek van het wetenschappelijk denken ontleent zijn weergaloza effectieviteit aan wat tegenwoordig als "the successful separation of concerns" wordt aangeduid, aan de isolatie der beslommeringen. In plaats van een probleem in zijn volle onverdunde complexiteit te lijf te gaan isoleert de ervaren onderzoeker alle aspecten die hij onafhankelijk van de rest kan onderzoeken, en met die verschillende aspecten houdt hij zich om de beurt bezig, met de een na de ander. Deze techniek is zozeer het ijkmerk van succesrijk wetenschappelijk onderzoek, dat de ontdekking van een isoleerbaar aspect dat in onafhankelijkheid bestudeerd kan worden vaak de meest essentiele bijdrage is, omdat daardoor het onderzoek binnen het bereik der mogelijkheden komt.

De vraag welk wetenschappelijk doel je nastreeft, en de vraag hoe je het resultaat, indien bereikt, aan de man zult brengen zijn van nature twee verschillende vragen. Het zijn twee verschillende beslommeringen, en niets wordt gewonnen door ze te vermengen, integendeel. Zorg voor de presentatie dient niet voorop te staan, de zorg voor de presentatie dient gerechtvaardigd te worden door de kwaliteit van het aan te bieden product. Als deze prioriteit vergeten wordt —en in de informatica wordt hij vaak vergeten omdat daar de wetenschappelijke traditie nog niet zo hecht verankerd is— dan worden "the casual user" en "the average programmer" even verlammend als "de modale student" is voor het wetenschappelijk onderwijs, zodra die als norm geaccepteerd wordt. Onze vriend van Kemenade zal mij er dan ook niet van weerhouden zijn "modale student" aan mijn hooggeleerde sandaal te lappen.

transcribed by Carl Ludwigson
revised Thu, 15 Nov 2007

EWD589

Vijfde toespraak tot mijn studenten, najaar 1976.

Er leven op Gods aardbodem twee soorten mierenkolonies. Een mierenkolonie is een heel ingewikkelde samenleving van allerlei verschillende types mieren, vaak zelfs in symbiose met allerlei andere insecten. De twee soorten onderscheiden zich door de relatieve specialisatiegraad. Er zijn de hooggespecialiseerd kolonies waar wel twintig veschillende soorten beestjes, ieder met hun heel specifieke rol in zo' samenleving elkaar verzorgen. Ieder beestje is heel gespecialiseerd en aan deze specialisatie ontleent de kolonie zijn efficiency, en daarmee zijn overlevingskans. Aan de andere kant zijn er de veel minder gespecialiseerde kolonies, waar maar een soort of zes samen met elkaar optrekt. Deze kolonies werken minder efficient, zij ontlenen hun overlevingskans evenwel aan hun groter aanpassingsvermogen. Het probleem van de hooggespecialiseerde kolonies is dat zij slechts ontstaan kunnen als ter plaatse de levensomstandigheden eeuwen en eeuwen nagenoeg onvernaderd blijven; veranderen die omstandigheden merkbaar, dan gaat zo'n kolonie alsnog te gronde. De hooggespecialisserde kolonies hebben dan ook een heel klein verspreidingsgebied, de minder gespecialiseerde vind je over de hele wereld.

Ik moest hieraan denken toen ik in gesprekken met jonge wiskundigen onlangs merkte, dat de meesten van zins waren om zich een plekje onder de zon te veroveren door op een of ander gebied of gebiedje specialist te worden, liefst zelfs een van 's werelds weinige specialisten. Ze dachten door zo'n vergaande specialisatie hun eigen toekomst veilig te kunnen stellen.

Ik denk, dat zij zich verschrikkelijk vergissen. De verdergaande specialisatie in onze samenleving, de steeds fijner wordende werkverdeling is een verschijnsel in hoofdzaak van de laatste eeuw. Allerlei speciale beroepsopleidingen zijn daarvan een duidelijk symptoom. Deze ontwikkeling is ingegeven door een streven naar collectieve efficiency. Om een klein voorbeeld te noemen: vroeger studeerde je een vak aan de universiteit en als je dan gepromoveerd was kon je, als je daar zin in had, bv. leraar worden. Mijn vader was nog van die generatie: als hij zijn vak moest opgeven, zei hij "chemie", als hij zijn beroep op moest geven zei hij "leraar"; en hij is altijd chemicaus gebleven. Tegenwoordig kan je voor de klas komen te staan nadat je een zogenaamde leraarsopleiding hebt gevolgd.

Of het nagestreefde doel, de collectieve efficiency, wel helemaal bereikt wordt, is iets waarvan ik nog niet altijd zo zeker ben. In het geval van de speciale leraarsopleiding, die dan wel goedkoper is dan een volwaardige universitaire studie, heeft het ongetwijfeld tot een verschraling van de middelbare school geleid, waarvan de beste leerlingen het ergste slachtoffer zijn. En hoeveel onze maatschappij daar later voor zal moeten betalen, is te griezelig om over na te denken. Maar laten we vandaag even aannemen, dat over het algemeen het doel van de collectieve efficiency er wel mee bereikt wordt. In dat geval moeten we niet vergeten, dat het het gespecialiseerde individu is, dat de risico's draagt!

De ellende van individuele specialisatie is, dat zelfs een marginals verandering in de werkzaamheden de specialist van weleer buiten spel kan zetten. En deze veranderingen in werkzaamheden vinden natuurlijk plaats, aangezien zich in elke maatschappij economische, politieke en technische veranderingen voordoen. Maar hoe fijner de werkverdeling, hoe groter zulke veranderingen schijnen en hoe dramatischer hun gevolgen zijn. Met uitzondering van het geniale unicum, dat altijd boven de wet zal staan, moet ik dan ook concluderen, dat de verdoorgevoerde specialist niet zijn eigen belang dient, misschien het collectief belang, maar dan voor de prijs van een vergrote persoonlijke kwetsbaarheid.

transcribed by Carl Ludwigson
revised Thu, 15 Nov 2007

  EWD 590

19th October 1976

A first investigation of the crossflow computer.

Acknowledgement. This text was written while drs R.W.Bulterman, ir.W.H.J.Feijen, ir.A.J.Martin and drsF.J.Peeters were looking over my shoulder. It summarizes discussions in which dr.M.Rem participated as well.

The purpose of this note is to investigate an alternative to the architecture of (instruction) pipe-lining. It has been inspired by the following objections against pipe-lining.

1. The interlocking of pipe-lined machines is very expensive and complicated. This has several undesirable consequences.

1.1 It is very expensive to design.

1.2 It is very difficult to prove the correctness of the design.

1.3 It is expensive to make and hard to maintain.

1.4 It violates by its very structure one of the basic assumptions of traditional sequential hardware, the assumption being that if each instruction, all by itself, is verified to operate correctly, a sequence of instructions will operate correctly as well; this assumption is justified in traditional sequential hardware because there successive instructions can only interfere via explicitly named, discrete memory elements —storage cells and registers—. "Checking" the correct operation of a pipe-lined machine with its intertwined instruction executions seems orders of magnitude more difficult, if not impossible.

2. The use of a pipe-lined machine presents conflicts because at each conditional jump it is hard to decide how to direct the instruction fetch. Either we stop —but then the effect of pipe-lining is temporarily paralyzed— or we guess.

2.1 Guessing is unattractive. First of all it requires the whole machinery for "undoing" in the case of a wrong guess; secondly it exerts strong pressure upon the programmer —or the compiler?— to make on too detailed a level the program text dependent on expected frequencies.

2.2 I have been told that designing an optimizing compiler for a pipe-lined machine is fraught with unpleasant surprises.

2.3 I have been told that effectuating an interrupt in a pipe-lined machine in an orderly fashion has, in many cases, been too difficult for the designers.

We intend to explore the so-called "crossflow computer" as an alternative machine architecture that may achieve the speeding-up effects of pipe-lining but hopefully without most of the complications listed above. Stated very shortly: we would like to harvest the fruits of concurrent processing without paying the price of extensive synchronization protocols, and without introducing the extensive, diversified hardware. More precisely: we envisage a machine consisting of a modest number, —six, say— in hardware identical components, each component in principle not much more complicated than a traditional sequential machine. In order to stress the fact that these components should be viewed as executing together —and in rather strict synchronism— the same algorithm, we shall consistently refer to them as "components": the components together constitute a single sequential machine.

In order to avoid false expectations we would like to stress, right at the beginning, that as far as the crossflow computer can be regarded as an exercise in concurrency, the exercise is very modest. We will be perfectly happy if we arrive at an architecture which, by means of six times as much hardware, reduces execution times by a factor of two or three. We are perfectly aware of the fact that our approach is not applicable if someone wants to reduce computation time by a factor of ten at the possible expense of twenty or forty times as much equipment.

As a matter of fact, preliminary investigations have indicated —and, as I have heard, this is confirmed by experiences elsewhere— that we must be glad if we manage to keep our, say, six components happily productive, when our start is a traditional sequential algorithm. This upper bound has an interesting possibility of which we have been aware right from the start. (At the moment of writing it has not been explored yet.) The possibility opens up when the machine is equipped with a few more components: if they cannot be used to speed up the computation, they may be used for run-time checking!

Note. Run-time checks are, by definition, extremely skew and, as such, yield very little information. If run-time checks are performed at the expense of progress speed, there is, therefore, a strong pressure to omit them during production runs —with all undesirable consequences—. In practice, the dilemma has always been solved by building-in dedicated, concurrently active equipment, the prime examples being the parity check and the interrupt detection. A few additional components could perhaps be dedicated to program dependent run-time checking, that could then be performed without noticeably slowing down the computation proper. (End of note.)

*                  *
*

Let us try to give and motivate a —by necessity in this stage rough— description of the kind of machine we intend to investigate. The machine will consist of a modest number of identical "components". Each component will comprise a private high-speed memory and a purely sequential processor. Information exchange between the components is assumed to take place via a common bus, with the fundamental assumption that during a time slot in which the bus is used, information can be broadcast by one of the components and be picked up by all the others.

Note. For the time being we shall assume that the bus is very fast compared with the processing. The extent to which this assumption is essential or a matter of convenience —e.g. for the ease of compiling— remains to be seen. (End of note.)

Note. The bus is assumed to be a galvanic contact between the components, with all the receivers "reading" simultaneously. The number of components is assumed to be small enough so that the fan-out presents no serious problems. (End of note.)

Note. The assumed speed of the bus and "clock skew" could present problems; for the time being we hope that they can be solved. (End of note.)

Each component looks like a sequential machine operating under control of the program stored in its own store. Just as we introduced the term "component" versus the whole "machine", we introduce, in order to avoid confusion, the term "fragment" versus the whole "program". When the whole machine executes a program, each component executes its fragment. We consider it the task of the compiler to construct from the source program the, say, six fragments that will control the activity of the, say, six components.

Note. The division of the total workload over the six components is decided statically (if you know what I mean). We consider the six components to form one machine: when one of the components is out of order, the machine is down. The so-called "graceful degradation" is most definitely not our target. Everybody who wants that, should couple a number of crossflow machines. (End of note.)

The six components are assumed to work in rather strict synchronism. I.e. not only will they be controlled by a common clock, but even the execution of the six fragments is synchronized to the extent that we could, as a first approximation, visualize the six fragment executions taking place under control of a central ("virtual"?) instruction counter. In practice we don't expect this to be truly the case. Firstly, instruction counters locate instructions in the stores and dynamically corresponding fragment parts in different components could require different amounts of store. Secondly, it is not excluded that certain redirections of control —possibly, for instance, the return from a procedure— don't take place simultaneously in all six components: some of them might be mildly out of phase. It should be pointed out that we expect the pattern of flow of control of the program fairly faithfully reflected in each of the fragments: a loop on the program is practically certain to give rise to a corresponding loop in each of the fragments.

A point of special concern has been the problem of bus allocation; the bus is clearly a common resource and it seemed mandatory that the bus can be used without any sort of handshaking, either for the purpose of synchronization or for the purpose of conflict resolution between two or more senders. We have therefore decided that the possible patterns of bus usage are fixed during compilation (or "fragmentation") and are recorded in the fragments to such an extent that for each of the components its fragment prescribes when to send or to receive what. This decision makes quite clear the extent to which the various fragments derived from a single program have to be derived simultaneously and in strong interdependence of each other: at run time the sending of a result by one component under control of its fragment must coincide with the reading from the bus by one or more other components under control of their fragments. There will be no contention, i.e. if during a time slot more than one component sends, there must be something wrong —either component malfunctioning or an erroneous compiler—. A hardware check on such erroneous bus usage is assumed.

For the synchronization of the bus contacts various techniques can be considered. Under the assumptions that

a) each instruction takes a fixed, a priori known number of time units

b) the order code contains the instructions "SEND" and "RECEIVE", that transmit information from a component register to the bus and vice versa respectively

c) the order code contains DELAY instructions, each of a fixed, a priori known number of time units,

the fragments can be coded in such a way that during concurrent execution —as if by magic!— each SEND coincides in time with the appropriate RECEIVE's. The obligation of "padding out" the fragments is tedious, but not difficult. Alternatively we could consider each RECEIVE to extend up to the "next" SEND. Note that also in this case the fragmentation cannot be performed without rather detailed timing information: we would have to ensure that no send starts too early. With the above we don't think we have explored all possibilities: at this stage of our investigations we would prefer not to commit ourselves beyond the decision that during fragmentation the pattern of bus usage is determined.

Note. We have not fully committed ourselves yet on what the pattern of bus usage may depend. It will certainly depend on the flow of control —which, therefore, is largely common to all fragments—, it could in principle also depend on intermediate values: if during a specific time slot a number of components are going to receive the value of a[i], stored in another component, the identity of the sender could be made dependent on the value of i, viz. when the elements of the array are distributed over more than one component. (This is not what we emphatically envisage; on the other hand this is not the time to exclude it.)

A second example may be provided by an implementation of (in old notation)

if B then x:= y else x:= z fi;

if x, y, and z are stored in different components, the one containing x may receive its new value in a sense from an "unknown sender". Both the examples illustrate how (local) differences in flow of control may be confined to part of the fragments. (End of note.)

Note. It might be thought that timing obligations are hard to fulfill because execution time is not known a priori in case of repetition. In that case, however, the repetition will be faithfully reflected in all fragments. (End of note.)

Note. If we allow nondeterminacy in our source program, e.g.

if B1 → S1 ▯ B2 → S2 fi

the nondeterminacy has to be resolved on the level of the total machine, and not independently in the different components. (End of note.)

Note. In sequential programming we have already experienced the luxury of programming as if all guards of a guarded command set are evaluated concurrently. If the values of the different guards are formed in different components and they have, therefore, to be broadcast, the bus, which is assumed to have many wires, may be split up in a number of sub-buses. (End of note.)

*                  *
*

In order to describe the kind of happenings inside the working crossflow computer as we visualize it at the moment, we relate them to what would happen during a straightforward sequential implementation of the same program. (The fact that that relation is such a close one is indicative for the modest concurrency in our proposal.) We envisage that to each transmission on the bus will correspond either a guard-broadcasting or an assignment from the traditional sequential execution. Conversely we hope that many store instructions in the traditional sequential execution —in particular those to anonymous intermediate results— won't need the bus. It is envisaged that the bus contacts will take place in exactly the same order as in which the corresponding events would take place in the sequential execution, a correspondence to which we wish to stick for two reasons. The one reason is that without more revolutionary massaging of the program text, the design of the compiler/fragmenter is already difficult enough; the other reason is that we wish our reasoning techniques about sequential programs to remain applicable.

(To be continued.)

Plataanstraat 5 NL–4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff`
revised Sat, 24 Jun 2006

EWD591

The problem of the maximum length of an ascending subsequence.

We consider a sequence of   N   elements   A(1)   through   A(N)  . The order of increasing subscript value will be denoted by “the order from left to right”. From such a sequence we can take so-called “subsequences of length s” by the removal of an arbitrary collection of   N–s   elements and retaining the remaining   s   elements in the order in which they occurred in the original sequence. When, in addition, each element has an integer value, we call a subsequence "ascending" iff it contains no element with a right-hand neighbour smaller than itself.

Note.   According to this definition, all   N   subsequences of length   1   and even the empty subsequence are ascending ones. (End of note.)

We look for an algorithm that determines for any given sequence (with N > 0) the maximum length of an ascending subsequence that can be taken from it.

Note.   Although there need not be a unique longest ascending subsequence, the maximum length is unique, e.g.   3 1 1 2 4 3   gives   4   for the maximum length, realized either by   1 1 2 4   or by   1 1 2 3  . (End of note.)

If   k   represents the value we are looking for, we seek to establish the relation

R:    k = | the maximum length of an ascending subsequence taken from   A(1)   through   A(N)

Because   R   contains the parameter   N  , it is strongly suggested to take as invariant relation —or, as we shall see in a moment: as part of the invariant relation—

P1(k, n):    k = | the maximum length of an ascending subsequence taken from   A(1)   through   A(n)  .

It has the virtues that it would do the job in the sense that   (P1(k, n) and n = N) ⇒ R   and is easily established, e.g. by   k, n := 1, 1  . These observations suggest to establish   P1(k, n)   for   n = 1   and then to increase   n   under invariance of P1(k, n)   until   n = N , more precisely: to increase   n   repeatedly by   1   and to restore each time, when destroyed, the truth of   P1(k, n)   by adjusting the value of   k . Because extension with a next element can never decrease the maximum length of an ascending subsequence and can increase it by at most   1  , the adjustment of   k  , when needed, will have the form   k:= k + 1  . More precisely: because

P1(k, n) = wp(“n:= n + 1”, P1(k, n–1))

we have to investigate after   “n:= n + 1”   under which circumstances no adjustment of   k   is needed, i.e. when

P1(k, n–1) ⇒ P1(k, n) | , | (1)

and under what circumstances adjustment of   k   is needed, i.e. when

P1(k, n–1) ⇒ P1(k+1, n) | , | (2)

Relation (2) holds iff   A(n)   can be used to extend an ascending subsequence of maximum length ( = k) taken from   A(1)   through   A(n–1) ; this is true iff

A(n)  ≥   | the smallest rightmost value of an ascending subsequence of length k   taken from   A(1)   through   A(n–1)  .

This last inequality shows us, that besides   k   —as defined by   P1(k, n)—   we would also like to store the minimum rightmost value —let us call it   m   for a moment— of an ascending subsequence of maximal length. If (2) holds,  k   is obviously to be adjusted by   k:= k + 1  , and the assignment   m:= A(n)   would make   m   again equal to the minimum rightmost value of an ascending subsequence of maximum length (because, in this case, all ascending subsequences of maximal length taken from   A(1)   through   A(n)   will have A(n)   as their rightmost element.)

The introduction of   m   as the minimum value of the rightmost value of an ascending subsequence of length   k  , presents, however, a problem in case (1). In that case, the extension with   A(n)  , although not leading to an increase of k  , may require adjustment of   m   as it may lead to decrease of the minimum rightmost value of an ascending subsequence of that unchanged maximal length. This would be the case if the value   A(n)  —which now satisfies   A(n) < m — could be used to extend an ascending subsequence of length   k–1  , taken from A(1)   through   A(n–1)  . In order to decide that, we would also need the minimum rightmost value of an ascending subsequence of length   k–1  . Repeating the argument, we conclude that, instead of a scalar   m  , we need in addition to   k   an array variable   m   satisfying

P2(k, n, m):

for all   j   satisfying   1 ≤ j ≤ k

m(j) =
the minimum rightmost value of an ascending subsequence of length   j   and taken from A(1)   through   A(n)  .

Our total invariant relation will be   P1 and P2  .

Again, for   n = 1, P2   is easily initialized   —with   m(1) = A(1)—;   we have to investigate, however, what updating obligations for the array variable   m   are implied by our duty to keep   P2   invariant. The crucial discovery in the analysis of our updating obligations for the array variable   m   is that the elements of   m   itself are ascending, more precisely:

(1 ≤ i < j ≤ k) ⇒ (m(i) ≤ m(j))        .

This follows from the fact that   1 ≤ i < j ≤ k and m(i) > m(j)   leads to a contradiction: by removing from an ascending sequence of length   j   and with m(j)   as its rightmost value the leftmost   j–i   elements, an ascending sequence of length   i   with   m(j)   as rightmost value remains, and   m(i) > m(j)   then contradicts   P2  .

Again we investigate the situation as reached after   n:= n + 1  , i.e. when P1(k, n–1) and P2(k, n–1, m)   holds. Relation (2) holds iff   A(n) ≥ m(k). The new element   A(n)   can be used to form a longer ascending sequence,   k   has to be increased and the sequence of values is extended with   A(n)   by

m : hiext(A(n))       ;

it is correct to leave the values   m(i)   with   1 ≤ i < k   unchanged, for the new element   A(n) ≥ m(k)   and can never give rise to a smaller rightmost value for any of the ascending sequences shorter than the new maximum length   k  . Relation (1) holds iff   A(n) < m(k)  . Remembering that after the increase n:= n + 1   the relation   P2(k, n–1, m)   holds, we have to answer the question for which value(s) of   j   is the minimum rightmost value of an ascending sequence of length   j   taken from   A(1)   through   A(n)   smaller than taken from   A(1)   through   A(n–1)?   This can only be the case if   A(n)   is its new rightmost element, which must be smaller than its old value   m(j)  . So we have

A(n) < m(j) | (3)

But   A(n)   can only be the rightmost element of an ascending sequence of length   j   if

either   j = 1   or   j > 1 and m(j–1) ≤ A(n) | (4)

Combining (3) and (4) we find
j = 1   iff   A(n) < m(1)   and otherwise   j = the only(!) solution of   m(j–1) ≤ A(n) < m(j)  . This last solution is found in the program with a binary search; the invariant relation for the inner loop is   m(i) ≤ A(n) < m(j)  .

Observing that   k = m.hib  , the current higher bound for the index, we can use for   m(k) = m(m.hib)   the usual abbrevation   m.high   and conclude that we don’t need the variable   k   after all. For reasons of symmetry we denote   m(1)   by   m.low  , as   m.lob = 1  . Omitting all declarations we get the following program.

n:= 1; m:= (1, A(1));
do n ≠ N →
        n:= n + 1;
        if A(n) ≥ m.high →
                m:hiext(A(n))
            ⌷ A(n) < m.high →
                if m.low > A(n) →
                        j:= 1
                    ⌷ m.low ≤ A(n) →
                        i, j := m.lob, m.hib;
                        do i ≠ j - 1 →
                                h:= (i + j)div 2;
                                if m(h) ≤ A(n) → i:= h
                                    ⌷ A(n) < m(h) → j:= h
                                fi
                        od
                fi;
                m:(j)=A(n)
        fi
od;
print(m.hib)

Plataanstraat  5 | prof. dr. Edsger W. Dijkstra
NL-4565    NUENEN | Burroughs Research Fellow
The Netherlands

transcribed by Swarup Sahoo
last revised Tue, 5 Jul 2011

EWD592

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A small note on the additive composition of variant functions.

This is only a small note, for its observation is nearly trivial. The note is made, however, because it describes a method of some generality, by which results can be derived that —as I have observed— tend to strike the reader as “a trick” if he has never seen the like and is unaware of the method behind it.

It deals with finding a variant function for a repetitive construct with more than one alternative:

| do B1 → S1 ▯ ... ▯ Bn → Sn od .

The simple idea is to contruct the variant function t as the sum

| t = t1 + ... + tn ,

where ti is decreased by at least one by the i-th guarded command and left constant by the others.

We shall illustrate it with an example of matching simplicity. On a shunting yard are a finite number of trains; a train is either atomic (iff it consists of a single car) or composite (if? it consists of a finite number of cars greater than one). The yard is empty, when it contains no trains. Repeatedly we select a train: if it is atomic, it is removed from the yard, if it is composite, it is split into two (shorter) trains that, in this move, remain on the yard. The process terminates, when the yard is empty. The point is to construct the decreasing function t that is bounded from below, so that termination is proved. We sketch the process by

| do atomic train selected → remove it
|  | ▯ composite train selected → split it
| od

With CARS = the number of cars on the yard

| t1 = CARS

satisfies the requirement that the first guarded command decreases it and the other one leaves it constant. with

| TRAINS = the number of trains on the yard ,
|  | t2 = - TRAINS

would satisfy the requirement that it is decreased by the second guarded commend (because that increases + TRAINS). This remains true when we add a function left constant by it, e.g.

| t2 = f(CARS) - TRAINS .

(Note that we have already verified that CARS , and therefore f(CARS) for any function f , is unaffected by the second guarded command.) Because t2 has to remain constant when the first guarded command is selected, we must choose for f the identity function:

| t2 = CARS - TRAINS

and thus we find t = 2 * CARS - TRAINS .
(With CLOSCONNS = the number of closed car-to-car connections,

| t2 = CLOSCONNS

also does the job: it is left unchanged by the first and decreased by the second guarded command. This is not a new solution, for CLOSCONNS = CARS - TRAINS . )

*              *
*

For the asymmetric computation for x = gcd(X, Y) with X > 0 and Y > 0 :

x, y := X, Y; do X > y → x:=x - y ▯ y > x → x, y == y, x od

we find quite analogously t1 = x + y and t2 = y .

*              *
*

Note. Obviously the condition that ti is left unchanged by the j-th (j ≠ i) guarded commands is stronger than necessary: it suffices to establish that ti is not increased by the other guarded commands. (End of note.)

Note. Instead of choosing t = t1 + ... + tn , we could also take —after having chosen the ti — t = a1*t1 + ... + an*tn with all ai’s positive; in other words, the variant function is by no means unique, and we can choose the most convenient one. (End of note.)

The above has been prompted by my impression that some people seem to think that that there is something mysterious about the termination of the type of programs discussed. Its moral is that there is no mystery.

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
NUENEN NL-4565 | Burroughs Research Follow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-08 .

EWD593

Zesde toespraak tot mijn studenten, najaar 1976.

Wie tijdschriften doorbladert en hier en daar eens een artikel probeert te lezen, moet de enorme spreiding in kwaliteit wel opvallen. Sommige artikelen zijn voortreffelijk geschreven, anderen zijn onbegrijpelijk, niet omdat de lezer onvoldoende in het onderwerp is ingevoerd, maar domweg, omdat het artikel rommelig is opgezet en erbarmelijk is gesteld. Ik moet U bekennen, dat vastlopen in een artikel in de overtuiging, dat niet ik te dom ben, maar de schrijver te slordig is geweest, een ervaring is, die mij altijd furieus maakt. In zo'n geval mag de auteur zich in zijn handjes wrijven als hij met de qualificatie "Lummel" aan mijn gramschap ontsnapt, want doorgaans wordt hij voor heel wat anders uitgemaakt.

Is het bij officieel gepubliceerde artikelen al vaak droevig, nog vele melen erger is het bij de aangeboden manuscripten. Bij dit schiftingspraces word uit de aard der zaak ook ik betrokken, en wat je bij die werkzaamhaden onder ogen krijgt grenst werkelijk aan het ongelofelijke, Ik heb lange tijd niet begrepen, hoe dat kon. Die auteurs hebben toch ook artikelen van anderen onder ogen gehad, hebben toch ook ervaren hoezeer de effectiviteit van een artikel door onverzorgdheid tenietgedaan kan worden! Hoe is het dan mogelijk, dat ze zelf nog zulke rommel durven te produceren?

Ik kan slechts de volgende verklaring bedenken. Ten eerste moet ik aannemen, dat het hun niet geleerd is, hoe je een goedverzorgd manuscript moet aanbieden. Ten tweede moet ik aannemen, dat ze het ook niet nodig hebben gevonden zich dit zelf te leren: je krijgt het angstige gevoel dan ook, dat grote aantallen abiturienten het ook onredelijk zouden vinden om van hen te verwachten, dat ze iets zouden kunnen, waarvoor ze niet expliciet zijn opgeleid. Ik noem dat gevoel "angstig" amdat zo'n instelling niets meer of minder is dan een aspect van barbarij.

Het barbaarse geloof onder abiturienten, dat ze niet iets hoeven te kunnen, waarvoor ze niet expliciet zijn opgeleid, heeft zijn complement in het even barbaarse geloof der pedagogen, dat je, eventueel via een speciaal aangepaste cursus, iedereen alles kunt leren, tot aan "maatschappelijk verantwoordelijkheidsbesef" toe! Elk redelijk mens weet, dat dat onzin is; barbaarse onzin zelfs.

Toch vreet dit bijgeloof in de heilsboodschap van de speciale cursus door ons hele onderwijsbestel, want het is ten departemente een fetish. Het is de drijvende kracht achter alle vormingswerk, achter alle pogingen om het echte onderwijs door vormingswerk te vervangen, achter alle pogingen om, zoals je die hier aan de THE kunt waarnemen, het Studium Generale meer gewicht te geven.

Het Studium Generale is van zijn geboorte in 1945 af, altijd een heel moeilijk artikel geweest. Het is opgezet met de bests bedoelingen van de wereld. Net hadden we in NAZI-Duitsland meegemaakt, dat een technologisch hoogontwikkelde maatschappij geen garantie voor een beschaafde maatschappij inhoudt. En het is tegen de achtergrond van die traumatische ervaring, dat het Studium Generale is ingevoerd, in een vertwijfelde poging niet alleen capabele intellectuelen, maar ook nag beschaafde intellectuelen op te leiden. Kortom: een nobele onderneming, maar ook wel erg naief. Want wis gelooft nu werkelijk, dat "beschaafd zijn" per speciale cursus aangeleerd kan worden?

Als je het goed nagaat moet je concluderen, dat de optimisten, die dit soort cursussen gestimuleerd hebben, op hun manier al ten offer waren gevallen aan de barbarij, die ze bij anderen nog wilden bestrijden.

Zevende toespraak tot mijn studenten, najaar 1976.

Ik heb voor U de verheugende mededeling dat zijne Excellentie minister van Kemenade nog voor de val van het kabinet door onvoorzichtige woordkeus zijnerzijds met de billetjes bloot is gekomen. Hij is zo onmatig spraakzaam, dat ieder zoiets natuurlijk wel heeft durven hopen, maar je weet nooit of niet een of andere schutsengel, uit misbegrepen solidariteit met het R.K.volksdeel, zich niet geroepen voelt om zijn Excellentie minister van Kemenade voor al te flagrante flaters te behoeden. Tot mijn genoegen en satisfactie kan ik U mededelen, dat in dit geval zelfs het gilde der schutsengelen de hopeloosheid van zijn overigens nobele roeping heeft begrepen: zij hebben hem rustig zijn flater laten slaan. De enige vleugel, die ze nog voor hem hebben uitgestoken, was, dat ze er voor hebben gezorgd dat de flater van zijn Excellentie minister van Kemenade de landelijke pers niet gehaald heeft en slechts tot het Utrechts Nieuwsblad is doorgedrongen. De flater is er evenwel niet minder om: de billetjes zijn nu verhelderend bloot.

In Utrecht is gevestigd het IOWO, wat, geloof ik, staat voor Instituut voor Onderzoek inzake Wiskunde Onderwijs, tot voor kort onder het directoraat van Prof.Freudenthal, die onlangs door prof.van der Blij is opgevolgd. Uit hoofde van de taakstelling van dit instituut kan je veilig veronderstellen, dat de staf van dit instituut in hoge —en naar sommiger smaak zelfs: ongezonde— mate geinteresseerd is in de processen van onderwijzen en leren. Maar helemaal leuteren doen ze daar niet: in elk geval is zeker dat aldaar de boventoon niet door pedagogen gevoerd wordt, maar door wiskundigen, die tenminste weten waarover ze praten. Deze club bewijst dat een wiskundige, in weerwil van uitgebreide en gevarieerde onderwijservaring, niet noodzakelijkerwijs in een leuterkont hoeft te ontaarden. Bij de wetenschappelijke onaantastbaarheid van hun onderwijskundige conclusies mag U van mij best een vraagtekentje zetten, mits U onthoudt, dat ze vele malen beter gefundeerd zijn dan de ministeriele beslissingen, die door politiek vooroordeel zijn ingegeven.

In een interview met zijne Excellentie minister van Kemenade over de middenschool werd zijne Excellentie door de interviewer geconfronteerd met critische kanttekeningen over het middenschoolidee van de zijde van het IOWO. Zijne Excellentie —en dit was het moment, dat de billetjes zo bloot kwamen, dat hij de heren van het IOWO later zelfs zijn excuses heeft moeten aanbieden— reageerde neerbuigend afwijzend, met de opmerking, dat commentaar van dergelijke "technocraten" gevoegelijk genegeerd kon worden.

Hier ziet U zijne Excellentie in al zijn naakte lulligheid. Geconfronteerd met door competentie geschraagde oppositie weet hij niet beter te doen dan zijn opponenten verdacht te maken. Dat is op zichzelf al min. Nog erger is, dat hij voor die verdachtmaking naar het goedkoopste middel grijpt: hij vervalt in de kretologie, die het bij het grauw altijd goed doet, door met de term "technocraten" competentie an Sich in een kwaad daglicht te stellen.

Het alleronthullendste is echter, dat zijn Excellentie meende, met die woordkeuze iets slims gedaan te hebben. Wij kunnen slechts constateren, dat hij mentaal tot datzelfde grauw behoort en van de essentiele rol van de wetenschap in onze cultuur tot op heden niets begrepen heeft.

Het is al met al wel griezelig, dat een dergelijk gebreveteerd warhoofd, dat tot voor enkele jaren rustig in Nijmegen nieuwe warhoofden breveteerd(?) nu minister van Onderwijs en Wetenschappen is. Het wordt de hoogste tijd, dat het gilde der schutsengelen zijn zorgen ook eens uit gaat strekken over de slachtoffers van 's ministers schrijnend anti-intellectualisme: ze zullen er hun handen vol aan hebben.

transcribed by Carl Ludwigson
revised Thu, 15 Nov 2007

EWD594

(Recently I found the following text in manuscript among old papers of mine. It must have been written in the middle of 1973, but I don't think that in the intervening three years it has lost anything of its significance. Hence I now incorporate it in the EWD-series.)

A parable.

Years ago a railway company was erected and one of its directors —probably the commercial bloke— discovered that the initial investments could be reduced significantly if only fifty percent of the cars would be equipped with a toilet, and, therefore, so was decided.

Shortly after the company had started its operations, however, complaints about the toilets came pouring in. An investigation was carried out and revealed that the obvious thing had happened: despite its youth the company was already suffering from internal communication problems, for the director's decision on the toilets had not been transmitted to the shunting yard, where all cars were treated as equivalent, and, as a result, sometimes trains were composed with hardly any toilets at all.

In order to solve the problem, a bit of information was associated with each car, telling whether it was a car with or without a toilet, and the shunting yard was instructed to compose trains with the numbers of cars of both types as equal as possible. It was a complication for the shunting yard, but, once it had been solved, the people responsible for the shunting procedures were quite proud that they could manage it.

When the new shunting procedures had been made effective, however, complaints about the toilets continued. A new investigation was carried out and then it transpired that, although in each train about half the cars had indeed toilets, sometimes trains were composed with nearly all toilets in one half of the train. In order to remedy the situation, new instructions were issued, prescribing that cars with and cars without toilets should alternate. This was a more severe complication for the shunting people, but after some initial grumbling, eventually they managed.

Complaints, however, continued and the reason turned out to be that, as the cars with toilets had their toilet at one of their ends, the distance between two successive toilets in the train could still be nearly three car lengths, and for mothers with children in urgent need —and perhaps even luggage piled up in the corridors— this still could lead to disasters. As a result, the cars with toilets got another bit of information attached to them, making them into directed objects, and the new instructions were, that in each train the cars with toilets should have the same orientation. This time, the new instructions for the shunting yard were received with less than enthusiasm, for the number of turntables was hardly sufficient; to be quite fair to the shunting people we must even admit that according to all reasonable standards, the number of turntables was insufficient, and it was only by virtue of the most cunning ingenuity, that they could just manage.

With all toilets equally spaced along the train the company felt confident that now everything was alright, but passengers continued to complain: although no passenger was more than a car length away from the nearest toilet, passengers (in urgent need) did not know in which direction to start their stumbling itinerary along the corridor! To solve this problem, arrows saying "TOILET" were fixed in all corridors, thereby also making the other half of the cars into directed objects that should be properly oriented by the shunting procedures.

When the new instruction reached the shunting yard, they created an atmosphere ranging from despair to revolt: it just couldn't be done! At that critical moment a man whose name has been forgotten and shall never be traced, made the following observation. When each car with a toilet was coupled, from now until eternity, at its toileted end with a car without a toilet, from then onwards the shunting yard, instead of dealing with N directed cars of two types, could deal with N/2 identical units that, to all intents and purposes, could be regarded as symmetrical. And this observation solved all shunting problems at the modest price of, firstly sticking to trains with an even number of cars only —the few additional cars needed for that could be paid out of the initial savings effected by the commercial bloke!— and, secondly, slightly cheating with regard to the equal spacing of the toilets. But, after all, who cares about the last three feet?

Although at the time that this story took place, mankind was not blessed yet with automatic computers, our anonymous man who found this solution deserves to be called the world's first competent programmer.

*         *         *

I have told the above story to different audiences. Programmers, as a rule, are delighted by it, and managers, invariably, get more and more annoyed as the story progresses; true mathematicians, however, fail to see the point.

Plataanstraat 5 NL-4565  NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised Wed, 25 Aug 2010

EWD595

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On-the-fly garbage collection: an exercise in cooperation.

by

Edsger W.Dijkstra *)

Leslie Lamport **)

A .J.Martin ***)

C.S.Scho1ten ****)

E.F.M.Steffens ***)

*) | Burroughs, Plataanstraat 5, NL-4565 NUENEN, The Netherlands
**) | Massachusetts Computer Associates Inc., 26 Princess Street, WAKEFIELD, Mass. 01880, U.5.A.
***) | Philips Research Laboratories, EINDHUVEN, The Netherlands
****) | Philips-Electrologica B.V., APELDDDRN, The Netherlands

Abstract. As an example of intimate interference between sequential processes, a technique is developed, which allows nearly all of the activity, needed for garbage detection and collection, to be performed by an additional processor operating concurrently with the processor devoted to the computation proper. Exclusion and synchronization constraints have been kept as weak as could be achieved; the severe complexities engendered by this goal are amply illustrated.

Key Words and Phrases: multiprocessing, fine-grained interleaving, cooperation between sequential processes with minimized mutual exclusion, program correctness for multiprogramming tasks, garbage collection.

CR Categories: 4.32, 4.34, 4.35, 4.39, 5.23 .

On-the-fly garbage collection: an exercise in cooperation.

1. Introduction.

In any large-sca1e computer installation today, a considerable amount of time of the (general purpose) processor is spent on “operating the system”. with the advent of multiprocessor installations the question arises to what extent such “housekeeping activities” can be carried out concurrently with the computation(s) proper. Because the more intimate the interference, the harder the organization of the cooperation between the concurrent processes, the problem of garbage collection was selected as one of the most challenging —and, hopefully, most instructive!— problems. (Our exercise has not only been very instructive, but at times even humiliating, as we have fallen into nearly every logical trap that we could possibly fall into.) In our treatment we have tried to blend a condensed design history —in order not to hide the heuristics too much— with a rather detailed justification of our final solution. We have tried to keep exclusion and synchronization constraints between the processors as weak as possible, and how to deal with the complexities engendered by that goal is the main topic of this paper. It has hardly been our purpose to contribute specifically to the art of garbage collection, and, consequently, from that point of view no practical significance is claimed for our solution.

We tackled —in the form we knew it— the garbage collection problem as it presents itself in the traditional implementation environment for pure LISP. There the data structure to be stored consists of a directed graph in which each node has at most two outgoing edges, more precisely: may have a left-hand outgoing edge and may have a right-hand outgoing edge, but either of them or both may be missing. Our discussions were simplified considerably as soon as we followed the —not unusual— practice of introducing a special purpose node, called “NIL” —with its two outgoing edges pointing to itself— , and representing a formerly missing edge now by an edge with the node NIL as its target. For us, the introduction of the node called NIL was definitely much more than just a coding trick, for it allowed us to treat “adding an outgoing edge to a node”, “removing an outgoing edge from a node” and “redirecting an outgoing edge of a node”, which were originally regarded as three different operations, on the same footing, viz. as “redirecting an outgoing edge of a node”. In a sequel it will become clear that the homogeneity thus achieved has been absolutely essential for our purposes.

Furthermore all the nodes of the date structure to be stored are “reachable” (via a directed path along the edges) from one or more fixed nodes, called “the roots”, and modifications of the data structure are confined to redirecting an outgoing edge of an already reachable node. The roots are given a constant place in memory. The storage allocated to each node is constant in time and equal in size, to be more precise: sufficient for a few bits marking information (see later) and two addresses —for each of the outgoing edges the address of its target node— . Given (the address of) a node, finding (the address of) its left- or right-hand successor node can be regarded as an atomic, primitive action; finding its predecessor nodes, however, would imply a search through memory.

Besides redirecting an outgoing edge of a node towards an already reachable node, it should be possible to direct it towards a new node, that has to be added to the data structure; such a new node —which upon creation has only NIL as successor node— is taken from the so-called “free list”, i.e. a linearly linked list of nodes that are currently not used for storing a node of the data structure. The difference between those two types of changes of the data structure has been made to disappear, by linking the “free” nodes linearly —via their left-hand outgoing edge, say— and introducing a special root pointing to the begin node of the free list. (See Appendix 1.) Again this is more than a mere coding trick, for now also the nodes of the free list can be regarded as reachable. By furthermore declaring that also the special purpose node NIL is a root, we achieved our next homogenizing simplification: only one type of change of the data structure is left, viz. redirecting for a reachable node one of its outgoing edges to a reachable node.

Note that redirecting an outgoing edge of a reachable node may turn a number of other, formerly reachable nodes into unreachable ones: they then disappear from the data structure and become what is called “garbage”. Garbage may arise anywhere in store, and it is the purpose of the so-called “garbage collector” to detect such disconnected and therefore obsolete nodes and to append them to the free list. In classical LISP implementations the computation proper proceeds until the free list is exhausted (or nearly so). Then the computation proper comes to a grinding halt, during which the processor is devoted to garbage collection. Starting from the roots, all reachable nodes are marked. Because we have made the nodes of the free list reachable from a special root, nodes of the free list (if any) will in our case be marked as well. Upon completion of this marking phase, all unmarked nodes can be concluded to be garbage and are appended to the free list, after which the computation proper is resumed.

The minor disadvantage of this arrangement is the delay of the computation proper; its major disadvantage is the unpredictability of these garbage collecting interludes, which makes it hard to design such systems so as to meet real time requirements as well. It was therefore tempting to investigate whether a second processor — called “the collector”— could collect garbage concurrently with the activity of the other processor —for the purpose of this discussion called “the mutator”— which would be dedicated to the computation proper. In order to investigate a difficult problem, we have imposed upon our solution a number of constraints (compare [2]).

Firstly we wanted to reduce, as much as possible, the overhead on the activity of the mutator (as required for the cooperation with the collector.)

Secondly, we wanted the synchronization and exclusion constraints between the mutator and the collector as weak as possible. (The classical implementation presents in this respect the other extreme: a garbage collecting interlude can in its entirety be regarded as a single critical section that excludes all mutator activity!) We wanted in particular to avoid highly frequent mutual exclusion of “elaborate” activities, as this would defy our aim of concurrent activity: our ultimate aim was something like no more interference than the mutual exclusion of a single read or write of the same single variable. (One synchronization measure is evidently unavoidable: when needing a new node from the free list, the mutator may have to be delayed until the collector has appended some nodes to the free list. This is the now traditional producer/ consumer coupling; in the context of this article it must suffice to mention that this form of synchronization can be achieved without any need for mutual exclusion (see [3]). In our very first solution the overhead on the mutator was dependent on the question whether the collector was engaged on an odd or an even major cycle, a dependency which required a synchronization between mutator and collector; in our later solutions the need for this synchronization has been eliminated.)

Thirdly we did not want the mutator’s ongoing activity to impair the collector’s ability to identify garbage more than we could avoid. with a major cycle of the collector consisting of a marking phase followed by an appending phase, it is impossible to guarantee that the appending phase will append all the garbage existing at its beginning: new garbage could have been created between an appending phase and the preceding marking phase. (We do require, however, that such garbage, existing at the beginning of an appending phase but not identified as such by the collector, will be appended in the next major cycle of the collector.) Solutions we found, in which garbage created during a marking phase was guaranteed not to be appended during the next appending phase, have been rejected for that reason.

2. Preliminary investigations.

A counterexample taught us that the goal “no overhead for the mutator” is unattainable. Suppose that the nodes A and B are permanently reachable via a constant set of edges, while node C is reachable only via an edge from A to C . Suppose furthermore that from then on the mutator performs repeatedly the following sequence of operations
1)     making an outgoing edge from B point to C
2)     deleting the edge from A to C
3)     making an outgoing edge from A point to C
4)     deleting the edge from B to C .
The collector, which observes nodes one at a time, will discover that A and B are reachable from the roots, but may never discover that C is reachable as well: while A is observed by the collector, C may be reachable via B only, and the other way round. We may therefore expect that the mutator may have to mark in some way target nodes of changed edges.

Marking will be described in terms of colours. when we start with all nodes white, and, furthermore, can ensure that the combined activity of collector and mutator will make all reachable nodes black, then all white nodes can be identified as garbage. For each repetitive process —and the marking process certainly is one— we have always two concerns (see[1]): firstly we must have a monotonicity argument on which to base our proof of termination, secondly we must find an invariant relation which, initially true and not being destroyed, will still hold upon termination. For the monotonicity argument we have chosen (fairly obviously) that during marking no node will go back from black to white, or, stated in slightly more general terms:

| “at no moment during marking nodes will become lighter”.

For the invariant relation —a relation which must be satisfied both before and after the marking cycle— we must generalize the initial and final states of the marking process, and our first guess was (perhaps less obvious, but not unnatural)

P1: | “during marking there will be no edge pointing from a black node to a white one”.

Additional action is then required from the mutator when it is about to introduce an edge from a black node to a white one: just placing it would cause a violation of P1 . The monotonicity argument tells us that the black source node of the new edge has to remain black, and, therefore, P1 tells us that the target node of the new edge cannot be allowed to remain white. But the mutator cannot make it just black, because that could cause a violation of P1 between that new target node and its immediate successors. For that reason grey has been introduced as intermediate colour, and for the mutator we have considered the action —of which the “shading” part can be regarded as the overhead—

M1: | “the mutator changes an edge and shades its new target” .

Note 0. The “shading” of a node is defined to make a white node grey and to leave the colour of a grey or a black node unchanged. (End of note 0.)

Note 1. Disregarding P1 , the problem of node C , described at the beginning of this section, could also be solved by changing M1 into shading the old target instead of the new one; this would, however, lead to a solution of the type that we have rejected at the end of section 1. (End of note 1.)

As long as the whole of M1 , i.e. the combined changing of an edge and shading its new target, was taken as a single, indivisible “grain of action”, the invariant relation P1 was sufficient for a coarse-grained solution (as a matter of fact with the same collector as described in section 3 Encouraged by this success we tried to split action M1 up into two grains of action, one for changing the edge and one for shading the new target. Wanting to keep P1, which had been so successful, invariant, we had to choose as first indivisible grain of action the shading of the future target, and as second grain redirecting the edge towards the node just shaded, because doing it the other way round would have caused a temporary violation of P1 . Our solution, although presented in a manner sufficiently convincing to fool ourselves, contained a bug found by N.Stenning and M.Woodger [6]. If, after shading the future target, the mutator went to sleep, the collector could in its appending phase make that future target white again, in the next marking phase it could make the source black, whereafter the mutator would wake up again and could introduce a black-to-white edge; the new target node could then erroneously be considered as garbage.

In short: in the finer-grained solution we were heading for, total absence of an edge from a black node to a white one was a stronger relation than we could maintain. We could, however, retain the notion “grey” as “semi-marked”, more precisely, as representing the unfulfilled marking obligation: as before, the marking activity of the collector remains localized at grey nodes and their possible white successors. Again we tried to find and justify our fine-grained solution by using a —this time different!— coarse-grained solution as stepping stone.

3. A coarse-grained solution.

Relation P1 has to be replaced by a weaker one. (It will be replaced by P2 and P3 , as defined below.) In our previous effort we had made essential use of the fact that, after the collector had initialized the marking phase by shading all roots, the validity of P1 allowed us to conclude that the existence of a white reachable node implied the existence of a grey node (even of a grey reachable node, but the reachability of such an existing grey node was not essential). A weaker relation, from which the same conclusion can be drawn, is

P2:
“during the marking cycle (which the collector has initialized by shading all roots) there exists for each white reachable node a so-cal1ed “propagation path”, leading to it from a (not necessarily reachable) grey node, and consisting solely of edges with white targets (and, as a consequence, without black sources).”

Note 2. In the absence of edges from a black node to a white one, relation P2 is clearly satisfied. (End of note 2.)

Relation P2 is strong enough to draw at the end of the marking cycle the desired conclusion that all white nodes are garbage; all by itself, however, it is too weak to be kept invariant. It can be kept invariant when we restrict the existence of black-to-white edges by P3 —analogous to P1, but weaker— given by

P3: | “during the marking cycle only the last edge placed by the mutator may lead from a black node to a white one”.

Note 3. In the absence of black nodes, P3 is trivially satisfied. (End of note 3.)

When the mutator redefines an outgoing edge of a black node, it may direct it towards a white node: this new edge from a black node to a white one is permitted by P3 , but because the previously placed one could still exist and be of the same type, we consider for the mutator (instead of the earlier M1 ) , for the time being as a single grain of action:

M2: | “the mutator shades the target of the edge previously placed by it and changes an edge”.

Note 4. For the very first time that the mutator changes an edge, we can assume that, for lack of a previously placed edge, the shading will be suppressed or an arbitrary reachable node will be shaded; the choice does not matter for the sequel. (End of note 4.)

Action M2 has been carefully chosen in such a way that it leaves P3 invariant; it leaves, however, the stronger relation P2 and P3 invariant as well.

Proof. The action M2 cannot introduce new reachable nodes; it, therefore, does not introduce new white ones, for which extra propagation paths must exist. If the node whose successor is redefined is black, its outgoing edge that may have disappeared as a result of the change, was not part of any propagation path, and the edges of the old propagation paths will be sufficient to provide the new propagation paths. (Possibly we don’t need all of them as a result of the shading and/or white reachable nodes having become unreachable.) If the node whose successor is redefined was white or grey to start with, the net result of action M2 will be a graph without edges from a black node to a white one: if one existed, its target has now been shaded, and no new one has been introduced as the source of the new edge is not black. (It may have been shaded!) By Note 2, P2 still holds. (End of proof.)

We have now reached the stage where we can describe our first collector, which repeatedly performs the following program. (Our bracket pairs “if...fi” and ”do...od“ delineate our alternative and repetitive constructs respectively (see [1]), comments have been inserted between braces,and labels have been inserted for the discussion.) The program has two local integer variables i and k ; the nodes in memory are assumed to be numbered from 0 through M-1 .

marking phase:
begin  | {there are no black nodes; hence (see note 3) P3 holds
| C1:  | “shade all the roots” {P2 and P3};
|  | i:= 0; k:= M;
| marking cycle:
|  | do k > 0 → {P2 and P3}
|  |  | if  | C2:  | “node nr. i is grey:” →
|  |  |  |  |  | k:= M;
|  |  |  |  | C3:  | “shade the successors of node nr. i and make node nr. i black” {P2 and P3}
|  |  | ▯ | C2: | “node nr. i is not grey” →
|  |  |  |  |  | k:= k – 1 {P2 and P3}
|  |  | fi {P2 and P3};
|  |  | i:= (i + 1) mod M
|  | od  | {P2 and P3 and there are no grey nodes, hence all white nodes  are garbage}

end;
appending phase;
begin i:= 0;

|  | do i < M →  | {a node with a number < i cannot be black;  a node with a number ≥ i cannot be grey;  and is grabage, if white}
|  |  | if | C2: | “node nr. i is white” →
|  |  |  |  | C4: “append node nr. i to the first free list”
|  |  | ▯ | C2: | “node nr. i is black” →
|  |  |  |  | C5: “make node nr. i white”
|  |  | fi i:= i +1
|  | od {there are no black nodes}
end

The indivisible actions of the collector —between the executions of which actions M2 of the mutator may occur— are

1) | “shading of a single root” (from which C1 is composed: the order in which the roots are shaded is irrelevant)

2) | establishing the current colour of node nr. i (labeled “C2”)
3) | the total actions C3 , C4 (see, however, the Appendix) and C5 .

Remark 1. with a more elaborate administration local to the collector —a list of grey or possibly grey nodes— a probably much more efficient marking phase could have been designed. For the sake of simplicity we have not done so. (End of remark 1.)

We observe that (even independent of the colour of node nr. i !) action C3 : “shade the successors of node nr. i and make node nr. i black” can never cause a violation of P2 and P3 : the shading of the successors can never do any harm; as a result of the shading the outgoing edges of node nr. i are no longer needed for a propagation path, and making node nr. i black maintains the existence of the propagation paths needed,without introducing an edge from a black node to a white one.

Marking has been completed when all grey nodes have disappeared. Its detection by the collector, however, presents some problems. In the marking cycle of the collector as given above, k is reset to M each time the collector encounters a grey node, and the marking cycle terminates with a scan past all nodes, during which no grey nodes have been encountered. If we had only the collector to consider, the conclusion that upon termination of the marking cycle grey nodes are absent would be trivial; due to the ongrey nodes!— a more subtle argument is required to justify the conclusion that after a collector scan past all nodes, during which no grey nodes have been encountered, there are, indeed, no grey nodes. The argument is as follows.

Absence of grey nodes implies on account of P2 that all white nodes are garbage and that all reachable nodes are black. Hence, the state characterized by the absence of grey nodes is stable during marking: the absence of white reachable nodes prevents the mutator from introducing grey ones and the absence of grey nodes prevents the collector from doing so. Consider now the collector scan past all nodes during which no grey nodes have been encountered. Because the mutator leaves a grey node grey, no grey node can have existed at the beginning of that scan, i.e. the stable state must already have been reached at the beginning of that scan.

Finally, termination of the marking cycle is guaranteed because of the monotonicity of the colouring history of each node, and because of the fact that resetting k to M is always accompanied by effective darkening of at least one node (nr. i to be precise).

When the appending phase starts, all reachable nodes are black and all white nodes are garbage. Note that the existence of black garbage is not excluded. The appending phase deals with each node in turn: as long as it has not been dealt with (i.e. has a number ≥ i ) it cannot change colour: if black, it remains black because the mutator can only shade it, and if it is white, it is garbage and, by definition, the mutator won’t touch it. As soon as it has been dealt with (i.e. has a number < i ), it has been white and can at most have been shaded by the mutator. Black garbage at the beginning of the appending phase will not be appended during that appending phase, it will only be made white; during the next marking phase it will remain white, and the next appending phase will indeed append it. Therefore, no garbage, once created, will escape being collected.

4. A solution with a fine-grined collector.

In this section we show how the course-grained solution of section 3 can be used as a stepping stone for a solution which admits, as far as the collector is concerned, a finer grain of interleaving. In particular we shall show how C3 can be broken open as a succession of five indivisible subactions, say ( m1 and m2 being local variables of the collector):

C3.1: | m1:= number of the left-hand successor of node nr. i ;
C3.2: | shade node nr. m1 ;
C3.3: | m2:= number of the right-hand successor of node nr. i ;
C3.4: | shade node nr. m2 ;
C3.5: | make node nr. i black .

None of the actions C3.1 , C3.2 , C3.3 , and C3.4 can cause a violation of P2 and P3 . The actions C3.1 and C3.3 cannot do so because they leave no trace in common memory, and the actions C3.2 and C3.4 cannot do so, because shading cannot do so. Besides that, because shading of a node commutes with any number of actions M2 of the mutator, we have, by the time that the collector starts with C3.5 , a state as if the shading of node nr. m1 had been part of C3.1 and the shading of node nr. m2 had occurred simultaneously with C3.3 . Without loss of generality we can, therefore, continue our discussion as if “shade right-hand successor” and “shade left-hand successor” are available as indivisible actions. The problem, however, lies with C3.5 : can we safely make node nr. i black? Note that neither m1 , nor m2 needs still to be one of its successors: m1 and m2 even never need to have been its left- and right-hand successor simultaneously! A more thorough study of the mutator, however, reveals that it is safe.

Proof. During the marking phase we define a changing set of edges to which we given the meaningless term “Q-edges”.

Remark 2. We could only get the argument straight after the introduction of a meaningless term such as “Q-edges”. At first we used terms like “inessential” or “dispensable”, etc., but they all messed up our thinking. The problem is that an edge that is not “inessential” —in the above, special meaning of the word— is not “essential” —in the normal sense of the word— . It was very instructive to experience how totally misleading the choice of so-called “meaningful identifiers” can be. (End of remark 2.)

Remark 3. Note that we only define the set of Q-edges for our benefit. The mutator and collector would have a hard time if they had to update it explicitly: in the jargon the term “ghost variable” is sometimes used for such an entity. (End of remark 3.)

The set of Q-edges is defined as follows as a function of the evolving computations:
1)     at the beginning of the marking phase the set of Q-edges is initialized with all the edges with a grey target
2)     each time a white node becomes gray, all its incoming edges (that were not already a Q-edges ) are added to the set of Q-edges
3)     when action M2 , seen as a replacement of an outgoing edge, replaces a Q-edge —or an edge that, according to the second rule, would have become one as a consequence of M2’s shading act— the new edge that replaces it, is also a Q-edge : it “inherits the Q-ness” from the edge it replaces.

The above rules imply that a Q-edge is never needed for a propagation path. The third rule, all by itself, implies that once the left-hand outgoing edge of a node is a Q-edge, it will remain so, no matter how often redirected by the mutator, and that the same holds for the right-hand outgoing edge. In short: when, since the beginning of the marking phase, a given node has had a grey left-hand successor and has had a grey right-hand successor, it has two outgoing Q-edges, and making it black will never cause violation of P2 . It won’t violate P3 either: if it has a white successor, the corresponding edge must have been the last one placed by the mutator (it can therefore have at most one white successor) and that edge from a black node to a white one is the edge explicitly allowed by P3 . (End of proof.)

Note 5. In breaking up C3 we have placed C3.5 “make node nr. i black” at the end. As making a node black commutes with all other actions M2 and C3.1 through C3.4 , we could also have placed it at the beginning, before dealing (in some order) with the successors; P2 and P3 could then be violated temporarily. (End of note 5.)

5. A solution with a fine-grained mutator as well.

The treatment in the previous section was greatly simplified by the circumstance that the mutator could only interfere via a single type of action: as far as the collector was concerned, the mutator activity could be considered as a stream of actions M2, and it was therefore, so to speak, not necessary to take the mutator’s “instruction counter” into account. It was the possibility of this simplification that motivated us to postpone the transition to a fine-grained mutator till the end; this postponement was the more seductive because we thought that the following very simple argument would justify that transition.

It is obvious that no harm is done if at random moments a daemon would shade a reachable node. We now assume a friendly daemon that, between any two successive actions M2 of the mutator, shades the target of the last placed edge, and the idea was that then it would make no difference if M2 did not do the shading anymore, and that therefore it was safe to replace M2 by the succession of the following two separate indivisible subactions:

| “redirect for a reachable node an outgoing edge towards a reachable node”;
| “shade the target of the edge just placed”

It was David Gries who pointed out to us that, although the conclusion was correct, the argument contained a flaw: the friendly daemon’s activity does not exclude that, at the beginning of an action M2 , the node just shaded by the daemon in the meantime has been made white again by the collector, and the combination of daemon with shading M2 is therefore not necessarily semantically equivalent to the combination of daemon with M2 , from which the shading has been removed.

The full argument is that, with our friendly daemon, for the initial state of an action M2 during a marking cycle we can assert (besides P2 and P3) the absence of an edge from a black node to a white one, regardless of the question whether the last shading by our friendly daemon took place during the current marking phase or earlier: in the first case we observe that the only edge allowed by P3 to point from a black node towards a white one has a target that is at least grey, in the second case we observe that the marking phase started without edges pointing from a black node to a white one and that during marking the collector cannot introduce them all by itself. As a result of the guaranteed absence of an edge from a black/node to a white one, the proofs that M2 leaves P2 and P3 invariant is now also valid if M2 does not shade at all.

Remark 4. The detailed implementation of what we have described as “a grain of interleaving” falls very definitely outside the scope of this paper: many techniques —even allowing concurrent access to the same unit of information— are possible (see[3]). (End of remark 4.)

In retrospect.

It has been surprisingly hard to find the published solution and justification. It was only too easy to design what looked —sometimes even for weeks and to many people— like a perfectly valid solution, until the effort to prove it to be correct revealed a (sometimes deep) bug. Work has been done on formal correctness proofs ([4], [5]), but a shape that would make them fit for print has, to our tastes, not yet been reached. Hence our informal justification (which we do not regard as an adequate substitue for a formal correctness proof!). Whether its stepwise approach —which this time seems to have been successful in reducing the case analyses— is more generally applicable, is at the moment of writing still an open question.

When it is objected that we still needed rather subtle arguments, we can only agree whole-heartedly: all of us would have preferred a simpler argument! Perhaps we should conclude that constructions that give rise to such tricky problems are not to be recommended. One firm conclusion, however, can be drawn: to believe that such solutions can be found without a very careful justification is optimism on the verge of foolishness.

History and acknowledgements. (As in this combination this is our first exercise in international and inter-company cooperation, some internal credit is given as well.) After careful consideration of a wider class of problems the third and fifth authors selected and formulated this problem, and did most of the preliminary investigations; the first author found a first solution during a discussion with the latter, W.H.J.Feijen and M.Rem. It was independently improved by the second author —to give the free list a root and mark its nodes as well, was his suggestion— and, on a suggestion made by John M.Mazola, by the first and the third author. The first and the fourth merged these embellishments, but introduced the bug that was found by N.Stenning and M. Woodger. The final version and its justification are the result of the four authors in the Netherlands. The active and inspiring interest shown by David Gries is mentioned in gratitude.

References.

1. | Dijkstra, Edsger W., Guarded Commands, Nondeterminacy and Formal Derivation of Programs. Comm. ACM 18, 8 (Aug. 1975), 453-457.
2. | Steele Jr., Guy L., Multiprocessing Compactifying Garbage Collection. Comm. ACM 18, 9 (sep. 1975), 495-503.
3. | Lamport, Leslie, On Concurrent Reading and Writing. (Submitted to the Comm. ACM.)
4. | Gries, David, An Exercise in Proving Parallel Programs Correct. (Submitted to the Comm. ACM.)
5. | Lamport, Leslie, Report CA-7508-0111, Massachusetts Computer Associates, Inc.
6. | Woodger, M., Private Communications.

Appendix

Here we give an example of how the free list and the operations such as taking a node from or appending a node to the free list can be implemented. We consider the nodes of the free list ordered according to “age”. For each node in the free list, the right-hand successor is NIL , the left-hand successor is NIL for the youngest node and is the next-younger one for the others. We have a root called TAKE , its left-hand successor and its right-hand successor are both the oldest free node; we have a second root called APP , whose left-hand and right-hand successor are both the youngest free node.

Taking a free node —and making it the left-hand successor of some reachable node X , say— can be done in the following steps (shown in a hopefully self-explanatory notation):

| X.left:= TAKE.left;                       (All four actions should follow
| TAKE.left:= TAKE.right.left;            the shading convention chosen.)
| TAKE.right.1eft:= NIL;
| TAKE.right:= TAKE.left

Appending,:say, node Y —in action C4— could be done by:

| Y.left:= NIL; Y.right:= NIL;
| APP.left:= Y;
| APP.right.left:= Y;
| APP.right:= APP.left

When a minimum of two free nodes is maintained, the collector that appends is certain only to deal with nodes that are left alone by the mutator, and the action E4 need not to be regarded as a single indivisible action, but is trivially allowed to be broken up in the above subactions. The synchronization guaranteeing the lower bound for the length of the free list is here supposed to have been implemented by other, independent means.

5th of January 1977

Transcribed by Martin P.M. van der Burgt
Last revision 2015-01-23 .

  EWD 596a

Trip report E.W.Dijkstra, Copenhagen 10-12 Nov.1976

A short report on a short trip. Together with Ria —my wife— I have been for three days and two nights in Copenhagen as the guest of UUA/E (Univac Users Association / Europe), at its Fall76 Conference, where I was one of the leading speakers for the general session.

We left on Tuesday evening and returned on Saturday morning, travelling by night train (12 hours). On our way up North we did not sleep too well, for our cabin was too warm to be really comfortable. (We had turned off the heating, but it was the corridor along the cabins that was too hot.) Our journey back was much better. (In contrast to previous trips, however, I noticed both times when the train went aboard the ferry.) I can recommend this way of transport: the travelling costs for both of us were less than if I had travelled alone by air, and the train trip was much more peaceful.

Copenhagen is not a town to live in on "Five dollars a day"! The official price for our —excellent— hotel room was $83 a day! (I did not pay it, for we were there at Univac's expense, and Univac did not pay it either, as Univac had a reduced rate of $33 a day, but that was quite another matter.) A pair of leather jack-boots of $150, for instance, was no exception at all.

It is, however, a nice town to walk through and do some shopping. (Friday was for me a holiday and the two of us did just that.) "Den Permanente" and "Illum's Bolighus", although not so exceptional on the European scene as ten years ago, are still worth a visit when you are near: they are very beautiful shops.

The visit to the UUA/E Conference was no disappointment because I went with very few expectations. The public seemed very much of the same type as I had observed at an ABCU Meeting (Association of Burroughs Computer Users) in Amsterdam, the Univac officials present seemed less qualified than their Burroughs counterparts. I attended one sales presentation: the obligatory slides with text were adorned with colour pictures of nice young ladies (!), looking lovingly towards a Univac 1100/800 cabinet or an "intelligent terminal". It was worse than just offensive, it was sickening. And, of course, we were offered lunch by a few of the high Univac officials —directors of various software development outfits— but I was not impressed by the gentlemen. (As a matter of fact I was depressed, because in view of their position, their apparent superficiality was a little bit alarming. Ria, who attended the lunch as well and observes other things, thought that one of them was very nervous, so we may give him the benefit of the doubt.) I must make an exception for dr. George Champine (Univac, Roseville, Minnesota), who gave a nice and instructive talk on how external influences could cause hardware malfunctioning and on precautions taken with the aim of reducing the frequency of such undesirable occurrences; after his talk the two of us went back to our hotel where we talked for about two hours, and on hardware he seemed very knowledgeable, on software much less so, but eager to learn. (While in Zurich he had tried to contact Niklaus Wirth, as he had recently (!) heard interesting things about PASCAL, but Niklaus was already in Palo Alto.)

*             *
*

I gave essentially the same talk (EWD566: "Programming: from craft to scientific discipline.")) as I had given in Japan. This time I could estimate the extent to which it served its purpose, viz. to explain to managers the nature and the significance of the development in programming methodology as had taken place during the last, say, eight years. Judged by the number of questions posed to me during the discussion period the next day, the impact has not been impressive. (Michael Jackson —of "Michael Jackson, Inc,"—, the other invited speaker for the general session, had the same lack of noticeable reaction, and that amazed me much more, for he has great experience in presenting an overview of his methodology in such a way that people want to hear more about it, and I thought that he had done very well.) Was the problem that in view of the conference theme, we both spoke about programming while the majority of managers don't know how to do that?

Friday evening in the train, before I went to sleep I have been pondering. Perhaps I should write a text —even without being invited to talk on the subject!— on something like "What management should know about scientists". (The writing of a —perhaps equally necessary!— complementary text "What scientists should know about management" I think I should leave to someone else.) I don't expect a manager to be a scientist, the manager who has been a scientist doesn't present a problem either. The problem starts with the manager who has not an inkling of what scientific thought implies, and who hasn't the foggiest notion of what a "mental quantum jump" means, because he has never made one himself. I was reminded of my experiences with the Dutch Bank, where the directors (all of them with a training in Law) behaved like the chief of the primitive tribe, who objected to modern medical treatment against smallpox for his subordinates, as the experience would weaken their faith in his witch doctors.

*             *
*

Perhaps I had been given too favourable a picture of the average participant when the UUA/E Chairman invited me half a year ago. This time I learned that (male) participants preferring to join the Ladies Program are at these conferences not unusual. (On account of earlier experiences, this was now forbidden for Italians....)

*             *
*

My growing impression that a larger and larger fraction of the computing community is getting more and more "innovation proof" —a development of which I have received lately a few alarming indications— has not been contradicted at the UUA/E Conference and that, of course, is a little bit sad. But apart from that, it was a very nice trip that has been sufficiently instructive not to regret it. On the contrary.

*             *
*

There has been a time when I did not yet know the meaning of the verb "to enhance". Then came a period during which I thought that I knew its meaning. As a result of the Univac sales presentation, that second period, I am afraid, has now ended.

Plataanstraat 5 NL-4565 NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Wed, 31 Jan 2007

EWD597

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Yet another note about termination.

I had never thought that I would have to write this note, but apparently I have to. In a paper I had written:

| “For each repetitive process we must have a monotonicity argument on which to base our proof of termination.”

To my utter amazement, the Editor of the journal to which it was submitted. expressed in his letter seven lines of severe doubt about the above statement, ending with: “Perhaps it is true, but it is a rather sweeping claim.” I could only conclude that the need for a monotonicity argument for termination proofs is not the common knowledge I supposed it to be, and that the need, even when stated, is not intuitively obvious to everybody.

Because perhaps my Editor’s hesitation was caused by the nondeterminacy that also played a role in that paper, let us consider the general —and in general nondeterministic— repetitive construct DO:

| do B1 → S1 ▯ ... ▯ Bn → Sn od .

On my recent trip through the USSR, Tony Hoare, who is presently more operationally inclined than I, described it as

| {if B1 →S1 ▯ ... ▯ Bn → Sn fi}* or {IF}*

where with {...}* he meant “as many successive executions as possible”, where the execution of IF is regarded when all the guards are false (non BB). A termination proof for a given state x means that after a finite number of steps —i.e. applications of IF — the state non BB is reached. The actual number of steps may not be determined by x , e.g. do y ≥ 2 → y=: y - 2 ▯ y ≥ 1 → y:= y - 1 od with initially y ≥ 2 ; guaranteed termination for the initial state x , however, means that the maximum number of steps needed is finite. Denoting this maximum number by mn(x) , termination is guaranteed in all points x where mn(x) is finite. Denoting the transformation of the state as effectuated by IF symbolically by x=: F(x) —where F may be a partial function: F(x) need not be defined for states x , in which BB does not hold— it is clear that with the above meaning of mn we must have

| (mn(x) > 0) ⇒ (mn(F(x)) ≤ mn(x) -1) .

Note. If F(x) is a single valued function, the program is deterministic and the maximum number of steps needed is also the actual number of steps needed; and then we have

| (mn(x) > 0) ⇒ (mn(F(x)) = mn(x) - 1) . (End of note.)

Hence, for all initial states in which termination is guaranteed to occur, the finite function mn(x) which decreases monotonically by at least one at each application of x:= F(x) exists; conversely: each proof of termination boils down to a proof of the existence of such a monotonically decreasing function.

*              *
*

Because my challenged claim is one about all possible arguments for termination, a less operational approach that is directly based on the axiomatic definition of the repetitive construct might be appreciated.

For the repetitive construct DO the predicate transformation —see [1], page 35— is given in terms of the predicate transformation of the corresponding alternative construct IF by

| H₀(R) = R and non BB |
| Hk+1(R) = wp(IF, Hk(R)) or H₀(R) | (2)
| wp(DO, R) = (E k: k ≥ 0: Hk(R)) . |

From (2) it follows that for i < j we have Hi(R) ⇒ Hj(R) for all states and all post-conditions R . Proving termination means showing that a point x satisfies wp(DO, T) , i.e. that there exists a value t(x) such that Hk(T) holds there for all values of k satisfying k ≥ t(x) . As x satisfies an invariant relation, P say, it suffices to prove that

| (P and t ≤ k) ⇒ Hk(T) for all states x

But this is the same formula as on the top of [1], page 42. In view of the fact that (2) defines Hk+1 in terms of Hk , mathematical induction over k is by definition the only available pattern of reasoning. The argument is carried out in [1], pages 41/42; it shows quite clearly how for the transition from k to k+1 the monotonicity assumption about IF , viz.

| (P and BB and t ≤ t0+1) ⇒ wp(IF, t ≤ t0)

is essentially needed.

[1] Dijkstra, Edsger W., “A Discipline of Programming”. Prentice Hall, 1976

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
NL-4565 NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2014-12-12 .

06xx

07xx

709: My hopes of computing science

710: When messages may crawl, II (A sequel to EWD708)

711: Trip report E.W.Dijkstra, Ithaca, Albany, Austin (Texas), 26/5 – 10/6 1979

712: Trip report E.W.Dijkstra, Antwerp, 24–29 June 1979

713: On a problem posed by W.H.J.Feijen

714: Trip report E.W.Dijkstra, Mission Viejo, Santa Cruz, Austin, 29 July – 8 September 1979

715: Trip report E.W.Dijkstra, Munich – London, 16–29 September 1979

716: A short talk to my students about money

717: An exercise in exposition

718: Assembly conventions for the EDSAC

719: On not duplicating volatile information

720: Why correctness must be a mathematical concern

721: The design of a state space with a useful structure (I)

722: A book review for the IBM Systems Journal

723: On W.H.J.Feijen’s solution for the lexicographic minimum of a circular list

724: Een gotspe

724E: A chutspa

725: Trip report E.W.Dijkstra, Liege, Nov.–Dec.1979

726: How Dutch Informatics fell between two chairs

727: Trip report E.W.Dijkstra, U.S.A. 12 Jan. – 2 Feb. 1980

728: A problem solved by Netty van Gasteren and me

729: On well-shaped mathematical arguments

730: On two types of infinite sets of infinite sequences (by the Tuesday Afternoon Club)

731: An experiment in mathematical exposition

732: The teachability of mathematical thinking (Draft contribution to “Mathematics Tomorrow”)

733: Naar aanleiding van Experimentele post-propadeuse opleiding voor informatica-ingenieur aan de THE” (Eindhoven februari 1980 SOO/jc/sdb)

734: The superfluity of the general semaphore

735: A mild variant of Combinatory Logic

736: Recording the structure of trees in their leaves

737: A notational alternative for quantification

738: More mathematical folklore

739: A somewhat open letter to the Editor-in-Chief of Acta Informatica

740: A short proof of one of Fermat’s theorems

741: Partitioning the edges of the complete graphs into trees or cycles (by the Tuesday Afternoon Club)

742: A sequel to EWD740

743: A new policy for Mathematics Inc.?

744: A short note on symmetric distributed arbitration

745: Trip report E.W.Dijkstra, Los Angeles, Austin (Texas), and Portland, 6–28 August 1980

746: Trip report E.W.Dijkstra, Newcastle-upon-Tyne, 1–5 Sep. 1980

747: Comments on MIL–STD–1862, 28 May 1980

748: A somewhat open letter to Wladislaw M.Turski

749: On the productivity of recursive definitions

750: American programming’s plight

751: Mainly on the omission of parentheses

752: Distributed Arbitration (DRAFT, with C.S.Scholten)

753: On a theorem by Lambek and Moser

754: An error in EWD744

755: Very elementary number theory redone

756: A postscript to EWD755

757: A misguided educational effort

758: An intriguing example

759: A somewhat open letter to D.A.Turner

760: A somewhat open letter to F.Kroeger

761: Een kanttekening

762: We mathematicians are losing the race

763: A proof by Rutger M.Dijkstra and me

764: Repaying our debts

765: A Hungarian problem

766: An educational stupidity

767: A.J.Martin’s solution of the Hungarian problem

768: Largely on nomenclature

770: D.A.Turner’s reply

771: About 2-coloured 6-graphs

772: A methodological sequel to EWD771

773: Trip report E.W.Dijkstra, Han-sur-Lesse, 7–12 Jan. 1981

774: Trip report E.W.Dijkstra, California, 17–31 January 1981

775: On Kleinrock’s Theorem

776: Lambek and Moser revisited

777: A word of welcome (Draft)

778: A somewhat open letter to Nils J.Nilsson

782: A stupid notation

783: The administration as social disease

786: Trip report E.W.Dijkstra, England, 23 April 1981

786a: Sets are Unibags

787: A (new?) proof of a theorem of Euler’s on partitions

788: What we seem to have learned (with A.J.M. van Gasteren)

790: Trip report E.W.Dijkstra, München, 19 May 1981

791: The psychology of the user

793: The analysis of a two-person game

796a: Smoothsort, an alternative for sorting in situ

797: Fibonacci numbers and Leonardo numbers

798: Trip report E.W.Dijkstra, Newcastle, 19–25 July 1981

799: Trip report E.W.Dijkstra, Marktoberdorf, 26/7–10/8/81

EWD 709

E.W. Dijkstra Archive: Copyright Notice

The following manuscript

EWD 709: My hopes of computing science

is copyright 1979 IEEE. Published in Proc. 4th Int. Conf. on Software Engineering, Sept. 17-19, 1979, Munich, Germany.

This material is posted here with permission of the IEEE. Such permission of the IEEE does not in any way imply IEEE endorsement of any of The University of Texas's products or services. Internal or personal use of this material is permitted. However, permission to reprint/republish this material for advertising or promotional purposes or for creating new collective works for resale or redistribution must be obtained from the IEEE by sending a blank email message to .

By choosing to view this document, you agree to all provisions of the copyright laws protecting it.

MY HOPES OF COMPUTING SCIENCE

Edsger W.Dijkstra

BURROUGHS
Plataanstraat 5
5671 AL Nuenen
The Netherlands

Formulae have always frightened me. They frightened me, I remember, when I was sixteen and had bought my books for the next year. I was particularly alarmed by my new book on trigonometry, full of sines, cosines, and Greek letters, and asked my mother —a gifted mathematician— whether trigonometry was difficult. I gratefully acknowledge her wise answer:

"Oh no. Know your formulae, and always remember that you are on the wrong track when you need more than five lines."

In retrospect, I think that no other advice has had such a profound influence on my way of working.

A quarter of a century later, formulae still frightened me. When I saw Hoare's correctness proof of the procedure "FIND" for the first time, I was horrified, and declared that such a ballet of symbols was not my cup of tea.

And even now my first reaction to formulae, written by someone else, is one of repulsion —in particular when an unfamiliar notational convention is used— and when reading an article, my natural reaction is to skip the formulae.

At the same time I have a warm appreciation for well-designed formalisms that enable me to do things that I couldn't possibly do without them. I acquired almost naturally my agility in the first-order predicate calculus like I had learned trigonometry 25 years earlier, and in both cases using the tool effectively gives me great intellectual satisfaction.

I can explain this love-hate relationship only in one way. Why should I continue to shudder at the sight of formulae, whereas in the meantime I should know better? I think that, by now, I know from sad experience that only too many mathematicians and computing scientists have had the misfortune of missing my mother's wise advice at the impressible age of sixteen. Too often the five-line limit is ignored and, instead of using the compactness of the formal notation to keep the text concise, authors use it —in a still limited space!— for the introduction of much more complexity than I feel comfortable with. Hence my shudder. (I don't know how you feel about the famous report on the Algorithmic Language ALGOL 60. I admire it very much and think its fame well-deserved. But in retrospect I think ALGOL 60's syntax, though rigorously defined, more baroque than is desirable, and it is certainly the compactness of BNF that has made the introduction of so much arbitrariness possible.)

Later I learned that for the kind of effectiveness that I loved, mathematicians had a perfectly adequate, technical term: they call it "mathematical elegance" or "elegance" for short. I also discovered that the term is much more "technical" than most mathematicians suspect, much more "technical" in the sense that even among mathematicians of very different brands there exists a much greater consensus about what is a really elegant argument than they themselves seemed to be aware of. Show any mathematician a really elegant argument that is new for him: at the moment it becomes his intellectual property, he start to laugh!

The discovery of this strong consensus has made a great impression on me. It was very encouraging. It came at a moment that —in private, so to speak— I had already come the conclusion that in the practice of computing, where we have so much latitude for making a mess of it, mathematical elegance is not a dispensable luxury, but a matter of life and death. But I hesitated to say so very much in public, just for fear of pushing another buzzword; now I dare to do it, assured as I am that mathematical elegance is a clear notion, firmly rooted in our culture. But I am also aware of the fact that my sensitivity for it can be tracked down to how I was educated in my youth.

*                        *
*

Language is another issue. I often feel uneasy about it. At the time I got my mother's wise advice about trigonometry, I wrote many poems, and often I was dissatisfied: I knew that what I had written was not "it", yet I found myself unable to identify the shortcoming, and had to console myself with A.A.Milne's "As near as you can get nowadays.".

My first task at the Mathematical Centre in Amsterdam was writing the precise functional specification for the computer that was there at that moment under design. I did so to the best of my ability, and thought I had done so rather well —and, from the point of precision, I had—. But it was something of a shock for me to discover that, within a few days after its appearance, my beautiful report was generally known as "The Appalling Prose".

At that time I only felt that we had to learn how to write better about our own subject. I think that it was not until 1960, when Peter Naur acquainted me with Wittgenstein's famous quotation:

"What can be said at all, can be said clearly; and on what we cannot talk about, we have to remain silent."

that it slowly dawned upon me that, therefore, we had to learn to think better about our own subject.

In the meantime, I had another linguistic shock: I became a member of the ACM, shortly before its Communications started to appear. Prior to that I had hardly had any exposure to the foreign literature. What I then read was written in a way so totally different from what I, in relative isolation, had acquired as my own habit, that I was absolutely flabbergasted. The heavily anthropomorphic terminology was totally new for me, and hardly compatible with my cultural roots; so was the animism betrayed by the term "bug": we had never called a bug a bug, we had always called it an error.

Still hesitating whether or not to adopt the jargon, I was confronted with a next term of a glaring inadequacy —was it "program maintenance"? I don't remember— and I knew that I had to design my own way of writing about our subject in English, as I had done in Dutch. In retrospect this may strike you as a proud decision, but it wasn't: it was a decision taken in desperation, for otherwise I could not think in the way I wished to think.

One more remark about language that seems relevant. With English being computing science's Esperanto, colleagues with English as their native tongue often feel somewhat guilty about what they regard as their undeserved advantage over most foreigners. Their feeling of guilt is misplaced, because the advantage is ours. It is very helpful to have to do your work in what always remains a foreign language, as it forces you to express yourself more consciously. (About the most excellent prose written in our field that I can think of, is to be found in aforementioned ALGOL 60 Report: its editor had the great advantage of being, besides brilliant, a Dane. I have always felt that much of the stability and well-deserved fame of ALGOL 60 could be traced down directly to the inexorable accuracy of Peter Naur's English.)

*                         *
*

The above has been presented, by way of background information, as a help for the interpretation of what follows: a summary of my hopes of computing science. This topic is not as frivolous as it might seem at first sight. Firstly, already in my early youth —from 1940 until 1945— I have learned to hope very seriously: secondly, my hopes of computing science —which have directed most of my work— have shown a great stability. They evolved: some hopes became fulfilled, some hopes, originally far away, became almost challenges as their fulfillment began to appear technically feasible. Admittedly they are only my hopes, but they are of a sufficiently long standing that I now dare to confess them.

How were we attracted to the field of automatic computing? Why do we remain fascinated? What is really the core of computing science?

Well, everybody got attracted in his or her way. I entered the field by accident. I became attracted by the combination of the urgency of the problems that needed to be solved for the recovery of my country from the damage done to it in World War II, and the discovery that carefully applied brains were an essential ingredient of the solutions. Up till that moment I had never been quite sure whether my love of perfection had been a virtue or a weakness, and I was greatly relieved to find an environment in which it was an indispensable virtue.

I became —and remained— fascinated by the amazing combination of simplicity and complexity. On the one hand it is a trivial world, being built from a finite number of noughts and ones, so trivial that one feels oneself mathematically entitled, and hence morally obliged, to complete intellectual mastery. On the other hand it has shown itself to be a world of treacherous complexity. The task that should be possible, but wasn't, became the fascinating challenge.

For me, the first challenge for computing science is to discover how to maintain order in a finite, but very large, discrete universe that is intricately intertwined. And a second, but not less important challenge is how to mould what you have achieved in solving the first problem, into a teachable discipline: it does not suffice to hone your own intellect (that will join you in your grave), you must teach others how to hone theirs. The more you concentrate on these two challenges, the clearer you will see that they are only two sides of the same coin: teaching yourself is discovering what is teachable.

As I said, my hopes have evolved, and one way in which they did so was by becoming more precise and more articulate. Ten years ago I expressed my dissatisfaction with the then current state of the art by aiming at programs that would be "intellectually manageable" and "understandable". At the time they represented the best way in which I could express my then still vague hope; I apologize for these terms to the extent that they became buzz-words before they had become sufficiently precise to be technically helpful. What does it help to strive for "intellectual manageability" when you don't know how you would prefer to "manage intellectually"? What guidance do you get from the goal of "understandability" before you have chosen the way of understanding? Very little, of course.

I particularly regret my use of the term "understanding", for in the combination "ease of understanding" it has added to the confusion by not inviting to distinguish carefully between "convenient" and "conventional", and that distinction, I am afraid, is vital: I expect for computing scientists the most convenient way of thinking and understanding to be rather unconventional. (That is not surprising at all, for, after all, also thinking is only a habit, and what right do we have to expect our old habits to be adequate when faced, for the first time in our culture, with a drastically novel universe of discourse?)

My hope became more articulate, when programming emerged as an application area par excellence of the techniques that are well-known because we struggle with the small sizes of our heads as long as we exist. they are roughly of three different forms:
1)       separation of concerns and effective use of abstraction
2)       the design and use of notations, tailored to one's manipulative needs
3)       avoiding case analyses, in particular combinatorially exploding ones.

When faced with an existing design, you can apply them as a checklist; when designing yourself, they provide you with strong heuristic guidance. In my experience they make the goal "intellectually manageable" sufficiently precise to be actually helpful, in a degree that ranges from "very" to "extremely so".

For the techniques of scientific thought I called programming an application area "par excellence", and with that last term I meant two things: indispensable and very effective.

That they are indispensable seems obvious to me. They summarize the only ways in which we have ever been able to disentangle complexity more or less successfully; and we cannot expect our designs to turn out to be any better than the ways in which we have thought about them, for that would be a miracle. The indispensability of the techniques of scientific thought is, admittedly, only my belief, and you are free to dismiss it; you could remark that I am primarily a scientist, and that to someone whose only tool is a hammer, every problem looks like a nail.

I am, however, strengthened in my belief of their indispensability by the outcome of the experiments that we could take, viz., trying how effectively we could learn to apply the techniques of scientific thought. Of the experiments I am aware of, the outcome has been very encouraging. Engaged in these experiments, you start to treasure the just solvable problems, and try to present the most elegant solution you can think of as nicely as possible. I have now joined that game for several years and cannot recommend it warmly enough. It is a highly rewarding and fascinating learning process.

It is very rewarding for its immediate benefit: a significant decrease in the average amount of effort, needed to find a solution. The untrained thinker —unless a genius— spends inordinate amounts of effort in avoidable complications, and only too often, unaware of their avoidability, he fails to disentangle himself again: a vast amount of effort has then been spent on producing an inferior solution.

Our educators have something to answer for. Reading the literature, I must come to the sad conclusion that untrained thinkers are rather the rule than the exception: people have been taught facts and tricks, but not a methodology for using their brains effectively.

The scope of the educational challenge is enormous. It you accept it —and I think we should— you have my blessing. You'll need it —and much more!— because you will encounter formidable obstacles on your way. You'll have at least two dragons to slay. Confusing "love of perfection" with "claim of perfection", people will accuse you of the latter and then blame you for the first. Furthermore, in spite of all the evidence to the contrary, the teachability of thinking effectively will be flatly denied, and your methodological contributions —needed more than anything else— will be dismissed as "for geniuses only": remember, while fighting this second dragon, that most frequently the term "genius" is not used as a compliment, but only as an alibi for the mentally lazy.

*                  *
*

For a prosperous future of computing science —like for any science— it is essential that its achievements are published well, so that the next generation can start where the preceding one left. Above, I have expressed some of my dissatisfaction about the quality of today's publications in our field. The problem is a very serious one, and it is more than a purely educational problem. How do we publish a sophisticated piece of software? (We can reproduce the code, but that is only fit for mechanical execution. I meant "to publish" in the scientific sense: our text should fully enlighten the attentive reader.) Admittedly, many papers about algorithms could be written much better already now, but beyond a certain limit, no one knows for certain, how to do it well! And that universal inability makes it a technical problem, urgent and as yet unsolved. One of my fervent hopes is that we shall solve it.

How should a well-written publication about a sophisticated piece of software look like? We don't know yet, but two things seem certain. Firstly, the texts will be "mathematical" in the sense of Morris Kline, when he wrote:

"More than anything else mathematics is a method."

Secondly, the texts will have to be written in a style that is very different from the style of traditional mathematical texts. Depending on your mood you may regard this either as disturbing or as exciting, but in any case you should be convinced of the necessity of developing a radically new style of writing mathematical texts, very unlike anything ever written before: this novelty is required by the novelty of the subject matter. Traditionally, mathematical texts are written on a fairly uniform semantic level, and that style cannot suffice for the disentanglement of the many intricate intertwinings we have to deal with.

In the relation between mathematics and computing science, the latter has, up till now, mostly been at the receiving end, and it seems to me that the time has come to start repaying our debts. Besides broadening the scope of applicability of mathematical techniques (as indicated above) we could also change their traditional applications. When, at last, the predicate calculus were to become an indispensable tool in the daily reasoning of all sorts of mathematicians, when the replacement of the asymmetric implication by the symmetric disjunction were to rob the so called "reductio ad absurdum" from its special status and equivalence would no longer be expressed by the clumsy "if and only if", when mathematics would become enriched by a greater variety of inductive arguments, in all those cases such a development could possibly be traced down to computing science's wholesome influence.

But repaying our debt to mathematics at large is certainly not our only task: also computing proper needs our attention. We know that the problem of programming and system design are such that they cannot be solved without an effective application of the techniques of scientific thought. But how well are we able to apply them?

How well are we, for instance, able to separate the concern for correctness from the concern for efficiency? Both concerns are so "major", that I don't believe that significant progress will be possible unless we manage to separate them completely.

Efficiency has to do with cost aspects of program execution, correctness has to do with a relation between input and output, between initial and final states. Complete separation of these two concerns means that we can deal with the correctness issue without taking into account that our programs could be executed. It means that we can deal with the correctness issue, temporarily ignoring that our program text also admits the interpretation of executable code, i.e., we must be able to discuss correctness independently of an underlying computational model. To learn to dissociate our reasoning from underlying computational models, and to get rid of our operational thinking habits, that is what I regard as computing science's major task. That is what I would like to see achieved more than anything else.

Its difficulty should not be underestimated: it is like asking the average mathematician suddenly to do Euclidean geometry without drawing pictures. As Morris Kline remarks:

"But the pictures are not the subject matter of geometry and we are not permitted to reason from them. it is true that most people, including mathematicians, lean upon these pictures as a crutch and find themselves unable to walk when the crutch is removed. For a tour of higher dimensional geometry, however, the crutch is not available."

The analogy is almost perfect: the pictures are to geometry what computational histories (or "traces") are to computing science, "and we are not permitted to reason from them". But the operational thinking habits are firmly rooted in many wide-spread traditions, ranging from automata theory, via LISP, to FORTAN and BASIC, and many people, including computing scientists, lean upon traces "as a crutch, and find themselves unable to walk when the crutch is removed". In the case of uniprogramming the trace is a linear sequence of states and events, about as manageable and "helpful" as a picture in two- or three-dimensional geometry. But in the case of multiprogramming traces are unmanageable and the "crutch is not available".

For Euclidean geometry the analytical methods of Descartes provided the alternative to the crutch, and in analytical geometry the generalization from three to more dimensions was technically very smooth. In programming, the postulational methods of Floyd and Hoare provided the alternative to the crutch; in uniprogramming they did so very successfully, but their generalization from uni- to multiprogramming is —at the time of writing and to my knowledge— less smooth, although after the successful start of Gries and Owicki I haven't the slightest doubt that in the long run it will be done quite successfully. The need to delineate very carefully one's "point actions" is a new aspect of the game; so is the discovery of Laws that give the implementer a greater freedom in embedding in space and time the activities involved in the implementation of single point actions. (One of the ways in which we can appreciate the manifestly greater difficulty of designing multiprograms is that the implementer is interested in much greater freedom: under which circumstances, for instance, is he allowed to implement in a distributed system a point action —in the presence of other traffic!— by an activity in node A, followed by a "slow" message from A to B, and finally, upon reception of the message, some activity in B?)

Dealing successfully with these technicalities will, I am very much afraid, be a minor task, compared to the educational challenge of getting nonoperational arguments accepted and getting people thereby out of the their operational thinking habits, for over and over again they prove to be a mental stumbling block for accepting a nonoperational argument, particularly when, from an operational point of view, it does not make sense. It is distressingly hard to make someone accept a universal invariant while he all the time remains obsessed by his knowledge that in his implementation it will never be true, because his implementation will never show a moment in which it won't be halfway engaged on one or more point actions somewhere in the network. The fight against operational thinking habits is a major educational task (of which the crusade against anthropomorphic terminology is only a modest beginning.)

*                *
*

I hope very much that computing science at large will become more mature, as I am annoyed by two phenomena that both strike me as symptoms of immaturity.

The one is the wide-spread sensitivity to fads and fashions, and the wholesale adoption of buzzwords and even buzznotions. Write a paper promising salvation, make it a "structured" something or a "virtual" something, or "abstract", "distributed" or "higher-order" or "applicative" and you can almost be certain of having started a new cult.

The other one is the sensitivity to the market place, the unchallenged assumption that industrial products, just because they are there, become by their mere existence a topic worthy of scientific attention, no matter how grave the mistakes they embody. In the sixties the battle that was needed to prevent computing science from degenerating to "how to live with the 360" has been won, and "courses" —usually "in depth!"— about MVS or what have you are now confined to the not so respectable subculture of the commercial training circuit. But now we hear that the advent of the microprocessors is going to revolutionize computing science! I don't believe that, unless the chasing of day-flies is confused with doing research. A similar battle may be needed.

An unmistakable symptom of maturity of computing science would be a consensus about "what matters" among its leaders, a consensus that would enable us to discuss its future course as if computing science were an end in itself. Obviously, such a consensus can only emerge as the byproduct of a coherent body of knowledge and insights, but the crucial point is "knowledge of what?" and "insights in what?". What would be worth knowing? What would be worth understanding?

I believe that a bold extrapolation from the past will help us to find the answers. When programming methodology in the early seventies adopted formal techniques for verification and for the derivation of correct programs, earlier ways in which programming language features had been discussed were suddenly obsolete. The earlier pragmatic discussions, blurred by different tastes and habits, had only created a confusion worthy of Babel, but then the simple question "does this proposed feature simplify or complicate a formal treatment?" cut as a knife through the proposals and did more to establish consensus than eloquence or bribery could ever have achieved. My extrapolation from that experience is that our knowledge should concern formal techniques, and our understanding should be of the limits and of the potential of their application.

Let me comment in this connection shortly on two developments currently in bloom, developments that certainly fall under the heading "formal techniques": the knowledge is being developed, but about the understanding of limits and potential I have in both cases my misgivings. I mean abstract data types and program transformation, both under development in an effort to separate correctness concerns from efficiency concerns.

For the blooming of abstract data types I feel some co-responsibility, having coined and launched the terms "representational abstraction" back in 1972, and if it turns out to be a mistake, part of the guilt could be mine. One hint that it might be a mistake comes from the fact that it is only a slight exaggeration to state that, after five years of intensive research and development, the stack is still the only abstract data type ever designed. This is in strong contrast to what happened when its inspirator, the closed subroutine, was invented! For this disappointing outcome, so far, of the research devoted to abstract data types I can, at my current stage of understanding, offer two tentative explanations. The one is simply that an abstract data type is so much more complicated, so much harder to specify, than a subroutine, that it is orders of magnitude harder to invent a useful one. (If that is the case, I have only been impatient.) The other one is that, when all is said and told, the type of interface, as provided by an abstract data type, is inappropriate for its purpose: when we analyze carefully really sophisticated algorithms, we could very well discover that the correctness proof does not admit a parcelling out, such that one or two parcels can comfortably be identified with an abstract data type. In other words, the hope that abstract data types will help us much could very well be based on an underestimation of the logical complexity of sophisticated algorithms and, consequently, on an oversimplification of the program design process.

Program transformations —each of which embodies a theorem!— have been suggested as a candidate that could contribute to the necessary body of knowledge. The hope is that transformations from a modest library will provide a path from a naïve, inefficient but obviously correct program to a sophisticated efficient solution. I have seen how via program transformations striking gains in efficiency have been obtained by avoiding recomputations of the same intermediate results, even in situations in which this possibility —note that the intermediate results are never part of the original problem statement!— was, at first sight, surprising. And yet my hope is tempered for the following reason: when, in contrast to the correctness of the naïve algorithm one starts with, the correctness of the efficient one critically depends on a (perhaps deep) mathematical theorem, the chain of transformations would constitute a proof of the latter, and, to the best of my knowledge, mechanical proof verification is very cumbersome and is expected to remain so. I am afraid that great hopes of program transformations can only be based on what seems to me an underestimation of the logical brinkmanship that is required for the justification of really efficient algorithms. It is certainly true, that each program transformation embodies a theorem, but are these the theorems that could contribute significantly to the body of knowledge and understanding that would give us maturity? I doubt, for many of them are too trivial and too much tied to program notation.

And this brings me to my final hope: before I die, I hope to understand by which virtues the one formal notational technique serves its purpose well and due to which shortcomings the other one is just a pain in the neck.

On my many wanderings over the earth's surface I learned that quite a few people tend to help me starting an animated conversation by the well-intended question: "And, professor Dijkstra, what are you currently researching?". I have learned to dread that question, because it used to leave me speechless, or stammering at best. Came the moment that I decided that I had better design a ready-made answer for it, and for a while I used the answer, both true and short: "Programming.". the usual answer I got was very illuminating "Ah, I see: programming languages.", and when I then said "No: programming.", my good-willing partner seldomly noticed that he was being corrected.

The ACM has a Special Interest Group on Programming Languages, but not one on programming as such; its newest periodical is on Programming Languages and Systems and not on programming as such. The computing community has an almost morbid fixation on program notation, it is subdivided in as many subcultures as we have more or less accepted programming languages, subcultures, none of which clearly distinguishes between genuine problems and problems only generated by the programming languages it has adopted (sometimes almost as a faith). For this morbid fixation I can only offer one explanation: we fully realize that in our work, more than perhaps anywhere else, appropriate notational conventions are crucial, but also, we suffer more than anyone else from the general misunderstanding of their proper role.

The problem is, of course, quite general: each experienced mathematician knows that achievements depend critically on the availability of suitable notations. Naïvely one would therefore expect that the design of suitable notations would be a central topic of mathematical methodology. Amazingly enough, the traditional mathematical world hardly addresses the topic. The clumsy notational conventions adhered to in many mathematical publications leave room for only one conclusion: mathematicians are not even taught how to select a suitable notation from the established ones, let alone that they are taught how to design a new one when needed.

This amazing silence of the mathematicians on what is at the heart of their trade suggests that it is a very tough job to say something sensible about it. (Otherwise they would have done it.) And I can explain it only by the fact that the traditional mathematician has always the escape of natural language with which he can glue his formulae together.

Here, the computing scientist is in a unique position, for a program text is, by definition, for one hundred percent a formal text. As a result we just cannot afford not to understand why a notational convention is appropriate or not. Such is our predicament.

Nuenen, April 1979.

Transcribed by Guy Haworth

Last modified Tue, 6 Jul 2010.

EWD710

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

When messages may crawl, II (A sequel to EWD708).

In EWD708 I wrote “the messages are essentially empty envelopes; allowing the envelopes to contain something was felt to be a minor complication that we could postpone for the time being”. The purpose of this note is to investigate how minor or major this complication turns out to be.

We modify the program by distinguishing the different messages from C to D by a subscript i and the ones in the opposite direction by a subscript j :

|  | (1)

| {P} do B1Ci,→ S1i; S1Di {P}
|  |  | ▯ B2Dj → S2Dj; S2Cj {P}
|  | od

and its correctness proof now comprises the (many) theorems

| P and B1Ci ⇒ wp(“S1Ci; S1Di”, P) | (2i)
| P and B2Dj ⇒ wp(“S2Dj; S2Cj”, P) . | (3j)

In this note we regard the way in which the difference between different messages from C to D has been indicated by the implementation as irrelevant: the contents of the messages may differ, they may be sent along different channels that can be distinguished, or any mixture thereof. It is an implementation detail, from which we are allowed to abstract.

In analogy to EWD708, the following program is regarded to be representative for the corresponding mail system:

| {P} (A j: cj:= 0); (A i: di:= 0); {M}
| do B1Ci → S1Ci ; di:= di + 1 {M}
|  | ▯ di > 0 → di:= di - 1; S1Di {M}
|  | ▯ B2Dj → S2Dj; cj:= cj + 1 {M}
|  | ▯ cj > 0 → cj:= cj - 1; S2Cj {M}
| od

with the corresponding proof obligations

| (E j: cj ≠ 0) or (E i: di ≠ 0) or P = M | (4)
| M and B1Ci ⇒wp(“S1Ci; di:= di +1”, M) | (5i)
| M and di > 0 ⇒ wp(“di:= di - 1; S1Di”, M) | (6i)
| M and B2Dj ⇒ wp(“S2Dj; cj:= cj + 1”, M) | (7j)
| M and cj > 0 ⇒ wp(“cj:= cj - 1; S2Cj”, M) | (8j)

With the same notational convention —(9) and (10)— from EWD708, we can satisfy (4), (6i), and (8j) by choosing for M

M: | wp(“(A i: S1Di ↑ di); (A j: S2Cj ↑ cj)”, P) | (11)

provided that (11) makes sense. In analogy to EWD708 this implies (A j: cj ≥ 0) and (A i: di ≥ 0) , but this invariance is duly maintained by the above representation of the mail system. But for (11) to make sense, we must require that (A i: S1Di ↑ di) and (A j: S2Cj ↑ ci) are defined, i.e. we must require

| (A i1,i2: "SlDi1 ↑ di1; SlDi2 ↑ di2" = "S1Di2 ↑ di2; S1Di1 ↑ di1") | (16)
and | (A jl,j2: "S2Cj1 ↑ cj1; S2Cj2 ↑ cj2" = "S2Cj2 ↑ cj2; S2Cj1 ↑ cj1") | (17)

(This curious way of numbering results from my desire to give similar formulae in this note and in EWD708 the same number.)

Salvo errore et omissione I have come to the conclusion that properties (12) and (13) are stronger than necessary, and so are their consequences (14) and (15), as mentioned in EWD708. In order to prove (5i) from (2i) the weaker assumptions

| (A j: B1Ci ⇒ wp("S2Ci ↑ ci", BlCi)) ( | 14)
and | (A j: BlCi and wp("S2Cj ↑ cj; S1Ci", R) ⇒ wp("S1Ci; S2Cj ↑ cj", R)) | (15)

suffice. (The absence of the beginning term “E1C” in (13) and (15) of EWD708 is, in retrospect, just an omission.)

One way of proving (14) and (15) is to show —as suggested in EWD708— for each (i,j)-pair

| B1Ci ⇒ wp(“S2Cj”, B1Ci) | (12)

| B1Ci and wp(“S2Cj; S1Ci’, R) ⇒wp(”S1Ci; S2Cj“, R) . | (13)

Properties (12) and (13) have the attraction that they are local properties of node C of the telex system. Note that relations (14) and (15) are also a consequence of

| B1Cj ⇒ (cj = 0) . | (18)

Similarly, in the spirit of EWD708, we would try to prove for any (j1,j2)-pair

| ”S2Cj1; S2Cj2“ = ”S2Cj2; S2Cj1“ | (19)

from which (17) follows. Again we should note the existence of the alternative: cj1 = 0 or cj2 = 0 .

Summarizing our proof obligation with respect to node C , we have to show:

| (A i, j; BlCi ⇒ wp("S2Cj, BlCi) or cj = 0) | (20)
| (A i, j: BlCi and wp("S2Cj; S1Ci", R) ⇒ wp("SlCi; S2Cj", R) or cj = 0) | (21)
| (A jl,j2: "S2Cj1; S2Cj2" = "S2Cj2; S2Cj1" or cj1 = 0 or cj2 = 0) | (22)

With respect to node D we have, mutatis mutandis, the same obligations.

The weakening of our proof obligations, as represented by (20), (21), and (22) leaves me with mixed feeling. Each time we have to make essential use of the weakening, we have to prove that under certain circumstances “exponents” are zero, and those are global properties that are not directly reflected —at least for the time being I don’t see how— in the original telex system. I console myself with the thought that, if a mail system is our eventual target, they are not very desirable properties: in order to make a mail system it is customary to make message receptions commute if possible. One advantage of conditions (20), (21), and (22) is certainly that they give the designer of a mail system a clear summary of his options.

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
5671 AL NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-02-18 .

EWD 711

Trip report E.W.Dijkstra, Ithaca, Albany, Austin (Texas), 26/5 - 10/6 1979.

I left home on Saturday 26th May 1979 at 19.15 and arrived at J.F.Kennedy Airport twelve hours later. Flight KL641 had not been very smooth, and the usual discomfort of flying had been enhanced by a large number of Italian tourists in the "reduced fare section": Italian is another one of those languages that has to be spoken very loudly. To catch my connection to Ithaca I had to go from J.F.Kennedy to La Guardia Airport; the helicopter service connecting the two airports no longer existing, I went by limousine ($3.00 and 40 minutes). At 21.00 (local time) I arrived at Ithaca where David Gries and his twins were waiting for me at the gate. The Grieses go to bed early and are early risers (5.30 is not unusual for David), and this makes them really ideal hosts for the traveller from Europe that arrives with his body still full of six hours of time shift (the absorption of which was a main purpose of that visit). Two hard-boiled eggs, three glasses of milk, some whisky and then: off to bed!

On Sunday morning Bob Constable and Jim Donahue came with their families and we walked after a short drive to the local waterfall, distinguished by some superlative —"the highest East of the Mississippi" I think— . The rest of the afternoon the whole lot of us enjoyed the meal that Elaine Gries had prepared in our absence. (I still felt a bit groggy and my thoughts —if any— sometimes wandered away.) The next two days I went with David to Cornell University. On Monday afternoon I gave a lecture for a sizeable audience (in spite of the fact that it was Memorial Day), Tuesday was mostly spent on private interests. (David was extremely helpful: my private interests were suddenly increased by one when we discovered that the Dutch travel agent had booked me on a non-existent flight from Austin to New York!)

Early in the evening I flew with two other passengers in a one-pilot plane from Ithaca to Albany. When I arrived in the Americana Inn I was still rather shaky, for we had met a great thunderstorm on our way. The pilot was proud of the way in which he had managed to avoid it (and I am willing to believe in the justification of his pride); I wonder how bad the "ups" and "downs" would have been otherwise.

The next two-and-a-half days I attended the "Software Engineering Workshop" that had been my primary reason for this visit to the USA. "The workshop is sponsored by the Rensselaer Polytechnic Institute, the General Electric Research and Development Center, and the National Science Foundation. The objective of the workshop is to focus on R+D in software engineering as a national need." It had been organized by Dr.Philip Lewis (GE) and Prof.Herbert Freeman (RPI).

The DC-10's being grounded, Barry Boehm (TRW) was unable to present his talk in person. He sent his visual by special delivery and gave his presentation via a telephone link. The technical organization involved in this last-minute arrangement was impressive; the result was hardly worth the trouble.

As a panopticum displaying current programming practice and management superficiality it may have been highly successful, but as a workshop on Research and Development in software engineering it was a depressing disaster. To indicate the level: Earl Van Horn (DEC) used most of his half hour as a speaker to argue that "software evolution" would be a more appropriate term than "software maintenance" and Jean Sammet (IBM) thought this remark really an eye-opener! (In passing we note that at least two participants did not know their literature, cf. Comm.ACM, 21, 10 (Oct.1979) p.882.) Also illuminating were recommended activities such as "Measurement of Productivity, Reliability, Quality" or "Development of Integrated Software Development Support Systems".

In my innocence I thought that by now it was common knowledge and a reason for common concern that in so many software activities the separation between research and development is not made with sufficient clarity, with the result that many projects are undertaken as development projects, the required research component being grossly underestimated. But things seem to have gotten worse! Many seemed not to have the slightest idea what research in connection with software would look like, and the vital distinction seemed more blurred than ever. (In this connection I thought it telling that Research and Development has become such a unity that in its abbreviation "R+D" the spaces were usually omitted: "R + D" was exceptional).

Elsewhere (EWD690) I have compared the pragmatic engineer —who believes in his design as long as it works— with the scientific designer —who believes in his design because he understands why it must work— because, in general, we seem to have too much of the first and too little of the second. I would therefore welcome a shift in the division of labour between the two types. But such a shift fell way beyond the mental horizon of this community which, as a result, in expressing its needs could only ask for more and more of the same. (In the weekend thereafter I saw the June 4 issue of Newsweek "Innovation: has America lost its edge?" What I had seen seemed a striking confirmation.)

At Cornell David had shown me a curious document in which questionnaire answers had been summarized showing how U.S. Departments of Computing Science rated each other. The three with the highest general ranking were Stanford, MIT and CMU. They were also specifically the ones with the highest ranking for AI and I could not escape the impression that the glitter of AI —at least: of its hopes and claims!— had been confused more than once with scientific achievements in computing. I would have forgotten this document had it not been for Carl E.Hewitt (MIT) who, in a discussion, referred without hesitation to "the best institutes, MIT and Stanford" to which he added "and CMU" —after a very small hesitation, but the "and" between MIT and Stanford had already given him away!— , whereas at the same time he had already made it abundantly clear that computing science at MIT is still in a poor shape. (His proudest announcement boiled down to how successfully they had mimicked Xerox PARC!)

Prof.D.Tsichritzes (Toronto) gave a short, sensible talk. The gist of his message was that concurrently active microprocessors, all by themselves, will tend to make life more complicated, and that, therefore, we should try to exploit them for simplification wherever possible, e.g. by reducing the complexities of sharing. He spoke after me, and did better than I had done: hesitating between presenting the survey I had prepared and quickly designing a talk for this audience, I had chosen for the first option. Prof.F.L.Bauer, who spoke on the last day (and had tactfully left his title undefined) chose the second option: he gave a very clear, very elementary introduction to formal techniques, full of reassurance that they were no more than "a shorthand notation for common sense". It was well-adapted to his audience and well received. At 13.30 that Friday I was in the air on my way to Austin, Texas, where I arrived at 20.05 that evening.

I was picked up at the gate by Walter E.Feeser, the manager of the Burroughs Engineering Technology Center that I would visit the next week, and taken to the Austin Hilton that still proudly announced that "There is no place like Hilton". Thank goodness! In one's room no desk at which one can write, only a wobbly one-legged table floating on a thick floor carpet. (At least I invented a new article for the American travel market: the portable, cordless carpet mower.)

During the weekend Dr.Hamilton Richards of Burroughs and his wife extended their hospitality to me. They had excellent desks in their new home, and when I did not work I could satisfy my curiosity by observing the progress of such interesting activities as further insulation of a newly installed solar water heater. For the next week I would have dinner each evening with one or two different staff members of the Technology Center, with the exception of Wednesday evening, when I had dinner at the home of professors Dale, both of Texas University. (Portions at Texan restaurants are such that it is no problem to maintain one's weight by skipping lunch. I advise, in fact, the untrained visitor to do so.)

On Tuesday, at noon, I was collected by someone from the University of Texas at Austin, had lunch with a few more, and in the last afternoon gave a lecture at the Department of Computing Science. It was the same lecture I had given a week earlier at Cornell University and this time it went very smooth despite the lack of adequate blackboard space, a lack for which I was unprepared. Overhead projectors are suitable for giving presentations —sales or otherwise— , but for the delivery of a good lecture a sizeable blackboard is indispensable, and from its absence in a university lecture room I can draw but one conclusion about that university, and that is a sad one. (Monday afternoon and Tuesday morning at Burroughs we had been addressed by Christian Hoffmann. Though the facilities in the conference room were almost adequate, he preferred to show his visuals; but he was from Purdue...) Professor Dale tried to understand the development of computing science in terms of the (older) development of .... economy, and his colleague, professor Simmons —by training a psychologist!— considered "applied mathematics" as a contradictio in terminis. But all this I only discovered the day after my talk, of which it became in retrospect almost surprising that it had been received so well. (Is the fact that my audience was by no means restricted to people from T.U. perhaps an explanation?)

The rest of the week I spent at the Burroughs Engineering Technology Center. My hosts were considerate and inspiring and my visit was satisfying, except that at the end I realized that a week was too short. On the other hand, I had been on the road for two weeks and going home was a welcome change. David Gries had discovered that for the trip home the Dutch travel agent had booked me on a nonexistent flight from Austin to New York, and I had been booked on the next existing one, about one hour later. The Braniff plane from Austin was an additional 50 minutes late; after an agonizing wait for my luggage to appear at La Guardia, I jumped into a taxi to J.F.Kennedy ($12.— and 25 minutes) and I caught my connection. At Sunday noon my wife, who had come with the car to Schiphol, and I were on our way to Nuenen.

Thanks to the good care of my hosts in Austin, my American vocabulary has been extended vigorously, with words such as "humdinger" and "red-neck"; I was reminded of the latter one on my way back when I crossed the Atlantic with in the seat next to me a (too) rich 63-year-old, talkative person who, I think, is properly described as "a reactionary gentleman". He complained bitterly about the decay of the New York Plaza Hotel that was no longer what it used to be, and declared me to be his greatest friend as soon as he had discovered that I was a Dutchman because at least in South Africa they still knew how to deal with those niggers. The exposure was tiring —I would have preferred some sleep— but very instructive.

18 June 1979
Plataanstraat 5
5671 AL NUENEN
The Netherlands

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 16-Oct-2011

   EWD 712

Trip Report E.W.Dijkstra, Antwerp, 24 - 29 June 1979

"There is no place like Hilton!" but a "Quality Inn Hotel" is a close approximation: breakfast and lunch with the same Muzak as in the toilets, dinner with the Muzak from the bar in addition. In a couple of days such a cacophony becomes sheer torture. The food, however, was on the whole much better —at least when we compare a Belgian Quality Inn with an American Hilton—.

The purpose of the visit was a five-day seminar on programming that I conducted for Burroughs employees. The audience that I met was not quite what I had expected, as a few of the European plants had been unable to send participants; there were four participants from the USA and six from Europe. Instead of those six I had expected something like sixteen, and those missing ten were a bit of a disappointment for me. Twenty people would have made it more worthwhile, it would also have been easier for me: when trying to conduct a dialogue and to let the audience cooperate in the development of a solution, you tend to get more suggestions from the larger audience. (I have explained to them that as a result of the small size of the group they all had to carry a double burden.) It was quite a pleasant group to work with, they found it difficult, but were intrigued and worked very hard. It was my impression that on the average the European participants found it a little bit easier than the American ones to catch the spirit of the whole thing —when correct, not a surprising observation—. As in Valley Forge, we met from 9 till 12 and from 14 to 17 and disbanded at Friday noon. And "hotelwork" in the evenings. On Friday morning —the farewell session"— I have shown a termination detection for diffusing computations; the preceding four days we had dealt with the development of sequential programs, it seemed illuminating to show the same techniques can be applied in the case of distributed computing.

When I left Eindhoven on Sunday afternoon, the young couple ahead of me in the queue in front of the international ticket counter clearly had a very difficult request; after waiting for my turn for almost fifteen minutes I gave up because I had to catch my train. When I tried to buy my ticket from the conductor, he told me that he could only sell me a ticket until the border. In Roosendaal I announced to the Belgian conductor that I wanted to buy a ticket from Roosendaal to Antwerp; he said "OK", but never showed up, so the last stretch I travelled free. (I travelled in the company of four Belgians who had been in the Netherlands for a few days and amused each other by telling "Belgian jokes". Most of them I couldn't understand, but I learned the announcement over the P.A. system at the Roosendaal railway station: "The train to Belgium departs when the hands on the clock coincide.") On Friday afternoon, when I returned, I again failed to buy my ticket at the station, but this time because the taxi that had been ordered to pick me up from the hotel was ten minutes late.

The brochure for the Antwerp Quality Inn announced its audio-visual facilities for meetings, but the facilities were absolutely miserable. They had promised a blackboard, but the one they provided was ridiculous —the size of an opened atlas, at best!—. The sad result was that I had to struggle the whole week with an overhead projector. The usual inconveniences of that "visual aid" are bad enough —the speaker is blinded and cooked—; this time I had the added inconvenience of a cord that was not long enough and a roll of foil that did not fit. Bah! The experience confirmed all my prejudices: the world would be served immensely by the defenestration of all overhead projectors.

Just before I left home I had heard over the radio that in large sections of Flanders a bacterial contamination of the drinking water had been discovered. (It had been discovered on Friday evening, but only on Sunday the population was warned to boil the water from the tap before drinking!) Had this something to do with the glass of rotten milk the Quality Inn served me on the second or third evening? Later in the week I began to taste chlorine while brushing my teeth.

Plataanstraat 5
5671 AL NUENEN
The Netherlands

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Tue, 8 Mar 2005

EWD713

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On a problem posed by W.H.J.Feijen.

Given, for M ≥ 0 and N ≥ 0 , the strictly increasing sequences

| F(0) < F(1) < ... < F(M-1)
| G(0) < G(1) < ... < G(N-1)

and the desired final state

R: | Q(M, N)

where the predicate Q has been given by

Q(m, n): | (E (i, j): 0 ≤ i <m, 0 ≤ j < n: F(i) = G(j)) = k

(the “N” to be read as: “the number of distinct pairs (i, j) with i and j in the ranges so and so, such that such and such”.) W.H.J.Feijen posed the problem of giving a formal derivation, heuristics included, of an efficient program establishing R .

The standard way of solving this problem would be “Replacing constants by variables”, i.e. would be to introduce two local variables —which we shall again denote by my and n — , their role being given by the invariant

P: | Q(m, n) and 0 ≤ m ≤ M and 0 ≤ n ≤ N .

easily initialized by

| “m, n, k := 0, 0, 0”

and enjoying the obvious property

| (P and m = M and n = N) ⇒ R . | (1)

(It could be remarked that also initializations such as “m, n, k := 0, N, 0” or m, n, k := M, 0, 0“ would have done the job, but symmetry should never be destroyed lightly.)

Appealing to (1) implies a final state with (m, n) = (M, N) ; the crucial observation is that the transition to it from the initial state (m, n) = (0, 0) can be made via so many different paths (increasing m or/ and n by 1 at a time) that we should raise the question whether we can exploit this freedom by strengthening P into P’ and by weakening the condition for termination. (The weaker the condition for termination, the stronger the guards and the sooner we may expect the repetition to stop.) We can weaken the condition for termination by not requiring that both the local variables m and n have reached their maximum value, i.e. we find ourselves looking for a P’ , stronger than P , and such that

| (P’ and (m = M or and n = N)) ⇒R | (2)

Investigating the case m = M , we find ourselves facing the question: what more should be known besides P such that we may conclude R ? In view of the monotonicity of the sequences F and G it would suffice to know that F(m-1) < G(n) because

| (Q(M, n) and F(M-1) < G(n)) ⇒ R .

Because we are only interested in the inequality F(M-1) < G(n) —itself to strong to be included in the invariant— the inclusion of F(m-1) < G(n) would suffice. Hence we find ourselves considering the invariant (symmetry!)

P’: | P and F(m-1) < G(n) and G(n-1) < F(m) ,

an invariant that admits the same initialization if we define formally F(-1) = G(-1) : minus infinity .

The standard routine of computing wp(“m:= m + 1”, P’), wp(“n:= n + 1, P”), and wp(“m, n, k := m + 1, n + 1, k + 1”, P“) and simplifying by omitting implied terms from the conjunctions gives the guards; the following program results:

| m, n, k := 0, 0, 0; {P'}
| do m ≠ M and n ≠ N →
|  |  | if F(m) < G(n) → m:= m + 1 {P'}
|  |  |  | ▯ G(n) < F(m) → n:= n + 1 {P'}
|  |  |  | ▯ F(m) = G(n) → m, n, k := m + 1, n + 1, k + 1 {P'}
|  | fi {P'}
| od

Plataanstraat 5 | prof.dr.Edsger W.Dijkstra
5671 AL NUENEN | Burroughs Research Fellow
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 2015-02-19 .

EWD 714

Trip report E.W.Dijkstra, Mission Viejo, Santa Cruz, Austin, 29 July - 8 September 1979.

On the first half of this trip I was joined by my wife Ria, my daughter Femke, and my son Rutger; for the latter two it was their first visit to the U.S.A., for Ria it was the second visit to the USA, but the first one to California.

On Sunday morning 9.00 the four of us were ready for departure, but the taxi that should take us to the Eindhoven railway station did not show up. After some telephoning we learned that the taxi had gone out to collect —and wake up!— the wrong Dijkstra. The timing of our schedule had been sufficiently pessimistic, and we caught the train we had planned to catch. When we arrived at Schiphol Airport we learned that there had been no reason for hurry or anxiety at all, as the KLM-flight to Chicago would be delayed by at least two hours (awaiting technical clearance). Eventually it became three hours; our schedule could not absorb that, and we missed our connection in Chicago. My main problem was that I did not know how to reach John McClintock, who had promised to collect us at Los Angeles International Airport. I asked KLM to send a message to the gate of United Airlines, where John expected us to arrive. When we did not show up, that message reached him after some ingenuity on his part, and after having waited another three hours at LAX he could finally collect us and drive us to our motel in Laguna Beach. His assistance was greatly appreciated, because I don't think that at that moment I would still have been able to learn how to drive an American car. All its niceties —power brake, power steering, electric windows, and (worst of all!) an automatic gear shift— were explained to me the next morning after a long and untroubled sleep. That Monday was essentially devoted to recovery. On Tuesday the four of us went to Disneyland (not after all sorts of people had assured me that even I would like it): I liked some of the recommended items and admired the technique of controlling large crowds, but it is beyond me how anyone would ever like to go there a second time. On Wednesday my work at Burroughs started.

Because I had not been to that plant for a long time, they had a lot to show to me; these discussions took place in the morning. In the afternoons I addressed three different groups, largely composed of people that had been attracted since my previous visit. One evening we attended a reception given in our honour, the next evening we had a (delightful!) dinner at Erv Hauck's home. It was nice to see how the children could carry on a conversation in English and seemed to feel themselves quite happy.

On Saturday morning the four of us left Laguna Beach in the rented Oldsmobile Royale for our trip up North, a trip that became very nice as soon as we had passed Los Angeles. Only Femke did not enjoy it too much: she was sitting at the sunny side of the car most of the day and fell asleep. We did not hurry and drove that day up to San Luis Obispo, where Burroughs had made a reservation in an excellent motel. We arrived there late in the afternoon; Femke and I each wrote a letter before we went to (a terrible) dinner. On Sunday we went, mostly along the coast, to Santa Cruz: a lovely ride! Apparently most Americans were in a hurry that day, for the road was not crowded at all. As a simple courtesy to the organizers, a main speaker should never arrive late; hence we arrived in the course of the afternoon on the campus of the University of California at Santa Cruz, a campus where I would live —or, at least, try to do so— for the next four weeks. (Week zero: a programming course, weeks one and two: The Summer Spectacular, and week three: a meeting of the IFIP Working Group 2.3 on "Programming Methodology".)

I found the UCSC campus not an inspiring place, and the longer I stayed there, the more depressing it became. The place seemed most successful in hiding all the usual symptoms of a seat of learning. In the four-person apartment we occupied, only one of the four desks had a reading lamp, and the chairs in front of the desks were so low that writing at the desks was not comfortable. Probably it doesn't matter. Can UCSC students write? Do they need to? The notice boards showed ads from typing services "Grammar and spelling corrected.". (One of these ads itself contained a spelling error!) Blackboards were hardly sufficient; there used to be neither bucket not sponge; the acoustics were from bad to terrible; the PA systems in the large lecture hall and in the theatre were inadequate; I did not find a US post office on the —very isolated— campus; all campus maps were incomplete, in mutual disagreement and in disagreement with the campus itself; in the one and only public place where we could meet in the evening —"Idler's Cafe"— conversation was impossible as the result of the summum of vulgarity: a row of noisy pin-ball machines! And —as I am told: even by dormitory standards— the food was terrible. We had to share the food —and what was worse: also the space in which to consume it— with the participants in other "educational" activities —such as a cheer-leaders school and a school of American football— . There were musical instruments on the campus and there seemed to be even a B�sendorfer, kept behind a well-locked door; initially I was annoyed by the fact that access to it was denied to us, but the accessible Yamaha's were in such a terrible shape that within half a month I had developed a certain sympathy for the guy that protected the B�sendorfer against the prevailing misuse.... In short: the place breathed an atmosphere of uncivilization.

Upon arrival we were greeted by Wim Feijen, who had been invited to assist me during the next week, by Netty van Gasteren, who was officially just a student, but gave valuable assistance, by Gary Levin and Fred Schneider from Cornell University, who were to assist David Gries. Originally only David would give a five-day programming course during week zero, but David's course had been so heavily overbooked that Bill McKeeman had asked me whether I could run a parallel session. And so we did. Each evening the five or six of us would meet, collect and compare experiences and make a plan for the next day —a plan from which, invariably, both David and I would depart— . But we kept our classes well enough in phase so that, on the last days, we could combine the troops a number of times in the larger lecture hall.

The audience was of a higher calibre than we had been led to expect on account of David's experience about five years ago, when he gave a similar course. At that time he had a sizeable fraction that knew nothing beyond COBOL. This time it was much better: for each Ph.D., we had two Masters and three Bachelors. We had eight people from various Bell Laboratories, about twelve people with academic affiliations. The reasons for the rise in quality were not clear: its announcement may have been different, the fact that it was presented as a technical introduction to The Summer Spectacular may have attracted a different audience, or the challenge of the programming task may, in general, be taken more seriously. The audience as a whole was, however, still far below the level of what Marktoberdorf has been able to attract: my impression was that 30 to 40 per cent. could only be described as mathematical illiterates, who had never done any formal manipulations in their whole lives. After two days we had to admit that, say, one out of every three was totally unsalvageable, and from then onwards we concentrated on teaching the others. When the week was over, we all decided that it had been very hard work, but that it had been worth the trouble. The audience seemed to be uniformly grateful. The weekend was used for recovery.

Then came the two weeks of The Summer Spectacular, i.e. the International Lecture Series on Programming Methodology, largely to be presented by members of IFIP WG2.3 who, by doing so, could earn their travel expenses. On ten days and nine evenings we gave together 49 performances: the four during the daytime in the large lecture hall, the evening lectures in the still larger performing arts theatre. The 27 lecturers had prepared their talks without any mutual consultation, the result was a kaleidoscopic overview. The set of lectures was as mixed as the audience and the one seemed to suit the other. I thought that more than a third was quite good, and that is not a bad score. I gave one evening lecture and three during the daytime. In the evening lectures we had to address the largest crowds (close to 300, I guess, compared to almost 250 during the day) with the poorer facilities for lecturing: the place was more suitable for "performing arts", and, forced by the circumstances, most of us did just that. (And some of us gave remarkably good shows!)

I missed the first two days of the Summer Spectacular as I went with Ria, Femke and Rutger to Yosemite National Park. We stayed the night in the Silver Top Motel in Fish Camp, a few miles from the Southern entry. In Fish Camp we had an excellent dinner. On the day of our arrival we went to the big Sequoias in Mariposa Grove, and I found them very impressive. My village boasts a tree that is about 380 years old, and whenever I pass it I think it a quite respectable, dear old tree. To face a tree that is undoubtedly alive and of an estimated age of 3800 years is quite a different experience! It is just another example of how big a factor ten is..... On the next three days I listened to Hehner, Backus, Sintzoff, Burstall, Hoare, and Dahl. On Friday morning Ria returned with the children to the Netherlands, Wim Feijen had already left on Thursday.

On Saturday we did almost nothing, on Sunday we took what I can only describe as a misguided tour to Monterey and Carmel. An hour at the Municipal Wharf and one-and-a-half hour on Cannery Row is —in spite of the joined efforts of John Steinbeck and the American tourist industry— just too much, in particular if it implies that later on the Carmel Mission and the 17 Mile Drive with the birds, seals, sea-lions and sea-otters have to be done in a hurry. For Netty van Gasteren and me it was a definite consolation to find in Carmel a good restaurant.

The next Monday I was absent again, as John Backus had invited me to give a lecture at San Jose, early in the morning. The period immediately after breakfast is never my most communicative one and Cadiou asked me all sorts of manager's questions. I did my best and enjoyed the scenery: it was very nice not to have to drive that stretch myself. In the morning Steve Zilles showed me what he was doing: a computer-driven colour TV-screen used to display the kind of diagrams I always skip when I encounter them in a book. This time politeness forced me to look at them —though the combination of bright colours and flickering made it almost a bit painful— . Needless to say I found my prejudices against pictures fully confirmed. After lunch I gave a talk; the facilities, I am happy to say, were adequate. After my lecture Gray explained to me a few of his "distributed processing paradigms", and that was illuminating. It seemed also very sensible: in this (still early!) stage of the game concentration on a few well-chosen (or should I say: carefully designated?) paradigms is almost the best thing one can do. Five people from IBM, San Jose, joined me for dinner in a very special Chinese restaurant that John Backus had selected: I enjoyed the food somewhat more than the company, but the food was very hard to compete with. Thereafter John saw me back to UCSC. A tiring day, but not uninteresting.

On the next four days I listened to Mealy, Turski, Reynolds, and Jackson, and gave my own four lectures (two of which had still to be prepared: material originally intended for The Summer Spectacular had been used during week zero). My lectures went this time very smoothly. (As a matter of fact, at several occasions I was impressed myself!) And for the circumstances —which I regret— that it was sometimes hard to read what I had written or to hear what I had said, I refuse to accept the blame. Views expressed in my last lecture —the closing lecture of The Summer Spectacular, delivered under the motto "Beauty is Our Business"— as to what should constitute the core of computing science would evoke violent opposition the next week, primarily from Jim Horning.

The meeting of WG2.3 left me with feelings more mixed than ever: some of the glue that used to keep that group of individuals together seemed to have dissolved.

One of the main components of the glue —at least: in my limited observation— used to be the shared recognition that, evidently, we did not know how to think, speak, or argue adequately about the problems we had to think, speak, or argue about. The next stage —again in my limited observation— was the shared recognition that (not surprisingly) only the most effective application of the mathematical method —in Morris Kline's sense: "More than anything else mathematics is a method."— could be hoped to solve the problems adequately. The charter was clear: searching for the relevant abstractions and separation of concerns that are specific to programming, and learning how to avoid in general the explosion of formulae when dealing with stuff more complicated than mathematicians had ever formally dealt with before. I found this charter sufficiently challenging to devote my scientific life to it; at the same time this charter was sufficiently unpopular "in the real-world" —the hyphen is not my invention!— to justify the protection of an IFIP Working Group (for what it is worth). I was forced to admit that the glue is no longer what it used to be.

1)     A sizeable fraction of the membership —both old and new— had failed to catch up with what has been achieved over the last ten years. Over and over again people tried to "understand" the topics in ways that have already been identified as inadequate at least eight years ago. I should add that many a speaker invited this misunderstanding by thinking himself —and hence presenting his material— in ways of well-identified inadequacy. (The mistakes of trying to "understand" a program in terms of the class of the corresponding computational histories, and of trying to "understand" programming languages in terms of a specific implementation were the most common ones. They caused endless confusion, which were depressing to witness.)

2)     Some lecturers did not succeed in attaining the effectiveness required of their mathematizations. There is nothing wrong with that: WG2.3 should be the audience par excellence to offer suggestions for improvement. Sometimes, however, those suggestions were not made, sometimes they were not invited, and for a working group concerned with methodology, both seem wrong.

3)     Then there are those members that I tempted to regard more or less as victims of the Educationists with their concern for The Whole Child and their disdain for competence. They cannot content themselves with what science may have to offer to programming methodology and consider the charter as I understood it as too narrow. As a result fruitless discussions on the verge of sociology and/or philosophy were unavoidable.

In retrospect —i.e. after two weeks— my overwhelming memory from this WG2.3 meeting is the very lousy impression I got from Xerox PARC (Palo Alto Research Center). Rumor est —and I have no reason to doubt the rumour's truth— that our chairman Jim Horning has drawn our member W.Teitelman's attention to the fact that he had not attended the previous three meetings and had reminded him of the rule that such lack of interest could terminate his membership. Nothing wrong so far, Teitelman was, indeed, not very interested in attending the meeting, but then their common boss at Xerox PARC, a certain Bob Taylor, exerted pressure on Teitelman on the grounds that it was good for Xerox PARC's status to have a few employees on WG2.3! So far the rumour. And Teitelman attended! At least, he did so in a minimal way: he was present on Monday and wasted our Wednesday morning with a terrible video-show.

On two television screens they played a video-tape showing Teitelman himself at his terminal, playing with "Interlisp" —something I wouldn't dare to show: last year's reference manual for Interlisp is already something like a two-inch thick telephone directory!— . (The show was —of course!— in colour, but its technical quality was abominable: colours shifted all the time, and often the screens showed as much disturbance as interpretable picture. The equipment used, I am happy to say, was not a Philips product. Without having attended such a session it is hard to believe what junk such a gadget-ridden subculture is willing to put up with. So much for the influence of a tool on those that try to use it!) The show itself I can only describe as insipid, and I was relieved when Teitelman showed the last remains of good sense when, with the words "This is too painful." he switched the equipment off before the show was over. This show and a discussion later during the week gave me the strong impression that at Xerox PARC research in computing science is primarily viewed as gadget development, rather than as gaining insight. (Wlad Turski gave a terse comment: "But what do you expect? Truth is not an industrial product.") In view of the fact that Xerox PARC is one of the U.S.A.'s more prestigious "research" establishments —so prestigious, as a matter of fact, that M.I.T. prides itself on mimicking it— this is a rather discouraging observation.

On Saturday morning at 8.15 Bill McKeeman came with his car to take me to the airport of San Jose. Via Los Angeles and El Paso I flew to Austin, Texas, where I arrived at sunset. Dr.Hamilton Richards, who had been so kind to offer me the hospitality of his home, was at the airport, where we rented a small Toyota that would serve me the rest of the week. On Sunday and Monday —Labour Day— the two of us went to the Burroughs Lab., where I met a Dutch student (from Twente) who, as part of his training, had worked there for ten weeks. Both he and the people at Burroughs seemed to be very pleased about the way in which that had worked out. On Tuesday morning and on Wednesday morning I lectured for the people that had been attracted since my last visit there. (My audience reconfirmed my earlier impression that Rice University is a pretty isolated place.) On Tuesday afternoon I had a discussion on a problem about we had had some correspondence since my previous visit; after that discussion I went home and had a little nap. (I am afraid that my body had not been built for the climate of Texas in early September: the days were exhausting and the nights not restoring.) Wednesday afternoon and Thursday morning I spent in company of Dr.R.R.Johnson, on Thursday afternoon I visited The University of Texas at Austin where I gave my last lecture of that trip. (I did so in a large auditorium, but this time the PA system was excellent.) The next morning, at 7.15, I was on my way home. Despite all the hospitality bestowed upon me, I did not regret my departure from Austin. (On the first evening Joanne Richards, Hamilton's wife, discovered a scorpion in their little son's bed. Presumably one can get used to such encounters, but I hardly managed to do so in five days and six nights.)

I had a long layover at JFK, most of which I spent reading and writing. I had been booked on KL644, leaving JFK at 22.10 and tried whether I could get a seat on KL642 that would leave New York three hours earlier. At the expense of an additional $100.— this was possible, but I thought it crazy to reduce a six-week trip by three hours at the additional expense of $100.— and declined the offer. On board of the KL644 it became known that the KL642 had had to return to New York on account of trouble with one of the engines! Had I been lucky! We landed at Schiphol on Saturday morning 11.00, where my wife was at the airport with the car. At 13.15 we were home. During the next week I felt that I had been away for six weeks: my problems with the time shift were unusually severe.

14 September 1979
Plataanstraat 5
5671 AL NUENEN
The Netherlands

prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 16-Oct-2011

  EWD 715

Trip report E.W.Dijkstra, Munich – London, 16 –29 September 1979.

     Actually these were two trips, between which I was three days at home. The first trip was to the 4th International Conference on Software Engineering in Munich, the second one was to Euro IFIP 79, held in London. I visited them both because for both conferences I had agreed to deliver an invited speech at the closing session. For the first conference I stayed in the little village of Holzkirchen as the guest of Professor Gerhard Seegmüller, during the second conference I stayed in the Wembley Eurocrest Hotel. But apart from such minor differences the two conferences were sufficiently similar to be dealt with in a single trip report. Both attracted slightly over 1000 participants —and, hence, were regarded by their organizers as a success— and both had the same sort of charter. I quote from the program of the 4th ICSE:

"The tone and emphasis of the present Conference has clearly been set by the fact that interest and emphasis is currently focussed on the tooling and tool support of the programming and software maintenance process; the use of computers to produce and maintain higher quality, timely, cost-effective and long-life software."

I quote from the Proceedings of Euro IFIP 79 —with the conference subtitle "European Conference on Applied Information Technology"—

"The whole emphasis is on applications, in government, in control of the environment, in the expansion of human capability, on social effects."

Both conferences pandered to current fashions and tastes of the many, as true products of bestsellerdom. The organizers sold their products and seemed content, but what went over the counter was in general just as vulgar as was only to be expected. I shouldn't have given in when their organizers invited me, I shall not attend such conferences for years to come, for they are a depressing waste of time.

      The one in Munich depressed me deeply. (That is not to say that the one in London was better: presumably my experiences at the first conference had suitably lowered my expectations of the second one.)

      In many fields the traditional controversy between "theory" and "practice" may be a very real and unavoidable one. What fascinates me about computing is that the controversy need not exist, for what is theoretically sound and scientifically elegant is usually at the same time eminently applicable in practice. This has been expressed by many —see the chapter "Theory and Practice" in "Software Engineering Techniques", Rome, 1969, Eds. J.N.Buxton and B.Randell— and experience has given abundant confirmation of it. And yet, at conferences like these, this stale and obsolete notion of the controversy is still in full vigour! The mathematician is still depicted as someone walking with his head in the clouds, the practitioner as someone who stirs in the mud (or even: has to stir in the mud) but does the "real work", etc. Hackneyed phrases seem to be the dominant mode of thought, and, as a result, I felt in a primitive society indeed. This feeling was enforced by the observation that exposure of the clichés, as well as challenge of the tacit assumptions, was strictly taboo. This was even the case with some explicitly stated articles of faith, such as:

Because modern technology can produce more chips than we need, computing science's most important task is to discover new applications for them.

Software engineering is in such a bad shape because it has refused to automate its own job.

Needless to say, I found these articles of faith somewhat hard to subscribe to.

*             *
*

      On one of the first days in Munich I was vividly reminded of my third visit to the USA, when I attended the Operating Systems Principles conference in Gatlinburg, Tennessee (1967). To my utter amazement the poor quality of the then current operating systems was there blamed on the fact "that we did not have a Language for writing Operating Systems in"; as a result of the predictably fruitless and confused discussion that then followed, the absence of a "Specification Language" was invented to share the blame.

      I was reminded of that incident when I was approached by three young Americans that (on account of a remark made while lecturing at the University of Texas in Austin) wanted to differ of opinion with me about the design process. Eventually I had skirted the (in their minds important) issue of "what language to use". (Shortly after my discovery that I was talking to three psychologists, Susan L.Gerhart saved me.)

      This happened after I had listened that day to two invited American speakers —Dr.Barry Boehm and Dr.Charles Vick— who had shocked me by their extremely sloppy use of their own language: full of meaningless jargon and awful neologisms —from Boehm I learned that besides "human factors" and "human engineering" (terms I cannot hear without a shudder) we now have "software psychology"— and, in the case of Vick, presented as if logic and grammar were dispensable commodities. Then I suddenly realized that both did business or belonged to the DoD, remembered how profoundly inadequately English had been used in the Ironman and Steelman requirements. Since that moment I cannot get rid of the lurking suspicion that much of the American preoccupation with all sorts of artificial special-purpose "languages" is closely related to the fact that large layers of that society —the academic world included— is basically illiterate. Such an assumption of wide-spread illiteracy is frightening, and has worried me all through the two conferences. We may have been unlucky with the selection of overseas speakers, but as far as I can remember Professor E.J.McCluskey from Stanford has been the only American speaker I heard that did not speak undiluted nonsense most of the time. After Boehm's talk in London I asked him, because he had been allocating software costs and I had missed the item, how much of the costs he felt could be attributed to the use of sloppy language. His answer was notable in two respects. The one is that he (almost automatically, it seemed) narrowed "sloppy language" down to the use of undefined terms; the other is his actual estimates "In small student projects I would say 20 percent. and in large projects much more." The result is that the lurking suspicion is still with me; and because the U.S.A. is a large and influential country I have now and then a hard job at not coming too close to despair. One thing is certain, however: independently of the question whether the lurking suspicion is justified or not, the intrinsic problems of computing science should not be confused with difficulties that have been created by the American educational system.

*             *
*

      In Albany and in Santa Cruz I had had two rehearsals for my invited speech; in Albany it had fallen flat on its face, in Santa Cruz —but that was for an audience that had been educated during the preceding two or three weeks— it had been a great success. In Munich, where I addressed about 1000 people at the end of the third and last day, it was a mild disaster. In London I therefore used the time I had available in my hotel room to reconsider its presentation. I gave it at the end of the fourth and last day, and this time I seemed to reach again most of my audience (with the exception of the Chairman of the Organizing Committee, who used the dimly lit Grand Hall to fall soundly asleep on the front row). The organizers had scheduled me for the closing session with the hope of keeping the participants' attention to the very last moment, but that gimmick failed: the last day only a fifth of the participants turned up. (I couldn't blame them.)

      In the first week I had enjoyed the beauty of the countryside of Southern Bavaria; after EURO IFIP 79 I strayed the night with Mike Woodger, with whom I had a very nice stroll amidst the Surrey hills on Saturday morning. My KLM flight back home was half an hour late.

Plataanstraat 5 5671 AL NUENEN The Netherlands | prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

EWD716

A short talk to my students about money

You may be amazed to discover that in the introduction to a series of lectures on implementation issues I feel compelled to address you on the topic of money. So am I. But I have to do so in reaction to a current trend in what is called "Software Engineering Education", a trend that is becoming more and more fashionable but --as I hope to show in the following-- also regrettable, because confusing.

The current educational argument, reduced to its bare essentials, is more or less as follows. Because the academically trained software engineer --whatever that is-- must be able to take responsibility for large projects and large projects require management, the future software engineer must learn how to manage his project in its environment. Because its environment, whether government or industry, is regulated in terms of schedules and budgets and the like, the software engineer must, therefore, acquire a thorough understanding of how schedules and budgets and the like are used in the regulation and organization of the environment in which he will have to work. The conclusion is obvious: one of the major pillars of wisdom on which any curriculum for software engineering must rest is called Management Science. I have learned that for many this "conclusion" is so much an article of faith that merely challenging it is already regarded as an act of heresy, only to be committed by the lunatic that is courting to become cast out from his society. But to act as that kind of lunatic is the scientist's predicament, so there we go.

One of the underlying assumptions concerns the proper role of the Universities: it is assumed that for the benefit of us all the campus should prepare the students for later life by familiarizing them, while still on campus, with the world outside, in which he will have to fit once he has got his degree. It is a view. Sometimes I fear that, within a few years, it may become the only view that will be permissible in our country. It is not my view. Let us listen, by way of contrast, to what the Cambridge historian G.R.Elton has to say about the teaching of his subject, because I think that his remarks are equally pertinent to any other topic than history:

"Three or four years spent at a university cannot teach a man to know history; they cannot train him as a politician or publicist or publisher; they can at best begin to lay some foundations for a view of the world and (universities being what they are) are likely to lay foundations which, as later experience shows, need to be broken up. None of this invites blame: the impossible need not be attempted. But if those years do not produce an effective conditioning of the reasoning mind, if they do not teach a man to think better than otherwise he would have done, they may justly be condemned as a waste of time."

(from: Elton, G.R., "The Practice of History", Sydney University Press 1967)

The other underlying assumption is that something called Management Science and worthy of the name, indeed, exists. I, for my part, haven't encountered that yet.

*                             *
*

I leave to you the choice of ordering principle according to which you prefer to arrange your impressions and memories. Perhaps you are used to interpreting each accident as a manifestation of the justice of God; or you prefer to describe changes as shifts of power; maybe you classify your impressions as phenomena associated with the rise and fall of ideas; perhaps you see primarily the circulation of money. I leave you free: so far as I am concerned, none is in any way "truer" than any other. But I do take the liberty of pointing out that for certain goals some of them are more helpful than others, and even that ordering principles have been adopted despite the fact that they have almost always been confusing.

Generally speaking, money has been one of those. I do not exclude that it is a helpful notion for someone "that understands all about money", but must add that I am not aware of having met such a person. In general, as I said, financial considerations are profoundly confusing. This is not to be wondered at, and no one is to be blamed for it: money is a notion as abstract and elusive as coins are concrete and tangible.

Evidently money has been used as a means for keeping track of mutual rights and obligations. As computing scientists we are reminded of the absolutely essential role played by non-negative integers (in this context known as "semaphores") when the co-operation between loosely coupled processes has to be organized. Representing an integer value by the corresponding number of things --say: number of coins in your pocket-- admits by the very nature of the representation non-negative values only, and as a computing scientist I am therefore perfectly willing to "understand" how since their invention coins have played some sort of role for the purpose of regulation. And when it is explained to us that the monetary crash of 1929 has been precipitated by almost unbounded credits, we are almost willing to accept that as an explanation: as computing scientists we only know too well that, to serve its purpose, a semaphore value must be strictly bounded from below. Such analogy may give us some coarse appreciation of money's proper role, but that is about all. Let me, therefore, give you two examples of how without a more subtle understanding of money, financial considerations may lead a designer astray. I observed both in the mid-seventies.

I listened to a series of lectures about hardware design. One of the speakers tried to explain to us that thanks to the rapidly developing technology hardware design had almost become impossibly difficult. After some probing the speaker's problem became clear: whenever he had the choice between different designs, he used to choose the cheapest, but that patter of behaviour presupposed that he could determine the price of a considered design with sufficient accuracy. And now he discovered to his dismay that technological changes had made "the future values of the coefficients in the price-equation" unpredictable. The poor man had lost his one and only guiding principle and did no longer know how to design!

The second example of financial confusion is a little bit more subtle and, I think, more wide-spread. I had described the outline of a system for the automatic management of a two-level store in a general purpose computing facility and had tried to justify all my design decisions. Though he thought most of my justifications pretty convincing, one of my academic colleagues was profoundly disturbed, because nowhere in my considerations I had paid any attention to the obligation of the system designer to maximize the utilization of the most expensive components of the installation. I was not amazed at the objection, because I have heard it many times before, though I was perhaps a little bit amazed to hear it from him. What did amaze me was, that it took me several letters to convince him that the supposed obligation to maximize the utilization of your installation's most expensive components is sheer nonsense.

You see, there are two completely different questions involved. The one question is roughly: "Given such and such an installation, what is the best way to provide such and such a service, and how good is that optimal way?" (For the sake of the argument I have slightly simplified that question by doing as if the notions "best" and "optimal" are sufficiently defined.) The other question is --equally roughly--: "Given the prices of the different possible installations, for which installation gives the optimal service most value for its money?"

To provide the answer to the first question is clearly the job of the computer professional, but note, that the question as put is absolutely independent of prices: it is possible to think about the question how to use an installation that has been given to you for free!

To answer the second question is the job of the director of the computation centre; and, again, note that he can make up his mind without knowing how the different degrees of service can be achieved with the different installations.

If both the computer professional and the director have done a good job, it is highly likely that, in the installation that eventually gets installed, there will not be a surplus of very expensive components, i.e. the ones that are there can be expected to be used reasonably intensively. But that was in no way a target for the implementer, it is only the result of the way the director has decided to spend his money.

The fact that the two concerns can be separated is more important than --as the case may be-- that they may be taken care of by the same person.

1st October 1979                                      prof.dr.Edsger W.Dijkstra

transcribed by Tristram Brelstaff
revised Sat, 12 Jun 2004

EWD717 - 0

An exercise in exposition.

The body of this note describes my solution to a problem communicated to me by R.W. Bulterman. The note is written because, after I had found my solution, it was not immediately clear how to describe it well. (This text is my second effort.)

The problem.

We consider a graph consisting of a pentagon A and a pentagon B, extended with all edges that connect a vertex from A with a vertex from B. (The graph has 2x5 = 10 vertices and 2x5 + 5x5 = 35 edges.) Furthermore it has been given that

1) | each edge is either white or black, and
2) | no three edges of the same colour form a triangle.

Prove that the five edges of pentagon A and the five edges of pentagon B have all ten the same colour. (End of problem.)

The proof.

Arrange the 25 edges that connect a vertex from A with a vertex from B in a 5x5 array, such that the cyclic order of the columns corresponds to that of the vertices of A, and the cyclic order of the rows corresponds to that of the vertices of B. There are five pairs of "adjacent columns" because the first and the last columns

EWD717 - 1

are also considered as an adjacent pair; similarly for the rows. (The array fits on a torus.)

We denote by "a cycle" either a row or a column. By calling two cycles "orthogonal" to each other, we denote that the one is a row and the other is a column. Two adjacent cycles are said to be "linked by a colour" if and only if there exists a cycle orthogonal to them in which they both contain an element of that same colour.

From 2) we can now conclude:

3) | no two adjacent cycles are linked by both colours.

for if, for instance, two adjacent columns are linked by one colour, 2) allows us to conclude that the corresponding edge of A has the opposite colour.

The "dominant colour" of a cycle is defined as the colour occurring most frequently in it. (Because each cycle contains 5, i.e. an odd number of elements, the dominant colour of a cycle is always defined.)

Consider, for instance, a column for which the dominant colour is white; it then contains white elements in two adjacent rows. On

EWD717 - 2

account of 3), an adjacent column contains at least one white element in those two rows, i.e. the two adjacent columns are linked by white. In general we conclude:

4) | adjacent cycles are linked by the dominant colour of any one of them.
On account of 3) and 4) we conclude:
5) | adjacent cycles have the same dominant colour.
Hence --by induction--
6a) | all columns have the same dominant colour
6b) | all rows have the same dominant colour.

Because the dominant colour of the array as a whole equals the dominant colour of the columns, but also that of the rows, 4) allows us to conclude:

7) | all ten pairs of adjacent cycles are linked by the dominant colour of the array as a whole,
and on account of 1), 2), and 7) we conclude
8) | the colour of any edge from pentagon A or pentagon B is opposite to the dominant colour of the array as a whole.

(End of proof.)

Plataanstraat 5 5671 AL Nuenen The Netherlands | 3rd October 1979 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Tue, 24 Jun 2003.

EWD718

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Assembly conventions for the EDSAC.

In this note I shall give a survey of the assembly conventions as developed for the EDSAC —later called “EDSAC 1”— in order to subject them to a later analysis. The choice of the EDSAC conventions has been inspired by three considerations:
1)     they have been well-documented (if we mean by “well-documented”: fairly completely; by today’s standards the book [1] is pretty unreadable!)
2)     the EDSAC in Cambridge, England, was —and shall remain forever!— the world’s first program controlled automatic digital computer (EDSAC standing for Electronic Delay Storage Automatic Calculator)
3)     the subtitle of [1] is: “With special reference to the EDSAC and the use of a library of subroutines”, and the second part of this subtitle explains why this machine deserves our special attention. In retrospect I think it quite impressive that the group in Cambridge realized, right from the start —note that this was in the late forties!— that there was no point in designing and building a machine without designing a discipline for its usage as well.

The store consists in principle of consecutively numbered locations of 17 bits —usually the text refers to “the address of a location” but the term “serial number of allocation” is also used occasionally— . In the true von Neumann style, such a 17-bit location contents admits two interpretations, viz. that of a “short number” and that of an “instruction” or “order”.

Historical aside. “A special feature of the EDSAC is the possibility of combining any two consecutive storage locations (provided the first one has an even serial number) into a single long storage location capable of holding a number with 35 digits. [...] It is possible to accommodate 35 digits in a long storage location, and not 34 only, since in the ultrasonic store of the EDSAC the digits of successive numbers are stored end to end and one digital position between each is left unused; when two storage locations are combined this position can be used to contain an extra digit (sometimes called the ”sandwich“ digit).” The existence of such long locations explains the constraint for some subroutines that “the first order must have an even address”.

In the section “Input and output subroutines” —when dealing with the input of long constants— the sandwich digit is responsible for the paragraph: “When a subroutine contains only one or two long constants, an alternative to the use of an input subroutine [for the conversion from decimal to binary representation] is to put the constant in as two short numbers. A difficulty arises, however, because there is an unused digit between each two short numbers (the ”sandwich digit“). The method can be used, therefore, to put in a number which has a zero in the 17th position after the binary point. This is not a serious limitation, since either the number itself or its complement is of this form unless it is an odd multiple of 2⁻¹⁷ .” (End of historical aside.)

In store, each instruction occupies 17 bits, from left to right:
5 bits for the functional part
11 bits for the address part
1 bit for the indication short/long (for some instructions, such as the jump instruction, not meaningful).

When stored, a subroutine always occupies a number of consecutive locations. Because an instruction of a subroutine may have to refer to one of the words of the subroutine itself, the bit pattern representing the subroutine in store may depend on the actual place the bit pattern occupies in store. Such reference to one of the own words of the subroutine arises
1)     in internal jump instructions —used as a tool for the implementation of alternative and repetitive constructs—
2)     in the use of (numerical) constants occuring in the bit pattern
3)     in the use of variables allocated within the bit pattern (independent of the question whether these variable words are also interpreted as instructions or not)
4)     in supplying in one of the registers of the arithmetic unit return information: the calling sequence of a (closed) subroutine contains an instruction that places itself in a register.

Note. Observe that allocating variable information within the bit pattern is not the only cause for the need within a subroutine to refer to itself. (End of note.)

Note. If instructions could address relative to the current value of the instruction counter or, better still, relative to the address of the first order of the subroutine currently being executed —a convention that would probably require a special register reserved for that purpose— the bit pattern representing a subroutine in store would no longer need to be dependent on its position in store. (End of note.)

Besides being dependent on its own position in store, the bit pattern representing a subroutine in store may also depend on the positions of other subroutine or data areas the subroutine needs to refer to.

All that has been said above about subroutines is also applicable to the main program. The only potentially different role —about which more later— of the main program is that it need not be placed in the subroutine library.

By today’s standards the store of the EDSAC was very small. In the instruction format we have 11 bit available for the address part, the machine was designed to have a store of 1024 short words only, and I am not sure whether more than 512 short words have ever been built. (The more mercury tanks, the more severe the technical problem of keeping them with sufficient accuracy at the same temperature.)

As a result it was understood, right from the start, that the total subroutine library would be many times larges than the total storage capacity of the machine. As a result the subroutine library must contain for each subroutine a representation that is independent of its actual position in store, when actually used.

Each subroutine in the library was punched on a separate piece of five-hole paper tape. Un the tape each instruction again consisted of function part and address part. The function part was represented by a letter —supposedly of some mnemonic value— , the address part was represented by a (decimal) integer, followed by a so-called “closing letter”; of the 15 closing letters available, 3 had a constant meaning, the remaining 12 were available to control, which bit pattern would be derived from the punched subroutine text, in which a different closing letter would be used for each subroutine or data area referred to.

Because the control needed is purely additive, the following arrangement works. During the reading of (a copy of) a library procedure each next word to be stored is formed by building up (the binary representation of) the instruction as represented by function letter and following decimal integer, and by then increasing the result by a “preset parameter” that depends on the closing letter. On the final tape each copy of each library subroutine is preceded by a series of “control combinations”, defining for each of the (variable) closing letters used in the following library subroutine the value of the corresponding preset parameter.

Historical note. I quote section 6-2 “Storage of library subroutines.” from [1]. “Subroutines in the library are punched on colored tape so that they can easily be distinguished from program tapes, which should be white. Several copies of each subroutine are provided and when not in use each copy is rolled in a small cardboard box. The boxes are filed in serial order in a steel cabinet. The master copy of each subroutine is kept under lock and key and is used only when all existing copies of the subroutine are damaged. The master tape is then used to prepare further copies by means of a duplicator. All copies must be checked against the master, by means of a comparator, before being put into the library for general use.” (End of historical note.)

The mechanisms sketched above are used in two ways. In the one way the programmer decides explicitly the complete storage layout of the final program, i.e. the addresses of the first orders of all subroutines and of the first numbers of all data areas. In terms of these chosen addresses he can formulate all the control combinations defining the preset parameters and the main program. The authors add: “A few spare locations can, however, be left between the subroutines if desired. This reduces the possibility of error arising because of a miscalculation of the locations required by a subroutine and enables corrections involving a slight increase in length to be made to a subroutine without renumbering. Such corrections often must be made to subroutines which have been specially constructed for the program.“

The other way is introduced as follows: ”[In the examples shown] the programmer has to decide where the master routine and each subroutine are to go in the store and to insert the correct addresses in the orders in the master routine which call in the subroutines. The object of an assembly routine is to relieve the programmer of these and other mechanical tasks.“ (In view of the modest size of the store, and hence of the largest program that could be composed for the machine, the argument in favour of the assembly routine doesn’t sound too convincing!)

Data areas are numbered in the order in which they occur at the beginning of the tape; they are followed by master routine and the subroutines, which are also numbered in the order in which they occur on the tape. References to subroutines or to data areas —either in master routine or in the control combinations defining the preset parameters— are essentially expressed in terms of these ordinal numbers. An assembly routine named ”M1“ places these areas and routines consecutively in store, at the same time filling in the starting addresses as they become known. The fifth note deserves to be quoted: ”If storage space is short, M1 may be placed where it will be overwritten by the last subroutine of the program.“

Note. On the one hand it is a feat of ingenuity that the same input program —the so-called ”initial orders“— could be used with and without the assembly routine M1 . I also think it telling that the use of the assembly routine M1 was optional; not using the assembly routine saved a word per routine and that may have been the reason. Another reason may have been that, when all was said and told, the service provided by the assembly routine wasn’t that impressive. (End of note.)

Let us now try to analyze the EDSAC assembly conventions a bit further. The purpose of this analysis is the isolation of its separate components and a more clear understanding of their roles.

We begin by remarking that, when assembly routine M1 is used, library subroutines are referred to in four different ways
1)     by their “library name”, as in the catalogue —in the following is shall use the term “library name” to refer to the name of a subroutine, viz. the name it has in the library—
2)     by a “closing letter”, as on the library tapes
3)     by their “ordinal number” as they appear on the final tape
4)     by their “address of first instruction” in store.

All four —library names, closing letters, ordinal numbers and addresses of first instructions— can be represented by bit sequences and, as such, all could occur on the final tape. The first question to be answered seems to be: why do the library tapes refer to each other by means of closing letters, and not by means of library names?

In the case of the EDSAC the answer is simple: the processing of a library name, in particular the associated selection —of the contents of the appropriate cardboard box from the steel cabinet— was deemed beyond automation and, hence, kept outside the machine. Hence no library names on the final tape, hence the need for other nomenclature.

Because this answer is so simple, it might be instructive to think for a moment about the situation in which such automatic selection of a standard subroutine text, given its library name, would be possible, but only “after a fashion”. With “after a fashion” I mean that such automatic selection, though possible, is a most painful process: we may think about the whole subroutine library —the contents of the steel cabinet, so to speak— being punched on one huge reel of paper tape. In that case the processing of a library name is sufficiently painful to make it obvious that a major purpose of the game is to represent the library subroutines selected in such a way that thereafter library names need not to be processed anymore.

As soon as we remember our target, i.e. the representation of the selected library routines that is free of library names, it is clear that our most attractive source is one in which the bulk is free of library names. Well, this is exactly what the closing letters do for us: on the huge reel we could have each subroutine body exactly as it is punched now on the tape in the cardboard box, but preceded by the analogue of the control combinations for the preset parameters; on the huge reel these control combinations would define the meaning of the closing letters that are used in the subsequent body in terms of library names.

The closing letters appear as a local terminology —local to the tape representation of the subroutine— for reference to its environment, and we are free to choose the most convenient terminology.

When members of a set are essentially identified by (an equal number of) successive integers, this is sometimes called “a closed nomenclature”. Closed nomenclatures have the advantages of being compact and being easily processed, viz. as subscripts in linear arrays, this in contrast to “open nomenclatures”, the processing of which requires searching, hashing or other “associative” techniques. (Names of people —assumed to be all different— form an open nomenclature: an arbitrary sequence of letters is almost never the name of an existing person; telephone numbers in a town, however, form an almost closed nomenclature. Quite wisely the telephone exchange only accepts the closed nomenclature, leaving to us the searching in the directory in order to discover what to dial!)

Note. When elements of a set are identified by means of a closed terminology, the membership test is trivial: the number must be at least equal to the lower bound and at most equal to the upper bound. The fact that the cost of this test is independent of the size of the set has been cleverly exploited in a number of surprisingly efficient graph-theoretical algorithms designed in the 70’s by R.E.Tarjan and others; the algorithms could be arranged in such a way that all subsets to be considered would always contain consecutively numbered vertices. Run-time legitimacy tests of addresses as encountered or generated during program execution form another application. (End of note.)

The successive closing letters are no more than a coding for the successive natural numbers: the local terminology in which the tape representation of a subroutine refers to its environment is closed. The vital importance of the local terminology per subroutine is not that it is closed —that is only very nice— but that it allows a representation that is independent of the actual environment: the same representation of the bodies is as meaningful on the huge reel of paper tape that contains the whole library, as it is on the final tape that contains only the subroutines selected.

Note. For the sake of completeness I should mention that in the EDSAC assembly conventions the protocol of the preset parameters and the closing letters is not only used for the extraction of the “sublibrary” consisting of the library subroutines actually used in the program: it also gives the programmer the possibility of additional control. We may have two library subroutines, B1 and B2 say, semantically equivalent, but the one Faster and the other shorter. Another library routine may need either B1 or B2, and the choice can be left to its user, who can express his preference in a preset parameter. (End of note.)

The dependence on the actual environment is concentrated in the definitions of the preset parameters. On the huge reel it had to be in terms of library names, these forming the only terminology that covers the whole library. But we wanted a final program tape free from library names, hence a local terminology for the set of selected routines has to be introduced. Having seen the advantages of a closed terminology, the introduction of the “ordinal numbers on the final tape” is no longer a surprise.

In the final stage, i.e. during the input of the program, assembly routine M1 allocates all routines and substitutes (or adds) “addresses of first instructions” all over the place, as required by the EDSAC hardware that transmits the bits of the address part of the instruction under execution directly to the selection register of the store (or to the instruction counter if it is a jump instruction). When no assembly routine is used, this distribution of position dependent information all through the program text takes place in two stages: the programmer, who composes the final tape, distributes “addresses of first instructions” up to the preset parameters —thus bypassing the terminology of the ordinal numbers— , and the input program takes care of their final distribution, from the preset parameters into the bit patterns representing the subroutine bodies in store.

Note that the final stage, as sketched in the previous paragraph, whether done with M1 or without, combines two distinct elements we had better distinguish between: the routines are allocated and the outcome of this allocation decision is distributed all through the program text. Such allocation decisions are in a very special way typical: they are both irrelevant and unavoidable. When we design a library text, the number of independent references to the environment decides the number of preset parameters, and when we make it a rule to use them in order, this number determines which closing letters we are going to use. But with N independent references we can pair the closing letters and the objects referred to in N! different ways! The way in which the routines get their ordinal number on the final tape is equally arbitrary. And so is the allocation of store regions to the different routines. Arbitrary, and therefore irrelevant, as they are, yet those decisions have to be taken. (It does not suffice to develop the theory that collisions can be avoided if every verhicle keeps the same side of the road: in practice a country has to choose between “keep left” and “keep right”.) It is very appropriate to leave such irrelvant but unavoidable decisions to the machine.

The distribution of the outcome of the allocation decisions all through the program text is, however, a completely different matter. No further decisions are taken, the only thing that happens is that the values decided upon are copied in all sorts of places.

In the case of the EDSAC this duplication, all through the program text, of such allocation information was dictated by the structure of the hardware, which was kept as simple as possible. We should, however, always remember its consequence: information that has been duplicated all over the place is very hard to change. As I hope to explain later, allocation decisions are very often typically the kind of decisions one would like to revoke. Under those circumstances a machine structure that, for supposed reasons of efficiency, forces extensive duplication of information that, for other reasons, one would like to keep volatile, can become a great nuisance.

The supposed benefits of duplication are always easily expressed and quantified: simpler hardware performing more instructions per second. The ill effects of the ensuing loss of flexibility in machine usage are more subtle and less easily quantified. They require more foresight than many a machine designer has shown to possess; as a sad result the penalties of operating system overhead can be impressive.

[1] Wilkes, Maurice V., Wheeler, David L. and Gill, Stanley, The Preparation of Programs for an Electronic Digital Computer. (With special reference to the EDSAC and the use of a library of subroutines.) AddisonWesley Press, Inc., Cambridge, USA, 1951.

Plataanstraat 5 | 18th October 1979
5671 AL Nuenen | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-04-11 .

EWD719

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On not duplicating volatile information.

In EWD718 I have described the assembly conventions for the EDSAC. With one aspect of the problem they dealt quite satisfactorily, viz. with the problem of extracting a sublibrary from the total library of subroutines. A characteristic of the organization was the introduction of a closed nomenclature for the elements of the extracted sublibrary, this in contrast to the open nomenclature for the elements of the total library. Less satisfactory was the free duplication (or the uncontrolled dissipation) of all sorts of allocation results formed in the various stages of the assembly process.

In the EDSAC organization one could get away with the crude solution of duplication thanks to a number of simplifying circumstances. I mention the following ones:
a)     Always the whole machine was allocated to the execution of a single program; as a result it sufficed to have an organization that could embed the assembled program in that fixed and constant environment as provided by “the machine”.
b)     The machine was “simple” in that it had only a one-level store in which each location was as good as any other.
c)     The main components of the assembly —master routine and library subroutines— were “simple” in the sense that they were components of a constant size that was well-known in advance.

In short: the problem of duplicated volatile information was avoided by not introducing volatility. In this note we shall attempt a more systematic study of the ways in which duplicated volatile information can be avoided: we can try to avoid either volatility, or duplication!

A crucial observation is that some duplications are unavoidable, at least if we accept as dogma the purpose of creating an environment from which the open nomenclature that covers the whole library has disappeared. A program may call explicitly the library subroutines A and B , both of which may need library subroutine C ; in that case the preset parameters of A as well as those of B will contain a reference to C . As the dogma excludes the use of the library name of C in those preset parameters, a local terminology has to be duplicated.

Because we want to avoid the duplication of volatile information, these multiple references to C must be in a nomenclature that we can afford to keep constant. In the EDSAC conventions we have seen two techniques. Without the assembly routine M1 the programmer had to decide the storage layout once and for all, and the references to C in the preset parameters of A and B would be in terms of the address of C’s “first instruction”. with the assembly routine M1 the preset parameters of A and B could refer to C in terms of its “ordinal number”. The latter has the advantage that then the references are independent of the lengths of subroutines (as implied by their allocation in store).

If we take a program as the unit of assembly, we are allowed to take each subroutine’s ordinal number in that program as providing a sufficiently constant nomenclature that we may duplicate in the preset parameters.

Having thus avoided duplication of first addresses of subroutines on the input tape we should explore what would be involved in keeping them volatile. The answer is simple: don’t copy them, neither during program assembly, nor during program execution. Still confining ourselves to the situation in which the complete machine is at a single program’s disposal, we come to the following machinery during program execution.

To start with we would need —with apologies for the acronym— a program routine table PRT with an entry for each ordinal number used in the program; each entry will “lead to” —and here I have intentionally used a vague terminology— the corresponding routine’s current “address of first instruction”.

The program routine table PRT is needed to call a routine: given the routine’s ordinal number it will provide the current address of the routine’s first instruction, an address that is needed for the selection of the next instruction to be executed. The access to PRT in order to process the ordinal number of the called routine introduces some overhead on the procedure call; as soon as the routine has been called, however, its successive instructions can be selected with full speed as before, if we maintain the EDSAC’s “instruction counter” as the register containing the address of the location containing the next instruction to be executed.

Note, however, that maintaining such an instruction counter is a dangerous thing to do: upon subroutine call it is filled with a copy of “the address of the routine’s first instruction”, information that we wanted to keep volatile! We must keep such an undesirable copy under strict control; I suggest that we do not allow further copies of it to be made. This implies that we must provide an alternative for the EDSAC way of supplying at subroutine call the return information. Instead of copying the contents of the instruction counter —i.e. supplying the current address of the call— we must supply a non-volatile characterization of the place of the call. Within the context of the program such a non-volatile characterization is provided by the ordinal number of the calling routine, together with the cell’s position relative to the location of the calling routine’s first instruction. From the need to provide such non-volatile return information we deduce that in addition to PRT the machinery requires a further status variable, CRN say, for the “Current Routine Number”. In the subroutine call CRN is redefined and set to the ordinal number of the routine called, while its old value is saved in the return information; upon return from the subroutine it is reset to the ordinal number of the calling routine, whose execution is continued. (The status variable CRN can be viewed as a non-volatile extension of the instruction counter.)

So much for not duplicating addresses of first instructions. What about the ordinal numbers? As long as each single program has the whole machine at its disposal and can be regarded as a unit of assembly, the situation is relatively simple.

On the final tape each library subroutine is punched in terms of closing letters and preceded by control combinations that define the preset parameters in terms of ordinal numbers that are substitued for the closing letters during the input of the program. As a result the subroutine call as stored contains, just as the return jump generated during program execution, the ordinal number of the target routine. The entries of the PRT contain for each routine the address of its first instruction.

An alternative would have been not to process the preset parameters during program input by substituting them for the closing letters, but to store them in little tables. one for each subroutine. We might call them SCLT’s, short for Subroutine Closing Letter Tables. The SCLT belonging to a subroutine would contain an entry for each closing letter used in the subroutine; each entry would mention the ordinal number of the subroutine corresponding to the closing letter in question. Each PRT-entry would lead, besides to the address of the subroutines first instruction, to its SCLT, e.g. by mentioning the latter’s starting address. The bit patterns representing the library bodies are now allowed to contain their original closing letters; during program execution each closing letter can be translated into the corresponding ordinal number because the current SCLT can be accessed because its starting address can be found in the PRT under control of the current routine number’ CRN . (This would be a second use of the status variable CRN .)

The second alternative has been mentioned, not because it is particularly attractive, but because the first alternative —substituting the ordinal numbers all through the binary texts— does not work as soon as we would like to store several programs simultaneously, but in such a way that they can share the bit patterns of library subroutines used by several of them. The ordinal numbers supply per program a closed terminology for the library subroutines used in that very same program. The sublibraries extracted for the different programs will, in general, overlap only partly; it is, in general, therefore unavoidable that the same library subroutine will be denoted in different programs by different ordinal numbers. In the case of simultaneously stored programs sharing the bit patterns of common library subroutines the first alternative therefore doesn’t work.

In order not to complicate matters still further we shall assume from now on that the mutual dependence of library subroutines as to be catered for by program assembly is fixed by (the current state of) the library, i.e. we now disregard the form of programmer control over the assembly process as mentioned in the Note on pg. EWD718 - 7. Under that assumption the mutual dependence of the library subroutines is fully determined by the union of the subroutines possibly needed by each of the programs. For the sake of the argument I assume that that union is still a small fraction of the total library, small enough, in any case, to justify extraction and introduction of a “union nomenclature” that only covers the union of the library routines possibly needed by the currently loaded programs.

The fact that we have to play a new sort of game may dawn upon us as soon as we realize that. without renumbering, it is impossible to keep the union nomenclature fully closed. When only the first program is loaded the union nomenclature can be kept closed. When the second program is loaded in addition to the First, we can still keep the union nomenclature closed by assigning the next numbers to the further library subroutines needed by the second program. Because at the moment of the loading of the first program it was unknown which library procedures it would share with the second program, gaps in the union nomenclature must be expected when the execution of the first program terminates before the execution of the second program does so. By always assigning in the case of extension the first currently free number —“trying to fill the left-most gop”— we seem to do the best we can do when we wish to keep the nomenclature as well closed as possible: thus the maximum value assigned never exceeds the union’s maximum size in the past. In this case I think that the first free number strategy is quite acceptable and I assume in the sequel that it has been adopted for the union nomenclature.

It stands to reason to expect, analogously to the PRT for each program, for the installation as a whole a URT , short for Union Routine Table, with an entry for each routine of the library that may be needed by at least one of the programs currently loaded. In contrast to the PRT’s, the URT need not be fully closed: in the middle of it we may have entries marked: “currently free”. While a member of the union of selected subroutines, each subroutine has a constant “union number”, which acts as the selector for its entry in the URT

Again we have essentially two choices for the bit pattern to be stored. In the one case we regard the union nomenclature sufficiently constant to allow its duplication. The role of the PRT in uniprogramming is fully taken over by the URT , and all programs and all subroutines refer to the subroutines in terms of union numbers. The machine needs the status variable CRN as before, the only difference being that its contents is now interpreted as union number, the ordinal numbers having disappeared from the scene. Also all return information is represented in terms of union numbers. A consequence is that when the same program is loaded at two different occasions, the bit patterns representing the program at those two occasions will differ from each other, the union numbers used being all different. Such free duplication of union numbers makes the internal representation of each program dependent on the environment in which it happens to be embedded, and I do not regard that as very attractive: such an organization really forces us to treat union numbers used by a program as non-volatile during its complete execution.

Suppose now that in our multiprogramming environment we would like to be able to interrupt a program execution, but in such a way that an interrupted computation can be resumed at a later stage, say a week or a month later. Suppose, furthermore, that during the interruption the installation proper must be able to shed the interrupted computation completely, i.s. all information pertaining to the interrupted computation will be dumped on an external medium —a magnetic tape, say— and the installation proper must be allowed to continue operating fully independently of the fact that there exists an interrupted computation to be resumed at some later moment. Well, that implies that we cannot allow the interrupted program to “reserve” union numbers: upon resumption it has to refer to the library subroutines in a different union nomenclature. In other words, we now have to consider the union nomenclature as volatile and, therefore, have to ask ourselves how its free duplication can be avoided.

We can solve the problem by a proper combination of the machinery considered previously, extended with one status variable (which is really a consequence of the transition from uni- to multiprogramming); I shall call this status variable CPR , short for “Current Program Reference”. In the order of increasing multiplicity, the machinery consists of the following components.

0. | For the installation proper as a whole:
0.0 | a Union Routine Table URT
|      selector: union number
|      entry : address of subroutine’s first instruction

     Remark. Duplication of union numbers occurs, but is restricted: a routine’s union number occurs in one PRT-entry of each program that needs the routine, directly, or indirectly. (End of Remark.)

0.1 | a status variable CPR equal to the starting address of the PRT of the program currently under execution
0.2 | a status variable CRN equal to ordinal number of the currently executed routine, as assigned to it in the program currently under execution.

1. | Per program loaded:
1.0 | a Program Routine Table PRT
|      selector: ordinal number
|      entry : routine’s union number (see Remark under 0.0) starting address of routine’s SCLT in this program.

     Remark. Duplication of ordinal numbers occurs, but is restricted: a routine’s ordinal number in this program occurs in one SCLT-entry for each subroutine selected for this program that refers to it; furthermore ordinal numbers are duplicated in the return information. (End of Remark.)

2. | Per program loaded per subroutine selected for it:
2.0 | a Subroutine Closing Letter Table
|      selector: closing letter
|      entry: ordinal number in this program of the subroutine the closing letter refers to (see Remark under 1.0)

The bit patterns representing the library routine bodies contain their original closing letters. The closing letters provide a terminology local to the binary text, which is translated via an SCLT in the terminology local to the program in which the routine is invoked; via a PRT this terminology local to the current program is translated into the union nomenclature. (Note how the PRT is determined by the current program, and the SCLT by the current program/routine combination.)

It first sight it seems a tortuous way of doing. Consider a library routine A with union number UA , calling a library routine C with union number UC . Let A be called from two programs in which it has the ordinal numbers OA1 and OA2 respectively, and in which the library routine C has the ordinal numbers OC1 and OC2 respectively. The closing letter under which the binary text of A refers to C has always to lead to UC, but the —technical trouble in the typewriter continued in handwriting— path along which depends on the identity of the current program: with OAi selecting in PRTi the SCLT is found that contains the entry OCi; with OCi selecting in PRTi we get UC. The point is that besides UC, which may not be duplicated, we need OCi as well, namely for the return information and for the setting of CRN.

Remark. In the meantime the flexibility mentioned in the note on page EWD718-7 is back again (End of Remark.)

Historical Note. The last organisation described is much more ambitious than I dared to consider while designing the THE multiprogramming system in the mid-sixties. The problem of sublibrary selection was avoided by always storing the complete library, which was not very big, in the installation proper, which, thanks to its drum, had a store that, at the time, was considered large.

Information to be stored was subdivided into so called pages of 512 consecutive numbered words; during its lifetime each page was identified by a unique bit pattern, thus providing a global nomenclature, which was freely duplicated all through the system. As a result the library was very hard to change; even extending it was not simple.

Furthermore it had to be a so called "load-and-go" system: during program compilation one or more page frames in core would be allocated to the programme for the course of its entire execution and the numbers of these frames would be freely duplicated all of the object text! Later we had many occasions to regret our loss of flexibility. (End of historical note.)

Remark. In the last arrangement the duplication of union numbers if so modest that renumbering can be considered. As a result the could remain a closed terminology. (End of remark.)

*              *
*

While carrying out the above analysis I was pleasantly surprised when observing how clear the guidance was that came from the combination of the two design principles —avoid the frequent processing of open nomenclatures and avoid the duplication of volatile information—. The principles themselves are not very surprising, but their combination is surprisingly effective.

A final remarks should be made. What should be regarded as "volatile" or as "non-volatile" greatly depends on the envisaged way of using the installation: remember that union numbers should be regarded as volatile when we want to remove interrupted computations from the instalation proper in such a way that they can be resumed later. But observe the influence on the proposed machinery. This was an influence at quite a detailed level. It gives an indication why machine design is so hard. I think I would be willing defend the last argument, even if it turns out that no one wishes to interrupt computations. Just to be safe!

Plataanstraat 5 | 29th October 1979
5671 AL Nuenen | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-02-24 .

EWD 720

Why correctness must be a mathematical concern.

(Inaugural lecture for the “Chaire Internationale d’Informatique” at the Universit� de Li�ge, Belgium).

Ladies and Gentlemen:

The topic to which this new international chair at Li�ge has been devoted has many names. On the continent of Europe the recently coined name “Informatics” has become generally accepted; in the Anglo-Saxon world the much older term “Computer Science” is most commonly used, though occasionally replaced by the now more appropriate term “Computing Science”. The latter term is more appropriate because it expresses quite clearly that not a piece of equipment, but an activity constitutes the core of its subject matter. By its very nature, this subject matter is highly technical; an inaugural address, however, is specifically the occasion at which technicalities should be avoided, and it is my purpose today to explain to you the significance of the topic without explaining in any detail the topic itself.

You cannot expect me to explain in a few words what mathematics is all about: in order to grasp that, one has to do mathematics for many years oneself. But I would like to show you one simple argument in order to give you in a nutshell some of the flavour of mathematics.

Consider the following silly game to be played by a single person with an urn and as many white balls and black balls as he needs. To begin with, an arbitrary positive number of balls is put into the urn, and as long as the urn contains two or more balls, the player repeats the following move: he shakes the urn and, without looking, he takes two balls from the urn; if those two balls have the same colour he throws one black ball back into the urn, otherwise he returns one white ball into the urn. Because each move decreases the total number of balls in the urn by 1, the game is guaranteed to terminate after a finite number of moves, and it is not difficult to see that the game ends with exactly 1 ball in the urn. The question is: “What can we say about the colour of that final ball when we are given the initial contents of the urn?”.

Well, we can try all possible games! The games that start with 1 ball in the urn are very simple. Because they involve no move at all, we might call them “the empty games”, and could represent them as

and

respectively.

The games of 1 move are not very complicated either: we can represent them by

respectively.

But among the games of 2 moves, life becomes already more complicated. We might represent them as follows (note that there are six possible games):

It is clear that such a tabulation becomes extremely tedious. Besides that, one is never ready with such a tabulation: suppose that we have made the tabulation of games up to 100 moves, then we know nothing to say when faced with an urn that initially contains 300 balls.

Looking at the three single moves possible, we observe that the last two ( and ) leave the number of white balls in the urn unchanged, while the first move () reduces the number of white balls in the urn by 2. In other words, each move leaves the so-called “parity” of the number of white balls in the urn unchanged: an even number of white balls in the urn remains even, and an odd number of white balls in the urn remains odd. In short: if the initial number of white balls is even, the final ball is black, and if the initial number of white balls is odd, the final ball is white. And that answers the question!

Note that this single argument settles the question for all initial contents of the urn, and per initial contents for all of the perhaps many possible games.

The above is a good carrier for some of the flavour of mathematics:
a)     the answer to our question was a very general one in the sense that it is pertinent to an unbounded number of different cases (here: possible games);
b)     the answer to our question was very precise; this in contrast to the soft sciences, such as sociology, in which generality is traditionally achieved by vagueness, i.e. precision’s opposite;
c)     the answer to our question has been justified by a convincing argument, i.e. the type of proof that makes mathematical statements more trustworthy than anything else we utter.

In a very elementary, but fundamental sense the example is also typical for some of the mathematical arguments that are relevant to automatic computing. Replace the initial contents of the urn by “the input”, the rules of the game by “the program”, the game as it evolves by “the computation”, and the colour of the final ball by “the result”, and the above example gives you in a nutshell the bare structure of one of the most effective ways we know of reasoning about programs. (Thanks to the fact that in each move the player draws two arbitrary balls, our example even reflects the characteristics of so-called “non-deterministic algorithms”, in which the computational history need not be uniquely determined by the input that has been supplied explicitly.)

A while ago I mentioned as a leading characteristic of mathematical statements their “generality” in the sense that they are applicable to a very large, often even unbounded number of cases. And it is good thing to realize that almost all computer applications are “general” in that very same sense. In a banking application one does not design a system that can only transfer $100 from the account of a certain Mr.Smith to that of a certain Mr.Brown! On the contrary, the banking system should be able to cope with the transfer of almost any amount from any account to any other account. So much for the generality.

The next characteristic of mathematics that I mentioned was precision. And it is a good thing to realize that almost all computer applications to be worthwhile have to have that characteristic of precision as well. Again the banking application may serve as an illustration. It is not only that all accounts are kept track of accurately to the dollarcent, it is much more: for it to be useful, the system as a whole must have a number of very precise properties. As far as the internal transfers from one account to another are concerned, the system must reflect the Law of Conservation of Money: the sum of the accounts must remain constant because each deduction from one account must be compensated by an equal increase of another account.

The last characteristic I mentioned was trustworthiness. And it is a good thing to realize that almost all computer applications to be worthwhile must be trustworthy. What is the purpose of designing a banking system with the best intentions, when in actual practice it fails to keep correctly track of the flow of money? Not only does it have to do so correctly, but before installing it and switching over to it we must have solid grounds for believing that it will do so correctly. Installing the system without such solid grounds would, in view of the risks involved, be an act of sheer irresponsibility.

Having thus shown that each worthwhile computer application shares with mathematics the latter’s three leading characteristics, I hope to have convinced you that by its very nature responsible system design and development —in short: programming reliably— must be an activity of an undeniably mathematical nature. And having chosen the banking application as illustration, I hope to have convinced you that this conclusion is not confined to the application of computers to science and technology.

Though the conclusion seems unescapable, I should mention for the sake of completeness that not everybody is willing to draw it. You see, mathematics is about thinking, and doing mathematics is always trying to think as well as possible. By an unfortunate accident of history, however, programming became as industrial activity in the United States at a moment that the American manager was extremely fearful of relying on the education and the intelligence of his company’s employees. And management tried to organize the industrial programming task in such a way that each individual programmer would need to think as little as possible. This has been a sad mistake, but the more management, with the conception of programming, failed to meet its deadlines and to achieve reasonable quality standards, the more has been invested in these ill-directed efforts. And now we have reached the paradoxical situation that, while the evidence for the intrinsic difficulty of the programming task has become more and more convincing each year, the recognition of the difficulty has become, both politically and socially, more and more unpalatable. It should be noted that under these circumstances foresight and courage, if not also the tenacity of a bull-terrier, are required for the foundation of an international chair of informatics at which programs and programming are considered to be worthy of our serious scientific attention.

Let me next indicate, in the broadest outline possible, what this serious scientific attention could cover. I shall keep this outline broad for two reasons: firstly this is not the occasion to bore you with technicalities, secondly I hope to give an explanation with which the subsequent occupants of this chair won’t disagree too much.

It is now the time to confess that my example of the game with the urn filled with a finite number of balls, each of which is white or black, though in one respect absolutely typical, is very misleading in another respect: compared to the actual situation in programming it is such a gross oversimplification, that the use of this example in an expository lecture is almost an intellectual dishonesty.

So that you may understand how terribly gross the oversimplification really is, I would like you to realize that something as trivial as “a factor of ten” —something we usually treat as a gradual difference from which we can abstract— makes in practice an almost essential difference. Once I was called to explain to a housewife what tremendous difference a mere factor of ten makes. I asked her, how many children she had, knowing that she had six. The lady saw the point. Compared to the programming problem, the urn example is an oversimplification that is orders of magnitude worse than merely ignoring a factor of ten.

In the urn example, the initial state is fully characterized by two integers, viz. the number of white balls and the number of black balls respectively. That specification of the input is ridiculously simple compared to, for instance, the class of possible inputs a compiler must be able to process, viz. all texts that are legal or illegal program texts in the programming language concerned.

In the urn example the final state, i.e. the colour of the final ball, represents only a single bit of information. That, again, is ridiculously simple compared to the output required from standard programs such as compilers, for which the representation of the result often requires millions of bits.

And finally, in the urn example I could state “the rules of the game” in one or two sentences, whereas in the practice of automatic computing the program —i.e. “the rules of the computational game”— often requires many thousands, and sometimes apparently even millions of lines of text.

In the urn example, a single argument based on the rules sufficed for all possible games. In computing, a single argument based on the program text would analogously suffice for all computations that are possible under control of that program. The necessary economy of thought requires as its ultimate consequence that we learn how to reason about programs without mentioning the corresponding computational processes at all. This means no more and no less than that we must learn how to come to grips with the program text as a mathematical object in its own right. We must be able to deal with it directly, rather than via the detour of the class of all corresponding computations.

It is abundantly clear that significant progress in programming, in reasoning about programs, and in the design of programming languages will only materialize, provided we learn how to do this, while temporarily fully ignoring that our program texts also admit the interpretation of executable code, because it is precisely that interpretation that clutters up our minds with all the computational processes, which truly baffle the imagination. In short: for the effective understanding of programs we must learn to abstract from the existence of computers.

This abstraction is not easy. For most people trained as electronic engineers it is even impossible —though not for all: it is a pleasure to mention Niklaus Wirth from Zurich as an exception— . This is not surprising, for suddenly they find themselves invited to abstract from what they have been taught to regard as the core of their craft. As you might expect, vested interests inhibit a widespread recognition of the obvious conclusion, viz. that as a rule departments of electronic engineering actually deprive their graduates from the ability to understand later in life what computing science is really about.

In the ears of the traditional mathematician the suggestion to abstract from the existence of computers sounds much more natural. He should feel quite at home with the idea of regarding, reading, writing, and manipulating program texts just like any other mathematical formulae. But there is one big, big difference: never in his life has he encountered such big formulae! Remember the drastic difference already made by a single factor of ten, and realize that program texts present themselves to the traditional mathematician as formulae that are not one, but several orders of magnitude bigger than the formulae he used to deal with! In relation to our mathematical tradition, it is just a drastic problem of scale, so drastic, as a matter of fact, that quite a few mathematicians, firmly rooted in the past, are quite unable to recognize programming as a mathematical activity. Research and education in computing sciences are, however, more concerned with the mathematicians of the future.

By now you may have some feeling for the type of topics that would be fully appropriate for this international chair of informatics.

The most general topic, and also the one of the widest significance, could be called “the scaling up of mathematics”. Such scaling up would imply a different style of mathematical texts in general, and the use of more appropriate notations in particular. By and large, current mathematical style has been determined by fashion, and current mathematical notation by accident.

The degree in which separable concerns are, indeed, separated is, for instance, an aspect of mathematical style, but as far as I know students of mathematics are not taught today to take in this respect a conscious decision.

Similarly, the adequacy of chosen notational conventions can be judged by their suitability to our manipulative needs. Again, as far as I know, students of mathematics are not taught today to screen notational conventions for their suitability before they adopt them.

As a result the style of today’s mathematical text is unnecessarily confusing and its notation in unnecessarily clumsy. This is obvious: people tend to commit all the sins they think they can afford to commit. Prior to a commitment to “scaling up” they can hardly be called “sins”, but computing’s demands on mathematics are sure to cause a “moral” shift between good and bad mathematics. Already now one of the common reactions of the well-trained computing scientist to the average mathematical paper is: “Oh gosh, what a lousy programmer the guy who wrote this must be!” Already now we could start purging the practice of mathematics from the usual little sins of which the computing scientists know that, at the next level, they will become capital ones. The scaling up of mathematics in general is, of course, a very ambitious topic.

A more modest topic, closer to the field of automatic computing, would be the following. In the case of a soluble problem, what is essentially the same solution can be realized by very different programs. This observation is well-known, but raises all sorts of questions.

A pretty obvious question would be “Which of the possible programs would be the easiest to understand?”, but the question is not as innocent as it seems, for what do we mean by “ease of understanding”? Programs are expressed in (what I may here denote by) linguistic structures, and different linguistic structures require different patterns of reasoning for the justification of their usage. Intuitively people tend to prefer the ones they are most familiar with, but we shouldn’t confuse “convenient” with “conventional”, and should remember that what we call thinking and understanding are not much more than our personal habits, habits that we can replace by others by training ourselves. Some linguistic structures are known to cause troubles in a sense as objective as the statement that decimal arithmetic is “easier” in Arabic than in Roman numerals, but the area as a whole is still a field for investigation and experiment.

Another question in connection with different possible programs, realizing the same solution is the following: “Does a single program suit all our purposes?”. The solution might have different relevant aspects, each of which is most manageably reflected in a different program. Who knows? Note that the absence of an example of such a solution does not settle the question: we tend to think about solutions in terms of a program that realizes it, and the mere conception of a solution that requires two or more alternative programs for the adequate reflection of its different aspects might therefore be well beyond our current intellectual abilities! I only raised the last question as an example, in the hope that it may give you some idea of the possible scope of our concerns.

While programming we don’t only consider different programs embodying the same solution to a given problem, usually we have to invent the solution as well. Human inventiveness being what it is, we usually invent more than one solution, with the result that we have to choose. When different solutions to the same problem can be shown to be correct by proofs that share part of the argument, is it possible to realize those solutions by programs that share parts of the text? Those parts of the text could then already be written without completely committing oneself to the solution to be finally adopted; the larger the program, the more important the possibility to postpone such commitments. Equally important is the possibility of postponing the precise choice of the problem to be solved: you really cannot expect your customer —regardless of whether you are your own customer or your customer is someone else— to have fully made up his mind and stick to it.

In the previous paragraph I have sketched in a very informal fashion some of the flexibility requirements. What the manager sees as “keeping options open” is seen by the scientist as “sharing”: different programs sharing code, different proofs sharing arguments, different theories sharing subtheories, and different problems sharing aspects. The need for such “sharing” is characteristic for the design of anything big. The control of such “sharing” is at the heart of the problem of “scaling up” and it is the challenge to the computing scientist or mathematician to invent the abstractions that will enable us to exert this control with sufficient precision.

After having seen how much the catch phrase “the scaling up of mathematics” captures of the challenge posed to us by the existence of modern computers, we are quite naturally led to the question to what extent those very machines —the fast symbol manipulators they are— could assist us in meeting that challenge. Like all the questions raised in the second part of this talk, also this question will remain unanswered here. I will confine myself to pointing out that the question has two sides.

Firstly we have questions such as “What mechanizable assistance can we think of besides the well-known program transformation and theorem proving systems, and how useful can we expect them to be?”, but also, once such a mechanization has been designed “How depends the economics of its usage on the size of the application?”. Because I did not define “size”, the latter question is vague, but remember we were interested in “scaling up”! Hence, costs growing quadratically (or worse) as a function of something we would like to increase by several orders of magnitude, would disqualify the tool for the very purpose we had in mind.

Secondly, the answer to what extent computers can assist us in meeting the challenge of “scaling up mathematics” also depends on our interpretation of that challenge. For some mathematicians doing mathematics is a mental activity whose primary purpose is understanding. Such a mathematician is inclined to reject an alleged theorem for which the only available alleged proof is millions of steps long, i.e. orders of magnitude too long to be read and, as he calls it, “understood”.

The question “What is Mathematics?” is as unavoidable and as unanswerable as the question “What is Life?”. In actual fact I think it’s almost the same question.

I thank you for your attention.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 18 November 1979 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD721

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

The design of a state space with a useful structure.(I)

We now turn to the discussion of another problem that is already old; it has been solved in one way or another in each implementation of ALGOL 60. In retrospect it is surprising that the problem has been so hard to solve and that with very rare exceptions —Burroughs Corporation is the exception that comes to mind immediately!— computer manufacturers have been very slow in recognizing the problem and in designing hardware suitable for its solution.

In EWD719 I introduced the transition from uni- to multiprogramming with the requirement that different programs using the same library subroutine could share the same bit pattern representing the subroutine body in store. This, of course, creates problems when information varying from call to call —such as the return information, to mention a very simple example— is allocated within the bit pattern representing the subroutine body. This allocation was very much ingrained in people’s minds, so much so that it found its way into the hardware —I remember a Siemens computer in which a subroutine jump with address n would store the return jump in location with address n and would substitute n+1 into the instruction counter!— and for a while it was thought that, therefore, invocations of a shared subroutine would have to exclude each other mutually in time —a synchronization for which aforementioned Siemens machine lacked the necessary facilities— . But the mutual exclusion was identified as a red herring as soon as recursion entered the picture: nested invocations are by their very nature not mutually exclusive.

In the case of subroutines the same piece of code can be invoked by different calls in the program. This implies that for each subroutine we can identify what we might call “its primary allocation commitment”, i.e. that fixed part of the machine the state of which depends on the call and, therefore, in general will vary from call to call. In different machines different conventions for the primary allocation commitment have been chosen.

In the EDSAC organization we find a mixture of all conceivable conventions:
1)     part of the primary allocation commitment consisted of storage locations allocated within the subroutine’s bit pattern (such as the return jump and other variable instructions)
2)     part of the primary allocation commitment consisted of the accumulator of the arithmetic unit (in which at call the return information was transmitted)
3)     a few fixed storage locations (such as location 0 ) were used by many subroutines for parameter passing
4)     for some subroutines part of the primary allocation consisted of an area of store to be chosen by the programmer and to be fixed with a preset parameter (the difference between the last two being that the first commitment was common to many subroutines, whereas the last one was usually specific to a single one).

In a machine like the IBM/360 with 16 general purpose registers in its arithmetic unit the convention of using a few fixed storage locations was usually not introduced.

In the EL-X1 the order code comprised 16 different subroutine jumps, each of them placing the return information in one of 16 consecutive storage locations (from 8 through 23); each subroutine had to be called by its proper subroutine jump and the corresponding location belonged therefore to its primary allocation commitment.

The first convention —a primary commitment to store allocated within the code— was forced upon the users of the first von Neumann machines for lack of B-lines (= index registers). It became a standard to such an extent that subroutines in which it was not adhered to were for at least a decade honoured with a special name: they had “re-entrant code”. Today it should not be a special feature anymore: subroutines stored in ROM (Read Only Store) are necessarily “re-entrant”.

Confining ourselves to re-entrant code we still have have a choice: do we try to give different subroutines in principle the same or in principle different primary allocation commitments? In the EL-X1 —and that is the reason why I mentioned it— a mixed strategy was adopted. Subroutines were arranged in a hierarchy: all subroutines that called no others were placed on level 0 , a subroutine calling others was placed on level n+1 when n was the maximum level of the subroutines it called. Subroutines on level n used location 8+n for their return link. At the time we thought this a bright idea, but it was, of course, a mistake. The trouble is that the locations from 8 to 8+n now form part of what we might call the primary allocation commitment of the program as a whole, and if the machine were to be used for multiprogramming a switch from one program to another would imply saving and restoring the contents of those locations.

In the IBM/360 and its copies it is usual to give each subroutine a heavy primary allocation commitment among the general purpose registers of the arithmetic unit: for reasons of homogeneity usually all of them. For reasons of speed the registers are the coder’s most beloved locations for storing frequently accessed information and the machine has indeed been designed under the assumption that the coder would use it that way. That was a mistake too, for the necessary saving and restoring of register contents now imposes a heavy overhead on the mechanism of subroutine call and return, so heavy as a matter of fact that for such machines so-called “macro expansion” —i.e. replacing the call by (an adapted version of) the whole subroutine body!— has become a usual implementation technique. (And where the technique was not applied, as in some implementations of PL/I , the poor programmer got the advice to avoid using procedures!)

The most homogeneous solution gives all subroutines the same primary allocation commitment, but keeps this commitment as small as possible in order to reduce the overhead of call and return as much as possible.

Note. The time taken for the execution of a program or program part can be “described” —the quotes because the terms used will not be defined precisely— by ii + w/v , where ii stands for “initial investment” and v for the speed with which the useful work w is done. In the case of a whole program, ii might stand for the time taken by the compilation and w/v for the time taken by the execution of the compiled program. In the case of a subroutine, ii might stand for the overhead of call and return and w/v for the time taken for the execution of the subroutine proper. It is always tempting to increase ii if by doing so v can be increased considerably: it is the temptation to which is yielded by the introduction of optimizing compilers, for instance, which themselves can be very time-consuming indeed. It should be noted that yielding to the temptation can be very dangerous, viz. in all those cases in which it cannot be guaranteed that w will indeed be big enough to get a proper return for the investment: the cost/performance ratio (ii + w/V)/w viewed as function of w is unbounded when ii ≠ 0 1 Installations spending most of their time compiling, loading, linking etc. have indeed been quite common. Because in most procedures w , i.e. the amount of useful work to be done, depends on the values of the parameters supplied at the call, a small value of ii is most desirable; otherwise one can get most unpleasant surprises when for a large number of calls w turns out to be small. (End of Note.)

The scene changed in the late fifties, when the following observation was made. Consider in the execution of a sequential program the time sequence of calls and returns; it satisfies the well-known grammar

| < sequence > ::= { < calli > < sequence > < returni > }

i.e. it is a nicely nested sequence with the call of A and the corresponding return from A as a matching bracket pair. To any moment in time corresponds a place in this sequence and we only need to store the return information corresponding to the bracket pairs that surround this place: they correspond to the calls of which the corresponding returns have not taken place yet. So let us introduce a non-volatile nomenclature for the members of this floating population of the bracket pairs that surround the current place in the sequence. The only orderly way we know of is assigning the first free number whenever the current place passes a call in the sequence, i.e. when a new member is added to the population of surrounding bracket pairs. Thanks to the fact that the sequence is nicely nested this strategy gives rise to a closed nomenclature! Each bracket pair becomes identified with a an ordinal number equal to the number of bracket pairs surrounding it.

This discovery is, of course, too beautiful not to be exploited. We introduce for such ordinal numbers the term “invocation numbers”; note that the invocation numbers provide a terminology that is local to the execution of a sequential program. With the execution of a sequential program we associate a Current Invocation Number, “CIN” for short. When the program execution is started, the CIN is initialized at zero, at every call the increase CIN:= CIN + 1 takes place, while CIN:= CIN - 1 accompanies every return. In a table with the invocation number as selector the return information can be stored in the entries under control of CIN ; upon return the return information can be retrieved again under control of CIN. At any time the value of CIN gives the length of the table, which is used as a so-called “stack”, in which the entries reside on a so-called LIFO (Last-In-First-Out) basis. In other literature the CIN is also referred to as “the current depth of calling”.

A machine built in the early sixties (the English Electric KDF9) had this built in, but alas under the assumption that a maximum value of 16 for CIN would suffice, an assumption that is hard to defend in the case of recursion. At the time of the design of the KDF9, recursive routines were not regarded as a reasonable programming tool; ’the problem is of course that the subsequent existence of machines on which the implementation of recursive routines presents serious problems prolongs the lifetime of such a prejudice.

Recursion drove another message home. Each routine needs in general some “working space” to allocate its local variables in. In uni-programming and without recursion one can establish a one-to-one correspondence between a routine and its local workspace. A naive implementation would then play it safely, allocating store in such a way that the local workspaces of any two different routines would be disjoint. But such a naive allocation does not exploit the fact that the local workspace of a routine is only needed between its call and the subsequent return from it: during its “activation”, as it was called. Hence so-called sophisticated implementations would perform an an extensive flow analysis of the program, trying to establish for any pair of routines whether their activations would always be disjoint in time. And then one can try to allocate working spaces, allowing as much overlap as possible, but only between the working spaces of those routines for which it had been established that their activations would never overlap. This allocation problem is as bad as any graph colouring problem. In retrospect it is amazing that people have tried such solutions and even prided themselves on having done it. The problem should never have been solved! It was purely generated by regarding the routine, instead of the invocation,as the unit of thought. That in this connection the invocation was the proper thing to consider was the message that was driven home by recursion, where the same routine may enjoy any number of simultaneous activations (but then each corresponding to a different invocation).

With invocation numbers we have introduced a really new element: a nomenclature that grows and shrinks as the computation evolves. As such its introduction really implies a significant shift of the interface between the program text and its interpreter. The following may clarify the role of the invocation numbers. Consider for simplicity’s sake a program in which no procedure is handed over as a parameter. In that case we can easily define for that program a directed “activation tree” as follows:
     the main program is the root of the activation tree, and each node of the activation tree has an outgoing edge for every routine it may call, with (an activation of) the routine called as its target node.

A nomenclature that distinguishes between all the nodes of this tree would provide a constant nomenclature that at any moment in time would distinguish between all “live” activations. Without recursion the tree is finite,

e.g.
| -> A -> B
M <
| -> B

but we do already have the possibility that the same routine —for instance, B in the above example— occurs at several nodes of the activation tree, i.e. the correspondence between routine and node is in general a one-to-many one. In the case of recursion the activation tree is infinite, and at least one routine occurs at an infinite number of nodes.

At any moment in time the current activation corresponds to one of the nodes of the activation tree. Its invocation number is its distance from the root. And we now exploit the fact that the local work spaces corresponding to the nodes on the unique path from the root to the current activation are the only ones that matter, and that in that subset, i.e. along that path, distance from the root (= invocation number) identifies the node (= activation) uniquely. The only special consequence of recursion is that along a path from the root the same routine may occur infinitely often instead of at most once.

I assume the local variables of a routine within its local work space identified by (small) integers, historically called “the displacements”. (Think, to simplify matters, for the time being about a local work space only comprising a fixed number of variables, each requiring one word of storage; “fixed” means here: characteristic for the routine and independent of its activation.) To all intents and purposes we can treat the displacements in terms of which the routine body refers to its local variables as a closed nomenclature; the displacement acts as a selector from the local work space.

Within the program each stored variable is then during its lifetime fully identified by an ordered pair (invocation number, displacement). For the program as a whole we introduce a

| Program Invocation Table, PIT for short
|  | selector: invocation number
|  | entry : return information,
|  |  | starting address of local work space corresponding
|  |  | to this invocation.

Via the Program Invocation Table PIT we can derive from the ordered pair (invocation number, displacement) the address of the location in which the value of the variable in question is currently stored.

| (To be continued)
Plataanstraat 5 | 21th November 1979
5671 AL Nuenen | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-02-25 .

  EWD 722

A book review for the IBM Systems Journal.

     Structured Programming, Theory and Practice, R.C.Linger, H.D.Mills, and B.I.Witt, Addison-Wesley Publishing Company, Inc., Reading, MA, 1979. 402pp. (ISDN 0–201–14461 ABCDEFGHIJ-HA-79, $18.95)

      Although published by Addison-Wesley, this book should be regarded as an IBM product, rather than a general textbook or a scientific monograph. According to its title page, all its authors are from IBM Corporation, and it appeared in "The Systems Programming Series", which is not only sponsored by IBM but, according to page IV of the book, has an "IBM Editorial Board". (Its members have been listed in alphabetical order, with the exception of Mr. Gruener from Addison-Wesley, who is mentioned last!) Addison-Wesley did a very neat job of binding and printing, with the exception of eight pages at the end of section 7.5 which are (reduced) facsimile of (poor) lineprinter output.

      The book has been divided into seven chapters with the following titles: 1. Precision Programming, 2. Elements of Logical Expression, 3. Elements of Program Expression, 4. Structured Programs, 5. Reading Structured Programs, 6. The Correctness of Structured Programs, and 7. Writing Structured Programs. I found the majority of them quite illuminating and/or instructive.

      Chapter 1 (14 pp.) sets the scene quite nicely and contains many remarks that deserve to be quoted, such as:

There is a simple reason why you should commit yourself to writing programs that are free from errors from the very start. It is that you will never be able to establish that the program has no errors in it by testing. Since there is no way to be certain that you have found the last error, your real opportunity to gain confidence in a program is to never introduce the first error. [Actually, the quotation ends with "to never find the first error", but that seemed one of the very rare misprints I detected.]

      The authors' healthy attitude regarding the proper role of mathematical proofs is shown by:

 A mathematical proof is an agenda for a repeatable experiment, just as in a physics or chemical laboratory. But the main subject in each experiment is another person instead of physical objects or material. The intended result of the experimenter is a subjective conviction on the part of the other person that a given logical hypothesis leads to a given logical conclusion. [...] As noted, any human fallibility may be present because reasoning is a human activity; that is, an agreement that a proof is correct and the actual correctness of the proof are two quite independent things.

      Chapter 2 (30 pp.) —ending with a one-page bibliography of "Related Reading"— introduces the necessary concepts and notations from mathematics in general, while Chapter 3 (46 pp.) does the same for programs in particular.

      Chapter 4 (56 pp.) pays to control flow an amount of attention which I thought a bit too much until I read Chapter 5 (66 pp.: you see, the chapters are getting longer and longer!), which ends with a 25-page "Case Study in Program Reading", one of the highlights of the book! The authors have undertaken the horrendous task of unravelling a contorted PL/I program —taken from the open literature!—, introducing this job with the very true words: "as it stands, it is a formidable object for human understanding!". This case study is impressive in more than one way: not only does it drive home the message how terribly (and needlessly) contorted programs can be, but it also illustrates the power of the methods derived in the preceding chapter.

      Chapter 6 (84 pp.: yes, again longer!) appealed less to me. As the authors remark themselves (p.237): "Even though the above derivation is a little tedious, [...]". Being used to what I am used to, I found the qualification "a little tedious" applicable to most of that chapter, as only a modest amount of mathematical sophistication could have shortened many an argument. Under the assumption that I was not representative of their target audience I decided not to blame the authors.

      Chapter 7 (94 pp.) is largely devoted to the systematic development of three programs, and the authors should be recommended on their choice of problems, as the three are very different from each other.

      One detailed comment on line 6 of the program on page 176, where, in the functional description of the succeeding program fragment, they have written

(∃k (key = table(k), lo ≤ k ≤ hi) → i :=k [...]) .

The truth of the boolean expression to the left of the arrow does, however, not define the value of k that is used at the right-hand side of the arrow: at the left-hand side k is a bound variable.

      One general comment. The authors have clearly tried to reach as large an audience as possible, a goal that evidently implied for them that they could permit themselves only a modest departure from the PL/I subculture. In a more radical attitude a shorter (and simpler) book could have reached their target audience. In short: for an IBM product, the book is excellent.

| Edsger W.Dijkstra The Netherlands

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

EWD723

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On W.H.J. Feijen's solution for the lexicographic minimum of a circular list.

For a given, non-empty —i.e. with N ≥ 1— list (C[0], C[1], ..., C[N-1]) we consider the N associated sequences Ci

| Ci = (C[i], C[i+1], ..., C[i+N-1])

in which all subscripts are reduced modulo N. We are asked to design a program determining an integer value k satisfying the relation

R: | 0 ≤ k < N and (∀i: 0 ≤ i < N: Ci GE Ck) ,

in which "GE" should be read as "lexicographically greater or equal than".

*              *
*

The lexicographic minimum CC is defined by the following two relations.

| (∀i: 0 ≤ i < N: Ci GE CC) | (0)
| (∃i: 0 ≤ i < N: Ci EQ CC) | (1)

From the transitivity of the lexicographic ordering we conclude

| (∀p, q:: Cp GE Cq or Cq GT CC) | (3)

Note. When, in a quantification, the range is obvious, we allow ourselves its omission. Hence the "::". (End of note)

*              *
*

Let P(k,n) be defined as:

P: | 0 ≤ k < n and (∀i; 0 ≤ i < n: Ci GT CC or i = k) | (4)

We observe immediately

| (P and n ≥ N) ⇒ R | (5)
| (∀i: 0 ≤ i < h: Ci GT CC) ⇒ P(h, h+1) | (6)

*              *
*

Let Q(k, n, l) be defined as

Q: | 0 ≤ k < n ∧ (∀i: 0 ≤ i < l: C[k+i] = C[n+i]) | (7)

Because the lexicographic order of the two sequences with equal leading elements does not change when those leading elements are removed from them, we conclude

| Q(k,n,l) ⇒ (Qa or Qb or Qc) | (8)

with the mutually exclusive terms

Qa: | (∀i: 0 ≤ i < N: Ck+i = Cn+i | (8a)
Qb: | (∀i: 0 ≤ i < l: Ck+i LT Cn+i ∧ l ≥ 0 | (8b)
Qc: | (∀i: 0 ≤ i < N: Ck+i GT Cn+i ∧ l ≥ 0 | (8c)

We furthermore observe that, for l=0, the last term of Q(k, n, l) is vacuously true.

*              *
*

We observe that P&ans;Q can be initialized by

| k, n, l:= 0, 1, 0

and is left invariant by the following three guarded commands.

1) | C[k + l] = C[n + l] → l:= l + 1

This follows immediatly from (4) —l does not occur in P— and (7)

2) | C[k + l] < C[n + l] → {P∧Qb} n, l:= n + l + 1, 0

Q and the guard imply together Qb, and note that Qb implies

| (∀i: n ≤ i < n+l+1: CI GT CC)

Hence, on account of (4) the invariance of P is guaranteed. The assignment l:= 0 ensures the invariance of Q

3) | C[k + l] > C[n + l] → {P∧Qc} n, l:= n + l + 1, 0

| h:= max(n, k+l+1);
| k, n, l:= h, h+1, 0

Q and the guard imply together Qc, and note that Qc implies

| (∀i: k ≤ i < n+l+1: Ci GT CC) ∧ l ≥ 0 .

With h = max(n, k+l+1) we conclude from the last result and P

| (∀i: 0 ≤ i < h: Ci GT CC)

and, thanks to (6), the invariance of P is guaranteed. The assignment l:= 0 ensures the invariance of Q .

*              *
*

Finally we show that

| (P ∧ Q ∧ k + l + 1 ≥ N) ⇒ R | (9)

1) | P ∧ Qa ∧ k + l + 1 ≥ N

From Qa we conclude that the sequence is periodic, and that the period divides n - k; hence

| (∃i: k ≤ i < n: Ci EQ CC)

Together with —what follows from P—

| (∀i: k < i < n: Ci GT CC)

we conclude Ck EQ CC, i.e. R .

2) | P ∧ Qb ∧ k+l+1 ≥ N

From Qb we conclude, as before,

| (∀i: n ≤ i < n+l+1: Ci GT CC);

because n > k, n+l+1 > k+l+1; because k+l+1 ≥ N we conclude, together with P

| (∀i: 0 ≤ i < N: Ci GT CC or i = k), i.e. R

3) | P ∧ Qc ∧ k+l+1 ≥ N

From Qc we conclude, as before,

| (∀i: k ≤ i < k+l+1: Ci GT CC);

because k+l+1 ≥ N, we conclude, together with P

| (∀i: 0 ≤ i < N: Ci GT CC);

this together with (1) implies false, and false ⇒ R.

(End of Proof of (9).)

Using (5) and (9), we see that the following program establishes R

| k, n, l:= 0, 1, 0
| do n < N and k + l + 1 < N →
|  | if C[k + l] = C[n + l] → l:= l + 1 {P ∧ Q}
|  |  | ▯ C[k + l] < C[n + l] → n, l:= n + l + 1, 0 {P ∧ Q}
|  |  | ▯ C[k + l] > C[n + l] → h:= max(n, k + l + 1);
|  |  |  | k, n, l:= h, h + 1, 0 {P ∧ Q}
|  | fi {P ∧ Q}
| od {R}

Termination. The function t = k + n + l increases by at least one at each iteration. Before the first iteration t = 1, before the last one t ≤ 2N - 3, hence 2N - 3 is an upper bound for the number of comparisons.

*              *
*

The above is —or will be— described much more beautifully by W.H.J. Feyen, including all the heuristics and acknowledgements. I wrote the above as part of my personal correspondence, for the sake of quick dissemination: I owe everything of the above to ir. W.H.J. Feijen.

29th December 1979 |
Plataanstraat 5 |
5671 AL Nuenen | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-04-11 .

  EWD 724

Een gotspe

In de stormachtige ontwikkeling van de informatica is het concept van de zg. "von Neumann machine" uitzonderlijk stabiel gebleken. In wezen bouwen en gebruiken we nog steeds dezelfde computers als 30 jaar geleden; door de zich ontwikkelende technologie is slechts hun capaciteit geleidelijk aan drastisch opgevoerd. Deze uitzonderlijke stabiliteit is meer dan alleen maar het gevolg van het feit, dat het concept van de von Neumann machine zo gek nog niet was; de von Neumann machine functioneerde tevens als de interface tussen hardware ontwerpers en de software ontwerpers die beiden de stabiliteit daarvan nodig hadden om hun eigen gebied te kunnen ontwikkelen. Doordat evenwel de von Neumann machine voor de hardware ontwerper het eindproduct maar voor de software ontwerper het startpunt was, heeft de constantheid van deze interface beide disciplines heel verschillend beinvloed.

Hand in hand met de toenemende capaciteit stegen de ambities. Elk volgend software project was een orde van grootte ambitieuzer en ingewikkelder dan het vorige, en de software ontwerpers hebben hun handen volgehad aan de ontwikkeling van de intellectuele discipline —dwz. het conceptuele apparaat, en de ontwerpmethodologie— die door de exploderende ambities vereist werd. Wat in deze bereikt is, is spectaculair maar betrekkelijk onbekend. (De onbekendheid bij het grote publiek is niet zo verwonderlijk. Ten eerste hebben we hier te maken met een vorm en een mate van complexiteit, waarvan buitenstaanders zich geen flauwe voorstelling kunnen maken; ze kunnen daardoor slecht waarderen wat er bereikt is. Ten tweede was methodologie niet altijd op tijd ver genoeg ontwikkeld, en pogingen van programmeurs om verder te springen dan hun polsstok op dat moment lang was hebben software een slechte naam bezorgd. Volledigheidshalve teken ik hier bij aan, dat programmeurs vaak de schuld hebben gekregen van fouten, die door hun managers waren gemaakt.)

Alle conceptuele problemen die door deze exploderende complexiteit zijn veroorzaakt, zijn de hardware ontwerpers bespaard gebleven, en dat was maar goed ook, want de hardware ontwerpers hebben hun handen er mee dan vol aan gehad om hun ontwerp steeds maar aan te passen aan de veranderende techonologieen, zich wijzigende economische parameters en zich verschuivende technische beperkingen. Ik zeg met opzet dat ze hun handen daarmee "meer dan vol" hebben gehad: ze hebben nauwelijks tijd gehad om hun methodologie te verfijnen. Wie als competent informaticus hardware designers —zelfs beroemde!— over hun werk hoort praten, gelooft weer in de Tijdmachine: hij waant zich &eacute;&eacute;n of twee decaden in het verleden. Het verschijnsel van de "glitch" kennen ze nog niet, over "hazards" praten ze nog net zo onbeholpen als vijftien jaar geleden, en ze ontwerpen nog steeds naief als een ambachtsman. Nog indrukwekkender dan hun technologische successen is hun methodologische stagnatie. Bij zo'n confrontatie slaat de informaticus de schrik om het hart, als hij zich probeert voor te stellen wat er gaat gebeuren, als dit soort mensen chips gaat ontwerpen, want je ziet al jaren onafwendbaar aankomen, dat ze getrouw alle vergissingen op hun silicon zullen bakken, waarvan de informaticus al meer dan tien jaar geleden heeft geleerd, hoe je ze vermijden moet. (En gezien de exorbitant hoge prijs van chip-ontwerp is dit precies wat onder de hand al gebeurt.)

En wat lezen wij in het "Verslag van de Adviesgroep Maatschappelijke Gevolgen van de Micro-electronica" (de "commissie Rathenau") om sectie 2.5?

"De softwareproblematiek lijkt overigens op die van het ontwerpen van IC's [zoals de Indo-Germaanse talen lijkten op het Nederlands! EWD]. Beide technieken moeten de aansluiting tot stand brengen tussen gestandaardiseerde componenten en de werkelijkheid. Wat verschilt is het standaardisatie-niveau; wat ook verschilt, is de wetenschappelijke omgeving, waarin de werkzaamheden passen. Een wetenschappelijke basis voor een software-technologie is nog nauwelijks gelegd; werkmethoden, en professionele gedisciplineerdheid zijn lang niet zo ver ontwikkeld als in de electronica."

Dat is, wat ik een gotspe noem! Het staat er heus zo. De afwezigheid van competente informatici in de commissie Rathenau heeft zich hier wel heel erg gewroken, en je vraagt je af wat de rest van het rapport voorstelt, wanneer wij kennelijk met Brecht moeten constateren: "und sie wussten nicht, wovon sie redeten".

Plataanstraat 5, NUENEN | prof.dr.Edsger W.Dijkstra

transcribed by Ionica Smeets
revised Fri, 12 Jan 2007

  EWD 724E

A chutspa

The concept known as the von Neumann machine has proved to be exceptionally stable in the otherwise tempestuous development of Computing Science. In essence, the computers we build are still those that were with us thirty years ago; technology, as it has developed, has merely led to a dramatic increase in capacity, however gradual the steps it has been reached in. This exceptional stability goes well beyond merely confirming that the von Neumann concept was not, after all, such a bad idea: its very stability provided a stable interface between designers of hardware and software, and, for both groups, the stable interface was an essential prerequisite to progress in their own fields. Now, to a hardware designer, a von Neumann machine is the final product; to a software designer, it is no more than a point of departure; hence, it need cause no surprise that the stability of the interface has exerted rather diverse influences on these several disciplines.

In software, ambitions were raised as increased capacity became available. Each succeeding project outdid its predecessors by an order of magnitude in aspiration and complexity. Software designers have been challenged to develop the mental apparatus —that is, the conceptual machinery and the resultant methods of design— imposed by ambition's uncurbed growth. The achievements in this field, provoked as they may have been by the challenge, while quite spectacular, are still relatively unknown. (That they should be unknown to the public at large is hardly surprising. Firstly, the subject is of an inherent complexity unfathomable to the uninitiated; taken by itself, this fact would be sufficient to prevent the public from appreciating the true magnitude of the undoubted achievement. Moreover, it is admitted that method has sometimes lagged behind: each programmer whose reach occasionally exceeded his grasp has added to the evil repute of software. In fairness, let us also note that programmers have often been blamed for errors of judgement perpetrated by their managers.)

Hardware designers have been spared the conceptual problems posed by this proliferation of complexity —and a good thing too. As it was, hardware designers have been hard put to it to adapt their designs —and re-adapt them and re-adapt them again and again— to changing technologies, to economic parameters in a constant state of flux and to ever-changing material constraints. I use "hard put to it" advisedly: the difficulties they were in hardly left them time to put some gloss on their methods of design. When in the audience of hardware designers discussing their work one can scarcely escape the suspicion that Wells's Time Machine exists and is operating: any moderately competent computing scientist feels violently wrenched back by at least a decade into the past, possibly two. To hear them —and this goes even for the famous— glitches are still unknown, or at least unrecognized; hazards are still being prattled about with the very uncomprehension that surrounded them fifteen years ago; the tribe's design methods still suffer from the craftsman's näiveté. It is hard to decide whether a computing scientist should be impressed by their technical achievements or appalled by their methodological backwardness. When confronted with these gentlemen, a computing scientist may perhaps be forgiven for feeling gripped by an elemental fear of what is bound to happen when the tribe will start designing chips in earnest: it has been ineluctable for years now that they will solidify in silicon each and every type of design misjudgment which the community of computing scientists has learned to avoid for at least the past decade. Incidentally, in view of the exorbitant level of chip design costs, this is precisely what is happening now.....

Let me now show what we are given to read in the Dutch "Report on the Social Consequences of Micro-Electronics" by an ad hoc advisory committee, also known, after its chairman, as the Rathenau Committee [their report, section 2.5]. To quote verbatim:

Software problems, we mention in passing, are similar to those met in designing ICs [as the Indo-European languages are similar to English —EWD]. Either technique must bridge the gap between standard components and reality. Yet there is a difference in the degree of standardization; moreover, there is a difference in the scientific background fitting the respective activities. A scientific basis for software technology has hardly been established yet; methods of operation lag far behind those developed in electronics; so does professional discipline.

Gentle reader, be not incredulous: this piece of pure and unadulterated chutspa has been quoted as literally as translation will allow. The absence of competent computing scientists from the Rathenau Committee has wrought the predictable havoc. One shudders to think about the remainder of the Report's contents when this sample shows, in Tennyson's words,

.... blind and naked Ignorance
Delivers brawling judgments, unashamed,
On all things all day long.

[The above is an English translation of EWD724, which was originally written in Dutch. I gratefully acknowledge dr.I.S.Herschberg's assistance in preparing this translation, with which —to tell the honest truth— neither of us is fully satisfied. For me —probably more so than for Herschberg, who has more experience in such matters— this confrontation with the translator's problems was an educational experience: it was a lesson in modesty.]

Plataanstraat 5 5671 AL NUENEN The Netherlands | 5 March 1980 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Hamilton Richards
revised Thu, 10 Aug 2006

EWD 725

Trip report E.W.Dijkstra, Liege, Nov.-Dec.1979.

This was not one trip, but five short ones: a one-day trip on Thursday 22 November 1979, and a two-day trip each of the four succeeding weeks. All trips were made in connection with the newly installed "Chaire Internationale d'Informatique", sponsored by IBM Belgium under the auspices of the FNRS (Fondation Nationale de la Recherche Scientifique). Professors A.Danthine and D.Ribbens of the University of Liege had taken care of the organization of such a chair for this academic year at the University of Liege. Their chosen topic was "The Correctness Problem in Computer Science", the chair being occupied by five people in succession, in order Edsger W.Dijkstra (Burroughs/THE), Robert C.Boyer (SRI International), J Strother Moore (SRI International), R.M.Burstall (University of Edinburgh), and Zohar Manna (Weizmann Institute/Stanford University). Each speaker is expected to occupy the chair for 4 successive weeks. Being the first to occupy the chair, I was also invited to deliver the inaugural address. (I have tried —see EWD720— to do that also a little bit on behalf of my successors.)

The planning for the opening session was absolutely fantastic. From 15.00 to 16.30 three Belgian speakers, then a short break —in order to allow the Walloon officials, who are not supposed to understand English, to leave the room— and then I until 17.30; then cocktails offered by IBM Belgium. Listening for two-and-a-half hours is, of course, much more that you can inflict upon an audience, and I was greatly relieved to hear that one of the Belgian speakers had been prevented from attending. Eventually two Belgians spoke from 15.00 to 15.45, the break was skipped, yours truly spoke from 15.45 to 16.30 and the cocktails were served one hour earlier than originally planned.

The first speaker was professor E.Betz, the current Rector of the University of Liege. He is a medical man and delivered a long concatenation of official phrases as if he had been paid to do so (what, in fact, he was). If his description of the role of computing science was correct, than it is quite clear that at the University of Liege computing science had not emerged yet as a coherent scientific discipline with a rigid existence of its own. It was all very "interdisciplinary".

The second speaker, C.A.de Meyer, President of IBM Belgium, spoke on the relations between IBM and the Universities. It was quite revealing that, in his title, IBM was mentioned first and the Universities last. The whole talk was very revealing, probably much more so than C.A.de Meyer had intended. He displayed a lot of the penetration tactics: select among the still respectable countries one of the more vulnerable ones —no indigenous computer industry, etc.— and attack the universities with the usual bribery of partly free machines and research fellowships to be spent at one of the IBM labs. It is hard to ascertain to what extent the brainwashing had worked. Several people warned me that IBM Belgium was a most dangerous organization, and on account of what I observed I was willing to believe that: I was rather amazed that de Meyer could tell this story and could present IBM as the great patron of Belgian computer science without being shouted down from the podium. I got independent confirmation that de Meyer's way of presenting the situation —viz. that the best thing the Belgians could do was to follow all the U.S. guidance so lavishly offered to them— was, in general, accepted. Several people asked me during the cocktail party since when I was back in Nuenen, whether I liked living in Europe again, etc. They were utterly amazed when I told them that I had been a Dutch resident all my life: that I could have become the kind of famous expert I evidently was without having learned the trade in the USA was simply beyond them.

*         *         *

During the next four weeks I occupied the "Chaire Internationale d'Informatique". In doing so I lectured for 32 hours. I left Eindhoven on Wednesday morning with the train of 7.55 and returned on Thursday evening at 18.30, having lectured both days from 10.00 - 12.00 and from 14.00 - 16.00 . The four nights in between I stayed in the Holiday Inn which I cannot recommend.

I started with an audience slightly over 100, I ended up with 70 people, about 30 of whom were students from Liege who, in a way, had no choice. Of the remaining 40 I can think of about 7 people that had caught the message and were duly thrilled. Not a bad score, in particular not a bad one when we take in account that those 7 youngsters had almost all teaching responsibilities at different Belgian Universities. The comment I heard from most of them was "What a pity that so-and-so isn't here!", where so-and-so referred to one of their colleagues or, more often, one of their professors. (It sounded very familiar: "What a pity my boss isn't here" was the overwhelming reaction of my Australian audience.) In a way I pity those youngsters. They form the bright young generation that takes the intellectual challenge seriously, but have to do so in a society in which the older generation hasn't the foggiest notion of what software is about —if not actually full of "fear and hatred of science" (E.T.Bell)— . One of the participants —with a degree in mathematics— complained bitterly —and to my taste fully justified— about the impossibility for Belgian students of mathematics to specialize in informatics. Apparently Belgian computing science is entirely in the hands of engineering and applied science.

And as it is mostly the Department of Electrical Engineering that has absorbed the subject, Belgian computing science is in very bad shape, and, in view of the difficulty of changing academic institutions, it is not clear at all how it will dig itself out of the hole again. In my inaugural address (EWD720) I had not hesitated —though a guest of the "Institut d'Electricite"— to state that "as a rule departments of electronic engineering actually deprive their graduates from the ability to understand later in life what computing science is all about". To the uninitiated this may seem a bold statement —to those living in a stratified society it may even seem a rude one— , it was, in actual fact, a very safe remark. After I had made it, one of my hosts announced that he would answer it when introducing me next week. He did not, and my reaction was "Well, he postpones that rebuttal for his closing speech". But he did not do that either: in the meantime it was too clear that even the design of a simple program was beyond him. I pity the 7 youngsters: I know the kind of battle they have to fight, they have my blessing (I am afraid that they need yours as well).

In one respect the course was not the success its organizers had hoped: though the course had been well-advertized in France, in Germany, and in the Netherlands, the audience was almost completely Belgian. In retrospect I am slightly annoyed by the absence of many of my countrymen, who could have learned so much. In contrast, the enthusiasm of the Belgians was heartwarming: one of them, who had his sabbatical in England, commuted from Cambridge.

*         *         *

From a social point of view, my hosts were perfect. All the transport in Liege —between station, campus, hotels, restaurants, etc.— were taken good care of, and we had a number of pleasant dinners. The dinner in Prof.Ribbens's home was a memorable one, so was the official dinner in the castle on the campus. The interior of this old building has been completely "redone", so as to make it suitable for housing academic receptions etc., and it had been redone very tastefully: we were all impressed. At that dinner we were 11 people; the discussion, though lively, never gave me the impression of being among scholars, but the food was excellent.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 9th January 1980 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

Note. Foreigners will not receive EWD724, which has been written in Dutch. (End of Note.)

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD726 - 0

How Dutch Informatics fell between two chairs.

In the late fifties the late prof.dr. H.D. Kloosterman proudly declared that "being a mathematician, he knew of course nothing about computers." It is sad, but the Dutch mathematical community as a whole still feels that way. When almost all your best brains ignore a topic, the consequence is obvious: as a result of the mathematical neglect, Dutch computing science is largely populated by second- and third-rate people. It is now so repellent that it is very hard to see how we could ever dig ourselves out of that hole again: it is very hard to convince a bright youngster that he should join that miserable crowd!

The terrible coincidence was that after World War II our electrical engineering wasn't ready either. We had one very pragmatic department, where heavy electrical engineering had the longest tradition, where electronics had not dissociated itself yet from "the radio hobbyist" --by way of analogy: think what happens to a department of mathematics where students only enrol because they are so fond of playing chess!-- , and where the electro-mechanical telephone exchange was their only connection to anything digital.

That was a very false start. In their unscientific minds they have now, 35 years later, still not made

EWD726 - 1

a clear separation between the electronic problem of how to simulate a discrete automaton with the analogue means at their disposal, and the non-electronic problem (which they had better leave alone, but don't) of how to reason effectively about a large, discrete universe. As a result, the Dutch electronic engineer can cope with neither of the two problems successfully. The collapse of the Dutch computer industry is a direct consequence of his incompetence --that this was caused by suddenly changing market situations is only eyewash-- and the telecommunication industry is soon to follow.

The trouble is that you cannot tell this in my country. It makes the mathematicians feel uneasy, perhaps even guilty, and the electronic engineers feel just offended; everybody gets only cross with you, instead of doing something about it.

Can anyone tell me how to suffer fools gladly when I see the havoc they make?

Plataanstraat 5 5671 AL NUENEN The Netherlands | 9th January 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Tue, 24 Jun 2003.

EWD 727

Trip report E.W.Dijkstra, U.S.A. 12 Jan. - 2 Feb. 1980.

I left home on the sunny winter morning of Saturday the 12th January 1980. I travelled smoothly —though I crossed the Atlantic with a very talkative neighbour (from Philips)— and arrived at Ithaca 18 hours after my departure from home. David Gries and Femke were at the gate. David drove us first to Femke's home, so that I could see her room. I gave her all the articles I had for her in my suitcase, and then David and I drove off to his home. There I got the traditional: "a big glass of cold milk, a hard-boiled egg, and a glass of whisky". Thereafter: off to bed!

The next morning David collected Femke —on the same trip on which he bought the Sunday paper— and she stayed with us for the whole day. Before lunch Femke and I listened to the recording of Wim Kan's New Year's Eve performance that I had brought with me. (After all, she had to know what has happened in our country during her absence, hadn't she?)

The next three days followed very much the same pattern. I would be at Cornell University (talking, listening, commenting or lecturing) until 16.00 when Femke would come; over a beer (or two) we would talk until dinner. On Monday evening we took all the Grieses out for dinner; we had a very pleasant dinner in a Chinese restaurant. On Tuesday evening we took two of (mainly) her friends out for dinner, but that was a disaster: during the night I discovered that the (vegetarian) Moosewood food, besides having been inedible, was also indigestible. The last evening we spent with the Gries family. I took leave from my dear daughter that evening and flew the next morning —in a really miserable commuter plane— down to Washington.

*         *         *

In the afternoon I gave a lecture at the University of Maryland. We then went to Washington D.C. for a meeting of the local Chapter of the ACM: cocktails at 18.30, dinner at 19.30, and performance by yours truly from 21.00 to 23.00. It was very hard work because I had to reach a crowd of about 300 people, but all went very well. My hosts took me back to the Center for Adult Education of the University of Maryland, where I had an excellent night.

On Friday 18th January I gave a one-day seminar —from 9.00 till 12.00 and from 13.00 till 17.00— for an audience of about 200 people, again under the auspices of the Washington Chapter of the ACM. That was hard work too, and slightly less successful because the audience was very mixed. (This despite the efforts of the organizers who had announced the happening in a way that should have made it perfectly clear to what type of audience I would address myself.) Early in the afternoon I developed with —part of— the audience the same program I had developed at the Australian Universities, early 1977; down under that example had been very suitable, in Washington it was clearly too difficult for a noticeable fraction of the audience. Apart from that one misjudgement, all went very well. (Before I started I had been introduced by Raymond Yeh to a man from Prentice-Hall. At the coffee break in the morning the P.-H. man came to me in order to excuse himself for the rest of the seminar: "You would make an excellent video tape! You are just like so-and-so!" I had to ask so-and-so; so-and-so was the presentator of a famous American TV-show! One gets the strangest compliments....)

The evening dinner was excellent; at 7.45 next morning my hosts were back at the Center for Adult Education, in order to take me to Dulles International Airport, from where I flew to San Diego. The Washington schedule had been very heavy; the very good care my hosts took of me was highly appreciated: I don't know how I could have fulfilled my obligations without it.

*         *         *

At San Diego Airport I was met by Dr.Lawrence D.Rogers, the General Manager of the local outfit of Burroughs' Terminal Systems Group. After having checked in at the Summer House Inn —the Sea Lodge having been fully booked up as a consequence of a golf tournament in La Jolla— and having visited the plant, I was taken to his home, where I was introduced to his family and stayed for the rest of the day. On Sunday 20th January we went sailing on the Pacific Ocean. The strong wind prevented us from achieving our original goal of getting a good view of the whales on their trek Southwards; it did, however, give Rogers the opportunity of proving that he was an excellent captain.

The next three days I worked at the plant. I had two disappointments. Two meetings with people from outside Burroughs had been arranged to take place there, but the one man was not very interesting and the other one did not show up. For the rest my time was well-spent; it was my first visit to that place and the encounter was mutually instructive. On the last day I gave at noon a one-hour lecture at the University of California at San Diego. The room was available for exactly one hour and it was a great challenge to present what I wanted to show —W.H.J.Feijen's algorithm for lexicographical minimum from a circular list— within 60 minutes. I just made it, without losing my audience, and that tells something about the quality of UCSD!

The hospitality of the Burroughs people down there was greatly appreciated —on no evening I had to make do with hotel food— and it was with some regret that I left them on Thursday morning for the Mission Viejo plant. I was taken by car and arrived at 10 o'clock in the morning. (From the San Diego plant I had taken with me a list of language rules:

1)     | Each pronoun should agree with their antecedent.
2) | Just between you and I, case is important.
3) | Verbs has to agree with their subject.
4) | Watch out for irregular verbs which has crope into the language.
5) | Don't use no double negatives.
6) | A writer should not shift your point of view.
7) | When dangling, don't use participles.
8) | Join clauses good, like a conjunction should.
9) | Don't write a run-on sentence you have got to punctuate it.
10) | About those language fragments.
11) | In letters themes reports articles articles and stuff like that we use commas to keep things apart without which we would have without doubt confusion.
12) | Don't, use, commas, which are not necessary.
13) | Its important to use you're apostrophe's correctly.
14) | Don't abbrev or use contract'ns.
15) | Check to if any words out.
16) | In my opinion I think that an author when he is writing something should not get accustomed to the habit of making use of too many redundant unnecessary words that he does not actually really need in order to put his message across to the reader of the piece.
17) | In re business letter, check it out per jargon.
18) | About repetition, the repetition of a word is not usually effective repetition.
19) | As far as incomplete constructions, they are wrong.
20) | Allways spel coreccly.
21) | And, last but not least, lay off cliches.)

*         *         *

When I arrived at Mission Viejo, R.D.Merrell, whom I had not seen for ages, was on the verge of leaving for Pasadena where he had a meeting at noon, but would be free during the afternoon as his plane left LAX only at 19.00 . So I jumped in his car and went with him to Pasadena. During his meeting I had first a quick lunch in the cafeteria of the plant; thereafter I wrote my report on my visit to San Diego. When Merrell's meeting was over we talked until he had to go to the airport; in the meantime John McClintock had come to take me back to Mission Viejo (well, actually Laguna beach, where I stayed in the "Surf and Sand".)

On Friday we went to the plant where I first asked Donna Spooner to clear up the mess created by the Dutch travel agent, who had booked me on non-existent flights back to the East coast. We worked there the whole day. So did John and I on Saturday afternoon. I spent the rest of the weekend writing until at 16.30 John came to take me to his home for the Sunday dinner. Because the next two days there was no conference room available at the plant, we worked those days in a conference room of Surf and Sand.

Knowing that I would have to leave on Wednesday morning very early for the East coast, I tried to set my body clock forward on Monday evening by going to bed early (i.e. at 22.00). It was, alas, one of my worst nights of the whole trip: after a few hours of sleep I was woken up by a terrible storm whistling through the sliding door that gave way to the balcony. (I was unable to close it any better.) The sand was silent enough, but the surf was very noisy; my room got very cold and I was shivering. It was only around 6.00 that I fell asleep again. At 7.00 the wake-up call came. We worked all day (I am not quite sure how I survived that day) and felt fully justified when I declined the invitation that reached me at noon to give a lecture at the University of California at Irvine late that afternoon.

Bob Jardine saw me to Santa Ana where I had a hotel reservation near what is now known as the John Wayne International Airport. Though Donna Spooner had said that now "I was all set" we went to the airport, just to make sure. I was, indeed, booked on the flights that I wanted to take. It had been said that at the airport they would take my erroneous tickets and would give me new ones. But the young lady at the counter looked as if I had made an indecent proposal to her "Oh, but this is an international ticket!". Thank goodness I had still enough dollars with me, for the only way out of the mess was buying the new tickets. Burroughs Amstelveen has to get reimbursed for the useless (and hence unused) tickets I had with me. After a pleasant dinner with Bob Jardine I went off to bed. I had several nightmares (about missing planes and the like).

*         *         *

On Wednesday 30th January I flew via Los Angeles and New York from Santa Ana to Ithaca where I stayed for one more night in Hotel Gries. When I arrived Femke was listening to a violin recital by Heifetz Jr.; afterwards I saw her for about ten minutes, but then her Ithaca life claimed her again. With the Greyhound of 9.00 I went the next morning to Binghamton, where I arrived at 10.05 in order to give my last performance of this trip that afternoon under the auspices of the "Technical Vitality Program" organized by SUNY at Binghamton, some form of Adult Education ("The Recycling of Intellectual Trash") for the employees of the local industries (primarily IBM, GE, and Singer). Of the whole trip this was by far the dullest audience I had to work with. In addition the facilities were abominable: though I had been promised a lecture room with wall-to-wall blackboards, I had to perform in a dining hall in which the people were sitting at round tables at too great a distance from small movable blackboards that had been placed at one end of the hall —for my "benefit", I presume— . The audience seemed pleased enough, but I knew that I had given by far the worst performance of the whole trip.

The next morning at 8.30 three faculty members joined me for breakfast in the Holiday Inn. (Since that breakfast I know what "a monument of ignorance" looks like.) With the Greyhound of 10.30 I went to New York. The Business Class of flight KL642 was —quite remarkable!— only occupied for 30 per cent. and I arrived in reasonable shape the next morning at Schiphol Airport where Ria was with the car. At 8.45, after 17 hours of travel, I was back home in Nuenen. With a cup of coffee I had a first look at the accumulated mail, and then: off to bed!

*         *         *

I had not realized the severity of the difficulties the Departments of Computing Science are facing in the U.S.A. as a direct result of the boom of the computer-related activities. It is very alarming (and everyone to whom I said so agreed wholeheartedly).

Firstly, the industry is paying such salaries to computing scientists (even to the mediocre ones) that the Universities can no longer compete; the battle is now so unfair that many a department becomes "filled with vacancies". Collectively the U.S. industry is killing the goose that lays the golden eggs. (Back home I checked it in the latest issue of the Comm.ACM, and, indeed more than 100 academic institutions advertise their vacancies in that single issue!)

Secondly, in direct response to the market, the enrollments for computing science are rising steeply. And, if the combination of those two circumstances were not bad enough, the field attracts most definitely the wrong type of students! In the American popular conception computing science is now farther divorced from mathematics than ever. (The pattern of semi-reasoning that leads to that opinion is obvious: economic necessity dictates that automatic computing becomes a major business, hence it cannot be mathematical because mathematics is only for the happy few. It is as simple as that! And for the sake of convenience we are supposed to forget that you cannot solve problems —in particular not mathematical problems— by bluntly denying their existence.) As is only to be expected the pressure to make the computing science education more "pragmatic" has only gained strength (see the so-called Feldman report in the Sept. 1979 issue of the Comm.ACM).

Being based on a fundamental mistake, the boom is not going to last. At Cornell University I met Doug McIlroy, who was out there, recruiting computing science Ph.D.'s for Bell Labs. While he was impressed by the improvement of the programming abilities of graduates over the last ten years —and that was nice to hear!— he made no secret of his greatest complaint either: even the computing science graduate from the best institutes —the second-, third-, and fourth-rate institutes he doesn't visit— was not enough of a mathematician! (It was nice to hear that at least Bell Labs has seen the light; I was pleased to hear that comment, and so was Juris Hartmanis, the current Head of the Department at Cornell.) He made it quite clear that as soon as managers could find better people and had the courage to employ fewer of them, the boom would be over.

I am very worried about the harm that will have been done in the meantime. On this trip I had the doubtful privilege of visiting a few third-rate institutes and of being confronted with a number of their graduates. It was a shattering experience: I had forgotten how utterly miserable a place a poor university can be! I met a few of their victims: atrophied brains, only able to stir a pool of jargon. It wasn't only depressing, it was frightening, as frightening as only the confrontation with idiots can be.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 7th February 1980 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD728 - 0

A problem solved by Netty van Gasteren and me.

Establish whether it is possible to partition six consecutive natural numbers into two triples such that the two triples have equal products.

* |  | *
| * |

Solution. A sequence of six consecutive natural numbers contains one or no multiple of 7.

If the sequence of six contains one multiple of 7, any partitioning of it gives rise to two triples with different products, only one of them being a multiple of 7.

If the sequence of six contains no multiple of 7, any partitioning of it gives rise to two triples with different products, because the product of all six reduced modulo 7 equals 6, whereas a square reduced modulo 7 equals 0, 1, 2, or 4.

Hence any partitioning of any six consecutive natural numbers into two triples leads to two triples with different products. (End of Solution.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 13th February 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon.

Last revised on Sat, Tue, 24 Jun 2003.

EWD 729

On well-shaped mathematical arguments.

The following is not written with the intention of making myself popular. On the contrary, I am afraid that I can think of sizeable subcultures —mathematicians, logicians, philosophers, psychologists, and pedagogues, to name just a few— whose primary reaction will be to be annoyed rather than amused or enlightened.

This text is written in the firm conviction that there is a profound difference between the notions "convenient" and "conventional". Its actual writing has been prompted by the observation that many people have great difficulty in making the distinction. Convenience should be an objective notion, independent of our personal habits and educational pasts, but many people, while intellectually agreeing that performing computations in decimal (Arabic) notation is more convenient in such an objective sense than doing it in Roman numerals, will make a moment later their notion of convenience again dependent on "what you are used to" (and this appeal to personal taste will be defended with adjectives such as "natural" and "intuitive"). But our tastes are formed by our habits, and our mathematical tastes are no exception: they are formed by our mathematical habits. Hence my desire to subject the latter to a closer scrutiny.

*                      *
*

When I was a pupil at the Gymnasium Erasmianum in Rotterdam, Euclidean Geometry was a major component of the curriculum. As far as I was concerned this needed no further justification, for I liked the topic. It was, however, explicitly justified on the grounds that Euclidean Geometry was an excellent topic to be used to teach us how to think logically. In a way it was, but were all the accompanying habits wholesome? I don't think so. We learned how to prove theorems, and that was good. We also learned the profound difference between an unproved conjecture and a proven theorem, and that was good too. But in retrospect I have equally profound objections to the way in which the theorems used to be formulated: they used to follow the pattern "if P, then Q" or, equivalently, "given P, prove Q". And this has strange consequences.

In one of the first chapters of a recent (!) book on geometry I found the following two theorems (I quote by heart):
Theorem 1. If, in a triangle, two angles are equal, then these two angles have bisectors of equal length.
Theorem 2. If, in a triangle, two angles have bisectors of equal length, then these two angles are equal.
The authors need a full page for the explanation why the second theorem is much harder to prove than the first one. While the first theorem can be proved "directly", the second theorem can be better proved "indirectly", i.e. it is easier to prove Theorem 2' "instead":
Theorem 2'. If, in a triangle, two angles are different, then these two angles have bisectors of different length. After having proved Theorem 2' —the so called "counterpositive"— the proof of the original theorem follows immediately. Suppose that Theorem 2 were false; then there would exist a triangle with two angles with bisectors of equal length that would be two different angles; Theorem 2' then tells us that their bisectors would be of different length. Because two bisectors cannot be simultaneously of equal and of different length, we have reached a contradiction. Hence our assumption that Theorem 2 was false is untenable, and, hence Theorem 2 is true.

What a terrible smokescreen! The authors failed to stress that Theorem 2 and Theorem 2' are exactly the same theorem, only formulated differently. With Theorem 2 of the form "if P, then Q", Theorem 2' is of the form "if (non Q), then (non P)", or, using the implication sign, they are of the forms

"P => Q" and "(non Q) => (non P)"

respectively. Remembering that the implication A => B is only an asymmetric way of writing the disjunction (non A) or B, we can equate the two formulations to

"(non P) or Q" and "Q or (non P)"

respectively; the disjunction being symmetric, the two expressions are clearly equivalent.

The whole folklore about "direct proofs" and "indirect proofs" and the medieval relic of "the counterpositive" could have been disposed of by formulating the theorems as disjunctions to start with!

Theorem I. Two angles of a triangle are different or they have bisectors of equal length.

Theorem II. Two angles of a triangle are equal or they have bisectors of different length.

It is my contention that it is (objectively!) more convenient to represent the symmetric relation A or B by "A or B" (or by "B or A") than by one of the asymmetric expression "(non A) => B" and "(non B) => A". Here one of my beliefs —or if you prefer: one of my considered opinions— surfaces: an asymmetric notation for a symmetric relation is a pain in the neck, and the pain is misleading.

The apparent "greater difficulty" of Theorem 2 is no more than an artefact, created by an inadequate notation. How utterly misleading that notation is I learned when I confronted an elderly mathematician (for whom I have nothing but the greatest respect) with Theorem 1 and Theorem I. It was for him not easy at all to "admit" their equivalence, because emotionally he processed the two quite differently: Theorem 1 was for him a theorem concerned with triangles with equal angles, while Theorem I was about any triangle. Though logically equivalent, they managed to "mean" different things for him.

When we have to demonstrate the truth of theorems of the form A or B or A or B or C, we have to show that under any circumstances at least one of the (two or three) terms is true. The general pattern of such proofs is the exhaustive investigation of the situations that are possible when all the terms but one are false; when we can show that in all these situations the remaining term is true, we have proved the theorem. With a theorem of the form A or B we have two different proof strategies, with a theorem of the form A or B or C we have the choice the choice between three different strategies. The point is that the choice is absolutely free and should be made consciously. We should always ponder about the question which set of situations to be investigated is the most manageable. (In the case of the theorems I and II, they are the situations in which something about the angles has been given.)

It is, for instance, exactly this freedom that should be wisely exploited in many of the problems posed in the Mathematical Olympics. Let me give you one example —again I quote by heart—

"Nine mathematicians meet at an international congress. When it is given that of any three of them, at least two can communicate in a common language, and no mathematician masters more than three languages, show that there exists a language common to at least three of them."

Well, this is a theorem of the form "A or B or C" with

A:   there exists a triple of the mathematicians that is incommunicado (i.e. such that no two of the triple have a language in common)

B:   there exists a mathematician mastering more than three languages

C:   there exists a language mastered by at least three mathematicians.

The asymmetric way in which the problem has been stated suggests to investigate the "given" situations, characterized by "(non A) and (non B)". Condition A being the most awkward one —concerning, as it does, pairs from triples— we may expect the set of possible situations satisfying (non B) and (non C) to be the most manageable one. So we find ourselves invited to investigate the situations that are possible under
non B: each mathematician masters at most three languages, and
non C: each language is mastered by at most two mathematicians.

In the case non C, each mathematician communicates in different languages with the other mathematicians he can communicate with; together with non B, we conclude that each mathematician can communicate with at most three other mathematicians. From this and the fact that the number of mathematicians exceeds 4 we derive the existence of a pair of mathematicians X and Y that cannot communicate with each other. Mathematician X can communicate with at most 3 of the remaining 7, and so can Y. Therefore, because 3 + 3 < 7, among those remaining seven there exists at least one mathematician Z that can communicate neither with X, nor with Y. The triple XYZ demonstrates the existence of a triple that is incommunicado, hence the truth of A. (End of Solution.)

I have shown the above example for several reasons. It is a further confirmation that the sooner the medieval relic "the counterpositive" is forgotten, the better. (You see, in the case of "(A and B) => C" we don't have a unique counterpositive! We have at least "(A and non C) => (non B)", "(B and non C) => (non A)", and "(non C) => (non A or non B)". But is "(A) => (C or non B)" a counterpositive as well?)

But a more disturbing observation can be made. Of course we could conclude that the inclusion of this problem in the Mathematical Olympics — traditionally solvable by an unusual solution requiring very little specialized knowledge— was a mistake, because standard heuristics lead to a straightforward solution. Indeed, the problem would have been regarded as trivial, had it been phrased as folows:

"Nine mathematicians meet at an international conference. When it is given that each mathematician masters at most three languages and each language is mastered by at most two mathematicians, show that there exists a triple of mathematicians, no two of which have a language in common."

Composers of the Mathematical Olympics are, however, traditionally no fools, and as a result I am disturbed by the observation that, evidently, people are not supposed to see that the second phrasing states exactly the same theorem as the first one. I can only draw two conclusions.

Firstly, it is not the theorem itself that presents any problems, it is only the first formulation that should be regarded as a mystification. And, secondly, the systematic demystification of such misleading formulations is in all probability not a standard component of our mathematical curricula (for, if it had been, the problem would never have been admitted). And that conclusion is a cruel exposure of our standard mathematical curricula: if we don't teach how to avoid avoidable complications our teaching must waste a lot of energy teaching clumsiness.

This is a very sad conclusion, but I am afraid that is is unavoidable.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 18th February 1980 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by eleftherios g stavridis
revised Wed, 20 Jun 2007

EWD730

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

On two types of infinite sets of infinite sequences.

by the Tuesday Afternoon Club.

In the following x will stand for the infinite sequence (x(0), x(1), x(2), ...........) where the x(i) are taken from a finite alphabet of at least two characters, say {0, 1}

Let us consider the sets of sequences S1 and S2 , defined as the solution sets of the equations P1(x) and P2(x), respectively, with

Pl(x): | (E i: i ≥ 0: (A j: 0 ≤ j < i: x(j) = 0) and (A j: i ≤ j: x(j) = 1))
P2(x): | (A i: i ≥ 0: x(i) = 0 or (A j: j ≥ i: x(j) = 1)) .

Because P1(x) ⇒ P2(x) , S1 is a subset of S2 , even a proper subset: there exists one solution of P2(x) and non P1(x) , viz. the sequence with x(1) = 0 for all i ≥ 0.

The set S2 has the property that for any non-member of S2 —i.e. any solution of non P2(x)— non-membership can be established on account of an initial segment of it. As a matter of fact, in this particular case only two elements suffice for this evidence, as follows from non P2(x):

| (E i: i > 0: x(i) ≠ 0 and (E j: j > i: x(j) ≠ 1)) .

The set S1 doesn’t have this property because there exists a non-member —viz. x(i) = 0 for all i ≥ 0— with the property that any initial segment of it is also the initial segment of a member of S1 . We call S2 “closed” and S1 “non-closed”, that is:

| “The set S is closed” means “any non-member of S has an initial segment that is not the initial segment of any member of S”.
| “The set S is non-closed” means “there exists a non-member of S such that any initial segment of it is also the initial segment of some member of S ”.

From the above it follows
1)     that a set of sequences is either closed or non-closed,
2)     that any finite set —in particular the empty set— is closed,
3)     that the (uncountably infinite) universe of all possible sequences is closed.

*              *
*

The notion of a closed set is of significance in connection with non-deterministic infinite computations. Consider the set of possible output sequences y corresponding to

| “initialize; i:= 0; | (1)
| do true → compute; print(y(i)); i:= i + 1 od” |

Here “initialize” and “compute” stand for terminating computations not affecting the value of i . If “initialize” and “compute” stand for deterministic computations, the set of possible output sequences consists of a single element; if “initialize” and (in particular) “compute” are non-deterministic, the corresponding set of possible output sequences can be infinite.

| “Program (1) is a continuous machine” means “in program (1) ”initialize“ and ”compute“ are both of bounded non-determinacy”.

We can now prove the following

Theorem 1. The possible output sequences of program (1) form a closed set or program (1) is not a continuous machine.

Proof. Let S be the set of possible output sequences of program (1). Either S is closed —in which case Theorem 1 holds— or S is non-closed. In the latter case, let x be a non-member of S such that each initial segment of x is also an initial segment of some member of S . Consider now the following program:

| “initialize; i=: 0; | (2)
| do ”y(0),...,y(i-1) is an initial segment of x “ →
|             compute; print(y(i)); i:= i + 1
| od; print(i)”

Non-termination of (2) is excluded because x is not a member of S Because each initial segment of x is also the initial segment of some member of S , the final value of i is unbounded. Hence, program (2) is a (weakly) terminating program of unbounded non-determinacy; hence “initialize” or “compute” is of unbounded non-determinacy, i.e. program (1) is not a continuous machine. (End of Proof.)

Theorem 2. A set of sequences is non-closed or is the set of possible output sequences of some continuous machine.

Proof. Let S be the set of sequences. Either set S is non-closed —in which case Theorem 2 holds— or it is closed. In the latter case consider program (1) with “initialize” deterministic and “compute” only constrained by the requirement that the next y(i) leads to an initial segment of some element of S . Because the alphabet is finite, “compute” need not be of unbounded non-determinacy. By virtue of its construction program (1) may then generate any member of S , and, S being closed, it cannot generate any non-member of S . (End of Proof.)

Having identified closed sets of possible output sequences with continuous machines, we propose to ignore for the time being non-deterministic infinite computations to which non-closed sets correspond.

Plataanstraat 5 | 19th February 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Last revision 2015-02-28

.

EWD731 - 0

An experiment in mathematical exposition.

Many people feel attracted to the implication on account of the simplicity of the associated inference rules

           A ⇒ B          (1)
           B ⇒ C
        -----------
           A ⇒ C

           A ⇒ B          (2)
           C ⇒ D
        -----------
        A ∧ C ⇒ B ∧ D

           A ⇒ B          (3)
           C ⇒ D
        -----------
        A ∨ C ⇒ B ∨ D

The transitivity of (1), and the symmetry of (2) and of (3) are clearly appealing. Rule (1), however, is a direct consequence of, and rules (2) and (3) are merely two different transcriptions of the same

           A ∨ B          (4)
           C ∨ D
        -------------
        A ∨ C ∨ (B ∧ D)       ,

a rule, which --on account of the symmetry of the disjunction-- can be applied in four different ways to the two given antecedents. Rules (2) and (3) give only two of the four. Rule (1) emerges as the special case

EWD731 - 1

           A ∨ B
           C ∨ ¬B
        -------------
           A ∨ C       .

I called this "a direct consequence" because --perhaps somewhat arbitrarily-- I would like to distinguish between inference rules (different applications of which may yield results that are not equivalent) and simplifications that are possible according to boolean algebra --such as replacing B ∧ ¬B by false and A ∨ C ∨ false by A ∨ C-- , but never change the value of the boolean expression.

* |  | *
| * |

The above caused me to revisit the problem of the nine mathematicians visiting an international congress, and about whom we are invited to prove

          A ∨ B ∨ C                     (5)

with

A: | there exists a triple of mathematicians that is incommunicado (i.e. such that no two of them have a language in common)
B: | there exists a mathematician mastering more than three languages
C: | there exists a language mastered by at least three mathematicians.

Very much like the introduction of (named!) auxiliary lines or points in geometry proofs, I propose to introduce named auxiliary propositions, such that

EWD731 - 2

we can prove lemmata connecting them to the above propositions, such as

D: | there exists a mathematician that can communicate with more others than he masters languages,

for which we can prove
Lemma 1 C ∨ ¬D.
Proof Obvious. With this qualification we mean here that we can start as well with observing

C ∨ | "each mathematician communicates in different languages with those others he can communicate with", etc.
as with observing
¬D ∨ | "there exists a mathematician that shares a language with at least two others", etc.

(End of proof of Lemma 1.)

With

E: | there exists a mathematician that can communicate with more than three others,

we can prove
Lemma 2. A ∨ E.
Proof Let "x | y" here stand for "x and y are two different mathematicians that have no language in common. With

G: | for each x, the equation x | u has at least five different solutions for u,

we observe (obviously)

        E ∨ G                  (6)

With

EWD731 - 3

H: | with y and z constrained to belong to an arbitrary quintuple, the equation y|z has at least one solution in y and z,

we observe (equally obviously)

        E ∨ H        .        (7)

Applying rule (4) to assertions (6) and (7) we find     E ∨ (G ∧ H)   ,
hence

E ∨ | "for each x, the equation x | y ∧ x | z ∧ y | z has at least one solution in y and z".

(End of proof of Lemma 2.)

Applying rule (4) to Lemmata 1 and 2 we infer the
Corollary.     A ∨ C ∨ (E ∧ ¬D)   .

Remembering rule (4) we see that (5) has been proved when we can prove B ∨ ¬(E ∧ ¬D)
or, equivalently
Lemma 3. B ∨ D ∨ ¬E.
Proof. Obvious. (End of proof of Lemma 3).

* |  | *
| * |

Note that in the above the Corollary was only used for heuristic purposes. Once Lemmata 1, 2, and 3 have been established we could have inferred

          A ∨ E
          B ∨ D ∨ ¬E
        ---------------
          A ∨ B ∨ D

and

          A ∨ B ∨ D
          C ∨ ¬D
     ---------------
          A ∨ B ∨ C

EWD731 - 4

and our two individual inferences would have been of the traditional form of the transitive implication.

* |  | *
| * |

I know that firm believers in the so-called "natural deduction" will state that, in the case of Lemma 2, I am just "deducing naturally" that A follows from the "assumption" ¬E. In this appreciation they will find themselves strengthened by the observation that in that proof all assertions start with "E ∨". They have a point, but the point is weak. Look at the structure of the proof as a whole. Lemmata 1, 2, and 3 capture it; from there rule (4) does the job, and at that level it is very arbitrary to subdivide assertions into assumptions and conclusions.

Remark. Observing the seven triples xyz for a pair (x,y) such that x | y , the argument proving Lemma 2 can equally well be phrased in terms of assertions starting with "A ∨". In the sense used above also Lemma 2 is obvious. (End of remark.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 27 February 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Tue, 24 Jun 2003.

EWD732

(Draft contribution to "Mathematics Tomorrow".)

The Teachability of Mathematical Thinking.

"It is always difficult to think and reason
in a new language, and this difficulty
discouraged all but men of energetic minds."

Charles Babbage                      

Whenever a next area of human endeavour is observed to be amenable to mathematical treatment, mathematics changes as a result of that discovery. Having observed from close quarters how programming could be developed from a craft (if not a black art!) into a mathematical discipline, I couldn’t help wondering what impact this development might have on the rest of mathematics. And the more I thought about it, the more I became convinced that the influence of computing science on mathematics at large may become very profound indeed.

On the whole spectrum that ranges from the crafts to the sciences, mathematics —though justly called "The Queen of Sciences"— occupies, amazingly enough, a middle position.

At the one end of the spectrum we have the crafts, implicitly transmitted from one generation to the next in the relation between master and apprentice: it is almost a transmission by osmosis. Guild members typically keep their common craft as a well-guarded secret among themselves.

At the other end of the spectrum we have the sciences, explicitly transmitted from one generation to the next in the relation between teacher and student. It is the tradition of the University to try to formulate knowledge as explicitly as possible, thereby bringing its treasures into the public domain.

Along this scale, however, mathematics today occupies a curious, in-between position. Mathematical results —i.e. theorems, proofs, and theories— are taught and published quite openly; how to do mathematics, however, is something that the members of the guild keep among themselves. And it is exactly here that computing science might have its greatest impact on mathematics as a whole: mathematics might move at last from its middle position to where it belongs, i.e. to the scientific end of the spectrum. Predictions are hazardous —in particular, when they concern the future— and, therefore, I shall abstain from them. But I shall give you some of my observations on account of which I regard such a change of mathematics as a very real possibility.

I first established that, to a large extent, professors of mathematics regard themselves as craftsmen. I did so by subjecting them to the following thought experiment. I asked them: "Suppose that we knew how to give a solid two-semester course in Thinking, would you be in favour of including it in the first year of the mathematics curriculum?" One would expect that such a simple question could be answered quickly by a simple "Yes" or "No". Instead, they all started to argue —some of them even vehemently— that such a course in Thinking was "of course" impossible! ("Thinking is unteachable, for, if it were, we would already have discovered how to do it.", and "Mathematicians are not made, but born.", and similar crap.) Whenever a craft is in the process of being superseded by a scientific discipline, the guild members always feel themselves threatened (and rightly so). The height of the emotional barrier that I had to overcome before my colleagues were willing to consider my question was a full confirmation that I was dealing with craftsmen.

The above experiment was prompted by another observation, which explains how computing science enters the picture. In the process of improvement of our programming ability the predicate calculus had become an indispensable tool for our daily reasoning; almost unnoticed, we became as familiar with it as the circumstances required. It was somewhat of a surprise to discover that, though known to all mathematicians, the predicate calculus is hardly used in most other areas of mathematics. (When trying to explain what we were doing to others, we often found their unfamiliarity with the predicate calculus a stumbling block.) From the fact that, in contrast to the computing scientists, the other mathematicians can get away without using that effective tool for formal reasoning I can draw only one conclusion: in some way or another, the intellectual challenge that the computing scientist faces is without precedent in our mathematical culture. The computing scientist has to learn how to cope with vast, subtly intertwined, discrete universes, which, indeed, provide a totally new environment for mathematical thought. The environment seems so new and in a peculiar way so demanding that it evokes novel thinking habits and novel modes of exposition, both of which are more effective than the traditional ones. It should be noted that they are more effective in a very objective sense, that is, in a sense as objective as in which we can state that decimal arithmetic is much simpler than computing in Roman numerals.

There is another circumstance why for mathematics the time to evolve from craft to science may have come, and why the doing of mathematics —i.e. thinking effectively— may become teachable, and that is our new appreciation of notational techniques. Mathematicians have always been aware of the vital importance of adequate notation; some of them —notably Leibniz and Babbage (not to mention Oughtred)— have even paid great attention to the issue. But the vast majority of them does not make a conscious effort to distinguish between "convenient" (in an objective sense, i.e. independent of our personal habits as formed in our educational pasts) and "conventional", and continues to prefer "what they are used to", even if their formulae are ambiguous! They have never given very conscious thought to the topic and, when challenged, shrug their shoulders, saying: "Well, you understand what I mean, don’t you?". (As long as personal habits and resulting tastes still play such a predominant rôle in the appreciation of notational alternatives, it is not amazing that international efforts at the standardization of mathematical notations remain strikingly unsuccessful.)

As long as mathematicians continue to work with a fuzzy aggregate of notational conventions, never explicitly stated and often mutually conflicting, no wonder that they regard the doing of mathematics as unteachable. They may shrug their shoulders and say: "Well, you understand what I mean, don’t you?", but then two comments are in order. Firstly, such a lack of system is bound to be a noticeable barrier for the novice. Secondly, a sizeable part of the competence of the professional mathematician may well consist in the ability not to get confused by his own funny habits.

The scene has changed dramatically, however, with the introduction of recursive formal grammars and their wholesale adoption in computing science since 1960. This was the year of the ALGOL Report which used BNF ("Backus-Naur Form") for the rigorous definition of the syntax of formal texts. (Among computing scientists, this technique is now so much common knowledge that they find themselves shocked —and almost unable to continue reading— when, for instance, they read a text written by a contemporary logician that still tries to do without it.) The extremely rapid propagation and wide-spread acceptance and usage of what was generally regarded —if not frowned upon!— in 1960 as a daring novelty is a most remarkable phenomenon; I think it would be stupid to underestimate its significance.

The notationally unaware often express the expectation that adherence to stricter notational conventions would not influence their thinking abilities. They speak from lack of experience, and they are wrong.

The habit of only writing formulae that satisfy the rules of a rigorously defined syntax gives the mathematician a new appreciation of one of his main tools, and enables him to exploit this tool more consciously and, hence, more effectively. It gives you a means for identifying your more clumsy thinking habits; obviously such an identification is a prerequisite for the effort to supplant them by —now: objectively!— more effective ones.

How profound the influence of our notations is on our thinking I learned the other day —the 4th of March 1980, to be precise— when I took an experiment with my students. Departing from the official topic of the course I presented to them the solution of a combinatorial problem. They all mastered the little mathematics needed, and that was essential because neither the problem, nor the solution, but my presentation of the latter was the real subject of the experiment. I showed them my cleanest presentation of the solution, carefully divested of all asymmetries that are only —be it traditional— notational artefacts. (The problem was a very good carrier for the experiment, because those asymmetries, already suggested by the way in which the problem had been stated, are the main cause of the problem’s "difficulty".) It was almost painful to see my students —whose training is otherwise traditional— struggle with my proof. When I wrote down assertions of the form A∨B, the poor boys could only understand them by translating them into either ¬A⇒B or ¬B⇒A —and, of course, never knowing how to make the irrelevant choice—. After I had carefully removed all misleading irrelevancies from my presentation, they could only cope with it by reintroducing them again! The experiment was somewhat shattering for me, because I felt that I was addressing 25 victims of mathematical miseducation. (I did not blame them: what can one expect from youngsters that have been taught to express so fundamental a concept as equality by the contorted "if and only if" as soon as the domain consists of truth-values? Needless to say, you won’t catch me using the symbol "⇔"!)

I called the experiment shattering; I did not call it depressing. On the contrary, it was inspiring! It convinced me that we are much nearer than I thought to being able to teach how to think: really educating young mathematicians to apply the techniques of scientific thought seems, as a possibility, excitingly close!

As far as the guinea-pigs are concerned, I am happy to report that, though puzzled, bewildered, or disturbed, they all made the impression of being thrilled (though perhaps not fully understanding why). None of them took the cheap exit of feeling offended.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 5 March 1980 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Alejandro Ruiz
revised Mon, 25 May 2009

EWD733

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Naar aanleiding van “Experimentele post-propadeuse opleiding voor informatica-ingenieur aan de THE” (Eindhoven februari 1980 500/jc/sdb).

Dit stuk had zoiets als een beleidsnota moeten zijn; het is helaas slechts een armzalige simulatie —om niet te zeggen: een persiflage— van wat het had moeten wezen.

De openingszin van de inleiding is, gezien het benoemingsbeleid van de onderafdeling der wiskunde sinds 1962, grotesk.

Het stuk is in zo onbeholpen Nederlands gesteld, dat de vraag wat er bedoeld is maar al te vaak verdrongen wordt door de pijnlijkere vraag of er wel iets bedoeld is; de inhoud —vermeend, vermoed of gepretendeerd— is daardoor vaak nauwelijks discutabel.

Even gênant is de collectieve incompetentie van de opstellers, zoals die zich manifesteert waar het stuk wel min of meer begrijpelijk is. Zo ontneemt het lonken naar de Bondsrepubliek en het zich ophangen aan de Amerikaanse curricula het stuk zijn laatste restje geloofwaardigheid, want dat heeft te veel van de lamme, die zich door de blinde laat leiden. (Zoals was te verwachten staat het ACM curriculum uit 1978 zelfs al weer stevig op de tocht, zie Comm. ACM 23, 2 (Feb. 1980) 67 - 70.)

*              *
*

Het valt de aandachtige lezer niet mee om veel verder dan de woordenbrei op pg.6 in het stuk door te dringen. Ontdaan van ergste taalfouten, ruis en dubbelzinnigheid luidt subsectie 3.1 vermoedelijk:

“3.1. Korte signatuuromschrijving. De I-ir beheerst de kennis van (in het bijzonder) automatische verwerking van informatie. Hij dient in staat te zijn zelfstandig deze kennis toe te passen en te ontwikkelen.” (Het origineel —13 woorden langer— is als een zoekplaatje: wie vindt 7 (!) zonden?)

Zoals het er staat is het erg “knowledge-oriented”: het weerspiegelt het beeld van de ingenieur als de man die de kennis gebruikt (en uitbreidt, etc.), die hij in zijn studie heeft vergaard. Dit beeld moge voor sommige ingenieurs, wier kennis door redelijk uitgekristalliseerde wetenschappelijke disciplines reeds voldoende geschraagd wordt, adequaat zijn, in de informatica is dit stadium (nog) niet bereikt; aan kennis en derzelver overdracht kan de in de korte signatuurbeschrijving geschetste rol derhalve niet worden toegedacht. (Met de heel reële mogelijkheid, dat de intellectuele uitdaging van de informatica zo anderssoortig is dan we tot nog toe hebben meegemaakt, dat het geschetste ingenieursbeeld nimmer op de informatica-ingenieur van toepassing zal zijn, hebben de opstellers blijkbaar absoluut geen rekening gehouden.)

*              *
*

De “Eindtermen” in subsectie 3.2 helpen ons niet veel.

De eerste eindterm is enerzijds belachelijk ruim —ergens “aan werken” kan iedereen, zolang geen succes verlangd wordt: zolang een rapport van de onzin aan elkaar mag hangen, kan zelfs ir. J.M.H.M.Claessens het redigeren— anderzijds beangstigend eng —het schijnt b.v. alle exploratie uit te sluiten die onmogelijk als probleemoplossing kan worden omschreven— ; de toevoeging “in een veelheid van situaties” hangt er als los zand bij (en is bovendien onzinnig: was “de oplossing van allerlei informaticaproblemen” bedoeld?)

De in de toelichting ad 1. genoemde “generalistenfunctie” lijkt moeilijk te rijmen met de in de 1ste eindterm genoemde “zelfstandigheid”; de toelichting op “academisch” is —niet alleen taalkundig— een lachertje.

De tweede eindterm is een slecht gestelde —en slecht gespelde!— kreet; de toelichting karakteriseert de koksmaat met zijn ruitekensbroek.

In de derde eindterm kan ik slechts een vereiste lezen mits we, het “general purpose character” van de informatica ontkennend, aan de verzameling mogelijke “toepassingsgebieden” een willekeurige (maar niet expliciet vermelde) restrictie opleggen. De toelichting ad 3. is mij duister: waar bestaat de samenhang met ad 1. uit?

De vierde eindterm is absoluut misplaatst: van iemand die zelfstandig kan werken is het immoreel te eisen dat hij het ook “in teamverband” kan. (Als hij het kan is het meegenomen, maar je mag het niet eisen.)

De toelichting ad 4. is. ondanks de linguistische onbeholpenheid (“deelgebieden”, maar waarvan?; “het laten samenwerken” i.p.v. “het samen laten werken”) onthullend. Hier blijkt —of leg ik dat verkeerd uit?— dat “generalist” in tegenstelling staat tot “specialist”; hier blijkt —een indruk, die versterkt wordt door 3.3., punt 5: “begeleiding van de realisatie etc.”— dat het niet de bedoeling is een vakman op te leiden die zelf iets kan. Ik krijg hier onontkoombaar de indruk dat de opstellers zich de vrijheid wensen voor te behouden abiturienten met een uiterst mistige bekwaamheid toe te staan. De toevoeging “teneinde een automatiseringsprobleem op te lossen” is in tweeërlei opzicht onthullend: ten eerste de engheid van visie die alles als “oplossing van een probleem” wil zien, ten tweede de inperking —tussen neus en lippen— van “informaticaproblemen” tot “automatiseringsproblemen”! De tweede helft van de toelichting ad 4. bij de “communicatieve vaardigheden” is in dit rapport een gillerd. (Straks wordt van onze hoogleraren vereist dat zij de taal van de SOO beheersen.)

De titel van subsectie 3.3 “Oplossing van een automatiseringsprobleem.” heeft mij ernstig verbaasd. wat doet die subsectie hier? Als het slechts een voorbeeld beoogt te zijn van wat een informatica-ingenieur zou kunnen doen, kunnen we dan niet met een voorbeeld komen waar de academische vorming overtuigender tot de activiteit bijdraagt? Als het evenwel representatief geacht moet worden, laten we dan meteen de hele onderneming, als we hem de nek niet kunnen omdraaien, naar de afdeling bedrijfskunde dumpen. De terminologie waarin de zes (2) stappen worden aangeduid doet niet onder voor het gewauwel van de SSAA van weleer (en inmiddels hebben we er ook nog een “informatieprobleem” bijl).

Subsectie 3.4 doet vrezen, dat het onder 3.3 genoemde “Oplossing van een automatiseringsprobleem” inderdaad representatief geacht wordt. we leren in elk geval wat je kunt doen met keuzepakketten: invullen!

Subsectie 3.5 maakt mij —in weerwil van de titel “Relatie tot andere informatica-opleidingsmogelijkheden”— niet duidelijk in welk wezenlijk opzicht de voorgestelde opleiding verschilt van de h.b.o.-opleidingen. Het bij het werkterrein van de informatica-ingenieur genoemde

| “- management van software constructie”

getuigt van een onpeilbaar diep wanbegrip.

*              *
*

Wat moet je in hemelsnaam aan met zo’n stuk snot? Ik denk niet dat het zin heeft de “Bestuurscommissie ad hoc currciculum experimentele studierichting informatica” de opdracht te geven het huiswerk over te doen: de stakkers kunnen niet beter. Rest ons slechts te adviseren de leden van de commissie oneervol te dechargeren en de secretaris over te plaatsen naar een functie waar hij minder kwaad kan.

woensdag 12 maart 1980 | prof.dr.Edsger W.Dijkstra

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-02 .

EWD734

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

The superfluity of the general semaphore.

Consider a set of sequential processes that are mutually synchronized by means of the operations V(s) and P(s) on a so-called “general semaphore” s , that is a semaphore that can take on any nonnegative value. We shall show the derivation of a set of equivalent programs in which the semaphores used are binary, i.e. restricted to the values 0 and 1 . This is done by replacing the operations P(s) and V(s) by the text fragments “ps” and “vs” respectively; they operate in a shared environment of integer variables and binary semaphores.

In the following the reader is assumed to be familiar with EWD703 “A tutorial on the split binary semaphore.”. The solution to the above problem can be viewed as a further demonstration of the applicability of the methods of EWD703, as their straightforward application leads to the following solution.

The shared environment consists of

integer bm | (initially = the number of processes, which is assumed to be > 0)
integer bt | (initially = 0)
integer s | (initially = the initial value of the general semaphore to be simulated)
semaphore m | (initially = 1)
semaphore t | (initially = 0) .

The program fragments are

ps: | P(m); bm:= bm - 1; bt:= bt + 1; Q;
| P(t); bt:= bt - 1; s:= s - 1; bm:= bm + 1; Q
vs: | P(m); s:= s + 1; Q

with Q being short for

Q: | if s > 0 and bt > 0 → V(t) ▯ bm > 0 → V(m) fi.

*              *
*

Next we have to investigate whether the alternative construct Q , with its guards as derived, can lead to abortion. On account of the invariant

| bt + bm = number of processes (> 0)

the falsity of the second guard —i.e. bm = 0— implies

| bt = number of processes (> 0) ;

if also the first guard is to be false we must, therefore, have s = 0 . In other words, all processes have performed the prefix of ps and the “semaphore” s equals zero. In the original set of sequential processes this situation would correspond to deadlock. Under the assumption that the original set of sequential processes is free from the danger of deadlock, the danger of abortion in Q is absent.

Our next concern is the potential nondeterminacy of Q : when both guards are true, do we really not care which of the two alternatives is selected? I propose that we do care and wish to give absolute priority to the first alternative because not doing so would have two consequences, both of which I regard as unpleasant. Firstly it could delay processes in the middle of ps without any reason as far as the current value of s is concerned, and from a strategic point of view that seems hardly attractive. Secondly, the absence of such an unnecessary delay has been shown to have a logical significance for the prevention of individual starvation when the P- and V-operations have been implemented weakly —i.e. in a way that does not exclude unbounded overtaking— . Hence I propose to strengthen the second guard of Q with the negation of the first:

| (s = 0 or bt = 0) and bm > 0 → V(m) .

Note. The only effect of this way of strengthening a guard is the reduction —in this case even the removal— of nondeterminacy; it does not introduce the danger of abortion. (End of Note.)

I furthermore assume that we are not interested in deadlock detection (by abortion or otherwise): if the danger of deadlock is present in the original set of sequential processes, we allow exactly the same form of deadlock in our equivalent programs. That means dropping the term bm > 0 from the second guard. Thus our new (and last) Q becomes

Q:             | if s > 0 and bt > 0 → {s > 0 and bt > 0} V(t)
|  | ▯ s = 0 or bt = 0 → {s = 0 or bt = 0} V(m)
| fi

*              *
*

The last phase of our development is one of (more or less) systematic optimization. with our final Q the value of bm is no longer relevant; hence the statements modifying its value can be removed, and so can bm itself. Furthermore, by substituting Q we may be able to simplify its guards differently in the different substitutions. This can be done by associating an assertion with each component of the split binary semaphore. Such an assertion can be taken as postcondition of the corresponding P-operation, provided it is implied by the preconditions of all V-operations on that component (and for the component initialized at 1 also by the initial state). In the following annotation we shall not repeat all the time the general invariant s ≥ 0 and bt ≥ 0 .

Applying this process to vs we get (when using the precondition of V(m) from the above Q )

vs:         | P(m) {s = 0 or bt = 0};
| s := s + 1 { s = l or bt = 0} ;
| if bt > 0 → {s = 1 and bt > 0} V(t) .
|  | ▯ bt = 0 → {s = 0 or bt = 0} V(m)
| fi

Note. For the simplification of the guards we have used the general invariant s ≥ 0 . The precondition of V(m) has been weakened from bt = 0 to s = 0 or bt = 0 , i.e. the original one. (End of Note.)

Applying the same techniques to ps we get

ps:           | P(m) {s = 0 or bt = 0};
| bt:= bt + 1 {s = 0 or bt = 1};
| if s > 0 → { s > 0 and bt = 1 } V(t)
|  | ▯ s = 0 → { s = 0 or bt = 0} V(m)
| fi
| P(t) {(s = 1 and bt > 0) or (s > 0 and bt = 1)};
| bt:= bt - l; s:= s - 1 {s = 0 or bt = 0};
| V(m)

Note. For the postcondition of P(t) we have chosen provisionally the disjunction of the preconditions of V(t) from vs and from ps , three lines higher. Since the second Q from ps now reduces to V(m) , we are done! (End of Note.)

We can further shorten the texts

1) | by moving the initial increases of s and bt into the alternatives
2) | by moving the three statements following the alternative construct in ps into both alternatives
3) | by replacing in the first alternative of ps           “bt:= bt + 1; V(t); P(t); bt:= bt - 1” by a skip
4) | by removing from the second alternative of ps the           “bt:= bt - 1; s:= s - 1” following the only P(t) left and inserting them in front of the only v(t) left
5) | by replacing in the first alternative of vs           “s:= s + 1; bt:= bt - 1; s:= s - 1” by “bt:= bt - 1”.

The result of these five successive transformations is

ps:     | P(m);
| if s > 0 → s:= s - 1 ▯ s = 0 → bt:= bt + 1; V(m); P(t) fi
| V(m)

vs:       | P(m);
| if bt > 0 → bt:= bt - l; V(t) ▯ bt = 0 → s:= s + 1; V(m) fi

We can shorten our texts still further by first introducing a redundant variable k satisfying

| k = s - bt

a relation that we can keep invariant by inserting into ps: k:= k - 1 and into vs: k:= k + 1 . The values of the guards can then be derived from k , and after removal of the then redundant s and bt we get

ps:         | P(m); k:= k - 1;
| if k ≥ 0 → skip ▯ k < 0 → V(m); P(t) fi;
| V(m)
vs: | P(m); k:= k + 1;
| if k < 0 → v(t) ▯ k > 0 → V(m) fi

Acknowledgment. The presentation of the last transformation is the result of a considerable improvement suggested by A.J.Martin. (End of Acknowledgment.)

Concluding remarks. Firstly I would like to stress that our discovery of the assertion to be associated with component t was just a stroke of luck. If the last Q of ps had not reduced to V(m) and the strongest precondition for the remaining V(t) would have failed to imply the assumed assertion for component t , we would have been in trouble; the assertion has then to be weakened. Apart from this piece of luck, that part of the derivation is entirely satisfactory.

I am less satisfied with the final transformations. They are trivial and easily performed with pencil and rubber or with chalk and eraser. They are, however, most laborious to record in written form. I leave to my reader the choice where to put the blame: on the whole approach that calls for the transformations or on the constraints of the written word. (End of Concluding Remarks.)

Plataanstraat 5 | 11 April 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-02 .

EWD735

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A mild variant of Combinatory Logic.

The following is written in reaction to the description of Combinatory Logic as given in [1] by D.A.Turner. With plus standing for the prefix adding operator, Turner defines the successor function suc by

| def suc x = plus 1 x .

To the right of the equality sign, juxtaposition is assumed to be associative to the left; more fully bracketed we would have had

| def suc x = (plus 1) x .

Because at both sides of the equality sign, the variable x occurs only as the very last atom, we can abstract x from both sides by omission, yielding def suc = plus 1 .

This wouldn’t have been possible if suc had been defined by

| def suc x = (plus x) 1

because here the right-hand side is not an expression in which x —i.e. the variable to be abstracted from— occurs only as the very last atom.

Combinatory logic is a discipline for rewriting, if necessary, such right-hand sides in such a way that X —or, in general: the variable to be abstracted from— only occurs as the last atom of the expression. Given

| def f x = E

we derive a G , such that

| G x = E (Law of Abstraction)

from which “by omission” then follows.

Turner denotes G by [x]E or by ([x]E) —to be pronounced as “abstract x from E”— and describes (following Curry) abstraction as a textual operation. I almost quote from [1] —remember that juxtaposition associates to the left, at least at both sides of the equality sign— “We introduce three combinators S , K, and I [It is customary to print these constants in bold face, EWD] , defined by the equations

| S f g x =f x (g x) | (S)
| K y x = y | (K)
| I x = x | (I)

and define abstraction as follows

| [x](E1 E2) = S ([x]E1) ([x]E2)
|  | [x]x = I
|  | [X]y = K y

where y is a constant or a variable other than x . That the abstraction thus defined obeys the Law of Abstraction given above can be proved by an induction on the size of the combination E — we leave this as an exercise for the interested reader.”

After having pointed out that this abstraction process leads to very long-winded formulae, Turner introduces for brevity’s sake two extra combinators B and C , defined by

| B f g x = f (g x) | (B)
| C f g x = f x g ; | (C)

please remember the left-associative juxtaposition: we could have written

| ((C f) g) x = (f x) q.

*              *
*

So much for Turner’s description of combinatory logic. His notational conventions have the (potential) technical advantage that each formula can be represented by a binary tree with labels —combinators or identifiers— in its leaves.

I found the fact that during the abstraction process combinators and identifiers (for variables) are treated on the same footing more confusing than illuminating. As it stands, the abstraction process also defines how to abstract a combinator from an expression; perhaps somewhat rashly I regard this, however, as a rather meaningless facility.

Note. Not only some abstractions, but also some applications should be regarded as meaningless. I owe to C.S.Scholten the following very nasty example. From

| def funny x = x x

we derive according to the rules

| x x = S I I x

hence

| def funny = S I I .

How well-deserved the name “funny” is is demonstrated by applying it to itself and reducing:

| funny funny=S I I (S I I) =
| I (S I I) (I (S I I))=
| S I I (S I I) = funny funny .

The expression (funny funny) is endlessly reducible! (End of Note.)

I was also disturbed by the extreme asymmetry introduced by the combination of a) the placing of the combinators and b) the association to the left. This is particularly noticeable in the fully bracketed form of rule (S):

| ((S f) g) x = (f x) (g x)

To the right we have two expressions, both containing the variable x . The combinator S , though pertaining in a way to both, is placed as a prefix to the left-hand one. My gut feeling —which of course may err— tells me that this is ugly.

Note. It could be argued that application is not only asymmetric —in general “a b ≠ b a”— but that the two components are very different, being “function” and “argument” respectively. But two remarks are in order.

Firstly, the distinction between “function” and “argument” is not as clear-cut as is often thought. with z standing for a complex number and re(z) and im(z) standing for its real and imaginary parts respectively, we could regard re and im as real functions defined on a complex domain. With z as a record with two fields we would write z.re and z.im respectively, i.e. a complex value can be regarded as a real function on the domain {re, im}.

Secondly, it is exactly combinatory logic that allows expressions for a and b , such that “a b” and “b a” , though different, are extremely meaningful. (See below.) (End of Note.)

A third complaint only emerged when exercising it. While abstracting and applying I found myself all the time adding and removing bracket pairs. This is not to be wondered at: when we look at the S-rule in its fully bracketed form, it is not clear at all, how the bracket pairs to the right and to the left correspond with each other.

So I set myself the goal of finding an equivalent notation to which the above objections would not apply. Most of the exploratory work was done together with C.S.Scholten; the synthesis to be described below emerged on 8 April 1980 in a session of the Tuesday Afternoon Club, which screened the manuscript for what follows a week later.

*              *
*

In the following there is no such thing as association from the left, and I shall introduce no redundant or optional bracket pairs. My starting point is the set of fully bracketed expressions, satisfying the syntax

| < exp > ::= < identifier > | (< exp > < exp > ) .

I shall not introduce the need to abstract a variable from an expression in which that variable does not occur. The formal definition for occurrence is the following obvious one: with x and y standing for identifiers and E, E1, and E2 standing for expression, we define

| x in E = if E = y → x = y
|  |  | ▯ E = (E1 E2) → (x in E1) or (x in E2)
|  | fi .

We shall now define how to abstract an identifier x from an expression E , provided x in E . We shall do so by defining abstraction from a more general class than just expressions, viz. “terms”. While expressions are built from parentheses and identifiers only, terms may also contain so-called combinators; a term may also be empty. In the following coms stands for a possibly empty sequence of combinators, and coms+ for a non-empty sequence of combinators. The syntax for terms is (see, however, correction below, originally on the next manuscript page)

| < term > ::= < empty > | < exp > | (< term > coms+ < term > ) .

Correction. The syntax for < term > as given previously is too restrictive: according to it the above ((T1 coms+ T2) h) is not a term! The syntax

| < term > ::= < empty > | < exp > | ( < term > coms < term > )

is too broad; it is acceptable provided we rule out from the last alternative the forms (), ( < term > C), and (B < term >-) , or state the non-occurrence of such terms as a theorem. See previous note. (End of Correction.)
NB. See Appendix on page EWD735 - 8, etc.!!!!!

Note that each bracket pair always surrounds two terms, separated by a possibly empty sequence of’ combinators, such that neither of the terms is empty or the combinator sequence is non-empty. I shall not introduce the need to abstract a variable from a term in which that variable does not occur; with furthermore T , T1 , and T2 standing for terms, we define

| x in T = if T = empty → false
|  |  | ▯ T = E → x in E
|  |  | ▯ T = (Tl coms+ T2) → (x in Tl) or (x in T2)
|  | fi .

Provided x in T , “abstract x from T ” —as usual denoted by “[x]T”— is defined by

| [x]T = if x in T | 0.
|  |  | if T = x → empty | 1.
|  |  |  | ▯ T = (Tl coms T2) → | 2.
|  |  |  |  | if x in Tl → | 3.
|  |  |  |  |  |  | if x in T2 → ([x]T1 S coms [x]T2) | 4.
|  |  |  |  |  |  |  | ▯ non x in T2 → ([x]T1 C coms T2) | 5.
|  |  |  |  |  |  | fi | 6.
|  |  |  |  |  | ▯ non x in Tl → {x in T2} | 7.
|  |  |  |  |  |  | if T = (T1 x) → Tl | 8.
|  |  |  |  |  |  |  | ▯ T ≠ (Tl x) → (Tl B coms [x]T2) | 9.
|  |  |  |  |  |  | fi
|  |  |  |  | fi
|  |  | fi
|  | fi

Notes. The guard in line 8 is only true if come is the empty sequence of combinators and T2 = x . This line represents the only case in which an original bracket pair disappears. No new bracket pairs are introduced; hence, the resulting bracket pairs are a subset of the original ones. Line 8 describes “abstraction by omission” .

Because in line 2 coms = < empty > implies that neither T1 nor T2 is empty, line 4 represents the only possibility of generating a bracket pair containing a single atom: (S) . Therefore, in line 8 T1 is not empty. (End of Notes.)

A reduction rule is applicable whenever we encounter a term of the form

| ((T1 coms+ T2) h) ;

in view of the rule of the absence of redundant parentheses this implies that h is not the empty term. The nature of the reduction is determined by the leading combinator of coms+ :

| ((T1 S coms T2) h) = ([T1 h] coms [T2 h])
| ((T1 C coms T2) h) = ([T1 h] coms T2)
| ((T1 B coms T2) h) = (T1 coms [T2 h])

where [T h] is short for

| [T h] = if T= < empty > → h ▯ T ≠ < empty > → (T h) fi .

Like Turner I leave the verification that

| [[x]T X] = T             (Law of Abstraction)

as an exercise for the interested reader.

Note. We have already observed that in a term derived by abstraction from an expression and of the form (T1 S T2) both T1 and T2 may be empty. If it is of the form (T1 B T2), T1 will not be empty; if it is of the form (T1 C T2), T2 will not be empty. As a result, reduction will never lead to a redundant bracket pair. (End of Note.)

*              *
*

Of course the new notation doesn’t rule out anomalies like funny. We would have

| def funny = (S) .

According to the new rules we find in a single reduction step —the intermediate stage with the square brackets has only been given for the sake of completeness—

| ((S)(S)) = ([(S)][(S)]) = ((S)(S)) .

As another example we consider the function twice , given by

| ((twice f) x) = (f (f x)) , hence
| (twice f) = (f B f) , hence
| twice = (SB)

and similarly the function thrice , given by

| ((thrice f) x) = (f (f (f x))) , hence
| (thrice f) = (r B (F B f)) , hence
| thrice = (SB (SB))

Now we consider and reduce as far as possible

| (thrice twice) = ((SB (SB)) twice)
|             = (twice B (twice B twice))
|             = ((SB) B ((SB) B (SB)))

Hence

| ((thrice twice) f) = (((SB) B ((SB) B (SB))) f)
|             = ((SB) ((SB) (f B f)))
|             = ((SB) ((r B f) B (f B f)))
|             = (((f B f) B ( f B f)) B ((f B f) B (f B f))) .

Hence (((thrice twice) f) x) = (f (f (f (f (f (f (f (f x)))))))) i.e. f⁸(x) —where I placed the brackets in the traditional fashion!—

As a final example, consider E = ((* ((+ x) y)) y)
I then derive without further intermediate results

| [x]E = ((* B (+ C y)) C y)
| [y][x]E = ((* BB (+ BC)) SC)

In Turner’s style we would have had E = * (+ x y) y .
In that case I had to derive

| [x]E = C [x](* (+ x y)) y
|         = C (B * (C [x](+ x) y)) y
|         = E (B * (C + y)) y .

(Actually I had one intermediate step more.) Skipping the intermediate steps I found

| [y][x]E = S (B C B (B *) (C +)) I , or fully bracketed —almost fully, that is—
|         = (S ((((B C) B) (B *)) (C +))) I

*              *
*

The difference between the two techniques is clearly that I propose to attach strings of combinators to internal nodes of the parse tree; the other convention expands the binary tree and stores the information of the strings of combinators in the leaves thus created. I haven’t learned yet, how to translate trees of the one type into trees of the other type. I cannot escape the impression that Curry’s conventions for “tree expansion” are in some sense more arbitrary than the conventions I have explored here.

Another moral of the story is that “Currying” as introduced by Turner is from a logical point of view no more than another red herring. Why replace “x + y” first by ’plus x y“, when we can parse these formulae as ”(x +) y“ and ”(plus x) y“ ? The only justification is that [x](plus x) = plus is shorter than [x](x +) = (C I) + —according to Curry/Turner— or (C +) —according to the conventions explored here— : in short, no more than a minor optimization if we assume that x is more frequently abstracted from (X +) than + .

I have the feeling that the above explorations should be continued.

NB. Appendix on the next pages!!! (End of NB.)

Plataanstraat 5 | 23 April 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstre
The Netherlands | Burroughs Research Fellow

Appendix. (Written after the above had been read together with C.S.Scholten.)

A first remark is that we can simplify the abstraction process as described on page EWD735 - 4 by replacing the alternative construct on lines 8, 9, and 10 simply by (T1 B coms [X]T2) . Cleaning things up we get

| [x]T = if x in T → | .0
|  |  | if T = x → empty | .1
|  |  |  | ▯ T = (Tl coms T2) →
|  |  |  |  | if x in T1 and x in T2 → ([x]Tl S coms [x]T2)
|  |  |  |  |  | ▯ x in Tl and non x in T2 → ([x]T1 C coms T2)
|  |  |  |  |  | ▯ non x in Tl and x in T2 → (T1 B coms [x]T2)
|  |  |  |  | fi
|  |  | fi
|  | fi .

From a theoretical point of view, this has two advantages. Firstly, the bracket pairs in the resulting term are now the same bracket pairs that occurred in the original term. Secondly, “abstraction by omission” has now been confined to line 1 , and in (T1 coms T2) the constituent terms T1 and T2 are treated on equal footing. Line 8 in the original version is no more than saving symbols at the price of symmetry, and that is at this level of discussion a doubtful procedure.

A more important remark is that my correction on page EWD735 - 5 was a short-sighted patch. We should have defined the syntax for terms independently of that for expression, viz.

| < term > ::= < empty > | < identifier > | ( < term > coms < term >) .

This syntax does not rule out redundant bracket pairs. When we now define ”T is healthy“ to mean:

| T is empty or
| T is an identifier or
| T is of the form (T1 coms T2) such that
|  | (T1 ≠ empty or ooms contains an S or a C) and
|  | (T2 ≠ empty or come contains an S or a B and
|  | T1 and T2 are both healthy

we can observe to start with that each expression is a healthy term. Furthermore no healthy term contains a redundant bracket pair —Either of the form “()” or of the form “((...))”— .

Furthermore —both in the original form of abstraction and in the cleaned up one— a healthy T implies (when defined) a healthy [x]T . Furthermore , for healthy T and healthy, but non-empty h , [T h] as defined on page EwD735 - 5 is healthy. In short, neither abstraction nor reduction ever introduces an unhealthy term!

Salvo errore et omissione, the above does the job. By the time that we have discovered the significance —if any— of our exercise, this text has to be rewritten anyhow; hence I think that this rough “working document” has reached the stage to be concluded. Besides that, I am tired.

*              *
*

At this stage it is very hard to formulate my acknowledgments. I am indebted to D.A.Turner for his article, to Hamilton Richards for having drawn my attention to it; I am greatly indebted to C.S.Scholten for joining me in my effort to understand combinatory logic in my way: his assistance in all stages of the development has been invaluable; I am indebted to the members of the Tuesday Afternoon Club for their help and criticism. The initiative and the errors are mine.

| (End of Appendix.)

[1] Turner, D.A., “A New Implementation Technique for Applicative Languages.” Software—Practice and Experience, Vol.9, 31-49 (1979).

Plataanstraat 5 | 6 May 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-05 .

EWD736

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

Recording the structure of trees in their leaves.

The following results are by no means new. I found the result for the binary tree in the late fifties; the result for the general tree —or something very similar to it— was discovered in the late sixties by C.S. Scholten and, if I remember correctly, by D.T. Ross as well. The reasons for writing this short note are twofold. Firstly, with a renewed interest in trees I realized that I had never seen the results properly recorded — they may be somewhere in Knuth's encyclopedia!—; secondly, thanks to a recent remark by C.S. Scholten I now understand them much better than before.

Offspring of the results are the following theorems.

Theorem 1. Consider for positive integer n the values R(n) given by

| r(1) = 1
| r(n) = the sum of all products r(i) * r(j), such that i + j = n with 0 < i, j < n.

Then r(n) < 4n. (Note that r(n) equals the number of rooted trees with n leaves such that each internal node has exactly two outgoing arrows).

Theorem 2. Consider for positive integer n the values R(n) given by

| r(1) = 1
| r(n) = the sum of all products r(i) * ... * r(j), such that i + ... + j = n with 0 < i, ..., j < n.

Then r(n) < 6n. (Note that r(n) equals the number of rooted trees with n leaves such that each internal node has atleast two outgoing arrows).

*              *
*

For a tree that is not a leaf so-called "traversal order" of its leaves is recursively defined as the traversal orders of the leaves of its subtrees dealt with in the order of those subtrees, e.g.

We shall characterize the structure of the trees by attaching to each leaf a label from a finite alphabet and listing those labels in traverse or order. The stated theorems follow from the fact that —as we shall show— for binary and the general rooted tree labels from a four-character alphabet in a six-character alphabet respectively suffice.

The labels serve two purposes. Firstly, they have to define which nodes —leaves to start with— are "sons" of the same "father". Secondly, because only labels of leaves have been given, the label of a father will be defined by the labels of its sons. (Regretfully enough, we cannot avoid also attaching an irrelevant label to the root of the tree.)

Each internal node has one so-called "first son" and so-called "last son"; it may have "middle sons". (In our example: 0,1,3, and A are first sons; 2,5,7, and B are middle sons; 4,8,10, and C are last sons.) In order that the labels determine which nodes —leaves to start with— are sons of the same father, we shall attach distinct labels to first sons, to middle sons, and to last sons. Because the middle son may be missing, the labels of the first and last sons of a father must determine the father's label.

With x possibilities for a first son's label and y possibilities for a last sons label, and an arbitrary label for the father, we conclude the requirement

| x * y ≥ size of the alphabet. | (1)

For the binary tree —no middle sons— the distinction between first and last sons requires

| size of the alphabet ≥ x + y | (2)

Relations (1) and (2) can be solved for size = 4.
For the general tree, in which we attach to each middle son the same label, we have instead of (2)

| size of the alphabet ≥ x + 1 + y | (3)

Relations (1) and (3) can be solved for size = 6.

The following codings show that these alphabet sizes indeed suffice.

For the binary tree we represent each label by the pair (b,c) with 0 ≤ b,c ≤ 1. A father with label (b,c) has

| a first son with label (0,b)
| a last son label (1,c)

i.e. distinct labels that satisfy stated inequalities.

For the general tree we represent each label by the pair (b,c) with 0 ≤ b ≤ 1 and 0 ≤ c ≤ 2. A father with label (b,c) has:

| a first son with label (0,b)
| zero or more middle sons with label (0,2)
| a last son with label (1,c),

i.e. distinct labels that satisfy stated inequalities.

Plataanstraat 5 | 21 April 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-05 .

EWD737

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A notational alternative for quantification.

In the following I restrict myself as usual to (beginnings of) countable domains; booleans and (enough) integers will do.

The so-called universal quantification is given by:

| (A i: 0 ≤ i < 0: B(i)) = true
| (A i: 0 ≤ i < n+1: B(i)) = (A i: 0 ≤ i < n: B(i)) and B(n) .

The so-called existential quantification is given by:

| (E i: 0 ≤ i < 0: B(i)) = false
| (E i: 0 ≤ i < n+1: B(i)) = (E i: 0 ≤ i < n: B(i)) or B(n) .

Augustus de Morgan's Law

| non (E i: 0 ≤ i < n: B(i)) = (A i: 0 ≤ i < n: non B(i))

is easily proved by mathematical induction.

*              *
*

Quite a few years ago the above notations inspired another one, which I found under circumstances indispensable. It denotes a natural number, viz. the number of different values of i in a range such that B(i) holds. Its recursive definition is

| (N i: 0 ≤ i < 0: B(i)) = 0
| (N i: 0 ≤ i < n+1: B(i)) = if non B(n) → (N i: 0 ≤ i < n: B(i))
|  |  | ▯ B(n) → (N i: 0 ≤ i < n: B(i)) + 1
|  | fi .

Let us call it "the quantified count". Once the quantified count has been introduced, we don't need the universal and existential quantifiers anymore. They can be defined in terms of the quantified count:

| (A i: 0 ≤ i < n: B(i)) = ((N i: 0 ≤ i < n: non B(i)) = 0)
| (E i: 0 ≤ i < n: B(i)) = ((N i: 0 ≤ i < n: B(i)) ≥ 1) .

We leave the proof that our new definitions are equivalent to our earlier ones as an exercise for the interested reader.

One advantage of the new notation is that Augustus de Morgan's Law becomes extremely simple. Omitting for shortness sake the ranges —and indicating this omission by a succession of two colons— it becomes

| (non (N i:: B(i)) ≥ 1) = ((N i:: B(i)) =0) ,

a relation that follows directly from the fact that a quantified count is a natural number.

All this was discovered quite a few years ago; I remember that it raised a mild suspicion that the introduction of two quantifiers where one quantified count would have done had perhaps been a notational mistake. In the meantime I encountered some more food for that suspicion.

*              *
*

The introduction of the universal and existential quantifiers reflects in two ways a doubtful practice. The minor complaint is that it is wasteful to introduce two special characters —in print they appear as inverted, bold, sans-serif A and E , respectively— when, in addition, we then need Augustus de Morgan's Law (1) to remind us that the one is only the negation of the other.

(In this connection it might be worthwhile to point out that in the boolean domain the "operation" of negation may be regarded as trivial in the sense that you cannot determine a boolean value x without determining the value of non x as well. In the integer domain you cannot determine a value x by determining a value y such that x ≠ y ; in the boolean domain you can!)

I called this a minor complaint: for the sake of brevity some redundancy in special characters may be defended. (This admission is not to be construed as a carte blanche from my side for the notational immodesty that some of our less wise mathematicians indulge in.) The major complaint is the introduction of a special notation for what seems at first sight an arbitrary dichotomy. Is for natural numbers the dichotomy in "equal to zero" versus "at least one" really the only meaningful one?

Of course it isn't. In the mathematical literature one finds the existential quantifier sometimes adorned with an exclamation mark to indicate the existence of exactly one value of i such that B(i), i.e.

| (E! i:: B(i)) = ((N i:: B(i) = 1) .

I do not know who introduced that exclamation mark —no doubt his name can be found in Florian Cajori's "A History of Mathematical Notations"— ; the introduction of such specific notational gadgetry is of course a road sign saying "Blind Alley".

Of this I made a mental note when I decided to let the matter rest until I had encountered the need for more other dichotomies. Yesterday's experience prompted the writing of this note. During my lectures, when applying the Gries-Uwicki Theory to a solution to the mutual exclusion problem between two processes, I derived the invariant

| non luck(0) or non luck(1) | (x)

or, in the notation used above

| (E i: 0 ≤ i < 2: non 1uck(i)) . | (y)

When my lectures were over and I walked back to my room I realized that the analogous relation after generalization from 2 to n processes would not be

| (E i: 0 ≤ i < n: non luck(i))

but

| (N i: 0 ≤ i < n: luck(i)) ≤ 1 ,

and that is a formula of a very different nature! In retrospect, formula (x), which suggests formula (y) so strongly, should be regarded as a notational trap (into which I duly fell).

Finally I ask my readers to savour the expression —in which the ranges have again been omitted—

| (N x:: (N i:: P[i] = x) ≠ (N j:: Q[j] = x)) = 0 ,

expressing that the finite sequence represented by array P is a permutation of the one similarly represented by array Q . Rendered in English it would be something like "No value occurs different numbers of times in P and Q , respectively.".

Without thus paraphrasing it I gave the above formula to a few mathematicians to stare at; they all knew the notation of the quantified count —I had used it before— but were by an accident of history more familiar with the universal and existential quantifiers. One of them needed a surprisingly long time to come to grips with it: one of his problems seemed to be to realize that a value occurring in neither of the two sequences occurs in both an equal number of times, viz. zero. The explanation may be that he had his original training in the Department of Mathematics in Nijmegen, and there —I recently learned— the natural numbers still start at 1 !

Note. There are two reasons why it is stupid to define the natural numbers as {1, 2, 3, 4, ....} instead of as {0, 1, 2, 3, ....}. Firstly, we already have a perfect name for the set {1, 2, 3, 4, ....}, viz. the set of positive integers. Secondly, by excluding zero from the natural numbers it becomes "unnatural", and the fact that for many the number "zero" is still a second-grade citizen is a standard stumbling block in mathematical thinking. In this case the situation is aggravated because, the University of Nijmegen being a Roman Catholic one, the term "unnatural" is there loaded with more pejorative connotations than elsewhere. (End of Note.)

The writing of the above was a pleasant —and I think fully appropriate— way of spending the day of the Abdication of Queen Juliana and the Coronation of Queen Beatrix. The weather is much nicer than predicted and I trust to become as grateful for her reign to Queen Beatrix as I am to who is now Princess Juliana again. The writing and subsequent typing of the above took me five hours; I consider them well-spent.

Plataanstraat 5 | 30 April 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-11 .

EWD738

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

More mathematical folklore.

| "Fermat's general method, that of "infinite descent", is profoundly ingenious, but has the disadvantage that it is often extremely difficult to apply." E.T.Bell in "The Development of Mathematics" (1945)

The purpose of this debunking note is to expose a few time-honoured mathematical concepts as mere artefacts of an unfortunate notation. The unfortunate notation writes non A ≥ C or non C ⇒ A instead of the symmetric disjunction A or C .

The indirect proof.

Mathematicians call a proof of the theorem A ⇒ B "indirect" when, instead of proving A ≥ B "directly", one proves non B ⇒ non A . But you cannot prove the one without proving the other: both are equivalent to non A or B . The distinction is void.

The reductio ad absurdum.

With C and non C as the prototype of a contradiction —an "absurdity"— the reductio ad absurdum proceeds as follows. In order to prove A

0) | one proves | non A ⇒ C
1) | one proves | non A ⇒ non C
2) | one concludes | non A ⇒ (C and non C) , hence A .

But, apart from notation, the above proof must be equivalent to

0) | proving | non C ⇒ A
1) | proving | C ⇒ A
2) | concluding | (C or non C) ⇒ A , hence A .

In so-called contrast to the first proof the latter one is called "a proof by case analysis"! The distinction is void. I prefer

0) | proving | A or C
1) | proving | A or non C
2) | concluding | A

Mathematical induction.

I was taught two patterns for mathematical induction.
Pattern 1:

1.0) | prove P(0) | ("the base")
1.1) | prove (A n: n ≥ 0: P(n) ⇒ P(n+1)) | ("the induction step)
1.2) | conclude (A n: n ≥ 0 P(n)) |

Pattern 2:

2.1) | prove (A n: n ≥ 0 (A i: 0 ≤ i < n: P(i)) ⇒ P(n))
2.2) | conclude (A n: n ≥ 0: P(n))

The following are comments on the way in which I was introduced to them— a way that, I am afraid, is rather standard.

Pattern 1 , which regretfully is the better known one, was postulated and by renaming, substitution, and simplification pattern 2 was derived from it.

My first complaint is that no one pointed out to me that the two are equivalent, i.e. that by suitable renaming, substitution, and simplification the validity of pattern 1 can again be derived from the postulated validity of pattern 2.

My second complaint is that no one ever pointed out to me that the transition from pattern 1 to pattern 2 represents an obviously permissible strengthening of the induction hypothesis, thereby offering the opportunity for a simpler proof obligation.

My third complaint is that no one pointed out to me that for given P pattern 2 is in a sense canonical because the transition from 1 to 2 is idempotent. The moral of the story is that pattern 2 should always be preferred.

Fermat's "infinite descent" consists of proving (A n: n ≥ 0: P(n)) by showing that the assumption non P(n) leads to the existence of a natural value i < n , such that non P(i) , which then leads to a contradiction.

I quote from E.T.Bell again —but this time from his "Men of Mathematics"— "His own account is both concise and clear, so we shall give a free translation from his letter of August, 1659, to Carcavi.

"For a long time I was unable to apply my method to affirmative propositions, because the twist and the trick for getting at them is much more troublesome than that which I use for negative propositions. Thus, when I had to prove that every prime which exceeds a multiple of 4 by 1 is composed of two squares, I found myself in a fine torment. But at last a meditation repeated many times gave me the light I lacked, and now affirmative propositions submit to my method. The course of my reasoning in affirmative propositions is such: if an arbitrarily chosen prime of the form 4n+1 is not a sum of two squares, [I prove that] there will be another of the same nature, less than the one chosen, and [therefore] next a third still less, and so on. Making an infinite descent of all the numbers of this kind I arrive at the number 5, the least of all the numbers of this kind [4n+1]. [By the proof mentioned and the preceding argument from it], it follows that 5 is not a sum of two squares. But it is. Therefore we must infer by a reductio ad absurdum that all primes of the form 4n+1 are sums of two squares." "

But what is Fermat's proof obligation? With

| P(n): the n-th prime of the form 4k+1 is the sum of two squares

he has to prove

| (A n: n ≥ 0 : non P(n) ⇒ (E i: 0 ≤ i < n: non P(i))),

but this is identical to 2.1: both are

| (A n: n ≥ 0: (E i: 0 ≤ i < n: non P(i)) or P(n)).

Hence Fermat's method of "infinite descent" is nothing but normal mathematical induction in its easiest form. It doesn't deserve a special name and E.T.Bell's appreciation of it as quoted at the beginning of this text is all rubbish.

Plataanstraat 5 | 1 May 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-16 .

  EWD 739

A somewhat open letter to the Editor-in-chief of Acta Informatica.

Dear Professor Paul,

      please do not interpret this letter as a request to revoke the rejection of our paper "Termination detection for diffusing computations": editors are free to decide. We are just sending you some of our comments on the reports from the referees.

      Referee A seems to complain about the inclusion of a proof of the correctness of our solution. This is, in general, a very odd complaint, since the absence of a correctness proof would have been a more valid ground for objection. In this particular case the complaint is still more amazing, since the structure of the proof is the central theme of our paper. By considering this topic inappropriate for a scientific journal such as Acta Informatica he almost insults its readership.

      The technical "criticism" of referee B boils down to the remark that inadequate implementations of our scheme might fail to display the desired behaviour. He blames us for the absence of implementation details, which are, however, irrelevant to the quintessence of our scheme. We have, for instance, intentionally left unspecified whether messages and signals are transmitted instantaneously or may "crawl", since —in contrast to other designs— our scheme may be implemented under either circumstance. To provide the additional synchronization that would be required if buffers are bounded and to derive the minimum buffer sizes then required for the absence of deadlock is a problem we have intentionally left out: firstly, it is not the subject of this paper, and secondly, it is trivial because its solution is absolutely standard. We believe to have used the well-known device of abstraction to good advantage.

*               *
*

      We do not pretend that our paper is without shortcomings. On the contrary, after the 15 months (!) that the refereeing of our paper (of less than 2000 words) has taken, we ourselves would like to rephrase at least one sentence. The paper has been tersely written —perhaps even too much so— and must be hard to read for those that erroneously assume half of the sentences to be noise. One thing is certain: the suggestion, made by both referees, that this paper could be improved by severe condensation is ridiculous.

      Please transmit our comments to the referees; two additional copies of this letter have been included for your convenience.

      With our greetings and best wishes,

yours sincerely

prof.dr.Edsger W.Dijkstra
Burroughs
Plataanstraat 5
5671 AL NUENEN
The Netherlands
drs.C.S.Scholten
Philips Research Laboratories
5656 AA EINDHOVEN
The Netherlands

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

EWD740 - 0

A short proof of one of Fermat's theorems.

Consider the np distinct "words" of p "characters" that can be formed from an "alphabet" of n distinct characters. Draw from each word an arrow to the word that is obtained by rotating its characters over one place to the left, i.e. from n₀, n₁, ..., np-1 an arrow is drawn to n₁, ..., np-1, n₀ . Because p successive rotations transform a word into itself, the arrows form cycles of lengths that are divisors of p.

Hence, if p is prime, 1 and p are the only possible cycle lengths. Because a cycle of length 1 corresponds to a word all characters of which are equal, exactly n distinct words occur in a cycle of length 1. Hence the remaining np-n words occur in cycles of length p, i.e. for any n and any prime p, np-n is a multiple of p.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 27 May 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD 741

Partitioning the edges of the complete graphs into trees or cycles.

by the Tuesday Afternoon Club

The k(2k-1) edges of the complete 2k-graph can be partitioned into k subspanning trees. We demonstrate the construction for 2k=8:

[picture] | the three remaining trees are obtained by successive rotations over π/4.

The k(2k+1) edges of the complete (2k+1)-graph can be partitioned into k subspanning cycles. We demonstrate the construction for 2k+1=9:

[picture] | the three remaining cycles are obtained by successive rotations over π/4.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 27 May 1980 prof. dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD742 - 0

A sequel to EWD740

For some p we define "rings" as circular arrangements of the numbers from 0 through p-1. By "circular" we mean that rotation of an arrangement does not change the ring it represents (e.g. 02341 and 34102 represent the same ring). Obviously, there are (p-1)! different rings. From each ring we draw an arrow towards the ring one obtains when each number is increased by 1, mod p. Because a succession of p such transformations transforms a ring into itself, the arrows form cycles the lengths of which are divisors of p.

Hence, if p is prime, 1 and p are the only possible cycle lengths. Because a cycle of length 1 corresponds to a ring with a constant difference mod p between each number and its clockwise neighbour and that difference may range from 1 through p-1, exactly p-1 rings occur in a cycle of length 1. Hence, the remaining (p-1)!-(p-1) rings occur in cycles of length p, i.e. for any prime p (p-1)!-(p-1) is a multiple of p.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 30 May 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD743

A new policy for Mathematics Inc.?

As Chairman of the Board I must apologize for having called this meeting at such a short notice. I trust, however, that you will excuse us because without actually taking positive action we couldn’t have predicted the sudden death of Jean-Paul Sartre the usual three months ahead of time. His untimely death marks the end of existentialism, and as a company we shouldn’t close our eyes for the fact that this philosophical movement has been indispensable for the creation, maintenance, and extension of our market.

Right from its inception, Mathematics Inc. has known that the successful industrialization of the development of mathematics would be tantamount to the Second Cultural Revolution and the Third Industrial Revolution rolled into one. Moreover, Mathematics Inc. has always known Man’s general tendency to resist change even when it constitutes progress. We all know the great subtlety the selling of our products has required, and it is to the everlasting credit of our Sales Department, our Public Relations Department, our Publicity Department, and our Department of Educational Services that so many millions of customers could become fully dependent on our products without at the same time losing their feeling of human dignity. We should never underestimate the moral, cultural, intellectual, and philosophical stress to which the wholesale adoption of our products has subjected our more enlightened customers. The existentialist philosophy has been indispensable for the success of our company: during the emotionally difficult transition period it has provided our customers with the jargon that seemed to salvage the vestiges of personal initiative and individual responsibility. Sartre’s untimely death has drawn this period to a sudden close, and we are here to discuss the possible courses of action lest the subtle balance in the love-hate relation between the company and its customers shifts.

Let me repeat: our professional pride in the spectacular progress of mathematical technology is fully justified, but this pride will fail to save the company when the very success of our products rebounds on us. Already structuralism, which invests symbols with a mystical appeal similar to the one numerology once gave to numbers, provides our current (and future!) customers with a verbalization of the point of view that first and foremost depicts them as a product and even as a victim of modern technology. More than ever we have to face and fight the paradoxical situation in which the unavoidable mathematization of industry and the equally unavoidable industrialization of mathematics go hand in hand with violent anti-mathematical feelings in the substrate of our culture.

In this preliminary discussion I shall present you with two possible courses of action.

One of them is to face the problem squarely and call as loudly as possible attention to the main problem our culture faces, viz. the social impact of the mass production of cheap mathematics. The rough structure of the argument is clear: we depict the progress of technology as an autonomous force, and after having shown with enough examples from the past how progress of technology cannot be stopped, an appeal to “historical necessity” will do the rest. We build up the case that “society will have to learn to live with it”, and, from thereon, leave the soft scientists with the baby. In your evaluation I ask you to take into account the following factors.

Pro is the circumstance that by founding committees and sponsoring conferences Mathematics Inc can get relatively inexpensive publicity in which the sponsoring company will be presented as a socially responsible organization and more as an ally or potential saviour than as the villain in the piece.

Contra is the circumstance that, if the argument of the historical necessity is going to work, we have to dissociate our company from existentialism as quickly and as rigorously as possible. (Just in case we decide to need it, a 300-page booklet with maxims from Claude Lèvi-Strauss is in preparation for our sales force, and a series of two-day seminars has provisionally been planned for next month.) Contra is also the serious possibility that we cannot find enough soft scientists we can rely upon; in short, we face the danger that after a fully successful start the whole project will be messed up in its second phase.

Finally I would like you to know that, if this course of action is followed, a number of activities on a national scale in the different countries we operate in is deemed to be more effective than activities on an international level. In a situation like this, national activities have two great advantages. Firstly, by presenting it as a national problem, it is easier to make people “accomplices” of efforts at “solution”. Secondly, in each country the seduction can be tuned to the national needs as perceived by the respective citizens: in the industrialized world we can argue that mathematics is the technology of the future, since it uses no energy and causes no pollution, whereas in the developing countries we can promote mathematics as the cheapest and most effective way of developing, etc.

The second course of action is almost orthogonal to the first. (Taking both, however, is not excluded.) It would essentially be not to accept Sartre’s death and to continue to capitalize on existentialism and, since we are now “on our own” so to speak, to do so even more actively than we have done before. (Also for this course of action philosophical training material for our sales force is in preparation.) Whether this course of action can be recommended for the developing nations is still under investigation. In the industrialized world, however, we can promote the abundance of mass-produced cheap mathematics as The Great Equalizer. We can argue that prior to this breakthrough of mathematical technology insight, knowledge, and hence power, were the prerogative of the happy few from the upper class, whereas now the intellectual self-realization has come within the reach of all. In view of the diversity of J.-P. Sartre’s political views we can promote “Mathematics for Democracy” under all meanings of both terms; for a truly international company like Mathematics Inc., such multi-interpretability is an advantage that should not be underestimated. In evaluating this second course of action I ask you to take the following factors into account.

Pro is the circumstance that under the second course of action the company need not redesign its image. In our advertising we can stress the continuity of our tradition and the stability of our products, on which our customers can rely for many years without the danger of expensive conversions to meet problems of incompatibility between proofs of our whole range. Mathematics Inc. as the Solid Rock amidst the swift currents of fads and fashions, etc. For the company it avoids the need for extensive retraining of our personnel, since we can proceed as before, only much more so.

Contra is the risk that we underestimate the strength of the structuralist movement and that what we present as stability will be misinterpreted as inflexibility: our proofs may need more than just restyling in order to continue offering a timely product. I would like all of you to take into consideration that any policy that appeals to the older customer but fails to establish our company firmly in the minds of the younger generation is in the long run a dangerous policy.

As your Chairman I am looking forward to your considered opinions on the best policy to follow. I expect your recommendations to be conflicting, but such confusion should not disturb anyone. We should never lose our faith in the eternal Laws of Logic, and, hence, we should never lose our faith in what we have founded on them: Mathematics Inc. Semper floreat et crescat!

Hosanna Building
Plataanstraat 5
5671 AL NUENEN
The Netherlands
prof.dr.Edsger W.Dijkstra
Chairman of the Board of
Mathematics Inc.

transcribed by Bart Vreugdenhil
revised 02-Dec-2011

EWD744

NOTE: This transcription was contributed by Martin P.M. van der Burgt, who has devised a process for producing transcripts automatically. Although its markup is incomplete, we believe it serves a useful purpose by virtue of its searchability and its accessibility to text-reading software. It will be replaced by a fully marked-up version when time permits. —HR

A short note on symmetric distributed arbitration .

This is only a short note . Firstly, my problem is only partly solved; a pending holyday precludes a long note now. The results obtained so far, however, deserve recording.

We consider the classic mutual exclusion problem of N cyclic processes, each with its critical section and to be synchronised in such a fashion that at any moment at most one of the processes is engaged in its critical section. The equally classic solution employees one binary semaphore, traditionally called "mutex" and initialised at 1. Each of the processes can then be coded as follows

do true ⇒ P(mutex);
| critical section;
| V(mutex);
| non critical section;
od

Here the semaphore mutex is a synchronisation tool equally accessible to all processes; for that reason above solution is called "centralised"; as used, the semaphore mutex accomplishes N-fold arbitration. In this short note we occupy ourselves the problem of achieving N-fold arbitration when twofold arbitration between identified partners is the only available primitive.

The classic solution is as follows. Place each of the processes in a distinct node of the complete N-graph, and associate with each edge a binary semaphore. Each "critical section" is preceded by the N-1 P-operations on the binary semaphores associated with the edges meeting at the node in which the process in question is placed; the critical section is followed by the compensating V-operations.

All solutions of this form obviously ensure N-fold arbitration, since no two processes can be simultaneously engaged in their critical sections. The only remaining problem is to prescribe for each node the order in which the N-1 P-operations occur in such a fashion that the danger of deadlock is absent.

Note. Because each binary semaphore is accessed by two processes, it blocks at any moment at most one process. As a result the question doesn't arise which of the blocked process is allowed to complete this P-operation when the V-operation on it is performed. Furthermore, the fact that each semaphore blocks at most one process precludes the danger of infinite overtaking, and hence a solution which is free of the danger of deadlock is also free of the danger of individual starvation . (End of note.)

A very simple way of avoiding the danger of deadlock is the following. Assign to each edge a "rank" such that no two edges that have an endpoint in common have the same rank, and let each process complete the P-operations in order of increasing rank.

Note. The introduction of the ranks is no constraint at all. In every node of the order of the N-1 P-operations has been prescribed in such a way that the danger of deadlock is absent, ranks can be assigned to the edges in such a way that in each node the P-operation occur in the order of strictly increasing rank. The latter requirement imposes a total ordering on the ranks of the N-1 edges meeting at a node; the absence of the danger of deadlock implies that these N total orderings of subsets of N-1 edges are compatible. (End of note.)
added by the author in the margin: This note is wrong (17/10/80)

All of the above we knew for a long time, it only serves as an introduction for the following results.

*              *
*

Scholten's results. For each deadlock-free assignment of the edge ranks the number of different complete blocking states equals 2N-1. A complete blocking state is one in which one of the processes is engaged in its critical section while among the others no others no further arbitrations are possible.

Proof. Compete blocking state is characterized by the process in critical section and for each other process by the rank of the edge for which arbitration took place in its disfavour. By dealing with the edges in a fixed order of (weakly) ascending rank we can construct any complete blocking state by the following non deterministic algorithm.

A variable c is initialised with the set of all N nodes; we then deal with the edges in the fixed order. When we encounter an edge with both endpoints still in c, one of the two endpoints is removed from c, otherwise c is left unchanged; a node removed is tagged with the rank of the edge in question.

Because each edge has two different endpoints, c contains at least 1 node all through this execution of the above algorithm; because we process all the edges of the complete N-graph the execution terminates with at most 1 node in c. We conclude that execution terminates with exactly 1 node in c; this node identifies the one and only process in its critical section.

Because N-1 nodes have been removed from c, we have had N-1 binary choices; hence there are 2N-1 different complete blocking states possible. (End of proof.)

Corollary. No symmetric ranking exists or N is a power of 2.

Proof. With a symmetric ranking the number of complete blocking states with the same process in its critical section is independent of the identity of the latter process; in that case N is a divisor of 2N-1, i.e. N is a power of 2. (End of proof.)

*              *
*

Dijkstra's result. A symmetric ranking exists or N is not a power of 2.

Proof. The above is proved by constructing a symmetric ranking in the case that N is a power of 2. Number of the nodes from 0 through N-1. The digits of the binary representation of the rank of the edge connecting node x and y are defined as the sum mod 2 of the corresponding digits of the binary representation of x and y. Thus the ranks 1 through N-1 are assigned, and he N-1 edges meeting at a single node are all different rank. Renumbering the nodes by inverting in the binary representation of each node number the k-th digit does not affect the rank thus asssigned. Hence, given the ranks, any node can be regarded as node 0, and the ranking is therefor symmetric. (End of proof.)

Acknowledgement. With the aim of introducing the opportunity for recursive arguments, W.P. de Roever suggested to me to investigate first the situations in which N is a power of 2. (End of Acknowledgement.)

*              *
*

After having exchanged these two independently formed results, Scholten and I investigated the worst case delay possible with the symmetric ranking just described. We asked ourselves the following question. What is the maximum number of critical section traversals between the moment that a process has completed its noncritical section and the next completion of its critical section? In this investigation we made the weakest assumption that guarantees in individual progress when a process is blocked because of an arbitration decided in favour of a competitor, thar arbitration as inverted when that competitor leaves its critical section. For N = 2k that maximum number of traversals equals

| (P i: 0 ≤ i < k: 2i+1)

i.e. for N=2, 4, 8, 16, ... the maximum number of traversals equals 2, 6, 30, 270, ...

Consider, for instance, the case N = 16. The nodes can then be divided into two sets A and B of 8 nodes each such that the edges of rank ≤ 7 connect two nodes from the same set and the edges of rank ≥ 8 connect to nodes from different sets. Note that each of the two sets in isolation presents with its internal edges our standard ranking for the complete 8-graph. From a worst case history for set A in isolation —according to our induction hypothesis of length 30— we can construct for the 16-graph a history of length 9 * 30 = 270 by inserting in front of each traversal from A the eight traversals from B (each time in the proper order). It is not difficult to see that the resulting history represents a worst case history for the standard ranking off the complete 16-graph.

*              *
*

For N=2k we have investigated the standard ranking, which is a special way of assigning symmetrically the ranks from 1 to N-1 to the edges such that no two edges of the same rank have endpoint in common. How special is the standard ranking?

Select two distinct ranks p and q and travel from an arbitrary node V along the edges of ranks p and q alternatingly

| V____W____X____Y____Z
|       p         q         p         q

If the ranking is to be symmetric in nodes, the rank of VX equals that of XZ. Since only one edge of the rank ends in X, nodes V and Z are the same node! The edges of two ranks form cycles of length 4; its "diagonals" have a third rank. As a result, edges of afourth rank connect our 4-tuples pair-wise and edges of three other ranks pair our 4-tuples in the same fashion. Etc.

From this it follows that any symmetric ranking of the edges such that no two edges of the same rank have an endpoint in common must be a permutation of a standard ranking. With N=8 I investigated the maximum number of traversals for an essentially different ranking and found 32 instead of 30 for the standard ranking. At the time of writing I don't know whether the standard ranking gives rise to the best worse case behaviour.

Plataanstraat 5 | 13 July 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-03-16 .

EWD 745

Trip report E.W.Dijkstra, Los Angeles, Austin (Texas), and Portland, 6-28 August 1980.

With the exception of a half-day visit to prof. Misra and prof. Chandy of the University of Texas at Austin, this was entirely an industrial trip.

On Wednesday 6 August 1980 I flew from Amsterdam to Los Angeles to visit Hughes Aircraft Company.

On Friday 8 August I flew in the evening from Los Angeles to Austin, Texas, where I visited for two weeks the Burroughs Engineering Technology Center.

I left Austin on Saturday 23 August (very early in the morning) for Portland, to pay a visit to Tektronix and to address the local chapter of the IEEE.

On Wednesday 27 August I started my journey home (via Chicago). The next morning, while I was waiting for Immigration, the man that stood behind me in the queue saw in my passport that we lived in the same village; a Philips taxi was waiting for him at the airport and he offered me a lift, which was gratefully accepted. At 11:00 I was home. I brushed my teeth, and after two cups of coffee and a glass of sherry I went to bed. As far as transport was concerned I had travelled without problems: I had not been booked on non-existing flights and I had caught all my connections.

*         *         *

I had accepted the invitation from Hughes because my last contacts with the aircraft manufacturing industry were more than 25 years old. I came to satisfy my curiosity, and it was a definite disappointment when I learned upon arrival that, despite its name, Hughes Aircraft Company did not manufacture aircrafts. In other ways, however, the visit was sufficiently instructive not to regret it.

C.L.Nelson and J.M.Thompson from Hughes were at the Airport, recognized me without hesitation, and took me to my hotel, where I was offered dinner. I was, however, too tired and too much dried out to eat and had a few glasses of highly diluted whiskey while we discussed the next days' (heavy) schedule. And then: off to bed!

The next morning I had breakfast at 6:30 and was picked up at 7:15. As a guest of their "Communications and Data Processing Professional Development Seminar" I was supposed to give the same talk "Programming as a Battle against Unmastered Complexity" twice that day: at Fullerton from 9:00 till 11:00 (for an audience of 200) and at Culver City from 13:00 till 15:00 (for an audience of 225). At both sides the promised wall-to-wall blackboards were conspicuously absent. At Fullerton I had some 20 minutes to redesign my lecture, adjusting it to the constraints of the miserable overhead projector I had to make do with. The talk at Fullerton was an unadulterated disaster. Without any regard for acoustics, the organizers had chosen the largest room available: the cafeteria! Besides that they couldn't get the throat microphone working! In a very literal sense I reached at most one quarter of my audience. Reactions and questions from the floor were cruelly revealing: I was almost accused of unprofessional conduct because I had used identifiers of more than six letters, and I was asked whether I was "for or against the use of flowcharts". I felt subjected to the "time machine". In Culver City at least the throat microphone worked. The day ended with "Cocktails and Dinner with Key Hughes Computer Executives" in Marina del Rey. The food was good and the man sitting to my right was interesting.

The next day was spent discussing with the (newly formed!) "Hughes Corporate Software Engineering Committee". This was very illuminating: clearly several of its members hadn't the foggiest notion what programming was about and exactly one member displayed symptoms of a scientific attitude. The exposure offered a new explanation for the elaborate security measures.

In the course of the afternoon J.M.Thompson saw me to the airport. By the time that it was clear that he would rather discuss pet dogs than the future of his company, I suggested that he leave me to my fate (which was at the moment in the hands of Continental Airways).

*         *         *

The two weeks in Austin I was the guest of Dr. Hamilton Richards and his wife, and that was much nicer than staying in a hotel. I drove a Toyota Tercel (which I had been able to rent from Hertz without paying a deposit!): "a nimble car", though thanks to automatic gearshift and airconditioning almost without acceleration. The worst of the heatwave was over, but it was still warm enough (40�C in the shade). The first weekend we were expecting the hurricane Allen, but only a tornado, spawned by it, reached Austin.

The first week I was there together with Dr.David A.Turner of the University of Kent, who showed me unexpected possibilities of his programming language SASL. Besides collecting a few less trivial SASL programs —my first goal— I found a very nice example that should help me understand "progress" of such nonterminating nondeterministic computations —my second goal— . Finally —my third goal— I familiarized myself with the problem of garbage detection in SASL, but this was done with Dr.Richards during the second week, when Dr.Turner had left.

The first three days were spent in the conference room where our sessions were recorded on videotape, a "format" with which I was definitely unhappy. Thereafter we just worked and I felt much better. In retrospect I don't think it was the absence of the videotape that did it; more important was that we were with fewer people. A very important aspect of working together —and perhaps it is the most important one— is that people help and force each other to express themselves as adequately as possible. With J.M.Morris, whom I met in Portland, I checked my estimation that during sessions of the Tuesday Afternoon Club about 80 percent of our mutual comments are in this sense "linguistic", and it is probably that high percentage that makes the Tuesday Afternoon Club so effective. But neither Turner nor the people at Austin were used to such scrutiny, and the larger the crowd, the greater the danger that someone felt offended. And it was often precisely such scrutiny that they seemed to need more than anything else. (Admittedly, they are not the only ones to blame, since the computing literature does not set a very good example either. In C.J.Date's "An Introduction to Database Systems" I found within five minutes browsing the following horrible sentence:

"But if PHYSICAL is specified, the logical parent pointer in the prefix is conceptually redundant."

An area of human endeavour that produces such horrors is in bad shape indeed!)

During the second week Walt E.Feeser —the Austin manager and my "impresario"— had organized by way of experiment a two-and-a-half-day meeting where representatives from all over the company had been invited to present their greatest achievement and their greatest problem. It was a nice idea, but the experiment was not the success we had hoped. A number of last minute cancellations made the coverage less wide than intended, and most of the speakers —John McClintock from Mission Viejo was a notable exception— were not of the level required to make the meeting scientifically exciting. It was rather instructive than interesting.

*         *         *

When I arrived at Portland a four-men delegation met me at the gate: Don W.Terwilliger, Rick le Faivre, Bill Price and... Joe Morris, whom I still supposed in Dublin. Proud of their active vulcano, the gentlemen were eager to be flown round Mt. Saint Helens. So we went in a two-engine, six-person plane; the passenger most prone to airsickness got the seat next to the pilot. The views were most impressive.

On Sunday afternoon I attended at le Faivre's home an informal gathering, which I enjoyed after a long night's rest. It was the first long night of this trip, and it was a good thing I had it, for Terwilliger's schedule for the next two days was killing. (On Tuesday evening, my hosts were absolutely exhausted.)

The days started at 7:30 with a business-breakfast in my hotel. During the daytime I gave two talks and conducted three "open discussions" (with business-lunches in between). On Monday evening (from 22:00 until 22:30) I addressed the combined chapters of the ACM and the IEEE, a happening for which 600 people had gathered in the auditorium of Sunset High School. (I heard that people had come from as far as Seattle.) Besides tired I was nervous because I have rarely worked with audiences of that size, but it went very smoothly and was a great success; as luck would have it I got very nice questions from the floor, which gave me all the opportunities I might have wished. It was an excellent show. (Tuesday afternoon ended with a reception at the University Club in Portland. Someone who had closely observed my lecturing techniques the previous evening summarized "After five minutes you could do with your audience whatever you wished." It's a pity I don't remember those first five minutes. But, of course, it is all on videotape......)

*         *         *

Being less familiar, Hughes and Tektronix have made the most vivid impressions, impressions that haven't been fully digested yet. Both companies will claim that they are profoundly different from each other. (At Hughes the hierarchy was highly noticeable: name tags were adorned with special buttons indicating the number of decades its bearer was with the company; at Tektronix all visible signs of seniority are anxiously —and almost religiously!— suppressed: open cubicles and Christian names on principle.) But they are very similar; their programming is medieval. I quote from Joel J.Forman (Computer, Vol.13, no.6, June 1980) describing the state of a project at Hughes only a few years ago:

"The people managing the software had hardware backgrounds and, for the most part, no real understanding of software. One of their programs was a perfect example of how software had (1) no written documentation of any kind, (2) not one comment in the source listings, (3) no test plans, and (4) no person remaining on staff who knew what was contained on the paper tapes."

This was Hughes, but from what I heard I must conclude that to some people at Tektronix the above must sound familiar.

At both places I was stuck by a profoundly unscientific attitude, that makes them ready victims of the Ed Yourdons, the Barry Boehms, and the Tom Gilbs of this world. They just lack the distinguishing palate that identifies junk and don't see (nor feel, nor sense) the difference between competent scientists and the quacks from the educational fringes of computing. They are like the tribes that observe that the ritual dances of their own witch-doctor are not very effective against the current epidemic and, therefore, welcome and solicit suggestions for more elaborate ritual steps.

They are absolutely unaware of the techniques of scientific thought. One of the consequences is that they equate "scientific" with "experimental", and as a result they are ridiculously "experimental". They don't attract one guru, they attract as many as they can. One group follows one guru, another group follows another guru, and by "measuring" the performance of the various groups the management hopes to decide which ritual dances are the best.

Another consequence is the holyness of the breadboard, and of the subsequent cult of "iterative design". Verifying that "it works" is regarded as the summit of "scientific attitude". The mere suggestion that a competent programmer might not be interested in the "experiment" because he has designed his artefact in such a way that he understands why it must work is heresy.

A third consequence is an overwhelming inability to separate their concerns. They don't understand the vital r�le of functional specifications as "a logical firewall" between the (scientific) concern of correctness and the (commercial) concern of pleasantness. They don't separate the intrinsic problems of computing science from the additional problems engendered by the American educational system, etc. In short, their (untrained) thinking is just a mess.

I was definitely alarmed by the prevailing attitude towards education. At Hughes it was worse than at Tektronix, but also at the latter place the attitude was far from kosher. I am beginning to understand how so many American universities could degenerate into "graduate factories". It might help to know that for a Dutchman, who has in his own language only a single verb for "to hire" and "to rent", the expression "to hire someone" is of an incredible rudeness. I observed American industry regarding the graduate indeed as the university's "product", that you just "hire" whenever you need a specific competence!

Whenever I pointed out —as politely as I could— the dismal state of affairs, management had its defence ready: "But the graduates we can hire are no better." I am sure that I am "unrealistic" but I can only call that copping out (in particular when your company is "committed to excellence"!).

Hughes wasn't interested in the education of its employees at all. Education would only make them restless, and, besides that, education was not interesting because education is a long term process that only bears fruit after many, many years. (That is really how their objection to education was phrased! The consideration that the longer something takes to bear fruit, the more urgent that you start with it as soon as possible was way beyond their vision.) Tektronix professed to be interested in the education of its employees, but I couldn't escape the uneasy feeling that it was little more than lip service. I quote from the Tektronix, Inc. Annual Report, 32nd Year, May 27, 1978: (pg. 31)

"This avenue for self-development is available to everyone here. All Tek employees are allowed 40 minutes of company time each month, to use in whatever way they find most broadening and helpful."

My God! What is "40 minutes of company time (sic!) each month"? Ten minutes a week. The average human spends more in the restrooms.

Again with the best of intentions, Tektronix felt like sponsoring an "Oregon Graduate Center". But the only thing they could think of was organizing courses disseminating "knowledge"; I thought that the purpose of a university education was to teach people to think better than they would otherwise have done.

*         *         *

When I came home I observed the outcome of a (highly scientific) experiment I have been taking over the last 100 days. I did not trust the permanency of Parker's Super (!) Quink Permanent Black and wrote two sentences on a piece of paper that I glued on my windows. This spring being what it is, we had very little sun, but clearly enough to demonstrate Parker's fraud. I cannot promise a true reproduction of the level of greyness; for those interested I shall keep the original.

Plataanstraat 5 5671 AL Nuenen The Netherlands | 31 August 1980 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD 746

Trip report E.W.Dijkstra, Newcastle-upon-Tyne, 1-5 Sep. 1980.

On Monday 1st of September 1980 the British Caledonian flight from Amsterdam was 2 1/2 hours late, but on the way home I was much more fortunate: touch-down at 18:45 and —thanks to an immediately departing coach— home at 21:05.

The reason for my visit to England was the 13th Joint International Seminar on the Teaching of Computing science. (Here "joint" means sponsored by IBM and organized by the University of Newcastle-upon-Tyne.) Having just returned from a three-week visit to the USA, I wasn't too keen to go abroad again so soon thereafter; my unfamiliarity with this year's topic, viz. Artificial Intelligence, made me decide to attend the seminar nevertheless. It was very instructive, and I don't regret the visit. I shall deal with the speakers in alphabetical order.

Dr.H.G.Barrow (Artificial Intelligence Center, SRI International) gave three lectures on "Computational Vision". A repetitive speaker on a shallow topic, he was a punishment to be exposed to. (Seegmüller from Munich was quite indignant, calling them the worst lectures he had ever attended at a Newcastle Seminar. But that was the beginning of the week and he hadn't heard Winston yet.)

Dr.J.Darlington (Department of Computing & Control, Imperial College) gave two lectures on Automatic Programming. I had never heard Darlington before and perhaps my expectations were too high. His first talk (on "Past and Present") contained —obviously!— nothing new; his second lecture (on "Future") was neither inspiring nor convincing. Someone should have told him that densely typewritten pages are improper material to be displayed by means of an overhead projector; the foils written by hand contained too many spelling mistakes.

Mr.D.D.Grossman (Automatic Research Group, IBM, Yorktown Heights) gave three lectures, two on "Programming Robots" and one on "Modelling Robots". His visuals were of the usual, insipid, kind (no grammar, but catchwords typed in capital letters only), but when one ignored most of these he was an absolute delight to listen to. He was well-informed about the state of the art and very instructive. Carefully avoiding to pronounce a judgement he made it very clear that the state of the art he described is entirely pragmatic.

Dr.M.H.E.Larcombe (Department of Computer Science, University of Warwick) gave one lecture on "Robotics Research in the United Kingdom". He had been asked to present a catalogue and he did just that. He, too, pronounced no judgement and gave a clear overview. In his comments on British funding policy he was more explicit.

Dr.J.Strother Moore (Computer Science Laboratory, SRI International) gave three lectures: "Brief History of Mechanical Theorem-Proving", "A Tour through a Working Theorem Prover", and "Program Verification". I enjoyed his lectures most of all; without all the cartoons I would have enjoyed them still better. (Are cartoons during lectures the visual analogue of background music in shopping centres?) Without overselling he gave a balanced overview, not shunning technical detail when appropriate. He was also a very conscious speaker (returning to a question raised in his previous talk because he wasn't satisfied with the answer he had given on the spur of the moment). His sense of humour shared characteristics with that of Grossman; I think "detachment" is the word.

Professor Y.Wilks (Department of Languages & Linguistics, University of Essex) gave two lectures "Computers and Text Understanding" and "Computers and Dialogue Understanding", from which I got very little. He closed one of every five sentences with "OK?", and each time I was tempted to interrupt him with "To say the honest truth, Sir: No!" If he had expressed himself more carefully he could have spoken with a third of his speed (perhaps conveying more). He said nicely nasty things about philosophers, but I doubt whether he was any better himself. Viewed as a demagogue, however, he was quite interesting to observe. The quality of the handwriting on his visuals —as on those of Barrow— was a disgrace.

Dr.P.H.Winston (Artificial Intelligence Laboratory, MIT) gave two lectures, one on "Learning and Reasoning by Analogy" and one with the parochial title "An MIT perspective on Artificial Intelligence". Having heard his first talk I was grateful that, having to catch my plane, I was forced to miss his second one. Is having attained a greater verbosity and a greater superficiality AI's greatest achievement over the last decade?

Dr.W.A.Woods (Bolt, Beranek & Newman, Inc.) gave one talk on "Syntactic Control in Continuous Speech Understanding" and one on "Augmented Transition Network Grammars for Natural Language Understanding". (He did not seem to be the type of person to be aware of the syntactic ambiguities of the titles of his own talks.) During his first talk I listened with interest to the part that dealt with phonetics. His second talk convinced me once more of the inadequacy of an operational approach to programming. He was utterly amazed by my suggestion that the use of anthropomorphic might be misleading ("But that's what we all do!"); in all his life he had clearly never given a single moments thought to the question! (And then it was my turn to be amazed.....)

*                 *
*

With Professor K.F.Bowden (Department of Computer Sciences, University of Essex) I had an interesting conversation about the design history of the ATLAS . With Professor J.Katzenelson (Department of Electrical Engineering, Technion - Israel Institute of Technology, Haifa) I had a conversation which quite unexpectedly turned into a technical discussion: he thought he had solved the glitch problem! I also recorded the reaction of D.J.Wheeler (Computer Laboratory, University of Cambridge) when I told him that, for the last ten years, I had taught programming using an intentionally not implemented programming language: "But how do you know then, whether a program works?". Admittedly, it was at breakfast, but even then..... Or was he pulling my leg?

*                 *
*

In his famous after-dinner speech (Baden bei Wien, 1964) Fraser Duncan rightly deplored the introduction of the term "programming languages", which had the consequence that what used to be "languages" had now to be called "natural languages". Dr.Woods showed us the next chapter of that deterioration by referring to..... "really natural languages"! Similarly, Dr.Moore referred in his last lecture to "a real programming language" (meaning a subset of both FORTRAN 66 and FORTRAN 77). I think that I shall really try to expel the word "real" from my active vocabulary.

I made another linguistic observation that seems significant: the more infected by AI, the more frequently the speaker, instead of referring to "the (real) world", referred to "the (real) world out there". I though that very revealing (and very sick).

In summary, the theorem proving and program manipulation seemed sound science, the down-to-earth robotics seemed sound engineering, and the rest was definitely neither of the two. Despite my severe cold (from which I still suffer) I enjoyed the seminar: it confirmed all my prejudices and was therefore most comforting and reassuring. The seminar was exhausting: it made too heavy demands on our BSP's (= Bullshit Processors).

Plataanstraat 5
5671 AL NUENEN
The Netherlands
7 September 1980
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 10 Jan 2005

EWD747

Comments on MIL-STD-1862, 28 May 1980.

I quote the document’s opening paragraph:

"1.1 Scope. This standard defines the Instruction set architecture for the Military Computer Family (MCF) of the U.S. Army. The instruction set architecture includes all information required by a programmer in order to write any time independent program which will execute on computers conforming to this standard."

Very wisely, its authors have remained anonymous, for its English is atrocious. (For instance: delete in the first quoted sentence "architecture", and replace in the second quoted sentence "The instruction set architecture" by "It", "time independent" by "time-independent", and "which will execute on" by "for". The verb" to execute" is really transitive!)

Its lousy use of English doesn't only make the text ugly, but also makes it obscure. Sometimes a bit is 0 or 1, sometimes a bit is set or clear, and sometimes a bit is set or reset. With a word size of 32 bits the sentence "This 16 bit [should be 16-bit] descriptor will be aligned on a word boundary." isn't very clear. I was duly puzzled by "The Implementation Virtual Address space [should this be: Space?] is the minimum of the distinct virtual addresses which can be generated and mapped using an addressing mode with memory mapping enabled." Also by "the implementation virtual address space shall be a minimum of 224 bytes or 8 times the maximum implemented physical address space, whichever is greater." (These sentences still puzzle me.) The obscurities quoted are only examples.

*              *
*

The document contains no formal syntax of the syntactic category <instruction>. The document contains no formal definition of the semantics; each time the informal semantics is "explained" by an example. The document is schizophrenic in the sense that, besides attempting to give a functional specification for a piece of hardware, it also gives what looks like an assembly code. The latter is not explained at all, yet we find it used in the "explanatory" examples. To be used as a standard, the document is, as a result, profoundly inadequate; we must judge its anonymous authors as insufficiently competent.

*              *
*

The authors pride themselves that the instruction set has been tightly coded. Strictly speaking that claim is empty without explicit assumption about the frequency distribution of the various instructions; I think that for most distributions encountered in practice the claim can, indeed, be justified. If I have interpreted the standard correctly, the tight coding is, however, not without anomalies, e.g.: if the register in question is not R0 (= program counter), Indirect Register Mode is equivalent to Register Indexed Mode with the displacement = 0. In contrast to the Scaled Index Mode, which can address bytes, half words, words, and doublewords, Unscaled Index Mode can only address the first three, but no doublewords (like Indirect Register Mode and Register Index Mode). Scaled Index Mode gives the option of addressing a halfword either as a single halfword or as a double byte; similarly a word may be either a single word or a double halfword. Finally, indirect addressing of double word seems only possible by means of Scaled Index Mode with the index set to zero.

Note. Register Indexed Mode, Scaled Index Mode, and Unscaled Index Mode allow adressing with respect to the program counter (= R0), which, of course, has its value changed during the execution of the current instruction. The informal definition of their semantics fails to define with respect to which value of the program counter addressing takes place. With respect to the address of the leading byte of the instruction? With respect to the address of the leading byte of the operand specifier in question? Who knows! This is a telling illustration of the incompetence with which this standard has been written. (End of note.)

Section 8.1.5 ("Alignment of Context Pointers") is too obscure to be understood by me. (I can correct the first sentence by replacing "The question ....." by "The answer to the question ......"; for the next sentences I cannot suggest a correction.)

Parameter Linkage (section 8.4) solves soundly the problem of translating the actual parameter —expressed in the context of the call— into a formal parameter to be interpreted in the context of the called procedure. The information contained in a single "parameter descriptor", however, is rather meagre, and I am afraid that it will only suffice for the simplest of programming languages. More demanding parameter mechanisms can possibly be implemented by allocating a few "parameter descriptors" to each parameter.

Reading section 9 ("Exceptions") I would have benefitted from a description how designers propose to use the exception handling facilities. I am a little bit worried by the fact that a single UDLE bit controls whether all exceptions will be handled by the Supervisor or all exceptions will be handled by the procedure’s own Exception Handler. The leading sentence of that section seems to equate exceptions with program errors; avoiding such exceptions seems preferable to using the elaborate handling facilities.

The intended rôle of bits 30:31 of the Map Pointer Register (section 12: "Memory Management System") is unclear to me. It controls "relocation" and "protection" per map; I would have expected the control per map entry. Reasonable performance of translation from virtual to physical addresses requires some sort of associative store for the Segment Descriptors of the two current maps. Shared routines must have the same address in all programs that use them; there are no "pages": segments are the units of presence in / absence from primary store. During its complete lifetime a program had better occupy the same place in virtual store, which is a severe restrictions for programs that never die. Clearly the assumption is made that a virtual store of 232 bytes is large enough to avoid conflicts. It is unclear whether two independent concurrent programs are allowed to occupy overlapping areas in virtual store. (I think they are.) I think the system is OK, though I would feel more comfortable when I saw a virtual store allocation policy that would be feasible and free from conflicts.

I did not study I/O Controllers (Section 13) and the instruction set for channel programs in detail. (I tried, but felt I was assumed to know too much.) The "Indirect Buffer List" (Figure 13-1) strongly suggests that a channel can be prepared so as to generate in due time more than 1 interrupt. What happens when a second interrupt is generated before the first one has been honoured? I fear that one interrupt gets lost. I doubt that further "messages" can be safely given to an active channel for I saw little trace of the usual precautions.

Masking of I/O interrupts takes place by means of “priorities”, assigned to interrupts, and to be compared with the current priority of the processor as specified in bits 4:8 of the PSW. (Section 11.1: Interrupt Priority.) I thought that by now enough people knew that such arrangement should be considered a mistake.

Without further justification "the proposed IEEE standard for binary floating point arithmetic" has been adopted. (It looks very messy.)

The instruction code is a bit baroque. On pages 85 and 86 we find suddenly a Push and Pop for which R1 acts as stack pointer; R1 is also copied at procedure call and return. I found no description of the special rôle that has been conceived for R1. A second stack to transmit additional information for which the Parameter Descriptor it too meagre?

*              *
*

"Compare and Swap" (p.88) is specified to be "an interlocked operation", i.e. "no other memory access" to one of its operands until a certain stage of progress of the instruction execution. Compare and Swap is one of the rare instructions where "interlocked" is prescribed and, by default, we must assume almost all instructions to be non-interlocked. But that notion is only defined in terms of "atomic memory contacts", and about these the “standard” is remarkably silent. If a program fetches a one-word operand around the time that another activity may change that same word, is the program guaranteed to fetch either the old or the new value but never to fetch a mixture? In (usually unavoidable) circumstances such guarantees are crucial. (If the atomic memory contact transfers one byte, reading a 32-bit block had better be defined and implemented as an “interlocked” operation!) Concerning the possible interleavings of which memory accesses the "standard" is extremely vague; in my experience even disastrously so.

On page 121 we have two move instructions —potentially long moves— for which is postulated that they "shall be interruptable". Can that be built? The non-interruptable version would have an anonymous variable keeping track of the progress, but that cannot be saved and restored. Starting the complete move over again isn't safe either: the operands may have come from the store from locations the contents of which have been destroyed by the part of the move prior to the interrupt. (When that specification was written down, someone didn't use his or her brains.) On account of the existence of memory management traps, each instruction must be interruptable, and one had better see to it that each instruction can be restarted. (The necessary hardware by means of which “the danger of unproductive page flutter” can be exorcised efficiently doesn't seem to be required by the standard.)

*              *
*

The more I am reading the MCF standard, the more distasteful it becomes. At first sight the design struck me as rather conventional and conventionally elaborate, and the document struck me as the unconvincing result of a job done without either loved nor care. A second reading reveals it as too rough a sketch.

Acknowledgement. C. Bron, H. Maaskant and J. van de Snepscheut helped me to read the document; I owe them my gratitude (End of acknowledgement.)

Plataanstraat 5 | 11 September 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-04-07 .

EWD748

A somewhat open letter to Wladislaw M.Turski

Dear Wlad,

thank you very much for the copy of your “Design of Large Programs”; I cannot tell when it arrived, for it came while I was on the road. I have now read it twice and shall certainly read it a third time. I would like others to read it as well and, therefore, regret that the weakness of my copy forces me to remain a leaf of the distribution tree.

I found three typing errors "tha" instead of "the" on the last line of page 6, "invesitgations" instead of "investigations" on line –8 of page 10, and —more serious— "Dodrecht" instead "Dordrecht" on online +14 of page 10. (A remarkably low score for a document that was produced under such high pressure!) And there were, of course, a few articles missing. (In connection with articles a question. You have undoubtedly observed the profound stylistic difference between "A discipline" and "The art". Did this subtlety survive translation into Polish? Do you have word endings to serve that purpose?)

At first I found your paper very disturbing. You know, for many years I was completely baffled whenever I was confronted with "models" (and their companions: "interpretations"), having grown up with the idea that what a mathematician talks about constitutes ipso facto his subject matter (consistent or not). The more I learned about model theory, the more it struck me as a relic from the times before the healthy separation of mathematics from philosophy. For the latter topic I have developed a well-tended blind spot, and since my decision not to try to make sense of model theory I feel much better. It has saved me much confusion. (Do the planets provide a model for Newtonian motion, or do Newtonian equations provide a model for planetary motion? I preferred to regard that question as pointless. A number of years ago my Department decided to develop a course that should help students to "design (mathematical) models of real-world situations". Political considerations were stronger than my protest. Can you imagine my distress went I read in your abstract that you propose "to consider the specification as a theory with two models, one in the application domain, another in the program domain"?

I started reading —writing "yes", "hm", "thank you", "???", in the margin whenever I felt like it— and got enthusiastic at the bottom of page 5 "Given such a linguistic system we can formulate a specification by listing [the] specific constants and axioms of our specification".

Next to your paragraph explaining how the flow of control has "disappeared" (on page 7) I wrote "nice". You are right. The profound role of the semicolon is not sequencing, which is an operational aspect of the usual implementation, but functional composition. (Hence my abhorrence of the "end-of-line convention" —which seems a FORTRAN relic— and, at the other end of the spectrum, the semicolon as obligatory terminator of every statement. But that's now neither here nor there.)

When you started with "Consider a formula α. Let P, Q, ..., R be predicate symbols and F, G, ..., H function symbols occuring in α, etc.", I wasn't quite sure. however, whether I wished to follow you. (I was sure, however, that our pasts are very different.) The next two pages I found difficult. By the time I reached the inclusions Z⊂E(P) and Cn(Z)⊊E(P) I felt on firmer ground again.

One page further I was again with you, where you wrote: "In the naive approach to application programming one is very likely to encounter phrases to the effect that a good program models its application domain.” I, too, have indeed encountered phrases that effect and —see above— they always struck me as a sure symptom of profound misunderstanding. But the early occurrence of the word "naive" in your sentence triggered my immediate sympathy. The pivotal sentence of your paper seems to be the one that follows shortly: "If program is a model of a specification as an axiomatic theory, then why not consider the application domain ("the real world") as another model of the same theory? With my different past I would express that idea quite differently, but that does not prevent me from endorsing the suggestion whole-heartedly. (As a corollary it explains what we all know, viz. that database management will remain in its infancy as long as everything is "explained" in terms of employees, salaries, locations, etc.)

On line –2 of page 13 you have forgotten to underline: read “non” instead of “non”.

The pictures in the second half of your paper rather put me off, but that's what pictures always do to me, so don't worry. I shall try again.

*              *
*

The way in which you tie in specifications models theory leaves, for the time being, my feelings very mixed. On the one hand I feel that neither the relevance of Robinson's theorem of 1956, nor your taxonomy (i) through (vi) of how two (similar) specifications may differ could have been discovered without dragging model theory into the picture; on the other hand my nurtured dislike of the topic makes me believe (or makes me want to believe) that the morals of your findings can (and, hence should) be phrased much more succinctly without mentioning models at all. In the latter mood I blame the your training in logic for the form of this otherwise refreshing and inspiring paper. Your training in logic, which made you love the implication, is certainly responsible for the hilariously pleonastic sentence on page 9: "It can be easily seen that every inconsistent set of axioms is complete, and every incomplete set of axioms is consistent.")

May I thank you for your paper? Since I read it the future of our field looks brighter. With my greetings and best wishes,

yours ever,

Edsger

P.S. Information Processing Letters did a nice job in printing EWD687a! Thank you.

Plataanstraat 5 | 17th September 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 2015-04-12 .

EWD749

On the productivity of recursive definitions.

The purpose of this note is to summarize what we have learned at the last two sessions of the Tuesday Afternoon Club. We shall discuss conditions under which finite expressions can be said to represent infinite sequences. The simplest example of such a finite expression is

| ones

where ones is defined recursively by

| def ones = 1 : ones

(Here we have borrowed from SASL the colon to denote concatenation.)

Repeated application of the definition of ones gives

| ones
| = 1 : ones
| = 1 : 1 : ones     , and so on.

On terminology.

All through our discussions we have been been painfully aware of our need of a terminology that would not be misleading.

Aside. How much harm can be done by a misleading terminology was brought home to me this morning when I received a technical note (without title) written by Richard J. Treitel, a Stanford student. When I introduced the predicate transformer, I knew that it wasn’t fully correct to call it “wp” and it wasn’t fully correct either to denote its (second) argument and its value by “post-condition” and “pre-condition” respectively. In view of convention {P} S {R}, I could have called them “right-condition” and “left-condition”. Yet I adopted the traditional terminology, hoping that no one would be misled. But R.J. Treitel states about wp that “it explicitly involves a notion of time.” (End of aside.)

For our purpose, the term “infinite” won’t do. Firstly, when introducing two complementary concepts, I prefer positive terms for both, because naming one by the negation of the other destroys the symmetry by presenting the latter one as the more “basic” concept. (For x ≠ y I prefer the pronunciation “x differs from y” to “x is not equal to y”. I have still to encounter the first mathematician who pronounces x = y as “x doesn’t differ from y”!). Secondly, we shall encounter two drastically different ways in which a sequence can fail to be infinite.

In the time domain we have —remarkably enough!— plenty of negation-free terms to denote infinite, such as “eternal” and “permanent”, but that won’t help us, for my ultimate goal is a non-operational treatment in which our texts needn’t be interpreted as executable code. I have hesitated for a long time between “ongoing sequences” and “continuing sequences” —not being too pleased with either of the two—. After consultation of all my English and American dictionaries I concluded that “continued concatenation” should do the job.

Note. My Webster’s New Collegiate Dictionary gives: “continued fraction” n: a fraction whose numerator is an integer and whose denominators is an integer plus a fraction whose numerator is an integer and whose denominator is an integer plus a fraction and so on”.

The Shorter Oxford English Dictionary gives “Continued 1[...] 2. Carried on in space, time, or series” with as one of the examples: “C. Fraction: a fraction whose denominator is an integer plus a fraction, which latter fraction has a similar denominator and so on.”

(In passing I noted that none of my dictionaries defined “continued fraction: a fraction whose nominator is an integer and whose denominator is an integer plus a continued fraction.”)

I take the fact that dictionaries from both sides of the Atlantic Ocean close their definitions with the famous “and so on” as an indication that “continued” admirably renders the idea of a non-terminating recursion.

(End of “On terminology”)

*              *
*

In the following, <atom> stands for a character from a (finite or infinite) alphabet, say a natural number. Sequences, concatenations, and continued concatenations are defined by the following syntax:

| < seq > ::= < atom > | < conc >
| < conc > ::= ( < seq > : ⊀ seq ⊁ )
| < contconc > ::= ( < seq > : ⊀ contconc ⊁ )

With the bracket pair ⊀ ⊁ I denote an instance of the corresponding syntactic category, but with its outer parenthesis pair, if present, optionally stripped off. (This seemed a convenient way to indicate that concatenation as denoted by the colon is deemed to associate to the right.) Note that I did not bother to introduce the empty sequence (nor NIL).

The usual functions “head” and tail are only introduced for concatenations (continued or not):

| hd (p : q ) = a
| tl (p : q) = q

a head is always a <seq>, and a tail is a <seq> or a <contconc>, just as the argument.

For concatenations we define the true prefix “tpf n” of length n for n ≥ 1 by

| tpf 1 (p : q) = p
| tpf (n+1) (p : q) = (p : (tpf n q)) ;

a tpf n (p : q) —when defined, of course— is always a <seq>. The distinguishing feature of continued concatenations is that tpf n < contconc> is defined for all n ≥ 1; tpf n <conc> is only defined for n up to some limit —this because the true prefix of an <atom> is undefined.

That, for some f, tpf n f is defined for all n ≥ 1 is, in principle, always proved by mathematical induction over n. With

| def ones = 1 : ones

the fact that “tpf n ones” is a <seq> implies that also tpf (n+1) ones is a <seq> because “1” is a <seq>. Hence, ones is a continued concatenation.

With

| def C = c : D ;
| def D = d : C ,

One way would be to derive C = c : d : C by substitution and to proceed as before. With “seq f” meaning “f is a <seq>”, and with “Q m” meaning ”(tpf m C) and (tpf m D) are both defined”, it is easily seen that

| (seq c) ∧ (seq d) ∨ (Q m) ⇒ Q (m+1) ,

and mathematical induction over single m will do the job. In the case of mutual recursion this trick seems applicable in general.

More interesting recursive definitions contain a formal parameter, and are essentially of the form

| def f x = g x : f (h x) .

Given a predicate P such that,

| (P x) ⇒ (seq (g x)) ∧ (P (h x)) | (*)

(or, without functional application the highest priority:

| P x ⇒ seq (g x) ∧ P (h x) )

and with “Q m” meaning “for all x, Px implies that tpf m(f x) is defined”, it is easy to show that Q m ⇒ Q (m+1). Hence formula (*) summarizes our proof obligation for the demonstration that P x implies that f x is a continued concatenation.

The generalization to mutually recursive definitions is now straightforward. With

| def f0 x = g0 x : f1 (h1 x);
| def f1 x = g1 x : f0 (h0 x)

the analogue of (*) is P0 x ⇒ seq (g0 x) ∧ P1 (h1 x) and P1 x ⇒ seq (g1 x) ∧ P0 (h0 x) .

Finally some examples.

For | def id f = p : id q
|       where p : 1 = f

take for P: P x means: x is a continued concatenation

*              *
*

Consider: | eleven p = p : p
| eleven (p : q) = p : p+p1 : q1
|       where p1 : q1 =eleven q

Here the first line defines eleven for an argument that is an atom, the next two define the value of eleven when the argument is a concatenation. This time the previous P does not suffice; we need now : ”P x means: x is a member of the syntactic category <x>, defined by <x> ::= <integer> : ⊀x⊁ ”. (For such arguments the first line of the definition is irrelevant.)

In our next example we are interested in a condition Q x such that eleven is a <seq>. Take for Q, “Q x means that x is a member of the syntactic category <x>, defined by

| <x> ::= <integer> | <integer> : ⊀x⊁   ”.

We can prove

| Q x ⇒ Q (eleven x)

a result we need when we wish to prove that

with | def pascal x = x : pascal (eleven x)

Q x implies that pascal x is a continued concatenation. (The interesting value is of course, pascal 1; it equals the continued concatenation of the lines of the Pascal Triangle.)

What is the condition on x such that frill x is a continued concatenation, with frill given by

| def frill x = p : frill q
|       where p : q = eleven x ?

Remark. Instead of tpf n, which is not defined on atoms, we should have introduced pf n, given by

| pf 1 p = p
| pf 1 (p : q) = p
| pf (n+1) (p : q) = p : pf n q .

| (End of remark.)

Plataanstraat 5 | 18 - 25 September 1980
5671 AL NUENEN | prof.dr.Edsger W.Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 20-Jul-2015 .

EWD750 - 0

America's programming plight.

A competent programmer's most important assets are --perhaps in this order-- an excellent mastery of his native tongue and a considerable mathematical maturity. These facts are well-known and well-understood for more than ten years.

By a sad accident of history they make programming, which is difficult anyhow, in the USA even more difficult. Firstly, since the turn of the century the American culture has gradually turned itself away from mathematics (see Lynn A. Steen "Mathematics Today" or Morris Kline "Mathematics in Western Culture") to the extent that many of its otherwise well-educated citizens have no longer a balanced view of what mathematics is all about. The culture has become amathematical, sometimes even antimathematical. Who could foresee in 1900 that by the end of the century, thanks to the advent of computers, it would be more rewarding than ever to have a mathematically trained mind? Secondly, (see, for instance, Edwin Newman "Strictly Speaking") the ideals of the permissive society have accelerated the deterioration of the average usage of the English language. (Other Western countries suffer from such a phenomenon too, but the USA

EWD750 - 1

--as usual!-- seems to be ahead of them.) For American programming, these two developments are very unfortunate indeed.

There is a further encumbering circumstance; I knew it, but a recent visit to some U.S. industries made me perceive it in its full seriousness. The trouble is that programming became an industrial activity at a moment (see, for instance, William H. Whyte "The Organization Man") that the prevailing management philosophy aimed at making companies as independent as possible of the competence of their employees. Needless to say, this gave American industrial programming a very false start. How strong this attitude still is I learned during my recent visit when a horrified American manager reacted upon a suggestion of mine with: "But that would require people to think!". It was as if I had made an indecent proposal. (The very common reaction to look immediately for "a tool" as soon as a problem emerges could very well be a symptom of that same attitude.)

One further circumstance blurs people's vision. For those who understand what programming is about and agree with Morris Kline's verdict "More than anything else mathematics is a method," it is obvious that programming must be

EWD750 - 2

regarded as branch of mathematics, be it a somewhat curious one. Certainly now, but perhaps for ever, programming distinguishes itself from most other branches of mathematics by a different balance between the required knowledge and the required maturity. Programming requires relatively little mathematical knowledge; avoiding unmastered complexity, however, requires a great methodological awareness. I know that this unusual balance prevents some of my Dutch colleagues from viewing programming as a promising area of mathematical activity. More knowledge oriented than I, they keep asking "But where is the relevant mathematics?". They feel that the subject is "too shallow" or "not rich enough" to become a flourishing branch of mathematics. My recent visit to the USA reminded me of the fact that the American education is much more strongly knowledge oriented than the traditional European one. (A discussion about computing science education was immediately phrased in terms of the question "which subjects the student should take"; trying to improve their thinking habits wasn't considered at all.) The relatively modest role of mathematical knowledge in programming blurs the European vision; I am afraid it blurs the American one even more.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 19 September 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD751 - 0

Mainly on the omission of parentheses.

(This is an interruption of EWD749. While working on the latter, I noticed that I wanted to give more attention to some notational questions than I had foreseen. Because these notational concerns are a separate issue, it seemed better to put EWD749 aside and to devote a separate note to them.)

In the following, <atom> stands for a character from a (finite or infinite) alphabet, say for a natural number. Consider the syntax

<seq> ::= <atom> | ( <seq> : <seq> )   .

Here we have borrowed from SASL the colon to denote concatenation. Considering taking the "head" and the "tail" as undoing the concatenation, we can indicate that in the (tentative) embellishment

<seq> ::= <atom> | ( { hd = <seq> } : { tl = <seq> } )   .

For instance, hd((1:2):3) = (1:2) and tl((1:2):3) = 3 ; for sequences that are atoms, the functions hd and tl have been left undefined.

In each sequence <seq> from the above syntax the number of colons obviously equals the number

EWD751 - 1

of parenthesis pairs, and that number - though unbounded over the set of sequences - is finite for each sequence. This latter constraint no longer holds for "continued concatenations" <contconc>

<contconc> ::= ( { hd = <seq> } : { tl = <contconc> } )

The infinite continued concatenation as being defined above being a bit unwieldy to manipulate, a practical system also comprises finite expressions representing continued concatenations. By "representing" we mean here that it is possible to derive its head and to derive (a finite expression "representing") its tail.

* * *

The number of colons being equal to the number of parenthesis pairs, the above syntax is redundant. This redundancy is usually exploited by introducing rules according to which certain parenthesis pairs from the above syntax may be omitted. For instance, by omission of an internal parenthesis pair, (1:2:3) can be derived from ((1:2):3) and from (1:(2:3)). In order to avoid ambiguity, rules have to state in which of the two sequences the internal parentheses pair is obligatory. If (1:2:3) is interpreted as an abbreviation of ((1:2):3) we say that concatenation is "left-associative"; if (1:2:3) is interpreted as an abbreviation of (1:(2:3)) we say that concatenation is "right-associative".

EWD751 - 2

If we denote by the bracket pair <⃒ >⃒ an instance of the corresponding syntactic category, but with its outer parenthesis pair, if present, optionally stripped off, the alternatives for <seq> are:

left-associative: <seq> ::= <atom> | ( <⃒seq>⃒ : <seq> )

right-associative: <seq> ::= <atom> | ( <seq> : <⃒seq>⃒ )

and similarly for <contconc>

left-ass: <contconc> ::= ( <⃒seq>⃒ : <contconc> )

right-ass: <contconc> ::= ( <seq> : <⃒contconc>⃒ )    .

The above exploration served to convince myself that the choice between left- and right-association is totally independent of the asymmetry of the continued concatenation. When the choice is determined by the goal to omit as many parenthesis pairs as possible and we assume that most heads are atoms - and, from that I have seen, this seems a reasonable assumption - right-association is preferable for concatenation. Finally I observe that the bracket pair <⃒ >⃒ has served its purpose; my earlier explorations without it were clumsy.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 24 September 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Wed, 09 Jul 2003 .

EWD752

DRAFT

Distributed Arbitration.

| by Edsger W. Dijkstra and C.S. Scholten

0. Problem Description.

Generalizing the synchronisation paradigm of the Dining Philosophers [1, 2], we consider a finite undirected graph, whose vertices are called “philosophers” and whose edges are called “forks”. A philosopher is a process consisting of a continued alternation of two states called “thinking” and “eating” respectively. A fork is a resource shared between the two philosophers it joins; it is either free or owned by one of those two philosophers. The statement “a philosopher is eating” is equivalent to the statement that the philosopher owns all the forks it shares with others. Note that for a complete graph the above corresponds to total mutual exclusion, with evidently “eating” corresponding to the critical section; the case of the graph being a pentagon corresponds to the paradigm mentioned above.

Even in the case of complete 2-graph there is a problem, viz. the resolution of the contention for the single fork when the two philosophers happen to become simultaneously ready to stop thinking. We postulate this problem of binary arbitration solved. The contention invites us to introduce after thinking and before eating an intermediate state called “ready to grab” the fork. We can now formulate more precisely our postulate:

P0 | a fork is owned or no philosopher is ready to grab it.

With thinking periods of positive duration and eating periods of finite duration —and we shall assume this to be the case for the rest of our paper— we immediately derive from P0 following corollary

C0 | a philosopher ready to grab a fork owned by an eating philosopher will own that fork upon completion of the other’s meal. (It is understood that a thinking philosopher owns no forks.)

It follows that the postulated solution for the complete 2-graph is free from the the dangers of deadlock and of individual starvation.

We propose to solve the synchronization problem corresponding to a general graph in terms of binary arbitration as described above. In order to give the adjective “distributed” the strongest possible meaning, we accept the constraint that in any state a philosopher may be ready to grab at most one specified fork; as before, the state “ready to grab a specified fork” is terminated only by grabbing it. Consequently, a philosopher is from now on a process consisting of a repetition of

| thinking ;
| grabbing its forks in some order ;
| eating

For the sake of realism we admit after the atomic act of grabbing a fork a finite delay before the new owner enters its next state, in particular before it becomes ready to grab the next fork. For our later analysis it is then irrelevant whether, at the end of an eating period, the forks are released simultaneously or not.

1. Avoiding the danger of deadlock.

As long as a philosopher is ready to grab a fork (which —see P0— is owned by another) it is said to be “blocked” by that fork; the fork in question is called the “blocking fork” of that philosopher.

Deadlock —sometimes called “partial deadlock”— occurs when there exists a philosopher such that there is no possible future state in which it is eating. Without constraints on the orders in which philosophers grab their forks, the danger of deadlock is present when the graph contains a cycle: let each philosopher on that cycle grab its “left fork” first. In the sequel we shall formulate the precise constraint on the grabbing orders that exorcizes the danger of deadlock.

For each philosopher in a connected subset of (two or more) philosophers we define “its first fork in that subset” to be the first fork in its grabbing order that it shares with any other philosopher in that subset. In each connected subset “directed paths of first forks” are recursively defined by

1) | a single philosopher is a directed path of first forks
2) | a directed path of first forks extended with the first fork of its last philosopher is a directed path of first forks.

Since each philosopher in a connected subset has a first fork in that (finite) subset, cyclic directed paths of first forks exist.

Theorem 0. “the danger of deadlock is present” = “there exists a connected subset containing a cyclic directed path of more than two first forks”. End of Theorem 0.

Remark. Note that in the terminology used, a ”cyclic directed path of two first forks” corresponds to a single fork that is first fork at both ends. (End of Remark.)

Proof of Theorem 0.

Assume the existence of a subset containing a cyclic directed path of three or more first forks. The state in which each philosopher on the cyclic path owns its first fork can be reached when all the philosophers outside the subset are thinking. Since none of the philosophers on the cycle can be the first to eat, deadlock occurs. Hence the truth of the right-hand side implies the truth of the left-hand side.

Assume deadlock. This implies eventually the existence of a directed cycle of more than two blocking forks, hence of a directed cycle of forks each owned by, say, its target. If there exists an owned “diagonal” fork of the cycle, there exists a smaller directed cycle of at least three owned forks (built from the “diagonal” and one part of the original cycle). By induction we conclude the existence of a directed cycle of at least three owned forks, no diagonal of which is owned. In the subset formed by the philosophers on such a cycle, the forks of the cycle are the first forks of their owners. Hence the truth of the left-hand side implies the truth of the right-hand side. (End of proof of Theorem 0.)

We state the following corollary of Theorem 0

C1: | In a deadlock-free system with at least one fork, there exists at least one fork that is first fork at both ends.

Remark. Since each fork blocks at most one philosopher at a time, absence of the danger of deadlock implies, thanks to P0, the absence of the danger of individual starvation. (End of remark.)

In the sequel we confine our attention to systems free from the danger of deadlock.

2. Blocking paths and delays.

So-called blocking paths are defined recursively by

1) | a single philosopher is a blocking path
2) | a blocking path extended with the blocking fork of its last philosopher is a blocking path.

Let X be a philosopher. For the blocking paths that starts at X we define the following meaningful order. Consider two such paths:

1) | if one path is an extension of the other, the extended path precedes the other
2) | If neither is an extension of the other, they contain a philosopher Y such that both paths are identical from X to Y but are extended by different blocking forks of Y; the order in which Y grabs these two forks equals the order of the corresponding paths.

The above ordering of the blocking paths that start at X is meaningful for the following reason. Associate with each blocking path the following state: philosophers not on the path are thinking and the last philosopher on the path is eating. Upon completion of the current meal, a possible successor state of the system is the one associated with the next blocking path, where “next” is to be understood in terms of the above ordering of the blocking paths starting at X. (See the last paragraph of Section 0.)

Whenever X is not thinking, there is a unique blocking path starting at X and with its last philosopher eating. it now follows that the maximum number of meals that can take place between two successive thinking periods of X —called “the maximum delay for X”— equals the number of blocking paths starting at X.

From the previous paragraph it follows that a delay equal to the number of blocking paths starting at X can occur; from corollary C0 it follows that the delay for X cannot exceed that number.

3. Minimum average maximum delay for mutual exclusion.

For the sake of simplicity we shall confine ourselfs in the following two sections to complete graphs, i.e. a fork for each pair of philosophers. This corresponds to total mutual exclusion of the eating periods. From section 2 we conclude that the problem of minimizing maximum delays boils down to minimizing numbers of blocking paths; minimizing, for a given set of philosophers, their average maximum delay is, therefore, tantamount to minimizing the total number of blocking paths.

For N philosophers we shall now determine the minimum number of blocking paths. Let in a deadlock-free system fork f, shared by philosophers x and y, be first fork at both ends; the existence of f is stated in corollary C1. The blocking paths of the system can now be partitioned as follows:

A | Blocking paths containing neither X nor Y
BX | Blocking paths containing X but not Y and blocking paths starting at Y with X in second position
BY | Blocking paths containing Y but not X and blocking paths starting at X with Y in second position

Note. Because f is the first fork of both X and Y, a blocking path containing both starts at one of them with the other in second position. (End of note.)

Let us call SX the reduced system that remains when philosopher Y is removed (forks shared by y being removed from the grabbing orders of the others); For this reduced system, X will be denoted as “the pivotal philosopher”. The system SY is similarly defined by interchanging X and Y.

A blocking path from category A occurs in both reduced systems, independently of the place a pivotal philosopher occupies in the grabbing orders of the non-pivotal ones and vice versa.

The blocking paths from category BX are fully determined by the structure of SX, and similarly for BY.

Let PX and PY be the number of blocking paths in BX and BY respectively. In a system with a minimal number of blocking paths, PX = PY holds, because if PX < PY, we can decrease PY without affecting either PX or the number of A-paths by choosing the structure of SY equal to that of SX. (Since deadlock implies infinitely many blocking paths, this transformation does not introduce the danger of deadlock.)

In short, heading for systems with a minimal number of blocking paths, we can confine ourselves to systems with SX and SY of equal structures (i.e. replacing X in SX by Y yields SY.)

The equal structure of SX and SY implies that X and Y have equal grabbing orders and that each non-pivotal philosopher has the forks it shares with x and y in adjacent positions in its grabbing order. Thus we have to focus our attention on the reduced structure of N–1 philosophers. Repeated application ends with a structure of two philosophers.

The inverse process starts with two philosophers connected by one fork, and builds up the system by increasing the number of philosophers by one in each step. Such a step consists of “doubling” a selected philosopher. The fork connecting the pair is first fork for both, the rest of their grabbing orders is a copy of that of the selected philosopher; the grabbing orders of the other philosophers are “stretched” at the position of the selected philosopher, whose entry is replaced by the resulting pair in some order.

The structure satisfies relation.

R:
The number of philosophers in the structure equals 1 or the philosophers can be partitioned into two non-empty subsets V and W such that

1)
each philosopher grabs the forks it shares with members of its own set before it grabs those it shares with members of the other set , and

2)
the structures corresponding to V and W both satisfy R.

This is vacuously true to start with and remains true under the doubling operation: when a selected philosopher is doubled, the resulting pair belongs to the same set(s) as the philosopher it replaces.

A blocking path starting at a philosopher from V either has all its philosophers in V or is any of those paths extended with one arbitrary philosopher from W. (Firstly, such an extension is a blocking path; secondly, it cannot be extended with a further philosopher from W, since the last philosopher of the path has already grabbed all forks it shares with other members of W; thirdly, it cannot be extended with a philosopher from V either, since the last V-philosopher on the path owns all the forks it shares with the other members of V.) It follows that the total number of blocking paths equals:

| (NW + 1) · PV + (NV + 1) · PW ,
where | NV = number of philosophers in V
| NW = number of philosophers in W
| PV = number of blocking paths in V
| PW = number of blocking paths in W

Let f(x) be the minimum number of blocking paths in a system with x philosophers. Since our freedom in selecting the philosopher to be doubled enables us to realize any partitioning (and subsequent subpartitionings), our previous result tells us that f is the minimal solution of

for x=1: | f(x) = 1
for x>1: | f(x) = (n+1) · f(m) + (m+1) · f(n)
| where m≥1, n≥1, m+n=x

It can be shown that the minimal solution is obtained by choosing |m–n| ≤ 1. (See Appendix.)

4. Configurations symmetric in the philosophers.

From the previous section it follows that the minimal number of blocking paths can always be realized by assigning to each fork a natural number, called its “rank”, such that

1) | forks meeting at a philosopher have distinct ranks, and
2) | each philosopher grabs its forks in the order of increasing rank.

We call such systems “ranked systems”. (Ranked systems are obviously deadlock-free.)

Example. By way of illustration we give a system that is deadlock-free, is symmetric in the philosophers, and realizes the minimum number of blocking paths, but cannot be ranked. With four philosophers numbered 0, 1, 2, 3 and addition being modulo 4, philosopher i grabs the forks it shares with i+2, i+1, and i+3 in that order. We don’t need to consider that system; there is, indeed, a ranked system enjoying the same properties: it suffices to re-interpret “addition” as the bit-wise sum modulo 2. (End of example.)

In general, for a ranked system of N philosophers, the number of distinct ranks exceeds the number of forks meeting at a philosopher, e.g. N=3 requires 3 distinct ranks. In such a case, symmetry in the philosophers is precluded: in a symmetric ranked system each philosopher grabs a fork of each rank in the system.

In a symmetric ranked system, forks of two distinct ranks form cycles of length 4; their diagonals have a third rank.

Proof. Let p and q be two distinct ranks. Consider the two 2-fork paths (p,q) and (q,p), starting at the same philosopher. The latter shares with their endpoints forks which, for reasons of symmetry, have the same rank, r say. Hence their endpoints coincide. Obviously, the other diagonal is of rank r as well. (End of proof.)

Consider a symmetric ranked system of more than 2 philosophers. Two ranks partition therefore the philosophers into partitions of 4. Forks of a next rank either connect philosophers from the same partition, or pair partitions, thereby doubling their size and halving their number. The number of philosophers in a symmetric ranked system is, therefore, a power of 2.

Furthermore a symmetric ranked system exists for each N=2k. Number the philosophers (in binary) from 0 through N–1, and assign to the fork shared by philosophers i and j the rank i+j, where “addition” is again the bit-wise sum modulo 2. If X is the number of a philosopher, we can renumber the philosophers without affecting the ranks by performing for each philosopher number i: i:=i+X (addition again bit-wise modulo 2). In the new system —which is congruent with the old one— philosopher X has become philosopher 0, and thus the symmetry has been established.

It follows from our previous section that for N=2k the above symmetric ranked system realizes the minimum number of blocking paths, hence the minimum maximum delay for each philosopher. It follows from that same section that this delay equals unfortunately

| (PROD i: 0 ≤ i < k: 1 + 2i) ,

i.e. | k: | delay: | N:
| 0 | 1 | 1
| 1 | 2 | 2
| 2 | 6 | 4
| 3 | 30 | 8
| 4 | 270 | 16     and so on.

The exploding worst case casts some doubts on the general utility of binary arbitration as a means for implementing mutual exclusion. We can only recommend it when it can be shown on other grounds —such as timing considerations— that the worst case delay will not occur.

5. A two-stage solution.

The case of the complete graph, corresponding to total mutual exclusion, was studied in order to determine how bad worst-case delays could be. We now return to the general graph, for which we shall propose a different solution. At the level of detail in which it will be described, it uses less austere communication facilities than binary arbitration only, but it achieves the smallest possible worst-case delay.

For this purpose, the life of a philosopher is viewed as a cyclic succession of three states, called “thinking”, “hungry”, and “eating” respectively; for brevity’s sake the union of the last two states will be denoted by “tabled”.

Furthermore, also each fork has three states: either it is undirected or it is directed, i.e. it carries an arrow in one of the two possible directions.

The life of a philosopher is now programmed as follows, angle brackets being used to delimit “point actions”, philosophers sharing a fork are called each other’s neighbours.

do | true →
| thinking;
T0: | <directs an arrow towards each of its tabled neighbours and switches to hungry, hence to tabled>
| hungry;
T1: | <observes to be without outgoing arrows and switches to eating, hence remains tabled>
| eating
T2: | <makes all its forks undirected and switches to thinking>
od |

The system, which is started with all philosophers thinking and all forks undirected, maintains the following invariants:

Q0: | for each pair of neighbours X and Y “both X and Y are tabled” = “the fork shared by X and Y is directed”
Q1: | for each philosopher X “X is hungry” or “X is without outgoing arrows”.

As a consequence of Q0, a thinking philosopher has all its forks undirected; as a consequence of Q1, T2 removes only incoming arrows. The universal truth of Q0 and Q1 precludes simultaneously eating neighbours.

In order to prove that transitions T1 —which are implemented by making a philosopher “wait” until all its outgoing arrows have disappeared— cannot lead to deadlock, we observe the obvious invariance of

Q2: | directed forks do not form directed cycles.

The system is free from the danger of individual starvation. Observe a hungry philosopher X and all philosophers reachable from X via directed forks. All philosophers of this directed subgraph are tabled, hence that subgraph cannot grow. It is furthermore cycle-free (on account of Q2): its longest path ends at a philosopher that can eat and, hence, that maximum path length gives an upper bound for the delay of X. With N philosophers, the delay is therefore at most N.

Nice as this solution is, it begs the question, since the only safe way of implementing the T’s —in particular T0 and T2— as sequential processes that we know of is to make the T’s of neighbours mutually exclusive in time, and that mutual exclusion was the original problem.

Under the assumption that both thinking and eating of a philosopher always require more than N “transition times T”, an implementation of the mutual exclusion of neighbouring T’s by means of binary arbitration yields, on the microscopic level, a delay of at most “ transition times.

The moral of the story is that an algorithm with very poor worst-case behaviour can be safely used when embedded in an environment that prevents the realization of the poor performance.

References

[1] | Hoare, C.A.R., “Towards a Theory of Parallel Programming”. Operating Systems Techniques, Ed. C.A.R. Hoare and R.H. Perrott, Academic Press, London and New York, 1972, pp 61–71.
[2] | Dijkstra, Edsger W., “Hierarchical Ordering of Sequential Processes”, ibid. pp 72–93.

Appendix

The claim that the system

for x=1: | f(x) = 1
for x>1: | f(x) = (n+1)∙f(m) + (m+1)∙f(n)
| where m≥1, n≥1, m+n = x

yields its minimal solution for |m–n| ≤ 1 is equivalent to the statement that the function f defined by

| f(1) = 1 | ⎫
| f(2∙k) = (k+1)∙f(k) + (k+1)∙f(k) | ⎬ for k ≥ 1              
| f(2∙k+1) = (k+1)∙f(k+1) + (k+2)∙f(k) | ⎭

satisfies for m≥1, n≥1, P(m,n) ≥ 0 with P defined by

| P(m,n) = (m+1)∙f(n) – f(m+n) + (n+1)∙f(m) | (0)

With Q defined by

| Q(m,n) = m∙f(n) – n∙f(m) | (1)

we prove first

| m≤n ⇒ Q(m,n)≥0 | (2)

Proof of (2). On account of (1), (2) follows from

| f(x)/x is an ascending function for x≥1 | (3)

which follows from

| n∙f(n+1) – (n+1)∙f(n) > 0 for n≥1 | (4)

We shall demonstrate (4) by

a) | observing its truth for n=1 (note that f(2)=4),
b) | demonstrating that the first difference of the left-hand side of (4) is positive. This first difference is
| (n+1)∙f(n+2) – 2∙(n+1)∙f(n+1) + (n+1)∙f(n) =
| (n+1)∙(f(n+2) – 2∙f(n+1) + f(n)) for n≥1

We are left with the proof that f has a positive second difference. With ddf defined by

| ddf(n) = f(n+2) – 2∙f(n+1) + f(n)

we deduce from the definition of f

| ddf(2∙k) = 2∙(f(k+1) – f(k))
| ddf(2∙k+1) = (k+2)∙ddf(k)

Since f(1) = 1, f(2) = 4, f(3) = 11 we find for k=1: f(k+1) – f(k) = 3 and ddf(k) = 4. From that base it follows by induction that all first and second differences of f are positive. Hence, (2) has been established. (End of Proof of (2)).

Next we define — with (2∙k) div 2 = (2∙k+1) div 2 = k—

x₀ = m div 2 | x₂ = n div 2
x₁ = (m+1) div 2 | x₃ = (n+1) div 2

These functions satisfy —as is easily verified—

x₀ + x₁ = m | x₂ + x₃ = n

{x₀ + x₃, x₁ + x₂} = {(m+n) div 2, (m+n+1) div 2}

Using in the subscripts “∔” to denote the bit-wise sum modulo 2, we now consider the expression

| (S i: 0≤ i ≤ 2: (xi∔1 + xi∔2+1) ∙ P(xi, xi∔3) + (xi∔3 - xi∔1) ∙ Q(xi, xi∔2)) | (5)

In (5) we have two types of terms

a) terms derived from the middle term of P; they add up to

| – (x₁ + x₂ + 1) ∙ f(x₀ + x₃) – (x₀ + x₃ + 1) ∙ f(x₁ + x₂) =
| – f(x₀ + x₁ + x₂ + x₃) =
| – f(m + n) .

b) terms with f(xi) for 0 ≤ i < 4. The coefficient of f(xi) is

| (xi∔1 + xi∔2 + 1 ) ∙ (xi∔3 + 1 ) + (xi∔1 - xi∔3) ∙ (xi∔2 =
| (xi∔2 + xi∔3 + 1 ) ∙ (xi∔1 + 1) .

Combination of the terms with i=0 and i=1 gives

| (x₂ + x₃ + 1 ) ∙ f(x₀ + x₁) = (n+1) ∙ f(m) ,

Combination of the terms with i=2 and i=3 gives

| (x₀ + x₁ + 1 ) ∙ f(x₂ + x₃) = (m+1) ∙ f(n) .

Consequently, expression (5) equals P(m, n) .

Because (xi∔3 > xi∔1 ⇒ xi∔2 ≥ xi —and similarly (xi∔3 < xi∔1 ⇒ xi∔2 ≤ xi— we conclude om account of (2) that the second terms in (5) are ≥ 0. Therefore, P(m,n) ≥ 0 can be concluded from

| P(m div 2, (n+1) div 2 ≥ 0 and P((m+1) div 2, n div 2) ≥ 0

This observation concludes the inductive argument.

C.S. Scholten | Edsger W. Dijkstra
Philips Research Laboratories | Burroughs
5600 MD EINDHOVEN | Plataanstraat 5
The Netherlands | 5671 AL NUENEN
| The Netherlands

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD753

On a theorem by Lambek and Moser.

While looking for interesting functions mapping sequences of integers into sequences of integers, W.H.J. Feijen found in [1] the following results attributed to J. Lambek and L. Moser.

Let f be an ascending continued concatenation of natural numbers, more precisely:

| (A x : x ≥ 0 : 0 ≤ f x ≤ f (x+1)) ,

such that, furthermore, f x exceeds any given bound F for sufficiently large x, more precisely:

| (A F : F ≥ 0 : (E X : X ≥ 0 : (A x : x ≥ X : f x > F))) .

Let the function C with g = C f be defined by the relation for all y ≥ 0

| g y = (N x : x ≥ 0 : f x ≤ y)

(The right-hand side being read as “the number of distinct natural values x such that f x is at most y”). Obviously, g is also an ascending continued concatenation such that g y exceeds any given bound G for sufficiently large y.

The first result attributed to Lambek and Moser is that then f = C g, as is illustrated by the example

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ......
f : | 0 | 1 | 1 | 3 | 6 | 6 | 7 | 8 | 10 | 10 | ......
g : | 1 | 3 | 3 | 4 | 4 | 4 | 6 | 7 | 8 | 8 | ......

Let for any continued concatenation q of natural numbers the function D be defined by the relation for all n ≥ 0

| D q n = n + (q n) .

In the above example we would have

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ......
D f : | 0 | 2 | 3 | 6 | 10 | 11 | 13 | 15 | 18 | 19 | ......
D g : | 1 | 4 | 5 | 7 | 8 | 9 | 12 | 14 | 16 | 17 | ......

The second result attributed to Lambek and Moser is that D f and D g form a partitioning of the natural numbers. For people willing to generalize pictures the visualization “proves” these results. The elements of f and D f have been represented by vertical bars, one wide and of the corresponding length, those of g and D g have been represented by a horizontal ones. The mapping C then becomes a reflection.

Tracing the plot, we can place the bars in the order of increasing length: bar 14 is next (horizontally), bar 15 vertically, bars 16 and 17 again horizontally, etc.

[1] | Honsberger, Ross
| “Ingenuity in Mathematics”
| New Mathematical Library, Vol 23
| Mathematical Association of America (1970)

Plantaanstraat 5 | 9 October 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD 754

An error in EWD744.

When Scholten and I tried this morning to prove the correctness of the assertion made in the Note on page EWD744-2, we encountered difficulties, which were only resolved by finding a counterexample.

Obviously the six edges p, q, a, b, c, and d can not be ordered in a way with which pab, qbc, pcd, and qda are compatible. It is also easily verified that the four-process system, in which the processes claim three resources in the given orders, is deadlock-free. All by itself the cyclic path (a,b,c,d) could cause deadlock, but the shared resources p and q —even one of them would have sufficed— prevent the deadlock. The counterexample is symmetric in the four processes!

Plataanstraat 5 5671 AL NUENEN The Netherlands | 17 October 1980 prof. dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD755

Very elementary number theory redone.

The natural numbers are 0, 1, 2 and so on; for further details, see Peano.

The positive integers are natural numbers ≥ 1, i.e. 1, 2, 3 and so on.

The multiples are natural numbers ≥ 2, i.e. 2, 3, 4 and so on. The product of two multiples is larger than each of those two, in formula

| (A x, y : x ≥ 2, y ≥ 2 : x.y > x ∧ x.y > y ) | (1)

Multiples that are the product of two multiples are called composite, multiples that are not composite are called prime, in formula

| prime m = m ≥ 2 ∧ (A x, y : x ≥ 2, y ≥ 2 : x.y ≠ m) | (2)
| comp m = m ≥ 2 ∧ (E x, y : x ≥ 2, y ≥ 2 : x.y = m) | (3)

In view of (1), (3) can be rewritten

| comp m = (E x, y : 2 ≤ x < m, 2 ≤ y < m : x.y = m) | (3′)

From (3′) it is clear that it is decidable whether a specific m is composite.

Note that we have ¬(prime 1) ∧ ¬ (comp 1) .

With PF —for Prime Factorization— defined by

PF n = | n is the product of (0 or more) multiples, all of which are prime (the empty product being defined as 1)

we can state

Theorem 0. (A n : n ≥ 1 : PF n)

Proof. We shall prove Theorem 0 by mathematical induction, i.e. we shall prove

| (A n : n ≥ 1 : (PF n) ∨ (E i : 1 ≤ i ≤ n : ¬(PF i))) | (4)

Because (A n : n ≥ 1 : n = 1 ∨ (prime n) ∨ (comp n)) and the product of one number equals that number, we deduce from the definition of PF

| (A n : n ≥ 1 : (comp n) ∨ (PF n)) | (5)

Furthermore we deduce from the definition of PF

  (A x, y : x ≥ 1, y ≥ 1 : ¬(PF x) ∨ ¬(PF y ) ∨ PF(x.y ))

from which we deduce with (3')

| (A n : n ≥ 1 : ¬(comp n) ∨ (PF n) ∨ (E i : 1 ≤ i ≤ n: ¬ (PF i ))) | (6)

From (5) and (6), relation 4 follows by the standard inference rule. (End of Proof of Theorem 0).

Theorem 1. (A p : prime p : (E q : q > p : prime q ))

(This is Euclid's famous theorem that no prime is the largest one.)

Proof. Consider for arbitrary prime p the value Q defined by

Q = 1 + the product of all primes ≤ p.

Theorem 0 allows us to conclude that Q is the product of a bag of primes, and, because Q > 1, that bag is not empty. By virtue of Q’s construction, such a bag contains no prime ≤ p. Hence it contains at least one prime > p, hence at least one prime > p exists. (End of proof of Theorem 1.)

With UPF —for Unique Prime Factorization— defined by

UPF n = The bag of prime multiples whose product equals n is unique

we can formulate

Theorem 2. (A p, x, y : p ≥ 1, x ≥ 1, y ≥ 1 : ¬(prime p) ∨ ¬(p|(x.y ))  ∨  p|x  ∨  p|y  ∨  ¬(UPF(x.y )))

(Here “a|b ” should be read as “a divides b”.)

Proof. When the first two terms are false, x.y is the product of a bag of primes containing p ; when the next two terms are false, x.y is also the product of a bag of primes not containing p. Those two bags being different, we deduce ¬(UPF(x.y )). (End of proof of Theorem 2.)

We are now ready to state and prove

Theorem 3. (A n : n ≥ 1 : UPF n)

Proof. Theorem 3 is proved by mathematical induction, i.e. by proving

| (A n : n ≥ 1 : (UPF n) ∨ (E i : 1 ≤ i < n : ¬(UPF i ))) | (7)

Inspired by our proof of Theorem 0, we observe that (7) follows from (8) and (9), given by

| (A n : n ≥ 1 : (comp n) ∨ (UPF n)) | (8)
| (A n : n ≥ 1 : ¬(comp n) ∨ (UPF n) ∨ (E i : 1 ≤ i < n : ¬(UPF i ))) | (9)

Of these two, (8) follows immediately from (2), (3) and the definition of UPF. Assertion (9) requires, however, a more elaborate argument.

Consider a value of n, m say, such that the first and last terms of (9) are false, i.e. such that

| (comp m) ∧ (A i : 1 ≤ i < m : UPF i ) | (10)

holds. Because m is composite, it can be written as

| m = p.P = q.Q with | (11)
1) | prime p
2) | p ≤ q
3) | P standing for the product of a non empty bag of primes all of which are ≥ p
4) | Q standing for the product of a bag of primes all of which are ≥ q.

We obviously have 2 ≤ P < m, 1 ≤ Q < m, and P ≥ Q.

The conclusion UPF m, required to prove (9), can be drawn from

| p = q ∨ (comp p) | (12)

as follows. When q is the smallest value in a bag of primes, comp q is false and from (12) we deduce p = q. From (11) we deduce P = Q, and from (10) we deduce that P and Q stand for the same bag of primes. Since p = q, p.P and q.Q then also stand for the same bag of primes, and UPF m has been established

Establishing (12) is now our only remaining obligation. It is trivial in the case p = q. In the case p < q we consider value the M defined by

| M = (q−p) . Q

Because 1 ≤ M < m, we conclude from (10) UPF m. Because M = q.Q −p.Q = p.P−p.Q = p.(P−q), we conclude p|M. Since prime P, we now conclude from theorem 2

| p | (q−p) ∨ p|Q | (13)

Since 1 ≤ Q < m, we conclude from (10) UPF Q, i.e. all the primes in the unique bag of primes whose product equals Q are ≥ q, hence > p. The bag being unique, we conclude ¬(P|Q ). In combination with (13) we conclude p|(q−p); since we were considering the case p < q, we can conclude that q is composite. Having thus established relation (12), we have fulfilled our last proof obligation. (End of Proof of Theorem 3.)

Corollary of theorems 2 and 3.
(A p, x, y : p ≥ 1, x ≥ 1, y ≥ 1 : ¬(prime p)  ∨  ¬(p|(x.y ))  ∨  p|x  ∨  p|y ) .

The above was written in reaction to the presentation in [1] of essentially the same proof of Theorem 3. I found that presentation contorted and notationally clumsy. They write (for (11))

| m = p₁ p₂ ... pr = q₁ q₂ ... qs

Note the dots and the need to introduce the subscripts r and s. A little later, after having excluded p₁ equals q₁: “Suppose p₁ < q₁. (If q₁ < p₁, we simply interchange the letters p and q in what follows (sic).)”. A third of a page later they conclude that “the prime decomposition of m′ must be unique, aside from the order of the factors”. Theorem 2 isn't mentioned and when needed in the proof of Theorem 3 they borrow the result from a corollary of theorem 3! (Here their argument is almost cyclic.) And it is full of reductiones ad absurdum.

[1] Courant, Richard & Robbins, Herbert, What is mathematics? Oxford University Press paperback, 1978.

Plantaanstraat 5 | 20 October 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD756

A postScript to EWD755.

While presenting my proof of Theorem 2 in EWD755 I had forgotten my own preaching (in EWD731): with explicitly named predicates a more symmetric presentation is possible. With

C n p = | n is the product of a bag of primes containing p

D n p = | n is the product of a bag of primes not containing p

we have (as obviously as before) for positive integers p, x, and y :

1) | ¬(prime p) ∨ ¬(p|(x.y)) ∨ (C(x.y) p)
2) | p|x ∨ p|y ∨ (D(x.y) p)
3) | ¬(C(x.y) p) ∨ ¬(D(x.y) p) ∨ ¬(UPF(x.y))

Theorem 2 now follows by the standard inference rule. Note that for 1) and for 2) we need Theorem 0. (In EWD755 I failed to mention this.)

*              *
*

The above I regard as a different (and preferable) presentation of the same proof as in EWD755. The following alternative proof of theorem 0 from EWD755 I consider (perhaps somewhat arbitrarily) different.

Consider, for n ≥ 1, the following program

if | n = 1 → bag := ∅ ⫿ n >1 → bag := {n} fi;
do | bag contains a composite multiple →
| replace each occurrence of the largest composite multiple c in bag by the multiples x and y, where x.y = c
od |

The repetition leaves the product of the numbers in bag equal to n. On account of (3') from EWD755 —which is, of course, again needed— the lowest upper bound for composite multiples in bag can be taken as variant function, and termination is guaranteed. This proof is more constructive; Euclid would have liked it (if he did not prove it that way!).

Plantaanstraat 5 | 23 October 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD757

A misguided educational effort.

The other day I received a nice problem, which is a generalization of a problem I once invented. (See EWD570 and EWD578.) For n ≥ 1 the function f(n) is given by

| f(1) = 1 |  | (0)
| f(2k) = f(k) | for k ≥ 1 | (1)
| f(2k+1) = h (f(k), f(k+1)) |       " | (2)

The problem is to design an efficient algorithm for the computation of f(N) when no special properties of the integer function h —such as symmetry or associativity— are given.

From 1 and 2 we observe that the f-values for the consecutive argument pair 2k, 2k+1 are expressed in those of the consecutive argument pair k, k+1. Because

| f(2k+2) = f(k+1) | (1′)

also the f-values for the consecutive argument pair (2k+1, 2k+2) are expressed in those of (k, k+1). (Note that the above observations are not “surprising”: they are about the only thing inspection of (1) and (2) can teach us.)

The above observations suggest to carry out the computation using pairs of f-values corresponding two pairs of consecutive arguments.

More precisely, with (x, y) standing for a pair of consecutive arguments, i.e.

| x + 1 = y | (4)

and this (p, q) standing for the pair of corresponding f-values, i.e.

| p = f(x) ∧ q = f(y) | (5)

it is suggested to use (4)∧(5) as invariant relation. It can be established for the smallest values of the argument —(x, y) = (1,2)—; when we can hit the argument N by repeatedly “doubling” the pair of consecutive arguments (x, y) under invariance of (5), we have solved the problem. Because the initial value of y is already greater than N’s minimum value, we shall try to hit N by x, i.e. to establish x = N.

The repeated “doubling” of the argument pair (x, y) suggests the introduction of a variable, r say, whose value is restricted to powers of 2; the guiding of the “doubling” process requires two-sided control, which we can express by enclosing N in a shrinking interval. In short, we propose

| (E i : i≥0 : r=2i) ∧ r *x ≤ N < r *y | (6)

as our next invariant.

The above suggestions lead directly to the following program:

x, y, p, q := 1,2,1,1;
r :=1; do N ≥ r *y → r :=2*r od {(4) ∧ (5) ∧ (6)};
do r≠1 →
| r := r/2;
| if r * (x+y) ≤ N →
|  | x, y, p := x+y, 2*y, h(p, q)
| ⫿ N < r * (x+y) →
|  | x, y, q := 2*x, x+y, h(p, q)
| fi {(4) ∧ (5) ∧ (6)}
od {(4) ∧ (5) ∧ (6) ∧ r=1, hence p = f(N)}

Storing r.x and r.y as a and b respectively, we can code the same algorithm alternatively

a, b, p, q := 1,2,1,1;
do N ≥ b → a, b := 2*a, 2*b od {a ≤ N < b};
do a+1 ≠ b →
| k := (a+b) / 2;
| if k ≤ N → a, p := k, h(p, q)
| ⫿ N < k → b, q := k, h(p, q)
| fi
od {p = f(N)}

and we cannot help recognizing our dear old friend, the Binary Search.

In the above, the heuristics, though standard, have been fully spelled out for pedagogic reasons. Finding the above algorithm should not take a well-trained programmer very much time, nor much more paper than the proverbial backside of an envelope.

*              *
*

There exists a school (I wouldn't call it “a school of thought”) that believes in “teaching by example” and in “discovery by example”. I don’t. I concluded EWD376, which describes in detail the actual steps in which I had solved a problem from graph theory, with:

Finally we draw attention to the fact that we did not need a single example to explain what we were talking about or even worse to discover what the program should do. And this, of course, is as it should be.

From a colleague, who had written to me in 1970 “Somehow you seem to ignore (or attempt to ignore) what is known about the psychology of invention.”, the quoted paragraph evoked in 1974 the comment “The final remark looks to me like rubbish. But highly indicative of the author’s attitude!”. (Curiously enough —for he is a conscientious fellow— he did not take the trouble to reconcile his characterization “rubbish” with the fact that his own solution of the same problem was vastly inferior to mine.)

When we have to deal with a large set, inspection of the individual members is usually a waste of time; when the inspected subset is not “representative”, the inspection of individual members can even be profoundly misleading. Since, eventually, we have to deal with the whole set, thereby appealing to its definition, it is as a rule much more effective to analyze that definition directly. For the sake of effectiveness, one tries —as always!— to avoid exploding case analyses like the plague; inspecting individual members is almost the extreme of what one should learn to avoid. (Whenever you hear the traditional programmer’s excuse for a bug: “Oh, but that was a very special case!”, someone reveals he hasn’t been trained to think effectively.

The little problem mentioned and solved above occurs in a paper, whose main topic is apparently programming methodology. I haven’t seen the rest of the paper, but it must be terrible.

Drawn as trees, f(4) through f(16) are enumerated. The text continues with “We shall not use now our standard generalization procedure since it asks for many examples and would become a little cumbersome.”. Then the trees are re-drawn, with left and right leaves labeled differently; comparing f(n) with f(2³ + n) for 4 ≤ n < 7, the authors formulate a hypothesis about f(x) and f(x−2i when “2i is the greatest power of 2 contained in x.” After the confession: “The reader may feel that this induction hypothesis comes from too little information and would be right (we actually used traces for 1 ≤ x  ≤ 128)”, they inspect a few more labeled trees and come up with yet another “induction hypothesis”.

Finally they produce a very clumsy formulation of the solution given about (expressed in terms of such delightful functions as the length of the train of leading ones in the binary representation of x). That final clumsiness of their solution is, of course, no accident: it faithfully reflects the twisted route via which the solution has been reached.

This last observation gives me a second reason for objecting to such primitive heuristics: besides making problem solving a laborious and not very effective process, they lead —if they lead to anything at all— to inferior solutions. The observation invalidates the rather Jesuitical standpoint that, in heuristics, any approach is as good as any other as long as it leads you to an idea how to solve a problem.

Almost needless to say, the authors present (in 1980!) the solution without even a shadow of a correctness proof; “poor man's induction” is deemed sufficient.

*              *
*

That even at major universities such primitive heuristics are taught and recommended is depressing. I have no reason to suspect that the authors don’t teach the methodology with the best of intentions and in good faith. But the faith is wrong, despite its perpetuation by the psychologist and the educationalists. I know that they try to observe and describe how “people” solve and learn, but what is the value of such experiments? Even the vast majority of mathematicians should be regarded as amateur thinkers; in view of the “human material” used for such experiments, we cannot expect the psychologists and educationists to observe anything other than bad habits. It is our responsibility not to raise them to standards. I think we had, indeed, better “attempt to ignore what is known about the psychology of invention.” Most of it “looks to me like rubbish.”

Plantaanstraat 5 | 31 October 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD758

An intriguing example.

In the following all variables and all elements of the infinite arrays f [0...] and g[0...] are of type natural number.

Array f is ascending, i.e.

| (A x : x≥0 : f [x] ≤ f [x+1]) | (0)

and unbounded, i.e.

| (A y : y≥0 : (E x : x≥0 : f [x] > y)) | (1)

As a result of (1)

prog 0: | do f [x] ≤ y → x := x+1 od

terminates. Also — obviously —

prog 1: | do f [x] > y → g[y]:= x; y := y+1 od

terminates. The “combined” program

| x, y := 0,0;
| do f [x] ≤ y → x := x + 1;
|  ⫿ f [x] > y → g[x] := x; y := y+1
| od

obviously fails to terminate. Hence, x and y are both unbounded: more and more of f will be taken into account, and more and more of g will be defined.

From 0 we derive

| (N i : i≥0 : f [i] ≤ f [x]) ≥ x+1 | (2)

The weakest precondition that x := x+1 establishes

| (N i : i≥0 : f [i] ≤ y) ≥ x | (3)

is, according to the axiom of assignment,

| (N i : i≥0 : f [i] ≤ y) ≥ x+1 ,

which, on account of (2), is implied by f [x] ≤ y; hence, the first alternative leaves (3), which is established by x, y := 0,0, invariant. So does the second alternative (obviously).

From f [x] > y we derive, on account of (0)

| (N i : i≥0 : f [i] ≤ y) ≤ x ,

which, in conjunction with (3) allows us to conclude that, then, (N i : i≥0: f [i] ≤ y) = x. Hence, we have the second invariant

| (A j : 0≤j<y : g[j] = (N i : i≥0 : f [i] ≤ j)) | (4)

and this is exactly the property I wanted to prove about my program

*              *
*

The example is — see EWD753— inspired by the theorem of Lambek and Moser, a theorem Wim Feijen found when looking for functions to be programmed in SASL. As a matter of fact, my “combined” program was not the first program I wrote to solve this problem: it is a direct translation of the following SASL definitions I wrote first: (my syntax)

| def k x y (p:q) = | (5)
|  | if p ≤ y → k (x+1) y q
|  |  ⫿ p > y → x : k x (y+1) (p:q)
|  | fi
| def g = k 0 0 f

But even the proof of the fact that g is ascending —which in the iterative program follows trivially from the equally obvious invariant

| y = 0 cor g[y−1] ≤ x —

was very painful when I tried a proof technique � la EWD749 which does justice to the “functional” nature of applicative languages: (5) is expressed in terms of tails, my proof is in terms of finite prefixes. I think I should ask an expert (See EWD759.)

Plantaanstraat 5 | 9 November 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD759

A somewhat open letter to D.A. Turner.

Dear David,

I read with considerable interest your "Program Proving and Applicative Languages", but when I tried to apply your techniques to the first slightly more ambitious example my assistant W.H.J. Feijen came up with, it turned out to be a very humbling experience: I clearly lacked the knack of dealing with SASL programs.

Consider the following short SASL definitions (my syntax! I trust you will forgive me that)

def k x y (p : q) =
      if p ≤ y → k (x + 1) y q
       ⌷ p > y → x : k x (y + 1) (p : q)
      fi ;

def g = k 0 0 f

Here f is supposed to be ascending, i.e. to satisfy (P₀ f ) with

P₀ (a : b : c)   =   a ≤ b ∧ P₀ (b : c)

and unbounded, i.e. to satisfy (Ay : y ≥ 0: P₁ y f ) with

P₁ y (p : q)   =   p > y ∨ (P₁ y q).

When f is ascending and unbounded, it is clearly an infinite list. (I try to use the more positive term "continued concatenation" for that, but that is another story.)

You would do me a great service by showing me a proof that when f is ascending and unbounded, g is ascending and unbounded.

The precise formal relation between g and f is that for all y ≥ 0

sub y g = (N x : x ≥ 0 : y ≥ (sub x f )) | (0)

where sub is defined by

def sub n (p : q) =
      if n = 0 → p
       ⌷ n > 0 → sub (n−1) q
       fi

and the (N ... ) should be read as: the number of distinct values x in the range x ≥ 0 such that y ≥ (sub x f). You would do me a great service by showing me as well, how you would prove (0). I am looking forward to your reply.

         With my greetings and best wishes,

                   Yours ever

                            Edsger

5 November 1980

transcribed by Guy Haworth
revised Thu, 8 Nov 2007

EWD760

A somewhat open letter to F. Kr�ger.

Dear Dr. Kr�ger:

In a recent article [1], you prove —in my notation, see [2] —

{a ≤ 100 ∧ b = 1}

do 100 < a ∧ b ≠ 1 → a, b := a−10, b−1

 ⫿ a ≤ 100 → a, b := a+11, b+1

od {a = 101}

Allow me to show you the argument I, as a programmer, came up with.

I rewrote the proof obligation as follows

{a ≤ 100 ∧ b = 1}

do a ≤ 100 → a, b := a+11, b+1 od;

{P0, hence P0 ∨ P1 ∨ P2}

do 110 < a ∧ b ≠ 1 → a, b := a−10, b−1 {P0 ∨ P2}

 ⫿ 100 < a ≤ 110 ∧ b ≠ 1 → a, b := a−10, b−1 {P1}

 ⫿ a ≤ 100 → a, b := a+11, b+1 {P0}

od {(P0 ∨ P1 ∨ P2) ∧ 100 < a ∧ b =1, hence a = 101}

with | P0 = 100 < a ≤ 111 ∧ b ≥ 2
| P1 = 90 < a ≤ 100 ∧ b ≥ 1
| P2 = (a = 101) ∧ (b = 1) .

The two program transformations have no effect. You may always insert before a repetitive construct an excerpt from it; you may always split a guarded command. The first repetitive construct terminates obviously. The verification that P0 ∨ P1 ∨ P2 is an invariant of the second one is simple and straightforward.

In order to prove the termination of the second repetitive construct, we observe

1) | the initial truth of P0. (excluding truth of the last guard)
2) | that the truth of P1 implies the falsity of the first two guards and the truth of the last one.

As a result the last two guarded commands may be merged and the invariant relation may be strengthened. We rewrite the second repetitive construct as follows

{P0, hence P0 ∨ P2}

do 110 < a ∧ b ≠ 1 → a, b := a−10, b−1 {P0 ∨ P2}

 ⫿ 100 < a ≤ 110 ∧ b ≠ 1 → a := a+1 {P0}

od {(P0 ∨ P2) ∧ b = 1, hence a = 101}

In view of P0 ∨ P2, the first guarded command sets a = 101; the second guard remains true until a = 111. The guards being mutually exclusive, we may rewrite —note that a loop with only the second guarded command obviously terminates—

{ P0 ∨ P2 }

do 110 < a ∧ b ≠ 1 → a, b := 101, b−1 {P0 ∨ P2}

 ⫿ 100 < a ≤ 110 ∧ b ≠ 1 → a := 111 { P0 }

od

Because P0 ∧ a = 111 implies the truth of the first guard, by almost the same device as used before, the two guarded commands can be merged, giving

{ P0 ∨ P2 }

do 100 < a ∧ b ≠ 1 → a, b := 101, b−1 {P0 ∨ P2} od

which trivially terminates. This includes a proof with a minimum amount of formal labor.

*              *
*

When I saw the length of your proof, it put me off; I stopped reading and developed the above argument. I had never really analyzed with McCarthy’s 91 function: it has always struck me as a rather contorted puzzle. After the above proof, I proved the termination in the style of R.W. Floyd, using a well-founded set; from that I derived a closed formula for the exact number of repetitions. It is neither long, nor difficult; but it is too boring to record here; the steps of the derivation are completely standard.

*              *
*

In my opinion —but the opinion is a well-considered one— computing science needs the kind of vigorous mathematics that results from a subtle balance between the application of formal techniques and of common sense. (And there are reasons to believe that in computing science that balance is more critical than in many other areas of mathematics.) I trust you can now understand why I find it hard to consider your “Generalized invariants” of great significance in the context of computing science. Perhaps your paper had better been published in the Journal of Logic than in Acta Informatica, where it gives fuel to the accusation that the latter publishes too much “pompous irrelevance”.

[1] | Kr�ger, F. : Infinite proof rules for loops. Acta InInformatica 14, 371-389 (1980)
[2] | Dijkstra, Edsger W.: A Discipline of Programming. Prentice-Hall, Inc, Englewood Cliffs, N.J., USA

Plantaanstraat 5 | 11 November 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD761

Een kanttekening.

De hele discussie over experimentele studierichtingen informatica is zozeer in het politieke vlak getrokken, dat zelfs Gedeputeerde Staten van Noord-Brabant hun duit inmiddels in het zakje hebben gedaan. Het onmiskenbare enthousiasme der politici wordt door serieuze informatie: echter niet gedeeld, en deze discrepantie tussen de opvattingen van leek en vakman verdient een kanttekening. (Niet dat deze kanttekening mij alom in dank zal worden afgenomen: bij velen heeft het politiek enthousiasme al zo onstuitbare vorm aangenomen, dat ze van de discrepantie niet eens meer willen horen.)

Het politiek enthousiasme vindt zijn oorsprong in twee heel verschillende overwegingen. Het is ten eerst een reactie op de technologische ontwikkeling die in de “chip” is geculmineerd: reductie in omvang schijnt de technische mogelijkheden te scheppen —en reductie in prijs de financiële— voor allerlei nieuwe toepassingen van digitale apparatuur. De vruchten der technologie liggen kennelijk voor het oprapen; wie niet ijlings ook op deze “bandwaggon” springt, raakt kennelijk hopeloos achter; de “chip” wordt de motor van onze economie, etc.

Het is ten tweede de reactie van onze academische instellingen (als instituten) op deze euphorie. Beducht voor teruglopende inschrijving zien zij hun kans schoon. Bloeiende studierichtingen informatica kunnen kennelijk de bedreigde academische instellingen aan de nodige studenten helpen. Eindelijk kunnen ze realiseren wat al jaren van hen verwacht wordt: maatschappelijk relevant bloeien.

Maar hoe reëel zijn deze dromen? Wie zich erin verdiept wat verantwoorde beoefening en toepassing van de informatica impliceert, ziet de noodzaak van het proces dat zich steeds duidelijker aftekent: de ontwikkeling van de informatica tot een nieuwe —zij het om begrijpelijke redenen vrij ongebruikelijke— tak der wiskunde. Wie zich voorts de noodzaak van voortreffelijke taalbeheersing realiseert, beseft dat slechts een vrij beperkt aantal jonge mensen tot de vereiste competentie kan worden opgeleid.

Als experimentele studierichtingen informatica —tegen alle pressie in— het peil handhaven en aan de studenten de eisen stellen, die het vak nu eenmaal stelt, blijft het een bescheiden aantal studenten betreffen, en dat was niet de bedoeling! Zo het lukt, zullen de verantwoordelijke informatici in gebreke worden gesteld.

Als ze aan de pressie toegeven en aanzienlijke aantallen z.g. “informatica-ingenieurs” gaan afleveren, is het merendeel schromelijk incompetent. Wat gedroomd was als een bloeiende activiteit, wordt binnen het academisch bedrijf een etterende zweer, met de wiskunde in de weinig benijdenswaardige positie van de korst op het pus. Ook dan zullen de verantwoordelijke informatici de schuld krijgen. Voor de gevolgen van de incompetentie der z.g. “informatica-ingenieurs” zal het wetenschappelijk onderwijs dan mettertijd de rekening gepresenteerd krijgen.

De dromen zijn niet reëel. De informatica bevindt zich in de benarde positie een taak opgedrongen te krijgen, waarvan de onmogelijkheid, hoewel technisch aantoonbaar, politiek onacceptabel is. Die onmogelijkheid is zo inopportuun, dat politici haar domweg ontkennen; wie haar nochtans betoogt, wordt gemakshalve als perfectionist afgeschreven.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 13 november 1980 prof.dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD762 - 0

We mathematicians are losing the race.

I am furious! I am [expletive deleted] furious! While we believed we had succeeded --be it at considerable expense-- in convincing all Wall Street analysts that it would be premature to be too explicit about the problems of the Hosannah Press, BUSINESS WEEK (of September 1, 1980) blew the gaff! And it did not do so in an inconspicuous comment, but it devoted a complete Special Report to the situation! Am I, as Chairman of the Board of Mathematics Inc., allowed to be furious?

Hosannah Press is a more or less independent daughter of ours, and flourishing she was! She published the well-known series "Better Mathematics for the Millions" at reasonable cost; she hired genuine mathematicians (from us) to provide the material, but the royalties (to us) used to be no more than 10% of the turnover. As I said, she was a fairly independent daughter, and that's the way it should be.

But things have changed. The first disturbance of the financial relations was caused by computerized typesetting, which significantly reduced the production costs of mathematical books (which used to be healthily high on account of all the formulae). The next assault came from Xerox

EWD762 - 1

and all the Japanese copiers in its wake. But the complete distortion of the price balance came with the wide-spread acceptance of the microfiche!

The market is just enormous: on microfiche you can produce a book for about 1/100th of the original price, and they are so small that a shelf can store a thousand times as many books. A booming new industry, you would expect.

Forget it! Our mathematicians are not keeping up with the advances in printing technology. From a physical point of view, a publication is now so cheap that royalties have risen to more than 90% of the total cost. With such a ridiculous price balance, the financial independence of our --in the meantime grown-up-- daughter becomes, of course, a farce, and you cannot blame her for accusing us for lagging behind.

We have shown her representatives what measures we had taken, such as our ISAPS (Interactive Semi-Automatic Proof System) and even the more impressive TDF (Theory Development Facility). The first one enables an average mathematician to increase his proof productivity from 30 to 60 lines a month, the second one allows a mathematician with a minimum of skills to produce up to a 100 times as much text as he has keyed in.

EWD762 - 2

But our daughter's representatives were not impressed at all. As one of them explained to us, we are only skimming the production process. For an effective cost reduction we need to design completely new axioms and inference rules, so natural and intuitively clear that even a child --not to mention the printer himself-- can develop all the mathematics needed to fill the publications.

The only thing we could do was to promise humbly to our grown-up daughter that we would do our best. We asked her what she would do during the shortage of really cheap mathematics. "Don't worry, Daddy," she said, "I just allocate 50% of my expenses to marketing."

In a way it is quite rewarding to see that an important journal like BUSINESS WEEK devotes a Special Report to Mathematics Inc. Semper floreat et crescat!

Hosannah Building
Plataanstraat 5
5671 AL NUENEN
The Netherlands
13 November 1980
prof.dr. Edsger W. Dijkstra
Chairman of the Board
of Mathematics Inc.

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD763 - 0

A proof by Rutger M. Dijkstra and me.

Theorem. Consider the grid points, i.e. the points (x,y) with integer coordinates x and y, and let each grid point be painted with one of C distinct colours. For each X and Y, X distinct vertical grid lines and Y distinct horizontal grid lines exist such that their X.Y points of intersection have all the same colour.

Proof. Consider, for some k, the "strip" of points (x,y) with 0 ≤ x < k . In this strip the number of distinct possible colour patterns for a row is bounded (by Ck, to be precise). The number of rows in the strip being unbounded, at least one colour pattern occurs therefore in at least Y distinct rows. By choosing k larger than C.(X-1) we ensure that, in each and hence in this colour pattern, at least one colour occurs at least X times.

Acknowledgement. After having proved the theorem for X=Y=C=2 --that was the problem as originally posed-- my younger son, Rutger, removed during our discussion of the generalizations the last case analysis from the argument.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 23 November 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD764 - 0

Repaying our debts.

To whom it may concern!

There is a wide-spread belief that, whenever a new area of human endeavour has been shown to be amenable to mathematical treatment, the rest of mathematics got eventually enriched by that development. It seems likely, and today I don't feel inclined to challenge the belief. But it raises a question.

Over the last 25 years, and at an increasing pace during the last 10 or so, programming has become "an area of human endeavour amenable to mathematical treatment": the art—or black magic!— of programming has evolved into a scientific discipline. In its relation to the rest of mathematics, computing science has so far been largely at the receiving end. The question I would like to raise is: "Has the time come to repay our debts?".

Is programming as a mathematical activity sufficiently novel? In other words, do we have any currency in which to repay our debts? Though aware of the danger of being accused of myopia, I venture an affirmative answer. I could give that affirmative answer more less ex cathedra: the programming challenge being like nothing mathematicians have ever

EWD764 - 1

faced before, the mathematics that grew to meet it must be sufficiently unusual. But such an answer is, of course, only convincing when we preach to the already converted. Slightly more convincing is perhaps a public confession: when I saw Hoare's first correctness proof of a program, I declared most emphatically that such a ballet of symbols was not my cup of tea! I have rarely been so wrong; several years later I was dancing the ballet myself, and I liked it.

If I needed a catch-phrase to capture what seems novel, I would come up with something like "problems of scale in a formal environment". Coping mathematically with the programming problem obviously implies that we regard the programming language we use as some sort of formal system, and each program we consider as some sort of formal object. As long as we ignore problems of scale, there is nothing novel in that approach, for it would be rather similar to what all sorts of logicians do. But programs are often big! Admittedly, most formal experiments have been carried out with rather small programs, but sizes are increasing and how to push the barrier still further is becoming an explicitly stated research topic.

I am perfectly willing to endorse the opinion that most vigorous mathematics results from a subtle

EWD764 - 2

balance between applications of formal techniques and of common sense. It is that view of mathematics that may explain some of programming's mathematical "novelty". In the previous paragraph I have explained the intrinsically formal nature of the programming activity; on the other hand, the programmer's environment—the modern computer—truly deserves the predicate "general purpose". The tension between the two might explain my feeling that the balance between formal techniques and common sense is more critical in programming than in many other areas of mathematics.

Over the last ten years, the predicate calculus became our tool for daily reasoning, its use gradually replacing more and more of the usual verbal arguments. This development was quite clearly forced upon us by the nature of the subject matter we had to deal with; the limited use the usual mathematician makes of the predicate calculus seems an indication of the "novelty" of the programmer's task.

A more wide-spread adoption of the predicate calculus in the rest of mathematics would be a very natural candidate for computing science's influence. I would consider that influence as very wholesome. Firstly, it seems a very effective way of cleaning up the presentation of many an argument. (We did experiments with a few examples, more or less chosen

EWD764 - 3

by accident, and each time the improvement was considerable.) Secondly, the discipline is purifying: formalization works as "an early-warning system" when things are getting contorted. Thirdly, it clarifies, since it reveals all sorts of mathematical distinctions—such as "proof by infinite regress"—as artefacts of an in retrospect unfortunate formulation of the argument.

In the long run its influence could be very profound indeed. With sufficient familiarity and sufficient manipulative agility the formal argument becomes the most concise way of capturing our "understanding": it becomes the way in which we prefer to "understand". Eventually it may invalidate the widely-held dogma of the unteachability of thinking.

In the above we need not be deterred by the predictable objection from mathematicians of the more conservative persuasion, who will point out that in most of existing mathematics the logical structure of the arguments is not intricate enough to warrant their formalization, since, even if their observation is correct, there remains the question of the chicken and the egg.

* |  | *
| * |

Another channel through which computing science

EWD764 - 4

could exert a potentially profound influence on the rest of mathematics is the computing scientist's attitude towards notational conventions. In the early days, when large sections of the computing community considered the constraints of the limited character set of the punched card sacrosanct, we have committed the most terrible sins, and—I am sorry to say—limited printing facilities of modern terminals seem nowadays to invite similar sinful behaviour.

That physical austerity has not been totally unwholesome. With B a predicate on the natural numbers, I denote quantification by

           (E x: 0≤x<X: B x) and (A x: 0≤x<X: B x)

Historically, the use of underlining for the creation of new characters has been inspired by the constraints of the typewriter (and of the Flexowriter in particular). But even in handwriting I prefer the E and A over the ∃ and the ∀ respectively. It can immediately be generalized to

           (N x: 0≤x<X: B x)          (1)

for the number of distinct values x in the range 0≤x<X, such that B x holds. (This is just to illustrate that the "upside-down convention" is an un-

EWD764 - 5

fortunate one.)

The recursive definition of (1) is left as an exercise for the reader. The underlined "N" in (1) is, however, only a minor issue: it has been included because
a) I could not work without it myself, and
b) I never encountered it in the mathematical literature.

I did encounter in the literature—even several times—something else, viz. the remark that it is very clumsy to express formally that the integer sequence A[0..N-1] is a permutation of the integer sequence B[0..N-1]. But, using (1), one can do so very easily! I could not escape the impression that, thanks to computing science, a somewhat different tradition of using symbolism has emerged.

* |  | *
| * |

Here is another observation. I think the average mathematician is not as keen as he could be to avoid avoidable case analyses. Let me give you one simple example from Ross Hansberger's "Mathematical Morsels". The example is interesting, since the copied page has been taken from a book in a series, explicitly devoted to "the purpose of furthering the ideal of excellence in mathematical exposition."

EWD764 - 6

Compare the alternative exposition. Consider a rectangular array of 7 rows of 3 points each. In each row one of the colours dominates. Select four rows in which the same colour dominates and select in each of those two points of the dominant colour. At least two of such latter selections occurred in the same pair of columns, since a pair of columns can only be selected in three different ways. The conclusion follows.

Hansberger's "say red" and his final three-case analysis have completely disappeared. (So have his P's, Q's, and R's; and all the subscripts.) In a comparable degree of verbosity the alternative exposition is only half as long. (The example has been chosen by coincidence: I encountered the problem when I had already started on this text.)

EWD764 - 7

People with a programming background are more alert at trying to avoid case analyses than other mathematicians, who don't seem to mind so much. I made this observation in the mid-seventies—during my, at the time numerous, travels—and it has never amazed me: as a programmer you know only too well that you have to "pay" for each case analysis as reflected by an alternative construct "if......⌷......fi" in your program, and the analogy between program structure and proof structure is too obvious to be missed. The tendency to avoid avoidable nomenclature (such as Hansberger's P's, Q's, and R's) is in all probability spin-off of the same influence.

* |  | *
| * |

The discrete nature of much of computing's subject matter has quite naturally increased the role of mathematical induction. First an observation. In order to prove for some predicate P,

           (An: n≥0: Pn)                              (2)

a proof by mathematical induction proves

           (An: n≥0: P'n)                             (3)

with P' given by

           (P'n)= (Pn) ∨ (Ei: 0≤i<n: ¬(Pi))           (4)

EWD764 - 8

Since (3) is of the same structure as (2), why not prove it by mathematical induction? I.e. why not prove (3) by proving

           (An: n≥0: P"n)

with—as in (4)—P" defined by

           (P"n)= (P'n) ∨ (Ej: 0≤j<n: ¬(P'j))         ?

By substituting (4) into the right-hand side of the definition of P", however, we deduce P"=P'. In other words, we can apply the trick only once, and the decision to conduct a proof by means of mathematical induction is idempotent. Is this observation important? I don't know, but from a methodological point of view I think it is illuminating; it is in any case very fundamental. Admittedly my sample was small: I showed this observation to about a dozen mature mathematicians, and learned that it was new—even a surprise—for all of them. In my more optimistic moments such an experience makes me believe that greater methodological awareness could be one of the currencies in which computing science could repay its debts.

More in particular, I believe that mathematics in general could benefit from more explicit applications of mathematical induction. By way of example

EWD764 - 9

I refer the reader to my article in Acta Informatica (Jan. 1980), which derives by means of mathematical induction over n the multiplicity of a prime factor p in n! ; this inductive proof is much simpler than the traditional argument—see, for instance, D.E. Knuth's "The Art of Computer Programming", Vol. I—which relies on the shrewd rearrangement of factors. (Eventually it even needs the summation formula for the geometric series!)

Note. That traditional argument worries me very much since I met an otherwise gifted mathematician that particularly like it precisely for its shrewdness. (End of Note.)

* |  | *
| * |

Assuming, for the sake of the argument, that the usual style of mathematical reasoning leaves considerable room for improvement, we may raise the question "Does it Matter?". I think it does.

I remember vividly how I showed to one of my colleagues in the Department how we had learned to deal formally and intellectually in a satisfactory manner with all sorts of little algorithms. My colleague wasn't impressed at all and only asked "But does this enable you to find new algorithms?" I was shocked by that reaction.

Firstly, because I would have answer in full

EWD764 - 10

confidence "Of course it will.", hadn't it been for the fact that I could answer truthfully "Yes, it has already done so.".

Secondly, because he allowed the "quod" to prevail so strongly over the "quo modo". This utilitarian view of science is very much en vogue today. I am afraid that it is the prevailing view among today's mathematicians, but I have a lurking suspicion that exactly that attitude is mainly responsible for the fact that mathematics is no longer regarded as an integral part of our culture and—to quote Morris Kline—"Indeed, ignorance of mathematics has attained the status of a social grace."

I am daily faced with the havoc created by the wide-spread profound ignorance of what mathematics is about. By the cultural isolation of mathematics we all lose, and mathematicians had better remain aware that Elegance is the very core of their business! (And, please, remember that this remark is made by a pragmatic industrial mathematician.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 1 December 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by David Wilson

Last revised on Sat, 19 Jul 2003.

EWD765

A Hungarian problem.

Martin Rem returned from his trip to Hungary with the following problem. Let two positive integers p and q be given. We start with a bag containing a finite number of integers. When the bag contains some number, x say, at least twice, a move is possible; the move consists of replacing in the bag two occurrences of x by x+p and x−q respectively. Show that this game terminates.

When we characterize the contents of the bag by its characteristic function f —i.e. for all x, f (x) = the number of occurrences of the value of x in the bag— and use the initializing guard —which is true when the equation can be solved and sets the unknown to a solution— the game can be written as follows

do x : f (x) ≥ 2 →

| f (x−q), f (x), f (x+p) := f (x−q)+1, f (x)−2, f (x+p)+1

od

To start with, we generalize the game: for each move a new pair (p, q) of positive numbers may be chosen. Furthermore we extend our program with auxiliary array n, initially satisfying for all x   f (x) = n(x), and modified by extending the guarded command with the statement

| n(x−q), n(x+p) := n(x−q) + 1, n(x+p) + 1

In other words, after initialization n(x) counts how many times f (x) is increased.

With c defined as c = (N x :: n(x) > 0) we have

Lemma 0.

Each n(x) is bounded or c is unbounded.

Proof. Since each f (x) is bounded by the constant number of integers in the bag, an f (x) that is increased an unbounded number of times is also decreased an unbounded number of times, causing increases of n(y) for some y > x (and some y < x). Hence we have for all x:
   n(x) is bounded or (S y : y >x : n(y)) is unbounded.
Hence, for bounded c there is no largest x for which n(x) is unbounded, hence there is no such x at all. (End of proof of Lemma 0).

Since “c is bounded and each n(x) is bounded” is equivalent with “the game terminates”, and since P ∨ Q equals (¬Q ∧ P) ∨ Q, we derive from Lemma 0:

Lemma 1

The game terminates or c is unbounded.

The smallest value in the bag is the smallest value x such that n(x) > 0 ; the largest value in the bag is the largest value x such that n(x) > 0 . Hence, from Lemma 1 we conclude

Lemma 2.

The game terminates or the difference between largest and smallest value in the bag is unbounded.

With the derivation of Lemma 2, the auxiliary array n has done its work. Defining “a gap of length h” as a solution of the equation

f (x) > 0 and f (x+h) > 0 and (A j : x < j < x+h : f (j)=0)

we conclude from Lemma 2, because the number of integers in the bag is constant,

Lemma 3.

The game terminates or the length of the largest gap is unbounded.

Finally we undo some of our generalization: let the choice of the pair of positive numbers for each move be restricted to pairs (p, q) such that p+q ≤ K for some K. We then have

Lemma 4.

No gap exceeds the maximum of K and the length of the largest initial gap.

Combination of the last two lemmata solves the Hungarian problem.

Acknowledgement and concluding remark.

Thanks are due to the members of the Tuesday Afternoon Club with whom I discussed my first proof of Lemma 2. That proof used mathematical induction on the number of integers in the bag. I am particularly grateful to R.W. Bulterman for the persistence of his dislike of the three-case analysis in the induction step required; He also objected to some handwaving with which I draw a correct but sweeping conclusion from “A possible move remains possible until done”.

I must admit that I would have liked a simpler termination proof than the one I found this evening. Perhaps it doesn’t exist: Hungary is a traditional source of non-trivial problems.

Considering first the generalized problem was an improvement; relaxing constraints could be a general technique for doing away with reductiones ad absurdum.

Plantaanstraat 5 | 2 December 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD766

An educational stupidity.

The following two divisibility tests are widely taught at Dutch schools.

The 9-test. To reduce a number modulo 9, add its decimal digits. E.g., with N = 15098,

15098 ≡ 8+9+0+5+1 = 23 ≡ 3+2 = 5.

It is proved by observing that, modulo 9, 10 ≡ 1, hence 10k ≡ 1. As a derivative, we are taught the 3-test: N mod 3 = 2 because 5 mod 3 = 2.

The 11-test. To reduce a number modulo 11, add its decimal digits with alternating signs, e.g.

15098 ≡ 8 - 9 + 0 - 5 + 1 = -5 ≡ 6.

It is proved by observing that, modulo 11, 10 ≡ -1, hence 10k ≡ (-1)k.

*                *
*

Here is another approach to the 11-test. Interpret the number, by pairing the digits, as written in base 100 and start with the 99-test

15098 &equiv 1+50+98 = 149 ≡ 1+49 = 50 ≡ 6,

where the last congruence is only modulo 11.

The fact that the last test manipulates only natural numbers could be viewed as a minor advantage. It is more important to see that the 11-test is related to the 99-test in exactly the same way as the 3-test is related to the 9-test. It is now immediately obvious how to reduce N modulo 111, viz. via a reduction modulo 999:

15098 ≡ 15+098 = 113 ≡ 2  ,

where the last congruence is only modulo 111. The possibility of this generalization is well-hidden in the traditional formulation of the 11-test.

Two instances of the general method are being taught as isolated tricks. I know that the mathematics involved is absolutely trivial; so much the worse that it isn't taught in all clarity!

Exercise. Prove that none of the decimal numbers 1001, 1001001, 1001001001, 1001001001001, ........ is prime.

Plataanstraat 5 |  | 4 December 1980
5671 AL NUENEN |  | prof.dr.Edsger W.Dijkstra
The Netherlands |  | BURROUGHS Research Fellow.

transcribed by Om P. Damani
last revision Thu, 8 Nov 2007

EWD767 - 0

A.J. Martin's solution of the Hungarian problem.

The day after I had shown EWD765 to Alain J. Martin, he told me a proof of Lemma 2 using mathematical induction. Lemma 2 was:

| The game terminates or the difference between the largest and smallest value in the bag is unbounded.

Assume Lemma 2, which is true for the empty bag, to hold for a bag with N integers. Consider a non-terminating game for a bag with N+1 integers, and consider the two mutually exclusive cases

a) | there exists a value X that, from a certain moment, remains permanently in the bag; from that moment onwards the game is identical to the corresponding game with the N other integers.

b)
no value remains permanently in the bag; the largest value in the bag will increase and the smallest value will decrease, both beyond any bound. (Let, at a given moment X be the largest element in the bag and observe the state after the move in which X disappeared; for the conclusion it is irrelevant whether, prior to that move, X was still the maximum element.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 8 December 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD768

Largely on nomenclature.

Before embarking on a new book —something that is under consideration— I would very much like to decide (wisely!) with respect to notation and nomenclature all those conventions that will permeate all through the text. It seems wise not only to write such conventions down, but to include them for the sake of feedback in the EWD-series. Your comments are solicited!

For the pronunciation of the relations I propose the following:

for “x = y” read “x equals y”

for “x ≠ y” read “x differs from y”

for “x > y” read “x exceeds y”

for “x ≥ y” read “x is at least y”

for “x < y” read “x is less than y”

for “x ≤ y” read “x is at most y”

The above reflects my current habit. I adopted “at least” and “at most” about 20 years ago; they are much shorter than “greater than or equal to” and “less than or equal to” (not to mention the horribly ungrammatical “greater or equal to”). An equally conscious, but more recent choice was “differs from”. This latter choice is probably more fundamental; the trouble with “not equal to” and “unequal to” is that they treat equality as the basic concept and difference as its absence, an asymmetry without justification. When introducing complementary concepts, we should find names for both and not arbitrarily call the one the negation of the other. The term “exceeds” was adopted quite unconsciously, but I like it so much that I can only regret having been unable to find as nice a verb to express “is less than”.

For ordered sequences —a common topic in computing— we also need terms. I propose:

| K(0) > K(1) > . . . is a “decreasing” sequence,
| K(0) ≥ K(1) ≥ . . . is a “descending” sequence,
| K(0) < K(1) < . . . is a “increasing” sequence,
| K(0) ≤ K(1) ≤ . . . is a “ascending” sequence.

The term “ascending” has been introduced to replace terms like “non-decreasing” and “weakly increasing”. The term “non-decreasing” is even worse than “unequal”: it suggests that a sequence is either decreasing or non-decreasing. Quod non. (It is only true for monotonic sequences; so we find “monotonically increasing” and “monotonically non-decreasing”, but that I can only regard as a verbose patch: what should an increasing sequence be that isn’t monotonic?). The adverb “weakly” as used in “weakly increasing” should be avoided for its hidden negation: a weakly increasing sequence is not necessarily an increasing sequence. Let a desperately angry animal always be an angry animal, independently of the meaning of “desperately”. (From this point of view there would be no objection to “strongly ascending” for “increasing”.)

For 1, 2, 3, ... I propose “the positive integers” and for 0, 1, 2, 3, ... I propose “the natural numbers”. There are two reasons to include zero in the set of natural numbers. Firstly there is the linguistic reason that, if zero were excluded, the term “natural number” would be superfluous: “positive integer” would do. Secondly there is the mathematical reason that in many an argument zero is a most “natural” number. (More natural, as a matter of fact, than many mathematicians are aware of. I have often seen the case analysis “either n is not divisible by p, or n has k factors p” while the argument for the second case was perfectly valid for k = 0.)

Whenever a range of natural numbers has to be indicated, I shall do so lower bound included and upper bound excluded, as in the existential quantification in the following description of mathematical induction:

“In order to prove for some predicate P

| (A n : n≥0 : P(n))

one proves

| (A n : n≥0 : P′(n))

with P′ defined by

| P′(n) = P(n) or (E i : 0≤i<n : non P(i)).”

Exclusion of the lower bound, as well as inclusion of the upper bound, would have forced bounds outside the realm of the natural numbers. I intend to let a lower bound never exceed an upper bound; then we have the (minor?) advantage that two ranges can be joined to form a single one if the upper bound of the one equals the lower bound of the other. Finally, the number of elements in the range equals the difference of the bounds. It now stands to reason to identify the elements of a sequence of length M —rows of a matrix or characters of a string— by a subscript in the range 0 ≤ subscript < M.

Minor remark. All this deviates from established mathematical tradition, and, consequently, from most of the programming tradition. Since the traditional conventions just “grew”, it is not amazing that they leave room for improvement. What may amaze my reader, however, is the amount of importance I by now attach to such a detail. (It almost amazes myself.) But I cannot help it: the evidence is too overwhelming.

Let me just mention the most recent example I encountered. From the University of St. Andrews I received the manual for a programming language they had designed for educational purposes. I remember one example of its string handling facilities. The little program was supposed to strip off the leading zeros from a string of decimal digits. The text contains quite a few additions and subtractions of 1, which (except one addition) would have been superfluous if subscription of string characters had started at zero. More seriously, the authors had written the manual under the illusion that the program could produce the error message “the input string is empty” without realizing that this case was indeed subsumed by the other error message “the input string consist of zeros only”! A very telling bug.

*              *
*

The above text remained —not fully without reason— for a long time in my pile of unfinished manuscripts. I now declare it finished .

4 March 1981 | prof. dr. Edsger W. Dijkstra
Plantaanstraat 5 | Burroughs Research Fellow
5671 AL NUENEN |
The Netherlands |

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD770

D.A. Turner's reply.

In reply to EWD759, D.A. Turner sent me the following proof by returning mail.

“Thank you for your “somewhat open letter”, which arrived yesterday. You pose several task —the order in which I have decided to tackle them is to establish first the precise formal relationship between f and g.

First some notation. I shall call the elements of a list f ,   f₀ f₁ f₂ etc. and I shall use the notation

| [h(i)]Bi=A

for the list [h(A), h(A+1), ..., h(B)].

Now I define a function “upto”

| upto i f = least j ≥ 0 such that fj > i | (upto.0)

The claim to be established is that

| g = [upto i f ] ∞ i=0 | (Theorem 1)

From upto.0 we deduce the following two propositions, which could be considered a SASL definition of upto

| a > i ⊢ upto i (a:f ) = 0 | (upto.1)
| a ≤ i ⊢ upto i (a:f ) = 1 + upto i f | (upto.2)

We have also your definition of the function “k”

| p ≤ y ⊢ k x y (p:q) = k (x+1) y q | (k.1)
| p > y ⊢ k x y (p:q) = x : k x (y+1)(p:q) | (k.2)

From these four propositions we shall deduce the following generalization of Theorem 1.

Theorem 0. k x y f = [x + upto i f ] ∞ i=y

Proof by structural induction on f, which is an infinite list of integers.

case ΩL (Note — we need to distinguish between ΩL, the undefined element in the space to which f belongs, and ΩI, the undefined integer. The relationship between them is ΩL = [ΩI] ∞ i=0     )

| k x y ΩL = ΩL from k.1, k.2 by case exhaustion

whereas

| [x + upto i ΩL] ∞ i=y
| = [x + ΩI] ∞ i=y     | from upto.1, upto.2
| = [ΩI] ∞ i=y        | properties of Ω
| = ΩL | as required

case p:f

| k x y ( p:f )
|  | = [x]p−y ++ k x p ( p:f ) | by repeated appl. of k.2
|  | = [x]p−y ++ k (x+1) p f ) | by k.1
|  | = [x]p−y ++ [(x+1) + upto i f ] ∞ i=p | ex hyp.
|  | = [x]p−y ++ [x + (1 + upto i f )] ∞ i=p | properties of +
|  | = [x]p−y ++ [x + upto i (p:f ))] ∞ i=p | by upto.2
|  | = [x + upto i (p:f ))] ∞ i=y | by upto.1 and rearranging

QED Theorem 0.

Whence, since g = k 0 0 f, we have immediatly

Theorem 1 g = [upto i f ] ∞ i=0

Also you asked me to establish that g is A) ascending and B) unbounded, given appropriate assumptions about f. This now follows easily from the above. (Relaxing the level of formality somewhat) we have:

A) from upto.0 it follows (by transitivity of “>” that “upto i f " is an ascending function of i. Therefore, whatever the nature of f, g is ascending.

B) Let us define “f is unbounded” to mean, “for any N≥0, there is a j ≥0 such that fj > N. Assume f is unbounded (f ascending not relevant. Then, from upto.0,

| upto i f is defined for all i ≥0

Given any N≥0, define j = max{f₀, ..., fN} then upto j f = gj exists, and by construction > N. So g too is unbounded.

*              *
*

So far Turner's reply. I like Turner’s proof, and in view of the fact that Turner answered me by returning mail it would be misplaced to complain too much about the fact that, in “case p:f ” the definitely less interesting case p<y hasn’t been dealt with explicitly.

I am slightly uneasy in “case ΩL” —particularly after the parenthetical remark explaining the difference between ΩL and ΩI— about the justification “from k.1, k.2 by case exhaustion”. My uneasyness is certainly caused by lack of familiarity how to deal with Ω. Take

| funny (p:q) = | if p≥10 → 1: funny q
|  |  ⫿ p<10 → 1: funny q
|  | fi

Is funny ΩL = ΩL? Or is funny ΩL = ones (with ones = 1: ones)? I expect the first answer though I would prefer the second one, if I am giving full weight to the remark in [1], page 37).

The first point to be made is that in reasoning about SASL programs, Ω can be treated just like any other value as regards being substitutable in equations

Perhaps I have failed to fathom the complete depth of the constrained “as regards being substitutable in equations”.

The correspondence was triggered by remarks in [1] such as the recommendation of applicative programming (pg 14):

The proofs (like the programs themselves) are very much shorter than the proofs of the corresponding imperative programs.

I had my doubts, which have not been dispelled by the comparison of Turner’s proof with the one given in EWD758.

[1] Turner, D.A. “Program Proving and Applicative Languages”, August 1980

Plantaanstraat 5 | 27 December 1980
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 10-Nov-2015 .

EWD771 - 0

About 2-coloured 6-graphs.

Let each of the 15 edges of the complete 6-graph be either red or blue. Three of the 6 nodes are said to form a "homogeneous triangle" if the three edges connecting them are of the same colour. Prove the existence of at least two homogeneous triangles.

* |  | *
| * |

We call two edges that meet at a node and are of different colour a "mixed pair" meeting at that node. Because at any node 5 edges meet, at most 2 * 3 = 6 mixed pairs meet at that node. Because we have 6 nodes, there are at most 6 * 6 = 36 mixed pairs. Because each mixed pair occurs in one inhomogeneous triangle and each inhomogeneous triangle contains two mixed pairs, we have at most 36 / 2 = 18 inhomogeneous triangles. The total number of distinct triangles being (6*5*4)/(3*2*1) = 20, we have at least 20 - 18 = 2 homogeneous triangles.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 29 December 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD772 - 0

A methodological sequel to EWD771.

The first time I heard the problem mentioned in EWD771 it was only required to establish the existence of at least 1 homogeneous triangle, and the proposed proof was as follows.

Consider an arbitrary node, say X. Among the five edges meeting at X, one of the two colours, say red, dominates. Let XP, XQ, and XR be three red edges. Either the triangle PQR has a red side, PQ say, or it has no red side. In the first case triangle XPQ is homogeneously red; in the latter case triangle PQR is homogeneously blue.

Before I found the proof recorded in EWD771, I found the following argument for establishing the existence of a second homogeneous triangle.

We know the existence of one homogeneous triangle. Let it be red; call its angles the A's and denote the remaining three nodes by the B's. Then there exists a homogeneously red triangle AAB or in each B at most 1 red AB-edge meets.

In the latter case, at least 2 blue AB-edges meet at each B. But then BBB is homogeneously

EWD772 - 1

red or BBB has a blue edge. In the last case there exists a homogeneously blue triangle of the type BBA, since in both end points of the blue BB-edge two blue AB-edges meet, which have at least one A in common.

I never liked that proof --I don't think I ever recorded it before-- . I disliked it for its case analysis, which distinguishes among three cases: the first and the second homogeneous triangle share 0, 1, or 2 nodes. The proof of EWD771 is so much nicer because it avoids this case analysis; also it does not distinguish between a first and a second triangle. Finally it avoids the (minor?) ugliness of the "say red".

The trouble started already with "Consider an arbitrary node, say X.", thereby destroying the symmetry among the nodes. In the second part we have, similarly, the A's versus the B's. (We could have made it still worse by giving the A's and the B's subscripts!) What we have lost, right at the start, is the symmetry between the colours.

To my feeling, the underlying "secret" of EWD771's effectiveness is that it has fully exploited the colour symmetry: for a pair of edges, being of equal or different colour

EWD772 - 2

are the only functions that are invariant under colour inversion. Maintaining the symmetry among the nodes --to the extent that in EWD771 they remain unnamed!-- did the rest. A final virtue may be that the proof of EWD771 is less of an invitation to visualization. To quote E.T. Bell (from his essay on Cayley and Sylvester in "Men of Mathematics")

"If there is any virtue in talking about situations which arise in analysis as if we were back with Archimedes drawing diagrams in the dust, it has yet to be revealed. Pictures after all may be suitable only for very young children; Lagrange dispensed entirely with such infantile aids when he composed his analytical mechanics. Our propensity to "geometrize" our analysis may only be evidence that we have not yet grown up."

Plataanstraat 5 5671 AL NUENEN The Netherlands | 30 December 1980 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD773 - 0

Trip report E.W. Dijkstra, Han-sur-Lesse, 7-12 Jan. 1981.

Compared with the size of the globe, the distance between Neunen and Han-sur-Lesse is very short. But the meeting I attended was not worth travelling it. It was a meeting of IFIP WG2.3 "Programming Methodology", which was boring instead of exciting. (The most exciting part of it may have been the visit to the world-famous caves, but this poor tourist did not join the excursion.)

I greatly admired Tony Hoare's power of concentration --and envied him for it-- : whenever the "presentation" did not interest him, he just worked. Tony had a few productive days. The meeting improved 24 hours before its closure when Tony showed, on the blackboard, what he had been doing during the past days and was followed by Cliff Jones, who blew the lamp of the overhead projector. (Like a good Belgian --thank goodness!-- our host did not have a spare.)

These meetings have their problems: we have members willing to show results that might interest others or to introduce promising topics for discussion, but we also have members who would like to show what they have done. In earlier years, speakers from the latter category could be diverted, but that is much harder now. We

EWD773 - 1

are a bit too polite; besides that, how does one divert a presentator that clings for dear life to his foils --"prepared in advance"-- when they are the only thing he's got and he insists on completing the show? The foils are there, so he needs the feedback from the audience as little as a film projector needs it; hence, he can ignore his audience, and often does so. People that give presentations instead of lectures should be accused of the offence of "contempt of audience".

My shortest explanation of the sorry state of American computing science is the observation that the topic still had to become of age after the overhead projector had taken over the American University Campus. Last week has strongly confirmed my opinion that the wholesale defenestration of overhead projectors would be a most salutary measure. (The argument that "preparation in advance" improves the quality of the way of presentation hardly seems to hold water: almost all we were shown was ridiculous. The foils of Parnas were geared to the illiterate manager --you know the type of foil: "capitals only" was one of its leading characteristics-- ; in honour of his wonderful printing equipment, Balzer had used seven different type fonts on a single foil and, besides that, he spelled "auxiliary" as he pronounced it: "auxillary"; most of the others

EWD773 - 2

switched from colour to colour with neither rhyme nor reason: in Horning's case the colour of his printed foils was determined by the whims of his secretary.)

To my taste too many speakers identified the problems of computing science with the difficulty of computing in an illiterate environment.

In a discussion about the effectiveness of mathematical arguments I showed for comparison two different proofs of the same theorem: a usual one and a beautiful one. Afterwards Parnas suggested that I had shown the latter mainly to boost my ego. Apart from that remark (which I think pitiable), the meeting was quite good-humoured and often very funny. (Sometimes it was even too much so; controversy has been laughed off and I fear that the exchange of scientific ideas has been hampered.)

Three cheers for our host Michel Sintzoff! Our accommodation was perfect. Travel to and from the place was a little bit difficult, "but the food was excellent".

Plataanstraat 5 5671 AL NUENEN The Netherlands | 13 January 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD 774

Trip report E.W.Dijkstra, California, 17-31 January 1981.

This two-week visit to California was almost entirely devoted to Burroughs: the first week I gave in Dana Point —a little North of San Clemente— a programming course to about 25 Burroughs employees, the second week I was at the Burroughs plant in Sorrento Valley near San Diego.

It so happened that first week we were with 5 members of the Tuesday Afternoon Club at the West coast! Martin Rem and Alain J.Martin attended a VLSI conference at CalTech, while Wim H.J.Feijen and Joseph M.Morris gave in Beaverton a programming course to 40 employees of Tektronix.

Alain J.Martin and I crossed the Atlantic Ocean together on Saturday 17 January 1981. Flight KL 601 was comfortable: in the Business Class only 40% of the seats were occupied and we both managed to get some sleep. But it is a long, long flight, and I was tired when I arrived. I was very grateful I was delivered at the Marina Inn in Dana Point, where I went to bed immediately. The Sunday I used for partial recovery from the trip; for the evening dinner I was joined by two participants from San Diego and the father of one of them. The father was a psychiatrist from Los Angeles, who had expressed a desire to meet me; it was a pleasant and civilized dinner.

The next four-and-a-half days followed very much the same pattern: I woke up at 5:00, had breakfast at 7:00, lectured from 8:30 till 12:00 and from 14:00 till 17:00, and, after a few drinks, had dinner rather early in the evening.

The best place to give such a course is a hotel so isolated that all participants live there all through the course: the isolation then ensures that the common dinner fulfils its social function and that, thereafter, the people can join forces when trying to do the homework. Pecuniae causa almost the worst possible place had been selected: Dana Point had been chosen so that the maximum number of people (about 10) could sleep at home, and our marina Inn had no dining facilities, so that, in the evening, the remaining participants got scattered around. The Marina Inn was downright miserable —incoming messages did not come through, they forgot to bring in coffee in the morning, etc.—; the best I can say is that the overhead projector was so poor that I was allowed to use the (inadequate) blackboard. In view of all the handicaps, it was a miracle that the course was the success it turned out to be.

The audience was very mixed: it ranged from Bachelor to Ph.D.'s, from MBA's (= Masters of Business Administration) to mathematicians. (In particular the MBA's had a very hard time.) It was a nice group to work with; they worked very hard and with great loyalty. (Neither the inauguration of Reagan, nor the freeing of the hostages caused any disruption.) They found it very difficult: many of them were unfamiliar with formal techniques in general and none was used to apply them to programming, so they had to travel long and far. The strain was not only intellectual, but also emotional: I posed them simple problems that could be solved by programs of three or four lines, but over and over again they found themselves in the situation that the majority could not find the solution. (In Feijen's audience, a young man with a fresh degree got so cross with his former teachers that he felt like suing his university!) Friday noon we broke up with the usual little sadness.

I left for San Diego where, for the rest of the trip, I had the privilege of being the guest of Dr.Lawrence D.Rogers and his wife. The weekend was used for recovery; it had been an exhausting week. On Saturday we went to the San Diego Wild Animal Park, on Sunday we did mostly nothing. (I wrote a letter, but that was physically painful after a week's work with chalk on a blackboard.)

The next week we left at 7:45 for the plant (where we arrived at 8:00) from where we returned around 18:00. On Monday afternoon I went to UCSD, where I gave a lecture from 16:00 to 17:00; I may have misinterpreted my observations, but I found the faculty wavering between science and pragmatism. On Wednesday we rose at 6:00 because I had to catch an early flight to Los Angeles, from where I returned in the evening. That day I visited Systems Development Corporation in Santa Monica. Until 14:30 I spoke in succession with three different groups, from 15:00 till 17:00 I addressed a sizeable audience. During the first hour I showed an unusual argument that I had developed the day before; the second hour I answered (the usual) questions from the floor. Several times I was reminded of Tom Lehrer's "If you cannot communicate, the least you can do is to shut up." (I quoted Wittgenstein instead.) Carrying out a multi-person project was repeatedly presented as primarily a communication problem, but when you start thinking about it, this is largely nonsense. When working all by myself I write everything down, thus forcing myself to be as explicit as required. Working together can only be an added incentive to be even more explicit (if possible). I have a lurking suspicion that the root of the difficulties of the multi-person projects lies somewhere else, viz. that many of the people involved think only vaguely and that the misunderstandings are caused by the fact that people don't really understand why they (supposedly) think themselves. Calling this "a communication problem" suggests the existence of clear but unformulated thoughts, and that does not seem to be a very fruitful hypothesis. I fear that "the communication problem" is a misleading euphemism, the acceptance of which explains parts of the almost morbid preoccupation with "specification languages" and the like. As if new rules for musical notation would enable me to compose a symphony..........

At LAX I met Alain J.Martin a few minutes after I had checked in for flight KL 602. He came from San Jos� and had carried his luggage himself; I came from San Diego and had booked my luggage through to Amsterdam. Both arrangements worked. We left Los Angeles early Saturday evening, early Sunday evening we were home. The flight being more crowded, I had not been able to sleep.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 4 February 1981 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD775

On Kleinrock’s Theorem.

The following has been triggered by C.A.R. Hoare’s “A general conservation law for queuing disciplines” (Information Processing Letters 2 (1972) 82–85); this article refers to L. Kleinrock, “A conservation law for queuing disciplines”, Naval Research Logistics Quarterly (June 1965) 181–192, and has been submitted because it offers for Kleinrock’s theorem a proof that is simpler than the original one.

In Hoare’s formulation, Kleinrock’s theorem is as follows. Assume (1) No server is idle when there is a waiting customer. (2) Arrival times and service times of both customers and servers are not affected by the decision who is to receive service at what time (i.e. they are independent of the scheduling). (3) Preemption is not used. Then

N ∑ i=1 Wi ·Ri

is independent of the choice of non-preemptive scheduling method. Here the customers are numbered from 1 through N, Wi is the total waiting time for customer i, and Ri is the total service time for customer i.

This note is written to point out that (1) for a single-server system the proof is trivial, and (2) for a multi-server system the theorem is not quite correct.

*              *
*

Consider a schedule in which customer q is served immediately after customer p, with Wq > Wp. The possible decision to service these two customers in the other order would have affected the waiting time as follows.

Wp, Wq := Wp+ Rq, Wq− Rp

The products Wp· Rp and Wq· Rq are therefore increased and decreased respectively by the product of the service times, and their sum remains constant. Kleinrock’s theorem follows by induction

*               *
*

Consider a two-server system in which three customers, with service times =1, =1, and =2 respectively, arrive simultaneously. Two schedules are possible with ∑Wi · Ri = 1 and = 2 respectively. For customer i, which is served from t 0 till t1 we can define a “moment of inertia” of his service as

   t1 ∫ t 0 t ·dt  =  ½ (t1²−t 0²)  =  (t1−t 0) · ⟮

t 0 + t1 / 2

⟯  =  Ri · (Ai + Wi  + ½ Ri)  =  Ri · Wi + Ci

where Ai is the moment of arrival of customer i and Ci = Ri · (Ai + ½Ri); our assumptions imply that Ci is independent of the scheduling. If S(t) is the number of customers served at moment t, then the "moment of inertia” of total service satisfies

   T ∫ 0 S(t) ·t ·dt   =   N ∑ i=1 Ri ·Wi + N ∑ i=1 Ci

Hence, Kleinrock’s theorem holds among schedules with the same “moment of inertia” of total service.

Acknowledgement. I am indebted to C.A.R. Hoare for having invited me to try to simplify is proof (which was already a simplification of Kleinrock’s). (End of acknowledgement.)

Plantaanstraat 5 | 4 February 1982
5671 AL NUENEN | prof. dr. Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

Transcribed by Martin P.M. van der Burgt
Last revision 12-Nov-2015 .

EWD759

Lambek and Moser revisited

Let f be an ascending sequence of natural numbers, i.e.

(A i,j : 0 ≤ i < j : f (i) ≤ f (j))

that is unbounded, i.e.

(A j : j ≥ 0 : (E i : i ≥ 0 : f (i) > j)) .

The function lambo is defined as follows: lambo(f ) is a sequence of natural numbers and g = lambo(f ) means that for all y ≥ 0, g(y) = x, where x stands for the minimum value such that f (y) > x, or, more formally, where x satisfies

R : | (A i : 0 ≤ i < j : f (i) ≤ x) ∧ f (x) > y .

In order to compute g, we design a program with the invariant relation

P : | (A i : 0 ≤ i < j : f (i) ≤ x) ∧ f (x) ≥ y

x,y := 0,0; {P}

do 
f (x) = y → x:=x+1 {P}

▯ 
f (x) > y → {R} g(y):=x ; y :=y+1 {P}

od

(1)

Note firstly, that the program

| do f (x) = y → x :=x+1 od | (2)

terminates because f is unbounded; note secondly, that the program

| do f (x) > y → g(y):=x ; y :=y+1 od | (3)

terminates; note, finally, that on account of the last term of P program (1) fails to terminate.

Consider now program (4), in which we assume g to be initialized g = lambo(f ); the same P is again an invariant.

x,y := 0,0; {P}

do 
f (x) = y → x :=x+1 {P}

▯ 
f (x) > y → {R, hence g(y) = x} y :=y+1 {P}

od

(4)

Also program (4) fails to terminate; because we are entitled to assert g(y) = x in the second guarded command, the program still fails to terminate when we include that relation in the second guard

x,y := 0,0; {Q}

do 
f (x) = y → x :=x+1 {Q}

⌷ 
f (x) > y ∧ g(y) = x → y :=y+1 {Q}

od

(5)

From the fact that (5) fails to terminate we conclude a further invariant

Q: | g(y) ≥ x

We conclude this by considering ¬Q : g(y) < x. In that case (5) reduces to (2), of which ¬Q is obviously an invariant; because (2) terminates and (5) does not, ¬Q cannot occur. Having established the invariance of Q, we conclude that the program still fails to terminate when we "strengthen" the first guard with wp("x :=x+1", Q ):

x,y := 0,0;

do 
f (x) = y ∧ g(y) > x → x :=x+1

▯ 
f (x) > y ∧ g(y) = x → y :=y+1

od

(6)

But program (6) is symmetric in the pairs (x,f ) and (y,g); hence

(g=lambo(f )) = (f=lambo(g))     ,

in other words: the function lambo is its own inverse.

Finally, let us consider the program

x,y := 0,0;

do 
f (x) = y ∧ g(y) > x → { x + f (x) = n } x,n := x+1,n+1

⌷ 
f (x) > y ∧ g(y) = x → { y + g(y) = n } y,n := y+1,n+1

od

(7)

Program (7) has the obvious invariant x + y = n, which justifies the two assertions. They, however, are the respective weakest preconditions for the invariance of

Q1: | the sets { i + f (i) | 0 ≤ i < x } and { j + g(j) | 0 ≤ j < y } form a partitioning of the first n natural numbers 0 through n−1.

From the fact that x and y are unbounded and from the invariance of Q1, which is true at initialization, we conclude the second result of Lambek and Moser, viz. that { i + f (i) | 0 ≤ i } and { j + g(j) | 0 ≤ j } form a partitioning of the natural numbers.

Note. By introducing x + y = n in program (1) we could have derived the second result of Lambek and Moser immediately; it, in turn, implies that the function lambo is its own inverse. But I thought the independent derivation of (6) more fun. (End of Note.)

* |  | *
| *

I am not quite clear about the moral of the above. We have proved theorems about the function lambo by first deriving a program for it and then massaging the program. For me this is a novel application of semantics preserving program transformations, and this novelty —as all such novelties— causes some mild excitement. On the other hand we know that a chain of program transformations is so close to a mechanically verifiable proof that it seems vain to hope to prove any "deep" theorems this way. (Here I should add that I get less and less certain about the significance of the supposed difference between "deep" and "shallow" theorems.) It is possibly no more than an occasionally neat way of formulating an otherwise not unusual mathematical argument.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 8 February 1981 prof. dr. Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Günter Rote
revised Wed, 14 Nov 2007

EWD777 - 0

A word of welcome.

Judged by the age of dedicated journals, Computing Science is now more than 25 years old. It would even be a mature science if the number of journals devoted to it were a reliable yardstick: by now this number is so large that the practising computing scientist can hardly suppress a shudder at the thought of yet one more journal to browse. Why, then, do I welcome the appearance of "Science of Computer Programming"? The shortest answer is that this one might be worth reading, but that is not the full story.

Being programmable is the automatic computer's outstanding characteristic and, accordingly, programming is computing's central activity: it is the core of the whole topic. Amazingly enough, for more than 25 years we have had no journal specifically devoted to it: no journal, no special interest group, no conference, no nothing! This absence would be defensible if programming were trivial and we could all do it well, but this is not the case. (Who doubts this statement should ask his colleagues to design a program for the Binary Search.) It is not hard to argue that the appearance of "Science of Computer Programming" is overdue.

But I don't think it could have appeared much earlier. Naur was the first to complain to me about the absence of "program literature", i.e. published

EWD777 - 1

programs that could be read and studied like any other scientific article and that would set a standard; Hoare was the second one to voice that complaint to me. This was quite a few years ago, but already then a program of some sophistication was such a compact deposit of its author's intellectual labour, that its presentation in a way that would enlighten the reader was a major problem. Yet, mutual enlightenment is what forges scientific communities!

But a decade of work under the banner of "programming methodology" has changed the situation and justifies some confidence that we have reached the stage in which we can begin to communicate programs and their development for the enlightenment of our colleagues.

"Science of Computer Programming" also has a calling beyond the community of our closest colleagues. It should help ending the current state of affairs in which managers see programming primarily as a management problem because they cannot manage it, in which electronic engineers don't see the problem and in which mathematicians ignore it. "Science of Computer Programming" faces the challenge of showing the world at large that, concerning programming, there is far more than meets the eye. All by itself, that challenge would already be worth this new journal (which, I trust, will not adopt

EWD777 - 2

the silly convention of switching to a smaller type font as soon as program text has to be printed).

For "Science of Computer Programming", the challenges are great; so are the opportunities. My best wishes accompany it: may it live up to our expectations!

Nuenen | Edsger W. Dijkstra

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD778 - 0

A somewhat open letter to Nils J. Nilsson.

Dear Sir:

You asked for my opinion - expressed in a few paragraphs - about artificial intelligence. Here it is.

I consider automatic theorem proving a respectable branch of AI. The effort was non-trivial and honest, and a successfully constructed formal proof is a result of an undeniable solidity. Besides that, it has certainly been illuminating for those mathematicians that were unaware of the profound (but sensible) informality of most of their arguments. And that is about the best I can say of AI.

To my knowledge, AI has not revealed better ways of using our own minds; in this respect I consider all the work on recognition problems and on playing games absolutely irrelevant. Neither has AI assisted us in a better appreciation of our own minds. On the contrary, by describing machinery in anthropomorphic terms and man in mechanistic terms, it has only added to the confusion. To the artificial intelligentsia that argue "But we are only symbol manipulating machines, aren't we?" one can only answer "There is none so blind as them that won't see!". The analogy is so shallow that I can characterize an appeal to it only as typically medieval

EWD778 - 1

thinking.

Viewing problem solving as "searching the solution space" may be appropriate in the context of its mechanical simulation, but not outside that context, and from all the efforts aimed at improving the search heuristics I expect therefore very little of significance beyond AI itself. The pragmatic nature of the quality criteria for heuristics makes the search for "better" heuristics an opportunistic game, for which I see no reason to expect that it will ever converge.

Finally, I know computing science as the prime example of a (cruelly) hard science - much less forgiving than mathematics in general - ; it never entered my mind to consider AI, in all its softness, a branch of it.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 26 February 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Sun, 13 Jul 2003.

EWD 782

A stupid notation.

For a set of  n  elements, the number of different subsets of  k  elements (0 ≤ k ≤ n) is

n!
––––––––
k!�(n-k)!

      .
   (0)

Mathematicians call each such subset "a combination of k out of n" and denote their number by

(
 n 
k
)

        ,
   (1)

a formula of which they are not quite sure how to pronounce it; one sometimes hears "n above k". From (0) and (1) they then derive the theorem

(
n
 k 
)

=

(
n
 n-k 
)

   (2)

*         *         *

For a set of  i+j  elements (i≥0, j≥0), the number of different ways it can be partitioned into two subsets of  i  and  j  elements respectively is

(i+j)!
–––––
i! � j!

   (3)

Let us call each such partitioning for short a "partitioning into i and j" and let us denote their number —in honour of Blaise Pascal— by

P(i,j) |    (4)

which is, of course, a symmetric function of its arguments:

P(i,j) = P(j,i) |    (5)

*         *         *

Notation (1) is bad in all respects I can think of. It is bad from (what computing scientists call) a lexical point of view: it does not fit on a line and —worse!— it usurps a parenthesis pair. Furthermore it has introduced such a novel arrangement of characters on paper that its pronunciation requires a completely new convention. (And these are objections I have learned not to think lightly of.)

It is also bad in that it destroys the symmetry: it represents a symmetric function of two arguments by an asymmetric function of their sum and one of the two arguments, thus forcing one to remember which is which. (This is no joke, for in older literature one can encounter instead of (1): C

k
n

.) Finally it raises the shallow (2) to the status of a "theorem"!

It is furthermore profoundly bad in that it is specifically geared to expressing the number of different partitions into 2 subsets of given sizes, whereas nothing prevents us from generalizing and defining for instance

P(i,j,h) =

(i+j+h)!
––––––––
i! � j! � h!

   (6)

which is obviously as symmetric in all its arguments as it could be. It provides the means for a smooth formulation of

P(i,j,h) = P(i,j) � P(i+j,h) |    (7)

which is a bit less insipid than the "theorem" (2).

*         *         *

After the above one might think that the dead horse does not need any more flogging, but I think I must disagree, because notations can have a more sneaky influence on our thinking habits than we usually care to admit.

Let us prove afresh that (3) gives the value of P(i,j). Consider the (i+j)! permutations of the i+j elements. With each permutation we associate a partitioning into  i  and  j  by separating the first  i  elements from the  j  remaining ones. Since i!�j! distinct permutations thus lead to the same partitioning into  i  and  j, P(i,j)�i!j! = (i+j)!, hence (3).

But this is not the proof of (0) that I was given a long time ago. That one went as follows. Let us choose  k  elements. For the first element we can choose among  n , for the second one among (n-1), and so on, until we choose the kth element among (n-k+1). Since each combination of  k  elements can thus be chosen in k! different ways, we conclude

(
n
 k 
)

=

n�(n-1)�...�(n-k+1)
–––––––––––––––
k�(k-1)�...�1

      ,

which formula was subsequently "cleaned up" by multiplying numerator and denominator by (n-k)!. Confronted with (4) as an alternative for (1), one of my colleagues —a statistician— defended (1) as being "closer to one's intuition"! I guess he was educated with the second proof.

Many mathematicians derive part of their self-esteem by feeling themselves the proud heirs of a long tradition of rational thinking; I am afraid they idealize their cultural ancestors.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 8 March 1981 prof. dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD783 - 0

The administration as social disease.

The following has been triggered by local circumstances. It is, however, written in English because the problem in question is not a specifically Dutch one.

For reasons that are quite understandable - and probably even respectable - our government would like to have a clearer picture of how and where the research potential at the Dutch Universities - which are all state-supported - is spent. In response to that desire, the Dutch Universities have set up mechanisms intended for surveying, evaluating, and possibly controlling the research carried out on their premises. To the merely orderly mind, this seems utterly reasonable and, on the whole, the effort is carried out with the best of intentions. The question to be raised is whether the best of intentions suffice or - more poignantly - whether all those good intentions may not do more harm than good.

I am forced to raise such doubts when I confront what I am observing with what I am convinced of, viz. that we have no reason to expect our conclusions and decisions to be any better than the language in which we talked and thought about them.

EWD783 - 1

In the language in which the whole procedure has to be carried out, the - so-called or would-be - notion of a "project" plays a central role. The underlying ideas are very simple. If you want to achieve something, you should be able to state in advance what you would like to achieve and how much the effort is going to cost you, and at yearly intervals you should be able to describe the progress you have made. By stating both in objective, "evaluatable", terms, you should enable the committee in question to decide whether your "project" is worth tackling and whether your progress is up to par. As I said, the underlying ideas are very simple; the trouble is that they are no good.

Firstly, if a reviewing frequency of once a year is appropriate in some cases, it must be absolutely inappropriate in many other cases, because research efforts extend over periods of time ranging from a rainy afternoon to quite a few years.

Secondly, only a fraction of our research efforts can be adequately couched in the format of "projects". It can be done with an expedition to observe an eclipse in order to test a prediction from the theory of relativity, but it is almost impossible for those efforts that start with someone smelling a rat.

EWD783 - 2

Smells are notoriously hard to describe, and the project framework therefore requires him to describe in advance the general shape of the rat he is after.

Thirdly, the goal of consensus - "the peer group", etc. - is a well-documented mistake. Such a consensus can only be reached at pretty homogeneous levels of concern and abstraction, whereas originality often requires a drastic departure from them in order to give profound attention to what all the others ignore.

Fourthly, the whole reviewing machinery has been built upon the tacit assumption that we have means, sufficiently objective to be operational, for establishing whether performance has been up to par, whereas we all know that we have not. The yardstick Academic administrations love most of all is the publication list, since it is supposed to be so objective. Knowing what the Publish-or-Perish-syndrome has done to the level of our scientific journals, we can only deplore the wide-spread adoption of that yardstick, the more so because we know that, though objective, the measure is pretty irrelevant. The number of papers a man submits is not a useful measure of his achievements, nor is the number of papers accepted. There are plenty of honourable reasons

EWD783 - 3

for not rushing into print. It may also be impossible to submit a paper because the appropriate journal has yet to be founded. When the appropriate journals exist, their editorial boards may refuse a paper because their boards don't want to frighten their readership. (I even know of a paper that was refused - by a German journal! - because it presented a solution that was deemed too simple to be worth publishing.) Alternatively one can look at the length of someone's entry in the Citation Index; the measure is equally objective and equally irrelevant.

The superficial reader of the above will conclude that in my opinion no research scientist should be held accountable for his work, but nothing could be farther from the truth. (In any case each scientist should hold himself accountable.) Exactly because this is serious matter I object to carrying it out in a Newspeak that makes it an Orwellian farce we can only survive by dressing things up in yet another layer of dishonesty.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 15 March 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Wed, 09 Jul 2003 .

EWD786 - 0

Trip report E.W. Dijkstra, England, 23 April 1981.

The occasion for this 24-hour visit to England was a meeting on Thursday evening of all people involved in the BP Venture Research Unit in celebration of the Unit's first anniversary. For Netty van Gasteren and me there were two reasons not to take the afternoon plane from Eindhoven to Gatwick. London's rush hour being what it is, we expected that we would be late for our appointment; furthermore we thought it a little bit much to make that whole trip for just a cocktail party and a dinner. So we included a visit to the Computing Laboratory of the University of Kent, Canterbury, and took the early flight. Netty stayed with us in Neunen the preceding night since we had to rise at 5:45 in order to catch it. (If we had known that, due to de-icing in Maastricht, the plane would be half an hour late, we would have stayed in our beds until 6:15!)

Apart from the delay the NLM flight to Gatwick was OK. (It was Netty's first flight in an F27.) By British Rail we went to Victoria Station - 45 minutes, every quarter of an hour - , from where we took return tickets to Canterbury East, where we arrived at 11:00 (local time: 12:00 by Dutch standards). Dr. P.H. Welch from the Laboratory was at the station to collect us. After a cup of coffee in Dr. E.B. Spratt's office I gave a lecture - essentially on EWD776 - from 12:00 till 13:00. After an excellent lunch in one of the colleges

EWD786 - 1

we left the campus and returned to London.

Having been given twice before - once at SDC in Santa Monica and once in Eindhoven for visiting Hungarian students - the talk went like clockwork; since it was the first day of term, my hosts were very uncertain about the size of the audience, but the (modest) lecture room was well-filled and about one fifth of my audience clearly enjoyed the lecture. The remaining four fifths looked puzzled when the first quantifier appeared on the blackboard. (In this respect the Hungarian students were better prepared!) When I complained during lunch, my hosts explained "Oh, but our students always look that way." We both found the place a bit depressing. At the University of Kent, the Computing Laboratory is part of the Faculty of Natural Sciences and computing is disjoint from mathematics. We sensed the traditional atmosphere of the Computing Centre; accordingly, staff and students seemed to suffer from underdeveloped power of abstraction. The campus was nice but - being built on the top of a hill - very windy.

When we arrived at Victoria Station at 16:06, the evening rush hour seemed to be already in full swing. After one confusion between Eastbound and Westbound - geography was never my strongest point - the Circle Line (yellow!) took us to Liverpool Street Station; from there it was a stone's throw to the

EWD786 - 2

(not so) Great Eastern Hotel.

Leisurely we refreshed ourselves - initially the towels in my room were lacking! - and dressed ourselves for the BP party, which started at 18:30. We were two dozen people, half of them BP officials. After the cocktails we were served some sort of dinner, which ended with a round-table discussion. The last speaker, Professor Sir Hans Kornberg, FRS, distinguished himself by not mentioning money; as member of the Venture Research Advisory Council he discussed the selection criteria they had applied. I found it very instructive to observe the differences in attitude between the various council members. As was to be expected, many used "long range" where I would have used "medium range" and their expectations struck me as very concrete and explicit.

Shortly after dinner everybody left. In my room I found, packed in plastic, my "Continental Breakfast" which I happily ignored the next morning. But the wake-up service - at 5:30 - worked. Four hours later we were back in Eindhoven. As I had spent my wedding day in England, my wife and I had that evening a very nice dinner in Breughel.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 27 April 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Wed, 09 Jul 2003 .

EWD786a - 0

Sets are unibags.

There is a one-to-one correspondence between the so-called "bags" of elements from a domain and the natural functions on that domain. A natural function bf corresponds to a bag b - or: is b's so-called "characteristic function" - means that for any d in the domain

bf(d) is called "the number of times d occurs in bag b" or "the number of instances of d in bag b";

bf(d) ≥ 1 is called "d occurs in bag b" and is denoted by "d in b";

changing the function bf by increasing bf(d) by 1 is described as "adding one d (or: one instance of d) to bag b" - an operation, which can be undone by "removal of one (instance of) d from bag b" - ;

the function bf being zero everywhere on the domain is denoted by "bag b is empty";

etc.

Bags are a useful metaphor when dealing with natural functions on all sorts of domains: bags of positive integers, bags of characters from a given alphabet, bags of differently coloured pebbles, etc. can come in quite handy.

Bags with characteristic functions whose range

EWD786a - 1

is restricted to {0,1}, i.e. bags all elements in which are distinct, are quite well-known to mathematicians, who call them "sets".

* * *

Sets are, in fact, so well-known that when, later, bags were discovered as a useful concept they were originally called "multisets". This was, of course, a misnomer, since, like an adjective, a prefix should restrict. (Hence the title of this little note.)

The purpose of this note, however, is to record a recent discovery, which amazed me greatly and the significance of which is, as yet, unfathomed: of about 10 grown-up mathematicians I asked, only 1½ had ever heard of multisets and only 1 of them had heard of bags (and that had been the other week). My question had been prompted by my observation of the difficulties an otherwise brilliant mathematician had with EWD785. The notion of a bag was profoundly unfamiliar to him! Since I can hardly think of anything more "natural" than a natural function, I am completely baffled. Does the mathematical community have more of such streaks?

Plataanstraat 5 5671 AL NUENEN The Netherlands | 15 April 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Wed, 09 Jul 2003 .

EWD787 - 0

A (new?) proof of a theorem of Euler's on partitions.

Euler's theorem. For any natural number N, the number of bags of (not necessarily distinct) odd natural nubers whose sum is N equals the number of sets of (distinct) positive integers whose sum is N.

Proof. In this proof:

i's | stand for positive integers,
q's | stand for odd natural numbers, and
t's | stand for powers of 2.

Euler's theorem follows from a 1-1 correspondence between bags of q's and sets of i's with the same sum.

In order to construct the bag of q's corresponding to a given set of i's, we observe that for each i the factorization i=t•q is unique, For each i in the set we put, with i=t•q, t instances of q into the bag. The result is a bag of q's with the same sum.

In order to construct the set of i's corresponding to a given bag of q's, we observe that each natural f is uniquely the sum of distinct t's. For a q with f occurrences in the bag we put into the set the i's of the form t•q for those distinct t's whose sum equals f. The result is a set of (distinct) i's

EWD787 - 1

with the same sum.

Grouping the i's in the set by largest odd divisor we see that the two transformations are each other's inverse. (End of Proof).

I found the above proof shortly after I had firmly decided to discard Ferrer diagrams and similar pictorial "aids". I asked myself how I could derive simply a bag of q's in a sum-preserving manner from a given set of i's. Since I was heading for a bag (in which multiple occurrences are allowed) I investigated how I could transform in a sum-preserving manner the individual i's into bags of q's. With the above result.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 27 April 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

P.S. By distributing the above I learned that the proof is already known.

EWD.

Transcription by John C Gordon

Last revised on Sun, 13 Jul 2003.

AvG5/EWD788

What we seem to have learned.

The purpose of this note is to record our main experiences during the first three months we addressed ourselves to the question “how to tame the complexity of artefacts such as proofs and programs”. At present we can only give an unsorted list: it is too early to assess their significance.

We have done most of our experiments with mathematical arguments; initially the presentation of the arguments was our main concern, but quickly we started to care about the arguments proper as well.

We started with the prejudice that brevity is a hallmark of mathematical elegance; our recent experiences have only strengthened it. In the beginning we committed in the name of brevity what we then identified as a sin, viz. brevity by omission. (It is an easy trap to fall into. Once alerted, we spotted many “sinful omissions” in the texts of others and even in our own first drafts.)

It took us some time to discover that giving the heuristics or buffering the shock of invention and giving the “clearest” presentation are not necessarily the same thing: the type of “clarity” we seem to be homing in on does not exclude surprises for the reader. (For the first author the ruthless separation of these two concerns came as something of a shock.)

It might be illuminating to point out that the type of “clarity” we are looking for is unthinkable (or unbelievable) for someone that identifies convenient with conventional. Our whole search for “clarity” is based on the conviction that some patterns of reasoning are objectively “simpler” than others in the same sense as in which doing arithmetic in Arabic numerals is objectively “simpler” than in Roman numerals.

To give a specific example, we know full well that the natural numbers are much, much older than the negative integers. We are inclined to regret that that aspect of history has been faithfully copied in the education of all of us. (If we are very puristic, we should even object to the name “natural numbers” since it suggests that the negative numbers are in some sense “unnatural”.) It obscures the fact that the unrestricted integers have been invented to simplify matters. It seems that in order to become mathematically adult we have to learn to dissociate ourselves from our pasts: we have to rid ourselves of all sorts of common but confusing thinking habits. But we have to identify them first!

We knew — see EWD447 “On the rôle of scientific thought”, August 1974 — that “separation of concerns” is essential. It now seems that such separation can and should be applied to a much greater extent than we anticipated three months ago.

Zero and One.

We knew that the mathematical community still hesitates whether zero is a natural number. The second author discovered this when he observed how the majority of mathematicians he had asked proved

s(n+1) = s(n) + 1 – (p–1) · m(n+1)

where s(n) = | the sum of the digits of the p-ary representation of n, and
m(n) = | the multiplicity of the factor p of n, i.e. the maximum value m such that pm divides n .

The theorem follows from subtracting 1 from n+1, carrying out this simple computation in base p. The second author’s observation was that most mathematicians introduced a case analysis depending on whether n+1 was divisible by p or not, unaware of the fact that the argument about the length of the train of trailing zeros of the p-ary representation of n+1 is also applicable when that train is empty.

We encountered several new instances. After having defined P(n) as the number of unordered partitions of n, one author separate defined P(0) = 1. In another paper he derived the sequence c₁, c₂, c₃,... from the sequence b₁, b₂, b₃,... according to the formula

cj = bj – (j–1) ·m       .

Had he denoted the sequences by b₀, b₁, b₂,... and c₀, c₁, c₂,..., the formula would have been

cj = bj – j ·m       .

Another mathematician — who knew perfectly well that the empty product should equal 1 — had severe problems in accepting that (Ai: 0 ≤ i < n: B(i)) should equal true for n=0. Also the interpretation of the command “direct arrows towards your tabled neighbours” caused problems in the absence of tabled neighbours.

In classical Greece, one was not considered a number. As a result poor Euclid had to give two separate proofs for his algorithm for the greatest common divisor of two numbers, one for the case they had a common divisor and one for the case they had not. By now people should know better, but the other week we saw a (bright!) mathematician confused because he thought the largest odd divisor of 15 was 5. Evidently, one is still a second-class citizen.

It can be argued that our Western languages with their singular and plural forms keep these distinctions alive. The circumstance offers a further advantage of formal over verbal arguments.

Postponing definitions and proofs.

This section is mainly about the arrangement of the material to be presented. The message is that most of our experiences with the presentation of programs seem to carry over to the presentation of mathematical arguments in general.

Programs are now usually presented in the so-called “top-to-bottom” or “top-down” fashion. There are good reasons for this. Programs have to bridge the gap between the problems and the tools; whereas the programming languages that provide their building blocks have been very stable — some would even argue: depressingly so — the general-purpose nature of the tool is faithfully reflected in the diversity of the problems to be solved. Top-down presentation presents first what is specific and unfamiliar, thereby providing the framework in which the later details fit. (This also explains why hardware designers, who over the last decades had the diversity at the side of their building blocks, tend to prefer the so-called “bottom-up” presentation.)

Since Euclid’s Elements were written, mathematicians tend to present mathematical theories in a bottom-up fashion: axioms first! But presenting a solution based on known foundations is more akin to presenting a program, and accordingly, we found top-down presentations more appropriate. (This could be an example of how “convenient” and “conventional” can diverge.) For instance, when demonstrating that two sets have the same cardinality it seems worth a sentence at the beginning, announcing whether a counting argument or a one-to-one correspondence will be developed.

A minor consequence of this principle is that we don’t lump all defintions together at the beginning of the exposition, but postpone each definition until it is needed.

A major consequence is our tendency to use lemmata before we have given their proofs. Though unusual, this seems entirely correct. The statement of a lemma is a logical firewall between its usage and its proof; the use of a lemma is independent of how the lemma can be proved and, during the study of its use, knowledge of its proof is therefore an unnecessary burden.

How naming can hurt.

One of the problems of presenting, annotating, or specifying a sizeable program is avoiding such naming conventions that the number of names needed explodes: not introducing avoidable names becomes vital. As an exercise we therefore tried to present a number of mathematical arguments with great precision and detail but using as few names as possible. We learned two things.

Firstly we discovered a few notational habits that create the need for new names. The “... convention” is one of them, e.g. Courant and Robbins assume

“m = p1 p₂... pr = q₁ q₂... qs,

where the p’s and the q’s are primes.” In the continuation of their text “pr” and “qs” both occur half a dozen times, though the actual values of r and s are totally irrelevant in the argument. The introduction of pictures in geometry — see AvG1/EWD780 — forces the introduction of nomenclature, viz. in order to refer in the text to components of the picture.

Secondly we learned that the introduction of names can complicate the argument — see EWD763/764 and EWD771/772, AvG0b — viz. when the need for case analyses is introduced because the naming has destroyed the symmetry. Both examples are very impressive but a caveat is in order: a 2-coloured grid of points and a 2-coloured complete graph are rather similar objects and the experience might not be transferable outside combinatorics.

On overspecification.

With the introduction of

“m = p₁ p₂... pr = q₁ q₂... qs”   ,

Courant and Robbins have done more harm than just introducing two superfluous subscripts: they have represented a bag of primes by a sequence of primes, though everyone knows that multiplication of integers is “commutative”. (Multiplication is “commutative” means that you can “interchange” the factors without affecting the product: a ·b = b ·a . But “interchange” is only meaningful with respect to a notation that has destroyed the symmetry. The symmetry is the fundamental property; commutativity is a notational artefact.) The clumsiness culminates in Courant and Robbin’s formulation of the conclusion:

“Hence the prime decomposition of m′ must be [read: “is”, AvG/EWD] unique, aside from the order of the factors.”

We had similar experiences in AvG4/EWD785 and in EWD787, which both dealt with so-called “unordered partitions”, i.e. bags of positive integers with given sum. They were nicely formulated in terms of bags in contrast to the proofs of Post and Sylvester respectively; the partitions being “unordered”, Post and Sylvester immediately took the liberty of ordering the parts — say in descending order — and carrying out the argument in terms of that order.

For Post, this had the consequence that he also had to introduce the “reverse” of a partition, i.e. the same partition written in ascending order. For Sylvester it had the more dramatic consequence that he missed the generalization from 2 to k:

“Consider for any natural number N the bags of positive integers whose sum is N. The number of those bags not containing a multiple of k (k ≥ 1) equals the number of those bags containing no integer k or more times.”

Using the term “unordered partitions” has two drawbacks. Firstly, starting from sequences in which the order does matter — < 3, 2 > ≠ < 2, 3 > — the concept is weakened, though adjectives and prefixes should strengthen a concept (instead of calling bags “multisets”, we should call sets “unibags”). Secondly, the term “partition” hides the general concept of a bag: it groups the bags of positive integers quite arbitrarily by their sum.

21 May 1981

drs. A.J.M. van Gasteren
BP Venture Research Fellow
Dept. of Mathematics
University of Technology
5600 MB EINDHOVEN
         The Netherlands
prof. dr. Edsger W. Dijkstra
Burroughs Research Fellow
Plataanstraat 5
5671 AL NUENEN
The Netherlands

EWD790 - 0

Trip report E.W. Dijkstra, München, 19 May 1981.

It was a long day and the two nights were short. I left Eindhoven on Monday evening at 21:00 with the Britannia Express and arrived at 7:20 in Munich. That evening I returned from Munich at 23:10 with the Austria Express. On Wednesday morning at 9:00 I was back in Eindhoven: I had been away for 36 hours. The first night I did not sleep too well, for it was a bit warm in my cabin. The second night I slept better but shorter: I had to change trains in Köln at 6:45.

When I arrived in Munich I was met on the platform by Bauer, Broy, and Partsch. After breakfast in a near-by hotel we walked --it was a beautiful day!-- to the building of the Technische Universität Munich, where we conducted our business until 16:45. F.L. Bauer had invited me for dinner at his home in Grafrath, from Munich's main station 33 minutes by "S-Bahn". With the train of 21:50 I returned to Munich. The hospitality of Bauer and his wife was greatly appreciated; when the four --nice!-- little children had gone to bed, the three of us had a pleasant dinner.

Our business was the selection of the participants for this summer's NATO Summer School in Marktoberdorf. We had to select 95 from 150 applicants. The constraints were more complicated than I had expected. Different funding sources forced us to distinguish between NATO countries, communist countries, and the rest. (And, among the NATO countries, Greece, Portugal, and

EWD790 - 1

Turkey occupied a somewhat exceptional position.) Orthogonal to that subdivision we had to distinguish between academic and industrial applicants. My greatest fear had been that the letters of recommendation, coming from so different cultures as they did, would be incomparable, but that fear turned out to seem unjustified. Some letters were unclear at first sight, but after a few rereadings a reasonably clear picture used to emerge pretty convincingly. The only remaining trouble was that 150 applicants was just a lot to go through; hence it was a day of hard work.

On my way to Munich I was the only occupant of the sleeper; on the way back all berths of the car were occupied. Both times the attendant was Dutch.

When I came home I felt slightly groggy, and I slept for two hours in my own bed.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 20 May 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Mon, 30 Jun 2003.

EWD791 - 0

The psychology of the user.

The following has been written after I had studied the special issue (guest editor: Thomas P. Moran) on "The Psychology of Human-Computer Interaction" of the ACM Computing Surveys 13,1 (March 1981). Out of a sense of duty, I studied this issue with a greater attention than usual, the issue being devoted to a topic I had always ignored happily.

I found "The Psychological Study of Programming" by B.A. Sheil (Xerox Palo Alto Research Center) a revealing and illuminating article. In his introduction he states about programming methodology "[...] the claims that are made are all basically psychological; that is, that programming done in such and such a manner will be easier, faster, less prone to error, or whatever. [...] However great their appeal, though, the methodological recommendations of computer science should be recognized as empirically testable, psychological hypotheses. Unlike mathematics, literary criticism, or folklore, a discipline of computer science has an obligation to validate these claims."

Does it? Fulfilling this obligation seems to me for computing science as hard (or even impossible) as for the rest of mathematics. It is more honest - and, hence, probably wiser - not to make such claims and show one's methodological findings - as in the rest of mathematics! -

EWD791 - 1

on the basis of "Take it or leave it.". (In this connection I am tempted to add that we had better recognize the scientific community's freedom to teach on that basis. I shudder at the thought of the totalitarian environment in which we may only teach what has been "validated" by the psychologists.)

That Sheil himself has not challenged the stated obligation is the more amazing since the rest of his article argues that - even to the standards of psychology - the empirical testing done so far is not above criticism and that the psychological hypotheses submitted so far are much too simplistic to be of any relevance for a subtle activity such as programming. In contrast to the quotation from Sheil my conclusion is that "the recommendations of computer science should be recognizable as empirically testable, psychological hypotheses if psychology is to fulfil its scientific promise". Sheil's article is reasonably well-written.

So is "Human-Computer Interaction in the Control of Dynamic Systems" by W.B. Rouse. On linguistic grounds I have argued elsewhere - in EWD618 - that "the user" is not a person of flesh and blood, but a literary figure like a caricature; he - or should I say: it? - is an artefact of computing. This is fully confirmed by Rouse's article, largely devoted to user models. For a given

EWD791 - 2

model one can try to maximize the model's satisfaction, motivation, or performance. Functional specification acts as a logical firewall between the concern for correctness - i.e. the question whether a system meets the specification - and the concern for pleasantness - i.e. the question whether a system meeting the specification fits well in the intended environment - . It is a pleasure to see how well W.B. Rouse keeps these two concerns separated: he fully confines himself to concerns for pleasantness. By way of illustration I quote the question he raises in his conclusions: "What fraction of the task responsibility should be allocated to the human (at a particular instant in time) in order to keep him sufficiently involved and motivated [sic!] to perform acceptably over weeks, years, or a whole career?". His concern is entirely at the other side of the logical firewall, and I cannot even regard it as "a subfield of computer science". (Rouse's article is so readable because he is quite honest about his pragmatism: "While such explanations may be inadequate in terms of scientific rigor, they can be quite useful as design tools.". He is from the University of Illinois, Urbana.)

The paper "Human Factors Studies of Database Query Languages" by Phyllis Reisner (IBM Research Laboratory, San Jose) is perhaps best characterized

EWD791 - 3

by the following quotation. "Gould and Ascher [also from IBM, EWD] asked subjects, who were given a problem statement [...], first to write a problem formulation in their own words, then to write a plan to solve it, and then to code it [what?, EWD] in IQF. [...] They found, for example, that whether or not the problem was well expressed seemed to affect problem formulation time, but not [the time taken by?, EWD] the other two stages." What an amazing finding. Earlier, Reisner devotes almost a column to "procedurality" though "The notion is not clearly defined" and remains that way. The "experiments" described don't seem very relevant to me, the paper is poorly written and I got nothing out of it.

The paper "Behavioral Aspects of Text Editors" by David W. Embley and George Nagy (both of the University of Nebraska, Lincoln) is long, and contains a lot of information, such as "The standard key size is 0.5 inch (1.27 centimeters) in diameter and the standard horizontal spacing is 0.75 inch (1.81 [sic!] cm)." and "Prolonged use of the light pen was also reported to be fatiguing since the arm cannot rest.". I don't exclude that the paper is interesting for people interested in such things.

The paper "The Psychology of How Novices Learn Computer Programming" by Richard E. Mayer (the

EWD791 - 4

University of California, Santa Barbara) closes the issue. For everyone who wants his prejudices against psychologists - or against BASIC, for that matter - reconfirmed, the paper is obligatory reading. His approach to understanding computer programming - and also to teaching it, if he had his way - is fully operational; BASIC's statement "LET X = 5" is explained as a succession of 6 (!) so-called "transactions", each with three attributes. The paper is 20 pages and almost impossible to plough through.

The introduction "An Applied Psychology of the User" by T.P. Moran (Xerox Palo Alto Research Center) should be reread when all is over. Its opening sentence "This special issue of Computing Surveys on "The Psychology of the Computer User" [notice the difference, EWD] represents [= presents? EWD] the debut of user psychology, as a coherent subfield of computer science, to the computing community." is then no longer convincing. Its last section "Status of the Field" is quite sober: "Too much of the reported work on user psychology suffers from sloppy methodology, such as lack of experimental control and overgeneralized interpretation.". I couldn't agree more.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 12 June 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Wed, 09 Jul 2003 .

EWD793 - 0

The analysis of a two-person game.

As long as possible, two players make a move in turn; the player faced with a situation in which no move is possible has lost the game.

The situation is given by two natural numbers (i.e. integers ≥0). A move being possible means that both numbers are positive; a move then consists in decreasing one of the numbers one or more times by the other, but such that the number decreased remains ≥0.

It as asked to characterize those initial situations in which the player who has the first move can guarantee to win.

* * *

Our first observation is that, since no move affects the greatest common divisor of the two numbers, only their ratio matters. Our second observations is that, since the situation is symmetric in the two numbers, we can confine ourselves when moves are possible to a ratio ≥1. Our third observation is that, to start with, a move consists in decreasing the ratio by an integer; if then 0 < ratio < 1, the roles of smallest and largest number have been interchanged, and we should replace the ratio by its inverse. And this suggests to characterize the ratio by its finite expansion as continued fraction, more precisely by the sequence of positive integers

EWD793 - 1

(0) | k₀, k₁, ... , kn

such that the ratio equals rn, given by

r₀ = k₀ and ri+1 = ki+1 + 1 / ri    .

A move with a non-maximal decrease decreases kn by an amount < kn ; a move with a maximal decrease decreases n by 1 ("drops kn").

The state n=0 ∧ k₀=1 corresponds to a ratio =1, which is a winning situation for the initial player. It is exceptional in the sense that all ratios >1 can be represented with k₀ ≥2 . For such states we define

| trail = n - ( MAX i : 0≤i≤n ∧ ki ≥2 : i )

i.e. the length of the train of ones on which (0) ends. Handing your opponent a situation with trail odd forces him to return a situation with trail even. With trail even you can either hand your opponent a situation with trail odd or terminate the game and win. Hence trail even characterizes the remaining winning situations, i.e. the ratio > (1 + √5) / 2 .

Plataanstraat 5 5671 AL NUENEN The Netherlands | 17 June 1981 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Sun, 13 Jul 2003.

EWD796a

Smoothsort, an alternative for sorting in situ

by | Edsger W. Dijkstra
| Burroughs Corporation

Abstract.

Like Heapsort —which inspired it— smoothsort is an algorithm for sorting in situ. It is of order N∙log N in the worst case, but of order N in the best case, with a smooth transition between the two. (Hence its name.)

Key Words and Phrases: sorting in situ, heapsort, sorting trees, sift, computational complexity.

CR Categories: 5.25, 5.31

Author’s present address:
Edsger W. Dijkstra, Burroughs, Plantaanstraat 5, 5671 AL Nuenen, the Netherlands

Introduction

Heapsort [0] [1] is an efficient algorithm for sorting m(i : 0 ≤ i < N) in situ; some, however, consider it a disadvantage of heapsort that it absolutely fails to exploit the circumstances in which the sequence is initially nearly sorted. While sharing in general with heapsort its N∙log N characteristic, smoothsort does not share this disadvantage: for an initially (nearly) sorted sequence, smoothsort is of order N with a smooth transition between the two. Smoothsort can be viewed as a pure exchange sort that is of order N∙log N in the worst case. For brevity's sake we shall describe sorting the integer sequence m(i : 0 ≤ i < N) in ascending order.

General outline of smoothsort

After a preparation in its first phase, smoothsort builds up the sorted sequence from right to left, i.e. it maintains between q and m

P0:     (A i, j : 0 ≤ i<j ∧ q ≤ j< N : m(i ) ≤ m(j ) ∧ 1 ≤ q ≤ N

which is vacuously true for q = N and enjoys the useful property that P0 ∧ q = 1 implies that the sequence m is in ascending order. (Since smoothsort modifies m only by swapping two of its elements, m obviously remains a permutation of the same bag of values.)

The second relation, built up during smoothsort's first phase and maintained during its second phase, is

P1: | The unsorted prefix m(i: 0 ≤ i < q) is the postorder traversal of a tree in which no son exceeds its father.

Relation P1 ensures that the rightmost element of the unsorted prefix is its maximum element and that, therefore, q can be decreased by 1, without violating P0. In order to maintain P1, however, the decrease q := q − 1 must, in general, be accompanied by a rebuilding of the tree. This clerical obligation has no analogue in heapsort, in which a similar tree is pruned by removing a leaf: in smoothsort the tree is pruned at its root and without precautions it would, in general, fall apart into a forest of subtrees. Smoothsort restores the tree by grafting each subtree of the forest on the root of the subtree to the right of it.

Note that relation P1 has been inspired by the desire to leave the sequence m untouched when initially already in ascending order.

Once the shape of the tree for q = N has been chosen, the grafting procedure sketched above determines the shape of the tree for all smaller values of q. Our desire to construct an algorithm that would be of order N when m is initially (nearly) sorted forced us to derive the shape of the next tree from that of the preceding one. This recurrent computation, which heavily depends on the way in which shapes of trees are represented, is responsible for much of smoothsort's apparent complexity.

The presentation of smoothsort

In our presentation we shall follow the principle of postponing definitions until they are needed and —as a special case— not introducing variables until they are needed. The latter leads to so-called "program projections". A program is projected on a subset of its variables by omitting the declarations of its other variables and all statements not assigning to any of the variables of the subset projected on; the remaining expressions may only depend on the variables of the subset. Each time we shall give the minimal extension of the subset projected on. In the new statements thereby introduced, the variables introduced earlier are constants.

This way of program presentation has the advantage of introducing one complication at a time. It has the disadvantage of hiding the heuristics that led to the algorithm to be presented; the general outline and later remarks have been included to overcome this disadvantage as much as possible. (I think that we shall have to learn to live with the fact that presenting the final design in the most disentangled way and giving the heuristics —perhaps even in the form of a possible design history— are not necessarily compatible goals.) Finally I beg the impatient reader to remember that a program projection —though a legal program— does not make sense in isolation: its sole purpose is to be extended to something meaningful.

When invariants are given, they precede the repetition of which they are the invariant.

The introduction of q

Projected on the variable q, smoothsort is reduced to

|[ q : int; q := 1 {invariant: 1 ≤ q ≤ N }
 ; do q ≠ N → q := q + 1; od {invariant: 1 ≤ q ≤ N }
 ; do q ≠ N → q := q − 1; od
]|

Variable q denotes the length of the unsorted prefix; the above projection shows that smoothsort as presented here is only defined for N ≥ 1.

The introduction of r

Projected on the variables (q, r), smoothsort is reduced to

|[ q, r : int; q := 1; r := 0 {invariant: q − r = constant}
 ; do q ≠ N → q := q + 1; r := r + 1 od {invariant: q − r = constant}
 ; do q ≠ N → q := q − 1; r := r − 1 od
]|

Remark 0. Variable r comes in handy in two ways. Firstly because m(r) is the rightmost element of the unsorted prefix, and secondly because replacing its initialization r := 0 by r := X will cause smoothsort to sort the sequence m(i : X ≤ i < X + N ). Smoothsort accommodates such a shift of origin a little bit more easily than heapsort.

The introduction of p, b and c

Invariant P1 states that the unsorted prefix m(i : X ≤ i < q) is the postorder traversal of a tree, but does not define the tree. In this section we shall begin to define the tree for the unsorted prefix of length q and how the shape of that tree is recorded using the triple (p,b,c).

To this purpose we regard the unsorted prefix m(i : X ≤ i < q) as a so-called standard concatenation of so-called stretches.

A "stretch'' is a subsequence of consecutive elements m(i : h ≤ i < h1) for some h ≤ h1 (which we shall later identify with the postorder traversal of a binary subtree of the tree mentioned in P1. As we shall see later, it is desirable that the number of stretches that concatenated together constitute the unordered prefix is relatively small. Stretches, however, don't come in all possible lengths and when q is not a stretch length we need more stretches to cover m(i : 0 ≤ i < q). The available stretch lengths are the so-called Leonardo numbers

... 41   25   15   9   5   3   1   1   (−1)

given by LP₀ = LP₁ = 1 and LPn+2 = LPn+1 + LPn + 1. (The justification for this choice of available stretch lengths is better postponed.)

The "standard concatenation'' of a sequence of length q1 consists of the longest stretch with the length ≤ q1, followed by the standard concatenation of the remainder (when not empty).

Remark 1. We leave it as an exercise for the reader to convince himself of the fact that the standard concatenation of a sequence of given length decomposes the sequence into the minimum number of stretches. (End of Remark 1.)

For the sake of the recurrent stretch length computations, we introduce for each stretch length b its "companion'' c, i.e. we maintain

(E n: n ≥ 0: b = LPn ∧ c = LPn−1)   ;

here LP₋₁ is to be taken = −1. This is achieved by modifying variables b and c using only "up'' and "down'', defined by

up:   b,c := b + c + 1, b        and           down:   b, c := c, b − c − 1    .

The stretches forming a standard concatenation are given by the triple (p,b,c); more precisely, with a binary representation of p

.....   p₅ p₄ p₃ p₂ p₁ p0   ,

the triple (p, b, c) defines the set of stretches LPn+i for all i such that pi = 1 and n defined by LPn = b  ∧  LPn−1 = c  .

Note 0. As a first result, the length of the standard concatenation given by the triple (p, b, c) can —destructively— be computed by

   length := 0
;  do p > 0→
          if   even(p) → p := p/2; up
          []  odd(p) → length := length + b ; p := (p − 1)/2; up
          fi
od                           (End of Note 0.)

Note 1. The representation is not unique: the operations "p := 2*p ; down" leave the standard concatenation represented by the triple (p, b, c) unchanged.  (End of Note 1.)

The above coding of a standard concatenation is possible because, with the exception of stretch length 1, which may occur twice in a standard concatenation —e.g. of length 2 or 7— each stretch length occurs at most once, whereas for stretch length 1 we have LP₁ and LP₀ at our disposal. We adopt the additional convention of recording a single stretch of length 1 as LP₁.

Note 2. We leave it as an exercise for the reader to prove that, as a consequence of the stretch lengths being Leonardo numbers, in the binary representation of p only the two least significant 1's may be adjacent. This fact will be used in our next project. (End of Note 2.)

We now extend the subset of variables projected on by adding the triple (p, b, c) satisfying the invariant

P2: The length of the standard concatenation represented by the triple (p, b, c) equals q.

|[ q, r, p, b, c : int; q := 1; r := 0; p, b, c := 1, 1, 1  { invariant: P2 }
  ; do q ≠ N
       → if p mod 8 = 3
              → p := (p − 1)/2; up; p := (p − 1)/2; up; p := p +1  {b ≥ 3}
           [] p mod 4 = 1
              → down; p := 2 * p
               ; do b ≠ 1 → down; p := 2 * p od; p := p +1  {b = 1}
             fi; q := q + 1; r := r +1
   od   { invariant: P2 }
 ; do q ≠1
     → q := q − 1; r = r − 1
      ; if b = 1
          → p := p − 1; do even(p) → p := p/2 ; up od  { p mod 4 = 1}
         [] b ≥ 3
          → p := p − 1; down; p := 2*p + 1; down; p := 2*p + 1  { p mod 8 = 3 } 
        fi
   od
]|

Note 3. For the (nonempty!) standard concatenation we have chosen in the above the "normalized" representation with odd(p). (End of Note 3.)

Note 4. The assertions at the end of each alternative have been given in order to stress that —as it should be!— the one repeatable statement is the inverse of the other: assertions in the one reappear as guards in the other [2]. (End of Note 4.)

Note 5. The reader may wish to prove that p's property as described in Note 2 is the invariant of both repetitions. (End of Note 5.)

Note 6. The above projection is still of order N. The argument is as follows. In the first repetition the number of "down's" is bounded by the number of "up's", which is certainly less than 2N. The second repetition is merely the inverse of the first one and the conclusion follows. (End of Note 6.)

The introduction of m

At last the time has come to describe how stretches and the standard concatenation define which order relations between elements of m are maintained by smoothsort. We begin with the stretches, on which predicates "trusty" and "dubious" will be defined. In accordance with the interpretation of a stretch as the postorder traversal of a binary tree we shall refer to the rightmost element of a stretch as the "root" of that stretch.

Denoting a sequence of length LPn by < seqn >, we parse for n ≤ 2

< seqn >   =   < seqn₋₁ >< seqn₋₂ >< root >

where < root > stands for a singleton sequence. Stretch < seqn > is dubious means that both < seqn₋₁ > and < seqn₋₂ > are trusty. Stretch < seqn > is trusty means that, in addition, the roots of < seqn₋₁ > and < seqn₋₂ > are at most the root of < seqn >; a stretch of length 1 is by definition both dubious and trusty. As a consequence, the root of a trusty stretch is the maximum element of that stretch.

When stretches thus parsed are viewed as postorder traversals of binary trees, trustiness means that no son exceeds its father. A dubious stretch is made into a trusty one by applying the operation "sift" —a direct inheritance from heapsort— to its root, where sift is defined as follows: sift applied to an element without larger sons is a skip, sift applied to an element m(r1) that is exceeded by its largest son m(r2) consists of a swap of these two values, followed by an application of sift to m(r2).

Remark 2. We can now partly justify our choice of the Leonardo numbers as available stretch lengths, i.e. justify why we have not chosen (with the same recurrence relation)

...   33   20   12   7   4   2   1   (0)   .

The occurrence of length 2 would have required a sift able to deal with fathers having one or two sons, like the sift required in heapsort ; thanks to the Leonardo numbers a father has always two sons and, consequently, smoothsort's sift is simpler. End of Remark 2.)

During the second repetition smoothsort maintains

P3: | The stretches of the standard concatenation of the unsorted prefix m(i : 0 ≤ i < q) are all trusty.

During the first one it maintains the weaker

P3': | of the standard concatenation the unsorted prefix m(i : 0 ≤ i < q) the rightmost stretch is dubious; its other stretches are all trusty.

Remark 3. The weaker P3' has been introduced for reasons of efficiency which cannot be explained now; see, however, Remark 4. (End of Remark 3.)

So much for the order relations captured by the stretches. In addition smoothsort maintains during the second repetition

P4: | The roots of the stretches of the standard concatenation of the unordered prefix m(i : 0 ≤ i < q) are ascending from left to right.

a relation which is useful since P3 ∧ P4 implies that m(x), the rightmost element of the prefix, is a maximum element of the prefix, and this is the circumstance under which q := q −1 maintains P0. During the first repetition smoothsort maintains the weaker

P4': | the roots of the trusty stretches of the standard concatenation of the unordered prefix m(i : 0 ≤ i < q) that are also stretches of the standard concatenation of length N are ascending from left to right.

We now have to investigate

1) | what to add to the first repetition for the maintenance of P3' ∧ P4'
2) | what to insert between two repetitions in order to transform P3' ∧ P4' into P3 ∧ P4
3) | what to add to the second repetition for the maintenance of P3 ∧ P4

Investigation 1. In the case p mod 8 = 3, the standard concatenation ends on a dubious stretch of length b which must be made trusty before it can be combined with the preceding stretch and the following element into a new dubious rightmost stretch. This can be achieved by applying sift to m(r) . Since no new trusty stretch is added to the standard concatenation, P4' is maintained without further measures.

In the case p mod 4 = 1, the standard concatenation ends on a dubious stretch of length b, which in this step becomes the last but one stretch of the standard concatenation and, hence, must be made trusty. In the case q + c < N, it suffices to apply sift to m(r) as before, since this stretch will later disappear from the standard concatenation. In the case q + c ≥ N, however, just applying sift to m(r ) might violate P4' since this stretch of length b also occurs in the standard concatenation of length N. Making a dubious stretch trusty and including its root in the sequence of ascending roots is achieved by applying "trinkle" to m(r). (As we shall see later, trinkle is like sift, be it for a partly ternary tree.) (End of Investigation 1.)

Investigation 2. The reader may prove that it suffices to apply trinkle to m(r) . (End of Investigation 2.)

Investigation 3. In the case b = 1, the standard concatenation loses its last stretch, and P3 ∧ P4 is maintained without further measures.

In the case b ≥ 3, the rightmost stretch of length b is replaced by two trusty ones; hence P3 is maintained. To restore P4 it would suffice to apply trinkle first to the root of the first new stretch and then to the root of the second new stretch, but this would fail to exploit the fact that the new stretches are already trusty to start with. This is exploited by applying "semitrinkle" in order to those roots. (End of Investigation 3.)

Remark 4. From a logical point of view it would be perfectly permissible to replace a call on trinkle by a call on sift, which would make the dubious stretch trusty, followed by a call on semitrinkle, which would include its root in the sequence of ascending roots. After this substitution, each iteration of the first repetition starts with a sift and the whole first repetition is followed by a sift. Since initially the last (and only) stretch is trusty, we can transform the program by removing all calls on sift and inserting a single call on sift at the end of the repeatable statement of the first repetition. This is essentially the program transformation that would be required if we wished to replace P3' by P3. (The collection of trusty stretches being extended, P4' would require reformulation.)

The version resulting from the above transformation is, however, rejected because a succession of sift and semitrinkle requires in general more comparisons and swaps than trinkle, as will become apparent later. This can be remedied by replacing the single call on sift by guarded calls on either sift or the combination in the form of trinkle (and removal of the calls on semitrinkle from the first repetition, which have now been catered for). P3 would still be valid, P4' would have to be changed. This version, however, is rejected since it would lead to a duplication of the evaluation of the guards p mod 8 = 3, etc ... (End of Remark 4.)

In order to enable the reader to check the code in which calls on sift, trinkle, and semitrinkle have been inserted, we give their calling conventions. (These conventions are not to be regarded as a recommendation: they have been chosen because in this publication I did not want to make any assumptions about a parameter mechanism.)

Routine sift is applied to the root m(r1) of a stretch of length b1, of which c1 is the companion. Routine trinkle is applied to the root m(r1) of the last stretch of the standard concatenation represented by the triple (p, b, c): this representation need not be normalized. Routine semitrinkle is applied to the root m(r) of a stretch of length c which is preceded by the nonempty standard concatenation represented by the triple (p, b, c): again the representation is not necessarily normalized.

Note that "p := (p − 1)/2; p := (p − 1)/2; p := p + 1" has been simplified to "p := (p + 1)/4" and that "r := r − b + c; down; r := r + c decreases r by 1.

smoothsort:
|[ q, r, p, b, c, r1,b1,c1: int
  ; q := 1; r := 0; p, b, c := 1, 1, 1   { invariant P3' ∧ P4' }
  ; do q ≠ N
       →  r1 := r
           ; if p mod 8 = 3
               →  b1,c1 := b, c ; sift; p := (p + 1)/4; up; up
             []  p mod 4 = 1
               → if q + c < N → b1,c1 := b, c; sift
                   [] q + c ≥ N → trinkle
                   fi; down; p := 2 * p
                 ; do b ≠1 → down; p := 2 * p od; p := p + 1
             fi; q := q + 1; r := r +1
    od { P3' ∧ P4' }; r1 := r; trinkle { invariant: P3 ∧ P4 }
  ; do q → 1
       → q := q − 1
         ; if b =1
             → r := r − 1; p := p − 1; do even(p) → p := p/2; up od
           [] b ≥ 3
             → p := p − 1; r :=r − b + c
              ; if p =0 → skip [] p > 0 → semitrinkle fi
              ; down ; p := 2*p + 1; r := r + c ; semitrinkle
              ; down ; p := 2*p + 1
           fi
  od
]|

up1:       b1,c1 := b1+ c1+1, b1
down1:   b1,c1 := c1, b1 − c1 − 1

sift:
do b1 ≥ 3→
     |[ r2: int; r2 := r1 − b1 + c1
      ; if m(r2) ≥ m(r1 − 1) → skip
        [] m(r2) ≤ m(r1 − 1) → r2 := r1 − 1; down1
        fi
      ; if m(r1) ≥ m(r2) → b1 := 1
        [] m(r1) < m(r2) → m : swap(r1,r2); r1 := r2; down1
        fi
      ]|
od

semitrinkle:
   r1 := r − c
 ; if m(r1) ≤ m(r) → skip
   [] m(r1) > m(r) → m : swap(r, r1); trinkle
   fi

Trinkle is very similar to sift when we regard each stretch root as the stepson of the root of the stretch to its right. Applied to a root without larger sons, trinkle is a skip; otherwise the root is swapped with its largest son, etc. The trouble with the code is that all sorts of sons may be missing. In the following, trinkle is eventually reduced to a sift, viz. when the stepson relation is no longer of interest.

trinkle:
|[ p1: int; p1,b1,c1 := p, b, c
  ; do p1 > 0→
        |[  r3: int; do even(p1) → p1 := p1/2; up1 od; r3 := r1 − b1
          ; if p1=1 cor m(r3) ≤ m(r1) → p1 := 0
            [] p1 > 1 cand m(r3) > m(r1)
               → p1:= p1 − 1
                ; if b1=1 → m:swap(r1,r3); r1 := r3
                  [] b1 ≥ 3 →
                     |[ r2: int; r2 := r1 − b1+ c1
                      ; if m(r2) ≥ m(r1 − 1) → skip
                        [] m(r2) ≤ m(r1 − 1)
                           → r2 := r1 − 1; down1; p1 := 2 * p1;
                        fi
                      ; if m(r3) ≥ m(r2)
                            → m:swap(r1,r3); r1 := r3
                        [] m(r3) ≤ m(r2)
                            → m:swap(r1,r2); r1 := r2; down1; p1 := 0
                        fi
                     ]|
                  fi
        ]|
    od
]| ; sift

And this concludes the code, in which I have abstained from implementation dependent optimizations.

In retrospect

While heapsort prunes the tree leaf by leaf, smoothsort prunes the tree at the root, and immediately one of heapsort’s charms is lost: while the tree in heapsort remains beautifully balanced, the tree in smoothsort can get very skew indeed. So why bother about smoothsort at all? Well, I wanted to design a sorting algorithm of order N in the best case, of order N∙log N in the worst case, and with a smooth transition between the two (hence its name).

This is also the answer to the question why I introduced P4. By dropping P4 one can dispense with trinkle and the code becomes much simpler. The price to be paid is a search for the maximum stretch root in order to establish that m(r) is a maximum element of the unsorted prefix. Though such a simpler sorting algorithm is quite defensible, I rejected the option because it is never of order N.

One can also raise the question why I have not chosen as available stretch lengths: ... 63  31  15  7  3  1, which seems attractive since each stretch can then be viewed as the postorder traversal of a balanced binary tree. In addition, the recurrence relation would be simpler. But I know why I chose the Leonardo numbers: with balanced binary trees the average number of stretches is 1.2559  {= ¼(5+√5)(²log(1+√5)−1)} times the average number of stretches with the Leonardo numbers. (I do not present this ratio as a compelling argument).

It is possible that others have thought of this algorithm, but have rejected it for valid reasons, as yet unknown to me. I could not find it in the literature and it is not mentioned in [3], a recent article that compares five well-known sorting algorithms when fed with initially nearly sorted sequences. (That article compares Straight Insertion Sort, Shellsort, Straight Merge Sort, Quicksort, and Heapsort.) If it has not been discovered earlier, I would like to know the reason, because all its ingredients are well-known since the discovery of the heapsort in 1964.

Besides the possible interest in smoothsort I had another reason for developing it to the degree I did and for writing the above. (It took me three weeks, but I consider them well-spent.) The reason was that I knew beforehand that in trying to present smoothsort in a way as disentangled as possible I would encounter considerable difficulties. I hope they have been surmounted sufficiently well.

Acknowledgements

I am greatly indebted to C.S.Scholten and to all the members of the Tuesday Afternoon Club, with whom I had the privilege of discussing the algorithm, its coding, and its presentation. They have helped me clarifying my own thoughts and have suggested several significant simplifications. I am furthermore indebted to D.E.Knuth and W.M.Turski for their comments on the previous version of the text, and to the participants of the Marktoberdorf Summer School, 1981, on whom I could try out my presentation.

References

[0] | Williams. J.W.J., Algorithm 232 HEAPSORT C.A.C.M, 7, 6 (June 1964), pp. 347−348
[1] | Floyd, Robert W., Algorithm 242 TREESORT 3 C.A.C.M., 7, 12 (Dec. 1964), p. 701
[2] | Bauer, F.L. and Broy, M. (Ed.), Program Construction, Lecture Notes in Computer Science 69, Berlin, Heidelberg, New York, Springer Verlag, 1979, pp. 54 − 57
[3] | Cook, Curtis R. and Kim, Do Jin, Best Sorting Algorithms for Nearly Sorted Lists, C.A.C.M., 23, 11 (Nov. 1980) pp. 620 − 624

Plataanstraat 5 | 16 August 1981
5671 AL NUENEN | prof.dr Edsger W. Dijkstra
The Netherlands | Burroughs Research Fellow

transcribed by Frederik Hertzum
revised Sat, 28 Jul 2007

  EWD 797

Fibonacci numbers and Leonardo numbers.

     (The following formal derivations and computations
are absolutely elementary and without scientific in-
terest. But I am interested in some numbers and
need the formulae, and learned that working on a
scratch pad I make too many mistakes. Hence.)

     The Fibonacci numbers are given by

F₀ = 1     F₁ = 1     Fn+2 = Fn+1 + Fn (or : Fn+2 – Fn+1 – Fn = 0).

The analytical solution of a homogeneous recurrence
relation like this is found by solving first the cor-
responding characteristic equation which one gets
by "trying" an F of the form Fn = xn :

(0) x² – x – 1 = 0

This equation has two different roots, which I
shall denote by  α and  β

(1) α = ½ + ½√5 = 1.618034        ¹⁰log α = 0.208988

β = ½ – ½√5 = – .618034

Obvious properties are

(2) α + β = 1          α∙β = –1

  α² = α + 1  ,  α³ = 2∙α + 1  ,  α⁴ = 3∙α + 2  ,  etc.

Because α ≠ β , αn and βn give rise to linearly
independent sequences and each solution of the
homogeneous recurrence relation is of the form

(3) Fn = X∙αn + Y∙βn

where the constants X and Y are determined by
solving the set of linear equations

(4)
X + Y = F₀

α∙X + β∙Y = F₁

Multiplying the second equation by α we get —see (2)—

(α + 1)∙X – Y = α∙F1   , and hence
(α + 2)∙X = F₀ + α∙F₁ , hence

       F₀ + (½ + ½ √5)∙F₁       2∙F₀ + (1 + √5)∙F₁        (5 – √5)
X   = ━━━━━━━━━━━━  =  ━━━━━━━━━━━━ ∙ ━━━━━
    2 ½ + ½ √5     (5 + √5)          (5 – √5)

           ₁
     =  ━━ (10∙F₀ – 2∙F₀∙√5 + 4∙F₁∙√5) =
          ²⁰

           5∙F₀ + (2∙F₁ – F₀)∙√5
      =   ━━━━━━━━━━━━                                          (5)
                      10

and, for reasons of symmetry

         (5∙F₀ – (2∙F₁ – F₀)∙√5)
Y    =  ━━━━━━━━━━━━                                            (5')
                      10

For the Fibonacci numbers we substitute  F₀ = F₁ = 1
and find, according to (3)

(6) Fn = (½ + ⅟10√5)∙αn + (½ – ⅟10√5)∙βn

= .723607∙αn + .276393∙βn

* *
*

We now switch to the Leonardo numbers given
by  L₀ = 1     L₁ = 1       Ln+2 = Ln+1 + Ln + 1 . This
recurrence relation is not homogeneous but
—because x = 1 is not a root of (0)— this is only
an apparent complication: (Ln+2 + 1) = (Ln+1+1) + (Ln + 1),
and we immediately derive

(7)    Ln = 2∙Fn – 1  .

The nth Leonardo tree has Ln vertices. The
(n+2)th Leonardo tree is a binary tree, of which
the (n+1)th and the nth Leonardo tree are
the two subtrees. A number that is perhaps of some
interest is the distance from the root summed
over the vertices of the nth Leonardo tree.
Denoting this quantity by Kn we derive from
the definition

(8)    Kn+2 = (Kn+1 + Ln+1) + (Kn + Ln)
or
   (Kn+2–2) = (Kn+1–2) + (Kn–2) + (Ln+1+1) + (Ln+1)

or with

(9)   Kn = 2∙(Hn + 1)  or  Hn = (Kn–2)/2
(10) Hn+2 = Hn+1 + Hn + Fn+2

Solving (10) for Fn+2 and taking the recurrence
relation for the F's into account one finds that the
H's satisfy a homogeneous linear recurrence relation
with (x² – x – 1)² = 0 as characteristic equation. (This
is a special case of a more general theorem of
which I was not aware.) Hence the general form
of Hn is

(11) Hn = (a + n∙A)∙αn + (b + n∙B)∙βn

where the constants a, A, b, and B are determined
by solving  —see (2)—

(12)

a +

b   

= H₀

α∙a +

α∙A +

β∙b +

β∙B = H₁

(α + 1)∙a +

(2∙α + 2)∙A +

(β + 1)∙b +

(2∙β + 2)∙B = H₂

(2∙α + 1)∙a +

(6∙α + 3)∙A +

(2∙β + 1)∙b +

(6∙β + 3)∙B = H₃

We eliminate  a  and  b  with

(13) y₀ = H₂ – H₁ – H₀, y₁ = H₃ – H₂ – H₁

(α + 2)∙A   +

(β + 2)∙B  =  y₀

(3∙α + 1)∙A   +

(3∙β + 1)∙B  =  y₁

        ,

which leads to

5∙A  +

5∙B  =  z₀

α∙(5∙A)  +

β∙(5∙B)  =  z₁

                with

(14) z₀ = 3∙y₀ – y₁ , z₁ = 2∙y₁ – y₀

This set of equations is of the same form as (4).
Hence we have

                  5∙z₀ + (2∙z₁ – z₀)∙√5
(15)  A =     ━━━━━━━━━━━
                             50

                  5∙z₀ – (2∙z₁ – z₀)∙√5
(15') B =      ━━━━━━━━━━━
                             50

We can eliminate A and B from (12) with

y₃ = –2∙H₃ + 3∙H₂ + 6∙H₁ – H0

5∙a    +

5∙b

 = 5∙H₀

α∙(5∙a) +

β∙(5∙b)

 = y₃

which is again of the form (4). Eliminating  y₃, we get

                25∙H₀ + (–4∙H₃ + 6∙H₂ + 12∙H₁ – 7∙H₀)∙√5
(16) a =    ━━━━━━━━━━━━━━━━━━━━━━━
                                   50

                25∙H₀ – (–4∙H₃ + 6∙H₂ + 12∙H₁ – 7∙H₀)∙√5
(16') b =    ━━━━━━━━━━━━━━━━━━━━━━━

             50

Let us apply these formulae with the numerical
values of K₀, K₁, K₂, K₃ and then check them against
the numerical value of K₄ . (It is a long time ago
since I made my last check.)

n:

Ln:

Kn:

Hn

From (13) : y₀ = 2      y₁ = 3

0

1

0

–1

From (14) : z₀ = 3      z₁ = 4

1

1

0

–1

From (15) :

2

3

2

0

A =

15 + 5∙√5

━━━━━━ 

⁵⁰

=

3 + √5

━━━━

¹⁰

3

5

6

2

4

9

16

7

B =

3 – √5

━━━━

¹⁰

From (16)

a =

–25 + (–8 – 12 + 7)∙√5

━━━━━━━━━━━━━━

⁵⁰

=

–25 –13∙√5

━━━━━━━━

⁵⁰

b =

–25 + 13∙√5

━━━━━━━━

⁵⁰

.

In order to check these values for  n = 4  we compute

(a + 4∙A)∙α⁴ = ⅟50∙(–25 – 13∙√5 + 60 + 20∙√5)∙(3∙α + 2)
= ⅟100∙(35 + 7∙√5) (7 + 3∙√5) = ⅟100∙(245 + 105 + 154∙√5) =
3½ + 1.54∙√5 . This is OK and that is very encouraging.

We are now in a position to compute the asymp-
totic behaviour of the average distance from the root

Kn

━━

Ln

=

2∙Hn + 2

━━━━━

2∙Fn – 1

→

Hn

━━

Fn

→

⅟10∙(3 + √5)

━━━━━━━━

⅟10∙(5 + √5)

=    

5 + √5

━━━━

10

∙

With  N  the number of points, the average distance
grows as ⅟10∙(5 + √5)∙αlog N = .723607∙αlog N  , a growth
rate I would like to compare to the one of the completely
balanced binary tree. The number of nodes in the
nth binary tree equals  2n+1 – 1 . The sum over
its nodes of their distances from the root is
(S i : 0 ≤ i ≤ n : i∙2i) = (n–1)∙2n+1 + 2 . With N
the number of points, the dominant term of the
growth rate of the average distance from the
root is therefore  ²log N .  For the Leonardo
trees it is .723607∙αlog N = 1.042296∙²log N .
The ratio is —as was to be expected— larger than
1, but only very little so. (I am not convinced
of the relevance of the notion "average distance
from the root" ; it has the advantage that the
above estimations can be derived by elementary
means.)

* *
*

We know that, with a given number, taking
away the largest possible Leonardo number
and repeating this process on the remainder,
we decompose the given number,  x say, in the
minimum number f(x) of Leonardo numbers.
What is the average value of f(x) when  x
ranges over the first  N  natural numbers ?

Defining Di = (Sx : 0 ≤ x ≤ Li+1 : f(x))  , we have
D₀ = 0  ,  D₁ = 3  ,  Dn+2 = Dn+1 + Dn + Ln+1 + 2  ,
hence D₂ = 6  ,  D₃ = 14  ,  D₄ = 27  , etc.

This is the moment I am going to reap the fruit
of (13), (14), and (15). With Hn = Dn + 1  we have
Hn+2 = Hn+1 + Hn + 2∙Fn+1  , and (11) is applicable.
We have  H₀ = 1 , H₁ = 4 , H₂ = 7 , and H₃ = 15. From
(13)  y₀ = 2 , y₁ = 1 ; from (14)  z₀ = 2 , z₁ = 6 , and
from (15)  A = ⅟50∙(10 + 10∙√5) = ⅟5∙(1 + √5) . Hence the
dominant term of Hn  (and Dn)  is ⅟5∙(1 + √5)∙n∙αn .
The leading term of  Ln+1 (=2∙Fn+1 – 1)  is  ⅟5∙(5 + √5)∙αn+1 =
⅟₁₀∙(1 + √5) (5 + √5)∙αn .

The growth rate of the average value of  f(x)  is
that of Hn/Ln+1 , i.e. 2∙n/(5 + √5) = ⅟10∙(5 – √5)∙n =
.276393∙αlog N .

Analogously to the perfectly balanced binary trees
we can replace the Leonardo numbers by Bn = 2n+1 – 1.
Let  f'(x)  be the minimum number of B's with sum  x
and let  Cn = (S : 0 ≤ x ≤ Bn : f'(x)). We find
Cn = (n + 1)∙2n  . In this case the growth rate of the
average value of f'(x) is —not surprisingly—
Cn/Bn = ½ (n + 1) = ½∙²log N = ⁴log N . Comparing
this with the case of the Leonardo numbers

.276393  αlog N =  .796243 ∙ ⁴log N

and this time the ratio is markedly smaller than 1.

Plataanstraat 5

5671 AL NUENEN

The Netherlands

12th July 1981

prof.dr. Edsger W.Dijkstra

Burroughs Research Fellow

transcribed by Sam Samshuijzen
revised Tue, 7 Jun 2005

EWD798 - 0

Trip report E.W. Dijkstra, Newcastle, 19-25 July 1981.

Having been invited as "guest speaker" at the "Advanced Course on Functional Programming and its Applications" (University of Newcastle upon Tyne, 20-31 July, 1981), I had the opportunity to attend its first half. (People actually seemed quite pleased that I had shown up in person: F.L. Bauer had sent M. Broy instead and D. Scott, who just decommitted himself, was replaced at the last minute by D. Park from Warwick.) I was glad to be able to attend at least the first half, which in a way was quite instructive and illuminating (though on the whole not very "advanced").

My trip to Newcastle was the first occasion at which the KLM coach service from Amsterdam Central Station to Schiphol Airport let me down. The coaches had been given a second stop at the south side of the station, but not all the drivers had been told this and the coach I had intended to take failed to pick me up. As I had planned my trip with the usual pessimism I arrived at the airport just in time; and there I heard that the flight of British Caledonian to Newcastle was 85 minutes late ... Their plane back on Saturday morning was delayed by 10 minutes.

There were about 65 participants. We slept at Hender-

EWD798 - 1

son Hall, where breakfast was served at 8:00; at 8:30 the coaches left for the Computing Laboratory, where the lectures started at 9:00. The general pattern was three one-hour lectures in the morning and three one-hour lectures in the afternoon. Around 18:00 we would be back at Henderson Hall. Before and after dinner its common room was at our disposal; the bar was open until 10:30.

Four slots were filled by G.J. Sussman (Artificial Intelligence Laboratory, MIT) and a similar number by D.S. Wise (Department of Computer Science, Indiana University). Both belonged very much to the LISP subculture, neither of the two proved a single theorem, both showed too much and made such heavy use of anthropomorphic terminology that they were painful to listen to. Sussman's transparencies were printed, but overloaded; Wise's transparencies were handwritten, but very messy. Not used to Sussman's lecturing style - is it called "teaching by example"? - I found him very tiring to listen to; he spoke very fast but told very little, since he used most of his words to go in detail through a number of almost identical examples. Wise struck me as rather old-fashioned: he seemed to talk about the implementation of LISP in very much the same way as people did in the early sixties. LISP's syntax is so atrocious that I never understood its popularity. LISP's possibility to introduce higher-order functions was mentioned several times in its defence, but now I come

EWD798 - 2

to think of it, that could be done in ALGOL60 as well. My current guess is that LISP's popularity in the USA is related to FORTRAN's shortcomings.

J. Darlington (Department of Computing & Control, Imperial College) devoted three hours to program transformation as a program development methodology. His examples were well-chosen and carefully presented, but I am afraid he oversold his topic. At the end he talked about a grandiose transformation system yet to be built.

D.A. Turner (Department of Computer Science, University of Kent at Canterbury) devoted four hours on recursion equations and how to use them as a programming language. He had more new things to tell than all the preceding speakers; regrettably, he also oversold his topic more than them.

J.E. Stoy (University of Oxford) spoke for four hours on denotational semantics. His lectures were very well prepared, and the material was coherent. He was by far the best speaker. It was only a pity that, in his first lecture, he overestimated the speed with which his audience could absorb what he said. He doesn't only speak well, he also speaks fast. And he did not sell his topic.

G. Lindstrom (University of Utah) spoke for one hour as a guest speaker on "A Programmer's View

EWD798 - 3

of the Applicative Multi-Processor System AMPS." He did so with great enthusiasm. His visuals were very elaborate and I got the strong impression that he had given this "presentation" quite a few times. He was obviously an advocate of "graphical" presentation of how AMPS was supposed to work. His major example, however, was invalid in more than one respect - apparently no one had ever pointed this out to him before! - and this confirmed all my prejudices against pictures.

David Park (Warwick University) spoke as a last minute replacement for Dana Scott on "Fairness". The talk was well-prepared and carefully delivered, but I don't care very much for the topic.

As arranged with Brian Randell - last January in Han-sue-Lesse - I spoke about correctness proofs and showed an example that challenges the often repeated slogan that applicative programs are easier to prove to be correct than imperative ones. I felt at ease and gave my talk with pleasure.

Manfred Broy (Technical University, Munich) replaced F.L. Bauer; he presented a joined paper on different forms of nondeterminism and presented it well. Earlier in the week he had caught me when my foot slipped from the stairs and I fell.

* * *

EWD798 - 4

Harry Whitfield and his wife had invited me for dinner on Friday. When I returned at Henderson Hall shortly after midnight, I saw no one at the porter's lodge. Around one o'clock, when I was about to fall asleep, panic suddenly seized me when I realized that the next morning at 6:40 I would have to call a cab for the airport and that I had no coins to operate the telephone. I jumped out of bed and started wandering through Henderson Hall until I found someone still awake. He and his neighbour - Broy again - saved me. On the plane British Caledonian served a "continental breakfast" which was an offence of the Continent.

On the whole I could not avoid some feelings of deep disappointment. I still believe that the topic deserves a much more adequate treatment; quite a lot we were exposed to was definitely not up to par.

Marktoberdorf 29 July 1981 | prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcription by John C Gordon

Last revised on Sun, 13 Jul 2003.

EWD799

Trip report E.W.Dijkstra, Marktoberdorf, 26/7 - 10/8/81.

The occasion was the International Summer School in Marktoberdorf (near Munich), this time on the theme "Theoretical Foundations of Programming Methodology." For a variety of reasons this one was for me different from the preceding ones. Firstly I was now one of its three directors, secondly my wife Ria joined me on the trip (which was her holiday), and thirdly we had the car with us. Marktoberdorf is a little, mostly new, town, which never struck me as very exciting; thanks to the car and her freedom, Ria discovered for us that the surroundings are absolutely beautiful.

We drove down at our leisure, leaving Nuenen at Sunday noon and arriving at Marktoberdorf 48 hours later. While I was in Newcastle the week before, Ria had collected at the Dutch tourist organization two excellent maps with all the information --and nothing more: that was what made them so excellent-- for the traveller that would like to avoid the German Autobahn as much as possible. (Remarkably enough, these maps were free!) It is a way of travel I can recommend --and that is saying a good deal!--: despite the height of the season we were never caught in a traffic jam and finding an inn was never a problem. On our way down we had beautiful weather and we interrupted our journey by walks through a number of very medieval towns. On the way back we took a different route, but then it was raining cats and dogs and the journey home took us only 32 hours.

The Summer School started in real earnest on Wednesday 29 July at 08.45 and lasted until Saturday 8 August at 17:00, with Sunday 2 August a day off, and the afternoon of Wednesday 5 August devoted to the excursion. The pattern of the full day was two lectures, break, two lectures, lunch, two lectures, break and then a discussion from 16:00 until 17:00. Dinner --this time not at Hotel Sepp, but in the boarding house-- started at 18:00. It was a heavy schedule and I admired the participants, the majority of whom attended all the lectures (at least physically, as I learned when I asked how a lecture at which I had been absent had been).

The program was overloaded as usual: Tony Hoare and (mostly) Joe Stoy replacing Dana Scott, who did not show up, we had 11 lecturers presenting the material of 12 authors. Unavoidably, the quality of the lectures is far from homogeneous and this makes the audience wonder why they had to be exposed to so many lectures of this speaker while they would have preferred to hear more from that one. Despite my directorship I wondered too, and next time I hope to figure out how to do something about it. I know that all professors have been created equal, but some are most definitely more equal than others. The British speakers were collectively by far the best, the French were by far the worst, condemned as they were --and I am afraid, rightly so-- of the crime of "contempt of audience".

Joe Stoy gave an excellent overview of Scottery and I can think of no better incentive to study Scott's material in real earnest. (In doing so, the student should bear in mind that the definition of the semantics of baroque programming languages is probably its worst possible application area.) Tony Hoare gave an equally clear overview of his theory of Communicating Sequential Processes, his careful phrasing made him a pleasure to listen to. Both used "visuals" they had used many times before. Joe Morris showed us his technique for dealing formally with "aliasing". In contrast to the previous two, he wrote his transparencies while lecturing. He suffered noticeably from the absence of a decent blackboard on which he could display the argument in its entirety; his ability to develop it in spite of the primitive tools available made his lectures the more impressive. Rod Burstall spoke from freshly prepared visuals and had himself as a speaker under very good control; he spoke at half his usual speed. His theme was "Specification Languages and Categorical Programming". He presented his extensively prepared lectures with great enthusiasm but totally failed to convince me that his approach made sense. Compared to what he did with it the weight of his mathematical machinery seemed to me to be out of all proportion. My guess is that one can ignore the topic with impunity for at least the next five years. These were the lecturers of whom I attended all lectures.

I heard Zohar Manna on Program Synthesis and Temporal Logic. He presented his material with great gusto, but I was all the time reminded of "Much ado about nothing". In the Program Synthesis --work he has done together with Richard Waldinger-- he made at great length a meaningless distinction between "assertions" and "goals", in the Temporal Logic he was the worst misuser of anthropomorphic terminology. ("When I want to express that I am at L.": here "L" is a statement label and the second "I" from the above quotation stands for something like "control", whereas the first "I" stands for Zohar Manna. The ambiguity illustrated in the above quotation made many of his sentences totally unintelligible.) I attended four of Sharon Sickel's six lectures. The first five were devoted to the use of Horn Clauses as a programming method, her last lecture --the last lecture of the summer school-- was a well-intended sermon. She had paid great attention to the presentation of her technical material, which she illustrated with an example she had learned at the very first lecture of the summer school! She presented "logic programming" as half-way between problem statement and a fully algorithmic solution. Her point was well-made, but five lectures was perhaps more than was needed for that purpose. She, too, was very operational (what, in view of her topic, was rather surprising). Her sermon contained all the buzz-words, motherhood statements and general purpose pictures; it did not evoke the discussion she had hoped it would evoke, but perhaps everybody was tired.

Maurice Nivat and Bruno Courcelle were very French. Of both I attended the first third of their lectures; the exposure confirmed my impression that for computing science, Bourbaki is not the ideal starting point. Both seemed to minimize their attendance; Courcelle at least had prepared his visuals with care. Our Manfreds --Wirsing and Broy-- were very German: the first one encyclopedic, the second one belligerent. Being well-prepared and carefully presented, their lectures were not unpleasant to listen to. I heard half of their talks.

I grossly deviated from the working material I had handed out. After my first lecture I decided to present "smooth sort", i.e. the algorithm I had developed the month before. All my lectures had been scheduled at the beginning of the day, an arrangement which would have been OK if I had talked on six separate topics. Now it was a handicap and for the presentation of smoothsort I needed four lectures instead of the intended three. But I did not lose the attention of the audience and I think my effort was appreciated. On the last morning I showed the generalized philosophers as I had done three years ago. At that occasion a remark by Susan Owicki prompted the removal of my original reductio at absurdum; this time Luigi Lorippo (from the University of Ottawa) came up with a more general proof showing that on an infinite network starvation was impossible. (The day after my return I received a long letter from Don Knuth, who wrote me that smoothsort was new to him. With Don's comments and my experience in Marktoberdorf I think I can now write the final version of that paper. I don't need to change much, but for a number of decisions I should indicate the reasons.)

It was a good thing the Summer School did not last longer: at the end we were all exhausted. In Johanniskreuz (near Kaiserlautern) I started a series of 12-hour nights.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
12 August 1981
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 12 Jul 2004

08xx

800: A bagatelle for the left hand

801: Distances from the root in skew trees (with C.S.Scholten)

802: Trip report E.W.Dijkstra, Scotland, Newcastle 31 Aug.–15 Sep. 1981

804: On equality of propositions

805: Trip report E.W.Dijkstra, Amsterdam, 26–29 Oct. 1981

806: Trip report E.W.Dijkstra, USA, 1–27 Nov. 1981

808: Canonical string reduction

810a: Fast image construction in computerized axial tomography (CAT) (with A.J.M. van Gasteren)

811: An alternative ending for AvG16/ EWD809

814: A review of a book on PEARL

818: A nice theorem on monotonic predicate sequences

819: Mathematical induction and computing science

821: From predicate transformers to predicates (Dedicated by the Tuesday Afternoon Club to C.A.R. Hoare at the occasion of his being elected Fellow of the Royal Society.)

824: Linearization of a two-dimensional search

826: Trip report E.W.Dijkstra, USA, 20 May 1982 – 14 June 1982

827: A very simple exercise in SASL

829: De software crisis, ontstaan en hardnekkigheid

831: Why numbering should start at zero

832: A theorem about infinite sequences of numbers

833: An In-Depth Seminar on Proven Tools & Techniques of Structured Methodology for Effective Software Configuration Management

837: Trip report E.W.Dijkstra, Newcastle-upon Tyne, 6–10 Sep. 1982

838: Trip report E.W.Dijkstra, Copenhagen, 10–16 Sep. 1982

839: Trip report E.W.Dijkstra, Utrecht 30 Sep.–1 Oct. 1982

841: “There is no ‘royal road’ to geometry”

845: McCarthy’s 91–function: an unfortunate paradigm

847: Trip report E.W.Dijkstra, Australia, 19 Jan.1983 – 12 Feb.1983

850: Trip report E.W.Dijkstra, Helsinki, 1–4 March 1983

852: Judging “HOS” from a distance

853a: Ingenieur Ebergen, Weledelgetrenge Heer

854: The fruits of misunderstanding

855: Trip report E.W.Dijkstra, Barcelona 5–7 June 1983

856: On maximizing a product

857: Generalizing an old formula

858: Trip report E.W.Dijkstra, USA, 10 June–3 July 1983

861: Research proposal: Our plans for the years to come (with A.J.M. van Gasteren)

862: A sequence with |x[n]| = x[n–1] + x[n+1] has period 9

864: The distributed snapshot of Chandy/Lamport/Misra

864a: The Distributed Snapshot of K.M.Chandy and L. Lamport

865: Trip report E.W.Dijkstra, Brasil & USA, 17 Oct.– 6 Nov. 1983

866: An analytical proof of the Butterfly Theorem

868: Computers and General Education: a position paper

869: Ter afsluiting van de “Inleiding tot de Kunst van het Programmeren”

870: My mother’s proof of the Butterfly Theorem (see EWD866)

872: The little essay I could not write

873: Trip report E.W.Dijkstra, London and Colchester, 16–20 Jan. 1984

876: De microprocessor als lollie

877: Some useful formulae (with A.J.M. van Gasteren)

878: A monotonicity argument (with A.J.M. van Gasteren)

879: Trip report E.W.Dijkstra, London, 14–17 February 1984

881: A review of “The Evolution of Programs”

885: Trip report E.W.Dijkstra, Muenchen, 12–14 April 1984

887: Trip report E.W.Dijkstra, USA, 23 April –10 May 1984

888: Trip report E.W.Dijkstra, Zürich, 22–24 May 1984

889: User-friendly Mathematics

892: Trip report E.W.Dijkstra, London, 12–14 June 1984

893: Trip report E.W.Dijkstra, USA, 17–26 June 1984

895: Trip report E.W.Dijkstra, Marktoberdorf, 30 July – 12 Aug. 1984

896: On the nature of computing science

898: The threats to computing science

EWD800-0

A bagatelle for the left hand

This is a kind of glossary --very incomplete, I am afraid-- of terminology I have learned to suspect. There was a time when it used to disturb me to hear or see the heavy use of a term that was never or rarily employed by myself. But, as the years went by, I discovered that I remained quite happy without those terms in my active vocabulary, and my sense of guilt has disappeared to the extent that their use by others can now make me quite suspicious. (The idea to write such a glossary dates from well before I broke my right arm; hence its low serial number.)

real

Beware of "the real world". A speaker's appeal to it is always an invitation not to challenge his tacit assumptions. When a speaker refers to the real world, a useful counterploy is pointing out that he only refers to his perception of it. We find it nowadays hyphenated in "real-world problems"; please remember that those are typically the ones we are left with when we have refused to apply their effective solutions.

References to "real programmers" I usually counter by the rhetorical question "Am I a virtual programmer?"

Make it a habit to check whether "real" is used as a euphemism for "education resistant". The "real" in "real numbers" passes this test and is quite respectable (provided you believe in Cantor and Dedekind).

EWD800-1

natural versus artificial

It is not only the food industry that employs "natural" as a vague recommendation. (The almonds the airlines serve with the drinks are always "Natural hickory flavoured".) In the worlds of logic and computing we find that same laudatory undertone in "natural deduction" and "natural language (programming)". On closer scrutiny it is a euphemism for something like "appealing to the uneducated".

The adjective is acceptable in the technical term "natural logarithm" and "natural numbers" (provided the latter start at zero).

Equally objectionable is the pejorative usage of "artificial". The nicest examples of such usage was given by the high military expert who declared that "obviously NATO is not interested in artificially simplified languages such as Pascal". Must we conclude that defence prefers naturally complicated languages? (Ada seems to confirm that conclusion.)

intuition

My Pocket Oxford Dictionary --which requires a rather large pocket-- defines "intuition: immediate apprehension by the mind without reasoning". If we don't believe in miracles, we seem to have only two possibilities: either the reasoning required is so short and standard that it is hardly worth being recorded or mentioned, or the "immediate apprehension" does not amount to much. In the first case "intuitively clear" means

EWD800-2

"obvious", in the second case it probably means no more than the absence of obvious counterexamples. In both cases, mathematical texts "recommended" for their appeal to the reader's intuition should be ignored, for such texts promote non-reasoning instead of better reasoning.

Despite the above, there are still people that believe that intuition is a good thing; there is no point in arguing with them for they prefer to believe in miracles.

views of data

I never talk about (different!) "views of data". Not only can I do without them, but I have even the distinct impression that by talking about them people are more hampered than helped.

Plataanstraat 5
5671 AL Nuenen
The Netherlands

27 January 1982
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Thu, 19 Jun 2003.

  EWD 801

Distances from the root in skew trees

by Edsger W. Dijkstra and C.S. Scholten

Renewed interest in algorithms for sorting in situ raised the question of the average distance from node to root in binary trees other than balanced ones. (Here binary trees are to be understood as rooted trees in which nodes have zero, one, or two sons.)

In particular we consider the infinite sequence of trees Ti (i ≥ 0), in which for some fixed p and q (p > q ≥ 0)

Ti for 0 ≤ i < p are arbitrarily chosen

Tn and Tn+q are the subtrees of Tn+p

With Hi = the number of nodes in Ti, we have

Hn+p = Hn+q + Hn + 1        ;

with Gi = the sum of the distances of te nodes of Ti from its root we have

Gn+p = Gn+q + Gn + Hn+q + Hn        .

We are interested in the asymptotic behaviour of Gi / Hi for large i, this ratio being the average distance from the root in Ti.

Without loss of generality we can confine ourselves to the case gcd(p,q) = 1, since in the case gcd(p,q) = g > 1, the sequence Ti consists of an interleaving of g mutually independent sequences.

With Ai defined by Ai = Hi + 1 and Bi defined by Bi = Gi – 2, we derive

(0)    An+p = An+q + An

(1)    Bn+p = Bn+q + Bn + An+p

Equation (1) is not homogeneous in the B's, but by solving it for the A's and substituting them in (0), we get a homogeneous recurrence relation for the B's, the characteristic polynomial of which is the product of (0)'s characteristic polynomial and the characteristic polynomial corresponding to the homogeneous part of (1). We conclude that the characteristic equation for the Ai is

(2)    xp – xq – 1 = 0

and that that for the Bi is

(3)    (xp – xq – 1)² = 0

Under the constraints gcd(p,q) = 1 and p > q ≥ 0, (2) enjoys the property of having one positive root, r say, such that r > 1 and all other roots of (2) have a modulus smaller than r. (For a proof of this theorem, see later.)

From this and the theory of linear recurrence relations we conclude

1)  
that the leading term of Ai is of the form k · ri for some constant k

2)  
that the leading term of Bi is of the form ( l + L·i ) · ri for some constants l and L.

Substituting these leading terms in (1) we get

( l + L·(n+p) ) · rn+p =
           ( l + L·(n+q) ) · rn+q + ( l + L·n ) · rn + k · rn+p

Since r is a root of (2) this can be reduced to

(4)    L / k = rp / ( p · rp – q · rq )

We define the skewness of a binary tree as the ratio (≥ 1) of the numbers of nodes in its two subtrees. For the trees Ti it follows from the leading term of Ai that the asymptotic skewness s is given by s = rq, whence q = rlog s. Remembering that r satisfies (2), we find rp = s+1, whence p = rlog (s+1). Hence (4) can be rewritten as

(5)    L / k =

s+1

(s+1) · rlog (s+1) – s·rlog s

Because r > 1 —so that the asymptotic value of Gi / Hi equals that of Bi / Ai—, we conclude that, expressed in r and s, the average distance from the root in Ti is for large i

(s+1) · i

(s+1) · rlog (s+1) – s · rlog s

Consequently, the average distance from the root in a tree from the sequence Ti with N nodes is

(s+1) · log N

(s+1) · log (s+1) – s · log s

i.e. an expression in s and N only.

*      *      *

We are left with the obligation to prove that f x = 0 with f x = xp – xq – 1 has one positive root r > 1 dominating the others. Since f 0 = –1 and f(+∞) = +∞, f x = 0 has an odd number of positive roots. Because f' x = xq–1 · ( p·xp–q – q ) we conclude that f' x = 0 has at most 1 positive root; hence f x = 0 has 1 positive root r and, because f 1 = –1, we conclude r > 1. In other words

(6)    for x ≥ 0    sgn(f x) = sgn(x–r)

In order to prove dominance of r, we consider a root m·ei·φ of (2), with m > 0. Consequently

mp · ei·p·φ = mq · ei·q·φ + 1 ,

from which we derive —by taking absolute values—

mp < mq + 1 ∨ (p·φ) mod 2π = (q·φ) mod 2π = 0 .

Since gcd(p,q) = 1, this can be rewritten as mp – mq – 1 < 0 ∨ φ = 0 or, in view of (6): m<r ∨ φ = 0. q.e.d.

*      *      *

Finally we remark that thanks to

p

q

   =   
log (s+1)

log s

any value of s can be approximated arbitrarily closely by suitable choice of p and q, a fact that enhances the significance of the expression in s and N for the average distance from the root.

28 August 1981

drs. C. S. Scholten
Philips Research Laboratories
5600 MD  EINDHOVEN
The Netherlands

prof. dr. E. W. Dijkstra
Burroughs Research Fellow
Plataanstraat 5
5671 AL  NUENEN
The Netherlands

transcribed by Martijn van der Veen
revised Thu, 11 Nov 2004

EWD802 - 0

Trip report E.W.Dijkstra, Scotland, Newcastle 31 Aug-15 Sep 1981

Sunday morning 7:10, Femke (who had just got her driver's licence) took me to the Eindhoven railway station. Well in time for the 10:55 flight to Edinburgh. I arrived at Schiphol, not knowing yet that my flight would be delayed for almost three hours. The plane, a Fokker Friendship, arrived in time but, while landing, the pilot had jammed its nose wheel. The plane having been manufactured ten miles from where we were, I thought in my innocence that it would be fixed quickly, but Air UK preferred to fly in the spare part from Norwich, England. In the course of the afternoon I arrived in Edinburgh, where I was collected by Mr. Hannah (of Burroughs) and his wife. They drove me to The Marine Hotel in North Berwick, where I would give a seminar the next week for people from various Burroughs plants in Europe.

I had hoped to address an audience of about 25, but found a list of only 14 names. The two men from France were at the last minute replaced by one other man and the two participants from Croydon just did not show up. So I started with 11. I ended with 10 because, on Wednesday morning before breakfast, Jim Wilson (from Cumbernauld, Scotland) was found unconscious on the beach. (After 24 hours for observation in the Royal Infirmary in Edinburgh, his wife was allowed to take him home. He seemed all right; he had been jogging.)

EWD802 - 1

The rather small size of the audience, I am happy to say, was more than compensated by its quality. They were bright. The majority was not very experienced and certainly not knowledgeable, but the combination of ignorance and intellect makes quite a pleasant audience: there was a lot I had to show them but I could show it to them! I lectured for five successive days, between 6 and 7 hours per day. The first two days were largely devoted to standard material (with on the first morning the standard surprise from the audience that universal quantification over the empty set yields true). One afternoon was largely spent on the development and explanation of heapsort (something I had never done before); I did this when I discovered that I was the only one in the room who knew that algorithm. Another afternoon was quite unexpectedly spent on multiprogramming. (I derived the implementation of the conditional critical region using a split binary semaphore.) For two of the three Walloons the language barrier was severe; they did not know a single word of Dutch.

On Friday afternoon at 17:00, Mrs. Joan Suggett of The Marine Hotel took me to the station of Drem, where I should catch the train to Newcastle-upon-Tyne. I was early and the train was late. The "station" of Drem is just two platforms at either side of the track; it was unmanned and the result was that for 45 minutes I was waiting alone in the middle of nowhere; the

EWD802 - 2

Scottish wind had begun to blow and I was relieved when the train at last arrived. Around 20:00 I arrived in Newcastle.

The next 9 days I stayed with the Randells. Brian's wife was at the station; half an hour earlier she had collected a French girl - the new teaching assistant for French - who stayed with them as well until she had found accommodation. This made the house somewhat crowded and, the weather being unusually mild, the two eldest children decided to sleep in a tent in the garden.

On Saturday afternoon Brian took Françoise - such was quite appropriately the French girl's name - and me to Warkworth Castle - that is, to what has remained of it, but that was impressive enough - and to the "Hermitage" nearby, a pre-medieval chapel hewn out in the rocks. A so-called unique experience. The next afternoon, Brian went with Françoise and some of his sons to a rugby match; I stayed home and wrote. On Monday I joined Brian on his walk to and from the University, where I spent the day talking and reading (in "The Mathematical Experience" by Philip J. Davis and Reuben Hersh (Birkhäuser), a new book, but too philosophical for me).

At the home of Harry Whitfield we had that evening the first social event of the 14th, Joint International

EWD802 - 3

Seminar on the Teaching of Computing Science, this time devoted to Very Large Scale Integration. The next morning the seminar started in real earnest.

We started with the obligatory IBM speaker, this time Dr. V.L. Rideout, and when he started with the usual slide show, I feared the worst. But, apart from the fact that he showed too much and spoke mostly in acronyms, he was an excellent speaker who gave an instructive survey of the technological difficulties of chip fabrication. (Later in the week, other American speakers would refer to the "fab line".) He gave 2 lectures. The third IBM lecture was given by Dr. J. Rivierre, who made it quite clear - he talked about test pattern generation - that for chips quality control is a profoundly unsolved problem. I appreciated his choice of topic, for too many in that field are only too happy to ignore this unfortunate circumstance. (I remember Noice's comment along the lines "From a technological point of view it is not attractive, but it does not matter too much for our competitors cannot do better.") His was a slide show too.

Dr. J. Gray (University of Edinburgh) gave two lectures on "Structured Design". What he told he told convincingly, viz. that design discipline made most of the elaborate "CAD tools" (CAD for Computer Aided Design) superfluous. In contrast to the previous speakers, Gray told perhaps too little. Besides the

EWD802 - 4

unavoidable slides he showed transparencies.

Prof. Dr. M. Rem used the blackboard. He gave 2 lectures illustrating a design discipline, the first one on a notation for restoring logic circuitry, the second one on partially ordered computations. In his first lecture he hesitated too much, his second lecture was much better. Amazingly enough, M. Wells (Leeds) almost exploded when he was half-way, complaining that Rem was not concrete enough and did not give a "picture to show what he was talking about". I can only fear that Wells has not followed what C.A.R. Hoare has been writing about during the last four years. (More in the audience seemed flabbergasted by the fact that so much can be said independently of the distinction between input and output. The inability not to make that distinction seems a further price to be paid for a very operational approach.)

Prof. H.T. Kung (Carnegie-Mellon University) gave 3 lectures on his high-performance special purpose designs, which are very original. (They are fun.) He had given these lectures - transparency shows - many times before, but delivered them with an almost contagious enthusiasm. The combination of a severe stammer and a strong Chinese accent made him not too easy to understand. The most amazing thing is that he did it all by hand-waving

EWD802 - 5

and seemed to have never considered a decent notation for and a more rigorous treatment of his highly concurrent computations.

(The above was written on the evening of Friday 11 Sept. 1981, while Brian Randell and his wife were to the opera; they had invited me to join them but, disliking opera, I had declined their invitation whole-heartedly.)

We were exposed to 3 presentations given by Prof. C.H. Sequin (University of California, Berkeley). Underlying his topic was the Mead/Conway design methodology "requiring virtually no specific knowledge about the physics of silicon devices", and that sounds very sensible. But his description of the course in which this way of designing chips was taught gave me the impression of something rather silly. He spoke much more like a manager than as a scientist, and I found him unpleasant to listen to. His students seemed to learn how to make the best of a set of dubious "design tools"; the gap between intentions and actual practice seemed very wide.

Finally we had 3 presentations by Prof. J. Allen (MIT) but he used such loose language ("multiple levels of process representation") that I found it impossible to figure out what he was talking about. One thing, however, was clear: his unshakable faith

EWD802 - 6

in "logic simulators". One of the "CAD tools" - Sequin had mentioned it too - tried to reconstruct the circuitry from the raster description of the masks! The amount of pattern recognition involved made it a very expensive (and not too reliable) tool, and Allen seriously proposed to design a special machine for this purpose. In his summary of what we had learned, Prof. C.A.R. Hoare compared it with the future software design tool that, by analysing the object code on the bit level, would perform the type checking for Ada programs "since, of course, you cannot trust the compiler". It was a great pity that, by that time, Allen had left.

Much of the design process as shown to us seemed engineering in the worst possible sense of the word, viz. essentially by trial and error. (In this connection, Sequin's insistence on the quick turn-around from the "fab line" was very telling: evidently the chip itself was a component in a major feedback loop in the design process.) A large part of the design costs seems due to ignoring that errors are the more expensive, the later you catch them. I could not help remembering that for certain types of artefacts such an experimental design strategy is fundamentally inadequate, e.g. a mathematical proof. You can only get a proof right by not making a mistake, and discrete designs share that property. The VLSI community as a whole does not seem to

EWD802 - 7

have learned that lesson yet.

On Saturday afternoon, Brian took me to a waterfowl park nearby, on Sunday I helped his daughter with her mathematics homework before I was off to Glasgow, where I arrived at 18:00 for a visit to the Department of Computer Science of the University. Dinner and part of the evening were pleasantly spent in the company of my host, Dr. J. Cavouras. The next morning was spent at the department, that afternoon, from 14:15 until 16:30, I gave a (new) talk on the presentation of programs for an audience of about 100 people. Immediately afterwards I left for Edinburgh, where I would spend a similar day at Heriot-Watt University. My host, Dr. H. Davis, was again most pleasant; I gave the same talk (be it compressed: from 14:30 until 15:45) for about 75 people. Air UK was on time, and at 23:00 that evening I was home again.

I found the two departments very different. Glasgow was not much more than a teaching establishment; it may amount to something in numerical analysis - Prof. D. Gilles was away, examining in St. Andrews - computing science seemed to have been replaced by the art of living with an ICL system. From incompatible character sets the discussion drifted to the question which campus facilities charged VAT

EWD802 - 8

(= Value Added Tax) for their refreshments. At Heriot-Watt, however, the range of scientific topics raised by my hosts seemed unbounded (the structure of termination proofs in connection with transfinite induction, Polya, early work of Hoare, and a few new monographs - including one which, by now, should be available in the U.S.A. but has not reached Europe yet -; the preceding enumeration is far from exhaustive).

The delivery of my own lecture, however, pleased me more in Glasgow than in Edinburgh. Perhaps my second audience was more demanding; perhaps I suffered in Edinburgh from lack of time (I had prepared the blackboard, which could have been a mistake). Perhaps it was because my preceding night in the Edinburgh Facility Club had been sleepless. At breakfast I heard that one of the young women serving at the Faculty Club had fallen under a train that night.

In Eindhover, Femke and Ria (my wife) were at the station; Femke drove.

Plataanstraat 5 5671 AL NEUNEN The Netherlands | 15 September 1981 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

Transcribed by Mikhail Esteves

Last revised on Tue, 14 Oct 2003.

EWD804-0

On equality of propositions

After the observation that equality of propositions seems to be underused in mathematical reasoning, I discovered that I myself was --perhaps not surprisingly-- only vaguely familiar with all sorts of equalities. This note --which is not deep at all-- is written to remedy that situation. I shall not repeat that ∧ and ∨ are symmetric, associative and mutually distributive; neither shall I repeat de Morgan's laws.

The following expressions (E0.i) are all equal.

(E0.0)

P

(E0.1)

¬¬P

(E0.2)

P ∨ P

(E0.3)

P ∧ P

(E0.4)

P ∨ F

(E0.5)

P ∧ T

(E0.6)

P ∨ (P ∧ Q)

(E0.7)

P ∧ (P ∨ Q)

With the possible exception of the last two, (the so-called "Laws of Absorption") this is very familiar ground. Also expressions (E1.i) are all equal.

In the following, = has the lowest binding power

EWD804-1

(E1.0)

P = Q

(E1.1)

¬P = ¬Q

(E1.2)

(P ∨ ¬Q) ∧ (¬P ∨ Q)

(E1.3)

(P ∧ Q) ∨ (¬P ∧ ¬Q)

Also expressions (E2.i) are all equal; since (E2.0) is symmetric, they occur in pairs.

(E2.0)

P ∨ Q

(E2.1)

P ∨ ¬Q = P

(E2.2)

¬P ∨ Q = Q

(E2.3)

P ∧ ¬Q = ¬Q

(E2.4)

¬P ∧ Q = ¬P

(E2.5)

P ∧ (R ∨ ¬Q) = (P ∧ R) ∨ ¬Q

(E2.6)

(¬P ∨ R) ∧ Q = ¬P ∨ (R ∧ Q)

The last two were absolutely new for me; their discovery --in a completely different context-- provided the incentive to write this note.

Plataanstraat 5
5671 AL NUENEN
The Netherlands

5 October 1981
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Sun, 22 Jun 2003.

EWD805-0

Trip report E.W. Dijkstra, Amsterdam 26-29 Oct. 1981

IFIP's TC2 and the Mathematical Centre in Amsterdam had organised a four-day "International Symposium on Algorithmic Languages" at the occasion of prof.dr.ir. A. van Wijngaarden's retirement as director of the Mathematical Centre.

On Saturday morning Ria and I drove to Schiphol to collect prof.dr. W.M. Turski (from Warsaw) and prof.dr. A.P. Ershov (from Novosibirsk), who stayed the weekend with us in Nuenen. (It was well-organized: their planes landed 10 minutes apart!) It was a very nice weekend; on Sunday afternoon we were joined by Femke, who first spoke for an hour Russian with Ershov and then exercised for more than two hours the pronunciation of Polish with Turski. The weekend gave Ershov the opportunity to absorb some of the six-hour time shift.

On Monday morning we took the 8.06 train to Amsterdam Amstel, where we took a cab; at 9.35 we were at the Mathematical Centre, where the symposium was held. During the next four days we had plenty of opportunity to explore the Amsterdam public transport system: we were lodged in the International Centre of the Royal Tropical Institute, on Monday evening we had a reception in the Stedelijk Museum, on Tuesday evening van Wijngaarden gave a dinner to friends in the Rosarium, and on Wed-

EWD805-1

nesday evening we had the Conference Dinner in the Lido at the Leidse Plein.

As member of the Program Committee I knew that it would not be a very good conference; apparently the computing community had sensed this, for there were only about 125 participants. There were three invited talks on van Wijngaarden's role: Heinz Zemanek (re IFIP), Peter Naur (re ALGOL 60) and Wlad Turski (re ALGOL 68). All three talks were well-prepared and well-presented. Good technical talks were given by R. Schild (from Switzerland), B. Meyer (from France), M. Broy (from Germany), M. Sato (from Japan) and J.C. Reynolds (from the USA). I found J. Darlington (from the UK) again totally unconvincing; J. Backus (from the USA) caused grave disappointment. J.D. Roberts (from the UK) baffled his audience, D. de Champeaux (from the Netherlands) insulted it by the lousiness of his presentation. H.S. Warren (from the USA) spoke about his thesis topic (under Schwarz at NYU), which was remarkably foolish, and all the rest I found rather boring. We had woolly talks --about "the user" and "the beginning programmer"--; some of the more mathematical papers most definitely lacked the effectiveness that is so dear to me. For lack of submitted papers the presentation of each had been allotted 40 minutes and on the average this was too much. (Independently of each other, two speakers of the Mathematical Centre filled half their slot by defining

EWD805-2

the notion of a transitive closure!)

The conference quite clearly suffered from the fact that it had been organised in honour of van Wijngaarden, who was sitting in the front row. A number of speakers really deserved to be torn apart, but the audience did not do it (or the chairman did not allow it) for fear of spoiling the fun for van Wijngaarden.

Turski's closing speech was magnificent. Belonging to the famous "minority" that left W.G.2.1 in protest in 1968, he should never have been asked to talk about van Wijngaarden and ALGOL 68. He solved his problem by treating ALGOL 68 as a mistake carried through to perfection, giving van Wijngaarden the credit for the latter, and W.G.2.1 the blame for the first. It was a very subtle balance!

On Thursday afternoon I was back home in time for dinner.

Plataanstraat 5
5671 AL NUENEN
The Netherlands

30 October 1981
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Thu, 19 Jun 2003.

EWD 806

Trip report E.W.Dijkstra, USA, 1-27 Nov. 1981.

My itinerary was as follows:
on the 1st Nov. from Nuenen via New York to Edison, N.J. to give a lecture at Bell Labs (on the request of Burroughs);
on the 3rd Nov. to Ithaca, to visit Cornell University (on my own initiative);
on the 8th Nov. via New York and Boston to the "Wang Institute of Graduate Studies" (invited as Distinguished Lecturer by Bill McKeeman);
on the 10th Nov. to Austin, Texas, for a visit to the Austin Research Center of Burroughs Corporation;
on the 20th Nov. to Pasadena for a visit to CalTech (at their request);
on the 26th Nov. back home, where I arrived at 18:00 the next day.

With most flights there was something wrong. In Amsterdam we left with a three-hour delay after a change of planes because of a failing lock of a luggage compartment door and half an hour before landing at JFK the captain announced that there was nothing to worry about: we landed with the fire engines along the runway. My flight from La Guardia to Ithaca was changed to one from Newark, but at checking in I learned that that one was going to Syracuse! The change was undone and I still caught my original flight from La Guardia. The flight from Ithaca was cancelled; eventually I flew from Syracuse to La Guardia, where I missed my connection to Boston. The flight from Boston to Austin had been moved forward over 9 minutes, the one from Austin to Los Angeles over 50 minutes. The return flight was OK; reaching LAX from Pasadena, however, had been difficult: it was the afternoon before Thanksgiving and all the freeways were jammed. I was very tired when I came home, and slept most of the following sixteen hours.

At Bell Labs I spoke one morning for an audience of 200 (with only 3 miserable flip charts as visual aid). At Cornell I gave a seminar (for 75 people) and one of the lectures in Fred Schneider's course. At the Wang Institute I gave a lecture for 278 people —no blackboard of course!— . At the University of Texas at Austin I addressed 150 people (without throat microphone, but the acoustics of the lecture hall were adequate). At CalTech I gave a seminar (for a larger audience than the lecture room could hold) and two lectures in Alain Martin's course. All these public performances went very well; I have lectured on five different topics.

From my visit to Edison I don't remember too much. I was collected at JFK by Tom Schaible, who lost the way: after almost an hour we were back at JFK. Monday morning was used for recovery; in the afternoon we inspected the lecture hall and I redesigned the introduction of my lecture in view of the absence of decent facilities. In the evening we were offered a dinner by Bell; Walter McWilliams and Steve Bourne were among our hosts and it was a pleasure to meet them again. I missed Doug McIllroy. Shortly after lunch on Tuesday, Schaible and I left for the airport.

I spent Wednesday, Thursday, and Friday in the usual way at Cornell. People came in to show me what they were working on. (John Hopcroft being absent, I could use his office.) The first hours they had not discovered yet that I was there, so that I could get some writing done. I saw several "program development environments"; one, geared to PL/C, was particular silly; another one, generating verification conditions, was silly too, but more interesting. It used attribute grammars and, three days (!) after they had realized that they could do first-order predicate calculus in the same manner, they had that system working —well, after a fashion: it failed to prove something like (a ∧ b) ∨ ¬a ∨ ¬b . (Not quite certain what had happened, the author blamed Gentzen.) Talked long with Fred Schneider and with Jan Prins; agreed with the latter that a project by one of their physicists —something like program improvement by semantics preserving but otherwise random mutations— was crazy. About the way in which they intend or try to apply logic —Constable's influence?— I am not too happy, but I guess a few youngsters will recover. It is still a very good department but is definitely beginning to suffer from the ubiquitous terminal. I stayed with David Gries and spent most of Saturday writing. Neither David nor I had the home telephone number of Bill McKeeman who had promised to collect me on Sunday at the Boston Airport. When my flight was cancelled, David managed to get the message through by calling John Guttag, who is now at MIT.

I stayed two nights with Bill McKeeman at his home in the woods. Sunday evening we had dinner there with seven, among whom Nancy Martin, whom I had met in January 1974 in Albuquerque. She is now on McKeeman's faculty. On Monday morning I prepared my transparencies. Then I had lunch with James Bouhana, who was worried about syntax and is co-authoring a book with Peter Denning. Dinner after my talk, and the next morning a two-hours discussion with more than a dozen students of the Wang Institute. Finally, three of them —they were very nice ones— saw me to the airport.

The Wang Institute sells its Graduate Studies aggressively —I stole a folder: "The most successful, most powerful software engineering leaders of the next 20 years will remember this building well."— in an environment full of computing industries of all sizes —among the audience at my lecture I counted more than 30 of such affiliations— . But if its graduates remember "this building" 20 years from now, they may do so to curse it: the Institute may bestow the degree of "Master of Software Engineering" and suffers accordingly from all confusing connotations of that misnomer. The curriculum was entirely geared to today's practice and lacked substance. Most students were employed by one of the 30 industries —who, as a rule, paid the tuition fee of $7000,- !— and Bill McKeeman swore that such was the curriculum those employers preferred. I left the place in a state of some distress. (I fear that the place is aptly characterized by the fact that my predecessor as "Distinguished Lecturer" had been Tom Gilb!)

The first two days at Burroughs's ARC (=Austin Research Center) coincided with a visit by a couple of vice-presidents from Detroit. On Friday I went for half a day to the University to talk with Misra and Chandy. With the exception of Wednesday afternoon —when I met Boyer and Moore at the University and gave my lecture— I was at ARC the next week. One morning I helped a little group of people to read an article: its approach was unfamiliar to them but I felt that they should know it. One afternoon I lectured on program development. One day was devoted to a discussion of proof patterns, another one to the dispelling of false hopes. And I tried to help clarify the direction of ARC's future research. At the end of that week I was exhausted. Each morning I was woken up at 7:00; at 7:45 I left and around 8:10 I arrived at the lab, where I stayed until 17:00 or 17:30. And on at least six evenings I had dinner in town (which often meant that shop talk went on).

When I arrived in Austin, Hertz did not have the ordered (and promised) Toyota; I was given a Ford Mustang —with automatic gear shift, etc.— instead. When I told my hosts that in the Netherlands the Ford Mustang was only used by beginning pimps, it was immediately known as "the pimpmobile". I did not like it at all and was glad to return it when I left for Pasadena.

In Pasadena I stayed with Alain and Marianne Martin. That weekend we did nothing until Sunday evening, when four people from the department came for a drink. The next two-and-a-half days I spent at CalTech in very much the same way as at Cornell. I spent several hours with Chuck L.Seitz and with Carver Mead; they both struck me as designers with great confidence. The whole atmosphere was rather pragmatic (perhaps a bit too pragmatic for my taste). I met two bright graduate students, but was not impressed by the quality of their average graduate student. On Monday evening I had dinner with a number of undergraduate students in one of the dormitories. Suddenly there was a deafening noise; in his room, one of the undergraduates had been fooling with his guns. One student explained to me that he did not care about the quality of his (hand)writing because he was preparing himself for an industrial career.

I could not resist the temptation to use for my last lecture a quotation from one of their own professors (of half a century ago), viz. E.T.Bell "Pictures after all may be suitable only for very young children." Shortly before I had been shown the department's system for colour graphics; when I looked at a screen displaying a text in four or five different colours, the system was recommended because it was so handy for making transparencies.

I could have guessed this. Alain had already warned me that at the beginning of each of my lectures we would have to remove the overhead projector. The cocktail party after my lecture at the University of Texas at Austin had prepared me. When the topic of my lecture —"The presentation of programs"— was mentioned, one of the faculty members, who had not attended my lecture, fully understood my choice of topic because there had been so much progress lately: "Books on programming used to be very dull, but recently I have seen at least two books with nice colour graphics." (I behaved very well and did not answer by telling that I had used white chalk only.)

The whole trip was a reminder not to confuse the problems of computing science with the problems of the American educational system, which treats the young American if not as education-proof at least as education-resistant. In this pessimistic mood, the pupil does not expect to get educated, the teacher does not expect to have much effect, and the whole educational process works only after a fashion. The same pessimism underlies the tacit assumption that you cannot expect a human to do an excellent job and the consequent craving for "tools". (It got so bad, when in the discussion after my last seminar someone mentioned "powerful language features", I had to point out quite explicitly that a programming language never solves your problems and that you may be grateful when it does not add to them.)

During the weekend in Austin I read "Less than words can say" by Richard Mitchell (also known as "the underground grammarian"); very amusing and equally distressing. "Should we raise a generation of literate Americans, very little of the America as we know it would survive." I am afraid he is dead right.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 28 November 1981 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD808 - 0

Canonical string reduction

This note addresses the problem of how to characterize an intermediate machine state during the evaluation of a SASL expression. Addressing that problem without any specific implementation in mind and observing that both the initial state and the answer are legitimate SASL expressions, I shall try to characterize the relevant intermediate states as SASL expressions as well. In doing so I hope to design such a strict scheme for using scopes that some light is shed on the problem of garbage detection.

I have to adapt SASL's syntax to my purpose. Instead of writing

  from 0
    where from n = n : from (n+1)

I shall write

  |[ from with from =
       |[ n : from (n+1) with n= ]|
  ]| 0

The inner block on the middle line delineates the scope of n ; the fact that it ends on "with n=]|" indicates that it represents what some readers may

EWD808 - 1

know better as the λ-expression λn • (n:from(n+1)). The outer block delineates the scope of the identifier from . Its first occurrence states that the whole block stands for the object locally known as "from"; "with from = " introduces a definition of the object locally known as "from"; the object being a function, its definition then follows as a λ-expression. Note the contrast with the original SASL program: there the whole expression "from 0" was defined with the scope of "from", while in our version the scope of "from" is chosen as small as possible.

We shall do our experiments with a slightly more ambitious program, viz. the program for the tabulation of fusc, inspired by J.L.A. van de Snepscheut, designed by A.J.M. van Gasteren, and using the function "zip" as simplified by F.E.J. Kruseman Aretz.

In regular SASL the text could be

  x
  where x = 1 : zip x (elf x)
        where zip (p:q)r = p : zip r q
      elf(a:b:c) = a+b:elf(b:c)

The above definition fails to express very directly - i.e. otherwise than by the recognition of the pattern "b:c" - that the tail of the original argument of elf is the argument of the recursive call.

EWD808 - 2

In our notation, we would write

|[ x with x = 1: (0)
     |[ zip with zip= (1)
     |[ p: (2)
  |[ zip r q with r= ]| with p:q= (3)
     |] (4)
|]  x (5)
( |[ elf with elf= (6)
     |[ a + (7)
  |[ b with b:?=y]| : elf y with a:y= (8)
     ]| (9)
]| x) (10)
]| (11)

The scope of x extends over 0-11; the scope of zip extends over 1-5; the scope of p:q extends over 2-4; the scope of r is on line 3; the scope of elf extends over 6-10; the scope of a:y extends over 7-9; the scope of b is on line 8.

The definition of zip on 2-4 is arrived at by successive abstraction. From

     zip (p:q) r = p:zip r q

we derive, by abstracting first from r,

     zip (p:q) = p : |[ zip r q with r= ]|   .

Here, the proper scope for r has been determined as follows: the placing of "with r = ]|" is prescribed by our rule for λ-abstraction, the placing of the

EWD808 - 3

corresponding "|[" is determined by the rule that the scope coincides with the smallest syntactic unit containing all occurrences of the variable in question. Here its place reflects that functional application is left-associative, i.e. that zip r q is short for ((zip r) q).

On line 8, |[ b with b:?=y ]| is no more than a complicated way of writing "hd y". The convention followed seems consistent - it is, in terms of number of characters needed, clumsy, but that is of no relevance here: we are not proposing a notation to be programmed in.

Things defined within a scope are significant within that scope. Our final result should have global significance. This observation presents the process of evaluation as exporting successive elements of x - which is a continued concatenation of integers - outside the scope of the local terminology. (We had already decided to choose our scopes as small as possible; exporting as much as possible from them is a natural extension. It can be claimed that we already did so, when we replaced

          |[ p : zip r q with r= ]|
by        p : |[ zip r q with r= ]|   .    )

Evaluation of an expression can now be viewed

EWD808 - 4

as applying such reductions (i.e. semantics preserving transformations) that lead to export from a scope of values global with respect to that scope.

In this case we can do that by substitution. We have an expression of the form

          |[ x with x = 1: E(x) ]|  .

The substitution x = 1:w - meaningful because "1" has a meaning outside the scope of x - leads to the equivalent, but further evaluated expression

          1:|[ w with w = |[ E(x) with x=1:w ]| ]|    .

The inner bracket pair delineates the scope of x, the outer bracket pair delineates the scope of w.

Applying the substitution x=1:w we get

1:|[ w with w = (0)
     |[ |[ zip with zip = (1)
            |[ p: |[ zip r q with r = ]| with p:q= ]| (2)
     ]| x (3)
    (|[ elf with elf= (4)
        |[a + |[ b with b:?=y ]| : elf y with a:y= ]| (5)
     ]| x) with x = 1:w (6)
    ]| (7)
]| (8)

This is, to my feeling, not the moment to eliminate x

EWD808 - 5

- by substituting 1:w for it - since, within its scope, x is referenced twice. The next thing to do is to unfold zip, i.e. replacing its outer occurrence by its definition and inserting its definition at its inner occurrence, i.e. replacing lines (1), (2), and (3) by

      |[ |[ p: |[ |[ zip with zip =
                      |[ p: |[ zip r q with r = ]| with p:q = ]|
                  ]| r q with r =
               ]| with p:q =
         ]|

Application of the above unfolded zip to x=1:w leads to the elimination of the outer p:q, i.e. the above can be simplified to

      |[ 1: |[ |[ zip with zip =
                   |[ p : |[ zip r q with r = ]| with p:q = ]|
               ]| r w with r =
            ]|

We can now eliminate x by replacing its last occurrence by (1:w). The above being applied to the expression of 4-6, we also eliminate in the above the outer r, which is only referenced once. The combined result of these eliminations is

EWD808 - 6

1: |[ w with w = 1:
       |[ zip with zip =
           |[ p: |[ zip r q with r = ]| with p:q= ]|
       ]|
      (|[ elf with elf=
          |[ a+ |[ b with b:?=y ]| : elf y with a:y= ]|
       ]| (1:w)) w
   ]|

The next step is one we have seen before, viz substitution. This time we substitute something for w, say 1:x. The result is

1:1:
|[ x with x =
    |[ |[ zip with zip=
          |[ p : |[ zip r q with r = ]| with p:q= ]|
       ]|
      (|[ elf with elf=
          |[ a+ |[ b with b:?=y]| : elf y with a:y= ]|
       ]| (1:w)) w with w=1:x
    ]|
]|

Again, I have not felt the liberty of eliminating w, being referenced twice. The next step is to unfold zip again. In order to save writing I have performed the subsequent unfolding of elf as well.

EWD808 - 7

1:1: (0)
|[ x with x= (1)
   |[ |[ p: (2)
         |[ |[ zip with zip= (3)
               |[ p: |[ zip r q with r= ]| with p:q= ]| (4)
            ]| r q with r= (5)
         ]| with p:q= (6)
      ]| (7)
     (|[ a+ |[ b with b:?=y]|: (8)
          |[ elf with elf= (9)
               |[ a+ |[ b with b:?=y]| : elf y with a:y= ]| (10)
          ]| y with a:y= (11)
      ]| (1:w)) w with w=1:x (12)
   ]| (13)
]| (14)

Now we are ready to eliminate the outer a:y scope. Lines 8-12 become then

   (1 + |[ b with b:?=w ]|:
      |[ elf with elf=
         |[ a + |[ b with b:?=y ]| : elf y with a:y= ]|
      ]| w ) w with w = 1:x

Now we can do several things. On account of w=1:x the top line of the above can be replaced by "(1+1:" and then by "(2:". We can also eliminate the outer p:q scope. They commute; then the outer r scope can be eliminated.

EWD808 - 8

1:1:
|[ x with x=2:
   |[ |[ zip with zip =
         |[ p: |[ zip r q with r = ]| with p:q= ]|
      ]| w
     (|[ elf with elf=
         |[ a+ |[ b with b:?=y ]| : elf y with a:y = ]|
      ]| w) with w=1:x
   ]|
]|

But now I get into problems. Taking the definitions of zip and elf for granted, the above can be represented as

1:1: |[ x with x = 2: |[ zip w (elf w) with w = 1:x ]| ]|

and in a really demand-driven mode we would substitute x=2:y and we would get

1:1:2:
|[ y with y=
     |[ |[ zip w (elf w) with w = 1:x ]| with x = 2:y ]|
]|

One way to proceed would be to eliminate the scope of x:

1:1:2:
|[ y with y = |[ zip w (elf w) with w = 1:2:y ]| ]|

EWD808 - 9

followed by an application of zip

1:1:2:
|[ y with y = 1 : |[ zip (elf w) (2:y) with w = 1:2:y ]| ]|

followed by removal of w's single reference:

1:1:2:
|[ y with y = 1: zip (elf(1:2:y)) (2:y) ]|

On the other hand, in a truly demand-driven way, we could have applied zip, using w=1:x

1:1:2:
|[ y with y = 1:
     |[ |[ zip (elf w) x with w=1:x ]| with x = 2:y ]|
]|

followed by a removal of w's single reference

1:1:2:
|[ y with y=1: |[ zip (elf(1:x)) x with x=2:y ]| ]|

I like that last form better, and consider the early removal of the scope of x - on account of "single occurrence" - a mistake. Let us, therefore, try only to substitute when forced to do so by a function application. Let us redo the game, but now in shorthand.

EWD808 - 10

|[ x with x = 1 : zip x (elf x) ]|

The introduction x = 1:w leads to

1 : |[ w with w = |[ zip x (elf x) with x = 1:w ]| ]|

Application of zip forces the first x to be substituted

1 : |[ w with w = 1 : |[ zip (elf x) w with x = 1:w ]| ]|

The introduction of w = 1:y leads to

1:1:|[ y with y = |[ |[ zip (elf x) w with x = 1:w ]| with 1 = 1:y ]| ]|

Application of elf is now possible, and the scope for x disappears

1:1: |[ y with y = |[ zip (2:(elf w)) w with w = 1:y ]| ]|

Now zip can be applied

1:1: |[ y with y = 2: |[ zip w (elf w) with w = 1:y ]| ]|

Substituting y = 2:x we get

1:1:2:
|[ x with x = |[ |[ zip w (elf w) with w = 1:y]| with y = 2:x ]| ]|

Next we apply zip, using w = 1:y once

EWD808 - 11

1:1:2:
|[ x with x = 1 : |[ |[ zip (elf w) y with w=1:y ]| with y= 2:x ]| ]|

Etc. In this way the dilemma does not emerge. We need, of course, more and more identifiers, but that does not matter. We could use f[k:k≽0]; f[k] stands then for (+e)kf.

It is very well possible that the above example is much too simple. It suggests me, that garbage detection should not be a serious problem, and that should make me suspicious.

Note. I have not proved that with my last regime the dilemma does not arise, for the time being I am willing to believe it. (I am very willing to believe that the dilemma does not arise this way, for it is exactly the place where I got stuck a year ago). (End of Note.)

Plataanstraat 5 5671 AL NEUNEN The Netherlands | 16 December 1981 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

Transcribed by Mikhail Esteves

Last revised on Thu, 16 Oct 2003.

EWD810a

Fast image construction in computerized axial tomography (CAT)

The purpose of computerized axial tomography is to approximate the distribution of the absorption density in a cross-section of a specimen probed by many X-rays in the plane of the cross-section. This approximation, which is a non-negative function on a circular domain, is called the “image” because it is usually displayed on a screen, brightness representing the function value.

For the sake of discretization, the circular domain is subdivided into so-called “pixels”, i.e. little picture elements in each of which the approximating function is constant. The required resolution imposes an upper bound on the size of the pixels and hence a lower bound on their number. Each pixel requires the computation of a scalar value and, these computations being elaborate, there is a premium on not introducing many pixels more than needed for the resolution. (For each pixel the value to be computed is, in fact, a linear compositum of all the measurements.)

This note describes the structure of a special-purpose machine that could compute the image on the fly, i.e. during the few seconds the X-ray scanning of the cross-section takes. In medical applications in particular, such immediate availability of the image is deemed important.

The specimen is probed with rays in N homogeneously distributed directions. (Practical values of N would be 2400 or 2520 , the least common multiple of the integers up to 10 : we shall show later why it is desirable for N to have many small factors.) The rays in one direction are not necessarily equidistant; the same pattern of parallel rays is used for all N directions by rotating it in the plane of the cross-section around the centre of the circular domain. (Hence the name “axial” tomography.)

With M rays in each direction, the complete probing of the specimen yields M*N scalar measurements, viz, one for each ray traversing the specimen. Each measurement yields an additive contribution to each point of the image and this contribution —for a justification we refer to the literature— is
(i) proportional to the measurement
(ii) constant along lines in the direction of the ray with which the measurement was taken.
The contribution is, in fact, positive along the ray and negative everywhere else (but monotonically approaching 0 as the distance from the ray increases); beyond (i) and (ii) the precise shape of the contribution is of no importance in what follows. The number of pixels is large, say 50,000; the number of measurements is a few times larger and, with each of the measurements contributing to each pixel value, we conclude that image construction is a very sizeable computation indeed. The ensuing severity of the real-time requirement calls for special purpose equipment with a high degree of concurrency.

We shall first describe the processing of a single measurement, i.e. how its additive contribution to the image is approximated. To that end the circular domain is covered by a pattern of narrow stripes in the direction of the ray from which the measurement was derived; for all measurements from rays in the same direction we shall use the same pattern of stripes. Contributions are approximated by functions that are constant in each stripe and the widths of the stripes must be small enough to make this approximation adequate. Thus we have taken (ii) into account. For each measurement/stripe pair the contribution value requires one multiplication: the value measured has to be multiplied by a constant whose value is determined by the positions of the stripe and of the ray of the measurement. (With a multiplier per stripe, the multiplications for a single measurement can be performed simultaneously.) Thus we have taken (i) into account.

In the second phase each stripe contributes to the pixels (partially) covered by it: the pixel value is increased by the product of the stripe value and the fraction of the pixel that is covered by the stripe. This requires a few constants per pixel. (If no pixel is covered by more than two stripes, in fact one fraction of coverage and one multiplication suffice.)

Note. Since the coverage fractions only depend on the pixels and the stripes, the measurements in the same direction can, if so desired, share the second phase: for each stripe the contributions from the individual measurements are added and this sum is multiplied by the coverage fractions. This reduces the amount of computation per pixel by a factor M (= the number of rays in each direction). Depending on the type of scanner, collecting the measurements in the same direction may require a considerable amount of high-speed storage. (End of Note.)

Our next purpose is to choose the pixels so as to exploit the rotational symmetry of the measuring device. To this end the pixels are arranged in concentric rings with N/k equal pixels in each ring. In the outermost rings the required resolution implies a small value for k, 3 say. The smaller the ring, the larger the value for k that the resolution allows; note, however, that k is restricted to the divisors of N.

Finally we decide to use the same stripe pattern for all directions. All through the image construction, the stripe pattern has N different positions relative to the image, and hence relative to each ring. A ring with N/k (equal!) pixels and the same ring after a rotation of k steps—i.e. a rotation over 2π k/N— are, however, congruent. In a ring with N/k pixels, the same coverage fractions therefore reappear after a rotation of k steps, but shifted over one pixel. Hence the total number of converage fractions pertaining to the pixels of a single ring is of order N.

A ring of N/k pixels is taken care of by a cyclic arrangement of N/k computational elements, called “nodes”, with a node for each pixel. In the ring, the node/pixel correspondence is, however, not constant. After a rotation of k steps, the pixel values are cyclically transferred to the next node in the cycle. (The direction in which pixel values are transferred is opposite to the direction of the rotation of the rays through the specimen.) In other words, with respect to the pixels the cycle of nodes acts as a —possibly two-way— cyclic shift register.

The arrangement has two important consequences. To each node belong precisely k (sets of) coverage fractions, corresponding to k successive directions, and to each node pertain only a few fixed stripes. The ring has —at least conceptually— a phase counter q ; at each rotation over 2π/N, q is stepped up or down mod K by 1 . At its transition between 0 and k–1 the pixel values are shifted (in the appropriate direction) to the next node. In actual fact, the value q is duplicated so that under control of it each node can select the appropriate set of coverage fractions. Thus we have achieved the distribution of the main computation over a sparsely connected network of nodes with modest traffic between them.

Intentionally we have not called our nodes “microprocessors”, since a single microprocessor might take care of a number of nodes corresponding to a number of adjacent pixels. The pixels may also be taken from adjacent rings; if these rings have the same number of pixels —i.e. the same value for k — the cyclic traffic between microprocessors can be smoothed by choosing a homo- geneous distribution of their phases. It should be stressed that neither the decision what phase to assign to a ring nor the decision which nodes to combine in the same microprocessor affects in any way the freedom of choosing the pixels for the discretization of the circular domain. The only two constraints for that discretization are, firstly, that in each ring the number of pixels is a divisor of N and, secondly, that all pixels in the same ring are congruent.

(I invented the above design while explaining the problem at a privatissimum —known as “The Tuesday Afternoon Club”— ; the above description is a joint effort of drs.A.J.M. van Gasteren and me.)

11 February 1982
prof.dr.Edsger W.Dijkstra,
Burroughs Research Fellow/
Buitengewoon Hoogleraar THE,
Plataanstraat 5
5671 AL NUENEN

Transcribed by Hamilton Richards
Revised 06-May-2016

AvG18/EWD811

An alternative ending for AvG16/EWD809

(Early comments from W.H.J.Feijen and from C.S.Scholten have suggested further disentanglement of smoothsort’s presentation.)

In smoothsort the descending tree covering the unsorted prefix is a so-called "leftward tree", i.e. a tree in which each son is situated to the left of its father. As a result, the rightmost element of the unsorted prefix is the root of the tree and hence dominates all other elements of the unsorted prefix. Note that the leftward trees are the only ones permissible under the constraint that smoothsort leaves an initially increasing sequence unchanged all through the computation. This constraint is strongly suggested by the aim that smoothsort be best-case of order N ; in a moment we shall encounter a further consequence of that aim.

Its rightmost element dominating all its others, the unsorted prefix can be shortened by one element without violation of P4. In contrast to heapsort’s tree, which is pruned leaf by leaf, smoothsort’s tree is pruned in the second phase at its root: it becomes a forest of as many trees can be made into a single descending leftward tree by grafting the one with the leftmost root upon the root of the other (sift being applied in circumstance c); hence the forest can be rebuilt —possibly in many ways— into a single descending leftward tree.

In smoothsort this freedom is exploited to bound the maximum number of sons with the same father, because such an upper bound is a sufficient condition for the number of comparisons to be of order N·log N in the worst case and of order N in the best case. In smoothsort each father has in fact at most 3 sons. In order to maintain that state of affairs, of the trees of the aforementioned forest only the tree with the lefmost root may have nodes with as many as three sons: by grafting in the order from left to right upon the remaining roots no father with more than 3 sons is introduced. The requirement that no different forest ever emerges implies that all fathers with three sons are on the leftmost path from the root of the covering leftward tree and that the unordered prefix itself is that tree’s postorder traversal. (The postorder traversals of its first-generation subtrees followed by its root.)

As a result we can —and shall do so in the sequel— view the unsorted prefix as the concatenation of the postorder traversals of one or more binary trees such that, firstly, in each binary tree each father dominates its offspring and, secondly, the roots of the binary trees are ascending in the order in which they occur.

In contrast to heapsort, which permanently uses (part of) the same simple tree, smoothsort has to keep track of the shape of a changing tree, i.e. it has to keep track of the sequence of binary trees whose concatenated postorder traversals form the unordered prefix. The sequence has to be such that the clerical labour involved herein can also be of order N in the best case.

To this purpose, the binary trees admitted are the so-called Leonardo trees LTi: LT0 and LT1, both consist of a single leaf, LTi+2 has LTi+1 as its left subtree and LTi as its right subtree. The concatenation is a so-called standard concatenation, i.e. it consists of the postorder traversal of the largest possible Leonardo tree, followed by the standard concatenation for the remainder of the unsorted prefix. Thus we achieve that the unsorted prefix is covered by the minimum number of Leonardo trees. (Leonardo trees have been preferred to balanced binary trees because, on the average, 25% more trees are needed for coverage by the latter.)

As in heapsort, smoothsort’s second phase —in which the sorted sequence is built up from the right— is preceded by a first phase in which the unsorted prefix of length N (i.e. covering the whole sequence) is prepared. In contrast to heapsort, this preparation starts from the left; q —in the first phase the length of the prepared prefix— is initialized at 1 and repeatedly increased by 1 until q = N.

The first phase’s main task is to see to it that at each increase of q the Leonardo trees covering the prefix are such that each (binary) father dominates its (binary) offspring. There are two cases. If increasing q by 1 boils down to extending the standard concatenation by a one-node Leonardo tree, this obligation is empty; otherwise LTi+1 , LTi , and the new element are combined into LTi+2 , to whose root sift is applied (circumstance b).

The first phase’s second obligation is to insert a grafting operation (circumstance c) each time a Leonardo tree is formed that will not subsequently be absorbed in a larger Leonardo tree; as a result, at the end of the first phase the roots of the binary trees are in ascending order.

In order to arrive at an algorithm of order N in the best case, a stack records which Leonardo trees cover the unsorted prefix. (Because each Leonardo tree occurs at most once in a standard concatenation, a bit stack in fact suffices.)

drs. A.J.M. van Gasteren
BP Venture Research Fellow
Dept. of Mathematics and
     Computing Science
University of Technology
5600 MB EINDHOVEN
The Netherlands

prof.dr.Edsger W. Dijkstra
Burroughs Research Fellow

Plataanstraat 5
5671 AL NUENEN
The Netherlands

Transcribed by Bart Vreugdenhil
Revised 10-Oct-2012

EWD814

A review of a book on PEARL

PEARL: Systematische Darstellung für den Anwender by Axel Kappatsch, Horst Mittendorf, and Peer Rieder. (300p.) —München, Wien: Oldenbourg, 1979.
ISBN 3-486-23021-2

This book’s title says “PEARL: a systematic presentation for the user”, where PEARL is an acronym for “Process and Experiment Automation Real-time Language”. I found it hard to decide which of the two is worse, the book or the language; eventually I decided that the language has won the race: the book is bad, but the language is terrible.

The book has eight chapters: 0. Introductory Example (4p.), 1. Construction of a PEARL Programme (13p.), 2. Data and Data Aggregates (57p.), 3. Communication with Peripheral Equipment (46p.), 4. Specification of the Peripheral Equipment in the SYSTEM Part (69p.), 5. Sequential Control (19p.), 6. Control of Concurrent Activities (19p.), and 7. Message Evaluation as Example of a Complete PEARL Programming System (42+48p.).

It is in all respects a publication from a subculture. The introduction mentions PEARL as an existing object, but neither when, nor by whom it has been designed, and references to the literature are confined to three pages of references to PEARL publications only. Worse, the poor reader has to join the authors midstream. In Chapter 0, the reader has to guess which letter combinations are key words —there are 146 (!) of them— and which are identifiers chosen by the programmer. In Chapter 1 it becomes annoying that the reader is confronted with a text in four different type founts without being told what significance to attach to that difference; similarly, formal syntax is given in an unexplained formalism; scope rules are given a pictorial “explanation”, the interpretation of which is guesswork. The pictorial “explanation” of assignment and dereferencing in Chapter 2 is a similar new mystery. Etc.

PEARL is described in terms of an elaborate private terminology. This was probably unavoidable since PEARL seems to combine the worst of PL/I, ALGOL 68, and three assembler languages. The reader’s life is complicated, firstly, by the absence of an index guiding the reader to the definitions of those private terms —the table of contents is too coarse to take its place— and, secondly, by the fact that many of these definitions are very implicit: a typical usage of the term is supposed to tell the reader what is meant by the term. (E.g. “INV does not belong to the type of an object, but to the access function represented by the identifier, and is therefore referred to as access attribute.” And as far as I could find out, this is supposed to tell us what is meant by “access attributes”.) In actual fact so-called “teaching by example” is a euphemism for not teaching at all.

The last chapter of 42 pages deals with a worked-out example of 28 pages PEARL code, given in a separate appendix. I did not have the courage to follow that example in any detail, since the appendix is a reduced copy of more than 1500 lines of extremely poor lineprinter output. (The manufacturer of that lineprinter has been tactfully left anonymous.)

Sometimes a subculture is an avant-garde; PEARL’s subculture, however, is inbred, old-fashioned, and backward. Its approach to the definition of semantics is entirely operational. For the semantic definition of sequential programming languages the operational approach is very clumsy, but in the case of concurrency it is a disaster. I think it is not only the book that is to be blamed for explaining the language in terms of an implementation —e.g. “the main significance of a module is that it represents a piece of PEARL text that can be compiled separately”—, I fear it is the language itself. Interrupts are primarily a device by means of which a number of sequential processes can share a smaller number of processors. The definition of a language geared to multi-programming should be absolutely neutral with respect to the number of processors that might be available in a specific implementation. In PEARL, however, “INTERRUPT” is one of the 146 key words! Though it is now well-known for more than 15 years, PEARL’s designers evidently did not know that the actual number of processors available is the easiest thing to abstract from. Whenever I see the announcement of a German book on Computing Science, I always wonder why it has been published in German; this time I wondered why it had been published at all. But I found the explanation: the German Federal Government has spent more than 50 million DM. on the development of this “baroque monstrosity” and when mistakes are made on a sufficiently grandiose scale they become by definition a precious achievement. The frequent reference to DIN documents is very telling: it is the n-th confirmation (n large!) that standardisation as primary target is one of the worst possible incentives for language design; with Ada the USA Department of Defense has increased —quite unnecessarily— n still further.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 28 February 1982 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

Transcribed by Bart Vreugdenhil
Revised 20-Feb-2013

EWD818

A nice theorem on monotonic predicate sequences

A predicate sequence Pi (i ≥ 0) such that —denoting universal quantification over all states by square brackets— (Ai : i ≥ 0 : [Pi ⇒ Pi+1]) is called weakening; a predicate sequence Pi (i ≥ 0) such that (Ai : i ≥ 0 : [Pi+1 ⇒ Pi]) is called strengthening. A predicate sequence Pi (i ≥ 0) that is weakening or strengthening is called monotonic.

Theorem For any monotonic predicate sequence Pi (i ≥ 0) we have
  [(Ai : i ≥ 0 : (Ej : j ≥ i : Pj)) = (Ei : i ≥ 0 : (Aj : j ≥ i : Pj))] .

Proof Let Pi (i ≥ 0) be a weakening predicate sequence; we then have for all natural i
(0)  [Pi = (Aj : j ≥ i : Pj)]
(1)  [(Ej : j ≥ i : Pj) = (Ej : j ≥ 0 : Pj)] .
For arbitrary Z we observe

  [Z = (Ai : i ≥ 0 : (Ej : j ≥ i : Pj))]
  = {(1)}
  [Z = (Ai : i ≥ 0 : (Ej : j ≥ 0 : Pj))]
  = {predicate calculus}
  [Z = (Ej : j ≥ 0 : Pj)]
  = {renaming the dummy}
  [Z = (Ei : i ≥ 0 : Pi)]
  = {(0)}
  [Z = (Ei : i ≥ 0 : (Aj : j ≥ i : Pj))]

which proves the theorem for weakening Pi (i ≥ 0).

Let Pi (i ≥ 0) be a strengthening predicate sequence; then the sequence of predicates ¬Pi is weakening and we conclude from the above
  [(Ai : i ≥ 0 : (Ej : j ≥ i : ¬Pj)) = (Ei : i ≥ 0 : (Aj : j ≥ i : ¬Pj))] .
Negating both sides and applying de Morgan yields
  [(Ei : i ≥ 0 : (Aj : j ≥ i : Pj)) = (Ai : i ≥ 0 : (Ej : j ≥ i : Pj))] .
(End of Proof.)

As we see from the proof, the two equal expressions mentioned in the Theorem are for a weakening predicate sequence Pi (i ≥ 0) most simply expressed as (Ei : i ≥ 0 : Pi); for a strengthening predicate sequence Pi (i ≥ 0) they are most simply expressed as (Ai : i ≥ 0 : Pi). These are the forms in which these limits are best known.

*    *

*

C.S. Scholten and I discovered this theorem while working on EWD816. We were slightly amazed that in its full generality the Theorem was new for us, the more so because monotonic predicate sequences occur so frequently and its proof is so simple. (The Theorem, though nice and in a way striking, is definitely not deep.) Hence this note.

Plataanstraat 5
5671 AL NUENEN
The Netherlands 3 April 1982
prof. dr. Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Matthew Hill
revised 11-Nov-2014

EWD819

Mathematical Induction and Computing Science

                Edsger W. Dijkstra
                Burroughs/Eindhoven University of Technology

I would like to use the opportunity of addressing a general mathematical audience to give that audience some feeling for computing science’s mathematical component. The reason is simple. Whenever a new area of human endeavour has been shown to be amenable to mathematical treatment, this has always had its impact on mathematics at large. And when the new demands made on our powers of mathematical reasoning are somehow drastically different from what we were used to, that impact can even be expected to be quite profound.

To avoid misunderstanding, a few introductory remarks first. Each application area of mathematical thought requires for its effective treatment its own mathematical style, its own formalisms and notations, its own peculiar balance between what is explicitly stated and what is implicitly understood and between the application of formal techniques and of common sense. For a new area, neither the appropriate symbolisms not the proper balances are obvious; in practice, consensus is only reached after many, many experiments and is as such a product of time and hard work.

Mathematicians that mainly work in by now well-established areas and were never involved in such struggles tend to take the availability of an adequate style for granted and to equate — in their world not without justification — “convenient” with “conventional”. In this respect, today’s computing scientist could not be more different: he finds that all sorts of mathematical habits, developed in the past for other purposes, are inadequate for his purpose and is forced to the recognition that time-honoured conventions of the mathematical world are often in a very objective sense highly inconvenient. As a result it is not unusual that the computing scientist regards his colleague in more traditional branches of mathematics as conservative beyond redemption, while the latter considers his colleague in computing a dangerous and barbarian radical. Such mutual ill feelings are, however, no more than the predictable outcome of underestimating the differences between the challenges the mathematical computing scientist faces and the challenges we faced before the advent of automatic computers, when, for lack of machines, programming was no problem at all. Let me, therefore, sketch the peculiar nature of the challenge faced by the mathematical computing scientist.

Programs are written in a programming language, which by the very fact of its mechanical interpretation represents a formal system of some sort. Each program text is a formula. It represents, to be precise, a predicate on the Cartesian product of the so-called initial state space and the final state space. Formally deriving a program from its specifications or proving the equivalence of two programs is no more and no less than a particular form of predicate calculus. I said “particular form of predicate calculus” because a predicate expression has to satisfy some criteria of constructiveness if it is to allow the interpretation of automatically executable code.

With the interpretation of a program text as a predicate expression we are at least conceptually on more or less familiar grounds. I said “more or less familiar” since it is my impression that the average mathematician knows of the existence of this classical predicate calculus but rarely uses it. This is in sharp contrast with the computing scientist, for whom the predicate calculus has become an indispensable tool for his daily reasoning. I said that the grounds were “at least conceptually” familiar: they are familiar to the extent that the average mathematician feels quite at home with the idea of manipulating formal expressions provided those expressions are not too big, say up to a few lines. But programs of a few hundred lines are not unusual at all. It is this scaling up that profoundly changes the rules of the game: any child can control a bicycle but you need a professional pilot to fly a supersonic plane. For cyclist and pilot, the laws of mechanics are the same, yet the conventional cyclist’s wisdom is of no great relevance in the cockpit.

*                       *
*

I have chosen to talk about mathematical induction since that is the indispensable tool for arguing about recursively defined structures and recursive definitions pervade all of computing science. It already starts with the definition of the syntax of our programming languages. The usual form is BNF (“Backus-Naur-Form”). After the definition of digits

<digit> ∷= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

the syntax of unsigned integers is given by

<unsigned integer> ∷= <digit>
         | <unsigned integer><digit>

— in words: an unsigned integer is a single digit or an unsigned integer followed by a digit — and after the definition of what letters are, identifiers are defined by

<identifier> ∷= <letter>
         | <identifier><letter> | <identifier><digit>

An example of a more complicated recursive definition would be the following definition of expressions

<addop> ∷= + | -

<expression> ∷= <product> | <addop><product>
         | <expression><addop><product>

<multop> ∷= * | /

<product> ∷= <factor>
         | <product><multop><factor>

<factor> ∷= <unsigned integer> | <identifier>
         | (<expression>)

The way in which in its last line parentheses are introduced illustrates the mechanism of the recursive definition in its full glory.

*                       *
*

The most common formulation of mathematical induction is: from
(the base)       P0
(the step)       (An : n ≥ 0 : Pn ⇒ P(n+1))
follows           (An : n ≥ 0 : Pn)

Other formulations of the step are

(An : n > 0 : P(n-1) ⇒ Pn)

and

(An : n > 0 : ¬P(n-1) ⋁ Pn)

Next we have the “course-of-values induction” — usually derived from the former formulation — : from
(the base)       P0
(the step)       (An : n > 0 : (Ai : 0 ≤ i < n : Pi) ⇒ Pn)
follows           (An : n ≥ 0 : Pn)      ,

with “infinite regress” as notational variant for the step:

(An : n > 0 : ¬Pn ⇒ (Ei : 0 ≤ i < n : ¬Pi)) .

A more modern formulation is

(An : n ≥ 0 : Pn) =
(An : n ≥ 0 : Pn ⋁ (Ei : 0 ≤ i < n : ¬Pi))

Note that
0) by expressing the implications as a disjunction, we made the difference between “course-of-values induction” and “infinite regress” — a notational artefact! — disappear;
1) the base has been subsumed in the step;
2) the whole statement is not one of implication but of equality of predicates.

But let us now depart from the natural numbers. Let us introduce the following nomenclature:
(U, <) is a partially ordered set
x,y are elements from U
S is a subset from U
P is a total predicate on U, where S and P are coupled by

Px = ¬(x ∈ S)     or     S = { x | ¬Px }     ,

where we have for each pair S,P :

(S = 0) = (Ay : y ∈ U : Py) .

“y is a minimal element of S” means

(y ∈ S) ⋀ (Ax : x < y : ¬(x ∈ S)) .

“U is well-founded” means that each non-empty subset of U contains a minimal element.

“U is well-founded”
= (AS ∷ (S ≠ 0 ) =
         (Ey : y ∈ U : y ∈ S ⋀ (Ax : x < y : ¬(x ∈ S))))
= (AS ∷ (S = 0 ) =
         (Ay : y ∈ U : ¬(y ∈ S) ⋁ (Ex : x < y : ¬(x ∈ S))))
= (AP ∷ (Ay : y ∈ U : Py) =
         (Ay : y ∈ U : Py ⋁ (Ex : x < y : ¬Px)))

From the above we conclude that well-foundedness is exactly the same thing as validity of a proof by mathematical induction.

A “decreasing chain” is a sequence x₀, x₁, x₂, ... of elements such that     (Ai,j : 0 ≤ i < j : xj < xi) .
“U is well-founded” = “all decreasing chains in U are of finite length”.

Proof. With the predicate DCF defined by

DCF y = “all decreasing chains of which y is the first element are of finite length”,

we have to prove

“U is well-founded” = (Ay : y ∈ U : DCF y)

Assume the left-hand side true; then the right-hand side equals

(Ay : y ∈ U : DCF y ⋁ (Ex : x < y : ¬DCF y))      ,

which is evidently true.

Assume the left-hand side false; then there exists a non-empty S such that it has no minimal element, i.e.

(Ay : y ∈ S : (Ex : x < y : x ∈ S))

from which the falsity of the right-hand side is evident.
(End of Proof.)

The above theorem shows the extremely close connection between well-foundedness and proofs of termination of a program. Let U be the state space of the computations, and let x < y mean that x is a possible successor state of state y. Each computation then corresponds to a decreasing chain and “all computations terminate” means that all those decreasing chains are finite, i.e. that the successor relation turns U into a well-founded set. Note that we have used equalities all over the place: terminating computations, well-founded sets, and the validity of inductive arguments are three faces of the same coin.

As a result, computing science has a vivid interest in well-founded sets and their construction. Lexicographic pairing is a beloved construction. If U and V — with general elements u and v respectively — are well-founded, their Cartesian product U × V is also well-founded under the ordering defined by

(u₀ v₀) < (u₁ v₁) = u₀ < u₁ ⋁ ((u₀ = u₁) ⋀ v₀ < v₁)      .

Lexicographic pairing has the further advantage of being associative. It is total iff (if and only if) the component orderings are total.

Proving properties of all sentences of a programming language is done by “induction over the syntax”. This is most elegantly done by introducing a partial order on strings: x < y means that string x occurs as syntactical component of string y; this partial order is, however, easily embedded in a total order, viz. string length. But sometimes we have to carry out inductive arguments over essentially only partially ordered sets, e.g. when the order relation is “earlier in time”, but we are dealing with a network in which events in distinct components are essentially unordered for lack of communication facilities between such components, and the lacking possibility of synchronization is at the heart of the problem to be solved.

Nuenen, 4 April 1982

transcribed by Jonathan David Arndt
revised 04-Jan-2021

EWD821

From predicate transformers to predicates

Dedicated to the Tuesday Afternoon Club to C.A.R. Hoare at the occasion of his being elected Fellow of the Royal Society.

Lemma 0. For any statement S and any constant predicate C

wp(S, C) = wp(S, T) ∧ C .

Proof. By substituting for C the two constant predicates T and F, respectively. (End of Proof.)

Lemma 1. For any statement S, any predicate R, and any constant predicate C

wp(S, R ∨ C) = wp(S, R) ∨ wp(S, C) .

Proof. By substituting for C the two constant predicates T and F, respectively. (End of Proof.)

In the following, P is a predicate in x and by definition P′ = Px′x ; variables x and x′ range over the same non-empty domain.

Lemma 2. For any predicate P in x we have for all x

P = (Ax′ :: x ≠ x′ ∨ P′) .

Proof. P = (Ax′ :: P) = (Ax′ : x′ = x : P′) = (Ax′ :: x ≠ x′ ∨ P′). (End of Proof.)

Theorem. For any statement S with state space x and any predicate P we have

wp(S, P) = wp(S, T) ∧ (Ax′ :: wp(S, x ≠ x′) ∨ P′) .

Proof.  wp(S, P)
  = { Lemma 2 }
   wp(S, (Ax′ :: x ≠ x′ ∨ P′))
  = { distributivity of wp over universal quantification }
   (Ax′ :: wp(S, x ≠ x′ ∨ P′))
  = { Lemma 1 }
   (Ax′ :: wp(S, x ≠ x′) ∨ wp(S, P′))
  = { Lemma 0 }
   (Ax′ :: wp(S, x ≠ x′) ∨ wp(S, T) ∧ P′)
  = { wp(S, R) ⇒ wp(S, T) }
   wp(S, T) ∧ (Ax′ :: wp(S, x ≠ x′) ∨ P′) .
(End of Proof.)

Hence, the predicate transformer wp(S, ?) is fully characterized by the two predicates wp(S, T) and wp(S, x ≠ x′) .

20 April 1982

Edsger W. Dijkstra
Martin Rem
Ronald W. Bulterman
Jan L.A. van de Snepscheut
W.H.J. Feijen
Frans Peters
Jan Tijmen Udding
Jo Ebergen
A.J.M. van Gasteren
Maarten Boasson

transcribed by Matthew Hill
revised 11-Nov-2014

EWD824-0

Linearization of a two-dimensional search

Let the integer pair (xi, yi) be denoted by Pi. Let of a finite number of such pairs all xi be distinct and let all yi be distinct. Let the pairs be partially ordered by Pi < Pj, defined by

Pi < Pj  =  xi < xj  ∧ yi < yj

Pj is a minimal element means ¬(E i :: Pi < Pj), and it is requested to find the minimal elements. We rewrite the condition of minimality for Pj

    ¬(E i :: Pi < Pj)
=  ¬(E i : xi < xj : yi < yj)
=  (A i : xi < xj : yi ≥ yj)

Under the assumption that the pairs have been numbered in the order of increasing x, the above reduces to

(A i : i < j : yi ≥ yj)  or  (A i : i < j : yi > yj) .

In other words: scanning the y's in the order of increasing x yields a new minimal pair each time we encounter a y smaller than we have encountered so far.

Since sorting can be done in N ∙ log N steps, we have an N ∙ log N algorithm. The solution is worth noting because I could not achieve that result --to my great regret-- without destroying the symmetry between the x's and the y's. The above was triggered by a reconsideration of the longest upsequence problem.

Burroughs Corporation
12201 Technology Blvd.
AUSTIN, Texas 78759
USA

25 May 1982
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Sat, 20 Sep 2003.

  EWD 826

Trip report E.W.Dijkstra, USA, 20 May 1982 – 14 June 1982

On Ascension Day I left my country with flight KL641, and until New York all went well. The delay at immigration/customs at JFK was considerable; in addition the customs officer taught me how rude, impolite, and unhelpful New Yorkers can be. It was so late that the "Interline Luggage Transfer" in the customs area no longer accepted my suitcase for the flight to Boston. The coach was too crowded. I had to walk to the TWA domestic terminal as fast as I could. Usually I travel light, but this time I was carrying books and the walk was no fun. At my destination I fell —I had nearly exhausted myself— but I broke nothing and just caught my connection.

Still panting I sank in the cushions of my seat, but though the flying time to Boston is only 35 minutes, I had plenty of time for recovery: it was more than 2½ hours later when I arrived in Boston. First we had to wait until a thunderstorm had passed, but then the captain announced that he could not get the nr. 1 engine going; after replacement of its start motor we took off. So much for TWA's preventive maintenance. During the 2½ hours we were offered 1 glass of 7-up.(After arrival the stewardess told us that she hoped we had enjoyed our flight and that it had been a pleasure to serve us!)

At Logan Airport I was collected by the Boston Chapter of the ACM in the person of Jacqueline Masloff who took me to the Marriott Hotel in Newton. After I had checked in she told me that she would be back Saturday morning at 8 a.m. and left. That Saturday I had to give a one-day seminar for the Boston Chapter.

The famous slogan "There is no place like Hilton" evokes with me the reaction "Thank goodness!". The Marriott Hotel taught that Hilton's slogan is a lie: until well past midnight the "live entertainment" in the bar vibrates in your room. (And for all that vulgarity one has to pay more than $100 per night!) Fortunately I was so tired I did not suffer too much.

The next day I wrote a letter before breakfast. After breakfast I established by telephone —50ct. per local call!— that there was no point in visiting Harvard: Michael O. Rabin was in Israel and Tom Cheatham left at noon for a trip. So I went to MIT.

After lunch I interrupted my visit to MIT to fulfill my moral duties towards The American Academy of Arts and Sciences. At the occasion of the opening of its new home it had asked all its Fellows and its Foreign Honorary Members to offer copies of their works for its new library. The new home of the AAAS surprised me: I had only read about it in terms of architectural superlatives, but once in the building I realized that the superlatives were deserved! I was received by a charming lady, who told me that she was particularly touched by my attention because Dutch members were so rare; I was glad to be able to offer, besides the books you can still buy, a copy of my thesis, which by now is a collector's item. (This is independent of the fact that it is by far the most boring thing I ever wrote.) We drank tea, I dedicated my gifts, was pleased to see "Elements of Style" by Strunk and White on the shelves and returned to MIT (with a markedly lighter briefcase).

I had hoped to meet Joe Stoy (of Oxford), who is visiting MIT this year, but he was not in and I could not get him on the phone since his line was engaged. Telling Corbató that I feared that Joe was sitting at his terminal in his home, Corbató typed in a message, which evidently appeared on Joe's screen, for a few minutes later Joe called. It was a nice demonstration of how technology can undo some of its own harm. Corbató being Joe's neighbour, he was glad to offer me a lift to Joe's home at the end of the day. I had a nice evening with Joe and Gabrielle Stoy, who lived near my hotel. I went to bed at half past ten.

Having to perform the whole day, I took only a light breakfast on Saturday morning. I was collected at 8:03 and after a half-hour drive we were at the college in whose auditorium the seminar was organized. I had a reasonable blackboard, but very little chalk and three whiteboards on which it is hard to write big enough for an audience of 170. The sound system was excellent. The morning session lasted from 9:00 till 12:20 with a fifteen-minutes break; the afternoon session was from 14:00 till 17:15, again with a 15-minutes break. (I spent those breaks signing copies of my book.) Lunch was very substantial and in view of the fact that at least one person had to stay awake, I skipped it.

It was a very nice audience to work with. In my opening address I had asked them to regulate the speed of my presentation, and they did so admirably for the rest of the day. The last 45 minutes were devoted to discussion; I got no silly questions! In my innocence I had thought that the day would end with a dinner with the organizers, but all the officials of the Boston ACM Chapter left, with the exception of Jacqueline Masloff and her boyfriend, who asked where I would like to be dropped. I was dropped at the home of Barbara Liskov who gave an end-of semester party to some colleagues and a number of graduate students. There was food as well.

The next morning Marriott's restaurant was too crowded to get a breakfast, but John Guttag came to fetch me around 11:45. In his home I had an excellent breakfast while he and Olga were having lunch. At 15:00, he drove me to the airport.

MIT used to be very much technology-driven and absorbed in systems of its own making. I was therefore not amazed when, upon my arrival at the 5th floor of 545 Technology Square I witnessed a heated discussion about blanks in column 1. When none of those students could tell me where Joe Soy's office was, I was amazed. ("If he is in Theory he must be on floor 8." After nine months they were still unaware of his presence! He had his room on the same floor as they, but at the other side of the elevators. So much for intellectual parochialism.) When, one hour later, I observed that they were still discussing blanks in column 1, I got very depressed. Later I learned that the "systems" subculture is generally regarded as a relic from the sixties, kept alive by some of the ageing faculty but no longer an attraction for the brighter students, who prefer a more scientific approach to computing. So there is a little hope for the Department —not much, for at the same time it is being snowed under by equipment.

On Sunday evening I arrived half an hour late in Austin, where I was met at the airport by my host, dr. Hamilton Richards Jr, of Burroughs Corporation. We rented a car from National, which could provide me with an American Rabbit with a four-speed stick shift. I preferred that over the originally reserved Toyota (which, of course, was already a great improvement over last year's pimpmobile). The Rabbit was more expensive than the Toyota, but I don't think that by selecting a Rabbit I can be accused of extravagance.

The next five days I went to the lab. On Tuesday evening I attended a party given in a large 100-years old house. I guess it is called "colonial style": large rooms, high ceilings and all wood. The acoustics were so marvellous that I played for almost an hour Mozart sonatas on a Steinway. On Wednesday and on Friday, K. Mani Chandi and Jayadev Misra from the University of Texas collected me around noon for lunch, after which they took me to the University. On Wednesday we discussed my recent work, on Friday theirs. We started working together and I probably showed them the way in which a hunch of theirs can be turned into a certainty. They had a beautiful paradigm to start with. At the lab I lectured and started to collect programs with the intention of studying their structure, their development, and their presentation. My first observations have strengthened my prejudices against terminals: absence of helpful and relevant comments was explained by "if I had added comments, it would not have fitted on the screen".

Because of Memorial Day we had a long weekend. My host and his family had gone to the coast; I stayed in his home and fed his fish and his cats. And I wrote about 10.000 words. On Saturday evening I had dinner with Misra, Chandy, Boyer, Moore, and their wives.

It had been warm when I arrived in Austin, but now it became really hot and humid. As a result my wrist began to hurt and writing was often painful. During my second week at the lab I devoted a larger fraction of my time to learning what people were doing. It was instructive and became very interesting when Mark Scheevel carried out as number of small experiments on my behalf.

One of the things I learned from those experiments was that in combination with lazy evaluation the dichotomy of "strict" versus "nonstrict" is really much too coarse. (I learned this the hard way when, to my great surprise, the interpreter refused one of my programs.)

During my second week in Austin I wrote EWD827. On the one hand it was a standard exercise: prove p=q by showing that p satisfies the defining equation for q. The defining equations for p and q were, however, of so different a structure that the exercise was not completely trivial. The example being very simple, that nontriviality came somewhat as a surprise.

I had cooked up that example on the preceding Friday afternoon during an informal discussion about recursion equations that took place at South West Texas State University, just before I gave a lecture there. I had to decline the invitation for dinner after my lecture for, that evening, my host had arranged my farewell party in Austin.

On Wednesday afternoon I flew to Los Angeles with Continental. Its magazine contained an article about the explosion in the number of vice-presidents in American business, in particular in the world of finance. And, sure enough, two days later I saw an office of a bank equipped with an "assistant vice-president".

All of Thursday I spent at CalTech, discussing recent work and the problem of finding competent faculty. I ended that day by giving a lecture. Earlier that afternoon the review of the so-called Silicon Structures Project by its sponsors had ended, and as a result of that coincidence I had representatives of a number of those sponsors in my audience, which was nice because my topic was most appropriate for such an audience.

After lunch I heard the sponsors' reactions to what they had seen of SSP. They were sobering. During the last year the main emphasis of the project had changed from "correctness by construction" to the more traditional approaches of "simulation", "line extraction", etc. My impression was that during the last year the project had sunk a good deal towards the average level of inadequate engineering. But the sponsors now felt much more "at home" with the project! It was frightening. It is well-known that the scope of the technical problems faced by industry are, in general, underestimated on the Campus; it now seemed that in industry itself that scope is still more seriously underestimated.

I was struck that evening by an Editorial Commentary by Paul Davis in the March 1982 issue of SIAM News: "The decline in math skills is no longer a joking matter", of which Alain Martin handed me a copy. I quote

"Japanese industry is now turning its attention to computing software, firmware, and hardware. If they deliver it as well constructed as their cameras and their cars, we will soon lose control of industrial process control, small business applications, local communication networks, and a multitude of other small machine and chip applications. If the newspaper and trade journal accounts of samurai software are accurate, reliability and precision will triumph.

Part of our country's vulnerability to such an assault lies in our failure to teach habits of precise thought and analysis. We are graduating too many sloppy scientists and engineers, and the fault lies in large measure in the decline of the quality and quantity of mathematics instruction at all levels, grade one through post-graduate."

I was struck, but not amazed. I had read (in the International Herald Tribune, May 20, 1982) the article by Paul DeHard Hurt (of Stanford) with the somewhat catchy title "America's Schools Are Flunking Science and Technology". He compares science and mathematics education in the United States with that in the Soviet Union, East Germany, China and Japan, and the numbers he gives speak for themselves.

I did not know how closely connected CalTech itself is connected to the "brain drain": a first count showed that between 40 and 50% of its faculty are of foreign origin and has received a major part of its higher education abroad. I knew that the brain drain has caused very uneasy feelings in the countries drained: they felt they were losing their best people. I now sense that it also causes uneasy feelings in the draining country: there is the worry that the American educational system is not self supporting. Life is very difficult.

*                     *
*

After the above had been written I saw (also from SIAM) a commentary by Derek C. Bok on current federal policy towards the NSF. I quote:

"Too few of us realize how much of the success of American science has depended on the wealth of outstanding talent that came to us from Europe during the decades that surrounded World War II. Today that source of talent has largely disappeared. If we cannot replace it with exceptional, young investigators of our own, the quality of our universities and the vitality of our scientific work is bound to diminish."

That is a very explicit expression of the worry I had sensed.

*                     *
*

On Saturday afternoon I made my ritual visit to Huntingdon's Desert Garden, where the cactuses impressed me as much as ever. If you are ever in Pasadena, don't miss it! It is of an absolutely unique, impressive beauty.

On Sunday I prepared my departure. With KL602 Martin Rem and I left Los Angeles in the evening for Amsterdam, where we arrived the next day at 16:00. In Pasadena's cooler climate the pain in my wrist had already begun to subside, and in the Netherlands I was glad to observe that the heatwave, of which we had heard, was over. At 19:00 I was home, at 20:30 in bed. I slept until noon.

*                     *
*

I found my fear confirmed that in the West, Artificial Intelligence would be taken more seriously since the Japanese seemed to do so. A series of three articles on "Thinking Machines" (by Tom Alexander) has recently appeared in "Fortune". They were shown to me by Professor Jayadev Misra, and I shared his sense of alarm about this symptom.

Stronger than at previous occasions, it seemed to me, the use of computing equipment is regarded as a condition for progress and the use of more equipment as a sign of more progress. A remark by Misra about the quality of the Department of Computer Science at Austin encountered strong disbelief from the side of a colleague (of the Department of Electrical Engineering): impossible, for the Austin Department had only 1 VAX, whereas Stanford had 15! The recent books by Gries and Reynolds have been criticized —be it in a rather unfair review— for their "non-technological" or "anti-technological" view of programming, i.e. for their lack of attention paid to "modern" —i.e mechanized— verification; proof systems are discussed "but not in a realistic or useful fashion". (The reviewer has a vested interest in mechanical program verification.) In the review of the Silicon Structures Project all the sponsors praised the project for the development of the graphics! (Here, however, I heard one rare critical note: one of the sponsors had asked himself whether the project dealt with the design of chips or with the design of posters.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 16 June 1982 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Tue, 17 Nov 2009

EWD827

A very simple exercise in SASL

  The idea is to prove the equality of two recursively defined infinite sequences by showing that the one satisfies the defining equation of the other. Here we shall try this out on the simplest example I can think of.

  Let us consider the equations

(0) | from n = n : from (n+1)
(1a) | inc(a:b) = a+1 : inc b
(1b) | x = 0 : inc x .

We have to prove x = from 0 . We observe

(2) |      (incn x = n : incn+1 x )
| ⇒    { inc is a function }
|      (inc(incn x ) = inc (n : incn+1 x ))
| =    { 1a }
|      (inc(incn x) = n +1 : inc(incn+1 x ))
| =    { def. of iterated functional composition }
(3) |      (incn+1 x = n+1 : incn+2 x )

With (2)⇒(3) providing the induction step and —since    x = inc0 x    by the definition of iterated functional definition— (1b) providing the base, (2) has been proved for all n. Since (2) is the same equation in    incn x    as (0) is in from   n   ,   incn x = from n   has been established for all n, in particular for n=0  , which completes the proof.

*                *
*

  I tried it the other way round , viz. I tried to show that from 0 was a solution of (1b), but this became a mess.
It is too warm and too humid to write much more now.

Burroughs | 6 June 1982
12201 Technology Blvd. | prof.dr.Edsger W.Dijkstra
AUSTIN, Texas, 78759 | Burroughs Research Fellow
USA |

transcribed by Germán González-Morris
revised Sun, 26 Dec 2010

EWD829

Titel: | De software crisis, ontstaan en hardnekkigheid.
Spreker: | prof.dr.Edsger W.Dijkstra Burroughs Corporation/ Technische Hogeschool Eindhoven

Samenvatting:

Het ontstaan van de software crisis is een direct gevolg van de onderschatting van het revolutionaire karakter van de moderne computer, welks programmeeropgave ons confronteert met een intellectuele uitdaging zonder precedent. De ontwikkeling van een feilloos programma van behoorlijke omvang is een opgave waarvan de moeilijkheidsgraad aanvankelijk schromelijk is onderschat; het voortduren van de software crisis is grotendeels te wijten aan het feit dat deze moeilijkheidsgraad over het algemeen tot op de huidige dag ontkend wordt. Op de achtergrond van deze ontkenning zal nader worden ingegaan.

De software crisis, ontstaan en hardnekkigheid

Edsger W.Dijkstra
Burroughs Corporation/
Technische Hogeschool Eindhoven

Officieel bestaat de software crisis sinds october 1968; toen werd zijn bestaan namelijk openlijk toegegeven op de NATO Conferentie over "Software Engineering" die te Garmisch-Partenkirchen gehouden werd. Maar hij bestond natuurlijk al veel langer, want anders was die conferentie toen nooit georganiseerd. En in het jaar onzes Heren 1982 bestaat hij nog steeds, want anders was deze ASI leergang er niet aan gewijd. En dat de software crisis nog wel een tijdje zal voortduren is niet een gewaagde voorspelling. Deze voordracht zal hoofdzakelijk gewijd zijn aan zijn ontstaan en zijn hardnekkigheid.

Op de vraag "Hoe is de software crisis ontstaan?" is een heel makkelijk antwoord te geven. Waarom mislukken zoveel softwareprojecten? Heel eenvoudig: omdat programmeren blijkbaar iedere keer weer veel moeilijker is dan wij denken. Dit onontkoombare antwoord is evenwel te makkelijk, want het roept onmiddellijk de vraag op hoe de blijkbaar schromelijke onderschatting van de moeilijkheidsgraad van de programmeeropgave heeft kunnen ontstaan en blijkbaar zo'n taai leven kan hebben.

Voor de aanvankelijke onderschatting van de moeilijkheidsgraad van de programmeeropgave is een heel duidelijke verklaring; zij bestaat uit twee gedeelten. Ten eerste eiste in de beginjaren de constructie van betrouwbare hardware alle aandacht op. De electronica betrad het onontgonnen terrein van de digitale techniek, daarbij tegelijkertijd geconfronteerd met een schaalvergroting zonder precedent en ongehoorde betrouwbaarheidseisen. Aan hardwareproblemen hadden we toen echt onze handen meer dan vol en de waarschuwing dat, als de machine eenmaal werkte, het gebruik niet triviaal zou zijn was het laatste, waar we behoefte aan hadden. Als de waarschuwing geuit werd —en dat werd hij wel— , werd hij niet gehoord. Dit is maar al te begrijpelijk: het was immers niet de eerste zorg.

Ten tweede werd de waarschuwing slechts schuchter gegeven, niet alleen omdat er veel moed voor nodig is om een impopulaire boodschap van de daken te schreeuwen, maar ook omdat de feitelijke ervaring, die de waarschuwing zou moeten schragen, nog ontbrak. We wisten dat het eerst ontwikkelde programma —voor het genereren van een tabel van quadraten— meteen had gewerkt; we wisten ook dat het tweede programma —voor het genereren van een tabel van priemgetallen— dat tot ontnuchtering van zijn auteurs niet had gedaan. Maar met die ervaring ontmoedig je niet een hoopvolle mensheid. Het was pas hun tweede programma, die kerels hadden toch nog geen enkele ervaring, en, bovendien, wie is er nou in priemgetallen geinteresseerd? Het punt is, dat automatische rekenmachines toen inderdaad artefacten zonder enig precedent waren en dat de programmeeropgave inderdaad eisen aan ons intellect stelt, die er nog nooit aan waren gesteld. Zonder eerder aan een dergelijke discontinuiteit te zijn blootgesteld is het inderdaad heel moeilijk voorstelbaar dat iets, dat toch doenbaar moet zijn, onvoorstelbaar moeilijk uitpakt. We kunnen het naiveteit noemen, onschuld klinkt vriendelijker, maar over de aanvankelijke onderschatting hoeven we ons niet te verbazen.

Boeiender is de vraag, hoe het mogelijk is geweest, dat deze onderschatting zo'n taai leven leidt. Langzamerhand is er meer dan een kwart eeuw overweldigende experimentele ervaring dat programmeren op zijn zachtst gezegd een uiterst verraderlijke activiteit is, zo verraderlijk dat hij de inzet van ons beste intellect rechtvaardigt. Maar de onderschatting duurt voort tot op de huidige dag. Deze ASI leergang is er een symptoom van: bij de voorbereidende sprekersbijeenkomst legde de secretaris, Mr. W.L. den Dekker, uit dat het traditioneel technisch/wetenschappelijke accent van dit soort leergangen dit maal "in verband met het onderwerp natuurlijk minder geprononceerd zou zijn". Een verklaring van het taaie leven van de onderschatting is ingewikkelder: een aantal oorspronkelijk onafhankelijke oorzaken blijkt elkaar wederzijds te versterken.

Het staat buiten kijf dat, toen het phenomeen computer zich kort na de tweede wereldoorlog aandiende, de internationale wiskundige wereld er niet rijp voor was. Traditioneel bestaat die wereld uit twee continenten, namelijk het wiskundig werelddeel dat zich bezighoudt met de problemen van het continuum en het deel dat zich op de discrete problematiek concentreert. Het zo eminent toepasbare werk van Newton, nu zo'n 300 jaar oud, is voor de continue wiskunde een enorme stimulans geweest en bij de stormachtige ontwikkeling van dat deel der wiskunde is de discrete wiskunde ontegenzeggelijk op het tweede plan geraakt. Maar de digitale rekenautomaat manipuleert per definitie nu eenmaal objecten in een discreet universum. Voeg hieraan toe, dat dit universum, hoewel groot, per definitie eindig is, en men kan zich misschien voorstellen dat het merendeel der wiskundigen van die generatie zich gemachtigd voelde het phenomeen computer te negeren: discreet en eindig moest het immers triviaal zijn. Men kan hun deze aanvankelijke beroepsblindheid bijna vergeven. Helaas moeten wij constateren, dat in de daaropvolgende 35 jaar deze beroepsblindheid nauwelijks is afgenomen en dat de wiskundige, die de intellectuele uitdaging van computing science serieus neemt, nog steeds een zeldzaamheid is en dat de gemiddelde wiskundige in bekrompenheid voor zijn nietwiskundige medeburgers niet onderdoet. Overheerst bij wiskundigen eenmaal het gevoel dat computers niet de moeite waard zijn om je mee bezig te houden, dan werkt dat vervolgens als een z.g. "self-fulfilling prophecy": als de intellectueel het best geequipeerden het vak links laten liggen, wordt het gebied bezet door tweede- en derderangs mensen en na enige tijd kan de echt knappe jongen zich nog moeilijker voorstellen dat daar een taak voor hem ligt. Ligt een stuk van de oorzaak van de software crisis bij het feit dat de wiskundige wereld door de bank genomen het gebied heeft veronachtzaamd, het taaie leven van de software crisis is mede het gevolg van het feit dat de wiskundige wereld door de inmiddels ontstane omstandigheden in deze veronachtzaming gesterkt wordt.

Naast deze culturele oorzaak is er ook een economische, die ging spelen op het moment dat Sperry-Rand als eerste rekenmachinefabrikant de UNIVAC als serieproduct op de markt bracht. Die markt moest gecreeerd worden, en die markt is gecreeerd door ondeskundigen, die over voldoende fondsen beschikten, gouden bergen te beloven. De gewenste ondeskundigheid was rijkelijk voorhanden in de top van grote bedrijven, die toen nog over geld beschikten; voor de gouden bergen zorgden de verkoopafdelingen der computerfabrikanten. Termen als "analytical engine", "mathematical machine" en "instrumentelle Mathematik" lieten er geen twijfel over bestaan waar in onze cultuur dit soort apparatuur was ontstaan en waarschijnlijk thuishoorde. Hoe verkoop je het dan een een administrateur? Door met een groots opgezette campagne het wezenlijk wiskundige karakter van de hele gebruiksproblematiek onder tafel te praten, programmeren voor te stellen als iets dat iedereen in een drieweekse cursus kan leren, kortom door zo hardnekking te verklaren dat het goud der beloofde bergen massief is, dat genoeg mensen het geloven. In de jaren die daar op volgden is er voor het vak van programmeur volledig critiekloos geronseld. Hier in den lande was MULO ruimschoots genoeg, maar in andere landen was het geen haar beter. Het resultaat laat zich denken: van de half-millioen professionele programmeurs, die de wereld inmiddels telt is het merendeel van een incompetentie die elke beschrijving tart. Maar hier ligt wel een verklaring van het taaie leven van de software crisis: een incompetent arbeidsleger van een half millioen ververs je niet een-twee-drie.

Heel pessimistische mensen betogen, dat de teerling is geworpen en dat we nooit van de horde incompetente programmeurs verlost zullen worden. Die sombere voorspelling is gebaseerd op de volgende, ongetwijfeld juiste observatie. Om met dit soort personeel er toch nog het minst slechte van te maken heb je veel van dat personeel nodig, dat vervolgens alleen maar werken kan in een organisatie zo strak, en ook zo infantiliserend, dat de mensen die je eigenlijk zou moeten hebben daar niet in passen. De observatie is ongetwijfeld juist; het is ook duidelijk dat het geobserveerde verschijnsel mede voor de taaihaid van het leven van de software crisis verantwoordelijk is. De pessimistische conclusie, dat de software crisis een eeuwig leven beschoren zal zijn lijkt mij evenwel een beetje haastig.

De sterkte van dit pessimisme verschilt van mens tot mens; over het algemeen is het in het bedrijfsleven sterker dan in het onderwijs. Het verschilt ook van land tot land; over het algemeen is het in de Verenigde Staten sterker dan in Europa. Dit laatste is niet verwonderlijk, aangezien de aftakeling van het onderwijs ginds nog verder is voortgeschreden dan hier. Het loont de moeite, daar en passant even de aandacht op te vestigen, omdat onze perceptie van wat de centrale problemen van computing science zijn de neiging heeft sterk beinvloed te worden door de Amerikaanse perceptie daarvan. Bij alle verhalen over de noden van "the casual user" en de intellectuele beperkingen van "the average programmer" moeten wij nimmer vergeten een duidelijk onderscheid te maken tussen enerzijds de intrinsieke problemen van computing science en anderzijds de moeilijkheden veroorzaakt door het falend Amerikaans onderwijsbestel. Van een academicus vanzelfsprekend vergen dat hij zijn moedertaal in woord en geschrift voortreffelijk beheerst en effectief hanteert geldt hier inmiddels als een beetje overdreven, in de Verenigde Staten als absurd en irreeel. Alle Amerikaanse nadruk op "readability", "self-documentation" en soortgelijke, niet nader gespecificeerde deugden wordt daardoor wel begrijpelijk.

Waar het pessimisme overheerst, heeft dat een ongewenst neveneffect. Het leidt er toe, dat de software crisis gezien gaat worden als een ongeneeslijke ziekte, en gelijk wij allen weten is de ongeneeslijke ziekte de bij uitstek vruchtbare bodem voor kwakzalverij. En inderdaad: ik ken geen professie met een zo grote kwakzalverdichtheid als de onze! Dit is een aspect waar ik het merendeel van mijn academische collegae in de Onderafdeling der Wiskunde en Informatica van de Technische Hogeschool te Eindhoven geregeld aan moet herinneren. Het is een verschijnsel, dat zij in hun eigen professie niet meemaken en waarmee zij alleen geconfronteerd worden, wanneer een onderwijskundige hun pad kruist. Maar wie met pek omgaat, wordt er door besmet: je kunt van buitenstaanders nauwelijks verwachten dat zij kaf en koren scheiden, en de hoge kwakzalverdichtheid in onze professie maakt het voor de academische wereld eens zo moeilijk het vak serieus te nemen.

Ligt de schuld van de charlatannerie bij de kwakzalver of bij het publiek dat hij bedot? Wel, als dat publiek bedot wil worden, ligt de schuld dunkt me daar. In het bedrijfsleven is zulks dunkt me het geval. Met heel serieuze bedoelingen karakteriseerde ik enige manieren die bij het orde scheppen in wat anders onbeheerste chaos wordt veelbelovend leken en lanceerde ik termen als "structured programming", "layers of abstraction" en "separation of concerns". In de kortst mogelijke tijd werden niet de bedoelingen, maar wel de kreten gemeengoed en bevond ik me tegen wil en dank ingedeeld bij de goeroes. Als het zelfs de serieuze wetenschapsman zo vergaat, kunt U nagaan hoe moeilijk het is geen kwakzalver te worden.

Het bedrijfsleven is zo wanhopig, dat elke heilsboodschap er in gaat als koek. Aan heilsboodschappen is dan ook geen gebrek. Voor de wanhopige manager is het bijvoorbeeld een ontstellend geruststellende gedachte, dat de gebezigde programmeertaal de bron van al zijn ellende is. De stakker klampt zich vast aan de droom van de programmeertaal, waarin programmeren zo makkelijk is, dat het allemaal vanzelf goedkomt. De nieuwe programmeertalen als panacee gaan in de kwakzalverskraam over de toonbank als verse broodjes bij de bakker. In dit verband berucht is de IBM-advertentie in Datamation, 1968, waarin een stralende Susie Meyer —in kleuren!— verklaart, dat de bekering tot PL/I het einde van al haar programmeerproblemen was. Hoe de arme Susie Meyer er een paar jaar later uitzag, vermeldt de historie helaas niet, maar het laat zich raden, want het wondermiddel heeft natuurlijk niet gewerkt. Wie de propagandaliteratuur voor Ada —de programmeertaal, die door het Amerikaanse ministerie van defensie wordt gepousseerd— leest, moet constateren, dat de wereld in 14 jaar weinig is veranderd. (In Polen wordt Ada, terecht en onthullend, als "PL/II" aangeduid.)

Naast de potjes met programmeertalen hebben we de flesjes met nieuwe operating systems: op een regime van driemaal daags een druppel UNIX wordt U het eeuwige leven beloofd. En als dat niet werkt, dan is er nog het onfeilbare poeiertje van de "personal computer". Dat is helemaal heerlijk, want zonder dat U zich iets van al die andere patienten hoeft aan te trekken, kan dit poeiertje gemengd worden helemaal naar Uw persoonlijke behoeften.

Het laatste en gevaarlijkste luchtkasteel in deze windhandel is het "intelligent terminal" waartegen je "gewoon" kunt zeggen, wat je nodig hebt. Hier ligt de fraude er duimen dik boven op: de meeste mensen weten niet wat ze nodig hebben, en als ze het al zouden weten, kunnen ze het niet zeggen, noch "gewoon", noch "ongewoon". Desalniettemin schijnt de Japanse industrie te staan te trappelen om het te leveren, en wij zullen wel stom genoeg zijn om het te kopen. Ik denk, dat het daarmee net zo gaat als met homeopathische geneesmiddelen: je weet nooit of het helpt en, "Baat het niet, dan schaadt het niet.".

Deze laatste geruststellende overweging is overigens een ernstige misvatting. De z.g. "word processor" wordt aangeprezen met de overweging, dat het zo makkelijk is om iets in je tekst te verbeteren. Maar elke stroomlijning van het correctieproces is een staande invitatie voor de productie van dingen, die deze correctie nodighebben. Het is een volslagen illusie, dat de "word processor" de auteur helpt. Weinigen immers kunnen de verleiding weerstand bieden, maar iets te produceren, dat dan later wel gerepareerd of geperfectioneerd zal worden. Maar uit een rammelend concept is door bijvijlen nog nooit iets goeds ontstaan. Met een tekst die niet deugt, kun je maar een ding doen: naar de prullemand verwijzen. Als ik de Nederlandse overheid was, zou ik het gebruik van dit soort apparatuur niet verbieden; ik zou het zwaar belasten, net als alcohol en tabak.

De hoge kwakzalverdichtheid is mede verantwoordelijk voor de hardnekkigheid van de software crisis. Elke keer dat de patient bij een volgend lapmiddel geen baat heeft gevonden, wordt hij argwanender jegens de medische wetenschap. De onvervulde beloftes van volledige genezing maken hem doof voor wat de wetenschap verantwoord geven kan: suggesties ter verbetering van de toestand.

Laat mij evenwel niet zo in mineur eindigen. De toestand is inderdaad hopeloos als het wetenschappelijk onderwijs zich laat koejeneren door de eis van "maatschappelijke relevantie". Die leidt er namelijk toe dat de maatschappij krijgt waar hij om vraagt en dat, wanneer om lapmiddelen gevraagd wordt, er lapmiddelen worden geboden. Het "Mundus vult decipi; decipiatur ergo." is dan onverdund van toepassing. De toestand is evenwel niet hopeloos als het wetenschappelijk onderwijs niet voor zijn leidinggevende taak terugdeinst en de moed heeft de wereld te bieden, niet waar de wereld om vraagt, maar wat de wereld nodig heeft.

Over de hele wereld is de toestand aan de universiteiten tegenwoordig zo benard, dat op hen je hoop vestigen onverantwoord optimisme moet lijken. De wortels van onze universitaire traditie gaan echter zo diep, dat ik er van overtuigd ben dat die traditie een taaier leven beschoren zal zijn dan de software crisis van vandaag.

Nuenen, 4 juli 1982

transcribed by Hans Terlouw
revised Sat, 9 Jan 2010

EWD831

Why numbering should start at zero

To denote the subsequence of natural numbers 2, 3, ..., 12 without the pernicious three dots, four conventions are open to us

a) |  | 2 ≤ i < 13
b) |  | 1 < i ≤ 12
c) |  | 2 ≤ i ≤ 12
d) |  | 1 < i < 13

Are there reasons to prefer one convention to the other? Yes, there are. The observation that conventions a) and b) have the advantage that the difference between the bounds as mentioned equals the length of the subsequence is valid. So is the observation that, as a consequence, in either convention two subsequences are adjacent means that the upper bound of the one equals the lower bound of the other. Valid as these observations are, they don't enable us to choose between a) and b); so let us start afresh.

There is a smallest natural number. Exclusion of the lower bound —as in b) and d)— forces for a subsequence starting at the smallest natural number the lower bound as mentioned into the realm of the unnatural numbers. That is ugly, so for the lower bound we prefer the ≤ as in a) and c). Consider now the subsequences starting at the smallest natural number: inclusion of the upper bound would then force the latter to be unnatural by the time the sequence has shrunk to the empty one. That is ugly, so for the upper bound we prefer < as in a) and d). We conclude that convention a) is to be preferred.

Remark  The programming language Mesa, developed at Xerox PARC, has special notations for intervals of integers in all four conventions. Extensive experience with Mesa has shown that the use of the other three conventions has been a constant source of clumsiness and mistakes, and on account of that experience Mesa programmers are now strongly advised not to use the latter three available features. I mention this experimental evidence —for what it is worth— because some people feel uncomfortable with conclusions that have not been confirmed in practice. (End of Remark.)

*                *
*

When dealing with a sequence of length N, the elements of which we wish to distinguish by subscript, the next vexing question is what subscript value to assign to its starting element. Adhering to convention a) yields, when starting with subscript 1, the subscript range 1 ≤ i < N+1; starting with 0, however, gives the nicer range 0 ≤  i < N. So let us let our ordinals start at zero: an element's ordinal (subscript) equals the number of elements preceding it in the sequence. And the moral of the story is that we had better regard —after all those centuries!— zero as a most natural number.

Remark  Many programming languages have been designed without due attention to this detail. In FORTRAN subscripts always start at 1; in ALGOL 60 and in PASCAL, convention c) has been adopted; the more recent SASL has fallen back on the FORTRAN convention: a sequence in SASL is at the same time a function on the positive integers. Pity! (End of Remark.)

*                *
*

The above has been triggered by a recent incident, when, in an emotional outburst, one of my mathematical colleagues at the University —not a computing scientist— accused a number of younger computing scientists of "pedantry" because —as they do by habit— they started numbering at zero. He took consciously adopting the most sensible convention as a provocation. (Also the "End of ..." convention is viewed of as provocative; but the convention is useful: I know of a student who almost failed at an examination by the tacit assumption that the questions ended at the bottom of the first page.) I think Antony Jay is right when he states: "In corporate religions as in others, the heretic must be cast out not because of the probability that he is wrong but because of the possibility that he is right."

Plataanstraat 5 5671 AL NUENEN The Netherlands |  | 11 August 1982 prof.dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Fri, 2 May 2008.

EWD832-0

A theorem about infinite sequences of numbers

Theorem.  An infinite sequence of (real) numbers contains an infinite monotonic subsequence. (End of Theorem.)

Proof.  Let the sequence be x(i: 0 ≤ i). Element x(i) is "dominant" means (A j: i+1 ≤ j: x(i) ≥ x(j)). We distinguish two cases.

The number of dominant elements is infinite.  In this case the dominant elements form an infinite subsequence, which is monotonic (viz. descending).

The number of dominant elements is finite.  In this case an N exists such that from x(N) onwards, no dominant element occurs, i.e. (A i: i ≥ N: (E j: i+1 ≤ j: x(i) < x(j))). Hence each x(i) with i ≥ N is the starting element of an infinite subsequence that is increasing, and therefore monotonic.

(End of Proof.)

I found this proof last Sunday evening; the day before I had heard the theorem together with the rumour that it might require a fancy proof. Quod non.

Plataanstraat 5
5671 AL NUENEN
The Netherlands

16 August 1982
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Thu, 19 Jun 2003.

  EWD 833

An In-Depth Seminar on Proven Tools & Techniques of Structured Methodology for Effective Software Configuration Management

     Isn't that a catching title? I think it is fascinating. But the most fascinating thing is that in order to compose that blah-blah, I needed to merge only two recent announcements:

"An In-Depth Seminar on Methodologies & Tools for: Software Configuration Management, Presented Entirely by the Guest Expert: Mr. Rick Frederick"

and

"Proven and Effective Techniques in ... Structured Methodology for Software Design and Development,
Presented Entirely by the Guest Expert: Mr. Robert J. Rader".

The first of these two-day courses will be given in London, Paris*, and Amsterdam, the second one in W.Berlin, Paris* and London.

* Paris session will include simultaneous translation in French.

Conference Management is by Technology Training Corp.; the folders further mention State of the Art Seminars Division Ltd. (To give some idea of their competence: my name occurs three times in their mailing list!) The courses are sponsored by "Education Foundation of the Data Processing Management Association (USA)" and "The Institute of Data Processing Management (UK)"; so much for the level of those two bodies.

*                     *
*

      We are flooded by such folders and they pose a problem. You see, it is very improbable that those courses have any content more solid than the folders, and the folders are patently empty. They push very impressive terms —"Configuration Management Phasing", "Automated Requirement Languages"— but what of the rôle of those hollow forms? As vehicles for serious thought they are inadequate, for they are about as meaningful as the decorations pinned on the chest of the average army general or communist leader. These terms are probably best understood as this secular age's equivalents of the magic formulae and the religious incantations of other times and civilizations.

      But the companies selling these wonderful words make enough money to remain in business one year after the other: evidently, enough people are taken in, and that is something to think about for a while.

*                     *
*

      Wherever the printing press has been in operation, we have had junk literature: the English "penny-dreadful", the American "pulp magazine", the Dutch "keukenmeidenroman" (= kitchen-maid novel), the German "Groschenroman" (= penny novel), the French "roman de quatre sous" (= four-penny novel), in short: pulp literature. The characteristic fact is that the addict firmly believes that he or she is reading the real thing; in its modern form it is known as "the nr.1 bestseller".

      The 19th Century did not only have its pulp literature, but also a lot of pulp music: remember the operette! Again the addict believed that he or she was listening to the real thing; in its modern form pulp music is known as "the top-hit".

      I think the time has come to recognize that we have pulp science as well. In earlier centuries we had astrology, numerology, alchemism; in this century Teilhard de Chardin has provided us with a nice specimen. And, please, don't forget all the nonsense written about the pyramids! Again, pulp science can be practised as seriously as genuine science and the addict firmly believes that he or she is dealing with the real thing.

      I think also the time has come to recognize that nowadays pulp science is a very flourishing business, too diverse to oversee it all. Psychology, pedagogy and the social sciences are clear examples; so are artificial intelligence and systems engineering. The last one has given rise to expressions such as "systems thinking" and "the systems movement", terms unmistakable for anyone who is somewhat familiar with the modus operandi of obscure cults.

*                     *
*

      The wide-spread existence of pulp science has to be stressed because, containing as few scientists as they do, many bureaucracies —including governments and university administrations— are no longer able to identify pulp science as such. And this has more serious consequences than the fact that some people are willing to pay $500.— for a two-day course that others instantaneously identify as bullshit.

      Nowhere in computing the quack density is as high as in the broad area of design methodology; needless to say, all the miracle ointments are at the very least "proven" or "tested". With that abundance of wonderful remedies the conscientious scientist, who refuses to offer a cure-all, may have a hard time convincing his administration or the funding agency that his efforts make sense. Whether he likes it or not, the language of the quack is almost forced upon him when that has become the only language that the authorities still understand. Slowly the distinction between the scientist and the salesman erodes; but once wide-spread acceptance has been allowed to become a goal, it becomes a quality criterion, and the world of science has become infested with the standards of the bestseller society. And those discourage any deviation from the status quo so strongly that for many the road to innovation and improvement is effectively blocked.

      Under these circumstances the scientist has to remember that there is no virtue in pandering to the tastes of The Great Unwashed and he has to learn to take it as a compliment when he is being "accused" of being not enough of a salesman. Perhaps he should make it a habit to close each technical paper with the standard formula

"Disclaimer. Neither in form, nor in content, the above is pretended to be an improvement. (End of Disclaimer)"    .

Plataanstraat 5 5671 AL NUENEN The Netherlands | 23 August 1982 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

 EWD837

Trip report E.W.Dijkstra, Newcastle-upon-Tyne, 6-10 Sep. 1982

The yearly joint International Seminar on the Teaching of Computing Science --sponsored by IBM UK Ltd and organized by The University of Newcastle-upon-Tyne-- was this time devoted to the topic "Formal Specification".

I arrived in Newcastle earlier than usual. Instead of returning as usual on Friday evening I changed my reservation to the morning flight so as to be able to attend a discussion on Friday afternoon at the University where one of my mathematical colleagues had launched such a violent attack on a text written by my assistant that some action from my side seemed necessary before I would be off to Danmark next Sunday. As expected, the man's criticism was unsubstantial: like so many more traditional mathematicians he was just unaware of the rigour with which computing science has by now separated logic from philosophy.

I shall deal with the speakers in alphabetic order.

The lecture by J.-R. Abrial "Specification and Construction of Parallel Processes" I missed as a result of my early departure, something I regretted very much since I had never heard him.

R.M.Burstall devoted three lectures on "Specifications using an Algebraic Approach". He was much clearer than I remember from earlier occasions, yet hardly changed my attitude: I am still unconvinced, yet I gladly give him the benefit of the doubt.

D.I.Good's first lecture was on "Specification and Mechanical Proof of a Distributed System in Gypsy". It had the charm of reporting on work actually done. He presented his achievement with just pride and great honesty, not hiding the fact that so far the economics of his approach left something to be desired. I was sorry to miss his second lecture "Reusable Problem Domain Theories"; I quote from his abstract "In our experience with specifying and proving several real programs of considerable size, we have found that the dominant cost comes from what essentially amounts to building an effective theory of the problem domain."

J.J.Horning gave one lecture on "Some Notes on Putting Formal Specifications to Productive Use", in which he closely followed the paper he wrote with John V.Guttag and Jeanette Wing. As a result I liked the lecture as little as the paper, which had already given rise to extensive correspondence and a long discussion between the two of us on Monday afternoon. He then gave two lectures on "Notes on the design of the "Larch" Family of Languages", of which I missed the last one, what I regretted since the one I could attend --though largely on plans and intentions-- contained more meat than the first one.

C.B.Jones gave three lectures --titled "The Rigorous Method", "Meta IV", and "An Application" respectively--. With him I can never escape the feeling that his VDL past still shows itself and that his formalism should be redesigned for the sake of effectiveness. The issue of "bias" was explained very clearly.

P.M.Melliar-Smith gave three lectures, all of which I could attend: "The Formal Specification and Mechanical Specification of SIFT: A Fault-Tolerant Flight Control System", "A System for Formal Specification and Mechanical Specification" and "The Specification and Verification of Asynchronous Distributed Systems". They were all very informative.

What is here euphemistically referred to as "flight control" concerns the problem of using electronics to make planes with mechanically unstable wings fly, which for the sake of reliability has to be approached by a bunch of machines working in parallel. Two operating systems have been designed for that task and the comparison between the two was illuminating. The one had been designed in the traditional way for a configuration with special-purpose hardware for the voting procedure, the other with the intention of proving its correctness for a configuration without special hardware for voting: the one had required 4000 statements and its correctness could not be established, while the other --in which Melliar-Smith had been involved-- required eventually only 250 statements. A nice confirmation! (And, please, remember that in a binary world a factor of 16 corresponds to 4 orders of magnitude!)

In his second lecture he explained quite convincingly why they had built their own deduction system. Instead of being confined to those tasks for which a decision procedure was available, the theorem provers hanging around --at SRI-- were inspired by heuristics inspired by Artificial Intelligence, a "sophistication" which had made them useless. I quote:

"A drawback to heuristic theorem-proving attempts is that successful proof depends upon intimate knowledge of the heuristics employed. One must understand how very subtle changes in specification structure, even those that preserve semantic equivalence, can affect the direction and final outcome of the proof attempt. Lemma form becomes as important as content."

So much for Artificial Intelligence.

In his third talk he described how they intend to use temporal logic. It was very clear, but much less convincing; presumably contrary to his intentions he gave more food to my suspicion that temporal logic's hidden quantifications embody a methodological mistake.

P. Mosses gave two lectures of which, after having heard the first, I skipped the second one.

R. Nakajima from Kyoto University had planned to give two lectures on "Use of Formal Specifications in a Modular Programming System". After a vain attempt of explaining the Iota system --using the most obscure graphics I had seen for a long time-- he gave his perception of the Japanese "5th generation computer". That was very funny and very illuminating. He described it primarily as a bureaucratic monstrum out of touch with reality. Its major impact seemed to be that now all research proposals had to be rewritten so as to make them look like "FGC proposals". In this respect it looks as if Japan is creating its own Ada, adding, as it is, to its society a next layer of dishonesty.

On Thursday evening, at the closing dinner at Durham Castle, W.M.Turski gave a nice after-dinner speech, in which he redressed the balance and put the supposed virtues of formal --if not formalistic-- treatment in proper perspective.

*                  *
*

Jim Horning and I enjoyed the privilege of staying at Hotel Randell. After our return from the closing dinner, Jim was tired and went to bed. Till then, Brian and I had not had the time to talk in peace; he described to me the highlights of the project he had been working on for the last nine months --and about which he could now talk freely--. It sounded fascinating; that last night a Hotel Randell I had a short sleep.

I did not join the excursion on Wednesday afternoon: fearing to be otherwise occupied during the weekend, I spent that afternoon preparing the after-dinner speech I would have to deliver the next week in Copenhagen. I did join all other social events: on Monday evening the "At Home" organized by Harry Whitfield and his wife, on Tuesday evening dinner and Northumberland folk music at Close House, on Wednesday evening an informal gathering, and on Thursday the closing dinner. That day F.L.Bauer had come from Munich, having some business to conduct with me and a few others. That had to be squeezed in as well. In retrospect I realize that I have hardly spoken to the general English colleague: my time has been fully occupied by those present whom I know very well.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
17 September 1982
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 27 Sep 2004

  EWD 838

Trip report E.W.Dijkstra, Copenhagen, 12–16 Sep. 1982

     I had been invited to give the banquet speech on Tuesday, September 14th, at the end of the second day of the three-day "ITT Worldwide Programming Managers' Meeting". The invitation had reached me during my last visit to Austin, Texas, and, having never visited that company, I accepted the invitation.

      Originally I had planned to fly to Copenhagen on Tuesday morning and to return the next day. But when Ria told me that she would like to join me and pointed out that neither of us had had much of a holiday this summer, that schedule was quickly changed. We decided to go by car and to leave Nuenen so early that we could drive up North at our leisure.

      The two of us left Nuenen on Sunday morning at 10:30. As soon as we had crossed the Dutch-German border, we left the highway and continued via secondary roads, changing seats every 120 km and stopping when we felt like it. Around dinner-time we found a nice little hotel, south of Lübeck. In the second half of the next morning we took the ferry from Puttgarden to Rødby and largely via very small country roads we drove to Copenhagen, where we arrived around 15:00. It had been a very nice trip: the weather had been fine, but not too warm and the late-summer landscape had been a joy to look at.

      That afternoon I prepared my "visuals" while Ria found her way in Copenhagen. Afterwards we joined the —excellent!— ITT dinner for which Winston Churchill Jr. had been invited as the speaker.

      The next day Ria and I renewed together our acquaintance with Copenhagen. The town was windy that day. I rested an hour before dinner where I spoke from 21:50 until 23:15. My speech was largely devoted to the double-talk in which much of the discussion about computing is conducted and to my amusement I saw it cut through the audience: half of it enjoyed it very much, half of it felt visibly uneasy (probably because I exposed their own behaviour).

      On Wednesday morning we left after breakfast at 9:40. Shortly after 18:00 we crossed the German-Dutch border and half an hour later we had dinner in Denekamp. That evening we visited my colleague Coen Bron in Hengelo, where we stayed for the night. We had not seen Coen for quite some time and it was a very nice evening. The next day we drove home via my mother in Zutphen and via friends in Apeldoorn.

*            *
*

      An ITT brochure on the company's commitment to programming opens with a quotation from Rand V.Araskog: "We recognize software utilization as the technological challenge of the future and we've mobilized to meet it." There is a budding awareness that that software shall have to be designed, but —at least as far as I could observe— no idea that an intellectual discipline is involved. The whole enterprise struck me as gadget-driven to the extreme.

      I quote from leaflets of the ITT brochure.

"Advanced Technology's work is basic to all aspects of the ITT programming effort: the definition of the Optimum Programmer Workstation [sic], and Programming Development Environment. [...] Advanced Technology investigates the full range of programming resources, programming management tools, integrated text and graphics systems, programming analysis tools, very high-level [sic] languages, programming design tools, voice commands, operational programmer workstation hardware prototypes, store and forward voice messages feasibility, and fully integrated programmer workstation prototype."

      So now you know what ITT's Advanced Technology is doing! Applied Technology is also interesting:

"[...] Advanced Technology specialists [...] work on all aspects of programming metrics [...]. Advanced Technology continuously improves the quality and the productivity of the corporation's programming by developing standards and auditing performance."

      To someone whose only tool is a hammer, each problem looks like a nail. I found it impossible to take ITT's Programming Effort seriously.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 18th September 1982 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Thu, 14 Jul 2005

  EWD 839

Trip report E.W.Dijkstra, Utrecht 30 Sep. - 1 Oct. 1982

This was a very short trip: I left Eindhoven on Thursday morning at 8:00 and returned the next day at 17:20. The occasion was a two-day seminar on "The software crisis", jointly organized by The Royal Institute of Engineers and the Dutch Computer Society. I was the second speaker and one of the members of the panel whose discussion closed the seminar. In particular the second capacity was a reason to attend the whole seminar, which was not exciting. Depressing would also be a quite adequate term.

This was not a disappointment, for I went with suitably low expectations: the organizers had already told me that "in view of the topic" they were not heading for a scientific level! And indeed, they reached their goal.

One view regards programming primarily as producing lines of code --for the latter, one of the speakers seriously used the hilarious acronym LOC!--; another view regards programming primarily as preventing an otherwise unmanageable complexity from emerging. The first view is too superficial to be helpful: it is like equating the study of a book with character recognition and the turning of the pages. It was however the one adhered to by many a speaker.

I enjoyed myself thanks to the presence of C.Bron, S.D.Swierstra (who moderated the panel discussion) and B.Waumans, people I know for years but whom I encounter only rarely. The highlight, however, was being introduced to Mr. Ivor Catt, whom I had never met in person, though I knew very well who he was.

By virtue of his involvement, Catt knows all the ins and outs of one of the major scientific scandals of the last 15 years, viz. the systematic suppression in the world of electronics of all publications about the phenomenon of the so-called glitch and its ramifications. Part of Catt has turned to the study of what one might call the sociology of science or the scientific establishment's mechanisms for the rejection of novel results. The story how once --on false accusations made at a secret meeting-- he had got immediate notice because it was thought mandatory that no one in the company, nor any of the company's --mostly military-- customers, should know of the glitch was typical.

(In EWD837 I mentioned Melliar-Smith's lecture on the fault-tolerant operating system designed for "flight control". One of the things it has been designed to capture is a malfunctioning caused by a glitch. In order to estimate the MTBF of the whole system, its designers needed to know the likelihood of a glitch, a figure the hardware designers have to provide. Today I heard that the electronic engineers of Bendix --the company manufacturing the hardware for the flight control system-- had been so well-conditioned that the glitch problem could not even be explained to them. I am not amazed.)

Plataanstraat 5
5671 AL NUENEN
The Netherlands
6 October 1982
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 27 Dec 2004

EWD841

“There is no ‘royal road’ to geometry”

It rains all evening; I walked with the dogs with raincoat, boots and my new self-thinking umbrella (which I bought for less then $3.00 at the Shell filling station). But this note is not about tonight or the rain: it is about my spoiled breakfast. This morning’s mail brought me a folder of the Savant Institute, “including all the latest works of James Martin”. Hence.

My attention was drawn by the announcement of his “Program design which is provably correct — a quantum leap in software”. From the blurb I only reproduce the quotation from the author himself:

“This report describes a mathematically based approach which is really usable because the mathematics are hidden under the cover of a user-friendly set of tools [a set of user-friendly tools?]. It is one of today’s most important breakthroughs in the technology of designing systems.

While it was generally thought that mathematically provable software was a long way in the future, a new technique has now emerged from the work of Margaret Hamilton and Saydean Zeldin which is both highly powerful and practical. The technique has been automated so that provably correct systems can be designed by persons with no knowledge of either mathematics or programming. The software automatically generates logically guaranteed code. Whereas mathematics like that of Dijkstra has been applied to only small programs [by the way, how does J.M. know?], Hamilton and Zeldin’s technique has been used successfully with highly complex systems. [Etc.]”

(A warning for eager buyers of this marvel: in contrast to my self-thinking umbrella, the book is not cheap, for Savant Institute charges $200.00 per copy.)

I cannot judge the book, for it has not appeared yet. But we can judge the above quotation!

I have still to encounter the first “correct” system — i. e. meeting its specifications — which is not “provably” so, but in view of his intentions and (his perception of) his “target audience” I propose to forgive James Martin his seemingly pleonastic “provably correct”. The core of his claim then boils down to his statement that, thanks to automation, “correct systems can be designed by persons with no knowledge of either mathematics or programming”.

This is, indeed, a very important breakthrough in the technology of system design that should entirely change the educational practice at our best Universities, where the Departments of Computing Science now waste most of their time teaching their students mathematics and programming. The moral of James Martin’s message is that, at the modest price of $200.00 per student, these Departments can be folded up. His claim therefore deserves our full attention.

If the designer provides no bit of information, he has had no choice and can therefore “design” only one —presumably trivial — system. By providing N bits of information he can express his choice between 2N systems, the coding system employed determining between which 2N systems he can choose.

Such a coding system has to satisfy the essential requirement that, by allowing N to grow sufficiently, any conceivable system can be designed. The trouble, of course, is that most conceivable systems — almost all conceivable systems — are utterly nonsensical in one way or another.

Furthermore the coding system must be such that the designer can know which system corresponds to the bit stream he is providing: without that knowledge he would not know how to build up the latter. This means that the coding system must be such that the designer can combine in some way or another “sensical” substreams into a larger “sensical” (sub)stream of bits. (It is here that coding in machine code, but probably also in COBOL or FORTRAN, shows one of its major shortcomings.)

Should the coding system be such that the designer can provide a bit stream to which corresponds no system at all? The answer is yes, human fallibility being what it is. Ideally each minor modification — whatever that may be — of an acceptable bitstream should turn it into one that is rejected but the implied redundancy should not be of the trivial nature of duplication or the addition of parity bits, for then the designer would automate the generation of the redundancy. Type-checking is a well-known example of successful mechanical exploitation of redundancy. So are all checks of the context-free syntax.

Another form of non-trivial redundancy is together with an algorithm its functional specification. Whether we should include it in the bitstream provided by the system designer is a reasonable question since this form of redundancy is so non-trivial that it requires a theorem prover to check it.

Avoiding it by omission of one of the two is not a good proposal. Giving the algorithm and ignoring its functional specification is what has led to the software crisis; furthermore the functional specification cannot be mechanically derived from the algorithm. Giving the functional specification and leaving the derivation of an algorithm satisfying it to the machinery — the dream of PROLOG — is no solution either: first of all it requires a (this time mechanized!) theorem prover to generate an algorithm, secondly the functional specification, when satisfyable, can be satisfied by infinitely many algorithms, most of which are highly undesirable for other reasons. Without the designer going into that reasons and their consequences, the machinery would require magic as a built-in feature to make the appropriate choice — this in addition to the magic required for a general mechanical theorem prover! — .

Viable mechanical verification that an algorithm satisfies its functional specification requires that the proof be broken down by the designer to lemmata for which a decision procedure exists: the moral of the story is that in any case — whether the proof is mechanically verified or not — the designer has to design the correctness proof if he wishes to go beyond providing algorithms and hoping for the best.

It is a consoling thought that for all this neither a training in mathematics — to understand what you are doing — nor a training in programming — to prevent the amount of formal labour required from exploding — is necessary. It is an alarming thought that quite a few gullible managers, who, like our James, don’t understand what he is talking about, are only too ready to believe in this next promise of salvation.

In my title I quoted Euclid’s alleged rebuttal to King Ptolemy I. Does it help if I translate it into contemporary American:

“There is no such thing as a free lunch.” ?

*           *
*

As any logician knows — since Gödel and Turing — there are such things as provably undecidable questions and provably uncomputable functions. People that don’t know that will believe anything. There is the lovely story of the IBM-employee — I shall not divulge his name — whose research proposal mentioned uncomputable functions. When the proposal was discussed he was asked in disbelief “Do you mean to say that there exist functions that our equipment cannot compute?” Upon which, tongue in cheek, the scientist answered: “Indeed, in their current form IBM computers cannot compute all functions”, upon which answer his proposal was approved!

In a way, the 30’s were more enlightened than the 60’s, 70’s, and perhaps the 80’s. In my very young days, impossibility results could be published and were not completely ignored. With the increased economic significance of technology, such scientific results are now too unwelcome.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 10 October 1982 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

Transcribed by Roman Beslik beroal
Revised 14-Sep-2012

EWD845

McCarthy’s 91-function: an unfortunate paradigm

McCarthy’s 91-function —see below— is an ingenious and at first sight baffling construction, which deserved all the attention it attracted when it became known. Unfortunately it also acquired the status of “difficult testcase” for any proposed theory or set of proof rules for recursively defined functions. This is unfortunate for two reasons. Firstly, this function can be dealt with —see below— by such thoroughly elementary means that it is doubtful whether it is a very good testcase; secondly, its contortions are of such a nature —see below— that any method of dealing with it shows more of those contortions that of the method that is supposed to be illustrated.

McCarthy’s 91-function is g, given by the following recursive definition

g(x) = if x > 100 ⇒ x - 10 ⫾ x ≤ 100 ⇒ g(g(x + 11)) fi

and one is asked to demonstrate that it equals f, given by

f(x) = if x > 101 ⇒ x - 10 ⫾ x ≤ 101 ⇒ 91 fi

Here we go!

  g(x)

definition of g

if x > 100 ⇒ x - 10 ⫾ x ≤ 100 ⇒ g(g(x + 11)) fi

splitting the first alternative and unfolding once in the second alternative

if x > 101 ⇒ x - 10
  ⫾ x = 101 ⇒ 91
  ⫾ x ≤ 100 ⇒ g(if x + 11 > 100 ⇒ x + 11 - 10
         ⫾ x + 11 ≤ 100 ⇒ g(g(x + 11 + 11)) fi)
  fi

splitting of the last alternative and simplification

if x > 101 ⇒ x - 10
  ⫾ x = 101 ⇒ 91
  ⫾ 89 < x ≤ 100 ⇒ g(x + 1)
  ⫾ x < 89 ⇒ g³(x + 22)
  fi

terminating tail-recursion of third alternative

if x > 101 ⇒ x - 10
  ⫾ x = 101 ⇒ 91
  ⫾ 89 < x ≤ 100 ⇒ g(101)
  ⫾ x ≤ 89 ⇒ g³(x + 22)
  fi

combination of second and third alternative and terminating tail-recursion of the last one

if x > 101 ⇒ x - 10
  ⫾ 89 < x ≤ 101 ⇒ 91
  ⫾ x ≤ 89 ⇒ g2n + 3(y) for some n ≥ 0 and 89 < y ≤ 111
  fi

applying g once in the last alternative

if x > 101 ⇒ x - 10
  ⫾ 89 < x ≤ 101 ⇒ 91
  ⫾ x ≤ 89 ⇒ g2n + 2(y) for some n ≥ 0 and 91 < y < 101
  fi

applying g another time in the last alternative

if x > 101 ⇒ x - 10
  ⫾ 89 < x ≤ 101 ⇒ 91
  ⫾ x ≤ 89 ⇒ g2n + 1(91) for some n ≥ 0
  fi

since g(91) = 91, the last two can be combined

if x > 101 ⇒ x - 10
  ⫾ x ≤ 101 ⇒ 91
  fi

definition of f

  f(x)          Q.E.D.

That is all, in a long sequence of minute transformations. It is a winding argument that, of course, can be delivered in 57 varieties, but when you have seen one of them, you have seen them all. The 91-function is, as said, an ingenious construction, but it is an unfortunate paradigm since it leads to demonstrations that are both lengthy and boring.

I hope this is the last technical note in which the 91-function is treated.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 21 December 1983 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Jonathan David Arndt
revised 21-Jan-2020

EWD 847

Trip report E.W.Dijkstra, Australia, 19 Jan.1983 – 12 Feb.1983

The reason for this trip was "The First Wollongong Summer School on The Science of Programming", held from January 31 to February 9, 1983, at Perisher Valley, Australia. It had been organized by Juris Reinfelds of the University of Wollongong, who had invited David Gries (Cornell University), Tony Hoare (Oxford University and me as its lecturers. He had invited our wives as well, an invitation my Ria and Tony's Jill had accepted; David was there all by himself. I was furthermore joined by Netty van Gasteren in her capacity of Teaching Assistant.

On Wednesday afternoon Netty's husband drove us to Schiphol, where in spite of the fact that we were early we had some difficulty in obtaining the kind of seats we preferred. The B747 of flight KL843 was fully booked, and we did not look forward to the flight, which was going to take more than 24 hours. The crew was refreshed twice —once in Dubai and once in Colombo—; on the whole the flight, though much too long to be comfortable, was not half as bad as we had feared. The B747 is really an excellent plane and KLM made the flight as comfortable as the circumstances permitted. (Eventually we left the plane with the feeling that KLM could not help it that the world is so big.) I wrote, however, much less than I hoped and expected to; with its alternation of deserts, mountains and seas the route via the Far East is much bumpier than, say, crossing the Atlantic Ocean or the Polar Route to Anchorage. I thought I could not sleep while sitting, but eventually I could not keep my eyes open, so that problem solved itself. Due to strong tail wind we arrived half an hour early in Sydney; due to heavy car traffic —caused by a railway strike— Juris Reinfelds, who had promised to collect us, arrived half an hour late. Just when Netty had decided to cash a traveller's cheque, Juris arrived; he drove us to Wollongong in his car, whose air conditioning we learned to appreciate. Around noon we were in the Boat Harbour Motel, where we slept most of the afternoon; Juris and his wife Lauma joined us for dinner. (The Boat Harbour Motel boasted a 4-star restaurant, but we have not been able to discover where those stars came from.) For the Australian traveller, life is complicated by the fact that during the weekend everything closes; Lauma had solved these problems for us, firstly by having shopped for us, so that we could prepare our own breakfasts etc., and secondly by inviting us for a Sunday brunch.

Saturday morning at 3:00 I was awake beyond redemption; so I continued the letter I had started on the plane. I wrote that day 10 pages; we explored that day the town and the beach and we slept some hours. Tony and Jill Hoare arrived on Sunday morning early; David's plane, which had been due to arrive within 20 minutes from theirs, had been diverted to Brisbane with engine trouble and David arrived as a result a couple of hours later. (Consequently, poor Juris had to make the trip Wollongong - Sydney and vice versa twice that day!) The newly arrived courageously stayed awake.

The rest of the week was devoted to adjustment to time shift and climate and to preparation of our Summer School. We met the other tutors —Geoffrey Dromey (Wollongong), Jeffrey Sanders (NSW Institute of Technology) and Rodney Topor (Melbourne). Monday and Tuesday were devoted to preparation, i.e. on the second day we organized an extraordinary session of the Tuesday Afternoon Club in order to show the Australian tutors what was expected from them. (we went through the first five pages of a long manuscript by Dromey, who did not know the word "pleonasm"; David was a great help.) Wednesday was largely devoted to interviews, first by the local television, then by the national radio, and finally by Computerworld. That evening, Juris took Netty, Ria and me to Cosi Fan Tutti in the Sydney Opera House. (The organizers of the 6th Australian Computer Science Conference would take David, Tony, and Jill on the day we three flew back.) The dinner before the opera was good and the building is curious; the seats were covered with plastic and duly uncomfortable. The performance was better looked at than listened to; at 24:30 we were back in our motel. Thursday was a day of rest; we did some shopping and wrote letters and postcards.

On Friday morning 7:10 we left in a minibus for Canberra, where Tony was to give a lecture at the Australian National University, either at the end of the morning or at the beginning of the afternoon, no one was quite sure. (It turned out to be at 14:00.) The journey to Canberra was not a pleasant one: it became very very hot in the minibus and its driver —Dromey— absent-mindedly indulged in a technical discussion for which he would have preferred to use both hands. After a depressing exposure to the results of the Australian drought we arrived in Canberra, well in time had Tony had to perform in the morning. After lunch, Tony gave his talk, but he was clearly not in the mood. In the evening the Department of Computer Science took us out for dinner; I enjoyed both the food and the company.

The our ways separated for almost three days. The others continued the next day their journey to Perisher Valley, while Ria and I stayed for a long weekend with Robin and Kate Stanton. (Robin had been my host in 1977, when I stayed for a month at ANU.) On Saturday we went to the Botanic Garden (whose trees gave surprisingly little shade), to the High Court and the (new) National Gallery, on Sunday to Tidbinbilla Nature Reserve, where we saw many emus, kangaroos (both from quite close) and —we were very fortunate!— one koala: a really charming animal! Both evenings Kate had guests for dinner. It was a pleasant weekend, but very hot: 34 degrees C. in the living room seemed standard. I wrote some, but not much. On Monday afternoon Robin drove with Brian Molinari and us in Kate's car to Perisher Valley, where in Sponar's Chalet, the Summer School would start the next morning. Upon arrival we were well-done and greatly relieved to find the shower in working condition. (With the nearest plumber at, say, 70km distance, I had voiced my misgivings about the sanitary conditions at Sponar's Chalet; David had spent part of the weekend trying to find me a room that would justify my fears, but had not succeeded. Sponar's Chalet had no laundry facilities, but that was intentional: lying in the middle of a national park it was not allowed to upset the ecology by detergents.)

The facilities at Sponar's Chalet were somewhat primitive but otherwise excellent, with the exception of the shape and temperature of the large room where we had to give our lectures: it had clearly not been designed for lecturing to an audience of 100 people. But Tony had his overhead projector and David and I had our blackboards (please note the plural). We lectured from 08:30 to 12:30 with a 30-minute coffee break and from 14:00 to 17:30 with a similar break for tea. I admired the sense of duty of the audience that was almost always complete (with the noteworthy exception of Stefan Postma from Pretoria, who hardly attended any lectures). It was hard work for all concerned; we lectured from Tuesday to Saturday, and the first two days of the next week; Wednesday morning was devoted to a discussion session, and at noon the Summer School was closed. Tony had his own topic: programs and predicates, specifications and the axiomatic theory for CSP; David and I shared at the beginning the topic of scientific program development, half-way I broadened the scope by some capita selecta.

Our original plan had been that we should lecture 10 days instead of 7, and that would indeed have been better, for a number of topics (such as the presentation of larger programs) had to be dropped. But the summer school had to be squeezed in between an Australian national holiday on Monday 31 January and ACSC 6, which started on Thursday 10 February in Sydney. This was a pity. It was, however, partially compensated by the active cooperation of the audience which was encouraged by the perfect isolation of Sponar's Chalet: all evenings one saw participants reading in the library, working, discussing the homework, etc. The tutors made long evenings.

On the whole I think the summer school went down very well. With an audience as mixed as we had one cannot expect to please all, and a few were discontented because we did not touch on what they perceived as the problems of "the real world" —such as how to make the best of a COBOL shop—. For the vast majority the rather formal approach was a refreshing novelty, which they liked very much. "Novelty" does not seem an exaggeration: my impression was that up till now most Australian discussion about programming methodology so far has been carried out in terms of the not very helpful imponderabilia as "ease", "understandability", "naturalness" etc.; the sharp distinction between convenient and conventional had not been made.

As any summer school we had our social activities. On Sunday we had excursions. I went to Thredbo to climb the Koscuisko, which was precisely the sad mistake I knew it would be: even the first 600m in the chair lift I disliked. At the end of the day I was so tired that next morning I slept soundly through most of Tony's lecture (but every time I woke up, it sounded so nice that afterwards I felt I could compliment him). On Sunday evening we had a recital for cello and piano (Mendelssohn, Franck and R.Strauss), at which the piano —carried all from Wollongong— was the weakest link. On Tuesday we had a very nice string quartet (Mozart, Shostakovich, and Mendelssohn again; I liked Mozart most): Richard Tognetti (17) and Karen Segal (18), violins, Debbie Lander (17), viola, and Rita Woolhouse (21), cello. They played very well and had not the handicap of an unwilling keyboard instrument.

Around noon, on Wednesday 9 February, we left in a big coach for Sydney, where we arrived around 19:00. By the time we arrived in Sydney, the driver, who had come that morning with the coach from Wollongong, had made something like 1200km. When he switched on the radio to listen to the cricket match, I did not protest at first, considering it might help him to stay awake, but after half an hour it was really more than we could stand and I had to ask him to switch it off.

In Sydney we —i.e. the six of us— were collected by Les Goldschlager, who drove us to our motel and then took us out for dinner in a Chinese restaurant. Some of us were primarily hungry, I was dried out, so much so that besides the beer I had noodle soup as a main dish. Dinner conversation was this time impossible: it was a restaurant with three guys making the most terrible music (electronic organ, drums, guitar, and male voices, all amplified).

The next morning, after the official opening of ACSC 6, I gave a keynote address from 9:10 to 10:00, which seemed to delight my audience. I presented the development of the new algorithm for the detection of termination of a distributed computation, which I had also shown at Sponar's Chalet; this time it was primarily an exercise in timing. After the coffee break, the six of us played truant and went to the Sydney Zoo, that is: tried to go: the personnel of the ferry that should take us there had just gone on strike. We took two taxis. We missed the platypus —it refused to show its face in the breeding season— but were fully compensated by the wombat and the koalas. Tired but satisfied we came back in the University Inn Motel at 17:00, glad to be able to have a short rest before we had to attend the Conference Dinner (which was called a banquet). Three Australian professors spoke at the dinner; brevity was the main virtue of their speeches, which were perhaps an explanation why, at Sponar's Chalet, we had got so many compliments for our lecturing styles.

Friday morning, from 9:00 till 10:10 —he did not know how to stop and the chairman did not assist him— Tony gave his keynote address in a for him very unusual fashion: he had decided not to show visuals and to use the blackboard instead. The "coins" had been abbreviated by "c", the "chocolates" had been replaced by "toffees" so the he could abbreviate them by "t"; knowing the difficulty of a last-minute change of identifiers I admired his courage. After the coffee break we took leave from David, Tony, Jill, and Juris and were taken to the airport.

On our outward journey, Netty, who had had two bad nights, had slept most of us; on the way back Ria, who had been terribly sick after the Conference Dinner —was it the Seafood Cocktail that I had skipped?— won the prize. Half an hour after take off my pen was empty; I filled it during the stop at Melbourne. With the same stops the return flight took 2 hours more: the difference between tail wind and head wind is evidently non-negligible. Again we arrived half an hour ahead of schedule. Upon arrival, Netty's husband and our daughter were waiting for us with two cars. After a shamefully long delay before our luggage showed up —usually Schiphol Airport is much better— we were reunited and drove South. Near 's-Hertogenbosch the five of us had a cup of coffee, and then our ways parted; at 9:00 we were back in Nuenen. While Ria informed her mother and other relatives the we had safely returned, I made coffee and started to deal with the accumulated mail, which had been admirably sorted during our absence. After Femke had done the shopping for the weekend, Ria and I went to collect Bamse and Duke (our two Samoyeds, who had stayed with our maid); they were in excellent condition and glad to see us back. They wanted immediately to be walked with: it was barely below zero, but I at least found it very cold. We slept from 12:00 to 15:00, whereafter we were almost back to normal. Later that afternoon, the florist delivered a congratulation from the Department of Mathematics and Informatics with my "Computer Pioneer Award" from the Computer Society of the IEEE, which I had received the day before I left.

*                      *
*

At the ACSC 6 Conference Dinner the empty chair between Ken Iverson and me became occupied by a charming lady, who was just a little late. Since my "A Discipline of Programming" had been her introduction to computer science she was very excited to sit next to me, and so she told me. After some conversation she realized that her other neighbour was somewhat lonely, turned to him with social grace and asked him "And, Dr.Iverson, what is your field of interest?". Iverson answered "APL.".

*                      *
*

I collected another piece of Ada gossip. When Ada was still the Green Language, Jean Ichbiah asked Mike Woodger to rewrite the manual, not trusting his own English. Mike found many obscurities and unclarities which he cleared up after having checked his understanding with the author. His version of the report then revealed the complexity of the design so ruthlessly that Ichbiah submitted his original text to the DoD.

*                      *
*

From "Proposal for an Australian Computer Science Network" by Robert J.Kummerfeld (Australian Computer Science Communications, Vol.5, Nr.1, p.196):

"Unfortunately, letters are not a very convenient means of passing messages since it is such an effort to write them.".

I was reminded of Samuel Johnson's "What is written without effort is in general read without pleasure.".

*                      *
*

After a trip like this one always asks oneself "Was it worth it?". Knowing the other speakers so well I got little out of it and we have been too busy preparing our performances to have much time for serious conversations amongst ourselves. Hence the fruit has to lie in Australia. I think the fruit was worth the effort. The Australians have an isolation complex with all sorts of consequences, and a pleasant one is that they are very receptive. (Up to this very day "A Discipline of Programming" sells very well in Australia, a fact I have always interpreted as a consequence of my 1977 visit and a symptom of their receptiveness.) This time almost half of the audience consisted of academic staff and my impression is that all Australian universities were represented. So it is not unrealistic to expect a noticeable effect from our visit, at least when the Departments of Computing Science will be given the opportunity. Particularly in Sydney it surfaced quite clearly that the Departments of Computing Science have to do their work under the hearty obstruction of the more established departments, which do their utmost best to keep computing a null-science; it all sounded very familiar.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 14 February 1983 prof. dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 10 Apr 2006

EWD 850

Trip report E.W.Dijkstra, Helsinki, 1 - 4 March 1983

On Tuesday 1 March I left Nuenen at 7:15 and arrived in Helsinki at 15:35; on Friday 4 March I left Helsinki at 13:40 and arrived in Nuenen at 18:45. The flights (Finnair and KLM respectively) were dead on time.

I was the guest of OY Paragon AB, the Burroughs representative in Finland. It was primarily a Burroughs trip. I had a busy schedule. They had arranged

(i) that I should give a lecture on Wednesday afternoon as part of their release of LINC —in today's jargon "a commercial applications generator"—
(ii) that I should deliver on Thursday morning the keynote address at ADP 83 —"atk 83" in Finnish— , the yearly data-processing conference in Finland
(iii) that I should meet the Finnish computer press on Friday morning. Furthermore they had included
(iv) a visit to the University of Helsinki on Wednesday from 11:00 to 14:45 (this visit had been included on my request)
(v) a visit to the Technological University on Thursday afternoon (at the request of Heikki Saikkonen).

On Tuesday evening —after a sauna of 109 degrees C.— I had dinner with Paragon; we started to prepare the LINC release, a preparation which continued next morning. On Wednesday evening the organizing committee of ADP 83 offered a dinner to itself and its foreign guests. On Thursday evening I had to attend the official Conference Dinner. On Wednesday I lunched with people from the University of Helsinki, on Thursday I had to attend at ADP 83 a lunch with the press (in general), on Friday I had lunch with Mr.Runge Karlsson, Chief Operating Officer of Paragon. The Finns took very good care of me, but Finnish hospitality seems such that one had better eat only half of the food one is offered.

Finnish audiences are difficult to work with. I had been warned that they don't respond while you are speaking, which is a pity because, for lack of feedback, your decisions about speed and degree of explicitness of your presentations have to be pure guesswork. After my lecture at the University of Helsinki several people expressed their admiration for the fluency with which I had done all the formal manipulations on the blackboard; my interpretation of that compliment was that I had been a bit fast.

My 20-minute talk on the subject of "The development of programming languages" at the LINC release was for me the most difficult one, since both the audience —about one hundred data-processing managers— and the setting —a sales presentation— were unfamiliar for me. I confined myself to the intersection of what I really believed and what seemed appropriate under the circumstances. I think I succeeded well: during the following cocktail party both organizers and participants expressed their appreciation.

In degree of difficulty it was followed by the one-hour keynote address at ADP 83 under the title "Tacit assumptions that hamper software development", because in the audience (of about 250) the scientists were an almost negligible minority. It was the main reason for my invitation, which I had accepted because I have to give a similar keynote address for a similar audience (only much bigger) next June in Barcelona. It went very well, despite the fact that I had prepared visuals. (Typically my financial foil attracted most of the attention; its text had been:

"A main reason why software is so expensive is that programming is done by cheap labour.
Another reason is that existing programs are considered valuable because their development has been so expensive."

Later they explained to me that I had said something they all agreed with but for which the independence of the scientist was needed to say it so clearly.)

At the University of Helsinki I spoke about "Predicate calculus and its role in Computing science" and at the Technological University about "The detection of termination of distributed computations". Both times I had an audience of about one hundred people and the lectures went very well. At the University of Helsinki I have devoted the first hour of my talk to Yossi Shiloach's Algorithm: it is always a fascinating experience to need at least a full hour for the explanation of a 5-line program solving efficiently an easily stated problem and manipulating no more than three counters! After that very convincing demonstration that a program can indeed be a very compact deposit of our intellectual labours I talked in more general terms about the role of the predicate calculus in computing. I regretted that I could not spend more time at the University for I would have liked to get better acquainted with some of the people I met. Fortunately I met some of them the next day after my lecture at the Technological University.

Other foreign speakers at ADP 83 were Anthony I.Wasserman (UCSF, Medical Information Science) and Niels Bj�rn-Anderson (Copenhagen Business School). From the latter's abstract I quote

"Almost all efforts by manufacturers are aimed at making the system "user friendly", by lowering the requirements on the user. As a secretary remarked "it is as if the systems with intelligent terminals are designed on the assumption that there is no intelligence in front of the VDU"."

(I only saw this after Heikki Saikkonen and I had already decided on a joint project, viz. the education of terminal-friendly end users.)

The highlight of my visit was the interview by the Finnish computer press. It was conducted by Pertti Jotuni (?), the doyen of Finland's science journalists. He was a delightful, knowledgeable man, who did not ask a single stupid question. At his request we discussed not only the influence of mathematics on computing, but also the influence in other direction. (Every book I quoted from he knew!)

*         *         *

I had forgotten to take a pair of solid shoes with me, but to my relief (and the amazement of my hosts) I was quite comfortable with my sandals in their -16 degrees C. When I came home, the Dutch spring had broken loose and Arthur Koestler has died.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 6 March 1983 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD852

Judging “HOS” from a distance

“[...] She even wrote a book.”

“About agapemones?”

“Yes. And the Higher Wisdom. And Beautiful Thought. That sort of thing. Full of bad syntax.”

“Oh, lord! Yes—that’s pretty awful, isn’t it? I can’t think why fancy religions should have such a ghastly effect on one’s grammar.”

“It’s a kind of intellectual rot that sets in, I’m afraid.[...]”

Dorothy L.Sayers in “Gaudy Night”

The majority of people would not dare to open their mouth anymore if they knew how much they revealed by doing so. Are apologies dangerous (Disraeli), so are acknowledgements. A paper is not recommended by a profuse acknowledgement to a colleague whom one knows to be too superficial. Having a technical writer write one’s article is not a recommendation either.

*            *
*

“HOS” stands for “Higher Order Software”, originally the name of a methodology, now the name of a company. I know the company’s product from four publications: [0], which introduced in 1976 HOS as “a methodology for defining software”, [1], which appeared after the foundation of HOS, Inc, [2], which oversells the product, and [3], which for all its brevity is very illuminating. Here is what I reconstructed from these sources.

Margaret Hamilton (now President HOS, Inc.) and Saydean Zeldin (now Vice-President HOS, Inc.) joined The Charles Stark Draper Laboratory in the mid 60’s where they got heavily involved in the programming of the Apollo on-board software and the like. Instead of closing their eyes for all the problems they encountered they have studied them and analyzed their origins, asking themselves all the time how these problems could have been circumvented. In the course of the 70’s they show symptoms of proposing a remedy.

Their first proposal has very much the form of an applicative programming language with identified intermediate results. The main motivations for their proposal seem to have been the following:

(i) all sorts of manual checks that had been developed —checks against the use of initialized variables, type checks, and their embellishments— could be mechanized provided the programs were expressed differently

(ii) the unbridled use of the assignment statement all but defeated most restart requirements

(iii) most multiprogramming designs suffered from a premature decision how the total workload should be spread over a number of (quasi-)concurrent processes. A notation that primarily described which values depend on which can obviously alleviate these problems.

Of [0] and [1], the first one is the more technical one. (From the limited information I have about the authors, my guess would be that [0] is more Hamilton and [1] is more Zeldin.) Both papers share the characteristic of being so poorly written as to cast severe doubts on the effectiveness of the refereeing for the journals in question (IEEE Transactions on Software Engineering and The Journal of Systems and Software respectively.) It is, in fact, often hard to figure out what the papers are about.

Certainly [0], the earlier one of the two papers, has done its fair share of sowing the seed of confusion. Its title mentions “defining software”, but the paper nowhere states what is meant by that expression. Here [3] gives the solution: they meant describing an algorithm in a way fit for mechanical execution, but that is what is usually called “programming”. A nice example of gobbledegook is the following sentence from its abstract: “We envision a scheme in which the definition of a given system can be described with an HOS specification language which, by its very nature, enforces the axioms with the use of each construct.” Just a few questions about this sentence:

(i) what is meant by “a scheme”?

(ii) how has the “given system” been given?

(iii) if we can “describe a definition”, what is the (profound) difference between a definition and its description?

(iv) what means “enforcing an axiom” and how does one do it?

I know that writing an abstract is a very difficult task, but there is no excuse for a sentence like the one quoted, not even in an abstract. Regrettably, similarly loose sentences occur throughout the paper, e.g. “The Structuring Executive Analyzer is a lower virtual layer module with respect to a given hierarchical HOS system in its dynamic state.”

The linguistic quality of [1] is amply illustrated by the following quotation: “A system development process is a system that develops another system. Such a system can be viewed as a process [etc.]”. The quotation makes one wonder why we need the different terms “system” and “process” (or whether we need them at all). Once every n sentences (for rather small n) one has not the foggiest notion what the authors are writing about and the reader’s self-respect can only be saved by the probably correct assumption that they wrote about nothing. (Though applauding the traditional anonymity of the referee, I regret it this time: it always helps to know whose judgement to ignore.)

A poor presentation of excellent subject matter is in principle perhaps thinkable, but the papers do not provide an instance of that rare (and unlikely) occurrence. The notational conventions adopted in the formal text and the ways in which they are used are not convincing; I mention just a few examples.

(i) They write “Factor(GCD(n1, n2), n1) = True” where “Factor(GCD(n1, n2), n1)” would have done; I conclude that the authors have only a partial understanding of Boolean expressions.

(ii) Though they also use “And” as infix operator and seem to allow “x0 ≠ 0 And y0 ≠ 0 And z0 ≠ 0”, in AXES “And” is a function name, forcing the user to write “And(x0, And(y0, z0))” or, alternatively, “And(And(x0, y0), z0)”. For associative operators the infix notation is, however, definitely preferable.

(iii) When they write “x And y” the “keyword” And is syntactically indistinguishable from an arbitrary identifier.

(iv) Whether to use “or” or “coor” depends on the fact whether selection criterion and subfunction depend on all arguments of the parent function. Independently of the relevance of the distinction, the significance of the redundance should be challenged: the same mechanism that checks their correctness if the text is required to distinguish between or and coor could replace, if necessary, or by coor if the text were allowed always to use or .

(v) The conventions require the introduction of very many identifiers. What is the advantage of writing “y = f (z)   z = g(x)” instead of “y = f (g(x))”?

(vi) The lavish use of subscripts reveals a lack of sound mathematical taste.

The overwhelming impression is that the authors have had more experience than education. The burning question then becomes “What kind of experience?”. They have certainly been able to improve upon what they refer to as “conventional techniques”, but in some of their examples these are so backward (if not downright stupid) that their achievement becomes rather unconvincing. I quote —from [1]—: “we discovered that many interface errors took place in the implementation phase when programmers would use instructions in an unstructured language, such as “GOTO + 3”. Errors would creep in when someone would come along, often the same programmer, and inadvertently insert a card between the GOTO instruction and the location at which it should have gone. Once we discovered the amount of errors that resulted, we enforced by standardization the use of instructions such as “GOTO A” rather than “GOTO + 3”. As a result, such errors never happened again.” I can believe that, but my problem is that the stupidity of admitting instructions such as “GOTO + 3” was well-identified as such more than 25 years ago!

Similarly, while really professional software development had stopped using flowcharts, say, 20 years ago, both [0] and [1] proudly mention the development of ..... a flowcharter! (The use of AXES, not mentioned in [0], strongly suggests that the latter flowcharter was developed in the second half of the 70’s!) It makes one seriously wonder how many of their development “tools” are, in fact, mechanized aids for the application of obsolete techniques. (I vividly remember an incident in 1969 when an admittedly professionally somewhat old-fashioned professor of computing science lost almost all his credentials with his colleagues —they were, in fact, flabberghasted— when it transpired that he still used flowcharts in his lectures.)

*              *
*

Of the publications studied, [2] is the most bulky one —as a matter of fact more than 400 pages—. It has about as much technical content as an average tract of Jehova’s Witnesses. The book transmits one message very clearly, viz. that for James Martin writing consists of stringing words together he does not know the meaning of; in all other respects the book only adds to the confusion. I quote by way of illustration —[2], p.40—

The approach described in this report is different. Instead of applying ad hoc programming constructs, it applies only constructs which are built with mathematical axioms and proofs of correctness. A library of provably correct operations is built. The operations manipulate precisely defined data types by means of provably correct control structures. [...] Most important, the mathematics is hidden from the typical user so that the method is easy to use.

and —[2], p58—

The functions, thus, decompose into primitive functions which are mathematically rigorous. The means of decomposition itself is proven to be correct in terms of the three primitive control structures which are mathematically rigorous. The data types used by the functions are mathematically rigorous. From these three mathematical bases, great cathedrals of complex logic can be built.

Please don’t try to understand the above, for that cannot be done. Martin wisely nowhere states what is meant by the magic formula “provably correct”. He only states what it does not mean:
—[2], p.3—

When we say “provably correct code” we do not mean that the program is necessarily without fault. [...]. However the majority of bugs in programs today are caused by the mechanics of programming, inconsistent data, sequence errors and so on.

Applicative programs can be translated into imperative ones, and this can be done mechanically. Unavoidably, the resulting imperative programs display a great number of desirable characteristics: they are syntactically correct —it is impossible to construct a correct translator that can produce a syntactically incorrect program—; all variables introduced by the translator are initialized by the program generated —no correct translator introduces uninitialized variables into the target program—; etc. In James Martin’s parlance “provably correct” means probably no more that by virtue of their mechanical production texts can enjoy certain characteristics.

From a professional point of view, [2] is eminently ignorable. In other respects it is interesting. It is revealing about HOS Inc., about James Martin and about the computing community in general. The company has “perfected” its product, but not by cleaning up the conceptual mess with which it started —[0] talks about “violation of this theorem”: how does one violate a theorem?—; instead it developed ..... a graphics editor! And that is precisely the kind of would-be embellishment the professional software designer is only too happy to ignore. I am afraid that HOS Inc. has done some “market research” and has concluded that the incompetent form a bigger market. I have never had reasons to consider James Martin as a competent computing scientist, but that he is a competent salesman I don’t doubt: he must have seen a market for [2] at $200 apiece. The book is so terrible that that is a depressing thought.

[0] | Hamilton, Margaret and Zeldin, Saydean, “Higher Order Software — A Methodology for Defining Software.”, IEEE Trans. on Software Engineering Vol. SE–2, Nr.1 (March 1976), 9–32.
[1] | Hamilton, M. and Zeldin, S. “The Relationship Between Design and Verification.”, Journal of Systems and Software, Vol.1, Nr.1 (1979), 29–56.
[2] | Martin, James, “Program Design which Is Provably Correct.”, Savant Research Studies, Carnforth, U.K. (1982)
[3] | Cushing, Steve, letter to ACM Forum, Comm.ACM, Vol.25, Nr.12 (Dec. 1982), 951.

Plataanstraat 5 5671 AL NEUNEN The Netherlands | 7 April 1983 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow .

P.S. The day after the above was completed I learned that James Martin is on the board of Higher Order Software, Inc..

EWD

Transcribed by Bart Vreugdenhil
Revised 13-Nov-2014

EWD 853A

Ingenieur Ebergen, Weledelgestrengde Heer,

Uw afstudeerperiode is wat anders verlopen dan aanvankelijk voorzien doordat U de gelegenheid kreeg een semester als assistent mee te draaien op het California Institute of Technology te Pasadena. Want dat bezoek bleek meer dan alleen maar een onderbreking van enkele maanden. Het werk, dat U daar deed, was U zo goed bevallen, de problemen waar U daar mee werd geconfronteerd hadden U zo gegrepen, dat U mij vroeg, of U niet op die problematiek mocht afstuderen.

In de maanden, die daarop volgden heb ik mij niet zonder zorg, en soms zelfs haast met enig beginnend schuldgevoel, afgevraagd of ik er wel goed aan had gedaan U de gevraagde toestemming te verlenen. Ik zag namelijk aankomen, dat het langer zou duren dan het scherpomlijnde onderwerp, dat ik U aanvankelijk had opgegeven. En misschien zou het zelfs wel aanzienlijk langer duren. U kunt zich voorstellen, dat ik me wel eens wat bezwaard voelde. Gelukkig wekte U niet de indruk zich bezwaard te voelen: in tegendeel, mag ik wel zeggen. U wekte, ten minste naar buiten, alle schijn van de bekende vis in het water.

Uw mededeling, dat U aan Uw afstudeerverslag wilde beginnen, werd met opluchting vernomen. Het is me daarna nog één keer zwaar te moede geworden, nl. toen we de eerste schets van het begin van Uw afstudeerverslag te zien kregen. Dat bevatte echt te veel abracadabra en we hebben U moeten wijzen op het recht van de afstudeerhoogleraar te begrijpen wat de abiturient opschrijft.

U hebt dat kennelijk heel goed in Uw oren geknoopt, want de volgende versie, die ook practisch de uitendelijke versie is, is voor het overgrote gedeelte een toonbeeld van compacte helderheid. En toen pas haalde ik verlicht adem. Ik geloof nog steeds, dat het oorspronkelijke onderwerp U aanzienlijk minder tijd zou hebben gekost; ik denk ook, dat het oorspronkelijke onderwerp waarschijnlijk tot een overtuigender werkstuk aanleiding zou hebben gegeven. Daar staat evenwel mijn overtuiging tegenover dat U in Uw worsteling met het door U zelf verkozen onderwerp ongetwijfeld ontzettend veel meer geleerd hebt dan met het oorspronkelijke onderwerp het geval geweest zou zijn. U hebt nu aan den lijve ondervonden wat er bij komt kijken als men nieuwe begrippen moet invoeren of nieuwe notaties moet ontwikkelen, allemaal zaken waar het oorspronkelijke onderwerp geen aanleiding toe zou hebben gegeven. Dat U in Uw afstudeerperiode zoveel geleerd hebt heeft mij met Uw keuze verzoend.

Het werk, dat U bij het Mathematisch Centrum gaat doen, zal ––als ik het goed heb begrepen–– in eerste instantie in het verlengde van Uw afstudeeronderwerp liggen. Ik vind dat wel leuk, want U had zo hoog, en aanvankelijk ook zo vaag gegrepen, dat het werk ten duidelijkste nog niet af is, terwijl het ten duidelijkste voltooiing verdient. Ik vind het ook een beetje jammer; in dat opzicht sta ik gelijkelijk tegenover de afstudeerperioden en de promotie: het is atlijd leuk als de jonge ingenieur c.q. de jonge doctor daarna heel iets anders gaat doen. Anders krijg je zo het patroon van de Amerikaanse Ph.D., die op zijn 25ste al het specialisme van zijn leven heeft gekozen. Te meer daar Uw onderwerp zoals dat heet "in het brandpunt van de belangstelling ligt", kan ik Uw continuering wel billijken. Bovendien hebt U genoeg levendigheid en flexibiliteit aan de dag gelegd om het vertrouwen te rechtvaardigen, dat U vroeg of laat wel weer van dit onderwerp los zult komen en iets anders leuks gaat doen.

Rest mij slechts U te feliciteren, de Uwen in deze gelukwens te betrekken, en U van mijn beste wensen te doen vergezellen.

Transcribed by Lucas Jacques
Revised 27-Dec-2016

EWD854

The fruits of misunderstanding

Some things, it seems, can only happen in the world of computing. The design of a new product is announced and the world is full of high expectations, but, when the product is ready and people start to use it, it fails to meet in a most blatant manner its main objective. It is a failure and one would expect it to recognized as such. Nothing of the sort: the original main objective is kindly forgotten and the vast majority believes the product to be a great success.

You may have another example in mind, I was referring to COBOL, whose main objective was to make the professional programmer superfluous and which is now the main vehicle for 3 out of 4 professional programmers. In the name of "ease of programming", "readability", "understandability" its verbosity was considered a virtue; in practice that same verbosity turned out to be one of it striking defects.

COBOL was not an isolated case. When in the 60's the promise of salvation by means of "higher-level" programming languages did not materialize, the slow response in batch processing was identified as the culprit that made efficient debugging impossible, and in the name of the fast response needed for debugging, "interactive programming" was introduced on a large scale. Its spread seems to have been totally unaffected by the fact that, in the mean time, controlled experiments had demonstrated that the beneficial effect of interactive debugging facilities on "programmer productivity" was at best marginal.

In 1968 we had the advertisement with a happily smiling Susie Mayer, who had solved all her programming problems by switching to PL/I. But when, a few years later, Harlan D. Mills and Ted Baker did their "model development" of the system for the New York Times, their team had to be strengthened by the additional of a PL/I expert.

But all this was long ago and won't happen again, because in the mean time we have discovered

(i) That interactive programming failed only because the communication channel between "end-user" and "work station" was too narrow a bandwidth: high-resolution colour screens and voice communication will overcome that limitation;

(ii) That PL/I failed because it did not cater for the needs of the "embedded programmer" and because it was insufficiently "portable" to be acceptable as a world-wide standard; these problems are now solved by Ada;

(iii) That the new generally admitted difficulty of rigorous programming is not so important after all, since it only applies to "programming-in-the-small"; in the "real-world" the problems of "programming-in-the-large" are much more pressing and for those "software engineering" is developing "programming support environments" with enough "intelligence" and "expert knowledge".

The invention of the slogans that will explain in 1990 why dreams (i),(ii) and (iii) turned into nightmares is left as an exercise for the reader.

The brutal fact is that a large part of the history of the computing can be written in terms of multi-million-dollar projects that failed. That may hold for other disciplines as well, but what seems unique to computing is that in most cases the future failure was already obvious at the moment the project was conceived. It is a long history of castles in the air, the one after the other, and the phenomenon is so persistent that it needs an explanation. How do we explain the persistent misjudgement of the technical issues involved?

The high failure rate could be explained by the assumption that the world of computing is largely populated by conscious quacks and deliberate frauds, but that is an explanation I reject because the underlying assumption is, firstly, too bitter to be healthy, and, secondly, wrong: by and large, the hopes are each time genuine. We obviously observe a wide-spread misunderstanding whose persistence is so remarkable that we cannot ignore it.

How do most people understand? What mean most people by "understanding something"? We seem to order our impressions to our satisfaction. Today the trees in our gardens are very restless; also the chimney is very noisy. But these observations are neither disquieting nor disturbing. I have my satisfactory way of coping with them: by booking them, as usual, under the heading "windy" I almost ignore them. And the next time I am taken on a sailing trip and the ocean waves are very restless, it is fine with me: after all, what is the difference between waves of water and waves of foliage? There is no difference if it suits our purpose not to introduce it. As we grow up we acquire our habits of thought and develop our metaphors --did you notice that I described the trees as "restless"? That was unintentional!--; They are characteristic for how we order our impressions and for how we use language.

The above tried to capture the most common way in which we seem to cope with novelty; when faced with something new and unfamiliar we try to relate it to what we are familiar with. In the course of the process we invent the analogies that enable us to do so.

It is clear that the above way of trying to understand does not work too well when we are faced with something so radically new, so without precedent, that all analogies we can come up with are too weak and too shallow to be of great help. A radically new technology can create such circumstances and the wide-spread misunderstanding about programming strongly suggests that this has happened with the advent of the automatic computer. (Nuclear weapons could very well provide another example of a discontinuity with which thinking in analogies cannot cope adequately.)

There is another way of approaching novelty but it is practised much more rarily. Apparently it does not come "naturally" since its application seems to require a lot of training. In the other way one does not try to relate something new to one's past experience --aware of the fact that that experience, largely collected by accident, could very well be inadequate--. Instead, one approaches the novelty with a mind as blank as possible and tries to come to terms with it on account of its own internal consistency. (It is like learning a foreign language without trying to translate back and forth to one's native tongue. This is clearly one's only hope is the two languages are only adequate for expressing very different thoughts: one has to learn to "think" in the new language.) My guess is that computing is such a novelty that only this second approach is viable, and that, consequently, we must try to free ourselves in this case from the habit of approaching the topic in terms of analogies.

To ease that process of liberation it might be illuminating to identify the most common metaphors and analogies and to see why they are so misleading.

I think anthropomorphism is the worst of all. I have now seen programs "trying to do things", "wanting to do things", "believing thing to be true", "knowing things" etc. Don't be so naïve as to believe that this use of language is harmless. It invited the programmer to identify himself with the execution of the program and almost forces upon him the use of operational semantics.

We should never try to come to grips with a huge set by looking at "enough" of its members, because that is so hopelessly ineffective. Ideally, the individual members disappear from the consideration and one deals with the definition of the set itself. In the case of understanding a program, we should not look at individual computations, ideally --i.e. for the sake of mental efficiency-- we should deal with the program in its own right, temporarily ignoring that it also permits the interpretation of executable code. All this is well-known --it is called the Axiomatic Method--. The point to be made here is that the use of anthropomorphic terminology erects a barrier for its application. One of the fruits of anthropomorphism in computing is that the most effective way of developing programs and reasoning about them is rejected on such grounds as "counter-intuitive", or "too abstract" and that is very serious.

I skip the numerous confusions created by calling programming formalisms "languages", except a few examples. We have had the general who wrote "Obviously, NATO is not interested in artificially simplified programming languages such as PASCAL." It also gave birth to the idea that a "living" programming language is better than a "dead" one. Not so long ago a branch of a large industry had received from the central facility of the company a program it had asked for, but the program had been written in PASCAL. The branch had an external software house translate it into FORTRAN "because PASCAL was not maintained".

And now we have the fad of making all sorts of systems and components "intelligent" or "smart". It often boils down to designing a woolly man-machine interface that makes the machine as unlike a computer as possible: the computer's greatest strength --the efficient embodiment of a formal system-- has to be disguised at great cost. So much for anthropomorphism. (This morning I declined to write a popular article about the question "Can machines think?" I told the editor that I thought the question as ill-posed and uninteresting as the question "Can submarines swim?" But the editor, being a social scientist, was unmoved: he thought the latter a very interesting question too.)

Another analogy that did not work was pushed when the term "software engineering" was invented. The competent programmer's output can be viewed as that of an engineer: a non-trivial reliable mechanism but there the analogy stops.

In contrast to the traditional engineer's mechanism, made of physical components, a program is an abstract mechanism, so to speak made from zeroes and ones alone. And this difference has profound consequences.

To begin with, a program is not subject to wear and tear and requires no maintenance. Yet the term "program maintenance" established itself, only adding to the confusion.

Secondly, the mechanism being abstract, its production is subsumed in its design. In this respect a program is like a poem: you cannot write a poem without writing it. Yet people talk about programming as if it were a production process and measure "programmer productivity" in terms of "number of lines of code produced". In so doing they book that number on the wrong side of the ledger: we should always refer to "the number of lines of code spent".

Thirdly, in the case of a physical mechanism, higher quality, greater reliability, greater precision, etc always induce higher cost. In the case of programs the correlation is the other way round since unreliability and high cost stem from the same source, viz. unmastered complexity. Yet, unreliability of commercial software is often defended by the remark that making the software better would have been too expensive.

Finally, the engineer's standard design paradigm does not work. He designs a thing to the best of his abilities, makes a prototype and tries whether it works satisfactorily. If not, he improves the design, and "repetatur". There are circumstances under which such interactive design is defensible; a necessary condition is, however, that the feedback loop can, indeed, be closed. And we know that with programs this is impossible, except with utterly trivial ones. For many a manager, for whom iteration by means of prototypes is the only design paradigm, this impossibility is so disconcerting that he is unable to see it. But is it a miracle that so-called "software engineering" became a movement devoted to "how to program if you cannot"?

The pre-computer object that offers the closest analogy to a well-designed piece of software is an equally well-designed mathematical theory. But also this analogy has its problems. It has a social problem: it is not very popular. Computing systems are sold to people that are expected to consider anything mathematical as the pinnacle of user-unfriendliness. It has, however, a more technical problem too.

The bulk of traditional mathematics is highly informal: formulae are not manipulated in their own right, they are all the time viewed as denoting something, as standing for something else. The bulk of traditional mathematics is characterized by a constant jumping back and forth between the formulae and their interpretation and the latter has to carry the burden of justifying the manipulations. The manipulations of the formulae are not justified by an appeal to explicitly stated rules but by the appeal to the interpretation in which the manipulations are "obviously" OK. By and large, the mathematicians form a much more informal lot than they are aware of.

Whether this informality is in general "good" or "bad" is neither here nor there. (There exists a type of mathematician with a puritan streak that feels guilty about it.) The point is that in most of computing this informality seems inappropriate when you wish to approach the topic mathematically. For this inappropriateness there are two reasons.

Firstly, by its very nature, each computing system embodies a formal system of some sort. We can of course (try to) hide this fact by giving it so many complicated --and ill-documented-- properties that in its capacity of a formal system it becomes an impossible one to use. Often this has happened by accident, sometimes this is done on purpose, the hope being that it becomes a suitable tool for informal use: such efforts can be characterized as trying to use a computer for the simulation of a non-computer and can be ignored in this context.

Secondly, the intrinsically discrete nature of symbol processing makes programming such a tricky job that --again: when we wish to approach the topic mathematically-- the application of formal techniques becomes a necessity. For safety's sake the reasoning has to be carried out mostly by rule-governed manipulation of uninterpreted formulae: the intuitive justification of these manipulations becomes for combinatorial reasons too error-prone.

There is a further aspect in which computing science, when regarded as a branch of mathematics, differs from most of the pre-computer mathematics. Traditional mathematics has subdivided itself into many different branches, each with its own specific body of knowledge. (This to the extent that, by now, the complaint that mathematicians from different branches can no longer communicate with each other is a very common one.) As a branch of mathematics, computing science differs from others in that the size of its body of relevant mathematical knowledge is relatively small. There was a time when I blamed the topic's youth for that circumstance and felt that the building up of such a body of knowledge would be a worthy goal. It never acquired, however, the status of one of my explicitly stated purposes in life, and, as time went by, it just faded away. The relative irrelevance to the core of the topic of much specific knowledge is, in retrospect, quite well understandable: it is a direct consequence of the fact that computers are truly "general-purpose" equipment. Extending the body of knowledge faded away as a purpose, when developing the "quo modo" began to absorb much more of my attention than developing the "quod". (I never felt attracted by the description of education as "knowledge transfer"; now I know why at least in the case of computing science that term is even very inadequate.)

If --as I am beginning to believe-- the relatively modest role of knowledge is intrinsic to the topic, this will be reflected in our way of teaching the topic. What nowadays is called "methodology" will play a larger role in the teaching of computing science than it has done so far in the traditional teaching of mathematics. Since, all over the world, the practise of mathematics is so tightly interwoven with its teaching, this last aspect in which computing science differs from the most of the rest is felt very much. It is a difference that cannot be glossed over. As a consequence of it, many computing scientists are hesitant to stress the mathematical nature of their topic for fear that this will be misunderstood as a plea for "more analysis, more statistics, more algebra and group theory" in the curricula, while what they meant was more rigour, more elegance, more hygiene and more convincing logic.

And here we have the full scope of our difficulties. With yesterday's words we have to plan today for tomorrow, and, the computing challenge being without precedent, the words are no good. If we don't coin new terms, we have to give new meanings to old words. Regrettably, the world of computing seems better at coining new terms for old meanings (or without any meaning at all).

Plataanstraat 5
5671 AL NUENEN
The Netherlands
19 May 1983
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by William G. Sirett (London,2003)
revised Mon, 2 Aug 2004

   EWD 855

Trip report E.W.Dijkstra, Barcelona 5-7 June 1983.

I left Nuenen on Sunday morning at 7:40 and returned on Tuesday evening at 23:10. (Marcus, my elder son, drove me to the railway station; Ria did not feel like driving, having just returned from the hospital, where she had been subjected to a back puncture.)

On my way to the airport I had a narrow escape. Maintenance of one of the railway bridges had been scheduled for that Sunday morning, and that would have caused a considerable delay. But the water level of the rivers was so high that the maintenance had been cancelled, and I arrived at Schiphol well in time.

The KLM flight, during which I started refereeing a (too?) long article submitted to ACTA INFORMATICA, was smooth, and dead on time. I set foot —for the first time in my life— on Spanish soil. My secondary hosts, Fernando Orejas and Pere Botella of the Facultat d'Informàtica of the Universitat Politècnica de Barcelona, met me at the airport.

My primary host was Benno Aladjem, Chairman of the Program Committee of the Convencion Informatica Latina. That conference would start on Monday and Aladjem had asked me to deliver the opening address. After I had made all travelling arrangements I learned that the conference would start on Monday at 17:00. As a result I gratefully accepted Orejas's invitation to visit his Department of Computing Science as well.

After we had gone to the hotel and I had checked in, Orejas and Botella showed me the medieval part of the city, which was within walking distance from the hotel. Having recently observed how personal computers are being pushed down our throats, I saw Gothic cathedrals with other eyes. Not too successfully I had always tried to understand the phenomenon of those huge medieval churches as manifestation of a collective devotion I could no longer reconstruct. This time I looked at them as technology-driven products, and each time I wondered why these churches had been built I saw visions of people enamoured with the realization that they knew how to do it. It even supplied a plausible explanation for the most absurd ornaments (of which Barcelona now has many). After a few hours we parted.

The hotel was quite modern (meaning that it is practically impossible to write in your room). I read the International Herald Tribune, which had been given to me on the plane, and listened to classical music —I had my (very portable) FM receiver with me—. At 21:00, Aladjem would collect me for dinner.

He phoned me at 21:05 that he was on his way; he arrived a quarter of an hour later. The first restaurant he took me to was closed; so was the second one. The third one was open, but only for the invited guests of a party. He drove me all through Barcelona and I have lost count of the number of closed restaurants we met on our way. It was absolutely ridiculous. Eventually, well past 23:00, we ended up in a fish restaurant. There I learned that Catalan is a language to be spoken very loudly in public places; but the food was very good: I had (white!) asparagus, followed by grilled (genuine!) sole.

The next morning, Botella collected me at 9:15 and took me to the Department, which is temporarily housed in a deserted nunnery. It was the beginning of a nice, but long, day.

General discussion started, and it did so very quickly since both Orejas and Botella, who —at different occasions had both been in my audience— were very familiar with my work. (Botella told me he owned a copy of my "Notes on Structured Programming" since 1969, the year I typed them! That that text had been circulated at such an early date in Spain was new for me.)

Suddenly it was 11:00 and I had to give my lecture. It went very well, though I was a bit short of blackboard space. Had I had more blackboards I would have manipulated my regular expressions with the same degree of detail as I had done several weeks ago at Imperial College, London. The mathematics was still quite fresh and the audience was duly surprised by this unusual application of regular expressions.

At 13:00 the talk was over and I was taken to the Dean's Office, where I was the first to sign the young Department's "Guest Book". Then lunch until 15:00.

At 15:30 we were at the Congress Centre. I had been asked to be interviewed for the Catalan journal of science, and the next hour was devoted to that interview. After 30 minutes meditation I was ready to give my opening address. From 17:00 to 17:45 we had the official speeches; I spoke from 17:45 to 19:00. I had tried out my visuals two months ago in Helsinki, where I had to speak at a very similar occasion. The Helsinki rehearsal was better than the Barcelona performance. There was simultaneous translation into Spanish, Portuguese, and French, but it was not too simultaneous. I could hear all three interpreters and found it very distracting to hear how far they were lagging behind.

The Convencion Informatica Latina was embedded in a fair/exhibition; after the reception I was taken to the (most impressive!) office of the director of the fair where I was asked to sign the golden guestbook of the fair; it was the first time I signed in the presence of clicking cameras. It was very funny! With three people of the University of Barcelona and two from Madrid I had a nice Catalan dinner.

The next morning the interview for the Catalan science journal continued until Orejas took me to the Airport. Shortly after 16:00 I was back on Dutch soil. I went home by train, interrupting my journey at Leyden where I had a dinner appointment with Andrei P. Ershov from Novosibirsk. Ershov was in Leyden for a conference on teaching and told me that in Siberia he had been "fighting violently" the introduction of BASIC in the secondary school system. His profound disapproval of BASIC did not surprise me —he is knowledgeable enough—, the fact that the battle had to be fought in Siberia was new for me.

I left Leyden with the 20:58 train, changed in Rotterdam and came home at 23:10. There I was chagrined to learn that Ria's "post-punctural" headache had not subsided. Two days later she was treated for that, the day before I left for the USA.

California Institute
        of Technology
PASADENA
United States of America
13 June 1983
prof.dr.Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sat, 22 Jan 2005

EWD856-0

On maximising a product

The problem is to construct a set of positive integers with given sum such that their product is as large as possible.

The first observation is that we need not include integers ≥ 4. The reason is that such an integer k can be replaced, without changing the sum, by the two integers 2 and k-2, thereby replacing in the product a factor k by a factor 2∙k - 4 and that we don't lose if 2∙k - 4 ≥ k, i.e. if k ≥ 4.

The second observation is that 1 only needs to be included if it is the only integer in the set, i.e. if the given sum equals 1. In all other cases we can increase the product without changing the sum by removing the 1 (which does not contribute to the product) and increasing one of the other integers by 1.

In the general case this leaves us with a set of 2's and 3's. The final observation is that we don't need to include 3 or more 2's: 2+2+2 = 3+3 but 2∙2∙2 < 3∙3.

*                *
*

We solved this problem a number of years ago (and were not the first to do so), but in my memory the argument was less clean than above. It was more or less polluted by

EWD856-1

the circumstance that the answer is not unique if the given sum is of the form 3∙n + 4: two 2's may be replaced by one 4.

Another way of complicating the first observation is to treat even and odd values separately, e.g. comparing for k = 2∙x the value 2∙x with x², and for k = 2∙x + 1 the value 2∙x + 1 with x∙(x + 1).

California Institute of Technology
PASADENA, CA 91125
United States of America

14 June 1983
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Sat, 20 Sep 2003.

EWD 857

Generalizing an old formula

It all started with a discussion about the role of pictures as substitute for calculational proofs. I was reminded of the pictorial illustration of the theorem that the sum of the first  n  odd natural numbers equals n²:

Immediately the question rose whether this formula can be generalized to higher powers of n, since from the 4th power onwards, visualization breaks down.

By mentally cutting 3 mutually orthogonal slices of thickness  1  from a cube of  n  by  n  by  n , one can convince oneself that

n³ = (S i: 1 ≤ i ≤ n: i² + i�(i-1) + (i-1)²)

and one begins to suspect the validity of

n⁴ = (S i: 1 ≤ i ≤ n: i³ + i²�(i-1) + i�(i-1)² + (i-1)³)

and similar formula, in general

nk = (S i: 1 ≤ i ≤ n: (S j: 0 ≤ j < k: ik-1-j�(i-1)j)). | (0)

This holds provided

nk = (S j: 0 ≤ j < k: nk-1-j�(n-1)j) + (n-1)k | (1)

because (0) holds for  n=0 , while (1) then provides the step for proving (0) by induction over  n .

We prove (1), which holds for  k=1 , by mathematical induction over  k:
       nk = (S j: 0 ≤ j < k: nk-1-j�(n-1)j) + (n-1)k
≡ { multiply both sides by n; n = 1 + (n-1) }
       nk+1 = (S j: 0 ≤ j < k: nk-j�(n-1)j) + (n-1)k + (n-1)k+1
≡ { definition of summation and n⁰ = 1 }
       nk+1 = (S j: 0 ≤ j < k+1: nk+1-1-j�(n-1)j) + (n-1)k+1

q.e.d.

The above was just for the record. I find the above double induction satisfactory and formula (0) was new for me.

Observation. In the mean time I asked people from five different countries: none of them had seen the above picture at school. We all agreed that that was a pity. (End of Observation)

Burroughs Austin Research Center AUSTIN, Texas | 25 June 1983 prof. dr. Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD858

Trip report E.W.Dijkstra, USA, 10 June - 3 July 1983

Ria being unable to see me to the station, I took a taxi to Eindhoven. I took the train to Amsterdam Central Station and from there the KLM coach to the Airport. (I found this the fastest and most reliable way of going to Schiphol.) Flight KL641 to New York had very strong headwind, once changed from 33.000 to 29.000 feet and was not as smooth as usual. As a result I did not write; I read the latest issue of "Daedalus" instead, which was devoted to the topic of "Scientific Literacy". (John G. Kemeny, co-inventor of BASIC and for 11 years president of Dartmouth College, gave a striking example of superficiality: he argues that computer literacy is more easily attained than scientific literacy because programming languages are simpler than natural languages.)

At JFK, immigration was as usual, so that my suitcase had arrived when I entered the customs hall. There the introduction of a "Green Line" had been a great improvement; I delivered my suitcase to the inter-airline luggage service and walked at leisure to the PanAm building, where a relative chaos reigned. All their planes were delayed, we had to change gates, the public address system was a composition of distortion and echo. I arrived an hour late at Washington National Airport, where I was collected by my host Steve Olson. (He had phoned the Washington office of PanAm after the scheduled departure time of my flight: while the plane was still firmly on the ground he was told that the flight was on time!)

I made this one-day stop in Washington to give Olson the opportunity to complete an interview that we had been conducting by mail since last Christmas. (The article is to appear in Science 83 --or, as the case may be, Science 84-- the bi-monthly of the American Association for the Advancement of Science.) The visit also served as a buffer for the time shift between Amsterdam and Los Angeles, and did so very well: I was interviewed until 23:10 and slept the next morning until 6:00. Olson told me that one of IBM's vice-presidents had been quoted, saying that computer science was irrelevant for his company's business. If true, this is bad news for IBM's customers.

Late in the afternoon I flew to Los Angeles with United Airlines, whose conveyor belt at Dulles Airport had broken down. The flight was delayed, the scheduled DC10 had been replaced by a DC8 with a spare crew, and we were combined with the passengers of an earlier flight, which had been cancelled. All my remaining flights, however, would be dead on time.

At LAX I was met by Martin Rem (who had arrived there the day before) and Alain Martin with his little Jerôme. On our way to Pasadena we generalized the relation that the sum of the first n odd numbers equals n² (see EWD857).

It was very nice to meet the family Martin again, whose guest I would be for the next 4 nights. On Sunday Alain and Marianne gave a brunch in their garden for 35 people + their assorted offspring. (This was at the occasion of the 10th anniversary of their wedding.) Marianne had done all the cooking --including the paté's-- herself, and I was deeply impressed. The next two days I spent at CalTech, writing, discussing with colleagues, talking to the provost, lunching with the dean of the division, and finally giving a very technical talk, which was well received. (Though it was after Commencement, I had quite an audience.) The new provost clearly wishes to strengthen CalTech's computer science, but the division itself seems hesitant (or divided) about its direction. I doubt that avoiding the dichotomy between theory and practice has been given the priority it deserves.

On Wednesday morning I took the coach from Huntington Sheraton, Pasadena, to LAX. (Warning for future users: it arrived at LAX 35 minutes behind schedule.) The Western Airlines flight to San Diego was excellent; at Lindbergh International I was collected by Dr. L. D. Rogers of Burroughs, whose guest I would be for the next 5 nights.

On Thursday evening, after cocktails and dinner, I lectured from 20:00 till 22:00 to about 100 members of the San Diego Chapter of the ACM, on Friday afternoon I gave a (more technical) talk at Burroughs SDRC (= San Diego Research Center). I had a number of useful meetings (Dr. L. Shevel and I were introduced to each other, I met Don M. Lyle, had a long discussion with Mrs. Janet Graessle about "the dual career ladder" and spoke with Robert F. Lakin --Director, University Relations-- about publications.) My schedule at SDRC was, however, too tight. I was shown a number of projects, but I did not see enough to give any deep comments

On Sunday, Laurie and Joy Rogers took me to "Seaworld" to see the more than 350 penguins at the new Antarctic Exhibition. This was fascinating! Also fascinating was a common murre that we have observed for almost half an hour playing under water with a pebble. We spent quite a while at a big pool in which a dozen dolphins were playing. All animals were obviously in excellent condition: I was impressed by the competence with which they were taken care of. (Minor example: near the big pool was a kiosk where one could buy little fish to feed the dolphins, and when the dolphins had had enough, the kiosk closed. Simple, but very effective.)

On Monday I flew with American Airlines via Dallas to Austin. The flight to Dallas was so punctual that I could catch an earlier flight to Austin, which was boarding when I arrived. And even my suitcase made the connection! In Austin I called Dr. H. Richards Jr. of Burroughs ARC (= Austin Research Center) to tell him that I had arrived earlier and that he need not hurry since I had found a nice quiet cool table to work at. He came about an hour later, we rented a Toyota Celica in which I drove under his guidance to Lakeway. For the next two days we would have a small conference --about two dozen people-- on Program Verification. From outside it was attended by Donald I. Good, Robert S. Boyer and J Strother Moore of the University of Texas.

Speakers were Clark Weissman, John Scheid, Val Schorre, Debbie Cooper (SDC, Santa Monica), Deepinder Sidhu (SDC, Paoli), Don Good and J Moore (University of Texas), David Turner (University of Kent), and I. We had a blackboard and overhead projector --I even used the latter--. Visuals that had been prepared for other occasions were rarely satisfactory. For me, seeing J Moore at work with a piece of chalk at the blackboard was one of the highlights; David Turner's talk was another one.

I found the conference interesting. One message came through loud and clear: formal techniques have an increasingly important rôle to play. There also seemed to be a reasonable consensus that that rôle should not be confined to verification "after the fact", so to speak, but that correctness concerns should guide the design process. Due to my presence, the feelings on the need for mechanization were more mixed. It was quite clear that the effort at mechanization has a strong influence on one's quality criteria for proofs. In some mechanization circles it seems no longer required that proofs be "elegant" in the sense as given by the Concise Oxford Dictionary: "ingeniously simple and effective". But when this results in proofs of 8000 or 13000 pages (!), I feel strengthened in my judgement that elegance is not a dispensable luxury.

Texas was warm. I had left xerographic copies in my briefcase in the car, and the ink had melted. Late Wednesday afternoon we returned to Austin. The remaining 2 days of that week and the first 4 days of the next week I spent at ARC. It was an unfortunate coincidence that two of these days were occupied by a meeting between people from SDRC and ARC (on an organizational topic, on which I had little to contribute). I gave one talk for a sizeable audience, and a tentative one for an audience of two. When I did not have a discussion with others, I just worked in my office.

Friday the 1st of July I spent at the University of Texas. (Burroughs had that day a so-called "floating holiday".) Misra and Chandy showed me a beautiful theory about distributed systems (with FIFO channels), for which part of the credit was given to Leslie Lamport. But the major part of the days was devoted to planning for the Department of Computer Sciences since the University of Texas has set itself the goal of developing that department into one of the country's centres of excellence in the field. (I found it very interesting to see how they tackled that task.)

I left Austin on Saturday around noon for Atlanta with Delta Airlines, and that was as pleasant as a flight can be. In Atlanta, the KLM ground service was taken care of by personnel of Eastern who did an excellent job --so excellent that I told it to the KLM purser--. The KLM flight to Amsterdam left 10 minutes late, but the jet stream was so strong that we arrived in Amsterdam 30 minutes ahead of schedule. I had been seated on the upper deck and had had some sleep.

Wim Feijen and Netty van Gasteren were at Schiphol to collect me and at 13:00 I was at the hospital where Ria had been operated [on] 3 days earlier.

*                            *
*

At my request I was given the outline of the design of an avant-garde machine. Mark Scheevel did an excellent job, for explanation and discussion together did not take more than two hours. He explained it so clearly that I could suggest a modification, which was estimated to improve performance by 10-15% at little or no cost. That, of course, was fun, but I am most delighted by the reason why I could make that apparently helpful suggestion at a glance: the design as presented violated one of the principles for a well-written (mathematical) article that have been discovered during the last year or so by Netty van Gasteren and me. I found that a very nice example of unexpected transfer --typically the kind of thing no form of research planning can ever anticipate.

*                            *
*

During my absence Ria had saved an article in the paper about French computing. It draws attention to the fact that, though neither the "Plan Calcul", nor its successors had been able to create a viable French computer industry, the French software industry was flourishing like nowhere else. This last observation was convincingly linked to the fact that the French secondary school system still takes the teaching of mathematics seriously. (Think what the French could have done if that teaching had not been infected by Bourbaki!)

*                            *
*

During a discussion about MCC ("an effort to out-Japanese the Japanese") software engineering was characterized as what those companies cling to that have given up hope that they will ever learn how to do the programming job properly. That makes software engineering's popularity a wide-spread cry of despair.

Plataanstraat 5
5671 AL NUENEN
The Netherlands

10 July 1983
prof. dr. Edsger W. Dijskstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sun, 14 Mar 2004

AvG29 / EWD861

Research Proposal

Drs. A.J.M. van Gasteren and prof. dr. Edsger W. Dijkstra.

Abstract. Our effort has been inspired by the impression that the effectiveness of the average mathematical argument can be greatly increased; our aim has been to confirm that impression by discovering general techniques for effectuating such improvements.

The impression was correct; even many a not-so-average mathematical argument turns out to leave room for considerable improvement.

Great improvement could be achieved by assigning a greater rôle to calculi of all sorts, the predicate calculus in particular. In view of the intrinsic generality of the predicate calculus — as stratification of all rigorous reasoning — its development into a workable tool was made a major focus of our efforts.

Techniques other than calculational, developed so far, are also effective beyond the environment of mathematics.

We envisage the next phase to be devoted to tasks such as
(i) the development of calculi and the extension of their range of applicability;
(ii) learning how to design suitable notations that cater for one’s manipulative needs;
(iii) discovering how to propagate, explain, and teach what we have learnt by trying to propagate, explain, and teach it.

Our plans for the years to come

“It is reasonable to hope that the relationship between computation and mathematical logic will be as fruitful in the next century as that between analysis and physics in the last. The development of this relationship demands a concern for both applications and for mathematical elegance.”

John McCarthy, 1967

Two accidents of history have retarded the widespread recognition of programming as a mathematical activity. The one accident was the development of average programming practice, in which programmers without mathematical inclination are fully absorbed by the intricacies of their tools and the fuzziness of their tasks. The other accident is that the style of mathematics the programming task requires turned out to differ so radically from the style of mathematics developed so far, that most mathematicians (including authoritative ones) failed to recognize programming as a human endeavour amenable to mathematical treatment. (In addition, the existence of computers that can execute the programs has misled people to believe that program correctness is an experimental notion, thus adding to the confusion.)

The mathematical styles in which proofs are conducted are the product of slowly developing traditions. In principle, these traditions are very pragmatic: mathematicians do not like to waste their time on demonstrating the obvious. Each time, however, that something is accepted as “obvious”, a certain risk is taken; in mature branches of mathematics there is a well-established consensus about which “risks” can be taken safely, and in that sense established styles are adequate.

Taking an example from plane geometry, we consider four points on a circle. These points determine six chords, a, b, c, d, e, and f, say.

The three possible pairings of the points give rise to three pairs of chords, viz. (a,c), (b,d), and (e,f). An example of an “obvious fact” is the statement that of the three pairs of chords one pair intersects inside the circle — (e,f) in the above — and two pairs intersect outside the circle. Practical reasons fully justify an appeal to this fact without proving it. In contrast with this, most mathematicians agree that the validity of the relation     e ⋅ f = a ⋅ c + b ⋅ d     between the lengths of the chords requires a proof. As a result, the statement has been given a name (it is the theorem of Ptolemy).

We point out that the existing styles just grew, are rarely the result of well-considered choices, and are by no means necessarily the most effective ones. Moreover, there is no reason to assume that, having grown in response to actual demands, they are adequate in new areas of mathematics.

The intellectual content of the “computer revolution” seems to be that the design of programs we can justifiedly rely upon faces us with mathematical problems that are in a very true sense without precedent in the history of mathematics. It means no more and no less than that we must be willing to question the adequacy of all sorts of time-honoured mathematical traditions.

The reason why the mathematical challenge of programming seems to be so radically new lies in the combination of the following circumstances:
(i) Programming is a problem area without effective “intuitive support”. With the latter we mean what the “picture” is for the geometer; for the programmer the “intuitive support” would be the class of possible computational histories that correspond to a program. Experience has shown, however, that this class defies imagination: the combinatorial explosion of operational arguments makes them ineffective, and, therefore, we have to resort to non-operational arguments. As a result, it is an area in which the “intuitive support” is very meagre.

(ii) In mathematics, the absence of “intuitive support” has always been countered by the application of the formal techniques of calculi. In view of the fact that, by virtue of its mechanical interpretability, each programming notation embodies eo ipso a formal system of some sort, a systematic application of calculi (logical or other) seems, indeed, indicated. This puts programming in principle on mathematically familiar grounds: program specification and program text are treated as formulae and a calculus is applied to demonstrate that the later satisfies the former. The crux of the matter is, however, the proviso “in principle”: viewed as a formula, a program text is several orders of magnitude larger than the formulae mathematicians are wont to work with, and this has a profound consequence. Manipulative techniques that engender an amount of formal labour growing quadratically or exponentially with formula length are quite acceptable in the familiar mathematical environment, in which formulae are short; in our environment they are just no good. Hence, the effectiveness of our manipulative techniques suddenly becomes a novel and major concern.

*                       *
*

Our long-range target is thus the design of much more effective mathematical arguments. When studying the shape of arguments and comparing alternatives, we quickly discovered that in such a study of effectiveness the subject matter of the argument was of secondary importance and that we need not restrict ourselves to examples taken from computer programming. The decision to extend our explorations to mathematical arguments in general provided the added advantage — besides offering more variety in our experiments — of giving us the opportunity to compare our proofs with traditional ones, which, unlike in the field of programming, are amply available in the literature.

In the first state of our explorations we concentrated on the presentation of arguments. (Topics of study were, for example, the choice of an appropriate size of logical steps in an argument and the problem of whether to introduce names for elements in the argument — such as the points on the circle in the geometrical example given in the preceding.) We did so for the practical reason that comparison of alternative arguments requires a homogeneous style of presentation, and for the more significant reason that we felt — and rightly so! — that there was in general much room for improvement.

Gradually we got involved in exploring ways, other than presentation, of making arguments more concise. Exploitation of symmetries and reduction of the rôle of case analyses were the obvious techniques towards this goal. Since too large logical steps in an argument engender the danger of logical errors and often leave the reader puzzling why the steps are legitimate, we adopted as our ideal a homogeneous degree of rather fine detail. Striving for both more conciseness and fine details, we found ourselves drawn to the use of formal techniques.

We began our experiments with combinatorial problems, which could be treated effectively by using the calculus of plain arithmetic. The predicate calculus was the next one to be used extensively. Lately, regular expressions were used calculationally, in a surprising context and at great calculational advantage.*) (For this purpose we needed a “regularity calculus”. Parts of it we had to develop ourselves: in the literature we found no traces of such calculational use of regular expressions.)

- - - - -

*) to be presented at a Discussion Meeting on “Mathematical Logic and Programming Languages”, to be organized on 15th and 16th February, 1984, under the auspices of the Royal Society of London. The proceedings will be published in the Philosophical Transactions and also as a separate Monograph.

- - - - -

Concerning our use of the predicate calculus to date, several remarks are in order.

(i) In order to forge the predicate calculus into a workable tool, we had to improve on the existing notational conventions. For instance, we designed a uniform notation for so-called “continued” symmetric, associative operators — such as summation —, in order to avoid the unnecessary notational distinction between, for example,     ∑²⁷i=n     and     maxn ≤ i ≤ 27     in     ∑²⁷i=n i²     and     maxn ≤ i ≤ 27 i². Instead, we write (∑i : n ≤ i ≤ 27 : i²)     and     (max i : n ≤ i ≤ 27 : i²). The symbol “i” following ∑ and max in the last two formulae indicates another innovation. In so-called “quantified” expressions like the above, we explicitly indicate, syntactically, which of the variables are the so-called “dummies”, in order to avoid ambiguities such as     max a ≤ x x + a², which indistinguishably stands for (max a : a ≤ x : x + a²)     or     (max x : a ≤ x : x + a²) — two very different formulae.

During our explorations, the arising need for such notational innovations was an encouraging confirmation of our impression that we were pursuing an as yet unexplored line of research.

(ii) We have used the logical connective of equivalence at great calculational advantage in preference to the logical connective of implication, often leading to a reduction in size of the argument by a factor of 2 or more. This experience could well be of great methodological significance since, on the one hand, it is this century’s tradition to base mathematics on set theory, whereas, on the other hand, set theory lacks the analogue of the logical connective of equivalence.

Recent information (from J Strother Moore) casts a completely new light on the rôle of equivalence, which suggests a different explanation for the fact that equivalence is used so rarely in traditional mathematics. The use of the equivalence is tantamount to so-called “symmetric rewrite rules”, which are shunned in automatic theorem proving because they allow the manipulative process to get hooked up in an endless loop — e.g. replacing A by B, then B by A, and repetatur ad infinitum —. A fear for similar dead ends may subconsciously underly the underexploitation of the equivalence in traditional mathematics.

(iii) Our experiences indicate that the predicate calculus in the form and notation that we developed for it over the last years is quite generally applicable. This, we propose to demonstrate in the next phase.

Among the recent results of our work, we mention the following two incidents:
(i) the efficiency of a computing machine (still on the drawing board) could be improved at a glance by more than 10% at the price of a very minor modification: the design violated one of our principles for a well-shaped mathematical argument;
(ii) our stress on the fact that 0 and 1 are very natural numbers, led to a significant simplification in a work on VLSI design; the simplification was obtained by identifying characters from an alphabet with one-character strings, and the empty string with the 0-element of the concatenation operator; as a result, two originally distinct functions — one on characters and one on strings — merged into one.

*                       *
*

We expect that in the next phase design, use, and propagation of calculi will form an important part of our activities. Our main goal remains what it was, viz. the streamlining of the mathematical argument — “streamline: [...] simplify, make more efficient or better organized”, Concise Oxford Dictionary —; over the last years we have learnt to appreciate calculational arguments — when available! — as effective means of streamlining, and extending their range of applicability has, therefore, become a significant subgoal.

In its wake, we hope and expect to come to grips with the problem of the design of suitable notations. (Most mathematicians agree that for many mathematical developments the availability of a good notation has been crucial; in this light it is surprising that the design of notations is not a topic explicitly addressed.) The systematic application of calculational techniques is expected to provide the necessary guidance: by virtue of their rather rigid format they will reveal more clearly the manipulative needs to which the notation should be geared.

Another thing we propose to do is to try to establish (by experimental exploration) the more general validity of a number of still tentative observations. For instance, in a number of cases we have observed that the explicit statement of what is considered “obvious” often allows the rest of the proof to be carried out in a more calculational manner. We suspect this to be the case in general.

In the mean time more macroscopic concerns are emerging. The clear delineation of the scope of all sorts of conventions is one of them (“scope” is the technical term for that part of a text to which a definition, convention, or assumption pertains); though important, it does not seem to raise profound problems. Tougher seem more structural problems such as the optimal size of scopes and the best interface between logical modules of the argument. (We seem to have collected evidence that striving for small size scopes results in more disentangled arguments, and that the “usefulness” of theorems depends more on the simplicity of their formulations than on, say, the complexity of their proofs.)

In a next phase, when we expect to have obtained a clearer and convincing picture of “true elegance”, we shall address ourselves more fundamentally to heuristics, i.e. the problem of how to construct a truly elegant argument.

*                       *
*

Concerning the ways in which our efforts can contribute to BP as industrial enterprise we see three aspects.
(i) More effective ways to doing mathematics are of immediate relevance for BP in its capacity of employer of mathematicians and computing scientists.
(ii) Our methodological techniques — such as “separation of concerns” —, though primarily developed in the context of intricate mathematical arguments, are quite general and of wide applicability; the mathematical arguments have served as “laboratory environment” in which these techniques could be explored in vitro.
(iii) Our efforts should assist BP in its continuing transition into a company more and more involved in high technology: “elegance” — in the technical sense in which we use the term —, formerly only nice, is now absolutely essential.

For all this to bear fruit, an effective dialogue with BP staff is necessary; our first experiences in this respect have been very encouraging.

transcribed by Jonathan David Arndt
revised 04-Jan-2021

EWD862-0

A sequence with |xn| = xn-1 + xn₊₁ has period 9

Recently I heard the theorem that any (in both directions) infinite sequence of real numbers xn such that for all n

|xn| = xn-1 + xn₊₁

(0)

has a period of length 9. Here is my proof.

p

p + r

(≥ 0)

r

(≥ 0)

-p

(≤ 0)

p - r

(≥ 0)

2∙p - r

(≥ 0)

p

(≥ 0)

r - p

(≤ 0)

- r

(≤ 0)

p

(≥ 0)

p + r

From (0) we conclude (i) that the sequence contains a nonnegative element, (ii) that one of its neighbours is nonnegative, and (iii) that at least one of the two elements adjacent to a pair of nonnegative neighbours is nonnegative. More precisely: the sequence contains in some direction a triple of adjacent elements of the form (p, p+r, r) with 0 ≤ r ≤ p. To the left we have extended the sequence with another 8 elements. From (0) we further conclude that the whole sequence is determined by a pair of adjacent values; hence, the repetition of the pair (p, p+r) at distance 9 proves the theorem. [The above deserves recording for its lack of case analyses.]

Plataanstraat 5
5671 AL NUENEN
The Netherlands

1 September 1983
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Tue, 24 Jun 2003.

  EWD 864

The distributed snapshot of Chandy/Lamport/Misra

[The algorithm dealt with in this note was shown to me on 1 July 1983 by K. Mani Chandy and Jayadev Misra —both of the University of Texas at Austin— who gave considerable credit to Leslie Lamport —of SRI International—. The next 8 weeks or so I was otherwise engaged, then the last 2 sessions of the Tuesday Afternoon Club were devoted to it. The first session was devoted to a reconstruction of the problem and of its solution and to a summary of our proof obligations; in the second session we devised the correctness proof given below. If I failed to do justice to the algorithm, I offer my apologies to its authors.]

We consider a finite network of sequential machines, strongly connected by uni-directional, first-in-first-out message buffers, and such that its activity can be described as a succession of atomic actions. Each atomic action takes place in one machine, may comprise the reception of one message from one of the machine's input buffers and may comprise the sending of at most one message per output buffer. Necessary initial conditions for an atomic action to take place are (i) that the machine in question is in an appropriate state, and (ii) that the buffer in question is not empty if the atomic action includes receipt of a message.

The state of the network is deemed to be fully described by the states of all machines and the contents of all buffers. For a given network a predicate is called “stable” if none of the atomic actions can falsify it, or equivalently, if it holds in all states reachable from a state in which it holds. (For example, in the now classical case of a diffusing computation the predicate “the diffusing computation has terminated” would be a stable predicate; in a token-preserving network the predicate “the number of tokens travelling the network equals 7” would be stable.)

Finally we assume some fairness, more specifically that the system's nondeterminacy is resolved in such a manner that each message entering a buffer eventually leaves it at its other end. (Any daemons ensuring this fairness are not considered to be part of the system.)

The execution of the snapshot algorithm to be designed is merged with the network's original activity; its purpose is to collect information allowing the detection that a stable state has been reached.

To this end

the repertoire of messages is extended with one new message, called “the red letter”,

each machine is equipped with a bit recording whether the machine is white or red

each machine is equipped with a bit for each of its input buffers, recording whether that input buffer is white or red,

the repertoire of atomic actions is extended —and modified, see later— with atomic actions for the receipt of red letters.

Initially all machines and all buffers are white. The snapshot algorithm is fired by one of the machines —the “starter”— by acting as if it has received a red letter (from “nowhere”').

As far as red letter traffic and colouring is concerned, the atomic action describing the receipt of a red letter is as follows:

the input buffer from which the red letter is received (was white and) becomes red —for the red letter received by the starter from “nowhere” this part of the atomic action is void—,

if the receiving machine was white, it sends one red letter over each of its output buffers and becomes red, if the receiving machine was already red, it remains so and it sends no further red letters

The above algorithm maintains the invariant that each buffer from a red machine to a white one contains precisely 1 red letter; on account of the fairness of that white machine, the latter will receive the red letter and turn red itself. Therefore, when the last machine has turned red, there is no buffer leading from a red machine to a white one; hence, all machines reachable from the starter are in the final state red. Since all machines are reachable from the starter, all machines are red in the final state. Since each buffer is the output buffer of some machine that has turned red once, each buffer has accepted 1 red letter: when the last red letter is received, the only still white buffer becomes red. The state of the network at that moment will be referred to as “the final state (of the snapshot algorithm)”; “the initial state (of the snapshot algorithm)” refers to the state of the network just prior to the atomic action in which the starter turned red.

So much for the red letter traffic. Its sole purpose is to trigger local snapshots, according to the following rules:

upon turning red, each machine records its own state,

each red machine records for each of its input buffers the stream of messages that it receives from that buffer as long as the latter is white. (For a buffer from which a white machine received a red letter, the empty string is recorded; for all other buffers, the string ends with the red letter carried by that buffer.)

Hence, the snapshot algorithm records a machine state for each machine, and a message stream for each buffer. The together comprise what is called “the snapshot state”.

Since the network is strongly connected, the record of the snapshot state can be collected in the starter, which then can investigate whether the snapshot state satisfies the stable predicate. (If not, the starter is supposed to start the snapshot algorithm a next time.)

In order to guarantee that it will be detected if the stable predicate holds, we shall prove about the snapshot algorithm

Lemma 0
      If the initial state of the snapshot algorithm satisifies a stable predicate, the snapshot state satisfies it.

In order to guarantee that no errorneous detection of stability can
occur, we shall prove about the snapshot algorithm

Lemma 1
      If the snapshot state satisfies a stable predicate, the final state of the snapshot algorithm satisfies it.

The two proofs are similar: in both cases we shall demonstrate that one state of the network is reachable from another. The proofs are rather operational in the sense that we shall take an arbitrary, but “fixed”, execution of the snapshot algorithm as our reference, to which we shall refer as “reality”; in addition we shall consider an identically constructed shadow network in which some of the atomic actions occurring in reality are faithfully copied, others suppressed. We shall describe this as if the two networks evolve in strict synchronism and shall define the states of the shadow network in terms of the given reality.

For the description of message streams we need some terminology with respect to the direction: a stream and a nonempty prefix of it contain the same oldest message; similarly a prefix of a stream is taken by omitting zero or more of its older messages; postfixing a stream is extending it at the end of its youngest message with still younger messages.

Proof of Lemma 0.

We have to show that the snapshot state is reachable from the initial state in reality. To this end, the shadow network starts in the same initial state as in reality and ends in the snapshot state (with all machines red).

In the shadow network we have at any moment

the colour of a machine is as in reality,

the state of a machine is:

for a white machine as in reality,

for a red machine as in the snapshot state,

the contents of a buffer are:

for a buffer from a white to a white machine as in reality,

for a buffer from a red to a red machine as in the snapshot state,

for a buffer from a red machine to a white one, from the contents in reality, the prefix up to and including the red letter,

for a buffer from a white machine to a red one, the record of incoming messages as recorded in reality by the red machine, postfixed by the contents of the buffer in reality.

To begin with, we observe that on account of (i), (ii, a), and (iii, a), the initial state of the shadow system coincides with the initial state in reality; and we observe that on account of (i), (ii, b), and (iii, b), the final state of the shadow system coincides with the snapshot state.

The correspondence between the two processes is as follows: to an action performed in reality by a white machine corresponds in the shadow network exactly the same action, to one performed by a red machine corresponds in the shadow network a skip.

The action of a white machine is possible on account of (i), (ii, a), and (iii, a) or (iii, c); it leaves (i), (ii), and (iii) clearly invariant if the machine remains white. If it turns red, we observe

ad (i): | that in both networks corresponding machines turn red simultaneously,
ad (ii, b): | that the snapshot is defined so as to establish the truth of (ii, b),

ad (iii, b):
if the machine for which it is an input buffer turned red, (iii, b) is established on account of (iii, c) and the definition of the snapshot state; if the machine for which it is an output buffer turned red, (iii, b) is established on account of (iii, d), the definition of the snapshot state and the fact that the machine postfixed the buffer contents with a red letter,

ad (iii, c): | on account of (iii, a) and the fact that buffer contents have been postfixed by a red letter,
ad (iii, d): | on account of (iii, a) and the fact that the machine just turned red has recorded so far an empty string of messages.

Proof of Lemma 1.

We have to show that the final state in reality in reachable from the snapshot state. To this end the shadow network starts in the snapshot state (with all machines and buffers white) and ends in the final state in reality.

In the shadow network we have at any moment

the colour of a machine is as in reality

the state of a machine is

for a white machine as in the snapshot state,

for a red machine as in reality,

the contents of a buffer are

for a buffer from a white to a white machine as in the snapshot state,

for a buffer from a red machine to a red machine as in reality,

for a buffer from a red machine to a white one, a postfix of the contents in reality, extending over the messages that the target machine in reality shall accept while red. (Note that if the red letter in the buffer in reality turns its recipient red, the postfix in the shadow buffer extends up to and excluding that red letter and the snapshot string is empty; otherwise the snapshot string is not empty and the postfix in the shadow buffer extends up to and including the snapshot string.)

for a buffer from a white machine to a red one, reality postfixed by the messages up to and including the red letter that the white machine will enter in reality into the buffer.

The correspondence between the two processes is as follows: to an action performed in reality by a red machine corresponds in the shadow network exactly the same action, to an action performed in reality by a white machine corresponds in the shadow network a skip, except that a shadow machine turns red when its partner in reality does so.

The action of a red shadow machine is possible on account of (i), (ii, b) and (iii, b) or (iii, d); it clearly leaves (i), (ii) and (iii) invariant. So does the skip performed by a white shadow machine despite the change in “reality” in which (i), (ii), and (iii) are formulated

For the switch from white to red we observe

ad (i): | this is maintained by the switch
ad (ii): | because the machine's snapshot state equals its current state in reality, (ii, a) prior to the switch ensures (ii, b) afterwards,

ad (iii, b):
if the machine for which it is an input buffer switches to red, the buffer in the shadow network has the same contents as its partner in reality on account of (iii, c); if the machine for which it is an output buffer switches to red, the buffer in reality just receives a red letter, hence the contents of the shadow buffer are as in reality on account of (iii, d).

ad (iii, c): | in reality the buffer just receives the red letter, the shadow buffer remains unchanged, i.e., the snapshot string (empty or closed by a red letter). But that is what (iii, c) defines if the red letter is the youngest message in the buffer
ad (iii, d): | the machine of which it is an input buffer just turned red; (iii, d) defines the snapshot string as the contents of the shadow buffer; according to (iii, a) the contents of the shadow buffer were the snapshot string prior to the switch, which has left the contents unchanged.

End of Proof of Lemma 1.

*          *
*

Remarks

I know that the above text can be shortened and polished; regrettably I also know that a very heavy schedule will prevent me from doing so in the near (and not so near) future. [One improvement is to record instead of the empty string a string containing just a red letter. The idea was to record in the snapshot the tree along which the blushing propagates from the starter over the network. But this propagation tree, though frequently mentioned during the discussions in the Tuesday Afternoon Club, has all but disappeared.]

I am very pleased by the obvious symmetry between the two proofs. [This symmetry only emerged in full force while writing this text.]

I am also pleased by my two-stage presentation of the snapshot algorithm: first the red-letter traffic, and then the recording it triggers. [The red-letter traffic is such a fundamental process that it probably deserves to be named, described, and justified in isolation. Then we can refer to it whatever we superpose on it.]

I think that the idea of introducing shadow networks next to reality was correct. The fact that there is not the slightest objection —as we did in the proof of Lemma 1— to initialize the shadow system in a way that depends on the “future” computation in reality is very similar to the fact that there is no objection —on the contrary, it can often be done at great advantage!— to using the value of the “still unknown, perhaps even still undecided” answer in the formulation of the invariant. [This is another reason for not trying to understand computations in terms of cause-and-effect: people used to that are immensely troubled by this trick.]

I am mildly annoyed by the 4-fold case analysis under (iii) of the invariants, but only mildly since it is probably unavoidable since bother source and target —the introduction of these terms would have helped!— of a buffer may have either colour.

I am profoundly annoyed, however, by my clumsy formulations of, in particular (iii, c) and (iii, d). My linguistic shortcomings are here painfully obvious; were I to rewrite this note, I would first think very hard how to define these strings before setting a pen on paper.

Acknowledgements

My first acknowledgements are due to K. Mani Chandy, Leslie Lamport, and Jayadev Misra, the authors of this beautiful algorithm, in particular to the first one of the above triple since he took the trouble of explaining it to me. The algorithm is so beautiful because it separates the general process of taking a distributed snapshot from the particular process of testing against a specific stable predicate.

My next acknowledgements are due to the members of the Tuesday Afternoon Club. They greatly helped in taking the firm decision to ignore all relativistic worries and to consider the atomic actions in reality totally ordered in time. I think that was a wise decision.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 8 September 1983 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Xiaozhou (Steve) Li
revised Mon, 15 Jan 2007

  EWD 864a

The Distributed Snapshot of K. M. Chandy and L. Lamport

We consider a distributed system of the form of a strongly connected, finite, directed graph, of which each vertex is a machine and each edge a uni-directional first-in-first-out buffer of sufficient capacity. (Strongly connected means that there is a directed path from any vertex to any vertex.)

A distributed computation consists of a succession of so-called “atomic actions”; each atomic action is performed by one of the machines: it changes the state of that machine, accepts at most one message per input buffer of that machine, and sends at most one message per output buffer of that machine. The buffers have no clairvoyance, i.e. a message can only be accepted after it has been sent.

For a message-accepting action to take place, the messages in question must have arrived; arrival of messages, however, only enables an atomic action to take place and never forces it to take place. Each message in a buffer will eventually be accepted by the machine to which this buffer leads. (The friendly daemon that resolves each machine's nondeterminacy so as to ensure the implied fairness is not considered part of the system.)

Between any two successive atomic actions the state of the distributed computation is determined by (i) the state of each machine, and (ii) the string of messages contained in each buffer.

A so-called “stable predicate” is such that, if it holds in some state, it will hold in all possible later states. If it holds, we say that “stability” has been reached. The purpose of the distributed snapshot algorithm of K. M. Chandy and L. Lamport is to collect such state information that, on account of it, stability can be detected.

The distributed snapshot algorithm is superposed upon the distributed algorithm such that, while the distributed algorithm evolves from state S0 to state S1, it collects the description of a so-called “snapshot state” SSS with the properties that —though there need not be a single moment at which it occurred— SSS is a state that is possible after S0 and S1 is a state that is possible after SSS. Hence, if stability has been reached in S0, SSS satisfies the stable predicate; conversely, if SSS satisfies the stable predicate, stability has been reached in S1.

In our first description of the snapshot algorithm each machine, each atomic action, and each message is either white or red. Each atomic action gets the colour of the machine that performs it, each message gets the colour of the action that sends it. In state S0, all machines and all messages are white. As part of the execution of the snapshot algorithm each machine turns from white to red once, i.e. each machine's individual history is a sequence of white actions, followed by a sequence of red actions. So, eventually, all machines and all actions are red. From the onwards, no white messages are sent; since all white messages in the buffers will be accepted in due time, eventually all messages in the buffers are red as well. State S1 is a state where all machines and all messages are red.

For the time being by magic —about which more later—, the moments at which the machines turn red are chosen in such a way that no red message is accepted in a white action. We note at this stage that such a choice of moments is possible: if, for instance, all machines turn red simultaneously, each machine would be red before the first red message entered the system and, hence, no red message would be accepted by a white machine.

The snapshot state SSS consists of

for each machine its state at the moment of its transition from white to red, and

for each buffer the string of white messages accepted from it in red actions.

Our purpose is to show the existence of an equivalent computation —i.e. equivalent with respect to the distributed computation and with respect to the snapshot algorithm— with its snapshot state as one of its intermediate states, i.e. with S0 as initial state, with SSS as intermediate state, and with S1 as final state. From that existence follows what had to be shown, viz. that SSS is a possible state after S0 and that S1 is a possible state after SSS.

The equivalent alternative consists of all the white actions in their original order, followed by all the red actions in their original order. To show its equivalence to the original distributed computation we observe that two successive atomic actions from different machines commute unless the first one sends a message that is accepted by the second one. From this it follows that a red action and a subsequent white one commute: from their colours we firstly deduce that, messages produced by the first one being red, the first one does not send a message accepted by the second. By interchanging them we derive a computation that with respect to the distributed algorithm is equivalent to the one before the interchange; colours of actions and messages having been left as they were, the property that no red message is accepted in a white action still holds and the snapshot algorithm, being defined in terms of colours, yields the same snapshot state.

Such an interchange, however, reduces the number of “inversions” by 1 (an inversion being a pair of differently coloured actions such that the red one takes place before the white one). Hence a finite number of such interchanges yields the equivalent alternative in which all white actions precede all red ones. And here all machines can turn red between the last white and the first red action; the system state at that moment is evidently the state yielded by the snapshot algorithm.

*            *
*

We now turn our attention to two details of implementation. Firstly, we have to implement the “magic” that sees to it that each machine turns red at an appropriate moment. Secondly, we have to see to it that each machine can record the proper string of messages for each of its input buffers.

Let us begin with the last requirement. A red machine has to record for each of its input buffers the string of accepted messages up to and including the last white message. We are not allowed to translate that into “up to and excluding the first red message” since that red message need not exist. Therefore, instead of colouring the messages, we extend the repertoire of messages with a special one, called the “marker”, with the convention that on each buffer the messages —if any— that precede the marker are deemed white and the messages —if any— that follow the marker are deemed red; like the other messages, the markers participate in the first-in-first-out regime of the buffers, and, upon turning red, each machine sends over each of its output buffers a marker before sending anything else over that output buffer.

The markers can also be used to implement the magic. Since each red message is preceded by a marker, machines turn red in time if they do so upon accepting their first marker while still white. The snapshot algorithm is initiated by (at least) one machine turning red (and, accordingly, sending a marker over each of its output buffers). Since each machine is reachable via a path from the initiator(s), and each message sent is eventually accepted, all machines will turn red in due time. Since each machine turns red once, each buffer carries precisely one marker. Hence, in each machine it is known when collection of the local snapshot information has been completed, viz. when over each of its input buffers a marker has been accepted. The local snapshot information can then be sent to a central point —probably the only initiator— where it can be subjected to the test whether the snapshot state satisfies the stable predicate.

*            *
*

The above algorithm is a creation of K. Mani Chandy of the University of Texas (Austin) and Leslie Lamport of SRI International (Menlo Park); the former of the two told it to me on the 1st of July 1983. Being otherwise engaged during July and August, I returned to it in September. Several sessions of the Tuesday Afternoon Club were devoted to it; first we reconstructed the algorithm, and then we experimented with various ways of reasoning about it. The contributions of C. S. Scholten in the later stages of those experiments are gratefully acknowledged. No one else, however, can be blamed for any shortcoming of the above text, which was written in Sao Paulo, Brasil.

It can be argued that we have been overspecific by viewing the original distributed algorithm as a linear sequence of atomic actions in time: no one cares about the relative order of actions that might take place concurrently. Yet I believe the linearization responsible for the fact that we could carry out the argument without the introduction of subscripts or any other nomenclature to distinguish between the machines. The linearization plays a role very similar to the choice of an otherwise arbitrary coordinate system in analytical geometry.

In comparison to earlier distributed algorithms for the detection of termination, the snapshot algorithm above is very beautiful in the sense that it is applicable independently of the specific stable predicate.

*            *
*

Additional Remark. In the above we have shown that if no red message is accepted in a white action, the individual speeds can be adjusted so as to let all colour transitions of the machines take place simultaneously. The condition is sharp: if a red message is accepted in a white action, its sender turns red intrinsically prior to its acceptor. (End of Additional Remark.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 7 November 1983 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Xiaozhou (Steve) Li
revised Mon, 15 Jan 2007

EWD865

Trip report E.W.Dijkstra, Brasil & USA, 17 Oct.-6 Nov.1983

Ria had not had much of a holiday this year —to put it mildly— and joined me on this trip, hoping that she would have recovered well enough to endure the hardship of long flights. I am happy to report that her hope was justified.

Our departure was not without commotion: 6 hours before we had to be at the Airport, we learned by accident that the Dutch public transport system was on strike. The problem was solved by our neighbour's offer to drive our car to Schiphol and back. We made the trip without encountering traffic jams and were at the Airport well in time. Via Lisbon and Rio de Janeiro we travelled to São Paulo in a mostly filled DC10 of the KLM. In view of Ria's back, I had asked —more than a month earlier— for seats with extra leg room. We got our special seats, that is: just in front of us a separation instead of another row of chairs. Where to leave our feet was not quite clear; by the time we arrived, our ankles were swollen. On the KLM coach from the Airport Viracopos to the centre of São Paulo we encountered Brazilian corruption for the first time: paying the fare in US dollars we were charged far too much and the collector tried not to give us a receipt. At 12:45 we arrived at the terminal where our niece would collect us, but she was nowhere in sight and it rained cats and dogs. At 13:30 she found us; she had been waiting at the other side of the terminal. The rest of that day was devoted to recovery from the journey.

The reason for my visit to São Paulo was "Informática 83", a one-week combination of an exhibition and a conference; at the latter I gave a talk at Burroughs's request (IBM had sent Ralph E.Gomory, but he spoke on the day of my arrival and, regrettably, I just missed him). On Wednesday I met Mr. Valdir Gomes of Burroughs, Brasil, who, for the next few days, most gracefully acted as my host, guide and guardian angel. That day he took me to the Exhibition, where we made the final arrangements for my performance the next day at the Conference and my visit to the University of São Paulo on Friday.

On Thursday I gave at the Conference a very good talk, though under strange and miserable circumstances. I had a very nice topic, viz. the distributed snapshot algorithm of Chandy and Lamport which, thanks to our work in September, I could explain effectively. But the circumstances were strange and miserable. I turned out not to speak under the auspices of Burroughs (which had the privilege of paying my ticket) but of Digibras, a state-owned computer company located in Brasilia. The latter company had failed to provide the promised blackboard, failed to announce my talk properly, etc. It was a good thing I could visit the University of São Paulo the next day, for had that talk been the sole purpose of my visit, it would have cost a dollar per second.

At the University I presented Yossi Shiloach's algorithm, which is always a nice topic for a technical talk of slightly more than a hour. I had a lively audience that understood my English. I spent an interesting day in a cosmopolitan atmosphere. The people were very aware of being in a developing nation. They discussed with me a winter school in computing science they organized every two years for about 500 participants; its most important contribution, however, was that the syllabuses were used to build up a series of computing science textbooks in Portuguese. The department struck me by its strong component of combinatorics, its ties with Schutzenberger, etc. One would not think that the most urgent part, but it was evidently needed —or had been needed in the near past— to make computing science academically respectable.

The weekend we stayed with our nephew and niece. The day before our arrival it had been very warm —so warm, in fact, that the computers at the IBM stand broke down— during our stay it was mostly wet and cool: for Ria none of the promised sunbathing in the garden. On Sunday evening we left and flew via Rio de Janeiro, Miami and Dallas to Austin, Texas, where we arrived around noon the next day. The rest of that Monday was used for recovery.

In Austin I had a very heavy schedule since UT (= University of Texas) wanted to show to me most of their Computing Science department and a lot more. Tuesday was primarily devoted to concurrency and data base research, Wednesday I met the mathematicians, and Thursday I was given a bird's eye view of automatic theorem proving. (The bird flew at high speed and at low altitude.) Late that afternoon I gave a lecture on avoiding case analyses. It was a first performance and it was well-received. I gave it in a large physics auditorium in which the sound amplification system was out of order, and in which I could use only one of the blackboards. On Friday I repeated the talk on the Chandy/Lamport algorithm at Burroughs ARC. Our social schedule was heavy as well: on Tuesday, Thursday, and Friday we had dinner with people from UT (Chandy, Dale and Boyer respectively), on Wednesday evening Ham and Joanne Richards, with whom we stayed, had invited a number of people from Burroughs. In addition, I was subjected to "business lunches" at UT, where I was introduced to all sorts of people (including the physicist who knew all about computing; you know the type; this specimen had never heard that the goto-statement had been a subject of discussion!) I have not sorted out my impressions yet.

We left Hotel Richards the next morning at 6:45; Ham kindly saw us to the Airport. We were 50 minutes late in taking off as the plane got fogged in while already on the runway. With half an hour delay we arrived at Burbank, where the whole family Martin was waiting for us. The next week we stayed in Pasadena, but for the fact that I took a "red eye flight" to Detroit and returned the next afternoon, so that I could have a discussion with Dr.W.Lee Shevel of Burroughs. (He had tried to contact me while we were in Austin, but eventually it turned out that both our schedules were too crammed.) In Pasadena I gave a talk at CalTech on Tuesday afternoon, and on Wednesday I took over Alain Martin's lectures. Alain and I have discussed the presentation of one of his designs; one evening Chuck Seitz came and we talked about what direction the department should take.

*                *
*

I had been amazed to see the Concise Oxford Dictionary define mathematics as "Abstract science of space & number". That struck me as particularly old-fashioned and inadequate: I would have expected something like the scientific discipline of effective reasoning. We checked it and Le Petit Robert and Webster's New Collegiate Dictionary gave essentially the same definition as the COD. On this trip I learned that we cannot blame the dictionaries for being out of date. Many mathematicians are very knowledge-oriented, and think about learning mathematics primarily in terms of acquiring factual knowledge rather than being able to do things such as disentangling an argument and reducing it to its bare essentials. It already began at the University of São Paulo —where I was shown a volume of Rota's Encyclopedia (sic) of Mathematics—, it continued at UT and CalTech: typically the question asked is which "mathematical prerequisites" I think most important for computing scientists. And then they want a very specific answer, such as: numerical analysis is more important —or less important, as the case may be— than algebra or combinatorics. I have not figured out yet how to explain politely but convincingly that the question does not strike me as very relevant, and that economy of thought, whatever the topic, seems to me to be of greater importance. One of computing science's major challenges —if not the major one— is how to avoid the mess of unmastered complexity —again: regardless of the specific application, for we are dealing with truly "general purpose" equipment—. One would expect this to hold for mathematics in general, but evidently the traditional mathematician of today has different priorities.

People seem in general to be more concerned about acquiring knowledge pertinent to their specific area than about mathematical methodology in general; consequently they hardly contribute to the latter. The fact that "users" —and here I include the numerical analysts, the physicists, and the artificial intelligentsia— have contributed so little to computing science is probably the same phenomenon.

*                *
*

In Austin, Ria had had quite a program too; São Paulo and Pasadena was a holiday for her, and so was Pasadena a bit for me: one afternoon we went to the Huntington Gardens, one afternoon to the Mount Wilson Observatory. The whole family Martin joined us on Saturday afternoon on our trip to LAX. The place is still quite confusing: the trip from Pasadena to LAX took by car 40 minutes, finding the KLM desk took us another 20. Flight KL602 to Amsterdam was (for a change) not crowded and we both slept for more than half of the flight. In the Netherlands, public transport was still on strike, but our eldest son Marcus was with our car at the Airport. At 17:00 we were home. (I more or less expected that our house would strike us as small, but it did not.) We phoned our mothers, and at 18:00 I was sorting the mail.

It was a trip of crime and pollution. In São Paulo my nephew had rented a house in which its owner did not dare to live any longer —she had moved to an apartment—. One evening we were invited to dinner; with five neighbours our host employed a private, armed guard. In Austin, crime was less conspicuous though female students were advised to avoid the campus alone at night. The day after our arrival in Pasadena, thieves broke into the neighbour's house in the middle of the afternoon. São Paulo's air suffers from industrial pollution —it is a town of 12 to 14 million inhabitants with the world's poorest drinking water—. Austin had its pollen and Pasadena its smog. It made my eyes itch.

Here it is already cold: we have a sunny day with a cloudless sky, the air is crisp and the autumn leaves have the most wonderful colours. I hear my piano being tuned downstairs.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
7 November 1983
prof. dr. Edsger W. Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 29 Mar 2004

EWD866

An analytical proof of The Butterfly Theorem

In a circle with centre O the chords AD and BC intersect one another in Q. The line PQR intersects AB in P and CD in R and is orthogonal to OQ. Prove PQ = QR.

(The name “Butterfly Theorem” is derived from the shape of the quadrilateral ABCD; Q, however, need not lie inside the circle.)

Proof. Take for the diameter OQ the x-axis and let its ends be (–1,0) and (+1,0). Since the lines connecting A to those endpoints are orthogonal to each other, A can be characterized with some α as the point of intersection of the lines

      α ⋅ (x + 1) + y = 0   and   (x – 1) – α ⋅ y = 0

and B, C, and D similarly with some β, γ, and δ respectively. (See Note.)

By multiplying the first equation by β and subtracting the second one we get

| α ⋅ β ⋅ (x + 1) + (α + β) ⋅ y – (x – 1) = 0 | (0)

By virtue of its construction (0) is a line through A; being symmetrical in α and β, it is also a line through B; hence, (0) is the equation of the chord AB. And similarly for the other chords.

The fact that Q with coordinates (q,0) lines on AD and on BC yields therefore

| α ⋅ δ ⋅ (q + 1) = q – 1     | (1)

| β ⋅ γ ⋅ (q + 1) = q – 1 | (2)

and since we may confine our attention to the case

| q + 1 ≠ 0 | (3)

— because, with Q on the circle, the theorem is trivial —

| α : β = γ : δ | (4)

On account of (0), the y-coordinate p of P satisfies

(α + β) ⋅ p = (q – 1) – α ⋅ β ⋅ (q + 1)       , or, on account of (1),

| (α + β) ⋅ p = (δ – β) ⋅ α ⋅ (q + 1) | (5)

On account of (0), the y-coordinate r of R satisfies

(γ + δ) ⋅ r = (q – 1) – γ ⋅ δ ⋅ (q + 1)      , or, on account of (2)

| (γ + δ) ⋅ r = (β – δ) – γ ⋅ (q + 1) | (6)

On account of (4), (5) and (6) are the same equation except for a change of sign. (The case α + β = 0 and γ + δ = 0 corresponds to the degenerate case that both AB and CD are perpendicular to OQ.)

Note. For brevity’s sake we allow ourselves an α that may be “infinity”, instead of writing

α0 ⋅ (x + 1) + α1 ⋅ y = 0       and       α1 ⋅ (x – 1) – α0 ⋅ y = 0

(End of Note.)

                                          (End of Proof.)

This theorem was shown to me on 27 Oct 1983 at UT at Austin by Shang-Ching Chou, who had proved it mechanically. The theorem was new for me and the proof had been long (I don’t remember, how long). In most of his proofs, coordinates of points had been chosen as free parameters. On my flight from Austin to Los Angeles I realized that characterizing A by α as done above would probably come in handy since the only thing done with A,B,C, and D was drawing chords through them: the sides of the quadrilateral are of more interest than its vertices.

The Tuesday Afternoon Club assisted me with the first draft of this proof. It was a nice exercise in analytical geometry.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 14 November 1983 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Jonathan David Arndt
revised 17-Dec-2019

EWD868

Computers and General Education: a position paper.
(A replacement for EWD867: it turned out that the topic for the panel discussion was not “Computers and Society” but “Computers and General Education.”)

At least to me it is not obvious that “Computers and General Education” is a worthwhile topic for a seminar like this. It is not a combination that immediately comes to my mind. If computers have to be part of it, why not “Computers and Bureaucracy”? If general education has to be in, why not “Bureaucracy and General Education”? I even think it could be argued that either of this alternatives is of greater societal relevance. But I shall not do so. Let us try to find out instead the possible significance of the topic as chosen by the organization.

A possible explanation for the choice is that the topic is a fad. That is not a nice explanation, but we cannot dismiss it since also organizers of panel discussions are not exempt from the influence of the media, and the latter really push the idea down our throat. I am not exaggerating. Here is, how, in a column recently published in The International Herald Tribune, Russell Baker describes it:

WASHINGTON… Here is a television commercial trying to sell household computers:

In the first shot Mom, Dad and Son are at the quaint old railroad depot. Mom and Dad wave Son goodbye as the train pulls out. Son is off to college to realize the American dream: A future with an expense account and so many tax lawyers that the IRS will never lay a paw on his annual income.

In the next shot the train is pulling into the same depot it just left. Mom and Dad are standing there looking lugubrious, and no wonder. There is Son about to disembark with his luggage. He looks wretched. He has been kicked out of college.

The invisible narrator says the lad lacked the computer savvy needed to pass. Mom and Dad didn't buy him a computer when he was a little boy.

Do you want this to happen to your child? If not, better buy a computer at once. The narrator recommends the computer made by the sponsor.

Evidently, computers are now sold with the same aggressive blackmail as encyclopedias used to be sold with, the education of your children providing the lever. The analogy might go further: the household computer might turn out to be as helpful and as reliable as the average encyclopedia. The analogy might even contain a warning, since the encyclopedia market collapsed when money became a bit tight and people came to their senses.

Further down, Russell Baker comments:

The commercial aims to make Mom and Dad feel guilty about the boy's failure. What nonsense. Mom and Dad have nothing to feel guilty about. The boy is so dumb he deserves to be kicked out, and no computer ever made will help him overcome his obvious inability make a sensible judgment of his situation.

So much for Russell Baker, whom we may classify as someone that entertains grave doubts. If the phenomenon were restricted to television commercials, it would not be too bad, for television commercials are not renowned for their impartial presentation. But it is much worse, since the phenomenon has also intruded into the scientific world. Allow me, in order to show that I am not exaggerating —and to show, in passing, how up-to-date I am on my literature— to quote from the Computing Reviews, Nov. 1983, in which a new scientific journal is announced. It is called “Machine-Mediated Learning”. To begin with we note that, if you have a memory, and if you are linguistically sensitive, that title should make you rather suspicious. We started with “Computerized Instruction”; via “Computer-Aided Instruction” it became “Computer-Assisted Learning”. And now it is “Machine-Mediated”… I can think of only one explanation for such frequent renaming: a new name was needed each time the previous one had lost its lustre. A convincing demonstration that the whole idea of machine-mediated learning is a bloody mistake would certainly be pertinent to that journal’s area of interest, but it is very unlikely that such a result would reach the pages of this journal, since its Editorial mentions only one criterion in the evaluation of articles considered for publication, viz. “the extent to which they facilitate the development and utilization of effective machine-mediated learning systems”. The conclusion is clear: rather than classifying this journal as scientific literature, we should classify it as propaganda.

So, let us start afresh and ponder as honestly as we can whether the advent of computers —undoubtedly a radical novelty with an exciting potential— has any consequences for the time-honoured goal of general education. Immediately, this question falls apart into two different ones: does the existence of computers give rise to new possibilities for general education, and causes it new obligation for general education?

Hard questions. Since I deny the existence of experts on general education, I refuse to pose as one myself. The only general education I can talk about is the one I enjoyed myself at the Gymnasium Erasmianum at the age from 12 to 18 years. I enjoyed it immensely and never missed machine mediation because I had never heard of such a thing. Having no complaint at all about my general education, which was pretty thorough by today’s standards, I had a hard time thinking of ways in which computers, had they existed at the time, could have helped in achieving what my teachers tried to achieve. Eventually I found one. Suppose that in my school days I had had the full text of Homer on a floppy disk. Homer himself knew that text by heart, but I did not, and as a result I could not answer the question that sometimes came up in my mind when I met an unfamiliar word, viz. “What are the other occurrences of this word? What are its other usages?”. Had I had Homer on a floppy disk, I would have been able to get an answer to that question and I might have been tempted to try to figure out that word’s meaning myself. As things were, I had to make do with Mehler’s Dictionary. Homer on a floppy disk was the only thing I could think of; admittedly it is a meagre harvest, but I am not disappointed since I did not expect to find much.

For the sake of completeness, I mention two other reasons one hears why general education could profit from the introduction of machine-mediated learning, but I tell you in advance that I think neither of them very convincing.

The one argument is one of, say, constant quality. Instead of subjecting the pupils to teachers of wildly varying degrees of competence and incompetence, it is better to give a single excellent course. The investment in such an excellent course would be very high, but it would be worth the trouble if its dissemination can be mechanized and thus will take place unpolluted by the incompetence of the teacher that happens to stand in front of the classroom.

It is an argument, but particularly in connection with general education I find it utterly unconvincing. General education has been defined as what remains after you have forgotten what you learned at school. It sounds as a bon mot, but it is no joke. In order to keep the discussion simple, let us stick to Homer, whose poetry I liked. During my last year at school, before going to sleep I would regularly read a few hundred verses of Homer’s poetry before going to sleep, looking up the few words I had missed the next morning. It is a habit I can genuinely recommend for the restless mind. The ability to read Homer without a dictionary and to enjoy it greatly turned out to be extremely volatile: I went to University where I was otherwise engaged and within six months I had lost the ability completely. In a highly knowledge-oriented world, my study of classical Greek should probably be regarded as a waste of time, but I don’t do so. If I close my eyes, the images of the scenes Homer evoked in me 35 years ago are as vivid as ever, but, more importantly, I owe to the teachers that taught me Greek, and who happened to be excellent, by virtue of their example that it would be a great idea to become a scholar. In short: the intellectual level of the people educating me made a much more lasting impression than the specific subject matter they taught me. At the University history repeated itself. After these confessions I hope that you are willing to respect that I am not convinced by the supposed virtue of machine-mediated learning that it can compensate for the intellectual limitations of the teachers.

The other argument in favour of the introduction of computers into the educational process —believe it or not, it has been seriously put forward— is orders of magnitude more fishy. That argument is that the introduction of computers into the educational process requires the design of educational software, and that the unusual explicitness required for that task would be of great benefit for educational science in general. It would force the educationists to make their educational models explicit, etc. This argument treats our schools as the happy hunting ground for the educationists; and for precisely that reason the argument strikes me as eminently ignorable.

In short: for the traditional aims of general education I see very little use of computers. The next thing to ask ourselves is, whether in response to the advent of computers, general education should extend or shift its goals.

I think it should, if we knew how. I shall give my reasons why I think it should, but at the same time these reasons explain why it will be very difficult for general education to meet this new challenge.

A general purpose computer is a device that, under the proviso of limitations of its capacity, can execute any algorithm and can do no more; without algorithm to execute, it does nothing. A computer is in what it can do so simple that, from a logical point of view, it is ignorable. The consequences of its existence are, however, profound.

It means that now all thinkable mechanisms can be implemented by as many specific algorithms, all executed by the same general purpose computer. The fact that now all thinkable mechanisms can be implemented with essentially identical hardware is a major feat of abstraction. We never had a device of such a flexibility, and to appreciate what that flexibility implies, one has to grasp what is meant by “any algorithm”. In its great flexibility the computer is without precedent in the long history of devices, and it is so much so that its advent represents a discontinuity in the history of devices. The unprecedented flexibility is a drastic novelty of a qualitative nature; grasping it is a conceptual challenge.

These conceptual problems are compounded by quantitative characteristics of modern computing equipment: storage capacity and processing speed are so huge that what takes place inside a computer at work completely baffles the human powers of imagination. And, when I say “completely” I mean “completely”. A simple factor of 10 makes already all the difference; I remember asking a housewife that did not believe that, how many children she had, knowing that she had 6 of them. Then she saw the point. Confront this with the fact for several decades, machines gained a factor of 2 in power each year: that is a factor of a thousand per decade and of a million within 20 years. When what was a gradual difference becomes big enough it becomes an essential difference because the analogies break down.

Most people, though grown-ups perhaps more than young children, try to understand the unfamiliar in terms of the already familiar. They think in terms of analogies, which work if the new thing is sufficiently similar to what they know already. But if the novelty is drastic enough, the analogies are too weak and people can no longer cope comfortably with the novelty. And such drastic novelty is precisely what technology can inflict on us: it happened with the creation of the atomic bomb, it happened with the invention of the computer and perhaps with the invention of the pill as well.

What could be the role of general education in all this? We should keep in mind that not the computer but the algorithms constitute the heart of the matter. Programming, i. e. the design of such algorithms, is much too difficult to teach to the public at large. Recent experience has confirmed what many of us knew already, viz. that programming is even too difficult for the average mathematician.

There is always the feeling “well, with a little machine and a simple programming language you should be able to show the kids something, should’t you?”. Regrettably, that is true, and regrettably, showing the kids something is probably precisely what is going to happen. I said “regrettably” because then the kids will get such a misleading experience that it will never clear up the confusion. It is much too similar to the way in which the manufacturers sold their machines by showing to top management in a one-afternoon programming course how simple it all was; and later top management not understanding how they had dug themselves into the hole called “the software crisis”. Another reason to regret it is that the kids will acquire patterns of thought that are deeply inadequate when they wish to become professional computing scientists. At the Universities we foresee that our freshmen will face an increasingly hard job of unlearning, and there is all reason to fear that the introduction of a little bit of programming at school will greatly enlarge our task —which is already considerable now— of undoing the damage done to the kids at secondary school. Let us be unreasonably optimistic and hope that programming will share the fortunate fate of the General Theory of Relativity, viz. the fate of not being included in the highschool curriculum.

What can general education then do to protect the layman? And among the laymen I include the average housewife, child, businessman, mathematician, electronic engineer, politician, and educationist.

I think we should try to make them more immune for all the humbug and dishonesty in which the world of computing abounds. I believe that that can be done. We should teach them the critical, sceptical reading of advertisements. Advertisements are very significant in two respects: they reveal the manufacturer’s perception of his customers’ appreciation of his products, and, furthermore, they are for the layman a major source of information.

It must be possible to make even the public at large immune for advertisements such as the recent one that under the slogan “You can’t reach the top by being a pencil pusher” suggested that, in order to become vice president, it sufficed to buy one of the company’s “Thought Processors”.

People should first learn to identify the misleading messages coming from the professional public relations men, viz. the advertisers. This should give them some immunity against more subtle misrepresentation as the one given by the enthusiastic computer user. The trouble with the latter is that he need not be dishonest: he may be a propaganda victim himself.

I refer to the wide-spread, but in general unchallenged, belief that making something “computer-aided” amounts to making it better. (The misery of computer-assisted examinations, better known as “multiple choice” should have cured us, but I am afraid that the lure was too strong.) Under no circumstance the dogma of automatic improvement should be accepted without challenge, for otherwise we would have in no time computerized jurisdiction.

Theses, added to oil the discussion.

Thesis 0. The idea of using computers in the process of general education came from two beliefs, viz. in the usefulness of computers and in the competence of educationists. Both beliefs could very well be exaggerated.

Thesis 1. The introduction of computing science in the secondary school curriculum can hardly be expected to give the layman a balanced opinion about the potential and the pitfalls of computer usage.

Thesis 2. For computing science students, prior exposure to microcomputers is a severe handicap.

Thesis 3. Fascination with the equipment is the hallmark of the amateur.

Thesis 4. The argument in favour of Information Technology that presents wide-spread application of Information Technology as an aid to the democratic process is at least suspect, and probably wrong in the sense that totalitarian regimes have at least as much use for Information Technology. Better than by equipment, democracy is served by the art of debunking. (In this respect, democracy is not alone.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 1 December 1983 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Roman Beslik beroal
revised 06-Oct-2012

EWD869

Ter afsluiting van de “Inleiding tot de Kunst van het Programmeren”

Ter afsluiting, niet alleen van het seizoen, maar van de hele serie, brengen wij “De gelijkheidstest voor cyclische lijsten”, een nog vrij recente compositie van Yossie Shiloach. De oorspronkelijke compositie is geschreven voor amateur-ensembles en bevat om die reden nauwelijks passages die van executant of toehoorder veel raffinement vereisen, en in zijn oorspronkelijke vorm bevredigt het stuk dan ook niet helemaal. Dat het toch zo snel tot het klassieke repertoire is gaan behoren, danken we dan ook aan de concertbewerking van Wim Feijen en Netty van Gasteren: zij hebben voor Shiloach’s Algorithme gedaan wat Maurice Ravel deed voor de Schilderijententoonstelling van Modest Petrovitch Moussorgski. Ik breng U nu een uitvoering van Shiloach’s Algorithme in de versie van Feijen en van Gasteren, aangevuld met eigen cadenzen.

*            *
*

Zo, dat was dan 17 jaar “Inleiding tot de Kunst van het Programmeren”: 17 bewogen jaren. (Ze bewegen nog steeds, mogen wij wel zeggen.) Een terugblik zij mij vergund.

Hoe veelbewogen die jaren zijn geweest wordt onmiddellijk duidelijk als we naar de naamsveranderingen kijken. Begonnen wij 17 jaar geleden met de Kunst van het programmeren, 8 jaar later hadden wij het over A discipline of programming en nog eens 8 jaar later verkreeg The science of programming burgerrecht. Deze progressie is zelfs voor de leek een onmiskenbaar symptoom dat er in die jaren veel moet zijn gebeurd.

De Kunst van het Programmeren: de naam was geen grapje, hij weerspiegelt heel duidelijk de tijd, waarin hij is ontstaan. Zo verscheen een jaar later Vol.I van het boek van Donald E.Knuth dat de naam The Art of Computer Programming mee zou krijgen. De naamkeuze was ingegeven door een mengsel van bescheidenheid en ambitie.

De bescheidenheid bestond daarin dat we, door over de kunst te praten, aangaven, dat de wetenschappelijke discipline nog niet bestond. (En zelfs 8 jaar later, toen dat allemaal heel anders was komen te liggen, kozen we heel bewust “A Discipline”: men lette op het onbepaalde lidwoord!)

De ambitie bestond daaruit, dat we het vak ten duidelijkste boven het toen vigerende niveau van adhoccery wilden uittrekken. Het gebruik van de term kunst leek die ambitie duidelijk te verwoorden, te meer daar het duidelijk was dat de gewenste ontwikkeling zijn eerste impulsen uit esthetische overwegingen zou moeten krijgen.

Terugblikkend moet ik erkennen de rol van die esthetische overwegingen voorzover ik mij kan herinneren destijds onderschat te hebben. Ik was mij er wel erg van bewust dat het geen zin had een uitgebreid formeel systeem te ontwikkelen en ons de bijbehorende manipulatieve vaardigheden eigen te maken voordat we heel zorgvuldig hadden gekozen, wat we nu eigenlijk wilden formaliseren en op wat voor soort programma’s we eigenlijk wilden afstevenen. We wisten een paar dingen inmiddels: we wisten dat de goto-statement een bron van ellende was, en begrepen zelfs gedeeltelijk waarom; we wisten, dat recursie een schitterend stuk gereedschap kon zijn. Maar het was nog heel duidelijk tasten; vandaar het esthetisch kompas. Even vooruitlopend moge ik illustreren hoezeer nog zes jaar later —en we zijn dan in 1973— de esthetiek richtinggevend was. De generalisatie van de if-then-else-clause naar de alternatieve constructie met de z.g. guarded commands ontstond uit het verlangen om in de uitdrukking voor het maximum van twee getallen de symmetrie tussen die twee getallen niet te verstoren. Op het moment dat ik zag dat mijn manier van symmetriehandhaving de introductie van nondeterminisme impliceerde, heb ik daar in eerste instantie nauwelijks bij stilgestaan: mijn eerste reactie op de introductie van nondeterminisme was van een gelaten “nou, dat moet dan blijkbaar”. Hoe groot de toen achteloos genomen stap was geweest heb ik me pas veel later gerealiseerd toen de eerder genoemde Knuth hem karakteriseerde als “a giant leap”.

Wat ik, door esthetische overwegingen primair te apprecieren als provisorisch richtsnoer, toen onderschat heb is hoe elegance een steeds centralere plaats in onze overwegingen zou gaan innemen naarmate de tijd voortschreed. Later heb ik in alle toonaarden bezongen dat in computing science wiskundige elegance niet beschouwd moest worden als luxe, maar als harde noodzaak. In 1967 zag ik dat beslist nog niet met de helderheid waarmee we er nu van zijn doordrongen.

Helaas was de gekozen benaming niet zo duidelijk als we gehoopt hadden: behalve tot schampere opmerkingen heeft hij, vrees ik, meegewerkt aan het misverstand dat het vak niet te leren zou zijn, dat het tentamen toch een loterij was en dat het daarom weinig zin had je er op voor te bereiden. Het behoeft geen betoog dat het tentamen voor studenten, die deze onjuiste conclusies trokken en daar naar handelden, inderdaad in een loterij ontaardde, maar dan wel een loterij met louter nieten. Het tentamen is hierdoor wel in opspraak gekomen, maar iedere keer dat we het controleerden bleken de cijfers voor “de kunst” zo schitterend te correleren met andere erkend selectieve tentamina, dat wij ons geen zorgen hebben gemaakt en het verwijt, dat het tentamen voor “de kunst” een intelligentietest was,als compliment naast ons hebben neergelegd. En dat was dan waarschijnlijk wat naief; volledig terecht, maar wel wat naief. Het gaat mij evenwel wat ver, de misverstanden louter aan de gekozen benaming te wijten. We waren voor Nederland waarschijnlijk ook wat vroeg: het was de tijd dat je als vooraanstaand Nederlands wiskundige zonder gezichtsverlies nog met trots kon verklaren “natuurlijk niets van computers te weten”.

Internationaal gezien waren we niet te vroeg. In 1968 kwam op de beroemde NATO Conferentie te Garmisch-Partenkirchen de “software crisis” in de openbaarheid. Datzelfde jaar trad een substantieel gedeelte van de IFIP Working Group 2.1 uit. Voor de uittredende leden was het politieke breekpunt de IFIP-bekrachtiging van ALGOL 68, een bekrachtiging, die zij misplaatst vonden. Van meer belang is de kern van hun motivering, nl. dat zij niet zagen hoe ALGOL 68 bijdroeg tot het moeilijkste aspect van de taak van de programmeur, nl. het scheppen van vertrouwen in de correctheid van zijn programma’s. Slechts een jaar later, in 1969, —en hier heeft de visie van de toenmalige president van IFIP, Heinz Zemanek, waarschijnlijk de doorslaggevende rol gespeeld— werd een nieuwe IFIP Working Group opgericht: WG 2.3, met als charter “Programming Methodology”. Inmiddels was “Notes on Structured Programming” via het informele circuit in omloop en dankzij de juist populair wordende copieermachines spoedig wijdverbreid.

[Geheel terzijde. Op het ogenblik vervloeken wij de copieermachines als de apparatuur, zonder welke de bestuurlijke verlamming van de universitaire democratisering zich niet zou hebben kunnen voltrekken, en het is niet misplaatst Xerox Corporation zijn rechtmatig aandeel toe te kennen in de wereldwijde verloedering van het academisch bedrijf. Tegelijkertijd dienen wij evenwel te erkennen dat de copieermachine een enorme rol speelt in de wetenschapsontwikkeling: een goed idee blijft niet meer geheim, en dat is een onschatbaar winstpunt.]

In het begin van de 70-er jaren kreeg het college zijn eerste dictaat: “An Introduction to the Art of Programming”. Ik kom nog geregeld verwijzingen daarnaar tegen, maar kan niet achterhalen of deze mogelijk zijn geworden door het informele circuit, dan wel door het feit dat The Indian Computer Society het in een waarschijnlijk gigantische oplage heeft herdrukt en verspreid. Het college is zijn werkelijke invloed waarschijnlijk pas gaan doen gelden in 1973 toen het Niklaus Wirth uit Zürich tot de publicatie van zijn Systematic Programming had geinspireerd. In 1976 verscheen A Discipline of Programming, 5 jaar later verscheen van David Gries het duidelijk daardoor geinspireerde The Science of Programming en was de oprichting van het tijdschrift van Elsevier The Science of Computer Programming een feit.

Inmiddels had collega Martin Rem, toen hij van CalTech terugkwam, het college overgenomen. Onder zijn zorgvuldige begeleiding is de veelbelovende puber tot volwassenheid gekomen. Let wel: volwassen betekent niet klaar, het betekent volwassen. Het college had zijn tijd van wonderkind gehad, de ernst des levens diende zich aan. Formele technieken zijn, zowel bij probleemanalyse als bij de constructie van oplossingen, een steeds grotere rol gaan spelen. De formele manipulaties zijn gestroomlijnd en gesystematiseerd en het vocabulaire dat in problemen herkenbare patronen beschrijft heeft zich ontwikkeld. In de jaren dat Martin Rem het college ontwikkelde, groeide dankzij mensen als Wim Feijen de instructie zonder tot routine te vervallen tot een solide traditie.

Kortom: een bloeiende activiteit in de kracht van zijn leven, een activiteit waarin het ideaal van Von Humboldt, nl. de verstrengeling van onderwijs en wetenschappelijke ontwikkeling, volledig tot zijn recht is gekomen. Dankzij wat wij in ons optimisme nog 2-fasen structuur noemen, hoewel het ernstig te bezien valt of die 2de fase ooit gerealiseerd kan worden, houdt dit college nu op te bestaan. Vrolijk stemt dit niet. Maar we kunnen proberen ons te troosten en wat lichtpuntjes te ontwaren, (Dat is nl, nog niet wettelijk verboden.)

We kunnen in elk geval dankbaar terugzien op de afgelopen 17 jaar, dankbaar dat het college tot wasdom heeft kunnen komen, dankbaar jegens alle instructeurs die tot de perfectie en verbreiding hebben bijgedragen, en dankbaar jegens al die studenten en anderen, die het college niet als spons, maar als wetsteen hebben bijgewoond.

We mogen ook dankbaar zijn voor wat we er zelf van hebben geleerd. Het heeft ons geleerd dat zoiets als programming methodology inderdaad bestaat; het heeft ons ook het bewijs geleverd dat dit onderwerp doceerbaar is —wat niet betekent dat iedereen het leren kan, maar dat is met elk doceerbaar onderwerp zo— . Het heeft ook onze appreciatie van formele technieken verhoogd: we hebben uit ervaring geleerd dat het wijdverbreide bijgeloof dat formele behandelingen noodzakelijkerwijze vervelend en langdradig zouden zijn om het voorzichtig uit te drukken niet gerechtvaardig is. Als onze ervaringen overdraagbaar zijn tot de wiskunde in het algemeen —en ik zie geen redenen waarom dat niet het geval zou zijn— is daarmee een methodoligisch vergezicht getoond om van te likkebaarden. De eigenlijk toch verrassende snelheid waarmee de invloed van dit college zich over de aardbodem heeft voortgeplant is de zoveelste rechtvaardiging voor de verwachting dat in de komende decennia computing science een zeker zo diepgaande invloed op de wiskundebeoefening in het algemeen zal hebben, als in het verleden de physica op de analyse heeft gehad. En dat is een opwindende gedachte!

En als laatste troost voor hen die het jammer vinden dat dit college in de kracht van zijn leven ophoudt te bestaan een herinnering aan het welbekende advies het feest te verlaten wanneer het nog leuk is.

Namens alle betrokkenen dank ik U voor Uw aandacht.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 7 december 1983 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD870

My mother’s proof of the Butterfly Theorem (see EWD866)

In a circle with centre O the chords AD and BC intersect one another in Q. The line PQR intersects AB in P and CD in R and is orthogonal to OQ. Prove PQ = QR.

(The name “Butterfly Theorem” is derived from the shape of the quadrilateral ABCD.)

Mother only used that the circle is a conic section and that Q divides the dotted chord into two equal halves. With O in the origin and the dotted chord of length 2⋅q along the y-axis, the substitution x ≔ 0 reduces the equation of the conic section to

y² = q²            (0)

The substitution x ≔ 0 reduces the equation of the (degenerate) conic section consisting of the lines AD and BC to

y² = 0            (1)

The substitution x ≔ 0 reduces the equation of any other member of the bundle on those two, i.e. of any other conic section through A, B, C, and D, to

y² + λ ⋅ y² = q² + λ ⋅ O       or

(1 + λ) ⋅ y² = q²            (2)

for some λ. This holds in particular for the (degenerate) conic section consisting of the lines AB and CD. Since the two roots of (2) have equal absolute values, this concludes the proof.

*                       *
*

Mother’s proof is far superior to mine. I worked with line bundles. By recognizing pairs of lines as conic sections she did it with a bundle of conic sections. And, in passing, she generalized the theorem. To quote Ross Honsberger “Bless her heart!”.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 18 December 1983 prof.dr.Edsger W. Dijkstra Burroughs Research Fellow

transcribed by Jonathan David Arndt
revised 13-Dec-2019

EWD872-0

The little essay I could not write

A month ago, I read inside the back cover of the Communications of the ACM, Vol.26, nr.12 (Dec. 83) an amazing advertisement of Reston Publishing Company Inc.. A book titled "The Programmer's Craft" is recommended as follows:

"A practical book that explores the theory and techniques that lie behind programming. Informal and easy-to-read, the mathematical rigor is kept to a minimum in favor of covering as many concepts as possible."

As you may believe, I was shocked by the profound misunderstandings reflected in that last sentence, so shocked, in fact, that I tried to devote a little essay to its analysis. In that essay I described how ease of reading is served by clarity and precision and how "mathematical rigor" has been designed to provide just that. And I wanted to explain how your programs become better, the fewer concepts you use. And finally I should point out how misled a society is when it considers "mathematical rigor" --its most helpful friend-- the pinnacle of user-unfriendliness.

But my efforts failed, and after several trials I gave up. I could do nothing but belabour the obvious! So the only thing I can do is to draw your attention to the quoted blurb and to ask

EWD872-1

you to analyse it yourself: for the rest of your life, the would-be recommendation "easy-to-read" will instantaneously fill you with grave suspicion.

*                *
*

Now I have not written my essay, there is still room on this page to quote two theses recently stated by Michel Sintzoff. They provide a nice contrast.

"The software industry is the first intellectual industry in history."

"The software industry is to become a precision industry based on scientific methods (much more so than the watch- or airplane industries)."

To which I can only add "Amen".

Plataanstraat 5
5671 AL NUENEN
The Netherlands

13 January 1984
prof.dr. Edsger W. Dijkstra
Burroughs Research Fellow

Transcriber: Kevin Hely.
Last revised on Thu, 19 Jun 2003.

EWD873

Trip report E.W.Dijkstra, London and Colchester, 16-20 Jan.1984

In her capacity of BP Venture Research Fellow, Netty van Gasteren attended a two-day seminar in London that was presented by her three colleagues in Edinburgh: Rod Burstall, Gordon Plotkin, and Robin Milner. In my capacity of her supervisor I could join her, and so did, since it seemed and effective way of being briefed on what the trio is up to, and I could combine it with a visit to the University of Essex, where I would like to meet Dr. Roland Backhouse.

We left Eindhoven with the 13:36 train and caught the 15:15 KLM coach from Amsterdam Central Station to Schiphol, where we had plenty of time to catch KL123 to Heathrow --in view of the unreliable weather we had not scheduled our trip tightly--. Flight KL123 was so bumpy that Netty was unable to eat on board; fortunately she had a little something at the Airport. (We flew in a good old DC8, planned to be sold at the end of the year. It became quite clear that the flight personnel would only part from it with regret, since it was the type of plane they liked most. In London we had one of the smoothest landings I ever witnessed --and that in spite of the most lousy weather!-- and I could understand some of their affection for the old machine!) Keith Cowey of the Venture Research Unit collected us and early in the evening we arrived at our destination, the Shepperton Moat Hotel.

The Edinburgh trio was scheduled to arrive one hour later --just in time for dinner--, but 5 inches of snow in Edinburgh delayed their flight so much that I had already prepared a replacement lecture, in case they did not show up, when they finally arrived. That was after the soup: we had given up waiting.

That night I learned that, if you have an electronic travel alarm, you should check the battery before leaving: mine was dead. So I switched on the alarm provided by the hotel and went to bed. That that piece of equipment was out of order I only learned the next morning when I overslept. Eventually Netty woke me by telephone. I had a high-speed breakfast, and then the seminar started.

The theme was "Developing a Science of Complex Discrete Systems" --and not "Complete", as was typed on the list of participants--. Each of the three speakers had two slots. Rod Burstall spent one slot to an overview, to his experience with "Categorical Programming" and to the work he did with Butler Lampson --who just left Xerox PARC and went to DEC-- on "A Kernel Language for Abstract Data Types and Modules". His second slot was mainly filled out with an example he had worked out the evening before. He wanted to show the usefulness of his notion of "type" in program specification and showed his initial specification of a thermodynamics programming package used in the oil industry.

Robin Milner's topic was "Using algebra for concurrency: some approaches". For reasons of time he gave only an introduction (which could have served as an introduction to Tony Hoare's Communicating Sequential Processes as well). His lecture was built on on two extremely carefully chosen examples, and was a delight to listen to. He abstained from trying to sell the immediate relevance of his work to the oil industry.

Gordon Plotkin's topic was a "Kernel Language", with its semantics so well-defined and its proof rules so well-established, that it can serve as the foundation for whatever programming language we would like to define and master. His goal seems very close to the one Scott and Strachey set themselves when they developed their "Denotational semantics"; he was very dissatisfied --and I think rightly so-- with how that had worked out in practice. (Whether his approach will work out better remains to be seen.) It was, however, very hard to extract this topic from his presentation, which was chaotic in the extreme. He spent most of his time on clarifying his baroque syntax, on explaining LISP fundamentals --such as the difference between "cons" and "append"--, on a too elaborate example for the generation of the possible structures of paraffin molecules, and on correcting his numerous errors.

In a number of rather different ways, the whole seminar struck me as very British. I mention the following observations.

(i) With great imagination, they set themselves high and intellectually ambitious goals. But their notations abound with local conventions, which are often uncritically adopted and never explicitly stated. (They seem to have never made up their minds about how to delineate scopes of dummies and, as a result, they usually don't; they rarely state the relative binding power of infix operators, etc..)

(ii) The role of Logic --in Britain still Philosophy's Handmaiden-- is primarily descriptive and that of mathematics in applications is primarily one of "modelling". (This was striking for us: we heard the term over and over again, whereas we never use it.)

(iii) When, at the end, Rod Burstall was asked whether this type of work was done only in Edinburgh, he said "Oh no,...", and listed a number of other British Universities!

(iv) The tension between academia and industry struck me as exceptionally strong. I found the speakers with their oily examples condescendingly talking down to their audience, but perhaps they were right: it was sometimes hard to believe half the audience consisted of scientists with a Ph.D --the one and only German participant was very different--.

On Thursday morning, 9 o'clock, Netty and I were collected by Dr. Ian White, who would take me to Liverpool Street Station and Netty to Britannic House. We were caught by one traffic jam after the other, and eventually I was fortunate to be able to catch the 10:50 train to Colchester. At 12:20, I arrived at the University of Essex; of the staff I was introduced to, Tony Brooker and Roland Backhouse were the only ones I had met before.

When I made the appointment, I had been asked whether I would be wiling to give a lecture, and I had agreed, giving as my title "The propositional calculus and Leibniz's Principle." Upon arrival I learned that I was scheduled at 15:00 and that the performance had been moved to a larger auditorium. (The P.A. system was excellent --for a change!-- but the --fixed!-- blackboard was not up to par.) I found it a very difficult audience to work with. Later I learned that I had had a double handicap to overcome. The first was that my audience had been familiarized with the misuse of notation that distorts "P≡Q ∧ Q≡R" into "P≡Q≡R"; the second one was that my audience, consisting of Essex students of computing science, was essentially amathematical. I know that --mathematics being as unpopular as it is-- more departments have tried to offer --by way of "computing without tears"-- computing without mathematics.

My visit to Essex was my N-th confirmation (N>>0) that this does not work. It made the whole place rather depressing (as exemplified by the staff member who seemed to welcome each sabbatical leave "if only to be away from Essex).

An hour after my talk had ended, we were joined by Netty. Until 20:00 we were left to our own devices. Then our hosts joined us for a very pleasant and civilized dinner. At 23:30 we were back in the University's Conference Centre --in the old mansion of Wivenhoe Park--. That night we were its only occupants --I had been given a key for the front door--. The next morning, 7:45, personnel had arrived to give to give us our breakfast and to order our taxi, which on its way to the station ....... got stuck in a traffic jam. By way of encouragement the driver told us that British Rail was on strike at several stations. Our train, however, was on schedule and we caught it. The snow, which had been predicted, did not show up and without further disturbances we completed our return journey: at 17:25 we were back in Eindhoven.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
22 January 1984
prof. dr. Edsger W. Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 27 Sep 2004

EWD876

De microprocessor als lollie

Onze overheid heeft besloten de informatica in Nederland te stimuleren door onder andere het vak in het middelbaar onderwijs in te voeren en scholen met microcomputers uit te rusten opdat brede lagen van de bevolking leren “met de computer om te gaan”. De veronderstelling is kennelijk dat wijdverbreide invoering van microelectronica onze geteisterde economie er weer bovenop zal helpen. Je kunt over deze heilsverwachting je twijfels uiten, maar deze twijfels, hoe gegrond ook, worden niet meer gehoord: de microelectronica is de laatste strohalm waaraan een wanhopige maatschappij zich heeft vastgeklampt als de doodzieke patient aan het wonderelixir van de kwakzalver. Gemakshalve, en ook omdat ik noch econoom, noch politicus ben, zal ik het belang van stimulering der informatica maar niet ter discussie stellen; de vraag, die ik wel wil stellen is of we mogen verwachten, dat de voorgestelde maatregelen effectief zullen zijn.

We weten langzamerhand dat de bijdrage van de electrotechniek zich beperkt tot het leveren van de hardware en dat we het grote probleem hoe we dat spul dan verantwoord kunnen gebruiken zelf zullen moeten oplossen. We weten ook, dat dit probleem, dat niet voor niets al meer dan 15 jaar zich onder de naam van “software crisis” aandient, hondsmoeilijk is. We weten ook, dat de ervaring van die jaren onomstotelijk heeft aangetoond dat de werkwijze van de ambachtelijke programmeur essentieel te kort schiet, en we begrijpen waarom.

Het z.g. “iteratief ontwerpen” is nl. de enige strategie, waarover hij beschikt. Men maakt een zo goed mogelijk prototype en probeert dat dan; waar het niet bevalt, brengt met wijzigingen in het ontwerp aan en probeert opnieuw, enz. Deze iteratieve strategie staat of valt met de mogelijkheid effectief te observeren of het prototype bevalt; het testen van programma’s kan wel de aanwezigheid van tekortkomingen aantonen, doch nimmer hun afwezigheid, en daarmee vervalt voor software het iteratief ontwerpen als adequate strategie.

Programmacorrectheid kan onmogelijk experimenteel worden vastgesteld en moet dus —als we er om geven!— anders worden aangetoond. De ontwikkeling van de daarvoor benodigde formele technieken is een van de wetenschappelijke triomfen van de informatica van de laatste decade, en we hebben nu het stadium bereikt, dat de werkelijk professionele informaticus bereid is om programma’s, die bijzonder genoeg zijn om het publiceren waard te zijn, te publiceren zonder ze zelf te hebben geprobeerd. Dat in het merendeel van de software industrie deze wetenschappelijke benadering nog geen wortel heeft geschoten en op de ambachtelijke manier wordt voortgetobd, is betreurenswaardig maar —organisatorische traagheid zijn wat zij is— niet verwonderlijk.

En nu gaat de microcomputer op de middelbare school geintroduceerd worden. Wat mogen we van het peil van dat onderwijs verwachten? Ik vrees, dat het niet eens het niveau van de ambachtelijke programmeur zal halen, maar blijft steken in het niveau van de hobbyist. De geestelijke bagage van de hobbyist is te enen male ontoereikend. Hij beschikt niet over de essentiele redeneertechnieken om met vrucht over een programmeeropgave te denken, en nog minder over het abstractievermogen dat nodig is om deze technieken met voldoende effectiviteit toe te passen. Niet allen dat de hobbyist het essentiele ontbeert, hij hecht —waarschijnlijk bij gebrek aan beter— altijd overmatig belang aan irrelevantie. De hobbyist gelooft, dat hij een beter programmeur is naarmate hij meer weet van specifieke machines, programmeertalen, implementaties, pakketten, noem maar op. Hij stopt zijn hoofd vol met allerlei vergankelijk feitenmateriaal waarvan de professionele informaticus allang geleerd heeft het te negeren omdat het zijn werk nodeloos afhankelijk maakt van specifieke omstandigheden. Terwijl de professionele informaticus inmiddels weet dat het de taak van de machines is om onze programma’s uit te voeren, gelooft de hobbyist nog, dat het de taak van de programmeur is om zijn machine te instrueren, hoe onbeholpen die machine ook mag zijn. Hij staat onveranderlijk toe dat de gebreken van zijn gereedschap door zijn hele werk heen vreten, omdat hij leren leven met die gebreken ten onrechte ziet als de kern van de opgave. En dat is, waarom hobbyisten onderling altijd juist praten over dingen, die er nauwelijks toe doen.

Wat ons voor grof geld gepresenteerd wordt als een stimulering van de informatica zal hoogstwaarschijnlijk ontaarden in een grootschalige stimulering van het computerhobbyisme, zulks ten detrimente van de landelijke informatica. Wij moeten vrezen dat het leiden zal tot grootschalig geklungel, waarin een aanzienlijk gedeelte van de ter beschikking staande intellectuele energie zal worden opgeslokt. In een tijd van grote werkloosheid, waarin mensen hun energie niet zinvol kwijt kunne, zijn zoethouders en tijdvullers wellicht te verdedigen; en als de gemiddelde Nederlander op het schaakspel is uitgekeken, moeten we de microcomputer misschien als milieu-vriendelijk zoethoudertje verwelkomen. Maar zo’n maatregel dan presenteren als redding van onze economie is wel een wat gekleurde voorstelling van zaken.

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

AvG34 / EWD877

Some useful formulae

Let f be a propositional expression and R a propositional variable. Using the slash "/" to denote "substituted for", we have the general equivalences

f ≡ ( f ( false / R ) ∨ R ) ∧ ( f ( true / R ) ∨ ¬ R )

f ≡ ( f ( true / R ) ∧ R ) ∨ ( f ( false / R ) ∧ ¬ R ) .

(We don't prove this; it should probably be proved using induction over the syntax.)

The purpose of this note is to draw the attention to a few special instances.

P ≡ Q ∨ R ≡ (( P ≡ Q ) ∨ R ) ∧ ( P ∨ ¬ R )

P ≡ Q ∧ R ≡ (¬ P ∨ R ) ∧ (( P ≡ Q ) ∨ ¬ R ) .

(Substituting in the latter formula ¬P for P we get

P ≢ Q ∧ R ≡ ( P ∨ R ) ∧ (( P ≢ Q ) ∨ ¬ R ) .

We used the last formula recently to prove

( y ≢ z ∧ a ) ∧ ( z ≢ y ∧ b ) ≡

( y ∨ a ) ∧ ( z ∨ b ) ∧ (( y ≢ z ) ∨ ¬ ( a ∨ b )) .)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 8 February 1984 drs. A.J.M. van Gasteren prof.dr. Edsger W. Dijkstra

transcribed by Alejandro Ruiz
revised Wed, 12 Nov 2008

AvG36 / EWD878

A monotonicity argument

In the following, square brackets denote universal quantification over x and y ; f is a function of two arguments such that
  [x < y ≡> f x y < f y x] . (0)

From the above, we derive the following results.

Since p < q ≡ q > p from (0):
  [y > x ≡> f y x > f x y] .

From the above, by renaming the dummies:
  [x > y ≡> f x y > f y x] . (1)

From [x = y ≡> f x y = f y x], by taking the term-wise disjunction with (0) and and (1) respectively:
  [x ≤ y ≡> f x y ≤ f y x] (2a)
  [x ≥ y ≡> f x y ≥ f y x] . (3a)

By taking the counterpositives of (1) and (0) respectively —which to all intents and purposes amounts to doing nothing—
  [f x y ≤ f y x ≡> x ≤ y] (2b)
  [f x y ≥ f y x ≡> x ≥ y] . (3b)

From (2) and (3) respectively:
  [x ≤ y ≡ f x y ≤ f y x] (4)
  [x ≥ y ≡ f x y ≥ f y x] . (5)

From (4) and (5), by taking the term-wise conjunction:
  [x = y ≡ f x y = f y x] (6)

By negating both sides of (5) and (4) respectively:
  [x < y ≡ f x y < f y x] (7)
  [x > y ≡ f x y > f y x] . (8)

It is nice to see how the five equivalences (4) through (8) follow from the single implication (0). Note that, since for reasons of symmetry (0) and (1) are equivalent, all formulae could also have been derived from (1).

We draw attention to the fact that we did not use that f depends on both its arguments: if f only depends on its first argument, (0) postulates that f is an increasing function, but if f only depends on its second argument, (0) postulates that f is a decreasing function of that argument.

*      *
*

The above grew out of our dissatisfaction with the way we were introduced to Euclidean geometry. With congruences, two theorems were proved seperately, viz.

“An isosceles triangle has two equal angles.” and
  “A triangle with two equal angles is isosceles.”

Prior to that it had already been shown that opposite to the larger angle lies the larger side, in the jargon: α > β ≡> a > b. This is a statement of the form (1); for the proofs of the theorems, congruences are not needed at all, since the theorems are subsumed in the conclusion corresponding to (6): α = β ≡ a = b.

We had similar experiences with the two theorems

“An isosceles triangle has two angle bisectors of equal length.” and
  “A triangle with two angle bisectors of equal length is isosceles.”

Thanks to the above, both theorems are subsumed in

“In a triangle, the larger angle has the shorter bisector.”,

a theorem that can be proved in a variety of ways. For instance, in a triangle with sides of lengths a, b, and c, the square of the length of the bisector of the angle opposite to a equals

b · c · (1 – (a / (b + c))²) .

This expression is an increasing function of b and a decreasing function of a. It is not difficult to show that an f that is an increasing function of its first argument and a decreasing function of its second argument satisfies (0).

drs. A.J.M. van Gasteren
BP Venture Research Fellow
Dept. of Mathematics and
 Computing Science
University of Technology
5600 MB EINDHOVEN
The Netherlands 22 February 1984

prof. dr. Edsger W. Dijkstra
Burroughs Research Fellow
Plataanstraat 5
5671 AL NUENEN
The Netherlands

transcribed by Matthew Hill
revised 08-Jan-2015

EWD879

Trip report E.W.Dijkstra, London, 14-17 February 1984

After an oral examination, my weekly lectures, and a quick lunch, Wim Feijen took took me in his car to the Eindhoven railway station for the 13:36 train to Amsterdam. After all the rain that had flooded Europe, the three rivers I crossed were most impressive. I left Eindhoven in the sun, and arrived in Amsterdam in fog. Fortunately, the fog did not prevent flight KL123 --in the same good old DC8 "Christoforus Columbus" I had last month-- to be flown dead on time. In London the Piccadilly Line made the same squeaking noise as last month; did I also have the same carriage? Shortly after 18:00 I arrived in St. Ermin's Hotel, which was very good --for the heart of London even unusually so--. I had dinner with C.A.R. Hoare, J.C. Shepherdson, D.A. Turner, G. Chen, and L. Paulson; after dinner we were joined by P.Martin-Löf, who had excused himself to prepare his visuals.

The occasion was the Royal Society Discussion Meeting on "Mathematical Logic and Programming Languages". Measured by the number of attendants --450--, the discussion meeting was an exceptionally great success. Measured by the composition of the audience it was probably less so. The audience consisted almost exclusively of (mostly) computing scientists and (some) logicians of British Universities. In view of the target audience that had also included "professional programmers and consultants from industry and commerce", "mathematicians and scientists" and "informed citizens", these latter categories were definitely under-represented. (Among the speakers --10-- I was the only representative from industry.) With the exception of Sir Michael Atiyah, FRS -he was one of the three organizers, but seemed to have left the organization to Hoare and Shepherdson-- the British world of academic mathematics was totally absent. (I was disappointed, but my British colleagues told me that this was exactly what they had expected.) I even don't know whether Atiyah's presence really counts; he seemed better at talking than at listening. The audience was also very British: Ole-Johan Dahl (Oslo), Maurice Nivat (Paris) and Michel Sintzoff (Louvain) were rare exceptions.

For two days, we had two speakers in the morning and three speakers in the afternoon:

-- R. Kowalski, D.A. Turner

-- D.I. Good, R. Milner, P. Martin-Löf (a last-minute replacement of D.S. Scott, who had suddenly decided not to show up)

-- E.M. Clarke, L.G. Valiant

-- J.R. Abrial, C.A.R. Hoare, E.W. Dijkstra.

R. Kowalski gave a talk titled "The relation between logic programming and logic specification". I had never heard Kowalski before, and I think I shall not listen to him again. The first half of his talk was on "imperative" versus "declarative" without defining the terms; in the second half he argued that the distinction was not that relevant.

D.A. Turner -on "Functional programs as executable specifications"- was clear and to the point. I was pleased to see that the scientist is gaining on the salesman. I was struck by the emphasis with which he regarded a formula like "x = 1:x" not as a (symmetric) rewrite rule but as an equation; the latter interpretation forces him to introduce "infinite objects", and I realized that I was not sure that I was entirely happy with that metaphor.

The Wednesday afternoon session was opened by D.I. Good on "Mechanical proofs about computer programs". He was the only speaker with slides --white letters on a blue background-- and his talk about the GYPSY environment as more a presentation than a lecture. Dr. D.W. Braben of BP later remarked to me that Good seemed to have been the only speaker who had adjusted his talk to the industry people that had been supposed to be present in the audience. The automatism with which Braben identified people from industry with second rate scientists was very revealing.

Then we had R. Milner on "The use of machines to assist in rigorous proofs". He talked about the l.c.f project ("logic for computable functions"), about ML ("metalanguage for conversation"), about tactical manoevres in proofs and "the notion of strategy construction". This work is now going on for more than 10 years, and Springer has even published a book about it. I realized that I could think of no one on the continent of Europe that is familiar with this work. Strange..... Are the British insular or are we blind? Do we think it too abstract and/or philosophical? Or too much bogged down by implementation? Or both. I did not run to the store to buy the book. Milner made a clear effort to reach his audience and was (again) a pleasure to listen to.

The day was closed by P. Martin-Löf on "Constructive mathematics and computer programming". I quote from his abstract ".... it no longer seems possible to distinguish the discipline of programming from constructive mathematics. [...] the intuitionistic theory of types [...], which was originally developed as a symbolism for the precise codification of constructive mathematics, may equally well be viewed as a programming language. [...] the inference rules of the theory of types, which are again completely formal, appear as rules for correct program synthesis. Thus the correctness of a program written in the theory of types is proved formally at the same time as it is being synthesized." But the 50 minutes were not enough to introduce an ignorant audience to intuitionistic type theory to the extent that it could follow a comparison with Scottery. He was a very sympathetic speaker and convinced at least me that something (possibly even of great conceptual elegance) was going on. He spoke with an endearing care.

In the evening we had the speaker's dinner, at which I had the honour of sitting opposite to Sir Andrew Huxley, the current President of The Royal Society. It was a very enjoyable meal. [When Sir Andrew Huxley left the table, so did Sir Michael Atiyah, leaving Hoare and Shepherdson with the guests. Did we get a glimpse of the pecking order?]

Thursday morning was opened by E.M. Clarke Jr. on "The characterization problem for Hoare logics: a survey". They say that familiarity breeds contempt: Clarke consistently pronounced "axiomatization" as "axiomization". The fact that he ended with the well-known "topics of further research" did not dispel the impression that this line of research has reached its natural end; it did, in fact, enforce it.

The second speaker was L.G. Valiant on "Deductive learning". He did not have much to tell (yet?). On account of arguments from complexity theory he tried to show that "teaching by example" does not work, but I am told that even the artificial intelligentsia have already acknowledged that. I did not like his cartoon-like pictures (which I thought slightly offensive); apart from that, he was a nice and modest speaker.

After lunch the last session was started by J.R. Abrial on "Program construction as a mathematical exercise". He stressed the importance of studying "the mathematical framework within which each program is supposed to behave. [...] Experience shows that the amount of logical and mathematical tools to be used in the construction of most computer programs is quite small." He lists sets, functions, relations, and natural numbers, sequences and trees. I found myself in partial agreement, having all the time the feeling of "Yes, but.....". In the talk he seemed to redo the foundations of mathematics, but is that really necessary? It might be. At the moment he did not convince me (though, admittedly, his stress on set theory somewhat put me off.) He was a very relaxed speaker, quite happy not to pronounce the s of the plural form.

He was followed by C.A.R. Hoare on "Programs are predicates". I quote from his abstract "A program is identified with the strongest predicate that describes every observation that might be made of a mechanism that executes the program. A programming language is a set of programs expressed in a limited notation, which ensures that they are implementable with adequate efficiency, and that they enjoy desirable algebraic properties. A specification S is a predicate expressed in arbitrary mathematical notation. A program P meets this specification if P → S." In the above quotation the contrast between "limited" and "arbitrary" carries the core of his message. The 1-place buffer, the 2-place buffer --and its implementation using 2 1-place buffers-- and the recursively defined unbounded buffer were his well-chosen examples; the lettering on his transparencies was exquisite, and the talk was a difficult act to follow.

But I was fortunate. During the interval Cliff Jones reminded me how once, at a W.G.2.3 meeting, the lamp of the overhead projector blew as soon as he started using the infernal equipment (about the use of which I had just teased him). In order to give the audience the opportunity to adjust itself to my accent, I started with a few silly remarks, and told that Professor Jones had just promised me not to pray that the lamp would blow under my fingers. I did EWD871, and just after I had explained "s wn u → u bn s" by "In addition, the machine reacts by making itself black."...... the bulb blew! I could not have staged it better. When, eventually, the bulb was replaced, I offered the burnt-out one to Cliff and continued my lecture. My talk was well-received. Upon the request of the session chairman I then closed the Discussion Meeting, thanking the organizers, the speakers and the audience. It was 17:45, and shortly afterwards the hall was empty.

In retrospect it was a pity that I did not end with a summing up or, possibly, a synthesis of some sort. Perhaps I should have tried, instead of telling my own story, but this time I preferred to stick to what I had prepared for the occasion.

Dahl, Hoare and Gries joined me for dinner.

*              *
*

The next morning, while I was writing at the make-up table in my hotel room a letter to W.M. Turski, the telephone rang. It was Braben asking whether he could see me. He arrived within 15 minutes, while I was checking out. He immediately told me that he had ordered a car to collect me and to take me to Heathrow, so that we could have some more time. So, eventually and quite unexpectedly, BP saw me to the airport.

Being the nervous traveller I am, I arrived at the airport well in time, the more so since my flight KL120 was half an hour late, due to late arrival of the aircraft. Fog in Amsterdam was the explanation. When we arrived in Amsterdam, I saw that I had plenty of reason to be glad that we landed at all. The decision not to book on the NLM flight from Gatwick directly to Eindhoven had been a wise one.

At 17:45, Ria collected me at the Eindhoven railway station. At 20:00 we were back in Eindhoven in order to listen to a string quartet. The first violinist could do with a more gifted barber. We were back in Nuenen in time for a telephone call at 23:00 from Detroit.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
20 February 1984
prof.dr. Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Sat, 28 Feb 2004

  EWD 881

A review of "The Evolution of Programs"

Nachum Dershowitz, "The Evolution of Programs", Birkhäuser, Boston - Basel - Stuttgart, 1983, 357pp.

The printing of this book is atrocious enough to decide never to open again a book published by Birkhäuser. Type founts and layout of pages, lines, and formulae are ugly and the individual characters are often printed with a quality that reminds me of The Compact Edition of the OED, viewed through a magnifying glass. For all, except the blind, this book is a pain to read. (If the author has provided the publisher with a camera-ready text, he shares the blame.)

The main chapters have the titles "General Overview", "Program Modification and Debugging", "Program Abstraction and Instantiation", "Program Synthesis and Extension", "Program Annotation and Analysis"; then we have 5 appendices "Global Transformations", "Program Schemata", "Synthesis Rules", "Annotation Rules", and "Implementation".

To give a flavour of the book I quote the opening paragraph of the Preface:

"Programs are invariably subjected to many forms of transformation. After an initial version of a program has been designed and developed, it undergoes debugging and certification. In addition, most long-lived programs have a life-cycle that includes modifications to meet amended specifications and extensions for expanded capabilities. Such evolutionary aspects of programming are the topic of this monograph. We present formal methods for manipulating programs and illustrate their application with numerous examples. Such methods could be incorporated in semi-automated programming environments, where they would serve to ease the burden on the programmer."

and from the chapter "Program Modification and Debugging" the Overview:

"For program modification one needs a program satisfying its input-output specification along with the specification for a new program. Comparison of the two specifications may suggest a transformation of the given program that will bring it [in] line with the new specification. Even if the transformed program does not exactly fulfil the goal, it may serve as a basis for constructing the desired program."

Given a program and a specification, the claim that the former meets the latter has the status of a theorem without its proof. Not surprisingly, the author discovers that for the justification of modifications one usually needs the correctness proof of the initial program as well. And that is regarded as awkward: "Even if [the programmer] uses one of the current prototype verification systems, he is required to supply most, if not all, of the necessary invariant assertions, in addition to guiding the theorem prover. The goal of automatic program annotation is to relieve the programmer of some of this burden." The central position of the program as the programmer's product is also reflected in his remark "Ultimately [sic], it is the responsibility of the programmer to ensure the correctness of his product."

But it is a severe mistake to think that a programmer's products are the programs he writes; the programmer has to produce trustworthy solutions, and he has to produce them and present them in the form of convincing arguments. Those arguments constitute the hard core of his product and the written program text is only the accompanying material to which his arguments are applicable.

By accepting as programmer someone that works under the motto "Code first, think later", Dershowitz adopts the mistake, like so many of his confraters in Artificial Intelligence who try to develop "tools" for obsolete programming techniques. His saving graces are that he knows that part of his work is "putting the cart before the horse" and that he absolutely refuses to oversell what those wonderful "programming environments" might do for us in the future. And we may be grateful to him for his reminder that Artificial Intelligence does not operate in the forefront of Computing Science.

A final remark. György Pólya has now been accepted by so many --and Dershowitz is no exception-- as the high priest of problem solving that doubting the wisdom of his teachings amounts to blasphemy. But when I read Pólya, each page showed me to have been written by a man who had never programmed and since then I am expecting the moment that we shall clearly see the extent to which Pólya's recommendations are a product of his time. I see in Dershowitz's book and indication that we are approaching that moment.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
27 February 1984
prof. dr. Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 27 Dec 2004

EWD 885

Trip report E.W.Dijkstra, M�nchen, 12-14 April 1984

The moral of this trip is: don't organize meetings on Friday the 13th, at least not in M�nchen. (Three years ago —see EWD790— we had a similar meeting on 19 May.) It was a 36-hour trip: on Thursday evening I left Eindhoven at 21:10, on Saturday morning I returned at 9:12, all courtesy Britannia Express. But for the Britannia Express it was still "out of season", which means that the 1st class sleeper is only included during the weekend. So, on the journey out, I used the 2nd class couchettes; I shared the compartment with two Germans, the berth was uncomfortable, and I did not sleep at all. On the way home, the weekend had started and I had a compartment in the sleeper, which was a good thing because the train was very crowded, the German Easter holiday having started with a discount weekend of the Deutsche Bundesbahn. As there was something wrong with a shock absorber between two carriages, it was not a smooth ride, but I was so tired that I did not notice it and slept until I was woken up by the passport control at the German/Dutch border. (On the way out, the German customs went through the train with a sniffing dog, undoubtedly for drug control.)

At 7:22 I was met by Herr Kuss and Manfred Broy; Fritz L.Bauer joined us a few minutes later and the four of us went to the Technical University M�nchen, where we made ourselves a breakfast from the rolls and milk we had bought on the way. Around 8 o'clock we were joined by Tony Hoare, who had arrived by plane from Heathrow the previous evening. He also had hardly slept, but that was because he had been working on EWD880b . His efforts had been rewarding: the first thing he showed me was a simplification of my proof.

The day was spent at the selection of the participants for the next Marktoberdorf Summer School. We had to select 90 participants from 160 applications. More rolls were bought in by way of lunch, and thanks to the fact that we made it a non-stop meeting, we were finished in time for Tony to catch his return flight at 17:15. (On Sunday, Tony would be off to Minneapolis, where he hade been asked to perform in a Distinguished Lecturer Series and to give a few further seminars; he would be back in Oxford before the end of the week. I could understand the choice of the organizers. At such occasions, the hospitality lavished on the Distinguished Speaker is always beyond reproach; nevertheless, the life of a Distinguished Speaker is a hard one.) The difficulty of the selection process is the comparison of letters of recommendation written by different people. It was very amusing (and sometimes amazing) to observe how much (and by what curious channels) we collectively knew about the candidates or their recommenders.

Afterwards Manfred, Fritz and I had a light dinner in town. Manfred then went his way and I went with Fritz to his home in Grafrath until I had to go to catch my train. In Grafrath I had two surprises. The one was that I met the good old Alston S.Householder —nearly 80— , who was staying with the Bauers. The other one was when Fritz said "Did you know that I have a new grand piano?". I said "No" and walked into the next room to have a look and a try. Immediately I could fully understand Fritz's pride and joy: a 2.15 m B�sendorfer (just for the record: serial nr. 36392). I played Scarlatti and Mozart, but not wearing the proper glasses and already having had two glasses of white wine, I left it at that. It was a delightful instrument.

I had planned to sleep on my way back twice as fast as usually, but I did not make it: on Saturday afternoon I took a solid nap of a few hours.

Plataanstraat 5 *) 5671 AL Nuenen The Netherlands | 15 April 1984 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

*) As of 1 September 1984 my mailing address will be

Department of Computer Sciences
The University of Texas at Austin
AUSTIN, Texas 78712-1188
Unites States of America

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD 887

Trip report E.W.Dijkstra, USA, 23 April - 10 May 1984

UT (=University of Texas) had invited Ria and me to Austin for a press conference and a reception to celebrate my acceptance of the Schlumberger Centennial Chair in Computer Sciences, Burroughs had asked me whether I could pay a visit to the University of Nevada at Reno, and I decided to return via Pasadena.

On Monday the 2nd day of Easter we left. Our daughter Femke drove us to the airport where KL665 took off at 14:20 for Atlanta, where we would have four hours to catch our flight EA271 to Austin. That was a long wait, the more so because KL665 arrived half an hour early and customs and immigration were very fast. (At the crucial moment I forgot the advice to present myself as mathematician and said that I was a computer scientist; as a result the customs officer asked me whether I brought any software into the country and ordered me to open my briefcase.)

On Thursday 3 May we were to fly on DL1770 at 16:15 to Dallas and from there with flight AA129 to Reno. This nervous traveller —who still had to return (for the first time unaided) his rented car— was very early at Austin Municipal Airport. This turned out to be very fortunate: at the Delta desk we heard that the flight was so much delayed that we could just catch an earlier UA flight to Dallas. And so we did. The last minutes of the flight to Reno were very bumpy. So were the first few minutes after take off the next day. (Must be the shape of the mountains near the Reno airport.) Flight UA1239 from Reno to Los Angeles was remarkable in that we left Reno half an hour late and arrived in time: I have timed it and at the intermediate stop at San Francisco we stood no longer than 13 minutes at the gate. We were impressed. At 20:42 we arrived rather hollow inside as we had expected to be served a meal during flight.

On Wednesday 9 May we returned with KL602 from Los Angeles to Amsterdam, where we arrived the next day at 17:25, which was 80 minutes late. Our suitcases were almost the first on the belt, Femke was with our car at the airport, and at 19:15 we were home (from which it can be deduced that Femke is not a slow driver).

*         *         *

We had planned to start in Austin in a rented apartment but upon arrival we heard that house prices were rising at a rate of 25% a year and that we had better buy a house as soon as possible. And so we did, but as a result we spent in Austin 9 very busy days. The day after our arrival we walked with Bob Boyer for a couple of hours in the vicinity of the UT campus (as I had once written that it would be nice to live, if possible, within walking distance of the University). But we were not attracted by what we saw: the houses were either too big or too shabby. On Thursday, house hunting started in real earnest, but it took the realtor that whole day to figure out what type of house we were looking for. (And even then the hunting was not very effective: the houses he showed were often as big a surprise for him as for us. As the days went by I got rather annoyed that he did not have floor plans. The problem was, of course, that we attached importance to other house characteristics than his average customer.) At the end of Monday morning we were shown the floor plan of a bungalow the construction of which had just started in Lakewood. It would be finished end of August. The floor plan could still be changed: by moving the kitchen and changing the shape and size of one of the bedrooms we got just what we were looking for. (The last night in Austin, Ria did not sleep, figuring out that she would prefer the kitchen entry in another wall. That meant another trip to the builder. The improvement will be implemented.) The rest of the time in Austin was spent to financing, signing contracts, selecting carpeting, doorbells, dish washers and what not. When we left for Reno, we were utterly exhausted.

On Wednesday afternoon, 25 April, I was interviewed by journalists of three papers. They were nice and evidently well-briefed. Among all the questions only one to which I had to answer "It would be rather unwise to answer to that one, wouldn't it?". It would have been much more efficient if I had received them simultaneously, but each paper wanted its own story, and I had to receive them in succession. I was then offered my reception in "the Littlefield House" which UT seems to use for rare occasions only: one of the guests told me that this was the first time in the 20 years he was at UT that he saw its inside. It was a pleasant surprise to be congratulated by Sandy Fraser; he is still with Bell Labs, but happened to be around.

The whole of Tuesday morning 1 May I was at the Austin Research Center of Burroughs. First I arranged my next trip to the USA with Larry Thomas, then I gave a lecture on the theorem I proved on 21 February. I had never given this lecture before and my ARC performance was a kind of dry run for Reno. It took 90 minutes. Bob Boyer and J Moore of UT were in the audience. Afterwards, by the look on their faces, I feared they had not liked it, but my fear was unjustified: "If proving in that degree of detail catches on, we'll soon be out of job!".

Twice we had dinner at Chandy's home, once with Bob Boyer and his wife, once with Pinkston and his wife. Pinkston is the recently appointed chief scientist of MCC (= Microelectronics and Computer Technology Corporation). I was reminded once more of the fact that, in American, mathematics is not called a "science"; could it be called a "scientific discipline"?

Ria and I spent the little time left "window shopping" in order to discover what we should take with us because it was either unavailable or much more expensive. (We observed, for instance, to our surprise that, whereas the price of blank audio cassettes is in general the same —why not? it is mostly Japanese import anyhow— the high-quality XLI-S of Maxell is suddenly twice as expensive.)

Like at our previous visit, we stayed with Ham and Joanne Richards, and that was very pleasant. Besides that they gave us all sorts of useful advice: Ham recommended a ridge vent, Joanne joined us when we had to select tiles etc.

There was a flu in Austin. Just before we arrived, K.Mani Chandy had lost his voice —our arrival had rendered him speechless— , Ria lost hers several days later. Fortunately I could give my lectures without any problem. Both of us had some unpleasant physical reactions to the climate —heat or pollen— , but I did not contract the conjunctivitis I had feared.

*         *         *

Upon arrival in Reno we were picked up by a man from Burroughs who saw us to our hotel. Having to absorb a time shift of another two hours, we went to bed almost immediately.

Most of Friday I spent at the University. In the morning we had a general discussion about computing science and its teaching. There were about two dozen people present, and most questions posed to me made excellent sense. They have no Ph.D. program in mathematics or computing science and felt themselves more geared to vocational training. I have repeated my warning that the scientific/intellectual needs of industry should not be underestimated. Before lunch I was joined by Ria. The lunch was a grandiose affair with about three dozen people (should I say "dignitaries"?) and the food was excellent. As it was just before my performance, I did not eat too much of it. I had an audience of about 170 people, the lecture took this time 100 minutes; I had a good blackboard, but the chalk made lines that were a bit too thin. Afterwards we had a quiet chat with Dr.Warren Fox (Vice Chancellor for Academic Affairs) before he took us to the airport. It was a nice day and I was glad that I had accepted the invitation.

At LAX we were collected by Alain J.Martin and Jan L.A. van de Snepscheut. We stayed with Alain & Marianne, on Saturday evening we had dinner with Jan & Trees, who were quite content with their house (which we had more or less selected on our previous visit to Pasadena).

We spent the weekend in peace and quiet. I wrote a few letters and a lot in my diary. (While in Austin I had lacked the time.) On Sunday afternoon, we went to see the desert plants in the Huntington Gardens. (A "must"!)

On Monday I took over Alain's lectures. The title of his course was "Communication and Synchronization" and I showed —once more!— the Chandy/Lamport Snapshot Algorithm, for which I needed the full 75 minutes. It was instructive for me to see their difficulties: they have very much an engineering mentality and I was obviously straining their powers of abstraction and of separation of concerns. (I had coloured machines and messages and in the second phase of the development I assumed that "by magic" no red message would arrive at a white machine. I had announced quite explicitly that I would eliminate the magic in the third phase of the development; yet it worried them all through the second phase.)

On Tuesday I gave my lecture a third time. This was clearly a lecture during term time: I had an audience of about 70 people, including Carver Mead, Chuck Seitz and Dick Feynman, to whom I had been introduced earlier that afternoon. (Becoming acquainted with Feynman was a privilege: here was a man that enjoyed his professorship! A refreshing and inspiring example.) The performance took 85 minutes and pleased me most of all. This time my introduction was beautifully smooth and I am looking forward to repeating that performance next week in Z�rich (at the ETH: again at an institute of engineering!).

One day, when I came to CalTech, Jan had just discovered that expressions can be evaluated using a queue instead of the familiar stack! The lovely thing was that he needed only five lines to describe his solution. Another day, Alain showed me a new beauty: a very simple solution of J.M.Morris's problem, viz. fair implementation of mutual exclusion using weak semaphores. Sjefke's original solution was very ingenious, but so complicated that I could never remember it. This one, which Alain designed together with Jerry Burch, is so elegant that I immediately showed it last Tuesday at my (last) lecture in Eindhoven. The moral is clear: never assume that something complicated cannot be replaced by something elegant. In short: the visit to Pasadena was highly rewarding.

Wednesday morning we did some shopping, Wednesday afternoon I composed a letter of recommendation, and then it was time to go to LAX. After having checked in we offered our hosts a dinner in the renewed airport restaurant. Since our flight was somewhat delayed —we saw our plane coming in during our appetizer— this was a nice way to spend the time.

We had a smooth flight back. First I wrote for a few hours, then I studied in C.Hamerik's Ph.D. thesis. (The full-size copy was too big to be read in an airline seat and in the middle of the night I woke Ria up by kicking a non-empty beer can on her pants. Her first reaction was not to be amused, her second one was more forgiving.)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 15 May 1984 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

P.S. My home address in the USA will be

6602 Robbie Creek Cove
AUSTIN, Texas 78750
United States of America

EWD.

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD 888

Trip report E.W.Dijkstra, Z�rich, 22-24 May 1984.

I left on Sunday at 15:15, I was home again on Tuesday at 15:45. I travelled via Amsterdam by train, coach, and air; both KLM flights were dead on time. As soon as Niklaus Wirth had heard that I was going to Texas, he had invited me to give a lecture at the ETH "while I was still in Europe", and I had accepted the invitation. Hence.

At 19:45, Niklaus and his wife were at the Z�rich airport. Half an hour later we were at their home in Furch, by my standards high up in the mountains: we had a beautiful view over the nearby lake (with still higher mountains at its other side). They refused to believe that KLM had fed me well enough and I had to eat the spaghetti that Niklaus had prepared (The spaghetti was nice.) The rest of the evening we talked: we had not seen one another for quite some time.

Monday we spent at the ETH from about 9:00 to about 19:00. In the morning Niklaus gave me a detailed demonstration of their Lilliths (annex laser printer) and some of the software he had developed, and then we talked about the structure of that software. I was very impressed; what I saw struck me as remarkably elegant and efficient. Niklaus's competence is so impressive because, by now, it is so broad: from language design to computer design, from language implementation to computer construction, from hardware interfaces to product specification. He proudly showed me his text editor; I knew no other text editors to compare it with, but it was all so clear and clean that I am fully convinced that his pride was justified. In passing he mentioned that by re-engineering the compiler (which had been done by others) he had speeded it up by several (binary) orders of magnitude. He clearly enjoyed how much he could do with "this little machine". (One begins to suspect that most software is so needlessly complicated that it could be improved by a factor of 10 or more.) I quote one comment from Niklaus: "If Ada's designers would have had to implement the language as well, I bet it would have been a lot simpler.". Currently he was pestered by people that wanted to "improve" Modula 2 with all sorts of "extensions" he had carefully avoided. Apart from that he was in great shape. (Having grown a beard he looks at last like a real computer scientist.)

After lunch I spent one and a half hour with his colleague Nievergelt. That was less successful, partly because by that time I may have been a bit tired. Nievergelt spoke too much the language we know so well from the standard data base person, and I was convinced once more of its inadequacy. Besides that he made the impression of being profoundly unmathematical. Then I listened for half an hour to Dr.Gati, but I am afraid I could not feign interest in his problem: the time to give my lecture was approaching.

Expecting a large audience, Niklaus had scheduled my performance in a larger hall in the building for mechanical engineering. To his horror he discovered that —with noisy traffic outside!— two windows had their frame broken and could no longer be closed. Chalk was of excellent quality and blackboard space almost sufficient. This time I needed 83 minutes, I guess I started with 150 people and ended with 125. We did not observe Engeler in the audience. (Should I have chosen a more aggressive title, say "On avoiding transfinite induction?")

We spent the evening in the pleasant company of a few younger staff members of the institute. Niklaus's wife had prepared a bowl (with kiwi fruit) and a nice, light meal; while opening the second bottle of wine I showed Niklaus how he should have opened the first one. (The next morning, at 7:55, people started to renovate the kitchen!)

Talking about "the big three" —Stanford, MIT, and CMU— , Niklaus remarked "They went for academic glory and failed to educate the engineers that are needed.". I know what he means and largely agree. The alternative of ETH, however, I could not find entirely convincing. There seems to be no link with mathematics (and in this case my impression is that the departments of mathematics and of informatics share the blame). As a culture they ignore —or even deny!— that important aspects of programs can be improved and, as a result, lack an important pretty objective yardstick. This is a handicap in teaching: the pragmatic virtues of the excellent engineer are too elusive. (One of the fringe benefits of formal proofs lies in their explicitness, which makes comparisons of proofs possible.) It is not clear how the ETH can dig itself out of that hole. They face the two usual hurdles. Firstly, when they tried to fill one of their vacancies with someone who could represent "the mathematics of programming", they discovered that they were unable to find/attract a suitable candidate. Secondly, whether they like it or not, the percentage of their freshmen that is without scientific inclination or aspiration is increasing. I have promised to send Niklaus our lecture notes for freshmen —the assumption being that his ability to read Dutch is like my ability to read Italian— : with home computers becoming as ubiquitous are they do, their current introduction to programming —operational and intuitive— is quickly becoming superfluous. I wish them luck, for the mere suggestion of the relevance of (rather formal) mathematical techniques currently encounters still strong resistance.

Z�rich was recommendably clean in comparison with Amsterdam; the bus stop near the Central Station for the coach to Schiphol I can only describe as a garbage dump. The best thing I can say about my own country is that in Amsterdam and Eindhoven the escalators to the platforms in their railway stations were operational. Z�rich was in the (noisy) process of building a new (underground) Central Station: it was a mess as if Z�rich was preparing itself for the next Olympic Games. The current connection to the airport is most impressive: from the central Station it is a 10-minute train ride. (The train revealed how rich the Swiss are: half of the train —eventually to Winterthur— consisted of 1st-class carriages!)

I arrived in Amsterdam at the disgracefully low temperature of 11 �C. The day before, Nuenen had had a rainfall of 26 mm. But at home I found a Harper and Row catalogue announcing a book that contained

"Techniques — including such varied topics as the critical and creative techniques involved in obtaining a Ph.D."

(A book on Artificial Intelligence. Who said that AI is close to fraud?)

Plataanstraat 5 5671 AL NUENEN The Netherlands | 22 May 1984 prof.dr.Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 15-Oct-2011

EWD889 - 0

User-friendly Mathematics

From publishers' catalogues of books on computing I have learned that the greatest recommendation nowadays is that the texts are void of any mathematical rigour, precision, or clarity. Obviously, traditional mathematical texts are the pinnacle of user-unfriendliness, and if the mathematical community does not want to get completely out of touch with the real world, it had better do something about it. Here is my modest contribution.

* |  | *
| * |

Hi folks! This is about the theorem of Pythagoras (read: "pythagoras"). Though he is already dead and was Greek, he was in fact quite modern. He is best known for having founded a new sect that meditated on the beauty and harmony of shapes, numbers and guitar music. (And you all like sects with guitar music, don't you?)

For a long time he meditated on a triangle with sides 3, 4, ...... No, let me give you a simpler explanation. It is really quite simple: for years, even stupid Egyptean farmers could use it to give their lots right angles. (You have heard of Egypteans, haven't you? They build those queer pyramids full of mystical measures. And those pyramids have right angles

EWD889 - 1

too!) The farmer would take three pieces of rope, one of 3 yards, one of 4 yards, and one of 5 yards, and he would tie them together. And then he would give three of his children each a knot and tell them —in Egyptean, of course— to pull and stretch the ropes as much as they could. (In former days, dads could not do their own work and wanted their kids to help them!)

Now that's the figure Pythagoras pondered about from the moment he had seen that the squares of the sides were equal. (If you are not sure about the squares of the sides, ask your mom.. She may still know, and if she does not, don't bother, for then it is evidently not that important. The important thing to remember is that the sides have a relationship.)

When Pythagoras discovered that the relationship did also hold for other triangles, you can imagine how exited he became! (Remember he was Greek.) When he had discovered his theorem, he was, in fact, so excited that he shouted "Eureka" —that is Greek too, though the Greeks still don't know how to write it with proper letters— and named the theorem after himself. So much for the theorem of Pythagoras and its discovery.

EWD889 - 2

The important thing, of course, is how we, modern young people, incorporate it into our sense of well-being and our place in the real world. The most important thing is that we learn not to be as over-awed as Pythagoras, whose sense of wonder mainly derived from the fact that he did not understand like us what he was doing. Today we should no longer ignore the possibility that the theorem is false because

the ropes had the wrong lengths or one of the kids pulled harder than the other two;

the angle was not as right as Pythagoras had assumed;

mom has made a mistake in calculating the squares;

our supposedly straight lines are actually curved (see the lesson "How Relativity made Einstein").

Exercise Explain in your own words why Pythagoras got so excited.

Plataanstraat 5 5671 AL   NUENEN The Netherlands |  | 28 May 1984 prof. dr. Edsger W. Dijkstra Burroughs Research Fellow

Transcribed by Martijn van der Veen

Revised Mon, 14 Jul 2003.

  EWD 892

Trip report E.W.Dijkstra, London, 12-14 June 1984.

On Tuesday I was picked up at 6:30 by Netty van Gasteren and her husband, who saw us to Eindhoven Airport. At 8:00 (local time) we landed at Gatwick; a BP driver was waiting to take us to the city.

Netty and I had gone to London in order to attend a seminar of the BP Venture Research Unit. It started on Tuesday 15:30 and lasted until Wednesday 18:00; there were —I guess— about 100 people in the audience.

Once in London, Netty and I went to Britannic House —BP's HQ— to prepare our visuals as I would be the first speaker that afternoon. (J Strother Moore of UT at Austin would be the other one.) We were joined by David Gries who had come down from Oxford. At 15:00 we met Wlad M.Turski who also had been invited to attend my talk.

I had essentially been asked to present a progress report on our work, but to do so to an audience of natural scientists (chemists, biologists, etc.) and a few managers. I did not fully succeed. Technically my talk was correct and I had been fortunate in the choice of my two examples (which were nontrivial, yet understood by a major portion of the audience). But I should have spent more time on mathematical methodology in general. Then J Moore showed in very general terms the mathematical verification of circuit designs; I think he was more successful in reaching his audience —he had cartoons—.

The following dinner —still on BP premises— was very good, by British standards probably excellent. Before and after it I talked with Wlad and we arranged to meet the next afternoon.

Netty attended all of the next day's performances, I only from 9:00 to 12:45 and from 17:00 onwards. I went to my hotel where I was joined by Wlad, whom I had planned to offer lunch. He agreed to my proposal that we should do some mathematics first (though he knew that then the restaurant would be closed). In his inspiring presence, I found a proof we liked very much. At 15:30, the food facilities were indeed very limited: we had to make do with a sandwich shop around the corner. At five, he saw me off at Britannic House. After the last lecture, the seminar was closed by a farewell cocktail party.

Netty and I returned to the Great Eastern Hotel, where we foolishly tried the dinner. Netty and I remembered that at a previous occasion —in the company of C.A.R.Hoare— I had had there a very acceptable Dover Sole. But the dining room was now a help-yourself carvery in which the food had reached a rare degree of inedibility. I had taken only a modest amount but even that I could not finish. We left the place in disgust and went to my room, where we worked. (There was, of course, no decent table to write at; we sat at the dressing table, where I wrote EWD891 under Netty's supervision.)

At 10:50 the next morning, I took leave from Netty, who stayed another week in London; a BP car took me to Heathrow. Having been booked on a later flight than I had asked for, I missed an appointment in Eindhoven. But I did return in time for bringing out my vote for the European Parliament.

Plataanstraat 5
5671 AL NUENEN
The Netherlands
16 June 1984
prof. dr. Edsger W.Dijkstra
Burroughs Research Fellow

transcribed by Tristram Brelstaff
revised Mon, 10 Jan 2005

EWD 893

Trip report E.W.Dijkstra, USA, 17-26 June 1984

This was my farewell trip to Burroughs. In the original plans I would have visited the company at ten different locations; eventually it became three. Being very busy these days, the reduction suited me, but I was also disappointed by it. (It was typical of my increased difficulty in reaching the company, a difficulty which had been one of the factors contributing to my decision to resign.)

On Sunday 17 June I flew from Amsterdam via New York, JFK, to Philadelphia. Air traffic congestion above JFK delayed my flight to Philadelphia by almost an hour. I was met by Terry Blok of Flemington, in whose house I would stay the next two nights.

Monday I was the whole day at the Flemington group. In the morning I was shown the manufacturing of terminals; the automation of the manufacturing process seemed very well under control and I was duly impressed. I gave my talk in the afternoon, sandwiched between two other Burroughs speakers. We had an audience of about one hundred people and my lecture (which I did not give for the first time) went very well. In the evening, five people joined me for dinner, at which both the food and the company were of exceptional quality.

Tuesday I went to SDC in Paoli, where William C. Hopkins was my host. The discussion before lunch with about half a dozen people was driven by their work and their plans. (The difficulty of reasoning about functional programs that incorporate nondeterminacy again surfaced. I knew none of the people, but contact was quickly established.) After lunch I gave my lecture, again for an audience of about one hundred. Again, it was very well received. (To my regret it was the same lecture as I had given the day before: I had about four or five rather different lectures ready, but both times I was forced to select the one that could be delivered with a minimum of visual facilities. It is always the same story!) Afterwards I had a very pleasant surprise: Ben Dent's daughter made herself known to give me her father's greetings, which were received and returned with equal pleasure. Bill Hopkins took me to the airport, from where the 18:15 plane took me to Austin, Texas. The weather was a bit rough, but I did not mind as we flew through magnificent domes of clouds, intriguingly illuminated by the setting sun: a "gorgeous" sight! Ham Richards, with whom I stayed the remaining nights, met me at Austin Municipal Airport.

In Austin my life was as hectic as the weather was warm, as I had to divide my time between ARC, UT, and myself. I went twice to ARC, once —too short— to be told about their plans and once —long enough— to give a lecture. (This was a lecture I had never given before; it ended with the proof I had found the week before in London with Wlad Turski.) On Sunday evening, Larry Thomas and his wife gave my farewell party. The rest of my time was divided between washers, dryers, tiles, humidity control equipment and curtain tape on the one hand, visa, teacher retirement, deferred compensation and long term disability on the other. After a visit to UT's International Office on Monday morning, I drove to the Airport and flew back. Regrettably I did not sleep and came home very tired: it took me more than two days to recover. (They were not all wasted: I went to the optician to get my new pair of glasses, to the dentist to get a new crown installed and to the ophthalmologist to have my retinae inspected.)

Back home, I found Ted Codd's complaint: "IBM is not very forward looking. Its main objectives year to year are this year's profits. IBM is very reluctant to look five years down the road." and the warning: "In California today, Japan sells more cars than Detroit. In the computer industry, the same thing could happen to IBM.". The complaint is not new, and, to the extent IBM is accepted as model, not confined to IBM either.

Next year I shall again face the issue from the academic side exclusively. In a way I am looking forward to it because, if the University sticks to its proper r�le, life on the campus is less beset by internal contradictions. It is very simple: a leading department of computing science has to concentrate on the scientific aspects of computing. We just cannot allow ourselves to be diverted by the existence of an industry that looks for improvement without change and has thereby incapacitated itself to profit from our graduates. An intellectually stagnated industry is bad, an equally stagnated university as well would be worse.

PS. I was pleased to observe that Burroughs ARC had attracted a full-blown logician. It is always nice to observe progress.

PPS. Broccoli divides the world: into those that believe that broccoli is edible and those that know it isn't.

Plataanstraat 5 5671 AL NUENEN The Netherlands | 28 June 1984 prof.dr. Edsger W.Dijkstra Burroughs Research Fellow

transcribed by Corrado Cantelmi
revised 29-Sep-2011

EWD 895

Trip report E.W.Dijkstra, Marktoberdorf, 30 July - 12 Aug. 1984

Originally, Ria and I should go together by car a we did three years ago, the trip being planned as Ria's holiday. In a next stage we asked friend and colleague Martin Rem to join the ride, and he accepted. Finally Ria had to decide to stay home as her mother had suddenly been taken to hospital, so Martin and I made the trip together.

The outward journey we did at leisure, leaving Eindhoven on Sunday 30 July at 09:30 and arriving in Marktoberdorf the next day at 15:00. After we had passed the Ruhrgebiet, we left the Autobahn and took country roads instead. The countryside and mediaeval towns were beautiful, but we would have enjoyed them even more had not we selected for the journey the two warmest days of this summer. It was often too hot to be comfortable. Apart from that we had a most pleasant journey and the car performed remarkably well: 15.2 km per liter!

Upon arrival, I had the unpleasant surprise of hearing that Unkel Fritz (= Prof. Dr. F.L.Bauer) had had a heart attack and was in hospital. Fortunately, the remaining two directors (Tony Hoare and I) were ably assisted by Manfred Broy --now at the University of Passau--, but as all three of us were scheduled for 6 lectures as well, we had a busy time.

For the participants, Sunday was a day off, but Tony and I drove to Münich Airport to collect Andrei Ershov from Novosibirsk. (Andrei seemed quite moved when he discovered us both at the gate.) After lunch the three of us went to Fürstenfeldbruck to say hello to Unkel Fritz. We were pleased to see that he was doing quite well, but a bit worried that he might be doing too well. At 17:00 we were back at the Summer School. [The strain was beginning to tell: in addition I had had a restless night, and Tony had to drive the last 10 km because I could no longer keep my eyes open.] It should be recorded that Herr Hans Kuss had given us excellent instructions, and armed --by him-- with a map of the area + town maps of München and Fürstenfeldbruck, we reached all our destinations without any problems.

Our return trip was very different. We left Marktoberdorf at 06:45 and drove to the nearest Autobahn. After 4 hours of driving we had an hour rest; after another 3 hours we were in Eindhoven. [During those 7 hours we had averaged 107 km/hour at 12.5 km per liter, which is not bad either. The engine was evidently in good condition.]

The organization of the Summer School was as smooth as smooth can be, a fact for which the local staff of the boarding school and the staff of the Technical University Munich share the credit. They obviously had great experience --this was the 7th Marktoberdorf Summer School--, but we all know that experience alone is not enough.

*                 *
*

In retrospect I am not so happy with the theme "Control Flow and Data Flow: Concepts of Distributed Programming" since it invited very operational considerations, and we all know that these are rarely really convincing. Similarly, the term "distributed" invited distinctions I rarely care to make. (I was repeatedly reminded of a visit I once made to the University of Waterloo, where they proudly showed me their "Remote Job Entry System" ---that had just taken six months to implement--. In my innocence I asked them how the "remoteness" had contributed so much to the complexity of the task, but I never got an answer.)

Krzysztov R.Apt (Paris) talked exclusively about CSP (= Communicating Sequential Processes, as published by C.A.R. Hoare in 1978), concentrating on termination and proof systems. In part of the distributed world, CSP has acquired a canonical status in the sense that the immediate reaction to a new suggestion is "Can you show how to implement it in CSP?". CSP, however, is not the last word about communicating processes (it is among the first ones). Apt's lectures suffered somewhat from this influence. The examples chosen to illustrate his points were a bit elaborate, but his conscious efforts to be understood were highly appreciated.

Manfred Broy (Passau) gave a somewhat encyclopedic overview of "Programming Constructs for Communication and Concurrency". Operational semantics occupied a very central position at first. I found it difficult to understand why he had chosen denotational semantics as alternative because --as Broy knows full well-- denotational semantics is still very operational. His visuals were quite readable, but he had too many of them.

Jack B.Dennis (MIT) spoke on "Data Flow Models of Computation" and did precisely what we had hoped he would do: he gave a clear survey of the work done in that area (mostly at MIT). It had the engineering flavour that was to be expected; as a European computing scientist I was struck by the fact that --in 1984!-- he still used FORTRAN programs for comparison. He kept the well-deserved attention of his audience until the very end. (He was surprised by the high quality of the audience, which was much higher than he had expected or was used to; the discovery was obviously inspiring.)

I covered only a small part of the material I had handed in: I developed a termination detection algorithm, presented the Snapshot Algorithm of Chandy and Lamport and showed how I used the predicate calculus without restricting myself to continuity. At my fourth lecture --after the excursion-- I was too tired and made promptly a mess of it when I resorted to a picture. At the other lectures I did not suffer too much from having to use an overhead projector.

C.A.R. Hoare (Oxford) was the most polished lecturer. He too covered only a small portion of what he had handed in. Under the title "Communicating Sequential Processes" he talked about how much can be said when the internal process states are largely ignored. (His vending machines did accept coins, but the receipts were not accumulated.) It was a great pity that on his foils --which he had used before and will use again-- he had used red and green as well: they are harder to read than black and blue. I was very pleased by his stress on the necessity of "many elegant algebraic properties".

Clyde P.Kruskal (Illinois) gave an overview of the parallel machines built or designed in the USA, gauging them with the time-complexity of three algorithms. He had not been told what audience to expect, was unprepared to meet it and ran out of material before his time was over. (Not surprisingly, Jack Schwartz at NYU had not taught him how to give a decent lecture either.) He was a stand-in for Kuck, who should not have sent him.

Robin Milner (Edinburgh) talked about his CCS (= Calculus of Communicating Systems). This was the first time I heard him in a series of lectures and he struck me as a very sympathetic speaker, full of consideration for his audience. I was amazed to observe that, while his original goals must have been very similar to what Tony is currently pursuing, the two results are so different. I started wondering about his background and could not decide between mathematics and philosophy. (When asked, he told me he had "a major" in both.) Perhaps he concentrates more on what is than on what is (elegantly) thinkable.

Ugo G. Montanari (Pisa) spoke on "Distributed Systems, Partial Orderings of Events and Event Structures" and I must confess that I have failed to grasp his purpose and what he was talking about. My impression was that of an elaborate formalism to be used for descriptive purposes only. And his terminology was definitely confusing (he used, say, "process" by way of abbreviation for "initial state of a process").

Martin Rem (Eindhoven ) talked about trace theory and its (possible) applications to VLSI design. Having prepared a set of self-contained lectures he found himself in the beginning in the situation of making the impression of duplicating some of the material of Tony Hoare. (Traditionally, Marktoberdorf knows no coordination between speakers in advance.) In the beginning he also suffered from having to use an overhead projector. But he found his rhythm and eventually his contribution was well-received. His visuals --modest in number!-- had been prepared with great care, his examples were each time the simplest that made the point and for each of his design choices he gave a convincing justification.

*                 *
*

From the above it follows that at least this director was not entirely pleased with the program we offered. The participants did not seem to mind (with the exception, probably, of a number of experienced educators); they had anyhow plenty of opportunity to enjoy the exposure to each other.

It is fascinating to observe that the audience of the Marktoberdorf Summer School gets better each time. I can think of only two explanations. Firstly, as the Summer School gets more famous, the selection prior to application gets more effective. Secondly, with progressing internationalization --my apologies for that ugly word!--, fluency in English has improved to the extent that I observed little of the language barriers I remember from earlier Summer Schools: one heard, of course, all the marked accents, but this time even the French hardly clung together. The moral of the improving quality of the audience is clear: we have to be increasingly careful in the choice of our lecturers.

At the end we were shown an illuminating statistic: for each speaker the average number of foils he had used per lecture. The maximum was 26 (for Manfred Broy), the minimum was 3 (for me, and I was quite pleased).

Austin, 3 September 1984

prof.dr.Edsger Dijkstra
Schlumberger Centennial Chair in Computer Sciences
Department of Computer Sciences
The University of Texas at Austin
AUSTIN, Texas 78712-1188
United States of America

PS. The official address is a bit long. And I even did not include my Social Security Number.

EWD.

transcribed by Tristram Brelstaff
revised Fri, 25 Jun 2004

EWD896

On the nature of Computing Science

Now this summer school draws to a close, it seems appropriate to try to put its topic into some perspective

Its official theme: Control Flow and Data flow: Concepts of Distributed Programming only determined the flavour, for regularly we were led to pretty general questions that seem rather central to computing in general. So, what is the nature of computing science, or, perhaps more precisely, what should its nature be?

There is much confusion about that, and that confusion should not amaze us, for computers nowadays have so many different aspects:

You can view computers primarily as industrial products, intended to be sold with profit. A burning question then becomes whether to advertise them with Charlie Chaplin or with Mickey Mouse and a computing science curriculum should contain a course in Sales Promotion as a major component.

You can view computers primarily as the main battlefield of international competition; in that case a computing science curriculum should mainly consist in courses on Security and Industrial Espionage.

One day you can view automation as the motor of your economy, the other day you can view it as the greatest threat to the employment situation; so the main courses in our computing science curriculum should be on Economy and on Industrial Relations.

In recognition of the fact that the new technology has its profoundest impact by adding a totally new dimension to the eternal philosophical questions Can machines think? and What is life?, we conclude that the major chairs in computing should be joint appointments betweens departments of Philosophy, of psychology, and of Biology.

The above enumeration is not exhaustive; I leave it to you to design and justify a dominant rôle in computing for the management scientists, the linguists, the experimental physicists and the educationists. This source of confusion about the nature of computing has now been sufficiently explained, so let us turn to the other component: science.

To begin with I would like to recall that Science as a whole has dismally failed to meet its original objectives. As you all remember, those original objectives were three.

Firstly, there was the development of the Elixir that would give you eternal youth.

But since there is little point in living in eternal poverty, the second objective was the development of the Philosophers Stone, by means of which you could make as much gold as you needed.

As you can imagine, the planning of these two grandiose research projects required more foresight than could be provided by the seers of the day and accurate prediction of the future became the third hot scientific topic.

We all know that, as the centuries went by, medicine divorced itself from quackery --at least we hope so!--, that chemistry divorced itself from alchemy and that astronomy divorced itself from astrology. This is just another way of saying that, for tactful reasons, the original objectives were forgotten.

Were they? No, not entirely. Evidently there is still a lingering sense of guilt for, as soon as a promising science or technology emerges, the old objectives are suddenly remembered and the young science is expected to meet them. To which we may add that, the less the new science is understood, the higher these expectations. We all know, how computing is now expected to cure all ills of the world and more, and how as far as these expectations are concerned, even the sky is no longer accepted as the limit.

The analogy raises, for instance, the questions which current computer-related research will later be identified as computing's alchemy, and whether this identification can be speeded up, but I shall leave these questions for your speculation and shall approach the matter from another direction.

Since the rules of the academic games are remarkably strict and stable, we can pursue the question, which aspects of computing could ensure its viability as an academic discipline. Here I am in a much better position since I developed ten years ago a well established theory about the viability of academic disciplines.

This theory tells us that if computing is to develop into a viable academic discipline, it has to be made into an unusually formal branch of mathematics, in which knowledge of facts will play a relatively minor rôle but methodological concerns will play an unusually large one. As a consequence there will be no significant distinction between pure and applied computing science. The current dictionary definition of mathematics "the science of shape, number and quantity" --which is already obsolete now-- will in the long run be replaced by "the art and science of effective reasoning", and when that has happened --a century from now or so-- computing science will have had a much profounder influence on mathematics at large than physics has had in the past.

All this is very exciting and also very inviting because mathematical elegance will play such a central rôle. As computing scientists we know that in our area, perhaps more than everywhere else, mathematical elegance is not a dispensable luxury but decides between success and failure.

It is nice to know the dictionary definition for the adjective "elegant" in the meaning "simple and surprisingly effective".

But before above rosy future will have been reached, some hurdles have to be taken. Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better. The computing industry is not the only one that has discovered that sore truth: so has the academic world. If you deliver a lecture that is crystal clear from the beginning to end, your audience feels cheated and mutters while leaving the lecture hall "That was all rather trivial, wasn't it?". One of our learned journals has rejected a beautiful paper of mine because the solution it presented was too simple to be of academic interest and I am waiting for the rejection of a paper on the grounds that it is too short.

Also our academic reward system works against us. One can get credit for some complicated concepts one has introduced, it is hard to get credit for the discovery how some established but complicated concepts had better be avoided: those unaware of these concepts won't notice your discovery and those with vested interests in them will hate you for it. Hence my urgent advice to all of you to reject the morals of the bestseller society and to find, to start with, your reward in your own fun. This is quite feasible, for the challenge of simplification is so fascinating that, if we do our job properly, we shall have the greatest fun in the world.

In short: Two cheers for Elegance!

Marktoberdorf, 10 August 1984

Plataanstraat 5
5671 AL NUENEN
The Netherlands

prof. dr. Edsger W. Dijkstra
Burroughs Research Fellow

transcribed by

revised Tue, 10 Aug 2004

EWD898

The threats to computing science

Let me describe to you by way of introduction the observation that induced me to choose "The threats to computing science" as my topic for this keynote address. The observation is simply that, when browsing through a computing science journal or conference proceedings, one usually sees at a first glance the geographical origin of the work described.

Now, in any area we have always had national differences, but their obviousness in computing becomes surprising as soon as we remember all the homogenizing forces at work during the first few decades in which the topic emerged, and allow me to mention a few of them, just to underline the strength of this argument.

Firstly, right from the start, English has been the Lingua Franca of computing: as early as 1956, when as a young Dutchman I gave my first lecture abroad, I did so —though at a German computing conference— in English. And as soon as, at either side of the Atlantic Ocean, the ACM and the BCS started their journals, these journals became the leading ones in the field.

Secondly, at an early stage, the computing scientists of the world became a travelling lot: the year of the UNESCO Conference in Paris, 1959, is about the time when the jet airliner became more common.

Thirdly —and this process had already started in the 50's— the computing community began to use more and more the same few machines and the same few programming languages. Even behind the Iron Curtain they could think of nothing better than faithfully copying the IBM/360 and are now busily implementing Ada at the request of the Red Army.

And finally, to deprive you of the last visual clues, people are beginning to use the same laser printers and the same text editing software. Gone are the days when Niklaus Wirth unmistakably identified himself by his typewriter and you could recognize his writings even when they were held upside down.

In short, in the young discipline of computing science, the homogenizing forces have been stronger than in any other discipline I can think of. And yet, the geographical origin of most of its publications is patently obvious.

* |  | *
| * |

I can think of only one explanation of this curious phenomenon, and that is the combination of strong local pressure and malleable computing groups that yielded only too easily to those pressures. Let us deal with the malleability first and with the pressures later.

The malleability is understandable when we realize that at the beginning the computing community was very uncertain as to what its topic was really about and got in this respect very little guidance from the confused and confusing world by which it was surrounded.

The Fathers of the field had been pretty confusing: John von Neumann speculated about computers and the human brain in analogies sufficiently wild to be worthy of a medieval thinker and Alan M. Turing thought about criteria to settle the question of whether Machines Can Think, a question of which we now know that it is about as relevant as the question of whether Submarines Can Swim.

A futher confusion came from the circumstance that numerical mathematics was at the time about the only scientific discipline more or less ready to use the new equipment. As a result, in their capacity as number crunchers, computers were primarily viewed as tools for the numerical mathematician, and we needed a man with the vision of Stanley Gill to enunciate that numerical analysis was for the computing scientist like toilet paper for the sanitary engineer: indispensable when he needs it.

But the greatest confusion came from the circumstance that, at the time, electronic engineering was not really up to the challenge of constructing the machinery with an acceptable degree of reliability and that, consequently, the hardware became the focus of concern. This distortion is faithfully reflected in the names coined in those days: ACM stands for Assocation for Computing Machinery, BCS stands for British Computer Society, and Universities founded in those days Departments of Computer Science. (The British Universities, a little bit slower to react, were by then a little bit wiser and erected Departments of Computing Science.)

I called this focus on hardware a distortion because we know by now that electronic engineering can contribute no more than the machinery, and that the general purpose computer is no more than a handy device for implementing any thinkable mechanism without changing a single wire. That being so, the key question is what mechanisms we can think of without getting lost in the complexities of our own making. Not getting lost in the complexities of our own making and preferably reaching that goal by learning how to avoid the introduction of those complexities in the first place, that is the key challenge computing science has to meet.

Nowadays machines are so fast and stores are so huge that in a very true sense the computations we can evoke defy our imagination. Machine capacities now give us room galore for making a mess of it. Opportunities unlimited for fouling things up! Developing the austere intellectual discipline of keeping things sufficiently simple is in this environment a formidable challenge, both technically and educationally.

As computing scientists we should not be frightened by it; on the contrary, it is always nice to know what you have to do, in particular when that task is as clear and inspiring as ours. We know perfectly well what we have to do, but the burning question is, whether the world we are part of will allow us to do it. The answer is not evident at all. The odds against computing science might very well turn out to be overwhelming.

Since the Romans have taught us "Simplex Veri Sigillum" —that is: simplicity is the hallmark of truth— we should know better, but complexity continues to have a morbid attraction. When you give for an academic audience a lecture that is crystal clear from alpha to omega, your audience feels cheated and leaves the lecture hall commenting to each other: "That was rather trivial, wasn't it?" The sore truth is that complexity sells better. (It is not only the computer industry that has discovered that.) And it is even more diabolical in that we even use the complexity of our own constructs to impress ourselves. I have often been impressed by the cleverness of my own first solutions; invariably the joy of the subsequent discovery how to streamline the argument was tempered by a feeling of regret that my cleverness was unnecessary after all. It is a genuine sacrifice to part from one's ingenuities, no matter how contorted, Also, many a programmer derives a major part of his professional excitement from not quite understanding what he is doing, from the daring risks he takes and from the struggle to find the bugs he should not have introduced in the first place.

These were internal complications. For a better understanding of the external pressures we had better view our topic for a moment in the wider context of science and society in general. Because computers appeared in a decade when faith in the progress and wholesomeness of science and technology was virtually unlimited, it might be wise to recall that, in view of its original objectives, mankind's scientific endeavours over, say, the last five centuries have been a spectacular failure.

As you all remember, the first and foremost objective was the development of the Elixir that would give the one that drank it Eternal Youth. But since there is not much point in eternal poverty, the world of science quickly embarked on its second project, viz. the Philosopher's Stone that would enable you to make as much Gold as you needed.

Needless to say, the planning of these two grandiose research projects went far beyond the predictive powers of the seers of that day and, for sound reasons of management, the accurate prediction of the future became the third hot scientific issue.

Well, we all know what happened as the centuries went by: medicine, chemistry, and astronomy quietly divorced themselves from quackery, alchemy and astrology. New goals were set and the original objectives were kindly forgotten.

Were they? No, not really. Evidently, the academic community continues to suffer from a lingering sense of guilt that the original objectives have not been met, for as soon as a new promising branch of science and technology sprouts, all the unfulfilled hopes and expectations are transferred to it. Such is the well-established tradition and, as we are all well aware, now computing science finds itself saddled with the thankless task of curing all the ills of the world and more, and the net result is that we have to operate in an unjustified euphoria of tacit assumptions, the doubting of which is viewed as sacrilege precisely because the justification of the euphoria is so shaky. Let me cast a few doubts, be it at our own peril.

The fundamental dogma of the euphoria is, of course, that whatever we can do, machines can do it better and cheaper, and, as a corollary, that the use of machines leads to a better product and saves time and money. The dogma continues to be accepted notwithstanding the fact that we observe almost daily that in many respects the product has deteriorated.

In June, during my last preparatory visit to the USA, I tried to order a telephone to be installed upon my arrival in September. The lady reacted as if I had made her an indecent proposal: didn't I know that after 30 days I "would be dropped out of the computer"? This was not incidental, this was characteristic: just think how often the bank has denied you a reasonable service on the ground that "the computer won't let them do it".

These are big installations, but the small ones aren't any better. As a referee I have to judge many manuscripts and the ones prepared on word-processors are invariably the worst, qua printing quality, or qua layout, or qua style, notation, and contents. The proposed style of composing —write first, improve later— rarely leads to a text from which all ill-considered turns have been weeded out. Finally, the suggestion that the proposed style of composing iteratively would save time is an obvious and blatant lie. And yet the equipment is sold by the millions...

Does this overestimation of the usefulness of the gadget hurt computing science? I fear it does. At the one end of the spectrum it discourages the computing scientist from conducting all sorts of notational experiments because "his word-processor won't allow them", at the other end of the spectrum the art-and-science of program design has been overshadowed by the problems of mechanizing program verification. The design of new formalisms, more effective because better geared to our manipulative needs, is neglected because the clumsiness of the current ones is the major motivation for the mechanization of their use. It is not only the performing artist who is, in a very real sense, shaped by the instrument he plays; this holds as well for the Reasoning Man, and I leave it to you to determine how disturbed you are going to be by this observation.

Back to the history of our subject. During the early days the concern to get the hardware more or less in working condition overshadowed all others and we naively thought that, once the hardware was reliable, our problems would be over, little realizing that our problems in using the equipment would really start only then. The confrontation with the difficulty of programming almost caused a severe dent in the faith in how wonderful computers were going to be. The solution to this moral dilemma was as simple as effective: the intrinsic difficulty of programming was just denied and, if problems had to be admitted, the so-called "primitive nature" of the machines was blamed and it was promised that with "the next generation" the problems would no longer occur.

Now here is a very real threat to computing science. The intrinsic difficulty of the programming task has never been refuted, it has only been denied because admitting it was socially unacceptable. Not surprisingly, research in programming methodology has not flourished in societies unable to admit that the programming problem was serious.

I vividly remember from the late 60's the tendency to blame the programming languages in use and to believe in all naivety that, once the proper way of communicating with the machines had been found, all programming ills would have been cured. To give you only one example, the ACM Conference on the Principles of Operating System Design in Gatlinburg, Tennessee, 1967, needed only one day to come to the rash conclusion that we did not know how to design operating systems because we did not have a language to design them in! If only we had the right programming language! The fact that operating system design posed some at the time tough conceptual and logical problems was hardly allowed to surface. Consequently, those problems did not get the attention they deserved, and this had far-reaching consequences: I recently read a series of articles on the Shuttle on-board software and, though President Reagan has generously offered a teacher a free ride, I tell you I am not available.

The quest for the ideal programming language and the ideal man-machine interface that would make the software crisis melt like snow in the sun had —and still has!— all the characteristics of the search for the Elixir and the Stone. This search receives strong support from two sides, firstly from the fact that the working of miracles is the very least that you can expect from computers, and secondly from the financial and political backing from a society that had always asked for the Elixir and the Stone in the first place.

Two major streams can be distinguished, the quest for the Stone and the quest for the Elixir.

The quest for the Stone is based on the assumption that our "programming tools" are too weak. One example is the belief that current programming languages lack the "features" we need. PL/I was one of the more spectacular would-be stones produced. I still remember the advertisement in Datamation,1968, in which a smiling Susie Mayer announces in full colour that she has solved all her programming problems by switching to PL/I. It was only too foreseeable that, a few years later, poor Susie Mayer would smile no longer. Needless to say, the quest went on and in due time a next would-be stone was produced in the form of Ada (behind the Iron Curtain perceptively referred to as PL/II). Even the most elementary astrology for beginners suffices to predict that Ada will not be the last stone of this type.

Ada will not meet its major objective, viz. that of reducing software costs by standardization, and it will not be the vehicle for programs we can rely upon, for it is so complicated that it defies the unambiguous definition that is essential for these purposes. Long before the design was frozen, computing scientists from all over the world have given plenty of warning but the political body in question preferred to ignore these warnings and to decide on a design that cannot be salvaged. From a scientific point of view all further attention paid to Ada is a waste of effort. But the sheer buying-power of the DoD makes Ada an undeniable reality, which in combination with DARPA's policies for the funding of software research can only increase the pressure to spend research effort on the wrong problems.

Another series of stones in the form of "programming tools" is produced under the banner of "software engineering", which, as time went by, has sought to replace intellectual discipline by management discipline to the extent that it has now accepted as its charter "How to program if you cannot."

In parallel we have the search for the Elixir. Here the programming problem is simply solved by doing away with the programmer. Wouldn't it be nice, for instance, to have programs in almost plain English, so that ordinary people could write and read them? People tend to forget that "doing away with the programmer" was COBOL's major original objective. Fifteen years later, 80% of the world's programming force was absorbed by the use of COBOL, a figure which gives us some idea of how effective that elixir has been. Elixirs are typically implemented —to quote Grace Hopper's own words— by "education of the computer".

Since then we have had elixirs in a countless variety of tastes and colours. I have fond memories of a project of the early 70's that postulated that we did not need programs at all! All we needed was "intelligence amplification". If they have been able to design something that could "amplify" at all, they have probably discovered it would amplify stupidity as well; in any case I have not heard from it since.

The major attraction of the modern elixirs is that they relieve their consumers from the obligation of being precise by presenting an interface too fuzzy to be precise in: by suppressing the symptoms of impotence they create an illusion of power.

Finally I must mention the now fashionable interdisciplinary research aimed at making Stone-and-Elixir all in one. I refer of course to the user-friendly programmer's workstation, the interactive learning tool, the integrated project support environment, and the fully automated high-resolution creative dream manufacturing management system.

* |  | *
| * |

So much for the unrealistic expectations from any novel branch of science or technology. In the case of automatic computing, the situation is further aggravated by two circumstances. Firstly, the public at large has very little feeling for the conceptual challenge implied by any non-trivial computer usage and tends to confuse —if I may use an analogy— the composing of a symphony with the writing of its score. As a result its expectations remain unchecked by an understanding of the limitations.

Secondly, I am sorry to say, both the computer industry and the education business contributed more than their fair share of misleading the public. I think of the company advertizing "Thought Processors" or the college pretending that learning BASIC suffices or at least helps, whereas the teaching of BASIC should be rated as a criminal offence: it mutilates the mind beyond recovery.

And all this wide-spread misappreciation of what automatic computing is all about is a threat to computing science because it tends to divert the research effort in which science can not —and hence should not try to— contribute. At the same time it explains the geographic differences I alluded to in the beginning of this talk: each society has its own specific problems and worries and hence asks for its specific Elixirs and Stones.

Take, for instance, "user-friendliness". Taken literally, this is like the term "motherhood": nobody can be against it, so it means nothing. And hence, if the term "user-friendliness" is given a meaning, it must be a terrible euphemism for something else. The catalogue of the average textbook publisher reveals the secret: the textbook recommendation that is deemed to be most effective is that the book is almost totally unmathematical. Mathematics, with its potential for and hence its requirement of rigour and precision, is evidently the pinnacle of user-unfriendliness. Conversely, a paper full of user-friendly topics is primarily respectable in a- or even anti-mathematical circles. (Personally I think the world could benefit from an International League for the Derision of User-Friendliness.)

There are, however, encouraging symptoms that the period in which each newly coined slogan could overnight be turned into a respectable research topic is drawing to a close, and those symptoms go beyond the button I received last year with the text "Stop BASIC before it stops you."; the fact that the Siberian Branch of the USSR Academy has launched a serious effort to prevent BASIC from being introduced at Soviet high schools is a more telling symptom.

From this country the bad news is that at one of its great Universities a specially created Vice President of Educational Computing has decided that all their undergraduates should have enough computing power at their disposal but that this required only equipment and no further education "since our kids already know how to program when they leave high school". The good news, however, is that this Vice President made himself the laughing stock of the company —with the possible exception of the company of his co-physicists—.

And also for the American Universities the tide may be turning. Traditionally they have been asked to train the work-force for the American industry, while the question of educating the industry so as to be worthy of their graduates was left untouched. But, currently, companies in Silicon Valley seem to be folding up at a higher rate than they are erected. I consider that good news because it could drive home the message that neither slogans like "knowledge-based decision aids", nor a combination of adhoccery and brute force will do the job. (It is regrettable that large groups only come to their senses after their day-dreams have turned into nightmares but, this being so, we should occasionally welcome the nightmares.) During the last decades the American Departments of Computing Science have severely suffered from a discrepancy between what society asked for and what society needed, but, be it slowly, the gap seems to be closing.

As I said earlier, the programmable computer is no more and no less than a handy device for the implementation of any thinkable mechanism. As such it poses on us the burden to demonstrate which mechanisms we can think of sufficiently clearly. It implies the challenge of blending Engineering with the techniques of Scientific Thought; this challenge is exciting and we are ready for it.

(Delivered at the ACM 1984 South Central Regional Conference, November 16–18, Austin, Texas.)

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
AUSTIN, Texas 78712–1188
United States of America

Transcribed by Michael Lugo

Last revised 16-Jun-2012 .

09xx

903: A short sequel to EWD863

904: A problem solved by my nephew Sybrand L. Dijkstra

906: Trip report E.W.Dijkstra, Nuenen & London, 10 Dec.’84 – 10 Jan.’85

907: Trip report E.W.Dijkstra, Netherlands, Austria, 23–31 Jan. 1985

909: Trip report E.W.Dijkstra, Westboro-Boston, 14–17 Feb. 1985

911: Trip report E.W.Dijkstra, Tulsa, 1–6 March 1985

913: On a cultural gap (Draft)

917: Another misguided effort

918: A summary of a year’s impressions

920: Can computing science save the computer industry?

921: A correction of EWD914–15

923: Trip report E.W.Dijkstra, Ithaca, Newport, 30 May – 13 June 1985

923a: Where is Russell’s “Paradox”?

924: On a cultural gap

925: Trip report E.W.Dijkstra, London, 25–27 June 1985

926: A computer to think about

927: The ATAC ( = Austin Tuesday Afternoon Club)

930: For the record: the Linear Search

932c: The streamlining of the mathematical argument

936: On anthropomorphism in science

947: A letter to a typewriter manufacturer

951: Trip report E.W.Dijkstra, Europe, 13.12.1985 – 10.1.1986

952: Science fiction and science reality in computing

956: Address to my students

958: On naming (with A.J.M. van Gasteren)

960: On a proof I learned from prof. dr. J. Haantjes

962: Introducing a course on mathematical methodology

963: Visuals for BP’s Venture Research Conference

966: Management and Mathematics

968: Trip report E.W.Dijkstra, Marktoberdorf, 29 July – 10 Aug l986

973: The cosine rule

974: The longer side is opposite to the greater angle

975: On the theorem of Pythagoras

976: Who is your “target audience”?

977: An address to my students (16.9.1986)

978: A sequel to EWD977 (18.9.1986)

979: A solution designed by A. Blokhuis

980: The strange case of The Pigeon-hole Principle

981: Address to my students (23.9.1986)

983: How do we contribute? (30.9.1986)

987: On a class of graphs with modest diameter

987a: On a class of graphs with modest diameter

988: On the phenomenon of scientific disciplines

988a: How experimental is computing science?

989: Proving Gupta’s Theorem

991: Why Johnny can’t understand

992: Difficult is easy

993: The nature of my research and why I do it

996: Courtesy A.J.M. van Gasteren, C.S.Scholten and J.G.Wiltink

997: Computing Science in the United Kingdom

EWD903

A short sequel to EWD 863

In EWD863, I left at the end the derivation of de Morgan's Laws as an exercise to the reader. The following proof, however, is too beautiful to remain unrecorded. I recall —with numbers as in EWD863— the axioms
[ P ∧ Q  ≡  P  ≡  Q  ≡  P ∨ Q ] | (9)
[ P ∨ ¬Q  ≡  P ∨ Q  ≡  P ] | (14)
and the theorems |
[ ¬¬Q ≡ Q ] | (19)
[¬(P ≡ Q) ≡ ¬P ≡ Q ] . | (20)
From (14), we derive with P := ¬P and P,Q := Q,P respectively: |
[ ¬P ∨ ¬Q  ≡  ¬P ∨ Q  ≡  ¬P ] |
[ Q ∨ ¬P  ≡  Q ∨ P  ≡  Q ] ; |
from those two with Leibniz's Principle (and symmetry of v and ≡ ) |
[ ¬P ∨ ¬Q  ≡  ¬P  ≡  Q  ≡  P ∨ Q ] ; |
from that one with | (20)
[ ¬P ∨ ¬Q  ≡  ¬( P  ≡  Q  ≡  P ∨ Q ) ] , |
and finally with (9) |
[ ¬P ∨ ¬Q  ≡  ¬( P ∧ Q ) ] . | (25)
With (19) —and [¬P ≡ ¬P], which is a syntactic descendant of [ P ≡ P ]— |
[ ¬P ∧ ¬Q  ≡  ¬( P ∨ Q ) ] | (26)
follows readily from (25). |

| Austin, 2 Dec. 1984

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

PS. The single substitution P,Q := ¬Q,P into (14), yielding

[ ¬Q ∨ ¬P  ≡  ¬Q ∨ P  ≡  ¬Q ]

would have sufficed in subsequent combination with (14).

(End of PS.) | EWD.

transcribed by Germán González-Morris
revised Fri, 17 Dec 2010

EWD 904

A problem solved by my nephew Sybrand L. Dijkstra

Given a circular arrangement of 16 lights and one pushbutton. When the button is pushed the new state of each light depends as follows on the (old) states of that light and its clockwise neighbour:

when they were both on or both off, the light is on in the new state;

when one was on and the other was off, the light is off in the new state.

Prove that all lights are burning after the button has been pushed 16 or more times.

*                      *
*

Having studied "Een methode van programmeren" --"A method of programming"-- by W. H. J. Feijen and me, and hence being familiar with the symmetry and associativity of the equivalence, my young nephew solved this problem essentially by the following argument.

An arbitrary light is called "nr.0", and the clockwise neighbor of light nr.i is called light nr. i+1. With

B(i,j) ≡ "light nr. i is burning after the j-th push"

the behaviour of the system is given by

(0)     B(i,j+1) ≡ B(i,j) ≡ B(i+1, j)

In preparation of a proof by mathematical induction we observe:

(i) since 2⁰ = 1, (0) equivales

B(i, j+2⁰) ≡ B(i,j) ≡ B(i+2⁰, j).                 (End of (i).)

(ii) From (the induction hypothesis)

(1)     B(i, j+2n) ≡ B(i,j) ≡ B(i+2n,j)

we derive, since 2n + 2n = 2n+1, by substituing i+2n for i

(2)     B(i+2n, j+2n) ≡ B(i+2n, j) ≡ B(i+2n+1, j)

and, similarly, by substituting j+2n for j

(3)     B(i, j+2n+1) ≡ B(i, j+2n) ≡ B(i+2n, j+2n)

Eliminating B(i+2n, j+2n) from (2) and (3) yields

(4)     B(i, j+2n+1) ≡ B(i, j+2n) ≡ B(i+2n,j) ≡ B(i+2n+1, j)

Eliminating B(i, j+2n) ≡ B(i+2n, j) from (1) and (4) yields

(5)     B(i, j+2n+1) = B(i,j) ≡ B(i+2n+1, j)

i. e. with n+1 substituted for n. (End of (ii).)

Combining observations (i) and (ii), we have proved (1) for all natural n, in particular for n=4:

(6)     B(i, j+16) ≡ B(i, j) ≡ B(i+16, j)

Since lights nr. i and i+16 are identical, B(i, j) ≡ B(i+16, j), hence, from (6), B(i, j+16) .

q.e.d.

The above proof is, all by itself, nice enough to be recorded. I am particularly delighted, for when the section on predicate calculus in our book kindles the above in the mind of a 15-year-old, the seed is worth to be sown.

                     Neunen, 14 December 1984

Prof. dr. Edsger W. Dijkstra
Dept. of Computer Sciences
The University of Texas at Austin
AUSTIN, TX 78712-1188
United States of America

transcribed by Michael Lugo
revised Tue, 27 Mar 2007

EWD906

Trip report E.W.Dijkstra, Nuenen & London, 10 Dec.'84 - 10 Jan.'85

(Sunday 23 Dec. 1984) We left the USA on Monday 10 Dec. 1984, but had left Austin the day before --courtesy Jayadev Misra, who saw us to the Airport at noon-- for Atlanta, where we stayed for 23 hours with a nephew and his family. (A very nice alternative to an awkward connection!) With our hosts we climbed the Stone Mountain on Monday morning; my sandals were inadequate and in Nuenen I have bought in the mean time a pair of flexible hiking boots. (also in Texas, sandals were not always the most ideal footwear.) During the KLM flight from Atlanta to Amsterdam, a high-pitched noise from the projector prevented us from sleeping during the movie; at Schiphol we almost missed part of our luggage, two suitcases being delivered on the wrong belt. Tuesday morning, 09:30, Marcus --our eldest son-- collected us at Eindhoven Airport.

During the days to come "And did you like your stay in Austin?" would be the most frequent question we had to answer. This was an opportunity to make up the balance sheet. Certainly most of it: most of UT, most of the countryside, most of the food, most of our house, most of our pattern of life (that is, to the extent it has been established), and most of the KMFA. At the same time, we had to admit the initial problems had sometimes been overwhelming, e.g. to register my new car it had to be inspected, to get it inspected I had to drive it through the town, to be allowed to drive it I had to be insured, and in order to get the insurance it had to be registered! (This is now a nice example of a deadlock situation, but as long as it lasted it was hardly funny.) and the problems with getting our house (more or less) finished and the airconditioning (more or less) wired according to specification had, of course, been out of proportion.

Our major adjustment problems so far seem to have been three.

(i) This one is trivial in nature, but was nevertheless tiring, time-consuming, and sometimes frustrating: the way in which goods are divided over different shops differs from what we were used to. And if you start thinking about the amount of information involved, it is suddenly not surprising at all that it takes a lot of time, effort, and experience to learn the new partitioning.

(ii) We were faced with a different interface between the industry and its customers: the last two or three phases of quality control are left to the customer. Well, that takes some getting used to! One side of the coin is that if you return a vacuum cleaner or handmixer, or point out that your airconditioning does not work, you get a new vacuum cleaner or handmixer and the control of your airconditioning is rewired; the other side of the coin is that your handmixer collapses an hour before the dinner guests arrive, you have to go to the shop at least twice instead of once, and that you have to leave the country before you have had the opportunity to verify that this time the airconditioning really works. (The last rewiring was done three days before our departure: I could only pray that the Bösendorfer won't dry out during our absence.)

Aside I now know the origin of "user satisfaction" as a quality criterion for software, and am grateful for that insight. I always found it a ridiculous criterion because it is technically useless: in 1960, Jaap Zonneveld and I implemented ALGOL 60 under the --evidently most inspiring-- slogan "The user be damned." It worked beautifully. (End of aside.)

(iii) In our innocence we thought that 22 years in the Dark South of the Netherlands --worse: only 15 minutes from the Belgian border-- had been a lesson that would last for life. But we were definitely unprepared for the high level of ubiquitous incompetence we would face in Austin. (When I try to tell with my most stoic face that on my car insurance papers, only 4 of the 17 characters of the chassis "number" are wrong, people here think I am kidding and don't believe me. When, early December, after we had ordered an ironing board, Sears delivered a hair dryer, we were no longer amazed.) A quarter of a century ago I learned that "The Backward Country" is a reference to the USA. I was surprised to learn that even in clerical and technological areas the nickname is still appropriate.

(Wednesday 26 Dec. 1984) Back in the Netherlands, life was as busy as expected. Ria went to her mother in Amsterdam, together we went twice to my mother (who had her 84th birthday on the 20th). We paid two visits to our dentist, I a visit to my physician for my medicine and to have the arteries in my neck checked --they were okay--. Ria did a lot of shopping, I some. We went to the bank in person, but confusion over the IRS I could clear up over the telephone. The first Thursday morning I helped my son Marcus move. Etc.

So far, I worked twice with Carel Scholten and twice with Netty van Gastern. With Netty I screened what she had written since her visit to Austin. The first day with Carel was devoted to what we had done during the preceding months; the second day was devoted to our book, on the manuscript of which I had started in the mean time. I wrote a long letter to my nephew Sybrand in Kortrijk, who had sent me a beautiful proof (which I recorded one evening in EWD904). It is so short and so beautiful that I may use it next month as an example of what can be achieved by formal means when I have to give a talk at the Symposium that will be staged on the occasion of Carel Scholten's retirement at Philips.

I attended last week's session of the Tuesday Afternoon Club --this week the THE is closed--. I showed them some nice proofs and drew their attention to the problem of establishing whether one given expression is a syntactic descendant (or: substitution instance) of another given expression. In the presence of symmetric, associative operators, the problem seems in general difficult, and I could convince them why it would be nice to know how difficult the problem really is. I had a long discussion with Martin Rem --more about science politics than about science itself--, and I paid three other visits to the THE.

In the Department of Mathematics and Informatics I found all the familiar tensions still very much alive. The mathematicians are still the champions of mediocrity and sabotage the informatics curriculum by giving the informatics students a fake course instead of teaching them what a proof is. (For one of their courses the examination was such a caricature that 170 out of 175 students passed the test!) The problem is that in the joint department the mathematics branch is almost as overstaffed as the informatics branch is understaffed. Were this not the case, the computing scientists would have taught their students mathematics themselves. Nothing shows that my departure has reduced the tensions; the problem is that these mathematicians are afraid. But by behaving in the way they do they disqualify themselves so blatantly that they can only hasten their own dismissal. (I see no future for socialist mathematics.)

(Sunday 6 Jan. 1985) In the mean time I worked another two Mondays with Netty and another two Fridays with Carel. (In between I had worked on the manuscript of our book.) I wrote a number of letters and spent a day on the completion of a refereeing job on which I had started shortly before I left Austin. (The paper was much too fat.) I had every reason to be grateful to Burroughs for having left me the copying machine in Nuenen: without attending to my mailing list I made several hundred copies this month.

And the social activities continued. On 1 Jan. 1985 Femke joined me on a trip to my mother (to wish her a Happy New Year and to say goodbye). On 3 Jan. 1985 Ria and I went to Holland. While she visited her mother in Amsterdam I visited friends in Aerdehout. After having collected Ria at her mother's retirement home, we went for dinner to friends in Voorburg.

We left them at 22:20. That night the winter started: we were caught by a snow storm and it took us almost three hours to reach Nuenen. Today, around noon, Femke called from Groningen asking us what to do about frozen water pipes. (Our house in Nuenen being better designed, it was a new experience for her.) Tomorrow I have to fly from Amsterdam to London, and I hope the best! (What else can one do?)

(Saturday 12 Jan. 1985) On Monday morning, Ineke van der Meiden took me to the Eindhoven railway station; the car ride took almost 40 minutes instead of the usual 12. Trains were still moving, but the trip to Amsterdam took an extra hour. Our planning had been sufficiently pessimistic: we caught our plane which flew on time. In London, Netty van Gasteren and I were collected by a BP driver, who took us to the BP Training Centre (very nice, but for the absence of decent blackboards).

The next two days, Netty and I addressed in turn an audience of about 20 people about the streamlining of the mathematical argument; it was a new audience, we used some old examples and some new ones. It was a nice audience --five of the people never opened their mouths-- but rather mixed, and that is a problem nowadays. Decades ago, when needing an example familiar to all, one could always fall back on Euclidean geometry, but that is no longer a common background today. (With for some triangle A meaning "it is isosceles" and B meaning "it has two equal angle bisectors" the proof of A⇒B used to be trivial, the proof of B⇒A used to be a notorious teaser, but only two people remembered that! Needless to say, we proved A≡B.) The audience seemed very pleased with our performance (more pleased, in fact, than we were ourselves).

Next morning, Netty gave me a wake-up call at 06:30. At 07:00 the taxi came to take us to Heathrow where our ways parted: I flew first to Schiphol, were Netty arrived shortly before I boarded the flight to New York. The PanAm flight from there to Austin was delayed by 1½ hour. When I arrived --past midnight, after about 24 hours of travel-- I was releaved to see Ham Richards waiting for me and annoyed to learn that my suitcase (which I had seen through customs in New York) had not made it. When I woke up this morning, it had started snowing. I phoned PanAm about my suitcase; it had arrived in Austin but I did not get the impression that PanAm was very eager to deliver it at Robbie Creek Cove.

While we were in Nuenen, Ria's bicycle was stolen when Rutger had used it to go to Eindhoven. (He had to walk back in the middle of the night.) I read a four-volume history of The Low Countries (with many illustrations): a long history of hunger, misery, violence and dishonesty. I could not escape the impression that my country's history as I learned it in my youth had been somewhat rose-coloured.

During our absence, the FM radio programs had changed: the German music program included more modern composers in the evening and the Flemish had become even more nationalistic; the Dutch radio had a new announcer with a very vulgar diction. We heard Moussorgsky's "Pictures at an Exhibition" thrice, and so with Handel's "Messiah" --once sung in German!--.

Austin, 12 Jan. 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750
U.S.A.

transcribed by Tristram Brelstaff
revised Sun, 29 Feb 2004

EWD907

Trip Report E. W. Dijkstra, Netherlands, Austria 23-31 Jan. 1985

I left Austin on Wednesday morning, but had left UT 24 hours earlier to pay a visit to and give a talk at MCC. Title: "Computing Science's Future". I had been warned that the interview with me that the Austin American-Statesman had published at Dec. 26, 1984, had evoked rather vehement reactions at MCC and was therefore prepared to meet opposition or disagreement. But none of that! Had I convinced them? Had I addressed a bunch of cowards? Or had the opposition thought it more convenient to stay away? I think that at future occasions I shall be more aggressive. I think the time has come to state -- politely but with all the bluntness required-- that the American computer industry is absolutely sick and that MCC won't cure it by perpertuating all the fashionable mistakes. Public Relations may still suffice to make an actor act as President of the USA but as a basis for digital systems design it is definitely insufficient. (The artificial intelligentsia and the other soft scientists in the world of computing won't love me for this, but they don't do so anyhow.)

The flight via Houston and Amsterdam was without events and at 9:20 Thursday morning I landed in Eindhoven, where I was collected by Ria with the little VW diesel we had rented. During the day I made a number of telephone calls, took a nap, did some shopping and started sorting papers by way of preparing our departure. I met my sons but not my daughter, who stayed in Groningen. That evening we had a few guests who came to say hello, and that night I slept soundly. On Friday morning, Ria and I completed the preparation of our departure and early in the afternoon we went to Philips Research Laboratories where I was the third speaker at the occasion of Carel S. Scholten's retirement. (I gave a poor speech; I had been upset and was probably too tired as well.) The day ended at midnight after a pleasant farewell dinner that Carel had staged at De Karpendonkse Hoeve. The day left me with very mixed feelings that would stay with me for the next few days. Much more than my poor performance --it was not the first time and it won't be the last-- it was the sudden reconfrontation with the narrow-mindedness of (mainly) the electronic engineer. It roughly reminded me of a number of experiences I would rather have forgotten. (Such confrontations always make me wonder "What are my blind spots?".)

The next morning at 8:15, Wija van Deurzen came with her Scirocco to see us to the Eindhoven railway station (via Son, where we had to return the VW diesel). At Amsterdam CS, I had difficulty carrying our (much too heavy) luggage from the train to the KLM coach. (Later Ria proved to be an expert at finding little lorries.) We flew to Munich, then by coach to München Hbf., from where we took an excellent train to Innsbruck. Gilbert Helmberg collected us there at 17:30 (in the same old VW station car, still going strong after 13 years).

It was very nice to meet him and his wife again, after so many years. We stayed in Gasthof Koreth --since 1493-- quite near to their house. That evening we had dinner in town with them and Arno, their oldest son; we were again amazed by the quality of their Dutch, which is astounding.

On Sunday morning, Ria and I walked to Innsbruck's old centre (and managed to visit the Hofkirche between two masses). After almost 500 years, Kaiser Maximilian is still very much present; I know of no other place where an otherwise so distant past is so nearby. It was beautiful, and so was the weather and were the mountains surrounding the city. The rest of Sunday we stayed with the Helmbergs.

The next morning, Gilbert collected me after his 8-o'clock lecture and took me to the new building of the Technische Fakultät, where I gave a lecture at 11:00. (I did Yossi Shiloach's algorithm; this time it was a smooth performance.) It was a nice audience, though the whole place --despite its 17.000 students-- struck me as rather provincial: most faculty members definitely preferred to address me in German. We had lunch with a few of them. That afternoon Gilbert and Thea showed us some of the surroundings. (On an icy parking lot I lost my balance but did not break my wrist.) We stayed the rest of the day with them. It was nice and illuminating to discuss the possible futures of mathematics with a very pure mathematician; he was unaware of "Leibniz's Dream" and the degree to which it is coming true.

On Tuesday morning we continued our journey to Vienna. (We were already in the train when Thea Helmberg came by to bid us farewell; we were surprised and touched.) In Salzburg we were joined by Unkel Fritz (= F. L. Bauer from Munich); when he heard we came from Innsbruck, he immediately asked "Do you know Helmberg?". We could reassure him. The train took us through Austria and Southern Germany; and it was again beautiful. In Vienna we were greeted by Heinz Zemanek who had come to the railway station to collect Unkel Fritz; Heinz took all three of us to our hotel (in a by definition old and accidentally very dirty Citroen ID, with leather upholstery: I had never seen that before).

The next forty hours we would live in the immediate vicinity of the St. Stephansdom in the heart of Vienna. After having been offered goulash in the "Bierklinik", we spent the evening in the Zemanek apartment at Blutgasse 3, again beautiful: a lovely mixture of (very) old and (very) new. As the evening went on, we met more and more acquiantances, among whom Mike and Peggy Woodger, whom we had not seen for quite some time.

On Wednesday we had in the great auditorium of the Austrian Academy of Science --yes, complete with baroque paintings all over the ceiling-- the festive symposium at the occasion of Heinz Zemanek's retirement (from IBM). Unkel Fritz gave a nice talk on "Whence and whither informatics?". Some talks were purely beatification of Zemanek --I don't think they would have been possible elsewhere-- some talks were ridiculous. Academician Prof. B. Sendov (Bulgarian Academy of Science) spoke on "Information and Knowledge"; his main point was that as all intelligence is based on knowledge, artificial intelligence had to be based on artificial knowledge. Prof. R. Trapple (University of Vienna), while speaking on "Cybernetics and Artificial Intelligence" gave a plea for peaceful use of artificial intelligence (such as equipping the hot line between Washington and Moscow with bi-directional automatic translation between English and Russian "so as to avoid misunderstanding between superpowers at critical moments"). He had founded the Austrian Society for Cybernetics, later generalized into the Austrian Society for Cybernetics and Artificial Intelligence, but --vide the peaceful use -- bandwaggons are presumably his true specialty. At the end of all this, Heinz Zemanek gave a very nice closing speech, tempered sarcasm being part of the survival kit of the sensitive.

On Thursday morning we took an early taxi to the Vienna Airport. Via Amsterdam and New York we flew to Austin. (The last flight was so bumpy that even the purser got pale; quite a few passengers clearly got afraid.) With a delay of 1 1/2 hour we arrived in Austin just after midnight. It was bitterly cold. But our luggage had caught all connections.

Austin, 2 February 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188,
United States of America

Transcribed by Michael Lugo

Last revised Tue, 1 Jun 2004.

EWD 909

Trip report E.W.Dijkstra, Westboro-Boston, 14-17 Feb. 1985

This was a short trip up North at the invitation of Data General. After my Thursday morning lecture at UT, I drove home to collect Ria and then to the Airport. We left Austin at 13:05, changed planes in Dallas, and arrived in Boston at 18:53 (local time). On Sunday, we returned via the same route. We flew with American Airlines in B727's; the planes were full, the flights were smooth and on time.

Data General had rented a car for us from Avis (a Dodge "Aries" that I did not like), and had made a room reservation at "The Bostonian Hotel", quite near to the airport (at the other end of the tunnels in fact). On the airport the traffic was congested, at the other end of the tunnel (in the heart of Boston) it was confusing. (They had sent us a map on which the hotel had been marked, but at the wrong place.) We reached the hotel at 20:15. The hotel's restaurant being full, we had dinner in a nearby caf�.

The next day we spent at Data General in Westboro. We left the city around 10:00, found Data General around 11:00, left close to 17:00, spent in Boston itself about an hour in a traffic jam and were back in the hotel shortly after 19:00. (At a merge, a huge truck mercilessly pushed the car in front of us out of its lane and against the car to its right: the victim was damaged at both sides.)

On Saturday we behaved like good tourist. First we walked to the Aquarium, which was very impressive. If you have never seen it, try to visit it the next time you are in Boston. Next we went to The Computer Museum. We found it interesting, but I doubt whether I can recommend that in general. On an old movie we saw a very young Doug Ross explaining an AI project! (Never knew that Doug had had a flirtation with AI!) I was struck by the strongly anthropomorphic terminology, used right at the start: in 1952 —in a program about the elections— Walter Cronkite (?) referred to the UNIVAC as "he". It was shocking, but it explains a lot. It was also interesting to observe the public: it did not seem to realize that, at the time, these early machines were great technological achievements, and when it saw such things as punched cards or paper tape, a condescending laughter was its primary reaction. In the afternoon we made the tour of the old city in a trolley. At the end of the day, after all the contrast between the old and the new, I think I could understand how Boston fills the American citizen with pride. We were very impressed by the result of the renovation of the Market Halls — the more so because, a stone's throw away, slums and ruins catered for the contrast.

At Data General we were given before lunch a short tour of the facility. During lunch —we were about nine people— I was most impressed by Julie Kling, the resident Linguist; I would not be amazed if she understood the limitations of thinking in terms of analogies at least as well as her technical colleagues. I thought I would start my lecture at 14:00 and it was with some disappointment that I learned that I would only start at 15:00. From 15:00 to 16:00 I showed our explanation of the Chandy-Lampart Snapshot Algorithm (a topic I had chosen because I suspected —with full justification, as it turned out— that my visual aids would be barely adequate: I addressed an audience of 200 in the cafeteria). I had hoped that the next hour would be available for a more general discussion (as announced), but suddenly the audience got restless —they wanted to leave before the rush hour?— and my host, Jerry Breecher, cut the performance short by offering me a portable personal computer. Then there was a big applause, but I don't know whether that was for my performance or for the present. Shortly thereafter, we were on our way to Boston, as before I as driver and Ria as copilot. I had learned (to my delight) that a year ago at Data General the job title of all programmers has been changed to —yes, your guess is right!— "software engineer". I said "to my delight" as this renaming is the strongest possible linguistic confirmation of what I suspected all the time, viz. that "software engineering" has failed to develop itself into an intellectual discipline of substance. The renaming was a cosmetic change that was possible because the new name did not mean anything very different from the old one. I am really delighted.

On Sunday morning, at Logan Airport at the gate, we met Joe Weizenbaum; he told us that 80 percent of the —accepted!— MIT freshmen had just flunked their writing test. On Sunday evening, Jayadev Misra and his wife came by, who —with amazing boldness and expertise— immediately installed my 256 Kbyte computer. My first impression is that the quality of its screen is enough to guarantee its utter uselessness.

Monday 18 Feb. 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Corrado Cantelmi
revised 29-Sep-2011

EWD 911

Trip report E.W.Dijkstra, Tulsa, 1-6 March 1985

For a two-day visit to the University of Tulsa, Oklahoma, Ria and I left Austin on Friday morning by car: knowing neither Northern Texas nor Oklahoma, we felt we should use the opportunity to get acquainted. On Friday we drove 225 miles, up to Tyler; on Saturday we drove 425 miles, through Northern Texas and Eastern Oklahoma, arriving in Tulsa in the evening. On Sunday, we had a day off: in the morning we went to the Tulsa Zoo —very hard to find— and the afternoon we spent in our hotel room, mostly writing and reading. After dinner our social obligations started. Monday and Tuesday were spent at the University of Tulsa, where we left at 17:30. That evening we drove 225 miles to Sherman; on Wednesday we drove the remaining 325 miles to Austin, where we returned at 16:00.

We drove 1254 miles in toto; it was our first opportunity to try out the new Audi 4000 S on a long trip. On the whole it passed the test with flying colours: it made on the average 36.3 miles/gallon (=15.4 km/liter), but the engine still seems a bit new —at a moment no sheriff was looking, I tried its maximum speed on a deserted road, but in its 5th gear it stopped to accelerate around 90 m/h—. It has, however, evidently been designed with the German Autobahn in mind: like its predecessors —this is our 4th Audi— it transmits on a bumpy road —and we encountered some!— all shocks and noises to the interior. On Tuesday evening we had an uncomfortable hour with road constructions and very heavy oncoming traffic on a two-lane road; Ria had the bad luck that she was driving on that stretch.

When we left Austin, we left Interstate Highway 35 as soon as possible, and took at Round Rock the U.S. 79 in the direction North-East. It is a route we can recommend: we liked the trip very much. Later we found ourselves —by accident!— on what is advertised as the Texas Forest Trail, the countryside was nice and did not strike us as monotonous at all. The stretch from Tyler to the border with Oklahoma is at first less exciting but becomes more and more interesting when one realizes one is crossing a river delta of impressive proportions. (The Red River, which forms the border between the two states, is really red!) Eastern Oklahoma is really beautiful. We drove most of State Highway nr. 1 —"at our own risk", as we were officially notified!— just along the mountain ridge, with the surrounding countryside far below at both sides of the road. Then we drank something in The Hilltop bar —what else!— : a wooden shed where four men and a woman were playing billiards in the middle of nowhere. We observed them for half an hour and I realized that I was absolutely unable to envisage the rest of their lives; in honour of our presence they threw coins in the Wurlitzer.

On our way back we came down on the US 281, now passing Dallas at the other side. Our way led through the hills, and, again, it is a trip we can recommend: the views were often breathtaking. (And we saw genuine ranches!)

But perhaps one should do it with a "motor home" or something like that, taking enough of one's own comfort with one to be independent. The catering was terrible. The Sheraton Inn in Tyler and the Ramada Inn in Sherman are places I hope never to visit again, and from my confession that we have allowed ourselves to be fed in places like McDonald and Golden Fried Chicken you can draw the rest of your conclusion. The Westin Hotel in the heart of Tulsa, however, was excellent; our room had even a desk at which I could write very comfortably (and so I did).

*         *         *

My official and widely publicized obligations in Tulsa were to give two talks at The University of Tulsa in their "Distinguished Lecture Series in Computer Science," on Monday on "The Snapshot Algorithm of Chandy and Lamport" —chosen because that is a technical topic I can lecture on when the "visual aids" are defective, and one never knows!— and on Tuesday on "Future of Computing Science" —because my host was very keen on such a talk— , both days at 15:00 in one of their largest lecture halls. Both talks went very smoothly, but the PA system was too weak, and that hurt during the last talk when I had a full house.

On Monday I met with a junior level computing science class, on Tuesday morning with a senior level one. With one or two exceptions, the students seemed totally unfamiliar with formal techniques. The most important part of my visit was probably a long discussion on Monday morning with William Coberly, the Chairman of the Department of Mathematical and Computer Science. I encouraged them to keep the two in a single department.

The University of Tulsa seemed to be a proud private university of modest size (6000 students). They wanted —as a department or as a university— not to cover "everything" but to concentrate on "what matters most", and for the selection implied they sought my guidance. I found them well-intended and open-minded, and as a result I liked the place. Whether they will succeed, however, is quite a different matter. They seemed to have their major stress in their undergraduate education, and somehow undergraduate courses seem always to be unduly knowledge-oriented. To me it is not obvious at all that computing science is an appropriate topic for an undergraduate curriculum here. (Typically, the most frequent question asked was what textbooks to use, a question I have never asked myself. The faculty members had fortunately the grace not to ask which programming language to use, but in the discussions the students did.)

On campus it was quite noticeable that Amoco was the dominant industry in town. I met a few people from Amoco Research and was in general favourably impressed by their views on the r�le of research in industry and on the r�le of industry in the scientific enterprise. The cooperation seemed to work (without unrealistic expectations at either side).

Austin, 7 March 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Science
The University of Texas at Austin
Austin, Texas 78712-1188
United States of America

transcribed by Corrado Cantelmi
revised 29-Sep-2011

EWD 913

On a cultural gap (Draft.)

On the typical university campus, the typical mathematician and the typical computing scientist live in different worlds: they don’t know each other or, if they do, they are not on speaking terms. The purpose of this essay is two-fold, viz. to give a historical explanation of this phenomenon and to argue that we should do something about it.

Now, exhorting the world to mend its ways is always a tricky business, for implicit in the exhortation is always the verdict that the world’s ways leave plenty room of improvement, a suggestion that is always offensive to the touchy. One way of gilding the pill is to qualify one’s sentences by all sorts of softeners, such as “typical”, “in general”, “on the average”, “usually”, “not uncommonly”. For brevity’s sake I shall not do so. (A second reason for not doing so is that I do not really believe in the effectiveness of the softeners with which one could lard one’s text: those who wish to take offence will anyhow succeed in doing so.)

At the heart of my historical explanation lies the thesis that when, now four decades ago, the automatic electronic computer was sprung on us, we were not ready for it and that thereafter —people and computers being what they are— wide-spread confusion about what had happened was unavoidable.

By far the most common way in which we deal with something new is by trying to relate the novelty to what is familiar from past experience: we think in terms of analogies and metaphors. As long as history evolves along smooth lines, we get away with that technique. It is obvious, however, that that technique breaks down whenever we are suddenly faced with something so radically different from what we have experienced before that all analogies, being intrinsically too shallow, are more confusing than helpful. But such radical novelties are precisely the things technology can confront us with; the automatic computer was one of them. (From the same era, the pill and the atom bomb were two others.) For coming to grips with radical novelty there is only one way, i.e. consciously trying not to relate it to one’s accidental past but to appreciate it for its internal structure. The latter way is far less popular than the former one as it requires hard thinking.

In short, being the radical novelty they were, computers were bound to cause confusion. In the world of computing —we did not talk about computing science yet— an accident of history caused further obfuscation. As I said earlier, we were not ready for computers, and now I may add that the unprepared included the electronic engineers that were supposed to design, build, and maintain them. The job was actually beyond the electronic technology of the day, and as a result the question of how to get and keep the physical equipment more or less in working condition became in the early years the all-overriding concern.

We now know that electronic technology has no more to contribute to computing than the physical equipment. We now know that a programmable computer is no more and no less than an extremely handy device for realizing any conceivable mechanism without changing a single wire, and that the core challenge for computing science is a conceptual one, viz. what (abstract) mechanisms we can conceive without getting lost in the complexities of our own making.

But in the mean time, the harm was done: the topic became known as “computer science —which, actually, is like referring to surgery as “knife science”— and it was firmly implanted in people’s minds that computing science is about machines and their peripheral equipment. Quod non. (These days I cannot enter a doctor’s, dentist’s, or lawyer’s office without being asked my advice about their office computer. When I then tell them that I am totally uninformed as to hard- and software products the market currently offers, their faces invariably get very puzzled.) The machine-oriented image of computing science, no matter how obsolete and distorted in the mean time, lingers on. Needless to say, it can only contribute to hiding for the mathematical community that a major part of computing science is by now —be it perhaps somewhat unusual— mathematical discipline.

When, after the first ten years, computers became available as industrial products, it was a commercial imperative for the computer industry to dissociate their products as far as possible from any form of mathematics, the latter being viewed as the pinnacle of “user-unfriendliness”. Its sales force accordingly brainwashed the public, including the computing scientists and mathematicians alike. So much for the external influences that helped form computing science’s public image.

As time went by, we got people using machines and on campus we got people involved in what was —timidly at first— called “computing science”. Did they promote of their activity an image that would appeal to the orderly and scientific mind that the mathematician regards as his specialty? Certainly in the beginning definitely not.

To begin with, they institutionalized the habit of referring to machines and their components and later to programs in a strongly anthropomorphic terminology. This must have put off many of their mathematical colleagues (certainly those who had learned to interpret the heavy use of anthropomorphisms as a sure symptom of professional immaturity). Though the underlying metaphors have long out-lived their potential usefulness and are now more a handicap than a help, the habit of anthropomorphizing equipment regrettably persists in the computing community until this very day.

Furthermore, the early scientists involved in computing came —of necessity— from other disciplines: they had mostly been trained as physicist, chemist or crystallographer (with an occasional astronomer and meteorologist). They were the machine users of the first hour. But for reasons I have failed to fathom, the vast majority of them have failed to transfer their scientific quality standards to the programming that became their major occupation: as soon as programming is concerned, otherwise respectable scientists suddenly accept to live by the laws of the logical jungle. (To this very day we find physicists willing to parade as computing experts, and that merely on the strength of having burnt up so much processing power.) A generation of “scientific” machine users has approached the programming task more as solving a puzzle posed by the machine’s manufacturer than as an activity worthy of the techniques of scientific thought. Their logical catch-as-catch can must have been repulsive to the orderly mind that —as said— the mathematician regards as his specialty. So much for their contribution to computing’s image.

How did the mathematician react to the advent of computers? The simplest answer is: “Not.”. As it takes for new scientific developments about half a century to become widely accepted common property, our mathematician’s values and prejudices had their roots in the late 19th, early 20th century. He was full of analysis, loved the continuum and the complex plane and considered infinity as a prerequisite for mathematical depth. How in the world could computing have anything to do with him? (In the sixties, a justly famous mathematician, then Chairman of the Department at Leyden University, still thought he could declare that “being a mathematician, he knew of course nothing about computers” without making a fool of himself.) If he acknowledged the existence of computers at all, he viewed them as number crunchers, of possible use as a tool for his colleague in numerical analysis —if he had one—. For numerical analysis, of which he knew very little, he had at best a mild contempt. So he disregarded computing completely, hardened in that attitude when he noticed that machines were primarily used for business administration, which was a trivial pursuit anyhow.

Occasionally his peace of mind was slightly disturbed when a colleague in number theory or combinatorics proved a theorem for all n by proving it himself for all n exceeding some large N and having one of those machines check it for all smaller values. He quickly restored his peace of mind by frowning upon the practice. Finally he settled on the compromise that a computer might occasionally be a useful tool, but then only for the more repetitious and boring part of the work, but since all computations were essentially finite and all finite problems were in principle trivial, why bother?

That way in which the mathematician soothed himself was, of course, flawed and as time went by he grudgingly admitted that there might be circumstances under which it might be untenable to lump all finite problems together under the category “trivial” and we should admit the sub-category “finite, yes, but much too big if you really want to do it”.

There is, however, a much deeper flaw. One day our mathematician concocted an argument that made him feel utterly respectable for it was full of transfinite ordinals and more of such good things. But when he proudly showed it to his colleague, what did he show: infinite sets or ........ just a finite argument? And this, of course, raises the question what mathematics is about: is it still —The Concise Oxford Dictionary, 6th Edition, 1976— the “abstract science of space, number, and quantity” or is it more “the art and science of effective reasoning”? I think we have here in a nutshell the full profundity of the cultural gap: the mathematician opts for the Oxford definition, the computing scientist for the latter alternative.

Let me try to sketch, by way of explanation of that preference of the computing scientist, what computing science came to be about. Computing science is not about computers, computing science is not about how to use computers in specific areas of potential application, computing science is about how to solve, with or without machines the (scientific) problems posed by the existence of computers.

As said before, we were unprepared for the advent of the automatic computer, and one of the things we were unprepared for was the shocking discovery —made as soon as the machines became available— that we could not program! All but the most simple programs turned out to be —and remain!— full of bugs.

Understandingly, the blame was put on the way the programmer writing in machine code had to express himself: an unfamiliar notation, the understanding of which required a complete awareness of all the idiosyncrasies of the machine in question. In response to our difficulties, what is now known as “higher-level programming languages” came into being. They offered the programmer a more familiar and more suitable notation that shielded him from specific machine characteristic and the implementation of which relieved him from a number of clerical burdens. They embodied a significant improvement that allowed a change of attitude: had it formerly been the task of the programs to instruct our machines, now it became the task of the machines to execute our programs.

With that change of emphasis, we got our second shock: shielded from machine characteristics and relieved from all sorts of clerical burdens, we still could not program! Slowly it dawned upon us the we could not continue to put the blame on the mechanisms available to us, because the major bottle-neck had become our inability to reason sufficiently effectively about what we were trying to conceive. With that recognition “programming methodology” became an area of explicit scientific concern.

From concerns such as “How do we best structure a program so as to facilitate our reasoning about it as much as possible?” it was only a short way to “How do we most effectively disentangle complicated arguments?” and, for instance, “modularity” became one of the catchwords. By the end of the sixties it was generally felt by the computing scientists engaged in this kind of methodological investigations that the closest familiar analogue to a well-engineered, sophisticated program was probably an equally well-engineered, sophisticated mathematical theory. Despite that feeling it took quite a few more years before they realized that their efforts had probably be best understood as part of mathematical methodology in general.

In retrospect, that slowness of the computing scientist in recognizing the intrinsically mathematical nature of his work is understandable: he was heading for a kind of mathematics of a flavour different from what the mathematician was wont to do: for the computing scientist, formal techniques would play a much more important r�le than they had done so far for the mathematician.

For the predominance of formal techniques in the computing scientist’s work, we can discern —again in retrospect!— three reasons, viz. a practical one, a circumstantial one, and a cultural one.

The practical reason was that formal techniques are indispensable for dealing in a sufficiently trustworthy manner with the type of complexities a program designer has to control.

The circumstantial reason was that any programming language represents by the very fact of its mechanical interpretability a formal system of some sort.

The cultural reason was that the computer scientist regards —“by nature”, so to speak— symbol manipulation as mechanical processing of uninterpretated formulae (regardless of whether he actually intends to mechanize parts of the process).

Part of the significance of what has happened has been seen by some of the logicians. P.Martin-L�f —see [0], to which I refer for further references— write for instance:

“It [=the creation of high level languages of a sufficiently clean logical structure] has made programming an activity akin in rigour and beauty to that of proving mathematical theorems. (This analogy is actually exact in a sense that will become clear later.)”

and

“In fact, I do not think that the search for high level programming languages that are more and more satisfactory from a logical point of view can stop short of anything but a language in which (constructive) mathematics can be adequately expressed.”.

The book [0], from which the above quotations are taken, has been given as motto

“‘It is reasonable to hope that the relationship between computation and mathematical logic will be as fruitful in the next century as that between analysis and physics in the last. The development of this relationship demands a concern for both applications and for mathematical elegance.’

(J.McCarthy, 1967)”

The earlier quotations illustrate that McCarthy’s hope is in the process of being fulfilled; his second sentence, however, captures the predicament of the computing scientist. The logician primarily studies formal methods in an effort of capturing how the mathematician does or should behave himself: he more ponders about those methods than that he uses them himself. The mathematician knows of the existence of mathematical logic but never uses it. (With a simple test I have actually established that, up till now, for the mathematical community George Boole has lived in vain: the fraction of mathematicians well-versed in the propositional calculus is absolutely negligible.) He definitely associates logic with the purer side of mathematics. In our history, the computing scientist seems to be the first to be asked to apply formal logic on a grandiose scale and to make formal techniques an integral part of his daily reasoning; in a way, circumstances have forced him to become more mathematical than the Pope is Roman Catholic.

My expectation —but I have often been accused of naive optimism!— goes further than McCarthy’s hope. I expect formal techniques to have in the next century a most profound influence on mathematics in general. Currently, the mathematicians are an informal lot, a state of affairs defended by the remark that a more formal treatment would make the topic boring, tedious, laborious, repetitious and what have you. The defence may seem valid, but what else can you expect in a world that has never seriously tried to apply formal techniques on a sizeable scale with elegant effectiveness? A convincing defence it is not.

From both sides, closing the gap will be most likely be experienced as a painful process. For computing scientists with an experimental bent it will be unsettling to enter a culture that would prefer their experiments to be superfluous; for the traditional mathematician it will be unsettling to learn that his time-honoured way of working is just no longer adequate. But that is precisely why I want the gap between the computing scientist and the mathematician to be closed: neither of them should deny themselves the challenge that is implied.

[0]   | Hoare, C.A.R. and Shepherdson, J.C. (Eds.), Mathematical Logic and Programming Languages, Prentice-Hall International London, 1985 ISBN   0–13–561465–1

Austin, 24 March 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX, 78712–1188
United States of America

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD917

Another misguided effort

Computing science has had very little influence on computing practice, which is mostly performed in a highly unscientific manner. I have been --and still am-- particularly worried about the ever-widening gap between computer science and the practices within the computer industry, which --I think-- should be our high-technology counterpart "in the real world". It has greatly saddened me to see that industry on the whole persists in a behaviour as if common sense suffices where I know that the techniques of scientific thought are required. My many crusades to remedy the situation, I am sorry to observe but not ashamed to mention, have not been particularly effective (so ineffective, in fact, that one of my Eindhoven colleagues called me a Don Quichote). Obsessed as I am I have frequently raised the topic in industrial environments; the average reaction admits the gap but then argues that computing science has very little to offer their business. The latter I have never been able to believe, a disbelief I found most embarrassingly confirmed when I heard of the following industrial project.

Inspired by the soaring cost of software development they wanted to do something about the (undeniable) fact that it is often so hard to understand a program written by someone else. To remedy the situation they wanted to develop some sort of "algorithm animator" that, as an aid to understanding, would graphically display how the computation evolved in time. Needless to say, the animator would have some sort of conceptual zoom lens that would enable the computation to be viewed at different levels of abstraction. There are at least three reasons why this project will fail.

(i) Program texts are highly compact deposits of our intellectual labour. In my case the essays I write about programs are about ten times as long as the raw code in which they culminate, a factor which cannot be "explained away" by the verbosity of my prose (which in these essays tends to be terse). In short: the program text is only the top of the iceberg. And it is vain to reconstruct mechanically the iceberg, given only the top.

(ii) Despite what herds of educationalists want us to believe, pictures are a most inadequate vehicle for representing the relationships one has to capture when reasoning about programs. (Are pictures ever adequate? To quote Morris Kline: "But the pictures are not the subject matter of geometry (!) and we are not permitted to reason from them. It is true that most people including mathematicians, lean upon these pictures as a crutch and find themselves unable to walk when the crutch is removed.")

You can take the experiment when lecturing. Draw a few pictures and the dumber students, who a moment ago had no idea what you were talking about suddenly nod "understandingly". In fact they still have not the foggiest notion, but they nod "understandingly", recognizing the picture --boxes with arrows--, the visual familiarity of which gives them a superficial but false sense of security. (Furthermore pictures are usually overspecific, even in geometry: you cannot draw a triangle without making it obtuse or not, even if the distinction is irrelevant for the argument.)

(iii) You can only animate individual computations, whereas the program is about the set of all computations possible under control of it. It is impossible to come to grips with a huge set by looking at some of its (hopefully) representative elements. The project has all the well-documented and well-understood intrinsic inadequacy of operational reasoning as built-in feature.

*               *
*

Is it really true that computing science has hardly anything to offer to the computer industry? I shared my exposure to this project with a colleague, and we both saw instantaneously that this project would fail. Only God knows how many millions of dollars computing science could save for them.

Such exposures are always very embarrassing, for how does one explain politely and without hurting how utterly foolish the project is? I always want to know where people undertaking such projects have been educated as the answer could enable me to strike one or more Universities from my list. But I have become very hesitant to ask that question, for too often the people had not been educated at all. The exposure left my colleague wondering whether such people really believe that such projects make sense. He found it hard to imagine and began to assume that only during office hours did they think and communicate in the slogan-ridden Doublespeak we heard, because everybody does it and they have been made to believe that it is part of the job. There seems no way out: they only have the choice between incompetence and dishonesty. It is terrible.

But, please don't blame us when the computer industry collapses.

Austin, 21 April 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Tristram Brelstaff
revised Sat, 19 Jun 2004

EWD918

A summary of a year's impressions

(Speech at the Second Annual Spring Banquet of the University of Texas Student Chapter of The Association for Computing Machinery.)

As you have probably deduced for yourself, my title is not really fair: it is only an academic year and even that is not over yet. But shorter titles better catch the attention, so --in a good commercial tradition-- we let salesmanship prevail over honesty. (Don't forget that the Dutch have been nicknamed "the Greeks of Western Europe". This was a --not very flattering-- comment on their trading practices.)

A slightly dishonest title, however, is not out of place, for my talk will be slightly dishonest too. I shall put on my European hat, not because it fits me better than any other --in fact: I prefer the freedom of walking with my head uncovered-- but because I felt that that was more or less expected from me. It's for the occasion. One should avoid disappointing one's host. But part of the dishonesty of my European hat is that I shall fake some more surprise, as if I had not visited this continent dozens of times before.

Now, the rôle of the foreigner commenting on someone else's country is always a risky, as one cannot hide under the cloak of humility as when criticizing one's own country. To reduce the risk of now being expelled from your community as the embodiment of un-American activity, let me point out two things. Lest I be lynched, so to speak. Firstly, my wife and I were willing to leave our family and our country for yours, so you can hardly expect us to be completely out of sympathy with your collective endeavours; and secondly, I could say nasty things about Europe too. I could, for instance, point out that from the point of competition it does not seem to matter very much what you do: Whatever stupidity you commit, it will almost certainly be faithfully copied in Europe one or two decades later. (Off-hand I can only think of two major exceptions: the Vietnam War and, until recently, Artificial Intelligence.)

In a discussion of the two sides of the Atlantic Ocean, the use of the terminology of our National Myths combines, of course, the dangers and advantages of gross oversimplification. But, when all is said and told, I think the advantages prevail because, even if those national myths are crude caricatures, they come to contain --as we shall see in a moment-- a greater element of truth than we would perhaps like or expect. Because everybody up to a point tries to live up to his National Myth, those National Myths become self-fulfilling prophecies and to the extent that that happens we should regard ourselves as fictional characters, as figures created by literature and folklore.

What are the myths, reduced to their bare bones? The European believes he can save Civilization by Education, the American believes he can save society by Technology. The European will try to solve specific problems first and foremost by Thinking, the American by a million-dollar budget to buy Equipment with.

The amazing thing is that such mythical faiths are indestructable, no matter how overwhelming the evidence contradicting them. Did European education save civilization? I seem to remember that, in this century, Europe ignited two world wars. Did American technology save its society? By all measures, the average productivity of the American worker is now only half of that of his European counterpart. (The statistics were not clear whether Europe included Britain; probably not.) There you are, but .... the myths persists, and by persisting they shape our societies and thereby us: the average American is surrounded by more gadgetry and his education does have greater cavities.

(Of course I know that ours is a confusing county: its name is "the Netherlands", it is called "Holland" and its citizens are "Dutchmen". But we have very old links: the Dutch founded New York, the Netherlands was one of the very first foreign countries to be honoured by an American ambassador. His name was John Adams; you may have heard of him. Last December we went for Christmas to were we came from. Just before we left, my wife saw our neighbour from across the street and told him that we went for a few weeks to the Netherlands. Reaction: "Oh, how nice! Is it now summer over there?")

We are not only the victims of the myths about ourselves but also of the myths about the other side. We were coming to the Mecca of Technology, weren't we? Well, probably we should have known better, but one of our greatest surprises while settling down was the profound level of technical incompetence we found ourselves faced with. Order an ironing board at Sears; we really had to get used to it that, by the time you come to collect it, it has become a hair dryer. We would get gas heating, so our house was wired for electric heating; for the sake of humidity control we would get two compressors, so the house was wired for one; eventually I ended up giving the man who designed our airconditioning a one-hour lecture on elementary control theory. In my innocence I thought I had come here to do computing science; now I know more about airconditioning than I ever wanted to know.

Now closer to our common business, the topic that I call "computing science". The myths influence our perspective of the topic. What is it about? Is it about computers --as your name "computer science" suggests-- or is it about the control of complexity? I would like to point out that these are no idle questions. What did the NSF do in reaction to a perceived trailing behind of American computing science? To your best-known universities it gave a few million dollars each, explicitly earmarked for upgrading their computing equipment-- stuff of which they probably had already too much. When last year a delegation of a big American computer manufacturer, kindly and with the best of intentions, asked how they could support our research endeavors in Eindhoven, I could only answer "How kind of you! The best way of helping us is by not giving us equipment.".

After our arrival we learned another thing that has consequences, both for our conception of computing and for our vision of the rôle of the universities. In our naivety we were considerably disturbed by the discovery that over here the interface between supplier and customer is very different from what we were used to: under the slogan "Satisfaction guaranteed", the American supplier leaves the last stages of quality control of his products entirely to the customer. At first sight it seems very practical and economical, for if your customer turns out not to demand high quality, why bother? But I fear that the attitude is penny-wise and pound-foolish.

My modus operandi was to design what according to my standards was the very best thing I felt I could realize. My customers used to be delighted with the smoothness of the service provided by what I had offered to them. That was, of course, nice, but somehow secondary. For me it was much more important to demonstrate that the job could be done excellently and to raise the quality standards of the profession. I am now beginning to understand slowly why such developments hardly took place here.

As soon as unqualified "user satisfaction" is accepted as quality criterion, you are in danger of faulting Albert Einstein for the fact that the Theory of Relativity is too difficult for the average highschool kid. You are also in danger of discovering easier ways of achieving "user satisfaction", for instance by making your customers "feel good", something that can be achieved by propaganda instead of by the quality of your products. And this is probably what is euphemistically denoted by "the post-industrial shift from manufacturing to marketing".

I must mention a further consequence of accepting "user satisfaction" as quality criterion. It inextricably intertwines the intrinsic problems of computing science with the local problems of embedding computers in society and is thus responsible for the fact that for someone from outside American computing science is often so parochial.

It also affects the way in which the rôle of the University is seen. The Ph.D. programs have been established about a century ago in reaction to the realization that American science was nonexistent: in the nineteenth century, the whole of the USA produced precisely one brilliant scientist --Josiah Willard Gibbs-- and he was totally unknown in his own country. The absence of American science was the result of the vocational role that had been granted to the universities, and the Ph.D. programs have been erected to remedy the situation. The measure worked, but only partly. It worked in the sense that now, more than a century later, American science definitely exists. It failed in the sense that the American university is still tied to the rôle of vocational training: in this respect the Ph.D. programs did no more than increasing the number of vocations by one, viz. that of the research scientist. I knew all this, but was yet surprised by the strength of the pressure on the academic community. The pressure is strong and subtle, but somehow many people --staff and students-- feel subconsciously that one must have very strong reasons and a lot of guts for displeasing the computer industry, the DoD, or one's colleagues on the rest of the continent. This is a pity.

It is the strength of that pressure that forces me to devote a few words to the American ambivalence towards science and learning. We all now accept that "Johnny can't add", but save the situation by knowing that "Johnny has a way with machines". The myth has to reconcile American technology with the "farm boy", uncorrupted by the fruits of learning and still in the American Garden of Eden. Reconciling the incompatible is a main function of myths, thus so far, so good.

But in order that you may see how much harm the myth can do, I now ask you to look at the following three facts in combination.

With a strong sense of economic responsibility, the American University sees and acknowledges the task of training the manpower and developing the knowledge, technology, and methods industry needs. For a CS department, these are the needs of the computer industry.

The University is very fortunate because today it is the high-technology industry it has to cater for. And since high technology is unthinkable without vigorous underlying science, the academic world now can --and hence must-- combine its scientific and its economic obligations. For the Department of Computer Sciences in particular it is Heaven, for the computer industry is a high-technology industry if there ever was one. (For many people, "high-tech" is almost synonymous with "computers.)

In the computer industry, driven by the slogans of its own invention, the correlation between the quality of a product and its position in the market is negligible, if not negative. The practice of the computer industry is all but unaffected by computing science's achievements, and the management of it, operating under traditions that predate the high-technology industry, does all its best to deny that they are in the high-technology business. They would, indeed, be shocked out of their wits, were they to discover that their leading technology is a highly mathematical one. Much safer to stick to good-old American common sense.

So there we are. The industry we feel called to serve is very sick, if not mortally ill. It has acknowledged that tuberculosis cannot be cured by ordinary asperine, but the only cure it accepts is aspirine repackaged for "round-the-clock relief". (And stomach-friendly!) We are faced with the dilemma of a grave discrepancy between what society asks and what society needs. I think the University has no choice: it has to go its own way until society comes to its senses. So much for our industrial relations.

Finally two remarks, one about universities in general and one about UT in particular.

I knew that I would enter an environment in which the distinction between the scientist and the salesman is dangerously thin and in which the Publish-or-Perish syndrome is so strong that Carl Friedrich Gauss would have been denied tenure. I was, however, unprepared for the discovery that one of the considerations for giving tenure is the candidate's "visibility"; I had not realized that the morals of the bestseller society had pervaded the academic community to such an extent. Similarly I was totally unprepared to see offered, as a service from UT to its students, a short course on "How to market your Ph.D." I was, in fact, shocked.

The last remark is about UT, in particular on the popular response to the question whether foreign students should pay higher tuition fees than residents; 85% of the people asked thought that appropriate. My sad conclusion was that 85% of those people had very little understanding of the conditions under which the academic enterprise can flourish. The academic world is essentially cosmopolitan, everywhere. If it stops being that, it unavoidably loses its strength and universities degenerate into local parochial schools. The Dutchman Erasmus was equally at home in Cambridge, Leuven, Paris, and Switzerland, and that familiarity was essential in opening up the closed outlook of the Middle Ages. The phenomenon of "Der Wanderstudent" has been essential in the building of the academic tradition. Foreign students are a crucial ingredient of academic life; so is a not necessarily foreign but at least cosmopolitan staff.

The topic is compounded by the circumstance that it is not clear yet whether the American system of higher education is self-supporting. The last time I checked it at one of your institutes of scientific excellence I discovered that of its faculty no less than 40% had been (mainly or entirely) educated outside the USA, and by international standards that figure is a bit high. We should remember that if the USA is not yet scientifically self-supporting, the symptoms of that shortcoming have been suppressed. The suppression is one of the things we could blame Hitler for, providing you, as he did, with a strong influx of well-trained intellect.

My firm hope is that, one of these centuries, US scientific life will become vigorous enough to sustain itself. But it can only do so in the recognition that scientists are intrinsically citizens of the world, because Science belongs to all and needs all.

Austin, 19 April 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750
United States of America

Transcribed by Michael Lugo

Last revised Sat, 29 May 2004.

EWD920

Can computing science save the computer industry?

Yeah, can computing science save the computer industry? Very good question. It has at least the virtue of being controversial. Departments of computing science all over the world work (and are funded) under the tacit assumption that the answer is of course affirmative. (In fact, the assumption is so tacit in those circles that the question is never raised there.) The computer industry, however, operates under the equally tacit assumption that —thank the Lord!— computing science has nothing to contribute to its business, which —as everyone knows— is primarily a matter of marketing, of timely inventing the proper slogan in name of which the next castle-in-the-air can be presented as solid real-estate.

As long as things seemed to work out quite well, no one was eager to raise the question. But things have changed. The industry is in grave trouble, because development and maintenance costs are soaring and the public at large is getting disillusioned with its products. The university departments are in trouble too: the computing boom has decreased their staff and increased their teaching load, and as far as computing science is concerned, most faculty members have no time for it anymore and most students are no longer interested in it. So let us pose the question.

*                      *
*

To begin with a number of observations that should be taken into consideration.

(A)    The core of the challenge that computing science has accepted is how not to get confused by complexities of our making. In passing we note that in those areas in which computing science has attacked this problem explicitly (e.g. the development of programs) it has been noticeably successful.

(B)    I am waiting for the stage —if it has not been reached yet— that all sorts of products of the computer industry —e.g. microprocessors— are (in some sense) cheaper than their documentation; giving a concise and complete functional specification —traditionally produced months, if not years, after the fact, if at all— is regarded as a major (if not impossible) task. In short, even in stand-alone products the computing industry has not been able to keep its products sufficiently clean and simple.

(C)    A major source of complexity is provided by the so-called "de facto standards", be it programming languages (Fortran, PL/I, Cobol, Ada), data base systems, or communication protocols. Wherever computing science has made significant progress —e.g. programming— ignoring those de facto standards has each been a necessary condition. The de facto standards are, indeed, so terrible —all of them!— that if the computer industry persists in adhering to them —for the so-called "sound commercial reasons"— computing science will be unable to save it.

(D)    The computer industry's way of speaking about its customers is very condescending: the user —sometimes strengthened as "the end user"— is treated as a moron —e.g. "making our systems so user-friendly that even housewives can use them"—. It even talks in derogatory terms about its own employees. In fact, their postulated lack of education or their education resistance, their postulated inability to write clearly and concisely, etc. are often used by management as a pretext for not trying to do a better job. As long as that pretext is used, computing science will be unable to save the computer industry.

Aside    Having your designs made by illiterate engineers and then descibed by technical writers, is an unworkable division of labour: the designer thus misses the feedback he needs. The lesson learned from programming language design —a lesson grossly ignored in the Ada development process!— is that precise definition as a design principle acts as an indispensable early-warning system for complexity inadvertently creeping in. (End of Aside.)

(E)    The industry's propensity to look for better "tools" is a reflection of the condescending style mentioned under (D). It is a reflection of the management philosophy that, for the sake of continuity and invulnerability, organizations should rely as little as possible on the specific abilities of individual employees. We should not forget that this management tradition is significantly older than the high-technology computer industry and, hence, could now very well be profoundly inadequate. As long as managers regard program development as a production process —and they do!— and express "programmer productivity" in terms of "number of lines of code produced per day" —and they do!— their mental categories are indeed inadequate. At my lectures for programmers on programming, all over the world the overwhelming reaction has been "What a pity our manager is not here!". My conclusion is that if the computer industry is unable to refresh —by education or by replacement— its by-and-large technically incompetent management, computing science will not be able to save the computer industry.

Some of my readers may think the conditions mentioned under (C), (D), and (E) so "unrealistic" that they have already concluded that computing science cannot save the computing industry. Those readers don't need to read any further. The following is written under the assumption that one day the computer industry will be wise or desperate enough to see that drastic improvement without drastic change is unrealistic.

(F)    We continue our explorations. The prime paradigma of the pragmatic designer is known as "poor man's induction", i.e. he believes in his design as long as "it works", i.e. until faced with evidence to the contrary. (He will then "fix the design".) The scientific designer, however, believes in his design because he understands why it will work under all circumstances. The transition from pragmatic to scientific design would indeed be a drastic change within the computer industry.

(G)    Conversely, without the transition from pragmatic to scientific design, the industry's intellectual resources will continue to be usurped by "maintenance" of systems that should never have been designed the way they are in the first place.

(H)    Combining (F) and (G), we see a prime responsibility for (industrial) computing science research: making the transition from pragmatic to scientific design technically possible. I call this "a prime responsibility" in the sense —see (G)— that this goal is so crucial that, if not attainable, we must conclude as yet that, regrettably, computing science is unable to save the computing industry.

(I)    The prime responsibility revealed under (H) is a mathematical challenge, of a scope radically different from the mathematical challenges accepted so far. The currently prevailing mathematical traditions, rooted in the last centuries, are, though time-honoured, no longer adequate and we now have to learn how to reason an order of magnitude more effectively than we are used to do. This conclusion should turn "mathematical methodology" into a prime issue for computing science research (and should convince the industry that mathematical elegance is not a dispensable luxury but the decisive factor between technical success and technical failure of its products).

(J)    There are several reasons to believe that research in mathematic methodology is a highly rewarding exercise. Firstly, it has been a neglected topic: it is no accident that the COD defines mathematics in 1976 as "abstract science of space, number, and quantity" rather than as "the art and science of effective reasoning". Secondly, the calling of logic —"Philosophy's Handmaiden"— has traditionally been the codification of how people think —more accurately: how people should think if they don't make mistakes—; despite the emergence of mathematical logic, the use of logical formalisms with the intent of freeing us from the shackles of our natural languages is still in its infancy. Thirdly, if there is an analogy between programming and doing mathematics —and I think that analogy is profound—, it is reasonable to hope that research on mathematical methodology will be as rewarding as research on programming methodology has been. (It could be argued that mathematics today is as much paralyzed by the concept of "the average mathematician" as programming has been by that of "the average programmer".)

(K)    For purely technical reasons it is to be expected that more and more mathematical reasoning will be in terms of formal calculations, i.e. in the form of symbol manipulations applied to uninterpreted formulae. This will take place in the name of effectiveness, independent of the circumstance that the formal calculations should become amenable to mechanical verification. Such tools should only be defended by an appeal to greater security and not by the (vain) hope of being able to cope with greater complexity. Computing scientists should be aware of the fact that tools have the unfortunate tendency to backfire. (Easing the correction of errors immediately leads to more errors being made.) Seeing how CAD for chips has deteriorated into the mechanical production of larger and larger multi-coloured posters, I doubt that the industry will exercise the proper restraint once it has recognized the possibility and potential of mechanical verification. But warnings, no matter how likely to remain unheeded, can never harm.

*                      *
*

Back to our original question: can computer science save the computer industry? My answer is "If the computer industry can be saved, only computing science can do it.". But it may take a long time before the computer industry —in particular the well-established companies— will share this view. It will almost certainly take longer than the limited period over which they plan their futures. In the mean time, the academic world —which traditionally plans much further ahead— has no choice. It has to refine and to teach to the best of its abilities how computing should be done; would it ever yield to the pressure to propagate the malpractice of today, it had better fold up.

Nobody needs to point out to me that the unescapable duty to train misfits creates its problems: it does so for the University, for its faculty, and for its students. But no one ever heard me suggest that doing science was a soft proposition. But, the more misfits we train, the shorter the time of transition. And this is a point of consideration: if the current malpractice continues too long, the computer industry will collapse and it is hard to save an industry that is no longer there.

Austin, 1 May 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Israel Fimbres
revised 16-Jun-2012

EWD921

A correction of EWD914–15

Formula (20) on EWD914–15 should be replaced by

(20)    [P ≡> (¬B ∨ wp(S,Q) ≡ Q)]

On EWD914–17, line 11

"⇒ {(20)}" should be replaced by "= {(20)}"

Peccavi!

Austin 30 April 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Joseph Carless
revised 11-Nov-2014

EWD 923

Trip report E.W.Dijkstra, Ithaca, Newport, 30 May - 13 June 1985

"If fundamentalism continues to spread at this pace, it will be very dangerous in the near future. [...] These people are fanatics. They've been brainwashed. You can't change them, so the government must stand up to them."

Jihan Sadat (as quoted in the International Herald Tribune, Friday, June 14, 1985).

Actually we left Austin only on Thursday 31 May, but we left our house on Wednesday, after having spent most of that day on preparing the house for our absence (Ria using the vacuum cleaner and similar tools, I the poison spray). Joanne Richards had invited us for dinner, Ham then gave us a ride to the Hilton Hotel where we spent our last (short) Austin night. Our flight left the next morning at 7:15. We were three, as Wim Feijen travelled with us. For ten days he had stayed with us at Robbie Creek Cove, in the weeks to come he would join me in giving what was officially called the "North American Summer School on Program Construction". This school was the main reason for Wim's visit to the USA; accordingly we did some preparation in Austin, but Wim also gave a very nice lecture at UT.

With an intermediate stop in San Antonio we flew to Pittsburgh, where we had ample time to change planes. From there with an intermediate stop in Elmira to Ithaca, where David Gries met us at the airport. Tony and Jill Hoare arrived 45 minutes later and in two cars we drove off to David's house, David in his own car and I in the Dodge Ariel that David had just rented, with me as second driver. For us it was very nice to meet Tony, Jill, and, a little bit later, Elaine Gries again. All hotels being full because of commencement —that Sunday— the five of us were spread over the Hotels Gries and Hartmanis, Ria and I stayed in the latter.

That evening we had dinner with a delegation of the Department of Cornell University, consisting of David Gries, Juris Hartmanis, and Bob Constable, and their wives. The company was pleasant, the food surprisingly edible and —thanks to a little nap?— Tony and Jill managed to stay awake. In order to make life for them not more difficult than it already was, we broke up shortly after dinner and Juris took Ria and me to his home. (Elly Hartmanis drove her own car.) Soon after our arrival, Elly, who had had a long day and had a long day ahead of her, went to bed. If I remember correctly, Juris and I stayed up late, half-way being deserted by Ria, who went to bed as well. I learnt a lot about the Cornell department, past and present.

On Friday, Elaine took care of Jill and Ria —they visited Elly's business— while David, Tony, Wim, and I "prepared" the Summer School the four of us were supposed to give at Newport. It was clear from the start that —like in Perisher Valley— Tony would do his thing, the rest had to be partitioned, and so we did. David would also do the language constructs, I the calculus, and Wim would join by the time we would reach the stage of examples and exercises. This division of labour implied that I would get the flak I expected from earlier correspondence with one of the participants —a certain Walter E. Tuvell— , who seemed greatly disturbed that I did not adhere to the foundations of mathematics as set forth by N.Bourbaki.

The Department of Computer Science at Cornell University had the nice habit of jointly drinking coffee after lunch, a ritual of which I have fond memories. We joined it. After a discussion on the current funding policy of mathematical research the conversation turned to the future of computing science. Juris directed the conversation in that direction so that we would be confronted with John Hopcroft's views on that matter (or John with our reactions to his views). Hopcroft's view seemed to be that computing science was all but completed and that the department should or would work for 90% in "applications". The view of completion is easily defended by identifying the topic's subject matter with its past achievements; the 90% is easily defended —in general!— by the cynical remark that most people are dull, computer scientists not excepted, and hence should not do science at all. But I prefer a broader scope of the subject, as that is more inspiring. John's position struck me primarily as a rationalization of the current stage of his own scientific career. He found little support for his views.

Early in the afternoon Tony gave us a talk to which —despite the short notice of 45 minutes— an audience of about 50 people attended. It was a very nice talk (and some of the questions during the discussion were very silly). Then there were informal refreshments —that day at Cornell I got completely decaffeinated— so that the students could meet us. (I had not realized that, since my previous visit, the student population at Cornell had been completely refreshed.)

That evening Ed Cohen, the organizer of the Newport Summer School, took us out for dinner at l'Auberge. Again the company was pleasant, the food was edible. Ed asked me whether I was aware of the fact that one of the participants was out for trouble: I answered that I was not surprised and told him not to worry.

Saturday morning we spent at the Grieses. Wim and David worked together on examples, Tony prepared more foils and I just thought. In the afternoon we all went to David's second house at the lake, where we were joined by several people of the Department: the Constables, Fred Schneider and Jan Prins. There was food for us all.

On Sunday we drove with two cars to Syracuse —Paul Gries joined us on that trip to return the Gries car to Ithaca— and flew to Boston (in an F28!) where we rented a huge stationwaggon in which the six of us (plus our luggage) went to Newport.

We were housed in "The Wayside Inn", a former mansion that had also been used as girls dormitory. A very strange place! The beds were okay, the plumbing was old-fashioned, the furniture was horrendous (and uncomfortable). It was run by a couple that provided minimal service. But —to my surprise, I must admit— one evening we noticed that the heating had been turned on! During the daytime the place was often unattended with the result that I was difficult to reach —UT tried it— .

The next morning the Summer School started. Prior to that, Tuvell already started his campaign: during the night he had made a tour of the dormitory and shoved a document under the doors of the participants rooms! During my lectures he was so obnoxious that after a while the participants booed him away. Then he wanted to distribute copies of our correspondence; after I had refused permission to copy my letter to him, he distributed copies of my letter nevertheless. Whatever ax he had to grind was lost in his bad manners.

Juris Reinfelds of the University of Wollongong, who had organized the summer school in Perisher Valley, after which this one was modelled, was one of the participants, and, hence, one of the people who could compare the two. He told us he was impressed —and also a bit alarmed— by the progress Tony, David, and I had made. It is difficult to judge one's own performances, but as far as Tony and David were concerned I could only agree. Tony was now clearly in the stage "after completion of his book", and David's way of presenting algorithms had significantly improved. (David himself gave the credit to Wim Feijen with whom he had discussed most of his examples.) Wim gave a number of model presentations, among which the inversion of the circular permutation, and the Boyer/Moore majority vote. The audience had never seen expos�s like that, liked them very much and was greatly impressed. Tony's lectures were very smooth —even dangerously so— and this time he had the satisfaction that people tried his exercises. But we all noticed the dangers of anthropomorphic terminology which, as the course went on, began to create confusion.

This time we had a very different audience: in Perisher Valley, participants from industry had been a marked minority, in Newport about 70% was from industry and, as a result, the audience was much more mixed. My impression was that this time we had to bridge a much wider gap. (Tony disagreed: in his memory the gap in Australia had been very wide too.) A number of the people were quite bright, but on the whole I found them alarmingly ignorant and uneducated. (What to think of a factory automation system of several hundred machines, big and small, of which after installation the designers learn the hard way of the phenomenon of after-you-after-you blocking? This is 1985! The danger was mentioned and circumvented in a well-known paper in the Comm. ACM of 1965.) I am afraid that we cannot escape the conclusion that for the "high-tech industry" the USA is aiming for, the infrastructure is still lacking.

On the way home I lost a suitcase. And now my back is aching, something I have not suffered from for years. I blame the Newport furniture. But we don't complain: here is the compensation of fresh white asparagus and jambon d'Ardennes!

Nuenen, 16 June 1985

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

PS d.d. 17 June 1985. I checked it today, and, contrary to W.E. Tuvell's emphatic statement, "well-foundedness" and "well-orderedness" are different concepts.     EWD.

Supplement EWD923

NASSPC Summer Camp Song - to the tune of "Old Macdonald",
Inspired by David Gries' spelling of Wim Feijen's name.

Dedicated in gratitude and appreciation
to the distinguished faculty and hard-working staff

Old Wim Feijen had a proof, -E-I-J-E-N,
And strange notations he did use, -E-I-J-E-N.
With an "equivales" here and a quantifier there,
Universal! Existential! ( Everywhere a bracket, bracket! )
Old Wim Feijen had a proof, -E-I-J-E-N.

( Edsger ) W. Dijkstra had a set, T-E-X-A-S
It was well-founded, you can bet! T-E-X-A-S
With inductions here and deductions there,
Formalisms! Witticisms! ( NEVER anthropomorphisms! )
( Edsger ) W. Dijkstra had a set, T-E-X-A-S.

Tony Hoare had brought events, D. F. B. C. S.
But wouldn't tell which way they "went", D. F. B. C. S.
With a coloured foil here and a " Query? Shreik! " there,
Chocolates! Customers! ( Not a trace of accent! )
Tony Hoare had brought events, D. F. B. C. S.

David Gries put out our eyes, P-L-A-I-D.
By showing up in "op art" ties, P-L-A-I-D.
With a proof rule here and a "dawt, dawt" there,
Volleyball! Ping-pong! ( All the time, his hands were waving! )
David Gries put out our eyes, P-L-A-I-D.

Poor Ed Cohen had the job, T-H-A-N-X!
To house and feed the swelling mob, T-H-A-N-X!
With a light bulb here and a soap bar there,
Coffee-finding! Door-unlocking ( Aleph-null of photocopies! )
But, Ed Cohen did his job, T-H-A-N-X!

Joel Neely
Newport,
11 June 1985

transcribed by Corrado Cantelmi
revised 29-Sep-2011

   EWD 923A

Where is Russell's paradox?

Why is "Russell's Paradox" called a paradox? It is supposed to be rendered by the example of the village with cleanshaven men in which the village barber is defined as the man such that the population he shaves is the population of villagers that don't shave themselves. And then comes the question "Who shaves the barber?".

But where is the paradox? If we define in a certain context x to be equal to 3, we define x to satisfy x=3, i.e. to be a root of the equation y : (y=3). For quite some time now, roots of equations seems to me the paradigm par excellence for definitions. How else to define √2 than as the root of y : (y²=2 ∧ y≥0)? After the invention of the reals that equation has indeed one root. Did we only know the rationals, the equation would have no root and √2 "would not exist".

For the barber of the village we have the equation

y : (Ai : i  is a villager :  i ≠ shaver.i  ≡  y = shaver.i )

and that equation has no solution. Conclusion: the village has no barber. Where is the paradox?

Probably I am very naive, but I also think I prefer to remain so, at least for the time being and perhaps for the rest of my life.

Austin, 22 May, 1985

prof.dr. Edsger W. Dijkstra
Department of Computer Science
The University of Texas at Austin
AUSTIN, TX 78712-1188
USA

transcribed by Apurva Mehta
revised Thu, 11 Nov 2004

EWD 924

Copyright Notice

The following manuscript

EWD 924: On a cultural gap

is held in copyright by Springer-Verlag New York, who have granted permission to reproduce it here.

The manuscript was published as

The Mathematical Intelligencer 8 (1986), 1: 48–52.

On a cultural gap

On the typical University campus, the typical mathematician and the typical computing scientist live in different worlds: they don't know each other or, if they do, they are not on speaking terms. The purpose of this essay is two-fold, viz., to give a historical explanation of this phenomenon and to argue that we should do something about it.

Exhorting the world to mend its ways is always a tricky business, for implicit in the exhortation is always the verdict that the world's ways leave plenty of room for improvement, a suggestion that is always offensive to the touchy. One way of gilding the pill is to qualify one's sentences by all sorts of softeners such as "typical", "in general", "on the average", "usually", "not uncommonly", etc.. For brevity's sake I shall not do so.

At the heart of my historical explanation lies the thesis that when, now four decades ago, the electronic computer was sprung on us, we were not ready for it and that —people and computers being what they are— widespread confusion was unavoidable.

By far the most common way in which we deal with something new is by trying to relate the novelty to what is familiar from past experience: we think in terms of analogies and metaphors. (Even the 5th Edition of the Concise Oxford Dictionary still defines a typewriter as a "machine for printing characters on paper as substitute for handwriting"!) As long as history evolves along smooth lines, we get away with that technique, but that technique breaks down whenever we are suddenly faced with something so radically different from what we have experienced before that all analogies, being intrinsically too shallow, are more confusing than helpful.

The only feasible way of coming to grips with really radical novelty is orthogonal to the common way of understanding: it consists in consciously trying not to relate the phenomenon to what is familiar from one's accidental past, but to approach it with a blank mind and to appreciate it for its internal structure. The latter way of understanding is far less popular than the former one as it requires hard thinking (and, as Bertrand Russell has pointed out, "Many people would sooner die than think. In fact they do."). It is beyond the abilities of those —and they form the majority— for whom continuous evolution is the only paradigm of history: unable to cope with discontinuity, they cannot see it and will deny it when faced with it.

But such radical novelties are precisely the things technology can confront us with. The automatic computer was one of then; from the same era, the atom bomb and —perhaps to a lesser extent— the pill were two others.

*                 *
*

To make matters worse, a few accidents of history increased during the first two decades the confusion as to what automatic computing was about still further.

When, for instance, computers became available as industrial products, it was a commercial imperative for the budding computer industry to dissociate its products as far as possible from any form of mathematics, the latter being viewed as the pinnacle of "user-unfriendliness". Its sales force accordingly brainwashed the public, including computing scientists, mathematicians, politicians, and managers. (The computer industry even brainwashed its own management, which to this very day, even if willing to admit that they find themselves in the "high-tech" business, would be horrified to learn that its leading technology is a very mathematical one.)

A confusion of even longer standing came from the fact that the unprepared included the electronic engineers that were supposed to design, build, and maintain the machines. The job was actually beyond the electronic technology of the day, and, as a result, the question of how to get and keep the physical equipment more or less in working condition became in the early days the all-overriding concern. As a result, the topic became —primarily in the USA— prematurely known as "computer science" —which, actually is like referring to surgery as "knife science"— and it was firmly implanted in people's minds that computing science is about machines and their peripheral equipment. Quod non.

We now know that electronic technology has no more to contribute to computing than the physical equipment. We now know that programmable computer is no more and no less than an extremely handy device for realizing any conceivable mechanism without changing a single wire, and that the core challenge for computing science is hence a conceptual one, viz., what (abstract) mechanisms we can conceive without getting lost in the complexities of our own making.

Remark The above terse summary of computing science's core challenge calls for a slight elaboration. I have tried it out at a number of occasions. Computing colleagues that know only too well from their own experience what I am talking about react with "That's aptly put." or a similar form of agreement. But I have also learned that, no matter how apt, it conveys little to those who have never seen the kind of complexity I am referring to. Let me, therefore, try to sketch its nature.

Blocks are made of buildings, buildings of walls, walls of bricks, bricks of crystals, etc., if you so desire down to the elementary particles constituting the nuclei. That is, we view the whole as composed of parts, which are in some sense "smaller" than the whole, and then apply the process recursively to the parts. We thus arrive at a hierarchical decomposition, the depth of which is some sort of logarithm of the ratio between the "sizes" of the whole and of the ultimate parts. But the ratio between an hour (for the whole computation) and several hundred nanoseconds (for an individual instruction) is 10¹⁰, a ratio that nowhere else has to be bridged by a single science, discipline, or technology. Compared with the depth of the hierarchy of concepts that are manipulated in programming, traditional mathematics is almost a flat game, mostly played on a few semantic levels, which, moreover, are thoroughly familiar. The great depth of the conceptual hierarchy —in itself a direct consequence of the unprecedented power of the equipment— is one of the reasons why I consider the advent of computers as a sharp discontinuity in our intellectual history. (End of Remark.)

Computers being a radical novelty, it is not amazing that we were not ready for them. The mathematicians, however, were more than unready.

Mathematicians have the social disadvantage of living in an introverted world with very much its own values and its own standards for judging merit and significance, a world which is fertile ground for inbreeding. And that is exactly what happened. The well-known definition of geometry (viz., "what the geometricians do") can safely be generalized to their conception of mathematics: as none of them had been thinking about automatic computing, automatic computing couldn't be mathematics.

As a subculture, they are not only narrow-minded, they are also very conservative. They know this themselves, but feel that, as heirs and custodians of an impressive tradition, they have indeed a lot to conserve. We all grant them that, but I suspect there is another mechanism at work. Mathematics differs from the other sciences in that the vast majority of its practitioners —including most of the outstanding ones— are heavily engaged in teaching. Teachers regard the effort spent on instilling habits as their investment and shudder at the thought of having to undo it. Consequently, they equate without hesitation "convenient" with "conventional" and, if it had not been for others, we would still be doing arithmetic in Roman numerals, because that was "easier" since people were used to it.

The mathematician had a technical disadvantage as well, his professional values and prejudices having their roots in the late 19th, early 20th century. He was full of analysis, loved the continuum and the complex plane, and considered infinity as a prerequisite for mathematical depth. How in the world could computing have anything to do with him? If he acknowledged the existence of computers at all, he viewed them as number crunchers, of possible use as a tool for his colleague in numerical analysis —if he had one—. (For numerical analysis, of which he knew very little, he had at best a mild contempt.) The long and the short of it is that he disregarded computing completely, strengthened in that attitude when he noticed that machines were primarily used for business administration, which was a trivial pursuit anyhow.

Part of the blame should be put on the early scientists that got involved in computing. They came —of necessity— from other disciplines: they had mostly been trained as physicist, chemist, or crystallographer (with an occasional astronomer and meteorologist). They were the computer users of the first hour, but regrettably the vast majority of them did not transfer their scientific quality standards to the programming that became their major occupation: as soon as programming is concerned, otherwise respectable scientists suddenly accept to live by the laws of the mathematical jungle. A generation of "scientific" machine users has approached the programming task more as solving a puzzle posed by the machine's manufacturer than as an activity worthy of the techniques of scientific thought. Their logical catch-as-catch-can must have been repulsive to the orderly mind that the mathematician rightly or wrongly regards as his specialty.

Part of the blame for the poor image of computing should also be put on the early Departments of Computer Science, as they were called. They were not very illuminating for the rest of the world as they were very uncertain themselves about the true nature of their calling. Usually these departments were little more than ill-considered cocktails of locally available disciplines (and semi-disciplines) that had some connection with automatic computing: electronic engineering, communication and switching theory, business administration, numerical analysis, numerical control, library science, artificial intelligence and the like, in short, such an incoherent bunch of disciplines that the resulting cocktail hardly appealed to the intellectually discerning palate. These premature departments were concerned with construction of the various possible application areas of computers; their problem was that, to begin with, they had to operate in the periphery of the science that was yet to emerge.

This discipline, which became known as Computing Science, emerged only when people started to look for what be common to the use of any computer in any application. By this abstraction, computing science immediately and clearly divorced itself from electronic engineering: the computing scientist could not care less about the specific technology that might be used to realize machines, be it electronics, optics, pneumatics, or magic. At the same stroke, computing science separated itself from all the specific problems of embedding computers meaningfully in some segment of some society —concerns that, societies being as different as they are, are almost unavoidably parochial—.

Let me mention —without any claim to completeness— some of the highlights that were to shape computing science as it emerged.

In 1960, trans-Atlantic cooperation resulted in the design of a new programming language ALGOL 60. As a vehicle for program design it was a great improvement over its existing competitor FORTRAN and it was immediately accepted as a standard where the latter was not already entrenched. Much more important than the programming language itself, however, was the way in which ALGOL 60 had been defined. The formalism that became known as "Backus-Naur-Form" (or BNF for short) and was used for a complete recursive definition of ALGOL 60's context-free syntax embodied a quantum leap in the rigour of language definition. From that moment, formal grammars were a corner-stone of computing science.

Then LISP emerged as programming vehicle for symbol manipulation. LISP can be viewed as a highly successful exercise in the mechanization of applied logic. For computing science, its cultural significance is that it liberated computing from the narrow connotations of number crunching by including all formal processes —from symbolic differentiation and integration to formal theorem proving— as computational activities.

In the mid-sixties, computing's scope was once more extended with a new dimension, when we learned how to program nondeterministic machines. The origin of the problem came from the task of designing "operating systems" that would enable the central processor to cooperate with a possibly large number of coupled but otherwise unsynchronized activities, communication with which would occur at unpredictable moments. The problem was of a humble, technical origin, but it was of great significance for computing's culture. The moments of communication between central processor and peripherals were not only unpredictable, but consequently also irreproducible, and as a result the experimental approach to programming was obviously no longer tenable.

It was at this stage that the distinction between pragmatic programming and scientific design began to appear in the world of programming. What is now known as "iterative design" is the paradigm for the pragmatist, who believes that his design will work properly unless faced with evidence to the contrary, upon which he will seek to improve his design. Among programmers, this finding and fixing of malfunctionings is known as "debugging" and the (unjustified) faith in its ultimate convergence was at the time widespread. As a result, the inability of repeating the experiment in the case of an observed malfunctioning (so as to identify its cause) came as a shock. The scientific designer, in contrast to the pragmatist, believes in his design because he knows why it will work properly under all circumstances.

Thus the ground was prepared for what happened in the late sixties and early seventies, when firm foundations were laid for reasoning about algorithms. It has changed the relation between programs and machines: was it formerly the task of the programs to instruct our machines, now it became the task of the machines to execute our programs. It has also changed the status of programs: had they formerly the status of conjectures supported by some experimental evidence, now they could (and sometimes did) attain the status of rigorously proved theorems. (Formerly, books on programming used to be recommended by the author's assertion in the preface that all the programs in his book had been tested on a computer. In the mid-seventies, the first book appeared that was recommended by the author's assertion that he had tested none of the programs in his book.) The fact that we continue to use the same term "program" for both the conjecture and the theorem is regrettable, for it is the source of much confusion.

Computing's last decade is sometimes called the decade of modularity, but that covers only part of the story. With aforementioned firm foundations for reasoning about algorithms we were in principle on familiar mathematical grounds, but only in principle: any ambitious sophisticated program, such as, say, a high-quality compiler, becomes daunting when viewed as a mathematical object. It is huge, in its design many, sometimes conflicting, goals have been pursued, and its final justification often requires many a subtle argument. Some form of "divide-and-conquer" is clearly indicated. But it is not a fixed amount of work that has to be partitioned: an unfortunate choice of parts can greatly increase the amount of work at both sides of their boundary! The original impulse for modularity came from a desire for flexibility, in particular how to subdivide a sizeable program text into "modules", i.e. clearly confined text segments that could be replaced by an alternative without compromising the correctness of the whole program, in very much the same way as we can replace in a mathematical theory the proof of one of its theorems without affecting the theory as a whole. But the emphasis has shifted from such mere replaceability to the question of how to break down the whole task most effectively: the demands are such that elegance is no longer a dispensable luxury, but decides between success and failure.

So much for a bird's eye view of the emergence of computing as an activity worthy and in need of the techniques of scientific thought. As mathematics is unique in the way in which it combines generality, precision, and trustworthiness, it is not surprising that computing science emerged as a discipline of a distinctly mathematical flavour.

*                       *
*

Like all transitions from craft to science, also this one caused tension and anxiety, and was not universally welcomed. Computing's craftsmen felt threatened by it and it has been bitterly resented by many a department of mathematics that had formerly assumed that computing would never distract or divert its best students. But even without that element of competition, some feeling of uneasiness among the mathematicians is understandable, for computing science, the topic they have ignored so completely, might have a profound influence on mathematics in general. It is indeed expected to do so, and to understand why this expectation is held, we should consider the following.

All through the ages, the spectrum of educational practice has known two extremes. At the one end we have the guilds, in which knowledge is kept as a well-guarded secret, and for that reason is never formulated explicitly; the apprentice joins a master for seven meagre years and absorbs the craft by osmosis, so to speak. At the other end we have the university, where the students listen to the professor, who tries to formulate his knowledge and the key elements of his abilities as explicitly as possible, thus bringing it all out in the public domain. Along this scale, mathematics occupies a curious, double position. While mathematical results are published and taught quite openly —to the extent that many mathematical curricula are very much "knowledge-oriented"—, how to do mathematics is hardly taught explicitly. Mathematical methodology is not a topic of explicit concern and, as we shall see in a moment, when mathematicians feel threatened, they do so in their capacity of members of their guild. In passing we note that it is not so much that they are unwilling to teach how to do mathematics, but that they are unable to teach it, not knowing how they do it themselves.

Along comes computing science as a mathematical discipline, but in a few important aspects very different from the average one. Firstly it is much less know1edge-oriented; this is probably a consequence of the fact that, while knowledge is always about a specific area, the computer truly deserves the epitheton "general-purpose". Secondly, formal logic, and formal techniques in general, play a much more important role; this is (i) because formal techniques are indispensable to control the type of complexity a programmer has to deal with, (ii) because, by virtue of its mechanical interpretability, any programming language represents a formal system of some sort, and (iii) because symbol manipulation as mechanical processing of uninterpreted formulae comes very natural to the computing scientist. Thirdly, it is a discipline in which methodological questions are a central, explicit concern. The latter two characteristics are, of course, closely related: in a formal argument —whether mechanized or not— the structure of the argument is given so explicitly that you cannot avoid seeing it. Or, to put it in another way, the reason why today's average mathematician does not know how he does mathematics and hence is unable to teach how to do it, is because he relies so heavily on informal arguments: informality is the hallmark of the mathematical guild member.

In the relation between mathematics and computing science, the latter has been for many years at the receiving end, and I have often asked myself if, when, and how computing would ever be able to repay its debt. And slowly, the picture of the answer emerged.

The liberation of logic from the philosophical obligation of mimicking how people are wont to reason has opened the way for the design of effective calculi, thereby greatly extending the range of applicability of formal techniques. Besides being of technical importance, that development is of cultural significance, as arguments made fully explicit in such neutral fashions provide the tangible subject matter of a teachable mathematical methodology: the secret craft of the guild is on the verge of being taken into the public domain.

In a remarkable instance of foresight, this was seen as early as 1967 by John McCarthy (of Stanford University) when he wrote:

"It is reasonable to hope that the relationship between computation and mathematical logic will be as fruitful in the next century as that between analysis and physics in the last. The development of this relationship demands a concern for both applications and for mathematical elegance."

The only thing to add is that now, almost two decades later, we dare to go a bit further and dare to include mathematics in general, This is because the analogy between programs and proofs is getting closer and closer. This has been seen on theoretical grounds by the logician Per Martin-Löf and made him write:

"It [= the creation of high-level languages of a sufficiently clean logical structure] has made programming an activity akin in rigour and beauty to that of proving mathematical theorems. (This analogy is actually exact in a sense that will become clear later.)"

and also

"In fact, I do not think that the search for high-level programming languages that are more and more satisfactory from a logical point of view can stop short of anything but a language in which (constructive) mathematics can be adequately expressed."

In addition and independently, the analogy between programs and proofs has been convincingly forced upon us by quite practical experiences, which go beyond existence proofs in the form of programs that construct the objects in question. Properties of possibly non-constructively defined objects have been elegantly derived from programs constructing those objects, using the standard techniques of designing and manipulating programs (e.g. showing that a function is its own inverse by manipulating a program computing it until the program is symmetric in its input and output). And, one step further, the techniques of program design have equally successfully been applied to proof design; it is in particular that last experience that strongly suggests that programming methodology and mathematical methodology are not that far apart at all.

Posing as a respectable scientist, I should abstain from crystal gazing in public, but I do see the possibility of a fascinating future in which the quality of the work of the computer scientists and of the mathematicians will be an order of magnitude better than it is now. It is a future in which we don't only agree that mathematical elegance is important but will also teach its conscious pursuit. It is a future in which we don't only agree that a good notation helps, but in which we actually teach how to design notations that are geared to the manipulative needs at hand. It is a future in which programs will display all the beauty of a crisp argument, and in which the dictionaries will no longer define mathematics as the "abstract science of space, number, and quantity" (Concise Oxford Dictionary) but as the "art and science of effective reasoning".

Austin, 13 September 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America.

The above text, for which EWD9l3 was a draft, has been written for "The Mathematical Intelligencer". I have thought about the inclusion of the Game of Stanley Gill (by way of gem):

The Game of Stanley Gill is played with four integer variables x , y , u , and v and two positive integer constants X and Y. The opening position of the game is x = X  , y = Y , u = X , and v = Y and consists in playing the following move as often as possible:

if x < y , decrease y by x and increase v by u ;
if y < x , decrease x by y and increase u by v .

The game ends with x = y , (x+y)/2 = gcd(X,Y) , and (u+v)/2 = scm(X,Y) , conclusions which follow from the fact that each move maintains:

0 < x
0 < y
gcd(x,y) = gcd(X,Y)
x·v + y·u  =  2·X·Y   .

EWD

transcribed by Churow Park
revised Tue, 6 Jul 2010

EWD925

Trip report E.W.Dijkstra, London, 25-27 June 1985

The purpose was to attend with Netty van Gasteren the two-day Science and Engineering Conference of the BP Venture Research Unit.

We left our house at 6:40 and at 7:00 Ria dropped me at what is no longer "Welschap" but is now "Eindhoven Airport". We said goodbye and Ria immediately returned home (and to bed). Netty joined me a few minutes later, and at 7:35 we were in the air. At 8:00 --local time: there is a one-hour time difference-- we "de-planed" at London, Gatwick, where a BP driver was waiting for us with the traditional battleship; 10 minutes later we were on the road. At 9:50 we checked in at the Great Eastern Hotel, while the driver waited to take us to Britannic House, where the conference started at 10:00. We were only a few minutes late.

On the first day of the conference we listened to 7 speakers, on the second day to 6, each filling a slot of 45 minutes. The first day I had to fight to keep my eyes open after lunch --audiences should not be fed-- but, otherwise, I found the conference quite enjoyable and, at the moment itself, quite instructive. Yet, seeing the program + abstracts three days later, I must confess that with several speakers I have applied the most efficient way of information processing (= "One ear in, and out the other"). I fear this is unavoidable.

The lectures were very well presented with the exception of the one given by Dr. S.G.Davies (Oxford) who had ignored the advice of the Venture Research Unit to assume an ignorant but intelligent audience. Davies repeated each remark three or four times before proceeding to the next; he was so repetitious that it was almost offensive. It was in any case ridiculous. Later Don W.Braben told me that the Davies lecture had been highly appreciated! We live in a difficult world. Was the audience less intelligent than the speakers had been told to assume? I don't think so; I think that one lecture was more like a light course at a heavy dinner.

Don W.Braben was very pleased with how the conference went, and I think rightly so. It has always been his ideal that the Venture Research Fellows would be meaningfully confronted with each other's work, and this time this seemed to happen. The discussions were lively and often included more than the closest colleagues of the speaker. And, of course, one cannot help learning all sorts of things (e.g. that control engineers are a very special brand of people).

On Tuesday evening we were offered a dinner at which the inedibility of most of the food was for me more than compensated by sitting next to Wladislaw M.Turski, who happened to be in London and had been invited by the Venture Research Unit so that we could meet. On Wednesday evening, we dined again at Fredericks Restaurant, Camden Passage, where the food was excellent. (The place had been recommended by Sharon Wylie of the VRU, who had reserved at table for Wlad, Netty and me. Eventually we were four, as we asked Dr. A.M.Paton of Aberdeen to join us; he had stolen our hearts by apologizing for the fact he was going to show some pictures.) Before the dinner Wlad and I spoke for a while alone.

The presence of Robert S.Boyer at the conference was for me a fringe benefit, as I was thinking about how to rewrite EWD905 (= Chapter 2). Over the last years my agility in using (my version of) the predicate calculus has become well-oiled, but I have no experience in its axiomatic presentation, and in a number of illuminating conversations with Bob I got a clearer picture of from what I should abstain from. I should not care about the fact that the number of natural functions on the boolean domain is countable, but the number of boolean functions on the natural domain is uncountable; I should also stay within the realm of "total" functions. And I should explain the modesty of my targets.

Thursday morning, Netty and I spent another 1½ hours at the Venture Research Unit: Don had a few things he wanted to talk about, and so had I. At 10:30, one of the battleships took us to Gatwick Airport; the first 40 minutes of that ride we inhaled the exhaust fumes of the London traffic. We arrived at Gatwick well in time. At Gatwick it was a mess. The international departure hall was overcrowded, the control of the notice boards announcing the departures broke down and when we reached the gate, loudly ringing bells gave for more than 10 minutes a false fire alarm. The NLM flight to Eindhoven was on time (but so bumpy that Netty skipped her meal, which is saying a good deal). Ria was with our rented VW Jetta at the airport, and I was on time for my 16:00 appointment at the THE.

It had been an inspiring conference. It was, alas, also very easy to see how, in contrast, a funding policy carried out by bureaucrats could easily stifle all refreshing research.

Coincidence From E.Patterson (Aberdeen) I heard the same story as I would hear the next week at the THE, viz. students (freshmen) "simplifying"

1/(a+b)        to        1/a + 1/b

In both cases my spokesmen voiced the suspicion that this "simplification" was actually being taught at secondary school. (End of coincidence.)

Nuenen, 6 June 1985

prof. dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, Texas, 78712-1188
United States of America

transcribed by Tristram Brelstaff
revised Sun, 14 Mar 2004

EWD926

A computer to think about

We all know of the possibility of starting a computer on a nonterminating repetition. This possibility is unfortunate because with the commercial equipment currently available, such a program takes an awful lot of time to execute it. I therefore propose a machine that needs 1 second for the first iteration and furthermore doubles its speed at each iteration.

Confront a mathematician with this proposal; he will immediately point out that your proposal is logically flawed: in what state will your machine be 2+ε sec. after it was started? Contradiction!

Show it to a physicist that knows his good, old Einstein; he immediately sees that, due to the finite velocity of light, one should implement the doubling of the speed by halving the size of the machine at each iteration. Then, after 2 seconds, the contradiction has disappeared, and so has your machine (but that is only fair: any computer irrevocably embarked upon a nonterminating computation is effectively lost).

Nuenen, 3 July 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

Transcribed by Michael Lugo

Last revised 25-May-2016 .

EWD927

The ATAC (= Austin Tuesday Afternoon Club)

The Tuesday Afternoon Club in Eindhoven (now to be referred to as ETAC?) was founded in 1973, when I became Burroughs Research Fellow. Being suddenly only one day per week at the THE, I felt obliged to reserve one afternoon for scientific contact. Its original purpose was twofold: to prevent our --and, in particular, my-- intellectual horizon from shrinking --for the first time in my life I would work in complete isolation for most of the time-- and to help my younger colleagues in finding out how to conduct their own research.

In name of the first goal, we sometimes spent an afternoon scanning the literature and studying what, at first sight, seemed interesting. But on the average this turned out too often to be too disappointing, and we stopped doing that. Sometimes we still studied work by others, but only on recommendation.

Tuesday Afternoons have never been prepared: the standard opening was "What shall we do?", and from the different suggestions we would choose. This format makes the happenings very unpredictable; some afternoons are exciting, some are just illuminating or useful, and some are a failure. I think this is a very good thing and I would like to keep it that way.

In my memory, we have had mainly three types of Tuesday Afternoons.

One type might perhaps be captured by "sensing directions", either of things taking place or of things to do. It could occur on a very specific challenge such as "Can we think of a dozen worthy Ph.D. topics?"; it could also occur after, say, a Marktoberdorf Summer School, when we would try to get a motivated feeling for significance/promise/wisdom of Category Theory, Temporal Logic, Event Theory or what have you. Such afternoons, as you might guess, are relatively rare and pretty exhausting. They are almost always successful.

Less rare (and also less predictable) is the afternoon that starts with tackling an unsolved problem. We never take one of the standard ones --the equivalent of Goldbach's conjecture, say-- preferring problems of our own design. A typical example is the on-the-fly garbage collection. Our reconstruction of the snapshot algorithm falls in the same category. On an afternoon like that, two rules are most important: at any moment at most one person should be speaking --long periods of silence are, however, permitted-- and everyone who has made a remark should be prepared to answer the question "Why did you say so?". It is the most effective way I know of making problem solving techniques explicit. One rule is essential: only accept problems because one has reason to hope that the effort of solving it will be instructive. (One of our foreign guests, from a more pragmatic culture, had grave, almost emotional problems. For three months he would ask in desperation "But why do you spend a whole afternoon on such a silly problem?" and for three months we would answer "Because we don't know how to solve it nicely.". After those three months, he caught the spirit.) Such afternoons are invariably exhausting, and failures are not uncommon (in the sense that the only thing we learned was that we still could not solve the problem.)

By now the most common afternoon is the one at which one member submits something he has written to the scrutiny of the others. The rule is that the author has no feeling to be spared and that the others try to improve his text as much as possible. Authors trained to that scrutiny are very attentive and will say "I noticed that we had to read that sentence twice. Can anybody explain to me his problems with it?" before anyone has actually complained. The fascinating observation is that, in such a situation, the author always gets a convincing explanation: a jump in the argument, a missing reference, a linguistic ambiguity, an unfortunate interpunction, or what have you. It quickly emerges how to mend the text.

I rarely saw a first version of a text pass such scrutiny unscathed, and this observation proves for me that Tuesday Afternoon Clubs are indispensable.

It has been during such sessions that a tradition has evolved as we arrived at a consensus which modifications were improvements. I realized that in Austin we have to go through that process afresh. It is partly purely technical, such as "avoid the superfluous", be it case analyses, nomenclature, or subscripts, and "Avoid the misleading", such as anthropomorphisms, operational arguments, or causal considerations (possibly in connection with the implication). It may be "political", and then consensus may be harder to reach. While there are technical reasons for avoiding most diagrams and for never using an example for clarification or disambiguation, people may feel tempted to sin in such respects in the belief that thus they serve their readership better. This is what I meant by "political". The Eindhoven Tuesday Afternoon Club accepted the political decision never to write down to its readers; respect and consideration was the cultural glue that kept the ETAC together. It is a very good glue; I think it is essential.

Austin, 29 August 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

Transcribed by Michael Lugo
Last revised 29-Aug-2013 .

EWD930

For the record: the Linear Search

Given a boolean sequence b (i : 0≤i ) which is not everywhere false. The program Linear Search determines the smallest natural value x such that b.x. More formally

|[ b (i : 0≤i ): array of bool {(Ei : 0≤i : b.i )}
;  | |[ x : int
| ;   | Linear Search
|  |  {R: b.x ∧ (Ai : 0≤i<x : ¬ b.i ) ∧ 0≤x }
| ]| |
]| |  |

Legenda In the outer block the constant environment is declared and what has been given about it is asserted. In the inner block the variable environment is declared and what has been given about it is asserted —when nothing has been given, as in this example, nothing is asserted—. The name of the program being specified is followed by the postcondition and the two blocks are closed. Note that variables only occur within their scope. The above is our preferred format for functional specifications. (End of Legenda.)

Aside From reviews of my books I have learned that many reviewers are annoyed by my closing brackets such as the above "(End of Legenda)", but they never give a convincing reason why I should depart from this convention, which, I think, is not without merit. So I shall stick to it. (End of Aside.)

The natural numbers being well-ordered, we conclude from the fact that equation x: b.x has natural solutions that x: b.x has a unique smallest solution, or, in other words, that x: R has a unique solution. Let X be the solution of x: R, i.e. let X be given by the fact that it satisfies

(0)       b.X ∧ (Ai : 0≤i<X: ¬ b.i ) ∧ 0≤X ,

a definition that allows us to rephrase R as

R: x := X .

Our first approximation to Linear Search could be

x := X

but as we have no closed expression for X, this approximation is much too crude.

For our next approximation we look for an initialization followed by a repetition, such that the dependence on b is confined to the latter. Since 0≤X is the only term in (0) in which b does not occur, this is then the only term we may use in justifying the initialization. That is, we are looking for an invariant that

is a generalization of R

can be initialized on account of 0≤X

I suggest as invariant P, given by

P:        x≤X

which leads to our second approximation

{0≤X } x :=0 {P} ; do x≠X → x:= x+1 od {R}

for which X–x serves for the termination argument since P ⇒ X–x≥0 , and X–x is decreased in each iteration.

Finally we deduce from P and (0) the lemma

P ⇒ (x≠X ≡ ¬ b.x) ,

which allows us to transform the second solution into our final solution for Linear Search:

{0≤X } x:=0 {P} ; do b.x → x:= x+1 od {R}

*                     *

*

The validity of the above solution is known —for more than a decade— as the Linear Search Theorem. It is a very simple theorem: it is as unsurprising as it is useful. In the folklore, it is known as "when looking for a minimum value satisfying some criterion, search in increasing order", but I would like to point out that we should be careful with such ellipses: instead of defining x as the minimum natural value x such that b.x, we could have defined it as the maximum value x such that (Ai : 0≤i<x : ¬ b.i ) .

I recorded the above derivation because it differs from the one I gave formerly in that X —the final value of x— occurs explicitly in the whole argument. My former argument used for the invariant the (equivalent) formulation

(Ai : 0≤i<x : ¬ b.i ) ∧ 0≤x ,

obtained from R by omission of the first conjunct. It contained an explicit appeal to

(Ai : 0≤i<x+1: ¬ b.i ) ≡ (Ai : 0≤i<x : ¬ b.i ) ∧ ¬ b.x

and locked the stepping stone of our second approximation.

I prefer the derivation given here, even though it might involve a little bit more formal labour had I proved the lemma explicitly. As the lemma is independent of the algorithm, the new version is a bit further disentangled. Hence my preference.

I am endebted to W.H.J.Feijen for pointing out to me the existence of this alternative derivation.

Austin, 1 Sep. 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Ryan Suchocki
revised 10-Apr-2016

EWD932c

The streamlining of the mathematical argument

I plan to extend the work done so far in collaboration with drs. A.J.M. van Gasteren at the Eindhoven University of Technology. This work was the first phase of a more general project, viz. the streamlining of the mathematical argument, which was inspired by our observation that many —if not most— mathematical arguments we encountered in the literature were unnecessarily complex and lacking in rigour by being incomplete. A few explorations sufficed to convince us that the potential for improvement was dramatic indeed, and we had to conclude that the mathematical community hardly pays any attention to the conscious pursuit of mathematical elegance (in the sense of the Concise Oxford Dictionary "elegant: simple and surprisingly effective"). In passing we note that high technology has now reached a stage of ambition in which mathematical elegance is no longer a dispensable luxury but often decides between success and failure.

Support from the BP Venture Research Unit was most welcome —and, we felt, appropriate— as soon as we discovered that, in the mathematical community, methodological concerns were markedly unpopular and that support from traditional sources was therefore unlikely. [ Mathematical results are taught quite openly and quite explicitly, as in the best tradition of the University. How to do mathematics, however, is taught only implicitly, by osmosis, so to speak, as in the tradition of the guilds, which guard the secret of their craft by avoiding the explicitness that would bring it out in to the public domain. The transition from craft to science always evokes opposition from the guild members and the Mathematical Guild is no exception. ]

Our explorations in the first phase have largely been confined to what had to be done first, viz. finding out what we wanted out streamlined arguments to look like, finding the relevant criteria for elegance (as technical concept), etc. Considerations of heuristics —i.e. how to design the effective argument settling a given question— has been consciously left to a later phase: there is no point in trying to develop a design methodology without a sufficiently clear picture of the key structural characteristics of the programs or proofs to be designed —with "structural characteristics" we refer to the ways of avoiding monolithic designs, to the degree of separation of concerns, to the choice which relationships are to be captured by syntax, the patterns according to which things are left anonymous or are named, the levels of abstraction that can be distinguished, etc.—. Similarly, when we learned that formal calculi of all sorts would have an important role to play, we postponed the problem of axiomatic foundation of such calculi: the intellectual investment involved would be premature without the "moral certainty" that one is founding the calculi one needs. [ These postponements directly reflect the separation of concerns that enabled the development of programming methodology that took place during the seventies. ]

The main results so far have been —with due credit to W.H.J. Feijen, C.S. Scholten, and the other members of the (Eindhoven) Tuesday Afternoon Club—

We identified shortcomings such as the Sins of Omission, of Repetition, and of Needless Distinction, and designed notational techniques catering for their avoidance and thus admitting the concise presentation of effective arguments. The resulting style has now been adopted in a book, in two completed Ph.D.Theses, in several articles and in numerous technical notes, and has been a precondition for our other results. (By way of verbal illustration, compare the following definition from Webster's New Collegiate Dictionary

"continued fraction: a fraction whose numerator is an integer and whose denominator is an integer plus a fraction whose numerator is an integer and whose denominator is an integer plus a fraction and so on"

with

"continued fraction: a fraction whose numerator is an integer and whose denominator is an integer plus a continued fraction" .)

We developed a theory of predicate transformer semantics, using an extended predicate calculus dealing with boolean functions on some domain. [ The relational calculus is a particularization for the special case that the underlying domain is a Cartesian square. ] The crispness of the theory is a convincing demonstration of how much can be achieved with a calculus that is notationally geared to the manipulations at hand.

We recently discovered how our methodology for the formal design of programs could be transferred to the design of proofs. This discovery is in any case of great promise, and probably of profound significance (see II, below).

We found several instances of how (more or less) special-purpose calculi can greatly facilitate design and correctness proof of programs that would otherwise have been hard to conceive and to justify. In program design, the use of the predicate calculus is now well-established. Last year the calculus of regular expressions was successfully applied in a new context — viz. that of distributed computations— and more recently A.J.M. van Gasteren developed with W.H.J. Feijen a special "ring calculus" for the design of a class of permutation algorithms. We sense a trend (see I, below).

The above results are not independent and clearly belong to the same "school of thought" that grew while I was at the Eindhoven University of Technology. At the University of Texas at Austin I found a very different culture, of which a strong tradition in mechanical theorem proving —established by Robert S. Boyer and J. Strother Moore— was one of the main attractions. I intend to exploit to the fullest my opportunities of acting as liaison officer between the two intellectually different cultures and to search for a fruitful blend of Austin's inclination towards mechanization and formal foundation and Eindhoven's stress on mathematical elegance. I see the following opportunities.

The (highly) effective use of elegant calculi seems a very promising area, the exploration of which has only begun. Tailoring a calculus to one's manipulative needs is clearly one of the main rules of the game, a game which Eindhoven, however, still plays "in Euler's style", i.e. without much formal foundation and without much basic insight in the limits of such calculi. (Uniqueness and completeness proofs, for instance, have traditionally bothered us.) The professional design of elegant calculi would make a well-established tradition of pure logic lead to "vehicles of formal reasoning" of great practical value.

The links connecting proof design and program design are getting stronger and stronger, both from practical experience (see iii, above) and from a theoretical point of view —the logician Per Martin-Löf sees an exact analogy between proofs and programs—. Consequently, for computing science/programming methodology, "proof-driven programming" seems an appropriate catch-phrase for a now promising research area. Austin's greater readiness to mechanize symbol manipulation will almost certainly give such a project a flavour it never gets as long as it is pursued in the Eindhoven style; at the same time it will open up a new area of application for the Austin tradition. [ Note that a formally derived program is an object fundamentally different from the intuitively constructed ones that pervade current industrial practice: the relation is as between a proven theorem and an unjustified conjecture. ]

American mechanized symbol manipulation is impressive; tied as it is to LISP —by now 25 years old— it is also unbelievably ugly. Decades of stagnation —the normal result of premature standardization— have been covered up by building faster, cheaper hardware. Mechanized symbol manipulation, but not in LISP's straightjacket, is an insufficiently explored avenue, and I am eager to see the experiment taken.

Independently, we and Boyer/Moore have found cases in which a syntactic analysis of the formal statement of the demonstrandum gave strong heuristic guidance, occasionally to the point of almost dictating how the proof had to be conducted. The time seems ripe to estimate whether our joint experiences warrant a more conscious exploration in that direction.

In view of the above I would like to extend my research contract with an Austin branch. Besides availability of the necessary funds, the realization depends of course on the availability of the necessary talent. Two Ph.D. students that expect to earn their title by the end of the year have shown their interest in joining me for a number of years. The one, Warren Hunt, is the first Ph.D. student of Boyer/Moore; his original background is in electronic engineering, for his thesis he has applied mechanical theorem proving to the justification of circuitry. At my last year's lectures he was the brightest spot in my audience and I would be happy to be able to attract him. The same holds for Bas Braams; in his student days he switched from mathematical engineering (in Eindhoven) to theoretical Physics (in Utrecht). During the last four years, partly at UKAEA Culham Laboratory (UK) and partly at the Max Planck Institut für Plasmaphysik in Garching (FRG) he has become a brilliant plasma physicist with extensive computational experience, and seriously considers becoming a computing scientist as well. They have not yet committed themselves (and have, of course, plenty of other opportunities, but I am afraid that that would hold for whomever I would like to attract). I would prefer to attract two "post docs" of sufficiently different backgrounds so as to stimulate each other.

In addition I would propose to be paid part of my summer salary and a budget for travel and communication.

transcribed by Martijn van der Veen
last revision Sun, 13 Feb 2005

EWD936

On anthropomorphism in science

(Delivered at The Philosophers’ Lunch, 25 September 1985)

I must apologize for not speaking to you, but reading to you. I chose to do so because, not yet feeling quite at home, I am a bit nervous. Of course I can argue to myself that I don’t need to, but that does not always work.

I can argue to myself that I grew up in a country whose population is only slightly larger than that of Texas, so why should I feel not at home? I spent most of my life at two universities, one four centuries old, the other a quarter, and if I take the geometric mean of those two ages I arrive precisely at that of UT, so why shouldn’t I feel at home here?

Well, actually it is not too bad. I think I am much happier here than I would have been, say, at XXX–XXX where it is possible to lose sight of what it means to be an intellectual. The reason that I am a bit nervous is that I am not quite sure what philosophers do and, hence, somewhat uncertain about my role here.

OK, so much for an irrelevant introduction; it was given to give you the opportunity to adapt your ear to my English.

* |  | *
| * |

I chose “anthropomorphism” because —besides being a nice broad topic— it is so pervasive that many of my colleagues don’t realize how pernicious it is.

Let me first relate my experience that drove home how pervasive anthropomorphism is. It took place at one of the monthly meetings of the science section of the Royal Netherlands Academy of Arts and Sciences, where we were shown a motion picture made through a microscope. Thanks to phase contrast microscopy —the invention for which Zernike got the Nobel Prize— it is now possible to see through the microscope undyed cultures of living cells, and that was what they had done while making this motion picture. It showed us —somewhat accelerated— the life of a culture of amoebae. For quite a while we looked at something we had never seen: I can only describe it as identifiable bubbles with irregular changing contours, slowly moving without any pattern through a two-dimensional aquarium. To all intents and purposes it could have been some sort of dynamic wallpaper. It was, in fact, rather boring, looking at those aimlessly moving grey blots, until one of the amoeba in the centre of the screen began to divide. We saw it constrict, we saw in succession all the images familiar from our high-school biology, we saw the centres of the two halves move in opposite directions until they were only connected by a thin thread as they began to pull more frantically at either end of the leash that still connected them. Finally the connection broke and the two swam away from each other at the maximum speed young amoebae can muster.

The fascinating and somewhat frightening observation, however, was that at the moment of the rupture one hundred otherwise respectable scientists gave all a sigh of relief: “at last they had succeeded in freeing themselves from each other.” None of us had been able to resist, as the division process went on, the temptation to discern two individuals with which we could identify and of which we felt —more in our bones than in our brains, but that is beside the point— how much they “wanted” to get loose. A whole pattern of human desires had been projected on those blots! Crazy, of course, but such is the pervasive and insidious habit of anthropomorphic thought.

Is anthropomorphic thinking bad? Well, it is certainly no good in the sense that it does not help. Why did the stone fall in Greek antiquity? Quite simply because it wanted to go to the centre of the earth. And, several centuries later, we had the burning question: why do stones want to go to the centre of the earth? Well, that is simple too: because that’s where they belong. Why are heavier stones heavier than lighter stones? Because they are more eager to be at the centre of the earth. But then Galileo made the troubling discovery that the heavier stone does not fall any faster than the lighter one. How come? Simple, dear Watson: the heavier stone has indeed a greater desire to be at the centre of the earth, but it is also more lazy. So much for a —be it somewhat simplified— history of the development of physics. I trust you got the message.

So anthropomorphic thinking is no good in the sense that it does not help. But is it also bad? Yes, it is, because even if we can point to some analogy between Man and Thing, the analogy is always negligible in comparison to the differences, and as soon as we allow ourselves to be seduced by the analogy to describe the Thing in anthropomorphic terminology, we immediately lose our control over which human connotations we drag into the picture. And as most of those are totally inadequate, the anthropomorphism becomes more misleading than helpful.

I started as a theoretical physicist, became involved in computing and may end up as a mathematician. It is specifically my connection with computing that has made me allergic, since computing science is cursed by a rampant anthropomorphism.

This has been so right from its inception, and found its way in the public perception of the topic, as is illustrated by the title of the book that Edmund C. Berkeley published in the fifties: “Giant Brains or Machines that Think”. The simplest way of showing how preposterous that title is is by pointing at its two companion volumes —still to be written— “Giant Hearts or Machines that Fall in Love” and “Giant Souls or Machines that Believe in God”, the most fascinating feature of the latter, of course, being that they can believe in God much faster than you. Regrettably we cannot sweep this nonsense under the rug by saying “Why bother? This is only popular press”. It finds its echo in publications that are intended to be serious, such as Grace M. Hopper’s article with the title “The education of a computer.”. It also finds its reflection in the multi-billion yen mistake of the Japanese “fifth generation computer project”, of which you may have heard. It would have taken care of the Japanese competition; regrettably —for the Western world— they seem to come to their senses, as the larger Japanese companies are pulling out of the efforts aimed at blurring the distinction between Man and Machine.

But the blur continues to linger on, and has a much wider impact than you might suspect. You see, it is not only that the question “Can machines think?” is regularly raised; we can —and should— deal with that by pointing out that it is just as relevant as the equally burning question “Can submarines swim?” A more serious byproduct of the tendency to talk about machines in anthropomorphic terms is the companion phenomenon of talking about people in mechanistic terminology. The critical reading of articles about computer-assisted learning —excuse me: CAL for the intimi— leaves you no option: in the eyes of their authors, the educational process is simply reduced to a caricature, something like the building up of conditional reflexes. For those educationists, Pavlov’s dog adequately captures the essence of Mankind —while I can assure you, from intimate observations, that it only captures a minute fraction of what is involved in being a dog—.

The anthropomorphic metaphor is perhaps even more devastating within computing science itself. Its use is almost all-pervading. To give you just an example: entering a lecture hall at a conference I caught just one sentence and quickly went out again. The sentence started with “When this guy wants to talk to that guy...”. The speaker referred to two components of a computer network.

The trouble with the metaphor is, firstly, that it invites you to identify yourself with the computational processes going on in system components and, secondly, that we see ourselves as existing in time. Consequently the use of the metaphor forces one to what we call “operational reasoning”, that is reasoning in terms of the computational processes that could take place. From a methodological point of view this is a well-identified and well-documented mistake: it induces a combinatorial explosion of the number of cases to consider and designs thus conceived are as a result full of bugs.

It is possible to base one’s reasoning on non-operational semantics and to design for instance one’s programs by manipulating one’s program text as a formal object in its own right, in one’s arguments completely ignoring that these texts also admit the interpretation of executable code. By ignoring the computational processes one saves oneself from the combinatorial explosion. This nonoperational approach is the only known reliable way of digital system design, and enables you to publish for instance in full confidence intricate algorithms you designed but never tested on a machine. The implied abstraction, in which time has disappeared from the picture, is however beyond the computing scientist imbued with the operational approach that the anthropomorphic metaphor induces. In a very real and tragic sense he has a mental block: his anthropomorphic thinking erects an insurmountable barrier between him and the only effective way in which his work can be done well. By the prevailing anthropomorphism the US, computer industry could easily be done in.

It is not only the industry that suffers, so does the science. Recently, a whole group of computing scientists from all over the world has wasted several years of effort. They had decided to apply to the relationship between a component and its environment a dichotomy: the “obligations” of the environment versus the “responsibilities” of the component. The terminology alone should have been sufficient to make them very suspicious; it did not and they learned the hard way that the whole distinction did not make sense.

Another notion that creeps in as a result of our anthropomorphism is the dichotomy of cause and effect. These terms come from our perception of our intended acts: we wish to pour ourselves a glass of wine, so we pick up the bottle and turn it, thereby causing the wine to flow from the bottle into our glass. Our act of pouring had the desired effect. But in the inanimate world there is little place for such a causal hierarchy. One of Newton’s Laws says that force equals mass times acceleration, and there is no point in insisting that the one causes the other or the other way round: they are equal. In the case of a piezo-electric crystal deformation and voltage difference are accompanying phenomena: if one applies a voltage difference, the crystal changes its shape, if the crystal is deformed, a voltage difference appears (as we all know from the butane cigarette lighter).

In particular the study of distributed computer systems has severely suffered from the vain effort to impose a causal hierarchy on the events that constitute a computational process, thus completely hiding the symmetry between the sending and the receiving of messages, and between input and output.

But even in the so much more abstract world of mathematics this has created havoc. It has caused a preponderance of mathematical structures of the form: “If A then B” or equivalently “A implies B”. Take good old Pythagoras

“If, in triangle ABC, angle C is right, then a²+b²=c²”.

but we have equally well

“If, in triangle ABC, a²+b²=c², then angle C is right”.

and the proper way of stating Pythagoras’s Theorem is by saying that in triangle ABC “a²+b²=c²” and “angle C is right” are equivalent propositions, either both true or both false. Analyzing the structure of traditional mathematical arguments one will discover that the equivalence is the most underexploited logical connective, in contrast to the implication that is used all over the place. The underexploitation of the equivalence, i.e. the failure to exploit inherent symmetries, often lengthens an argument by a factor of 2, 4 or more.

Why then have mathematicians stuck to the implication? Well, because they feel comfortable with it because they associate it —again!— with cause and effect. They will rephrase “If A then B” also as “B because A” or “B follows from A”. (The use of the words “because” and “follows” is very revealing!). Somehow, in the implication “if A then B”, the antecedent A is associated with the cause and the consequent B with the effect.

One can defend the thesis that traditional mathematics is anthropomorphic in the sense that its proofs reflect the causal hierarchy we discern in our acts, in the same way that traditional logic —for centuries viewed as the handmaiden of philosophy— is anthropomorphic in the sense that it tries to formalize and follow our habits of reasoning.

The advantage of this thesis is that it invites the speculation how mathematics and logic will evolve when they divest themselves from our ingrained human reasoning habits, when the role of formalisms will no longer be to mimic our familiar reasoning patterns but to liberate ourselves from the latter’s shackles.

And that is a fascinating question to ponder about!

Austin, 23 September 1985

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
AUSTIN, Texas 78712–1188
USA

Transcribed by Michael Lugo

Last revised 10 April, 2016.

EWD947

A letter to a typewriter manufacturer

Gentlemen,

I would like to acquire --and I trust that this is a wish you applaud-- a first-class electric typewriter that enables me to produce my technical notes, reports and scientific articles in what is now known as "camera-ready" form.

After having spent the major part of a day calling or visiting the major typewriter shops of Austin, Texas, I decided to contact you directly, for what those shops could provide was useless as far as I am concerned. And I hate to think that the typewriter industry is unable to produce a typewriter I could use, the more so as my wishes --well within the technology of today-- seem as modest as reasonable.

As a mathematician/computing scientist, I need besides the 52 letters, the 10 digits, and the usual interpunction signs a bunch of special characters. The total number of symbols is less than 100 and would fit on a single daisy wheel. And with a very few exceptions my special characters are not so very special either in the sense that they can be found on some daisy wheel.

Invariably I was offered the solution of buying enough different daisy wheels so that I would have (almost all) the desired symbols at my disposal. But that solution is utterly unrealistic, for, when using a typewriter, I wish to compose the text at the keyboard, formulae and all. (If I did not compose at the keyboard, the use of the machine would cost time instead of saving it.)

I am however unable to do mathematics at the keyboard if

(i)
a few vital symbols are lacking, and

(ii)
I would have to change daisy wheels a dozen times per line.

Unless I have all the symbols at my fingertips, the "solution" is unrealistic.

Do you think that as typewriter manufacturer you could manufacture the typewriter I need? If so, I would only be too pleased to specify my needs in the required detail. If my needs leave a few positions unused I shall be glad to assist you in the completion of the design.

Looking forward to your reply,

                   Edsger W. Dijkstra

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Javier Smaldone
revised Sun, 20 Jun 2004

EWD951

Trip report E.W. Dijkstra, Europe, 13.12.1985 – 10.1.1986

To start with a few advices to the airline passenger.

If your ticket is a few months old, check well in advance that the schedule has not been changed. When we arrived at Austin Airport in the expectation that Eastern Airlines would take us to Atlanta, we learned that Eastern Airlines had pulled out of Austin. Fortunately we were early enough to catch an earlier flight by Delta Airlines, which honoured our tickets. It was an unpleasant surprise to start our journey with.

Don't book a KLM flight for Friday the 13th in the hope that the plane will be occupied below average: you will find the plane fully booked with passengers that harboured the same hope.

Avoid departing from or arriving at Welschap with small planes like the F27 in those months when the runway could be covered with snow, sleet, or ice; I had three of such flights, only the last of which was actually consumed.

If you can enter the USA via Atlanta, do it. We walked from the gate to the belt and by the time we arrived there, the luggage was already coming in. It was fantastic. Immigration and customs were equally smooth. The official 91 minutes we had to change planes had been reduced to 71 by late arrival but we had plenty of time to catch our connection.

If you can choose a British Airways flight leaving Schiphol around noon, do it: the food was really excellent.

In the same vein I should suggest to avoid leaving the USA by KLM; catering for those flights is not up to par.

So much for my advices to the airline passenger.

*      *      *

After a thorough cleaning of the house, followed by a poisoning of all possible insect entrances, we left on Friday the 13th of December 1985 and arrived the next morning at 9:55 at Schiphol, where our daughter was waiting for us with a car. It was a foggy day.

We used the weekend for recovery as, on Monday, life would start in real earnest. Ria went that day by train to Amsterdam to greet her mother, while I was interviewed most of that day by a Mexican student from the University of Edinburgh who wrote a thesis on the history of software development.

On Tuesday, Ria and I drove, mostly in heavy rain, to Groningen at the other side of the country in order to attend the inaugural lecture by Jan L.A. van de Snepscheut, a lecture we very much enjoyed. That night we stayed with Femke, as she would graduate the next morning at the Department of Slavonic Languages. After the formality, she and a colleague offered their guests a nice breakfast by way of celebration. Around noon we left and drove to Nuenen, again mostly in heavy rain. South of the village Veghel, the cable of the clutch of the rental car broke. Thanks to the proximity of the garage where we had rented it and the kind assistance of a young lady that saw us getting stuck and offered her assistance, the delay was no longer than an hour. It was, however, raining cats and dogs, and we got accordingly wet.

On Thursday I went to the Eindhoven University of Technology, where I gave a talk at its recently founded Informatics Colloquium. I had a nice crowd and explained Battcher's Baffler, which by now is a very beautiful story. It was well-received.

And on Friday we went up North again, to Zutphen, where we celebrated my mother's 85th anniversary with a lunch in the IJsselrestaurant. That was the first time I met my mother and my sister, and on this trip the only time I met my brother and his wife. It was nice to see them all again; we did not stay too long as pretty foul weather had been predicted for the evening.

And so on, and so on. I worked only twice with Carel S. Scholten and only twice with Netty van Gasteren and attended only one session of the Eindhoven Tuesday Afternoon Club (on 31.12.1985). It was a nice session; we read AvG65/EWD950 "On notation" and collected helpful —and encouraging!— comments. And besides all that we did the usual things, visited the children and received them, had friends for dinner and were invited for dinner, etc. And occasionally we did nothing at all. We did not make much use of our bicycles, for in the night of 26/27 Dec. it started to snow, instantaneously transforming the whole country into one big Christmas card. So Ria and I put on our rubber boots and made a series of beautiful pictures in the immediate surroundings of Nuenen. It was unbelievable!

The winter will, however, go down into the Books of History as "The Winter in which We Found the Old Mont Blancs". I love my Mont Blanc but for many years am aware of the fact that the company stopped making this model about a decade it is the model with the built-in pump that takes much more ink than its replacement, which accepts cartridges as well. Since it is nice to have a spare, it has become second nature for me to try new models whenever I encounter them. One afternoon I went to the village stationery shop to buy European staples, saw a new Mont Blanc, tried it and did not like it, when the saleslady behind the counter said with great hesitation "When you object to using an ink pot, I have another model, but it is very old.....". The dear soul sold me her treasure for the original price. After that find Ria suggested that we should try that other branch in Someren, where Netty van Gasteren and Wim Feijen bought the remaining three copies. They too still had their original price tags and were even cheaper; on top of that they even got fl. 10,- discount per pen! So much for the stationery shops in little Brabantian villages.

The last Monday, Netty and I flew to England to give a workshop for BP. For safety's sake we went to by train instead of by air. The flight to was okay, but from there on everything seemed to go wrong. We arrived at Terminal 1, while Don Braben tried to collect us from Terminal 2. After Netty had contacted him by paging, we thought the problem had been solved but then the one confusion piled upon the other and eventually it took almost two hours to sort out that mess.

The workshop was held in the hotel "The Spread Eagle" in Midhurst where it was frequently as cold as the hotel was old. I slept —at least: tried to do so— in "The Queen's Suite", distinguished by a four-poster and a closet for powdered wigs (or wig powder, I don't remember) dating from 1430 A.D.. But apart from such minor inconveniences, the workshop was quite successful, the more so since we succeeded in flying back home on Wednesday evening. With Netty's Dick and my Ria and Femke we celebrated the happy reunions with a late Indonesian/Chinese dinner at Kota Radja opposite to the railway station. On Thursday we packed, in the evening a number of friends came by to say goodbye and on Friday morning Femke drove us with all our luggage to Welschap: this time we could use the small airport. At 19.55 local time we landed in Austin; we took a taxi and shortly thereafter we were home again. Not counting a dozen dead insects on the floor —and no scorpions this time!— we found the house at Robbie Creek Cove in perfect condition.

*      *      *

Europe is not happy these days. I found a lot of tension and envy. (The latter is probably the price to be paid for its prevailing egalitarianism.) By way of protest the Dutch truck drivers blocked a number of border posts and traffic junctions; when we arrived at Heathrow, the English taxi drivers were on strike; one participant of the workshop arrived a day late, due to a strike of the French air traffic controllers; and I never saw so many armoured cars and fully armed soldiers guarding the air ports. And at the Universities —at both sides of the North Sea— people are beginning to feel themselves so much betrayed by their governments that it is often hard not to get bitter. On paper there are still plenty of funds for informatics, but as that money has been ear- marked to work miracles it only promotes quackery. Tension and envy, and each proposal being wrapped up in more and more layers of dishonesty. Europe is not happy these days.

*      *      *

Needless to say, I bought myself a typewriter the other day, a Triumph/ "satellite III". It is electronic and in its more advanced features so user-friendly that the corresponding sections in the (46-page!) manual are utterly baffling. So far, the alphabet works.

Austin, 16 January 1986

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Martijn van der Veen
revised Sun, 6 Mar 2005

EWD952

Science fiction and science reality in computing

There is a lot of misunderstanding about computing science, among both computing's practitioners and the public at large, and the purpose of this talk is to clear up that misunderstanding, for it hurts all of us in more than one way.

On the one hand, the achievements of computing science are sadly ignored. Many projects in which the conscious application of the techniques and methods of computing science is indispensable are carried out in a totally unscientific manner as if computing science did not exist. This is a great pity, for it leads to many a costly failure that could have been avoided, and computing science is denied the due recognition for its achievements.

On the other hand, the expectations of what computing science will achieve for us are often totally unrealistic: the performance of miracles by the dozen seems to be the absolute minimum. And this is a great pity too, for it leads to false hopes and unrealistic planning, and when those wonderful plans fall through, computing science will be written off as just another form of quackery.

If you so desire you may view this talk as an effort to change what seems now to be the computing scientist's predicament: first he is not allowed to have any influence at all, and afterwards he will be blamed for all that went wrong.

At first sight one might think that explaining the quintessence of a science and then drawing conclusions as to its appropriate rôle is a straightforward technical job, but regrettably it isn't. The problem is that the message runs counter to too many vested interests and is for many too uncomfortable to be heard. In the past it could be delivered. It used to cause a momentary discomfort, and then the audience would laugh it off and return to the order of the day, tolerating the messenger very much as the court jester is tolerated. But things are changing, the vested interests have increased and been diversified, and more and more people are beginning to realize that this is no longer a laughing matter. While a knowledgeable and dispassionate discussion of these matters has become more and more urgent, it has become more and more difficult to raise the topic. For further technical details I refer to the fate of Galileo Galilei.

*      *      *

Earlier I said that achievements of computing science are sadly ignored. Well, if it were just that, it would not be alarming: there is by necessity a lag between the useful achievement in the laboratory and its general exploitation. In our case, however, it is alarming because over the last decades the gap between computing science and computing practice has only widened. Whereas computing science made great strides towards a vigorous, rigorous discipline, computing practice showed mainly stagnation. I am not exaggerating: the physicists still think that FORTRAN is the last word in computing, the chemists continue with BASIC, and what APL is for the electronic engineer, COBOL is for the MBA. The human tendency to get attached to the sources of one's misery has been hailed as the great stabilizing factor in many marriages and religions, but by their morbid attachment to those inadequate vehicles those disciplines have manoeuvred themselves into a position in which they are beyond help. These observations used to apply to the "casual user", but in the mean time the problem has been magnified by the fact that it has affected many university curricula that, instead of training first-class scientists, now train third-rate programmers.

Well, you might say, these people don't consider themselves programmers but physicists, chemists etc., but in the professional field the picture is equally bleak. We have all heard of the Shuttle that did not get launched due to an error in the synchronization software, so I shall give you another example. Recently, British Rail has installed its first computerized signalling system along one of its tracks and they advertised the system in the hope of selling it to other railroad companies by revealing that, in order to avoid the risk of using a compiler, the system had for safety's sake been written in machine code. It was evidently taken for granted that commercially produced compilers play dirty tricks on you. Another area rich in horror stories is provided by VLSI design; among its usual "tools" is a program —very expensive to run— that tries to reconstruct the circuits from the raster, needed because the program producing the raster cannot be trusted. But the alchemy of communication protocols probably beats them all; originally designed by telecommunication engineers to compensate for incidental hardware errors, they have become so unwieldy that they are responsible for the introduction of many more transmission failures than they were intended to correct and that the verification of their designs has become a major challenge: unravelling that mess can now be a Ph.D. topic. And all that inadequacy was avoidable, for computing science initiated its penetrating and successful study of the problems of compilation and synchronization more than twenty years ago. So much for the gap between science and practice; now for the unrealistic expectations.

We have already seen that curricula are being changed on the unchallenged assumption that, in this modern day and age, computer usage is essential to becoming a good scientist. Now this is very strange, for it is almost impossible not to challenge that assumption in view of the large number of very successful scientists we know that never used a computer because in their days there weren't any. It is true that microcomputers have been sold as aggressively as encyclopedias, blackmailing the parents with the future of their kids. And if you read between the lines, the message was even more seductive: give your kid our home computer, and he'll become a genius. But we cannot blame the industry for that misconception, no matter how hard it tries to push its goodies down our throats: in those advertisements they just appealed to the ever-present lurking desire for the Philosophers' Stone that makes gold and the Elixir that gives eternal youth and health. Industry was no worse than the common quack.

To the best of my knowledge it was not industry that invented the term "computer literacy", but society. Quite early in the game it was firmly implanted in the people's minds that computers were there to save our economies (and later also the economies of the countries of the third world). For a while, no one knew how, but fortunately someone hit upon the bright idea that information was "a resource", so that solved that problem, the more so since, for the first time in the history of mankind, we had now a valuable resource of infinite supply. Then people remembered how oil had created immense riches for a happy few; this time that should not happen again, so "computer literacy" for the millions was invented to solve that problem. What that term should mean is still an open question, but that did not prevent our visionaries from happily proceeding to invent the post-industrial society in which people, if not happily teleconferencing, would devote their ample leisure time to creative video-games.

There is nothing novel in people expecting that Heaven on Earth will be established in the near future; novel, however, is that microelectronics will do that job, rather than the Grace of God. I am not exaggerating: expectations are so unrealistic that what should be reasoned discourse sounds more often than not like people participating in a strange ritual, faithfully reciting prayers in a language they don't understand. Let me just quote you a few recent examples.

The director of a large research laboratory, when interviewed at the occasion of his retirement, extolled the virtues of the home computer by stressing that it would enable people "to order their creative thoughts". Now think for a while about the nonsense! Between you and me, when did you have your last creative thought? Two years ago? Not bad. It would have made more sense if he had said "to order the stamps in your collection". When Bertrand Russell made the famous remark "Many people would sooner die than think. In fact they do.", he showed more realism. My private conclusion was that that director retired none to soon.

At an international conference on Computers and Education it was immediately agreed that the little kids should be introduced to computers as young as possible. There was a moment's concern that such an intensive mechanization of the educational process might hamper the little kids in their emotional growth and in the development of their contactual skills, until someone remarked that "talking to a program could do no harm because, being a product of the human mind, a program was essentially human". Now that I come to think of it, wasn't also Hitler's Final Solution a product of the human mind?

At a recent conference on the feasibility or infeasibility of the software for the Star Wars project, one of the arguments in favour of feasibility, I have been told, was the remark that today almost all of the banking operations had been successfully computerized, hadn't they? Well, as a matter of fact, they haven't: as late as 1986 the salary payment of a large (computer!) company was electronically screwed up. But even if they had, it would have been a fake argument: the two projects are so different that the analogy is several orders of magnitude too shallow to be of any value. The worst of all, I think, was that this fake argument was put forward by someone who had found himself a place in the academic world.

*      *      *

In the sixties Sir Hermann Bondi wrote an article on who should do academic research. The question was an urgent one. Prior to the second world war scientists were a negligibly small minority, but in response to the recognition that that war had been won by science and technology, the academic enterprise was boosted thereafter. Not surprisingly, Bondi came to the conclusion that many of his contemporaries engaged in scientific research had really better be in some other business. Because the explosive growth of the university was directly related to the expected high benefits from science, Bondi also devoted a section of his paper to the usefulness of science in general. His conclusion is sobering.

He points out that of the problems coming from outside the campus, from "the real world", about 80 % are trivial and about 20 % patently unsolvable, and that academic research has its potential impact in the thin boundary layer in between as it is only there that knowledge, talent and hard work can achieve something that cannot be achieved by other means. In the scientific/technological euphoria of the day, such a sobering warning was more than needed; it was, however, neither heard nor heeded, but that is another story.

By an unfortunate accident of history, computing emerged during just those decades of unbounded faith in the wholesomeness and power of science and technology. Whereas the more established sciences had their roots and traditions in soberer times, we embarked on computing with our expectations unbridled. From a historical perspective, the naive optimism is quite understandable. And there may even be some justification for it. You see, Bondi is a physicist and his 80/20 % judgement was derived from his knowledge of how the natural sciences deal with the complexities that we are faced with in the world that surrounds us. Computing science, though, deals with a world of artefacts in which the complexity is of our own making. That makes a big difference and it is quite possible that, in computing, Bondi's "boundary layer" is not so vanishingly thin at all. But in order to make an educated guess of what that layer could and should compromise, we have to understand how computing science emerged and grew to operate.

Before turning to computing science specifically, however, I must dismiss one further dream that was frequently dreamt in those decades, viz. that it is possible to "plan" research so as to produce in due time what the world asks for. Science does not work that way (which, by the way, is a good thing as there is often a grave discrepancy between what the world asks for and what the world needs). E.T. Bell justly praises a number of rulers for being "far-sighted enough to see that the simplest way of getting mathematics out of a mathematician was to pay his living expenses". and the same holds for the other sciences. No dramatic progress of science ever occurred because some benefactor commissioned the result. Significant progress in science only occurs when after probing pondering a knowledgeable original mind has concluded that something baffling may now be ripe for understanding or something very difficult may now be done. Successful scientific research is the art of doing the just possible, and consequently scientific development is much better regarded as an autonomous process with its own private rules than as a planned activity with external objectives. (And this is the paradox faced by all directors of industrial research laboratories: after having attracted the right people, they cannot serve their company better than by leaving those people alone.)

*      *      *

Proponents of inter-disciplinary research sometimes seem to believe that the boundaries between the different sciences are no more than unfortunate accidents of history. But the way in which scientific knowledge has been parceled out over the different disciplines is not so accidental at all: what may constitute the area of a viable scientific discipline has to meet quantitative and qualitative constraints.

Among the quantitative constraints I mention that the area must be small enough so that the major highlights fit in a single person's head; on the other hand it must be large enough to provide intellectual food for at least a lifetime.

Among the qualitative constraints I mention that on the one hand its problems must be sufficiently independent from the rest so that they can be studied in relative isolation from that rest, while on the other hand the area has to have an internal coherence.

It is this last requirement that makes quite clear how the earlier departments of computing science predated computing science itself: to begin with they were no more than ill-considered cocktails of presumably computer-related topics that happened to be available on campus, eg. some electronics, some numerical analysis, some statistics and economics, some business administration and in the USA some artificial intelligence after a while. The cocktail, composed without coherence, did not taste too good. Forging coherence was one of the first tasks for those that were responsible for carving a niche in which a budding computing science would be viable.

For the sake of the coherence they withdrew from all specific areas of potential computer applications and tried to concentrate on what all those applications ought to have in common; they had done so for the sake of coherence and for the sake of the generality that is required for durability.

Another aspect of that durability was the conscious effort to avoid the training of scientists with a half-life of five years. This implied in particular staying away from everything that could only be given a meaning in close relation to the computing machines currently on the market. For instance, how to live with the idiosyncracies of OS/360 was considered a moving target that was none of computing science's concern.

In summary: the niche was carved, away from specific applications and away from specific machines. And, as time went on, in the same vein away from specific programming languages and operating systems. In the beginning this was done in order to protect the budding science from the volatility of the products from the market place, and when some of these products turned into de facto standards it was done to protect the flourishing science from the stagnation in the market place. Independent of the question whether to regret or to applaud this separation, I want you to understand that for the emergence of computing science as a viable discipline this separation was and still is a conditio sine qua non.

What did computing science do in that splendid isolation? More precisely, what did it do without losing the claim of applicability? Well, it did a lot; much more, in fact, than I can explain in the context of this lecture, but I can give you the flavour.

In the sixties it developed the parsing theory that was needed to raise compiler design above the level of error-prone adhoccery and to turn it into a teachable topic. This was a major achievement: I, for instance, quite distinctly remember how in 1962 those of us who had actually written a compiler were by the others still regarded as a kind of semi-gods. In connection with this achievement I would like to stress that it could never have occurred had we not learned in the mean time how to give a complete formal definition of the syntax of the programming language to be compiled: without that formal definition the compilation problem would have been too ill-defined to exist. Automata theory and complexity theory were developed to give essential and quantitative bounds on what can be computed at all; again, at the heart of these theories lies a very formal postulate as to what computing is, a postulate without which those theories cannot exist. For the sake of operating system design, the problem of process synchronization was posed and solved and the first theorems about the absence of deadlock were proved; again, a formal definition of the phenomenon intuitively known as deadlock was the first prerequisite for that achievement.

In the seventies the attention shifted from syntax to semantics, to begin with for deterministic sequential programs, but shortly thereafter including nondeterminacy and concurrency as well. I shall not try to describe the various activities in any detail: they ranged from providing a model for the typed lambda calculus to the development of programs by means of semantics-preserving program transformations. It was during that decade that programs became mathematical objects in their own right. The most concise way of capturing the change in attitude is probably to remark that, while formerly it had been the task of the programs to instruct our machines, it had now become the task of the machines to execute our programs. Program verification and program design were developed as branches of formal mathematics, with the result that it was no longer an act of irresponsibility to publish a program without having tried it on a computer.

Well, this has been a far from complete overview of how computing emerged as a science. and I apologize to all contributors whose work has remained unmentioned. But I do hope that it has been sufficiently complete and evocative to have given you the flavour of the quintessence of the discipline. It became a fascinating discipline because the separation between "pure" and "applied", which is traditional in so many others, got completely blurred and largely lost its significance. The luxury of working in an environment in which the distinction between pure and applied science is meaningless is probably a fringe benefit of the fact that the general purpose computer really deserves the epithet "general purpose".

It has all the flavours of pure mathematics, being more formal than most other branches of mathematics. It cannot escape being so formal since any programming language, by the sheer virtue of being mechanically interpretable, represents a formal system of some sort. At the same time it has the full flavour of applied mathematics because the sheer capacity of modern computers provides such an opportunity for confusion that its methods are indispensable if we prefer not to get trapped in the complexities of our own making.

Learning how not to get caught in the complexities of our own making, keeping things sufficiently simple and learning how to reason sufficiently effectively about the designs we are considering, all these have become central issues of computing science. This too was recognized more than a decade ago, when "separation of concerns" became a catch phrase of programming methodology.

Please notice that the way in which computing science carved itself its niche was, all by itself, an example of successful "separation of concerns". Whenever we invest a lot of mental energy in the careful design of any discrete system, we do so for more than just the fun of it: we always hope that the product of our efforts will be used for the benefit of others. We hope that it will satisfy a need, will meet the expectations and will please its users. In the prescientific period of system design, the unformalized notion of "user satisfaction" was for a time the only accepted quality criterion for software.

The shortcoming of "user satisfaction" as a quality criterion is that it is not a technical notion: it provides no technical guidance to the designer and, besides that, can be achieved by other than technical means, such as heavy advertising and brainwashing. Science can do nothing with it, at any rate preciously little. The concerns had to be separated, and that is where the functional specification entered the picture.

The rôle of a formal functional specification is simply to act as a logical firewall between two completely different concerns, known under the names of "the pleasantness problem" and "the correctness problem". The pleasantness problem concerns the question whether a system meeting such-and-such a formal functional specification would satisfy our needs, meet our expectations and fulfil our hopes. The correctness problem concerns the question whether a given design meets such-and-such a formal functional specification.

The logical firewall was necessary so as to create the correctness problem for computing science to tackle: it isolates computing science's well-carved niche from the pleasantness problem to which science has little to contribute. Please note that I did not say that the one problem is more important than the other; after all, no chain is stronger than its weakest link. What I said was that the correctness problem represented that part that we manage to bring inside Bondi's "thin boundary layer" where the conscious application of the techniques of scientific thought can avail, whereas the unformalized pleasantness problem intrinsically lies outside the domain of science.

You may have all sorts of problems, ranging from a dangerous intersection to whole generations of your population feeling threatened in their very existence. But science never solves your problems, it only solves its own ones, and the decision whether you accept the solution to the formal problem science posed to itself as a possible solution to your problem as well is unavoidably yours. In the same vein: science never provides a model for reality, it only constructs its own theory, and the question whether you accept your perception of reality as a sufficiently truthful model for that theory, well, that's your problem.... Truth and reality are no longer scientific notions and the scientist leaves talking about them to the philosophers, the prophets and the poets.

Seen this way, the rôle of science is quite limited, so disappointingly limited in fact, that many prefer to close their eyes to the limitations of science. Stressing these limitations was never very popular in the scientific community, among other things because it raises the question why society should tolerate scientists at all. This is no joke: we all know that if today a society decided to expel its scientists, it would not be the first to do so...

And now that science has "gone public", so to speak, it is not very popular among the public at large either. People have always had ambivalent feelings towards technology, and the more powerful the technologies people are confronted with, the more dramatic the dilemma of that ambivalence. They feel more threatened by technology than ever before; at the same time their hope of the salvaging power of science and technology is becoming more and more unbridled. In the good old days of the traditional quack, his ointment only needed to cure all ills, his Elixir only needed to give you eternal youth, and from the famous Philosophers' Stone only the modest trick of making gold was required. Those were the good old days, when the quest for the Philosophers' Stone was still in its infancy.

But in these advanced electronic days, the Philosophers' Stone has acquired completely new dimensions. An achievement still in the traditional vein of goldmaking is that thanks to robotics eventually all countries of the world will have a positive balance of trade. It will solve the problems of production and unemployment. It will give central government the power to fight crime and corruption, while the ubiquitous micro will be the safeguard of democracy. Teaching machines will rejuvenate the educational process while calculators, automatic spelling correctors and intelligent machines in general will make most education superfluous. All state secrets will be absolutely protected by infallible encryption; powerful decoding schemes will enable us to break all codes. Weapons and defense systems will be equally effective. But, most important of all, if we don't know what to do, we shall have our decisions "supported", our management will be informed and our information will be managed, our design will be as aided as our intelligence will be amplified, and without any special training everybody, really everybody, even managers and generals, will have all the canned expertise they need at their fingertips. The great novelty of today's Philosophers' Stone is that you can delegate your responsibilities to it.

So much for the blatant nonsense. Now it could be argued that in my unwillingness to compromise I have taken an extreme position; I know that quite a number of reasonable and respectable colleagues in the field would judge the limits as I have drawn them for computing science impractically narrow. They would point to all sorts of systems of great potential utility that would fall outside my very strict boundaries. They would argue, firstly, that currently such systems are designed without much of a formal functional specification, and, secondly, that we would not know how to give such a specification, even if we wished to do so. One example is provided by libraries of numerical routines for which neither the limits of their applicability nor the accuracy of the results have been clearly stated. Another example could be a system for optical character recognition as might be used in mail sorting, at least if delivered without a precise statement of which characters will be flawlessly recognized. True enough, but allow me to point out a few things.

Firstly, let me recall that I refused to grade the pleasantness problem and the correctness problem in relative importance, in other words that there is nothing intrinsically wrong with an unscientific project: it is only unscientific. Secondly, that these are projects in which apparently computing science's niche does not fit; well, if that's the case, computing science cannot contribute to them and had better leave them alone. Why should computer applications to which science cannot contribute be ruled out? I don't think we should be bothered about that. It is my firm conviction that we grossly underestimate the cultural significance of computers as long as we judge them primarily as tools, because I expect them to have a much profounder influence in their capacity of intellectual challenge.

My overriding concern, however, is that such projects exploit only part of the computer's characteristics and that they lead to rather unspecified products in which the computer's other characteristics have disappeared. The numerical routines exploit the number crunching abilities, optical character recognition exploits the storage capacity and the flexibility, but in both cases the final product is no longer an automaton with precisely stated properties. Hence the resulting product is no longer a machine in the sense of computing science and using it is like doing mathematics without axioms. Such numerical routines can only be used in a context where the answer does not matter or the numerical analyst using them has other means of verifying the answers; such optical character recognition systems can only be used in circumstances in which it does not matter if, say, a fraction of the letters is initially sent to the wrong destination. We can no longer rely on such systems as if they were automata, and we have to reject them in any closed loop.

For many, such a conclusion is unpalatable, and as a result there is a school of thought —or, if you prefer: a school of non-thought— that proposes that the situation is not that serious, that we should not be that rigid, that engineers have always allowed their components to fail occasionally, that striving for perfection quickly becomes counter-productive, and that we had better learn how to live in the real world with systems and subsystems that usually do what we expect them to do. It is a seductive proposal. Wouldn't it be nice to achieve excellence without having to strive for perfection? (This the more so, since in a heavy populist society, the latter is socially unacceptable.) It is the stance now taken under the banner of "software engineering".

But what proponents revealingly refer to as "the software engineering movement" is beset by a few unsurmountable internal contradictions.

One of them is the dogma that striving for perfection is counterproductive in the sense that it would make software development much too expensive. But what are the main causes of the soaring costs of software development? A major cost, in terms of both manpower and unforeseen delays, is debugging, and one can save a lot by investing more in preventing the bugs from entering the design in the first place. Since the errors are so expensive, in general the high-quality design is also by far the cheaper. Another major cause is that many systems are built on shifting foundations in the sense that the underlying software of operating systems and compilers is too shaky to be stable, with the result that each new release of that underlying software requires possibly extensive adaptation of what has been built on top of it. Finally, many of the tools the programmer is supposed to work with are so poorly documented that they force him to find out by experiment what they might be able to do for him. Since these experiments can be pretty expensive and time-consuming and —inductive reasoning being what it is— an educated guess is the best the poor programmer can hope for, the poor programmer is really in a miserable position. So here you see three major sources of cost explosion traced down to someone's assumption that striving for perfection is counterproductive!

Another contradiction of the software engineering movement surfaces as soon as a software engineer asks himself how he could become a better one, how the art, craft or practice of software engineering could be improved. He will immediately discover that he has to resort to the discipline he has rejected. Having accepted as its charter "How to program if you can't.", software engineering has manoeuvred itself into an impossible position, a position computing science can avoid only by refusing to compromise, by sticking to its own formal discipline, and by not pretending to be more.

A moment ago I mentioned poor documentation of a system as an intrinsic limitation on the reliability with which the system can be used mechanically in a larger context. This is the place to point out that hiring a technical writer is rarely a solution; the act is usually not much more than an admission that the system's designers are in some sense functionally illiterate. The common situation is that even an army of technical writers could not do the job because the system has grown so complex that it defies accurate description.

A striking example of this phenomenon has recently been provided by Ada. If Ada is going to provide a standard, that standard had better be unambiguously documented. At least two groups have had a go at it; both efforts resulted in formal texts of about 600 pages, i.e. many times longer than needed to ensure the impossibility of ever establishing firmly that the two documents define the same programming language. The fault of the patent unmanageability of these two documents lies neither with the two groups that composed them, nor with the formalisms they have adopted, but entirely with the language itself: only by not providing a formal definition themselves, could its designers hide that they were proposing an unmanageable monstrum. That Ada will decrease the pain of programming and increase the trustworthiness of our designs to within acceptable limits is one of those fictions for which a military education is needed in order to believe in it. The best thing I can report on this front are persistent rumours that even a military education does not suffice to maintain faith in the effectiveness of this Stone of the Philosophers. I have mentioned Ada explicitly because it provides a perfect illustration of what I alluded to at the beginning of this talk: its adoption was a political process in which computing science, whose warnings were viewed as a nuisance, was not allowed to have any influence, and, consequently, just maintaining one's well-considered doubts becomes, beyond one's control and intentions, a politically loaded act.

I haven't talked about artificial intelligence yet. Well, this topic is fraught with another political complication as it has become part of the transatlantic controversy: the topic never really caught on in Europe. For the first two decades after the war, a simple financial explanation sufficed. Artificial intelligence was expensive and Europe was poor; in addition, artificial intelligence was almost exclusively financed by the DoD, which focussed its funding —I won't say: support— on American research. But the financial explanation cannot be the whole story, because when Europe was rich enough to fund its own research in artificial intelligence, the topic still did not catch on. Neither did the other soft sciences really.

My conclusion is that it is but one aspect of a broader cultural difference. The European mind maintains a greater distinction between Man and Machine and has lower expectations from both of them. It is less inclined to describe the human psyche in mechanistic terms; it is also less inclined to describe inanimate machinery in anthropomorphic terminology; consequently, it considers the question whether machines can think as relevant as the question whether submarines can swim. Its society is evidently less gadget-ridden, in part because it expects much less from gadgetry, certainly not salvation. Conversely, the goal of mimicking human reasoning is apt to evoke the comment "Couldn't you try to copy something better?"

Usually I don't need to talk about artificial intelligence as it is only a specific area of potential machine application and as such outside the scope of computing science proper. I have to do it, however, as soon as it is proposed that, by applying AI techniques, machines will solve the software problems we don't know how to solve ourselves. Our first reaction to the Fifth Generation Project was a sigh of relief, in the style of "Well, if the Japanese industry tries to cash in on AI, that will take care of the Japanese competition.". Within a week or so came the sad realization that the Western world would probably lack the backbone needed for not joining that bandwagon.

Indeed it joined the bandwagon and, consequently, we have again the popularity of "Wouldn't it be nice if our machines were smart enough to allow programming in natural language?". Well, natural languages are most suitable for their original purposes, viz. to be ambiguous in, to tell jokes in and to make love in, but most unsuitable for any form of even mildly sophisticated precision. And if you don't believe that, either try to read a modern legal document and you will immediately see how the need for precision has created a most unnatural language, called "legalese", or try to read one of Euclid's original verbal proofs (preferably in Greek). That should cure you, and should make you realize that formalisms have not been introduced to make things difficult, but to make things possible. And if, after that, you still believe that we express ourselves most easily in our native tongues, you will be sentenced to the reading of five student essays. The problem with the "smart" machines is the same as we had with all the programming language "features": each next layer of "user-friendliness" blurs the specification and thereby makes the system more risky to use.

One final issue. It is not the topic of my talk but, in these political days, if I don't raise it myself, it will be raised in the discussion: what about the software required for SDI, better known as Star Wars? Well, I am sure I could not design it to my satisfaction.

I thank you for your attention.

transcribed by Martijn van der Veen
revised Sun, 30 May 2010

EWD956

Address to my students

Reading the literature almost always tempts me to conclude that the quality of the standard paper is below average. Let me list a few of the standard shortcomings of the standard paper:

the nontechnical prose is salestalk

the technical prose is sloppy and verbose

the notations are ill-considered and pompous

the formalisms adopted are clumsy

the definitions are unclear and incomplete

the proofs are omitted or a caricature of what they should be

the problem tackled is not worth solving (e.g. because it is easily avoided)

the author fails to challenge his tacit assumptions and to separate his concerns

the problem can be presented and dealt with better and in only a tenth or a fifth of the space.

So far, so bad. Worse often surfaces when one discusses these shortcomings with the author. While agreeing in an abstract way, he yet defends his articles with arguments in the following vein:

the paper is addressed to the XYZ community, which habitually expresses itself in that style, deviation from which would result in failure to reach his intended audience

the shortcomings don't matter because the intended audience knows how to resolve the ambiguities (if it notices them) and how to supply what has been omitted

had he followed the suggestions for improvement, the paper would have become so short that no one would notice that he had achieved something

in improved form, the paper would be rejected by the editorial boards and program committees of the XYZ community and, being untenured, the author cannot afford the luxury of that rejection.

Having a solid germ of truth, his defense sounds almost plausible. But we should not forget the following:

scientific research as planned by managers is planned as if the available budget is the limiting factor, whereas the problems worth tackling are our scarcest resource

the publish-or-perish syndrome has opened the flood gates for the write-only journals and the analogous speak-only conferences; there are more of those than we can form competent editorial boards and program committees

education has always been an up-hill struggle, and it is naive to expect from the XYZ community gratitude for showing that its pet problems are disposable

life of a scientist was never meant to be comfortable; exciting, yes, but comfortable, no.

We should never forget the crucial distinction between the salesman and the scientist. It is the salesman's duty to please his customers or, if that is too difficult, to fool them. It is the scientist's duty to raise our abilities by increasing our standards for quality and effectiveness, to show what can be done well by pursuing the just possible, and to clarify ruthlessly, independently of the fact that complexity sells better.

In these respects, there is no room for compromise: the alternative is no less than scientific corruption, and remember that the commonness of the latter phenomenon does not make it respectable.

Of course, you are free to join "for your protection" an XYZ community by accepting its standards as law; but if you do so, know that the scientist in you has been replaced by the party member.

Austin, 14 April 1986

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, Texas 78712-1111
United States of America

Transcriber: Kevin Hely.

Last revised on Sun, 30 May 2010.

AvG67/EWD958

On naming

It is impossible to do mathematics without introducing names. The main issues seem to be what things to name and how to name them. An important distinction seems to be whether a name occurs primarily in formulae to be manipulated or is to be embedded in sentences. We shall explore the latter context first.

Names in a linguistic context

One should be cautious when introducing a "meaningless" identifier that is identical to a word in the language of the surrounding prose. Standard examples are the Dutch "U" —U is een onsamenhangende graaf— and the English "a" — in order that a might be removed— and "I" — because I may be empty—. On paper this problem can be alleviated by typographical means: the identifier can be made to stand out by the use of italics or an additional pair of surrounding spaces, but these distinctions are hard to render in the spoken word.

Great caution is called for when giving a normal word a specific technical meaning. Naming a set "checked" or "preferred", a boolean "found", a logical connector "defines", or a type "chosen" all but precludes the use of these normal words in their traditional meaning.

But even if an author explicitly states that some common words will only be used in his technical sense and faithfully sticks to that discipline, the choice of such "meaningless" identifiers requires great care, because their normal connotations can still invite confusion. For instance in a recent manuscript we encountered wires that could be "open" or "closed", but on closer scrutiny, wires could be in a third state, which had been left anonymous but could have been called "ajar". This naming would have been very faithful in the sense that transitions between "open" and "closed" only occurred via the state "ajar". Yet, the nomenclature open/closed was unfortunate, because too often the two are considered each other's negation. In situations like this we often benefitted from the use of colours, e.g. red and blue for just exclusive states, yellow as the name of some property, and white, grey, and black when we wished to express a linear order. We also remember a graph in which the vertices were red or blue, thereby introducing red, blue, and violet edges. So much for the confusion that can be caused by the multiplicity of meaning of common words and by the author's inability to control which connotations they evoke.

A totally different concern is what we might call grammatical flexibility, i.e. does the term to be introduced have or admit the derivatives needed. To give an example of the problems one might run into, consider the adjectives simple and complex. Connected to the first we have the noun "simplicity", the verb "to simplify", and the noun "simplification"; for the other one we have the noun "complexity", the verb "to complicate", but we lack the analogous noun "complification", as the noun complication won't do: it refers to the result and not the act of complicating. Confronted with existing terminology, one may find oneself forced to coin the the missing term, e.g. "to truthify" in the meaning of "to effectuate the transition from false to true" in analogy with "to falsify"; in choosing a term, the need for such coinages should be taken into account. (For instance, the fast general acceptance of the technical term "stack" could well be due to the fact that it is linguistically more flexible than the older "push-down list".) So much for grammatical flexibility.

We would like to draw attention to a linguistic irregularity. In principle, adjectives and prefixes are constraining: a red dress is a dress, a washtub is a tub. Some prefixes, however, are generalizing and hence imply a hidden negation: a half-truth is not a truth. Natural languages can apparently live with this irregularity, but we cannot recommend it for the coinage of mathematical terms as they are specifically intended to be used in a logical context. So much for the semi-group that isn't a group and the weakly increasing sequence that isn't increasing.

Another fuzziness to be aware of is the natural use of "not", "and", and "or". The problem with "not" is that we cannot indicate its scope, vide "not retired or disabled" and "not uniformly convergent." The problem with "or" is that it is mostly exclusive, vide "Should I marry Jane or Ann?" and "Is it a boy or a girl?", but sometimes inclusive, vide "retired or disabled". The trouble with "and" is that it is sometimes conjunctive, vide "retired and disabled", and sometimes enumerative, vide "men and women". By the time we encounter "retired and disabled persons qualify", we have had it. In Texas the law says "Stop while schoolbus is loading and unloading.", in Missouri it says "while loading or unloading.". Evidently natural languages are not well adapted to cope with these constructs. The terminology we are talking about being intended to be used in verbal reasoning, it pays to construct it in such a way that such constructs can be avoided. We have the trichotomy "less than", "equal to", and "greater than". It really helps to introduce new names for their negations, viz. "at least", "different from", and "at most" respectively. In this way one avoids "not greater than" and "less than or equal to" — compare the latter one with "up to and including"!—. Similarly, "different from" enables us to avoid "not equal to" and the clumsy "less or greater than".

In short we suggest that when a concept is named it might be a good thing to give its complement an equally "positive" name. There are two reasons for this; firstly, sentences with too many negations quickly become utterly confusing, vide "I'm not sure that I don't dislike it if you are not present."; secondly, the negation as in "equal" versus "unequal" creates an asymmetry in the dichotomy that is often undesirable: it suggests that the positively named term is the more fundamental one. (Before you object by pointing out that equality is more fundamental than difference because equality is transitive while difference is not, please realize that "at most" is as transitive as its negation "greater than".)

To drive home the message we shall analyze the emergence of a well-known but unfortunate turn of phrase. Corresponding to "greater than" and "less than" we have the "increasing sequence" and the "decreasing sequence" respectively. Let us now admit equality as well. In the absence of new terminology, "Greater than" is then weakened to "not less than" or to "greater than or equal to". For a sequence with X.i ≤ X.(i+1) the corresponding characterizations a "not decreasing sequence" or an "increasing or constant sequence" are equally unacceptable. Mathematical parlance programmed around it by calling it a monotonically not increasing sequence. The whole problem is solved by introducing the adjectives "ascending" and "descending".

A final confession to end this section with. In a recent discussion of a permutation algorithm our elements began "unmarked" and ended up "marked". We have now several reasons for regretting this terminology: it destroys the symmetry, it is very operational, and is on the verge of introducing marks as mathematical objects.

Names in a formal context

In a formal context there should be no confusion as to what are names and what are more complicated expressions. Are P', A*, q̄, r̂ and Q∞ identifiers or are they the result of applying special functions denoted by  ',  *,  ̄,  ̂ and  ∞ to P, A, q, r, and Q respectively? Is P'' a name or is it equal to (P')'? Is subscription a mechanism for name construction, e.g. ΔA₁A₂A₃ or is it a special notation for function application? The latter is the only tenable interpretation if, after the introduction of the infinite sequence x₀, x₁, ... , we encounter a reference to xi. The difference seems slight, but notice that in the case of A₁, A₂ and A₃ the name A is in the same scope available for other purposes, whereas in the case of x₀, x₁, ... the name x is already in use as function identifier.

Aside. Note that such special function notations can create typographical and syntactic problems: the operator   ̂ could have to be applied to an expression or, in general, to a multi-character argument, and what is the value of P∞' if those operators do not commute? Unbridled introduction of such special function notations is therefore not recommended. (End of Aside.)

In the following we assume a relatively modest syntax for names introduced by the author, say not much more complicated than a sequence of letters and digits starting with a letter. We do so because in our experience little is gained by the introduction of two-dimensional names in fancy scripts, e.g. σ AH. But even with such a strict syntax our freedom in choosing is almost unlimited and it is the writer's task to exploit that freedom wisely.

We take the position that formulae's main purpose is to be manipulated and that, therefore, our choice of names should be guided by the ease of manipulation. The first consequence is that a short name is better than a long one. Trivial and obvious as the consequence may be, in this day and age it needs to be stated explicitly as it runs counter to the propaganda with which higher-level programming languages have been sold to the programming community, the idea being that the choice of sufficiently descriptive names would make programs "self-explanatory". This, however, was a fallacy: many a programming error can be traced down to the use of identifiers that were deemed to be sufficiently descriptive. In the case of a totally meaningless identifier it is obvious both to the writer and to the reader that all relevant properties must be stated explicitly.

A second consequence is that one should choose one's dummies carefully. Particularly in the case of a closely knit theory it can pay: in the case of substitution it is preferable to have the variables substituted for named differently from what is substituted, a difference which removes a possible source of confusion and error; often substitution can be avoided altogether by choosing the same names, e.g. naming an arbitrary solution of an equation by the same identifier as has been used for the unknown of the equation. Note that both difference and equality of names can be exploited.

Thirdly, we often introduce names in groups with some internal structure, e.g. in pairs, in cycles, in a hierarchy, or reflecting a combinatorial state of affairs (e.g. vertices and edges of a triangle). We strongly suggest to choose names that reflect such structure as fully as possible. We don't need to elaborate on the available techniques such as primes, correspondence between small and capital letters, alphabetic order, alphabetic nearness, multi-character names, but we do urge the writer to pay attention. (Two recent examples. Recently we saw in an argument the identifiers Xs, Ys, fx, fy replaced by P, Q, p, and q, and the "simplification" was striking. The new terminology significantly reduced the demands on the hand-eye coordination required for the argument's development; it also made the argument much more pleasant to read. The other recent example was a theorem about sets A, B, C, and D. Formulation and proof strongly suggested that the number four was essential, though the theorem was a special case of any number of cyclically arranged sets. In the author's formulation, the cyclic order was ABDC. We would like to suggest that the unfortunate terminology —and further notation, to be quite honest— could have played a role in the author's failure to discover the generalisation.)

Besides the question how to name there is the question what to name, and here lies a second reason why we urge the author to choose his names as carefully as possible. The choice usually being difficult, the author thus increases the probability of discovering that the name is not needed after all. Two things should be avoided: superfluous names and names for the wrong objects. Not claiming an exhaustive treatment of the topic, we confine ourselves to the most frequent symptoms of inadequate naming. An arbitrary identifier used only once is superfluous, e.g. "Every integer N greater than 1 can be factored into a product of primes in only one way." —Courant and Robbins in "What Is Mathematics?"—. Though a secretary could weed it out, this sin is remarkably frequent. (In passing we note that "greater than 0" would have been preferable, the empty product of primes being unique as well.) Superfluity can also be noticed in a statement like "In triangle ABC the bisectors of the angles A, B, and C respectively are concurrent." instead of "In a triangle the angular bisectors are concurrent.". Mild symptoms are displayed when the text gets enumerative, with lots of "respectively". A more serious symptom is usually the occurrence of "without loss of generality we can choose" or a similar clause, for then the chances are high that an underlying symmetry has been destroyed by an overspecific nomenclature. We called the latter symptom "more serious" because we have more in mind than just a cosmetic reformulation of the argument: it is often indicative of the possibility of designing an essentially superior argument —eg. replacing a combinatorial case analysis by a counting argument—.

So much for avoidable names. We now turn to the question whether the right things are named. If not, the general symptom is clumsiness of the development. We shall mention some examples first.

•   Defining the natural numbers as the integers from 1 onwards (with in its wake the failure to recognize 1 as the empty product, etc.). Avoidable case analysis and clumsy formulation are the standard byproducts.

•   The superfluous argument, or naming a function instead of an expression. A function's characteristic property is that it can be applied to different arguments, and if that flexibility is not needed and a function name, Π say, always occurs in the combination "Π(σ)", it could be argued that a name for that combination, P say, would have been more appropriate. The phenomenon occurs often, and if we count subscription, etc. as notation for function application it occurs very often. Sometimes it is defended on the ground that in a few isolated instances the function is applied to other arguments, but a notation for substitution could cater for these instances, eg. Pσσ, P(σ'/σ), or (λσ, P)(σ' for Π(σ') —we have also seen σ := σ';P with the rule that the low-priority semicolon is right-associative—. Sometimes the need to express universal quantification (over σ) is felt as a compelling reason for adopting the convention. People felt comfortable with (Aσ :: Π(σ)) but less so with (Aσ :: P), understandably wondering whether the dummy σ is arbitrary or not. In contexts where universal quantification over σ is the order of the day, great economy of expression can be achieved by denoting universal quantification over σ by a reserved bracket pair, eg. [P] instead of (Aσ :: Π(σ)).

•   Naming a subset versus naming the characteristic predicate. Given the predicate prime on natural numbers, we can define the set PRIME by

PRIME = { n | prime.n } ;

conversely, given the set PRIME, we can define on the natural numbers the predicate prime by

(0)      prime.n = n ε PRIME .

In view of this one-to-one correspondence, we need only one of the two. We have observed that the majority of mathematical texts opt for PRIME. In view of the similarity of the left- and the right-hand sides of (0) the choice seems almost irrelevant. But it isn't, because the logical connectives have been developed better than the set-theoretical operators. The latter — ∪, ∩, ÷, and \ — suffer from the constraint that each element of the result is an element of at least one of the operands of — ⊆ and = — suffer from the anomaly that the result is a boolean value. By way of illustration, we recently saw a proof that for some predicates a, b, c, and d the predicate

a ≡ b ≡ c ≡ d

was everywhere true; the author, however, had used sets and had formulated his demonstrandum as

A ÷ B ≡ C ÷ D    .

In short, by his decision to name the sets instead of the predicates, the author had obscured most of the symmetry (with the result that he failed to discover straightforward generalizations of his theorem). Also, do we like to need to know

A ∩ (B \ C) = (A ∩ B) \ C

whereas

(A \ B) ∩ C = (A \ B) ∩ C

is invalid? In general, we found the application of the logical connectives to the predicates much more convenient.

Note. The preponderance of named sets over named predicates is the result of an educational bias, which is also regrettable for other reasons: Venn-diagrams do invite case analysis. (End of Note.)

•   In the derivation of an algorithm computing the coordinates (X, Y) of a pixel on the screen, the subexpressions (X-X₀) and (Y-Y₀) occurred all over the place; calling the pixel coordinates (X₀+x, Y₀+Y) would have circumvented this. This was a very simple example; anyone with experience in analytical geometry knows how much difference the choice of a coordinate system can make. Repetition of lengthy or similar subexpressions is the usual indication of an unfortunate choice.

The gain can be more radical. The algebraic identity

(a-h)(b-c) + (b-h)(c-a) + (c-h)(a-b) = 0,

which for reasons of symmetry is very easy to verify, is the shortest proof (analytical or not) we know of the fact that the altitudes of a triangle are concurrent: if two of the addenda equal zero, so does the third! The above proof, however, presupposes the conceptual availability of vectors, their differences, and their scalar products plus the rules of the corresponding calculus.

Inadequate naming tends to manifest itself pretty clearly. We are the first to admit that in general it is less clear how to improve the situation: as the above example shows, the concept to be named might need to be invented. We do hold the belief, however, that in the process of such invention considerations of notational convenience can be of considerable heuristic value. (We do not know how Cayley and Sylvester invented the matrix calculus, but we can think of a scenario that starts with them getting tired of writing over and over again

A₁₁x₁ + A₁₂x₂ + | ··· |  + A1nxn = | y₁
A₂₁x₁ + A₂₂x₂ + | ··· |  + A2nxn = | y₂
| · |  | ·
| · |  | ·
| · |  | ·
An1x₁ + An2x₂ + | ··· |  + Annxn = | yn  ,

Sylvester losing his patience and Cayley tactfully suggesting "What about A·x = y ? ".)

(End of •’s.)

*              *
*

A final remark, be it on the borderline of naming and notation. We all know how, early in the last century, British mathematics was nearly killed by its adherence to Newton's fluxions and how a coup of the Analytical Society in Cambridge was needed for the conversion to Leibniz's method. In retrospect it is hard to see why several generations of mathematics could stick so tenaciously to the Newtonian version of the calculus. British insularity has been offered as an explanation, so has an ill-directed patriotism, but these are merely sociological explanations. The whole affair must have had a technical side as well. It has taken so long that we must conclude that at least from today's vantage point there was only a dim awareness of what a well-designed formalism can do for us. Letting the symbols do the work while manipulating uninterpreted formulae represents a conception of doing mathematics that must have been almost entirely foreign to those generations: had ease of manipulation been a recognized issue, the tragedy would probably have been prevented.

Austin, 13 May 1986

Prof. dr. Edsger W. Dijkstra
Dept. of Computer Sciences
The University of Texas at Austin
Austin, Texas 78712-1188
United States of America

A. J. M. van Gasteren
BP Venture Research Fellow
Dept. of Mathematics and Computing Science
Eindhoven University of Technology
Postbox 513
5600 MB EINDHOVEN
The Netherlands

Transcribed by Michael Lugo
Last revised Sat, 29 May 2010.

EWD960

On a proof I learned from prof. dr. J. Haantjes

In my freshman year at Leyden University (1948-49), dr. J. Haantjes �who, regrettably, died too young� was my only professor that excited and impressed me. He was exciting because he showed types of arguments that were absolutely novel to me, he was impressive because of the calculational agility with which he carried them out.

It was also his first year at the University. In retrospect I think he was as uncertain as to what to expect from his students as we were as to what was expected from us. He spoke softly and wrote small on the blackboard, both rather fast. I think he sinned against almost all educational principles of today, but, fortunately, those did not exist yet. Shy and uncertain, but also brilliant and dedicated, he was revered. He may have had a profound influence on me; if so, that would be for me reason for joy and even some pride.

I vividly remember his proof that the altitudes in a triangle are concurrent �I guess this was November 1948�. Consider the algebraic identity

(0)    (a−h) ⋅ (b−c) + (b−h) ⋅ (c−a) + (c−h) ⋅ (a−b) = 0

which depends on symmetry and associativity of addition and multiplication plus the fact that the latter distributes over the former. Since those properties are satisfied by vector addition and the scalar product, (0) also holds if we interpret a, b, c, and h as vectors �from some origin� to points A, B, C, and H respectively. Associating the orthogonality of two vectors with their scalar product being zero, we conclude from (0) that if 2 of the scalar products equal zero, so does the third, hence the altitudes in ∆ABC all go through H. (For convenience�s sake we have confined ourselves to the situation in which A, B, C, and H are all distinct.)

I was absolutely thrilled, remembering only too well the clumsy Euclidean proof on which I had been educated. (Calling the altitudes in the usual fashion AD, BE, and CF, one identifies the altitudes of ∆ABC as the angle bisectors of ∆DEF and then appeals to the concurrency of the angle bisectors of a triangle. This proof is really ugly, since it is very hard to avoid a case analysis on sharp and obtuse triangles; even without that case analysis, it is painfully indirect.) I still remember how thrilled I was.

*                 *
*

The other night, talking with a good friend about mathematical methodology, I tried to explain the above proof by way of example. In general willing to buy the argument, he yet was unconvinced of its merits because he had not learned how to see at a glance that (0) is valid. In explaining to him how one can see that at a glance, I saw that it would have sufficed to consider

(1)     a ⋅ (b−c) + b ⋅ (c−a) + c ⋅ (a−b) = 0

The drawing is simpler �6 vectors instead of 10� and (1) is about twice as easy to verify as (0). I don�t know why Haantjes chose to use (0), for he was a master in the simplest choice of coordinates.

What amazes me most is that, while I have often used this proof as example of an �ingeniously simple and effective� argument, it took me more than 37 years to discover this simplification.

                          Amarillo, 22 May 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Jonathan David Arndt
revised 10-Nov-2019

EWD962

Introducing a course on mathematical methodology

For a number of very different reasons, which will become clear in the course of this introduction, I cannot just begin with the subject matter of the course. Some explanations and warnings are needed first, because without them you probably would not know how to listen to me.

The warnings are mostly about me. Since I am in Austin, I have learned that I seem to address two types of students: on the one hand there are the students that have greatly appreciated my lectures as an enriching experience because they were so totally different from the others they were exposed to, on the other hand there are the students that blamed me for deviating from what they were used to.

Well, I don't intend to try to adjust my lecturing style to the expectations of the latter category. Firstly, I know that, never having been exposed to the American educational system, I would be unable to imitate my average American colleague. Secondly, I would be forsaking my educational duty if I tried: I have not been invited to come to UT so that I could offer what any knowledgeable experienced American colleague can offer better, I have been invited to complement the system and to represent what it tends to neglect.

To put it bluntly, a major part of my educational duty is to be an un-American activity become flesh. More concretely, whenever in this course a clash of cultures surfaces, we should remember that exposure to a different scientific and educational tradition had been planned, right at the start, as an essential ingredient of the course.

It is our combined duty, but primarily mine, to prevent this clash of cultures from becoming destructive. Your contribution to this effort is, for the moment, to listen as open-mindedly and as carefully as possible; my contribution will be to prepare you, as carefully as I can, for the differences with which you will be confronted.

I grew up in a society where the transition from secondary school to university was a very sharp one, underlined by all the accompanying linguistic symptoms. The university had professors, students, and lecture-rooms, the school had teachers, pupils, and class-rooms. At school we were addressed by our first name and in the familiar form, at the university by our family name and in the polite form. In short: abruptly we were treated as grown-up. We were addressed as "Ladies and Gentlemen" and expected to behave accordingly.

As we had just witnessed from uncomfortably close quarters the near collapse of Western civilisation, the cultural and scientific enterprise as embodied by the universities was taken very seriously, notwithstanding our awareness that not all of the academic community lived up to those high standards —as illustrated by the definition of a university professor as someone who casts false pearls before real swine—. But the standards [were] very much alive. It was our task to mature as cultured, competent scholars and scientists and no one expected us to prepare ourselves for a profession: that was done at trade schools and a university was not a trade school. (It would never have entered our minds to describe a professor as "someone who hasn't made it in industry"; the relation was probably the inverse in that industry had to make do with the left-overs of the academic world.) We had, in general, great respect for our professors and, conversely, they had great respect for quite a few of us. Talking down to one's students was something that was definitely "not done", and the rare professor that mistakenly did it was despised for it.

Certainly during my earlier years the idea of hand-outs would have been preposterous: we could make our own notes! When, in my later years, the professor of theoretical physics —he had come from the University of Utrecht— handed out a syllabus, we felt deeply offended. We experienced his excerpt as an obnoxious barrier between us and the original works from which it had been extracted. We accused him of contempt of audience and eventually he went to the University of Amsterdam.

Such were the formative years from which date the pan-academic prejudices that now parade as my well-considered opinions. They have profound consequences for the way in which I propose to give this course. Let me give you a few warnings.

I shall give an occasional hand-out —after all we are now more than a third of a century later—. But in principle you are required to make your own notes and to work them out between lectures. This is for you the only way of beginning to acquire the necessary penmanship and of discovering in time that you failed to understand what seemed so clear and simple when I explained it. This is not a vain warning: for decades I have been accused of telling such smooth stories that half my audience fails to see most of the potential difficulties.

Remember: you are grown-up. That means that it is not my responsibility to teach you something; my only responsibility is to give you the opportunity to learn, preferably a lot and stuff you cannot learn from someone else. I may give some exercises at which you may try your hand, I shall not give homework that must be handed in to be graded. I am not forcing you to listen to me, it is your responsibility to try to learn as much as possible. Remember: you are grown-up.

For a successful course, mutual respect is essential, and this mutual respect has to be earned. I, from my side, intend to do that by not using the poison of the educational process known as "the overhead projector", by trying to perfect my chalkmanship, by addressing you in carefully considered and grammatically complete sentences, and by drawing your attention to a host of essential particulars that otherwise would have escaped your attention. You, from your side, have to earn my respect as well. That goes beyond laughing about my jokes —just to show that you have noticed them— and correcting me when I have omitted a closing parenthesis. Your duty is such an active and criticial participation that what unavoidably starts as a monologue develops into a meaningful dialogue. Your rôle is not one of sponges, but one of whetstones; only then the spark of intellectual excitement can continue to jump over.

A final warning about my personal style. I am used to expressing myself tersely, a tendency that can only have been strengthened by the circumstance that I have to address you in what for me is a foreign language. I am not one of those so-called gifted speakers that can just turn their mouths loose; I am one of those unfortunate people that have to think about what they are saying. As a result I speak slowly, so slowly that I can pause in mid-sentence.  But, for Heaven's sake, don't be deluded: in all probability you have to listen twice as fast as you are used to. I grew up in a culture in which, if something had been said once, that should suffice: you had taken note, hadn't you? Let me, by way of exception, illustrate this point. I said "I am used to express myself tersely" and left it at that because the adjective "tersely" conveys the message accurately; I abstained from explaining the term for greater emphasis by adding "that is, I tend to use as few words as needed and tend not to repeat myself". [To this very day, idiot software managers measure "programmer productivity" in terms of "lines of code produced", whereas the notion of "lines of code spent" is much more appropriate. With words, it is in the same way.] In short, at the end of a lecture you should be at least as tired as I.

So much for the style in which this course will be presented. Let me now turn to the nature of the material I intend to cover.

The idea of giving this course has been born out of dissatisfaction with the ways in which mathematics has usually been taught since I was a student. The courses I followed consisted of facts, facts, and more facts: the triple (definition, theorem, proof) repeated ad infinitum. Very useful if you wished to apply or extend the theory and totally useless otherwise. Later I saw a different type of mathematics course emerge: tricks, tricks, and more tricks, recipes for solving very special types of problems and endless exercises so as to make their execution a routine job. Useful perhaps when that routine job is what you are heading for, but, again, totally useless otherwise. Furthermore, particularly in countries where rhetoric is confused with effective use of language, we have seen courses that are cult of pure form: the student is only taught a pompous language and mathematics is reduced to mannerisms.

The student that, like the wild animal being prepared for its tricks in the circus called "life", expects only training as sketched above, will be severely disappointed: by his standards he will learn nothing.

Let me quote by way of contrast and for inspiration, what G.R. Elton wrote about the teaching of history:

"Three or four years spent at a university cannot teach a man to know history; they cannot train him as a politician or publicist or publisher; they can at best begin to lay some foundations for a view of the world and (universities being what they are) are likely to lay foundations which, as later experience shows, need to be broken up. None of this invites blame: the impossible need not be attempted. But if those years do not produce an effective conditioning of the reasoning mind, if they do not teach a man to think better than otherwise he would have done, they may justly be condemned as a waste of time."

Well, I would be grieved to hear if your years at UT could, in Elton's words, "justly be condemned as a waste of time". In the name of the effective conditioning of the reasoning mind, in order to teach you to think better than you would have done, this course will be about the doing of mathematics. It is my purpose to bring into the public domain what in the traditional mathematics course is left explicit.

It is not my purpose to turn, in a one-semester course, all of you into as many excellent mathematicians. Remember: the impossible need not be attempted. But I can and shall try to give you the opportunity of becoming a better mathematician than otherwise you would have been and I propose to do so by exposing at least the major components of the mathematical craft and by warning you explicitly for some of the more common mistakes that the experienced competent mathematician avoids out of habit.

How to raise such a course above the level of motherhood statements —the level that is characteristic of the management courses sold by the training industry— has been told to us by William Blake (1757-1827)

"He who would do good to another must do it in minute particulars
General Good is the plea of the scoundrel, hypocrite and flatterer
For Art and Science cannot exist but in minutely organised particulars".

The moral of this quotation is that, in principle, no detail will be too small for our attention. I also like this quotation for the way in which it mentions Art and Science in the same breath, for, indeed, the analogy between the performing artist and the productive scientist is not so far-fetched at all. Among the very basic things the young pianist has to learn is how to take care of his finger nails; we shall encounter similar care, of our mathematical finger nails, so to speak. Also, the performing artist must become very familiar with the potential and the limitations of his instruments; so must we with our instruments such as pen, paper, and the printed page.

The analogy goes further. Just as a professor at a conservatory represents a musical style (to the extent that it is often possible to identify the master by listening to his pupils), I represent a mathematical style. It is up to you to decide later to what degree to adopt and to improve it. One thing, however, you are not allowed to do, viz. to reject it offhand for the sole reason that it does not reflect the way of doing mathematics you are used to. Of course it doesn't! That is precisely why you are here. This whole course is no more and no less than an invitation to take the experiment of changing some of your reasoning habits and adopting some new modes of expression. As you take the experiment you will notice that it is not acquiring the new habits that presents the greatest problem, for that is getting rid of the old ones. Perfecting oneself is as much unlearning as it is learning.

This is obvious. Yet it needs to be stressed because stupid educationists have invented for the educational process the profoundly inadequate term "knowledge transfer", suggesting a unidirectional stream of knowledge towards an accumulating recipient, who becomes monotonically more knowledgeable. I consider it a caricature at best. The trouble is that it may have stuck in some of your minds, thereby creating an extra barrier for the unlearning process. It makes some people totally unprepared for the recognition that among what they have acquired so far is possibly a lot of junk that is more a burden than an asset and that they should be happier without. One cannot be cautious enough with the choice of one's past.

Austin, June 1986

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, Texas 78750-1188
U.S.A

Transcriber: Kevin Hely.
Last revised on Fri, 28 May 2010.

EWD963

Visuals for BP's Venture Research Conference

When we had no computers, we had no programming problem either.

When we had a few computers, we had a mild programming problem.

Confronted with machines a million times as powerful, we are faced with a gigantic programming problem.

The programming problem is gigantic because

viewed as string of operations on a collection of variables, each individual computation is a gigantic object;

the individual computation depending on the input, a single program has to be able to control a gigantic number of different possible computations.

As a result, programming has become one of our most demanding intellectual activities, requiring great clarity of expression and the utmost economy of reasoning.

This conclusion has never been refuted; it is, however, regularly denied because of its uncomfortable implications.

It is vigorously denied by the computer industry, which would sell you its products rather as solutions to your old problems than as the source of terrifying new ones.

It is vigorously denied by those customers that otherwise would have to admit that their computer manufacturer has fooled them.

[Remember that computers are preferably sold by dealing with such a high level of the customer's hierarchy that incompetence in computing is assured and objections from the technically competent can be overruled.]

It is vigorously denied by those in computing that by its implications would be demoted to the rank of amateur.

[Remember: the surest way of making software design prohibitively expensive is viewing it as a production job to be done by cheap labour.]

It is denied in those companies whose top management consists of lawyers and accountants, as their management lore has all its roots predating the advent of the high-technology industry.

It is also denied by the personal-computer enthusiast that fails to distinguish between a barber and a team of surgeons.

Back to the irrefuted conclusion that programming is very difficult; its acceptance gave rise to Programming Methodology as a topic of explicit scientific concern.

In 15 years of Programming Methodology we have seen the combination of spectacular progress and sharp limitations.

Many formerly notoriously opaque algorithms now have "ingeniously simple and effective" explanations, which are jewels of clarity.

Sophisticated new algorithms are being derived which, 15 years ago, would have been absolutely impossible to conceive. But.....

Current mathematical style —which grew in response to other challenges— limits the applicability to relatively small programs.

The circumstances shaping the challenge, we try to redefine Mathematics from "The abstract science of space, number, and quantity" (COD) to "The (art and) science of effective reasoning".

We have learnt that calculi of all sorts have a major role to play.

We have learnt that it pays to design, for each calculus to be used, with great care a notation geared to one's manipulative needs.

We have learnt that most philosophers (those of mathematics included) are eminently ignorable.

We have learnt that a formalism's major purpose can be to free us from the shackles of our native language and the reasoning patterns induced thereby.

[Being "counter-intuitive" should not be held against any formalism that enables us to accomplish what is beyond the unaided mind.]

We have learnt that programming methodology and mathematical methodology in general are not so far apart at all. (For instance, a conscious separation of concerns is equally valuable for both.)

We have learnt that a purely syntactic analysis of the formal requirement can give heuristic guidance to the point of generating the best possible solution.

We have learnt that the potential for improvement can be dramatic, e.g. reducing a formal proof of two dozen steps to an equally formal proof of one step.

(Example.)

We have learnt that it pays to be ruthlessly pragmatic, but.....

We have also learnt that it is still very hard to sell to industry the economic value of mathematical elegance.

Austin, 5 June 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Fri, 28 May 2010

EWD966

Management and mathematics

A persistent piece of management lore holds that, for the sake of continuity and stability, large organizations should try to be as independent as possible of special gifts of individual employees. (See, for instance, “The Organization Man” by William H. Whyte, 1956.) As a result, large organizations still follow that advice, even high-technology industries for which the price may be heavy. In fact, large corporations repel (and sometimes even actively reject) the employee with special gifts, even if those gifts are highly relevant for the company’s business. The large corporations have to make do with the left-overs from those sections of society that are not afraid of relying on personal excellence, such as the academic world and some smaller companies.

Everybody is uncomfortable about this regrettable state of affairs and people silence their feelings of uneasiness in different ways. They may try to convince themselves that second-rate intellects are good enough for the industrial enterprise. This is the tacit justification for many a university’s graduation policy and for many a company’s hiring policy, but since the advent of the high-technology industry, the argument has become less and less convincing. Alternatively, industrial mediocrity is raised to the level of a Law of Nature and companies console themselves by the consideration that they are no worse off than their competitors. (The belief in the supposed Law of Nature is so strong that, if a competitor performs better, he will rapidly be accused of “unfair competition”: of course, for how else could he have outperformed them! The alternative —also practised— is to consider competence an unfair advantage.)

The practice of recruiting managers from the technical ranks strengthens in management the industrial tendency towards mediocrity because, in general, the best professionals are the least inclined to switch to a managerial position.

The organizational love of mediocrity has severely hampered all sciences in their effort of contributing to the industrial effort, and mathematics has been hampered most of all. They are several reasons for this.

Firstly, rightly or wrongly, more than their counterparts in other sciences, successful mathematicians are aware of the rarity of their personal gifts and abilities —the divine spark, etc.—; they are weak at suffering fools gladly and are most easily repelled by the ubiquitous mediocrity of the industrial world.

Secondly, by an unfortunate accident of history, the rise of industry and technology coincided with a decline of the status of mathematics as an integral part of our culture, a decline that has been faithfully reflected in the change of the general education curriculum. This is not the place to decide which party is to be blamed for this cultural isolation of the mathematician; here we should recognize the fact that today the mathematician has been relegated to his intellectual ghetto and that the public at large, including scientists like physicists and chemists, is no longer at ease with mathematics.

Thirdly, around World War II, the general perception of mathematics has been further distorted by the spectacular applicability of a few very special mathematical theories, such as linear programming, the theory of games and economic behaviour, and the finite-element method, to mention just a few. In the industrial mind —and also in the egalitarian mind of the socialist— mathematics was reduced to a (small) number of useful methods to be applied by who cares whom, provided he has been trained to apply the method. The view of mathematics as the art and science of effective reasoning has been completely lost in the process.

The distorted picture of mathematics as a collection of methods is widespread. From a managerial point of view it is of course a nuisance that trained people are still needed to apply these methods and the next goal of management has become to have all mathematical competence safely canned in a number of software packages. The high expectations of such software are widespread; but the popularity of the idea is the fruit of managerial misunderstanding of what mathematics is about and says nothing about the merits of the idea.

The distorted picture also affects the class-room: many students don’t want to be shown effective patterns of reasoning, they wanted to be told what to do. They have been trained to expect another mathematical cookbook , automatically read general guidelines as recipes that are supposed to suffice for the next exercise (something they —of course— rarely do). They expect a so-called “complete methodology”, with each next exercise carefully tailored to the potential of the preceding example and complain when they don’t get what only the quack can provide. [We just addressed a bunch of industrial computing scientists, and the above phenomenon was alarmingly pronounced.]

*             *
*

I think there are two morals to be drawn.

The first moral concerns the interface between society as user and the educational business as supplier of trained intellect. Prior to the advent of the high-technology industry there may have been a period during which that interface was relatively stable, society knew what to expect from university graduates and the universities knew what to aim for. Whatever that interface may have been, one thing is certain: since the advent of the high-technology industry that old interface is no longer adequate. In the high-technology industry now emerges the need of high quality standards way beyond what educational practice has ever envisaged. (To give but one example: the grading of student papers is done along an elaborate scale of error levels, whereas in many a new technology the grading is simply binary, viz. flawless or flawed.)

In adjusting the interface there is the danger of deadlock, viz. of industry ignoring the required quality standards because they are considered “unrealistic” in view of the level of the average university graduate and of the university receiving only disincentives to raise the quality. I see no way out before industry takes its technical troubles seriously; the courage to rely on competence will then come almost unavoidably.

The second moral pertains to the academic enterprise, which is sometimes tempted to apply “acceptance in the real world” as yardstick for the significance of scientific work. The second moral is that the application of that yardstick is lethal. As long as the “real world” sticks to the manager’s dream —and even continues to do so long after the dream has turned into a nightmare— that mediocrity suffices, its value had better be ignored on campus. When what society asks for coincides with what society needs and academia can provide it, the latter’s position is easy. Today we have a conflict: society needs competence and asks for quackery (automated or not); in a sad way academia has the last word: it can provide both.

In any large organization, mediocrity is almost by definition an overwhelming phenomenon: the systematic disqualification of competence, however, is the manager’s own invention, for the sad consequences of which they should bear the full blame.

                                                      Nuenen, 14 June 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Fri, 28 May 2010

EWD968

Trip report E.W.Dijkstra, Marktoberdorf, 29 July - 10 Aug 1986.

With speakers from half a dozen nations and participants from two dozen, we formed a mixed lot; observing the different national prejudices and inclinations was both amusing and frightening. People from (sub)cultures in which topic X is well-established tended to show the attitude: "What Computing Science is really about is X.", and for X you may substitute: predicate calculus, typed λ-calculus and mathematical foundations, logic, denotational semantics, category theory, mechanization, or algebra. and, of course these views are all terribly incomplete and one-sided, no matter how consistent each of them may be in isolation. Personally I was relieved to see that my own X —viz. "the mastery of complexity"— is pretty broad. (That is probably why it has served me reasonably well for more than two decades.)

Besides these technical differences, the participants had to cope with different educational philosophies; and so had the lecturers, who were blamed for their diversity. These differences were made the more confusing as they remained under the surface.

Crudely stated, the educational dilemma is whether we are aiming for (A) maximum competence, or (B) maximum number of graduates. In idealistic theory it need not be a dilemma —each student trained to his ability, etc.—, in practice it is: if essential topics or techniques are beyond the sophistication or intellectual energy of some students, view A blames those students (and tries to get them removed), while view B blames the topics (and tries to get them removed).

The dilemma surfaced in different ways. In the coach on our way back from the Boarding School to Munich, Richard S.Bird, temporarily representing view B, wondered whether we had not been confusing by collectively exposing the participants to five different notations for concatenation: would not it have been better if we could have settled upon a single one? Having seen the damage done to students for whom LISP is the only vehicle towards formality, I found myself arguing that the danger of becoming "mathematically monolingual" was far worse.

It also surfaced in the different appreciations of Gentzen's "Natural Deduction", designed to model how people "actually conclude" and "therefore", according to Gentzen, most appropriate in the classroom: it appeals to the student's intuition, it comes quite naturally, etc. (From my mouth you will never hear "intuitive" or "natural" used as recommendations.) It is quite possible that, half a century ago, Gentzen never envisaged large-scale applications of formal techniques. In any case he missed that a major virtue of formalisms can be to free us from the shackles of our native tongues and the reasoning habits induced thereby. The message that in actual usage Natural Deduction is a by now well-documented pain in the neck was not universally welcomed. [It could very well be that Natural Deduction has been used to try to make view B scientifically respectable.]

It also surfaced in the different judgements of the potential of formal techniques. Repeatedly we heard —declared as dogma— that the application of formal techniques was too laborious and tedious to be of any practical value. Typically, such noises came from people that had never tried to apply formal techniques in real earnest, and I got the impression that the dogma is also used as an excuse for not trying. They were the people that were not attracted at all —to quote E.T.Bell re formalization— by "the loss of the privilege of making avoidable mistakes". They were also the people that had the greatest difficulty in hearing high-technology's clearest message, viz. that designs now tend to be judged along a very simple binary scale: flawed or flawless.

The educational dilemma was manifest, and nobody, I observed, had swept it as far under the rug as the British. [The other day, back home in Austin, I read in the (British) weekly "Computing" of the indignation caused by the immoral suggestion of "merit pay". No wonder that that economy is in trouble.]

*                 *
*

I noticed an interesting linguistic shift. A well-known form of rabid anti-intellectualism used to be betrayed within a few minutes by the speaker's appeal to "the real world". But no more! The real world is no longer fashionable; it is now "out there". Apart from the change in terminology, nothing has changed: an appeal to "out there" betrays, again within a few minutes. the speaker's same rabid anti-intellectualism. (More is happening, but that I only have from hearsay: one of my academic colleagues was approached by people from British industry because they wanted to know "what was going on in the real world". Are they beginning to suspect that the computer industry so far has been a world of make-belief?)

I also found confirmed that satire is very hard to practise, because, no matter how good you think you have been at it, it takes reality no time to overtake you.

Early during the Summer School we had a Grill Party at Auerberg. At my table we spent some time stringing buzzwords together so as to concoct the theme for the 1988 Summer School. So, when a few days later over a beer someone asked me whether the next Summer School's theme had been decided, I could give him an instant reply "Non-monotone belief-based conflict resolution". One of the participants swallowed it hook, line and sinker and declared that he was very keen on attending that Summer School as well.......

In my speech after the Farewell Dinner I divulged among other things that I was in the process of founding "The International Institute for the Cultivation and Conservation of Artificial Complexity". Alas! The other day I read the announcement of "Software Engineering '86", a conference organised by the British Computer Society and the Institute of Electrical Engineers in conjunction with the Alvey Directorate at the University of Southampton, 10th-12th September 1986. There will be four parallel streams:

Software Engineering for Information Processing
Formal Methods in Software Engineering
Software Engineering for Real Time Systems
Software Engineering for Artificial Applications.

(I am not kidding!)

*                 *
*

The audience was at least as mixed as usual. In the beginning I congratulated ourselves because it took a remarkably short time to loosen them up and to get a discussion going. But I got disenchanted because the number of people participating in the discussions remained very small: we kept hearing the same voices and eventually the discussions became boring. The others one met during lunch, dinner and excursions; eventually I had to admit —am I ageing?—that too large a fraction was dull or vulgar.

Of my seven lectures, two were failures (at the first slots in the morning after the Grill Party and the Farewell Dinner). I did predicate calculus, derived proofs about extreme solutions and explained Batcher's Baffler. I liked my proof derivations most, the audience preferred Batcher's Baffler.

Of the other speakers, I liked the lectures of Richard S.Bird most. He showed a calculus in which he derived all sorts of programs computing functions on sequences. Both his derivations of programs and his proofs of theorems were very calculational. The fascinating thing was that he could justify almost all steps with "There is really only one thing you can do." It was a very convincing demonstration of the heuristic value of formalization.

Tony Hoare was the most controlled speaker: his visuals were beautifully prepared and he knew exactly how many minutes each would take. He talked about his Communicating Sequential Processes and he cannot be blamed that I had seen most of it (several times). But I am beginning to have some doubts about his topic, doubts that were reinforced by the observation that he continues to talk very operationally. I am no longer sure that today the concept of a process deserves such a central position in our thinking.

The lectures by Manfred Broy and Gérard Huet were very similar in that their visuals were totally inadequate and that, during their first five lectures, they snowed us under. During their last lectures the general reaction was "Oh, was that what you were trying to talk about! Why did not you start at the end?". I hope and think that Huet's material can be cleaned up considerably: the outcome could be a very nice, clean and small logic.

Cliff Jones and Rick Hehner were both clear and articulate, and that was greatly appreciated. Both of them sometimes seemed to make too much of a point of too little; neither of them was entirely happy about his performance. Do they suffer from the wrong kind of students?

J.Alan Robinson was fun to listen to, but the way in which he talked about resolution clearly betrayed that it had been conceived 25 years ago. I intended to use the nine-hour train trip from Munich to Eindhoven to study his handouts and to come home understanding all about resolution. His text, however, was so unsatisfactory that I gave up by the time we approached the German-Dutch border.

Listening to Michel Sintzoff was a unique experience. His first talk contained more half-uttered hints at analogies than clear statements, later it became clear that the analogies were daring. He then became very graphical, which put me off.

About the remaining speakers I can report very little.

*                 *
*

For me the Summer School was instructive. It gave me a survey of what different groups are trying; personally I found most inspiration (and confirmation) in Bird's work.

By accident I picked up another example of how people are "formed" by the instruments they use. Over a beer I posed a geometrical problem†), for which a very elegant solution can be worked out without pen and paper. Huet, who has worked for the last ten years on mechanical proof verification, translated the demonstrandum into a long, clumsy formula full of goniometric functions and concluded with "And now it is decidable", confirming my fear that a lot of the manipulation delegated to machines is perfectly avoidable.

I was struck by the immaturity of the audience. One expects from budding scientists that they believe that science may serve a purpose, one expects from budding computing scientists that they believe that computers may serve a purpose. But I do not expect full acceptance of the dogma that under all circumstances "computerization" is a great improvement: doubting the dogma was treated as heresy. The sore truth is that the audience had been brainwashed.

†) | Consider k points equally spaced around the perimeter of a circle with radius = 1 and the chords drawn from one of those points to the others. Show that the product of the lengths of those k-1 chords equals k.

prof.dr.Edsger W.Dijkstra                          17 Aug. 1986
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750-1188
United States of America

transcribed by Tristram Brelstaff
revised Fri, 28 May 2010

EWD973

The cosine rule

I realized that I had completely forgotten how the cosine rule was proved at school. So I found myself thinking about the design of a proof. In the usual terminology the cosine rule states

(0) | c² = a² + b² - 2·a·b·cos.γ

A simple proof observes

(1) | c = a·cos.β + b·cos.α | and
(2) | 0 = a·sin.β - b·sin.α

(the latter is the rule of sines; it follows from a·c·sin.β = b·c·sin.α, both sides equalling twice the area of the triangle). Squaring both sides of (1) and (2) and adding yields (0) —using

(3) | cos.γ = - cos.(α+β) | since α+β+γ = π,
(4) | cos.(α+β) = cos.α·cos.β - sin.α·sin.β

So far so good. Then I tried to derive this proof in a more orderly fashion. So I started with the right-hand side. Application of (3) for symmetry's sake yields

| a² + b² + 2·a·b·cos.(α+β)

and since (4) is the only thing we know about cos.(α+β), its application readily yields

| a² + b² + 2·a·b·( cos.α·cos.β - sin.α·sin.β )

Just remembering "sin² + cos² = 1" suffices to make you try to rewrite this as a sum of squares. But there is a snag! The expression being symmetric in α and β, it also admits the decomposition

| (a·cos.α + b·cos.β)² + (a·sin.α - b·sin.β)²

a decomposition that leads nowhere. An "honest" derivation considers both alternatives, at least as long as we don't wish to pull (1) or (2) out of the magician's hat.

The alternative is not to start with the right-hand side of (0) but with (0) and (1). Squaring the latter, subtracting the result from (0) and simplifying reduces the proof obligation to the rule of sines:

| (a·sin.β)² + (b·sin.α)² - 2·a·b·(cos.γ + cos.α·cos.β)
= { (3) }
| (a·sin.β)² + (b·sin.α)² + 2·a·b·(cos.(α+β) - cos.α·cos.β)
= { (4) }
| (a·sin.β)² + (b·sin.α)² - 2·a·b·sin.α·sin.β
= { algebra }
| (a·sin.β - b·sin.α)²
= { rule of sines }
| 0.

This is a proof of the type "there is really nothing else you can do", but for that, we had to start with (1) so as to be steered away from the barren decomposition.

Austin, 4 September 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Martijn van der Veen.

Revised Fri, 28 May 2010.

EWD 974

The longer side is opposite to the greater angle

The introductory chapters of texts on Euclidean geometry are traditionally fishy as Euclid’s axioms don’t really suffice. This treatment of the theorem mentioned in the title is no better, but may have the advantage of displaying its incompleteness quite openly.

Let α > β.

I need the postulate that a given geometrical figure —and its “mirror image”, whatever that may be!— can exist everywhere in the plane with the same internal measures. Then we can place the mirrored triangle Aʹ BʹCʹ with Bʹ =A and Aʹ =B and Cʹ at the same “side” —do we know that a straight line divides the plane into two parts?— as the base. The final postulate should guarantee that, since α > β, BC and BʹCʹ intersect in an interior point of these segments. Once you have swallowed all that, the rest is easy.

AC |   <   | Bʹ S |  +  | SC |  | (Euclidean axiom)
AʹCʹ | < | BS | + | SCʹ |  | "
AC + AʹCʹ | < | BC | + | BʹCʹ |  |

But also AC = AʹCʹ and BC = BʹCʹ, hence AC < BC.

The latter part of the argument is nice, because it does not require that △ASB is isosceles.

All that has to be swallowed holds on the sphere as well, but the characterization of the straight line connecting two points as their shortest connection is on the sphere dubious; so is the theorem, so that is fine.

Is there a workable axiomatisation of the Euclidean plane, so that we could really do geometry without pictures?

So much for one more illustration of the fact that the use of pictures usually betrays that the author does not really know the rules of his game.

Strange: in my youth, Euclidean geometry was presented as axiomatised, deductive discipline whereas algebra was presented without any axioms. The other way around seems easier (possibly with the Church-Rosser property as unproved theorem).

Austin, 4 September 1986

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD975

On the theorem of Pythagoras

For the theorem of Pythagoras, I start from Coxeter's formulation ("Introduction to Geometry", p.8)

"In a right-angled triangle, the square on the hypotenuse is equal to the sum of the squares on the two catheti."

Let us play a little bit with that formulation. In a triangle with sides a, b, and c —different from 0 so as to make its angles well-defined— we introdue the usual nomenclature α, β, and γ for their respective opposite angles. (We introduced one angle name so as to be able to express right-angledness, and the other two for reasons of symmetry.)

A formal expression of Coxeter's formulation is

γ = π/2     ⇒     a² + b² = c2     .

Besides the nomenclature we introduced, this formulation contains the (transcendantal!) constant π. Fortunately we can eliminate it thanks to

π = α + β +γ     .

Elementary arithmetic yields the equivalent formulation

α + β = γ     ⇒     a² + b² = c2     .

Isn't that nicely symmetric? It immediately suggests —at least to me— the strengthening

(0)      α + β = γ     ≡     a² + b² = c2     .

(This will turn out to be a theorem.) We get an equivalent formulation by negating both sides:

α + β ≠ γ     ≡     a² + b² ≠ c2     .

But x ≠ y   ≡   x < y   ∨   x > y , and the latter disjuncts are mutually exclusive. Remembering that the larger angle is opposite to the larger side, is it bold to guess

(1)      α + β < γ     ≡     a² + b² < c2                               and
(2)      α + β > γ     ≡     a² + b² > c²                  ?

Bold perhaps, but not unreasonable.

Note that (0), (1) and (2) are not independent: from any two of them, the third can be derived. They can be jointly formulated in terms of the function sgn —read "signum"— given by

sgn.0 = 0     ∧     (sgn.x =1   ≡   x > 0)     ∧     (sgn.x = -1   &equiv   x < 0) ,
viz.        sgn.(α + β - γ)    =    sgn.(a² + b² - c²)     .

Consider now the following figure. We have drawn

the case α + β < γ, in which the triangles ΔCKB and ΔAHC, of disjoint areas, don't cover the whole of ΔACB; denoting the area of ΔXYZ by "XYZ" we have in this case

CKB + AHC < ACB     .

In the case α + β = γ, H and K coincide and we have

CKB + AHC = ACB     ,

and in the case α + β > γ, the two triangles overlap and we have

CKB + AHC > ACB     .

In summary

sgn.(α + β - γ) = sgn.(CKB + AHC - ACB)     .

The three areas of the right-hand side are those of similar triangles and hence have the same ratios as the squares of corresponding lines, in particular

CKB/a² = AHC/b² = ACB/c² > 0     ;

hence

sgn.(CKB + AHC - ACB) = sgn.(a² + b² - c²)     ,

Hence we have proved

sgn.(α + β - γ) = sgn.(a² + b² - c²)     ,

a theorem, say, 4 times as rich as the one we quoted from Coxeter.

*            *
*

The title of this note could make one wonder why I would waste my time flogging a horse as dead as Pythagoras's Theorem. So let us try to summarize what we could learn from this exercise.

•    Three cheers for formalization! Instead of setting out to prove a² + b² = c² for a right-angled triangle, we included the antecedent γ = π/2 in the formal statement of what was to be proved. It was only after the introduction of π that we could eliminate it and met the "nicely symmetric" formulation.

•   Three cheers for the equivalence! It makes quite clear that the theorem is not about right-angled triangles, but about triangles in general.

•   Three cheers for the notational device captured in sgn. If we had not been careful, we would have ended up proving

(α + β) R γ    ≡    (a² + b²) R c²

for R any of the six relations =, ≠, <, ≤, >, and ≥

•   No cheers at all for that stage of the argument in which lack of axiomatization forced us to resort to a picture. Pictures are almost unavoidably overspecific and therby often force a case analysis upon you. Note that I carefully avoided the pictures for α + β > γ; there are 9 of them: K to the right of A, coincident with A, and to the left of A, and similarly for the pair H and B. For the argument these distinctions are irrelevant but, when drawing a picture, you can hardly avoid making them.

•   One of these days I would like to find a convincing explanation of the circumstance that youngsters continue to be educated with the theorem of Pythagoras in its diluted form as quoted from Coxeter. Notice that the 9 figures could have been avoided by also proving

CKB + AHC < ACB      ⇒      α + β < γ          and
CKB + AHC = ACB      ⇒      &alpha + β = γ     ,

i.e. proving (0) and (1) in full.

•   Notice that our figure was not pulled out of a magicians hat! As soon as sgn.(α+β–γ) occurs in the demonstrandum, it is sweetly reasonable to construct that difference. In order not to destroy the symmetry between α and β, one starts with γ and subtracts α at the one side and β at the other:

and this is the germ of the figure we drew.

Epilogue. I am in a paradoxical situation. I am convinced that of the people knowing the theorem of Pythagoras, almost no one can read the above without being surprised at least once. Furthermore, I think that all those surprises relevant (because telling about their education in reasoning). Yet I don't know of a single respectable journal in which I could flog this dead horse.

Austin, 7 September 1986

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

Transcription by Joel Hockey
Last revised on Thu, 27 May 2010.

EWD976

Who is your “target audience”?

“No one can write decently who is distrustful of the reader’s
intelligence, or whose attitude is patronizing.”

E.B.White in The Elements of Style, Strunk and White

The other day I had used as my quotation the notice from the Pool Committee: “Texas State Law requires that children under 14 years of age must be accompanied by an adult.” as a starter for dissecting that horrible corollary in “What is Mathematics?” by Richard Courant and Herbert Robbins:

“If a prime p is a factor of the product ab, then p must be a factor
of either a or b .”

Needless to say, that formulation was demolished. (I think we ended up with something like “A prime dividing the product of a bunch of integers divides at least one of those integers.”. I did not include the transition from implication to equivalence, because that is for later. This time we focussed on formulation.) One of my students felt urged to defend Courant/Robbins, and asked “But what was their target audience?”; in doing so he touched a raw nerve and unleashed a passionate sermon on the crime of contempt of readership. I quoted —only approximately— E.B.White and promised him a copy of The Elements of Style.

*                                *
*

If your text is going to be studied by 60 people and by pondering almost an hour about a turn of phrase that saves your average reader more than a minute, your hour has been well-spent. Your text should be as easy to read as possible. But that measure of “easiness” should be relative to what you have to say and not relative to the length of your text. So, if you aim for “easiness” by making your text needlessly verbose or repetitious, you are cheating. If you are sweeping difficulties under the rug by hiding them in vagueness —while a crisp formulation would reveal them— you are cheating again. There is only one respectable way of improving your text, viz. by being as clear as possible.

All the general advice about writing —such as “Omit needless words.”— is applicable, and most of it can be found in the general literature. Mathematical texts, however, pose their special problems.

Check all your sentences for ambiguity! And if it really matters, ask a non-specialist to read your text to see whether it makes sense. It is really more tricky than you think: in Boeing airplanes one can find a notice saying that something has to be locked “during take-off and landing”, which is funny as soon as you realize that you have to stop for a school bus “while loading or unloading of passengers”.

Think very hard about the choice of identifiers! Avoid if possible one-letter identifiers that are all by themselves words in the language of the surrounding prose, such as “U” in Dutch and “a” and “I” in English, as they may confront you with unpleasant surprises. (There is a page by David Gries, in which “I” occurs in three different roles: as personal pronoun, as identifier for an invariant and as Roman numeral! Of course, the reader can sort this confusion out, but it is better avoided.)

Be explicit in all your references to earlier theorems: give the number and don’t require from your reader to solve an avoidable puzzle. If you instantiate a formula, again, don’t present a puzzle, but state explicitly the substitution.

Never assume the meaning of a technical term known if you can give it in a single sentence: the reader that knows the term skips that explanation effortlessly, whereas its absence could present a major stumbling block for someone else.

Indicate clearly the logical status of the paragraphs in your text. The other week I struggled with a text in which the author stated a mathematical fact (that was new for me). For a long time it was quite unclear to me whether I was supposed to provide the proof myself, because the next paragraph just continued with further consequences and considerations, or whether the subsequent paragraph was the proof of the preceding fact. (The situation was aggravated by the fact that the text referred alternatingly to two different pictures. It was most confusing. And all that confusion was so avoidable! I got quite cross with the author.)

*                           *
*

Never to write down to your readership is for the computing scientist even more important than for any other scientist. When computers became a commercial product it was essential for industry that its sales force presented these machines as non-mathematical machines that could be used by any one. As a result of these commercial campaigns, research in computing science has been paralyzed by the “rule” that nothing you ever tried should be too difficult for “the average programmer”. Slowly —at least at the better universities— computing science research is digging itself out of that hole. But we should all be aware that publication practice has a greater inertia. We should make a conscious effort to stop writing for morons. As a science, computing cannot be expected to mature as long as its practitioners don’t take each other seriously.

Austin, 10 September 1986                        

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750
United States of America

transcribed by Mario Béland
revised Thu, 27 May 2010

EWD977

An address to my students (16.9.1986)

Last week, one of you asked me how I felt about a certain editing/type-setting system and I essentially evaded the answer, saying “Well, that is another story.”. Here is that story. It is not about that specific system, of which I am ignorant, but about utility in general.

One cannot identify with a cause without to a reasonable extent believing in it. From a medical student, for instance, one expects for instance the opinion and attitude that curing the sick —if you can do it— is a good thing that is worth doing. And for the medical freshman, such an opinion suffices. But by the time he approaches his graduation, one expects from him a much more subtle opinion that recognizes the circumstances in which a graceful death is the only effective cure. Most physicians reach that state of professional sadness and wisdom, if not before their graduation, then shortly thereafter. Also, as a rule, they don’t talk about it in public, not because they are ashamed of it but because society as a whole still thinks euthanasia too painful a topic to be discussed in public. So much for the medical profession.

What about the student of computing science —or “computer science” as it is called in this country—? One expects from him the opinion and attitude that the mechanical manipulation of bits of information is potentially a great thing, freeing us from the drudgery of all sorts of routine jobs and enabling us to do all sorts of wonderful things that would be absolutely impossible without automatic computing. And in the case of a freshman one does not even object when he includes among wonderful things “putting, at your expense, a clown on the moon”.

By the time, however, that the student of computing science approaches his graduation, or otherwise very shortly thereafter, one expects a more subtle opinion that recognizes the circumstances in which computerization is nothing but transistorized snake oil. They are many, and at later occasions I may discuss a number of specific instances. Let me conclude this address by one disturbing thought, viz. that society tolerates the computing profession because of its incompetence. It is our incompetence that makes us, though expensive, relatively harmless: were we as competent as we would like to be, we could offer the perfect implementation of the complete police state. We would be the darlings of any dictatorship.

Austin, 14 September 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

transcribed by Mario Béland
revised Thu, 27 May 2010

EWD 978

A sequel to EWD977 (18.9.1986)

I regard the computing community as a collective victim of the computer salesmen. Take, for example, the word processor.

In this country, where the Protestant work ethic is predominant, everyone feels good if he is busy and as a result it was possible to sell the word processor as a time-saving device. The irony of the situation is, however, that, as a commercial product, the word processor was so successful because, in actual fact, its usage costs time; as a result, it makes its user even more busy and feeling even better. It is the ideal tool for those that can confuse activity with work.

I have often been asked why I don't use that type of equipment, and my honest answer has always been that there is for me so much to write that I cannot afford the use of these time-saving devices. The reactions range from disbelief to anger.

The experiments have been taken with people that were both experienced writers in longhand and experienced users of word processors. The outcome was, firstly, that the linguistic quality of the mechanically produced letters was not noticeably lower than that of the hand-written ones, and, secondly, that they had taken 50% more time to be written. I concluded that probably no country can afford the human cost involved in widespread use of such equipment. And indeed; the other week I heard of a recent analysis why American industry has such a poor performance and a main cause turned out to be the low productivity of the white-collar workers, a low productivity that could be traced to over-automation of the office. I was not amazed.

I also know why that equipment is so time consuming to use: it is so easy to make a change in your text. It is an open invitation to write first, and to correct and improve later. I know that some schools of English composition even promote that form of iterative design as the one and only viable paradigm for writing. But I think that that is very short-sighted because in the longer run it is much more effective to train oneself to get one's text almost always right the first time.

I think these machines should carry a notice saying: "Warning! The Educator General has determined that electronic word-processing is detrimental to your writing proficiency.".

Austin, 15 September 1986.

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Hasnain Mujtaba
revised Thu, 27 May 2010

EWD979

A solution designed by A. Blokhuis

Consider all the chords between n distinct points on the perimeter of a circle, the points having been chosen such that each point inside the circle lies on at most 2 chords. Into how many regions is the area inside the circle divided by those chords?

The guess that for n = 5 the number equals 16 is correct; for n = 6, the number equals 31. (It is a very convincing example of the inadequacy of what is known as "Poor Man's Induction".)

*      *      *

The following argument derives an expression for the number of regions as a function of n.

In an effort of disentanglement we try not to use all our data simultaneously, in particular we temporarily ignore that eventually we will deal with all chords between n points. What can we say about the number of regions when a number of chords has been drawn?

Let us draw another chord:

Let       | R = the number of regions
| C = the number of chords
| I = the number of intersections inside the circle

and let us investigate the relation between their increments for the case

ΔC = 1 ;

ΔR is the number of segments into which the new chord is divided by the others, which is one more than the number of its intersections, i.e.

ΔR = 1 + ΔI ;

from the above we derive

ΔR = ΔC + ΔI ;

and, since I = 0 and C = 0 corresponds to R = 1, by induction over C

R = 1 + C + I .

So we are done if we can determine C and I.

This is the moment to remember that we were considering n "peripheral" points and all chords between them.

Each chord determines two distinct peripheral points, and vice versa, hence

C = (
n
2
)

.

Each intersection, by determining two distinct chords, determines 4 distinct *) peripheral points, and vice versa **), hence

I = (
n
4
)

.

*)  | Intersecting each other already inside the circle, the two chords don't share a peripheral point.
**)  | For any 4 peripheral points, only 1 of the 3 possible pairings leads to chords intersecting inside the circle.

So  

R = 1 + (

n
2
) + (
n
4
)

.

Since   

(
n
k

) = (

n – 1
k – 1

) + (

n – 1
k
)

,   we can rewrite

R = 1 + (
n – 1
1
) + (
n – 1
2
) + (
n – 1
3
) + (
n – 1
4
)

,

i.e. the sum of the first 5 entries of a line of the triangle of Pascal. The full lines adding up to the successive powers of 2, we now understand the misleading observations with which this note started.

The above argument is due to A. Blokhuis.

Austin, 16 September 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

transcribed by Martijn van der Veen
revised Thu, 27 May 2010

EWD980

The strange case of The Pigeon-hole Principle

If you come to think about it, The Pigeon-hole Principle presents a case that is curious in more than one respect.

It has a remarkably high status: it has a special name, under which it is well-known; Ross Honsberger even calls it "A fundamental tool of combinatorics".

It is surrounded by some mystique. Proofs using it are often regarded as something special, something particularly ingenious. This feeling of awe is, for instance, nicely reflected by Honsberger when he concludes one of his examples with "(Another triumph of the pigeonhole principle.)".

Its usual formulation is —as we shall see in a moment— unfortunate. Let me quote Honsberger once more —there is nothing special about me quoting Honsberger all the time: one of his books just happens to lie on my desk—:

"if more than n objects are distributed into a set of n compartments, some compartment must receive [ for "must receive" read "receives", EWD] more than one of the objects."

(Instead of "more than n" one often encounters the more specific "n + 1".)

My feeling is that these three observations are not unrelated.

*      *      *

To begin with, let me formulate the Purified Pigeon-hole Principle (PPP):

"For a non-empty, finite bag of numbers, the maximum value is at least the average value."

It is a generalization, because in the old formulation, it would be (OFPP)

"If more than n·k objects are distributed into a set of n compartments, some compartment receives more than k of the objects."

I think it is illuminating to analyze the differences between those two formulations (in what I consider increasing order of seriousness):

PPP does not mention n and k explicitly; this eases the application, because the conscientious application of OFPP would require explicit instantiations of n and k.

OFPP is very operational; it would have been less so, had "are distributed" and "receives" had been replaced by "have been distributed" and "contains" respectively. The metaphor drags a process into the picture, where only the final state matters. (This is really serious, for what if "the objects are already in the compartments"? Well, of course we could have put them there, but then some people feel obliged to argue that we could have done so in "arbitrary" order: irrelevantia in the formulation of a theorem have the awkward consequence that the conscientious user of the theorem has to demonstrate their irrelevance.)

OFPP mentions "objects" and "compartments", things that have nothing to do with the theorem. I know that some people believe that the introduction of such things "ease the visualisation", but I think the price too heavy to pay. When dealing with natural numbers, we should be able to deal with them in their own right and not be forced to introduce "objects" counted by them! (It is really like representing natural numbers in a unary number system, with the well-known difficulty of "the invisible zero".) Also, one may have to invent "compartments" that don't "look" like compartments at all. The "mystique" of the Pigeon-hole Principle is partly due the sometimes surprising invention of "objects" and the "compartments".

*      *      *

Let me now relate to you two stories about the Pigeon-hole Principle that both amazed me; for me —but perhaps I am sensitive to the point of allergy— they suggest that the traditional Pigeon-hole Principle is a focal point of how mathematics is (but not should be) taught.

A few weeks ago I was told "The Problem of the Soccer Toto". (Not knowing the rules of the soccer toto, I got the explanation; for your benefit I shall repeat them.)

On a given Sunday, 13 soccer matches will be played. Each match has one of three possible outcomes, denoted by "1", "2" and "X" respectively. Hence there are 3¹³ possible Sundays. For our purpose "Sunday" will be one of those 3¹³ possible "columns" of height 13, with in each line one of the three permissible entries 1, 2 or X.

A toto form consists of a row of blanc columns of height 13; its user is free in his choice of the number of columns he is going to fill in. The question is to devise a strategy for filling in the minimal number of columns so that at least 1 column coincides with Sunday in at least 5 entries. Here we go.

Forget about the 5: what if at least 1 column should coincide with Sunday in at least 1 entry? Two columns won't do, for Sunday then could contain for each line an outcome missing in the corresponding line of the toto form. With 3 columns such that at least one row contains all three outcomes, at least one coincidence —in that row— is guaranteed. So far we needed 3 columns and have used only one row. Can we use the remaining 12 rows to increase the score? By filling those each with some permutation of the three outcomes, we force in each row precisely one coincidence with Sunday. Make in each column the count of coincidences: their sum being 13, their average is 4⅓. and their maximum (PPP) is ≥5. End of argument (heuristics included). Notice that there was no need at all to interpret the form as a table defining how, indeed, each object (=match) was placed in one compartment (=column).

But suppose that the question had been different: given a form in which 4 columns have been filled in such that each row contains each of the three possible outcomes, can you show that at least 1 column coincides in at least 4 entries with Sunday? Now the total number of coincidences is ≥13, the average count is ≥3¼, and hence the maximum count is ≥4. Please notice that in this case the metaphor of putting objects (=matches) into compartments (=columns) creates problems: an object may "occupy" two compartments! (It is utterly predictable how the average mathematician will save his face: "Sure! If generalize the problem, I don't take the matches but the coincidences as my objects! I would have done so right at the start, would I have known that you would generalize the problem!") So much for the avoidable obligation of identifying the "objects".

But now the sad part of the story. The colleague that posed me this problem had been challenged with it by one of his graduate students. When we met again he was utterly amazed to hear that the problem could be solved without pen and paper, and when I told him my solution, he looked so puzzled that I am not sure he understood it. "Of course I know the Pigeon-hole Principle, but I never.....", and then wandering thoughts prevented him from completing the sentence. Was he still looking for the objects and the compartments? The way he had been introduced to the principle and all the imaginations that went with it was obviously a barrier to its straight-forward application. I felt that I had had a glimpse of something frightening.

The second story concerns my preparation of a lecture on the Pigeon-hole Principle: I wanted to show my students the most spectacular application of it I had ever encountered. I scratched my memory, and then I remembered: the lower bound for the length of the longest monotonic subsequence! I remembered my thrill, but had forgotten the argument, which I then set out to construct.

Let me state the problem first. We consider a sequence of numbers a.i with 0 ≤ i < N. We get a subsequence of length n by removing some N - n elements from the sequence and retaining the remaining ones in their original order. It is called "an upsequence" provided for any a.i and a.j in the subsequence we have

i < j ⇒ a.i ≤ a.j ;

in the case that we have

i < j ⇒ a.i ≥ a.j ;

it is called "a downsequence".

Let U be the length of a longest upsequence contained in the given sequence, and let D be the length of a longest downsequence contained in it. Prove that N ≤ U·D holds.

The argument I came up with went as follows. Let us construct U·D different labels; if we can now devise a regime that assigns to each element a distinct label, then N —being the number of labels used— is at most U·D —being the number of labels available.

How do we construct U·D different labels? The simplest way I can think of is all the integer pairs (u,d), with 1 ≤ u ≤ U and 1 ≤ d ≤ D. How do we devise a regime that assigns for i < j different labels to a.i and a.j? In order to relate the regime to up- and downsequences, we observe

i < j ⇒ a.i ≤ a.j ∨ a.i ≥ a.j

i.e. a.j can be used to extend either an upsequence or a downsequence ending at a.i. This observation reveals the regime: assign to a.i the pair (u,d) with u (and d) the maximum length of an upsequence (and a downsequence respectively) that ends at a.i. This guarantees

that distinct elements get distinct labels

that each label (u,d) needed satisfies 1 ≤ u ≤ U and 1 ≤ d ≤ D.

I was quite pleased with the reconstruction of this argument, until I realized that what used to be "a triumph of the Pigeon-hole Principle" no longer used the Pigeon-hole Principle at all!

I could reintroduce an appeal to the Pigeon-hole Principle, but only by a contorted rephrasing. [ Identify the elements with objects, the labels with compartments; assume N —the number of objects— to exceed U·D —the number of compartments—; then —PP— at least one compartment would contain more than one objects, which contradicts that distinct elements get distinct labels. Hence N does not exceed U·D. ]

Remark It is in this connection noteworthy that no one I asked formulated the Pigeon-hole Principle as follows: " With objects distributed into compartments such that each compartment contains at most one object, the number of objects is at most the number of compartments". It is logically equivalent to the original formulation, but looks quite different. And that, presumably, is precisely the trouble. (End of Remark.)

With its physical, object-oriented formulation, the classical Pigeon-hole Principle is very vivid, almost catchy. And there lie precisely its major shortcomings: the problem caused by such object-oriented formulation is that A ⇒ B and the logically equivalent "counter-positive" ¬B ⇒ ¬A invite completely different visualisations. The moral of the story seems to be that we should sharply distinguish between good mathematics and public relations.

Austin, 19 September 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750–1188
United States of America

transcribed by Martijn van der Veen
revised Thu, 27 May 2010

EWD981

Address to my students (23.9.1986)

I was alarmed when I learned the other day that on the problem of the chords in the circle —EWD979— some of you had spent perhaps more than 24 hours. I am all in favour of dedication, enthusiasm, fascination and all those good things, but honestly, Ladies and Gentlemen, it was not my intention to inflict such a, long (and probably vain) struggle upon any of you.

Technically, this course deals with two distinct topics: the structure or shape of really sweet arguments, and the heuristics of designing such really sweet arguments. These are two totally different topics, and it is hard to be very explicit about the heuristics before we have a clear picture of the sweetness we are aiming for. I cannot deal with everything simultaneously. I gave you the problem before I had given you any advice in avoiding unproductive labour. I am sorry and apologize. I do hope, however, that the many hours some of you have spent on this problem have not been wasted: they should have driven home the message that, if you would like to become a more effective mathematician, there is something to be learned.

The most helpful thing I can do at this stage is probably to relay to you the advice I got from my mother —an accomplished mathematician— at the age of 16. During the Summer Holiday I bought my books for the next year, among which a book on trigonometry. All the formulae with all those Greek letters somewhat frightened me, and I asked my mother, whether trigonometry was difficult. "Oh no," she said, "learn the standard formulae as well as you learned the multiplication tables, and, never forget: if you need more than five lines, you are on the wrong track.". I think it is only fair to tell you that probably no other remark has made such a profound influence on me as a mathematician; I am a great lover of the solution that fits on the proverbial back of an envelope, and, unless stated otherwise, all problems I give you have such a solution.

At this stage I can give you some behavioural advice. Contrary to what misguided —and misguiding— educationists may have told you, don't waste your time looking at specific examples. Trying to come to grips with a large set by looking at a few —hopefully representative— elements of that set is one of the most ineffective ways of spending one's time. Go immediately for the general case, or, in other words, attack the set not by looking at specific elements but by analysing the definition of the set.

The second advice is never to resort to mechanical aids like pen and paper without feeling slightly guilty. Postpone that stage as long as possible, and if you have to resort to those aids, don't make a picture —because pictures, unless very carefully designed, are more misleading than helpful— and don't scribble. Write slowly and as beautifully as you can, and as little as possible; if you still write too much, try writing with your other hand. You see, the only reason for writing symbols on paper is to let them do the work! The side-effect of postponing the use of pen and paper as long as possible is that by doing so you force yourself to explore the simple possible solutions first.

Austin, 22 September 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

transcribed by Martijn van der Veen
revised Thu, 27 May 2010

EWD983

How do we contribute? (30.9.1986)

I know many scientists. Some of them are exceptionally mean, but the vast majority is honest and decent. They would like their designs, be they systems, methods or theories, to be used and their writings to be read. And they wish so not only for their personal gratification, but also because they would honestly like to be helpful and to contribute. Their eagerness that at least somewhere their work is accepted is in general more than mere concern about their careers, it is a genuine reflection of their feeling that, if it is ignored, they have failed to contribute. So far, so good. The danger, however, is to equate degree of acceptation as a measure of your success, or, even worse, as a measure of the quality of your work.

The reason is, that there is often a great discrepancy between what the world asks for and what it needs. The dilemma confronts the computing scientists in its crudest form: the magic of the giant brains or machines that think is still so strong that what the world asks for from them are Philosophers' Stones by the dozen and all other forms of transistorized snake oil. Some of our colleagues have been unable to resist the temptation: if the world asks for Panchromatic Concept Animation, Based on Deep-Structured 3D Intuition Nets, they dutifully produce Panchromatic Concept Animation Based on Deep-Structured 3D Intuition Nets. I trust that I don't need to argue that embracing so fully the morals of the bestseller society is tantamount to academic dishonesty in one of its severest forms.

But there are much subtler forms of the dilemma. What the world needs most, but never asks for, is improvement of its ways of doing things. But you know how the world is: of course it is greatly in favour of improvement, but on closer inspection it insists on improvement without change. [Such is, in particular, the greatest ideal of all managers.] As a result, many authors are rather reluctant to deviate too visibly from established practice and current conventions. It is a problem all of us face. Do we continue to start numbering at 1 instead of with 0, merely because that's the way we used to do it? Do we stick to that habit even though we know that adherence to it —e.g. via Fortran— costs the computing community conservatively estimated at least $100 million per year? Perhaps —I hope— it comes so "natural" to you to start numbering at 0 that you don't realize anymore that this change of convention has been a hot issue; if so, let me inform you that, a quarter of a century ago, adopting the new convention was enough to make you an outcast in the mathematical world. The problem of this deviation was that it was so visible.

Consequently, many scientists feel much more comfortable if they can have their impact incrementally, by steps so little that the public at large is not frightened by them. If feasible, such an approach can be defended as an effective strategy. But in this discrete world, such continuous transitions are often impossible: you can try to buffer the shock by eloquence and metaphors, but no matter how hard you try, there is no gentle transition from classical mechanics to quantum mechanics, nor to the theory of relativity.

The moral is obvious. If, for the sake of acceptance, you stay closer to the status quo than you would like to, your cautiousness might render you ineffective in the sense that you will not effectuate the more radical improvement you had in mind. The successful scientist fits in the future he is aiming for; in the present he is living in he is by definition a misfit.

Austin, 26 September 1986

transcribed by Martijn van der Veen
revised Thu, 27 May 2010

EWD 987

On a class of graphs with modest diameter

The diameter of a graph is defined as the minimum path length, measured in number of edges, that suffices to connect any two nodes. We confine ourselves to undirected graphs. (For the complete graph, the diameter equals 1, for a star it equals 2.)

For the n-dimensional “cube”, the diameter equals n, and so does the “fan” —number of edges meeting— of each node. Some time ago, Jan L.A. van de Snepscheut showed me how for n=3 the diameter could be reduced to 2 without changing the fan. Without proof he mentioned that under that constraint, the diameter could be almost halved (to n div 2 + 1). Looking for a constructive proof of that statement, I found another class of graphs with diameter almost n/3, and a smaller number of edges (²/₃); the maximum fan, however, is n+1. More precisely:
      for a graph of 2n nodes with n = 3�k + 2:
•     the diameter is k+3
•     half the nodes have a fan n+1
•     half the nodes have a fan k+2   .

The remainder of this note is devoted to a description of my construction.

*         *         *

As is to be expected, we identify our nodes by n-bit strings, parsed as a pair —called x—, followed by k triples —called the y’s—. From now on we shall call our nodes “strings”.

We only introduce connections between two strings that either

(i) | only differ in their x,       or
(ii)    | only differ in a single y.

The connection pattern for the 4 different x-values is given by

(The assignment of x-values to the four corners is immaterial; who wants to be specific may think of 00 at A, 11 at B, 01 and 10 each at a C-corner.) The important property of this graph is that each corner can be connected to each corner —i.e. including itself— by a path of length ≤ 3 and containing A, B, and at least one C-corner. Depending on its x, a string is called an A-string, a B-string or a C-string.

A pair of different y-values is an A-pair, a B-pair or a C-pair according to their bit-wise sum: for three values of the bit-wise sum (say 001, 010, and 100) it is an A-pair, for three other values (say 011, 101, and 110) it is a B-pair and for the last value (say 111) it is a C-pair.

Two strings, differing only in one y, have the same x, are thus both X-strings (with X = A, B, C); they are connected if and only if the two differing y’s form an X-pair.

The diameter of the resulting graph is k+3, as follows from the following algorithm for finding a path. Compare the y-components of the source string with the corresponding y-components of the target string. Wherever they differ, they form an A-pair, a B-pair, or a C-pair. In the worst case, they all occur. Choose in the x-graph a path from source x to target x containing nodes of all types needed: when the string is an X-string, all y’s where we found an X-pair can be transformed into their final value.

The A- and B-strings —together half of them— have a fan of 3�k + 3 = n + 1; the C-strings —the other half of them— have a fan k + 2. The total number of edges is therefore 2n-2�(n + k + 3).

Remark   We could have partitioned 7 bit-wise sums of two different y’s differently, e.g. 2 A-pairs, 2 B-pairs, and 3 C-pairs. For A-strings and B-strings the fan would have been 2�k + 3, for the C-strings 3�k + 2 = n. The total number of edges would have been 2n-2�(n + 2�k + 3). (End of Remark.)

Since the gain over the graphs mentioned by van de Snepscheut only materializes for larger n, and n occurs as exponent in the number of nodes, I do not expect my construction to be of any significance if nodes are machines. But it is nice to know that this construction exists, and it was fun to design it. (Describing it was just as hard as I had expected.)

Austin, 6 October 1986

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD 987a

On a class of graphs with modest diameter

The diameter of a graph is defined as the minimum path length, measured in number of edges, that suffices to connect any two nodes; we confine ourselves to undirected graphs, in which there is at most 1 edge between any two nodes. The degree of a node is defined as the number of edges meeting at that node; it equals the number of “direct neighbours” of that node. Note that summing the degree of all nodes yields twice the number of edges.

The complete graph has a diameter equal to 1; the diameter of a star equals 2. Their maximum degree, however, is almost equal to the number of nodes. We are interested in graphs with a much smaller degree and yet a modest diameter. A well-known example of such a graph is the n-dimensional “cube”: the degree of each of its 2n nodes equals n, and so does its diameter. (Label the nodes with n-bit binary numbers and connect any two nodes whose labels differ in 1 bit. Then, firstly, each node has exactly n direct neighbours, and, hence, has degree n, and, secondly, the length of a shortest path between two nodes equals the number of bit positions in which their labels differ, and, hence, the diameter equals n.)

In [0] it was shown how the 3-cube could be modified so as to reduce the diameter to 2 without increase —actually: without change— of any of the degrees; without proof it was mentioned that, without changing the degrees, the n-cube could be transformed into a graph with a diameter equal to (n div 2 + 1). Looking for a constructive proof of that statement, I found a class of graphs for which the diameter is reduced by a factor of almost 3 and in which the number of edges is reduced by almost ¹/₃; their maximum degree, however, is n+1. (See, however, the discussion of alternative constructions at the end of this note.) More precisely:
      for n of the form 3�k + 2 we construct a graph with 2n nodes such that
•     the diameter is k+3
•     half the nodes have degree n+1
•     half the nodes have degree k+2   .

The construction

We identify our nodes by strings of k+1 digits, more precisely: by 1 tetral (i.e. 4-valued) digit followed by k octal (i.e. 8-valued) digits. From now on we shall call our nodes “strings”.

We introduce edges only between strings that differ in precisely one digit. A path thus consists of a sequence of strings, each next string obtainable from its predecessor in the sequence by a one-digit modification.

In contrast to the n-cube, however, not every pair of strings that differ in one digit will be connected by an edge: this would yield a diameter of k+1 but, since the tetral digits can be modified into 3 other values and each octal digit into 7 other values, such freedom would imply for each string a degree of 3+7�k and would thus defeat our purpose of keeping the degrees small. We shall now detail which strings we connect by an edge. Strings differing in the tetral digit and strings differing in an octal digit will be dealt with separately.

The tetral digit   Whether two strings differing only in their tetral digits are connected by an edge depends on these two tetral values. We choose some way of assigning the 4 tetral values to the corners of the following “tetral connectivity diagram”

and introduce an edge between two strings that start with tetral values connected in the above and are otherwise equal.

The letters at the corners serve a later purpose of classifying strings according to their tetral digits: a string is an A-string, a B-string or a C-string according to the letter of the corner to which its tetral value is assigned.

The important property of the tetral connectivity diagram is that each corner can be reached from each —nor necessarily different— corner via a path of length ≤ 3 that contains A, B, and at least one C corner. (The specific diagram given is primarily an existence proof for a connectivity diagram with the property just stated.)

The octal digits   Whether two strings differing only in one digit are connected by an edge depends on the combination of the pair of differing octal digits and the common tetral digit.

For the purpose of this description we write our octal digits in binary (i.e. ranging from 000 through 111). A pair of differing octal digits is an A-pair, a B-pair, or a C-pair according to the bit-wise sum (ranging from 001 through 111) of (the binary representations of) the two octal digits of the pair: for 3 values of the bitwise sum it is an A-pair, for 3 other values it is a B-pair, and for the last value it is a C-pair.

The specific way in which the 7 values of the bit-wise sum have been partitioned in 3+3+1 is irrelevant. The important property is that keeping one octal digit fixed and letting the other one range over the 7 remaining values yields 3 A-pairs, 3 B-pairs and 1 C-pair. (The specific construction in terms of their bit-wise sum is primarily an existence proof of such a classification of pairs.)

Two strings differing in only one octal digit have the same tetral digit, and are thus both X-strings (with X = A, B, or C); we connect them by an edge if and only if the two differing octal digits form an X-pair.

And this completes the description of our construction of the graph, of which we shall now demonstrate that it enjoys the stated properties.

Proofs of the graph properties

The diameter   We show how to construct a sequence of strings, starting with a given source string, ending with a given target string, and such that each pair of successive strings in the sequence is connected by an edge of the graph.

To this end we first compare in the k positions the octal digits from the source string and the target string. In each of the k positions, we encounter 1 out of 4 situations: the two octal digits are equal —in which case the octal digit at that position remains constant— or the two digits form an A-pair, a B-pair, or a C-pair —in which case the octal digit in that position will change once (i.e. from initial value to final value).

So the path contains at most k edges whose traversal corresponds to the modification of an octal digit. But if source and target digit of such a modification form an X-pair, the corresponding edge is available if and only if the transition is between X-strings. Fortunately, the tetral digit can always be transformed from source value to target value in at most 3 steps so that all the string types needed for the octal modifications indeed occur in the sequence. So we never need to traverse more than k+3 edges; for k ≥ 2, that number may actually be needed.

The degrees   We determine the degree of a string by counting its direct neighbours.

Half the strings are A- or B-strings. From the tetral connectivity diagram we read that we can reach 3 neighbours by modifying the tetral digit. Since in an A- or B-string each octal digit can be changed into 3 other values, we can reach 3�k neighbours by modifying an octal digit. Since all these neighbours are different, A- and B-strings have degree 3�k + 3 = n + 1. A similar analysis shows that the C-strings have degree k + 2.

Discussion of alternatives

A slight modification brings the maximum degree back from n+1 to n. We maintain the definition of X-strings, but modify the classification of the X-pairs: for 2 values of the bit-sum it is an A-pair, for 2 other values it is a B-pair, and for the last 3 values it is a C-pair. This does not affect the diameter; it yields for A- and B-strings a degree 2�k + 3 and for C-Strings a degree 3�k + 2 = n. The price to be paid for this reduction is an increase in the total number of edges (though for k ≥ 2 the number is less than in the n-cube).

Other variations are possible. For a graph with 5�16k nodes, we can characterize each node by a pental digit, followed by k hexadecimal ones. This is nice because 16-1 is divisible. It is thus possible to achieve a diameter of k + 5 and for all nodes a degree of 3�k + 2, and since k ≈ n/4, this is asymptotically better. The above can be achieved with the pental connectivity diagram

      .

Paths ABCDEA, ABCDE, and ABCDED demonstrate that the pental digit need not be subjected to more than 5 modifications. Exploration of other variations —e.g. others than powers of 2 for the base of the kth power— is left to the reader.

Acknowledgements   I am indebted to J.L.A van de Snepscheut for drawing my attention to the problem and to the members of the ATAC (=Austin Tuesday Afternoon Club) —in particular to Hamilton Richards Jr. and Amir Pnueli— for very helpful comments on an earlier effort of explaining my construction.

[0]   J.L.A. van de Snepscheut, Private Communication.

Austin, 22 October 1986

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD988

On the phenomenon of scientific disciplines

In this note we regard scientific disciplines as our modules of human knowledge and abilities, because this metaphor seems the simplest way of convincing the computing scientist that the whole of human knowledge and abilities should be appropriately partitioned.

For a scientific discipline to be viable, the area it covers must meet a number of constraints. It must not be too big: the core of its knowledge must fit into a single person's head and —our abilities requiring the maintenance of daily exercise— the required abilities should not be more than we can acquire and maintain. It should not be too small either: the area should be rich enough to keep us happily engaged for more than a lifetime.

To the experienced system designer, this sounds all very familiar: too large a module is too hard to manage, and too small a module is not worth creating as a separate entity.

Besides those quantitative constraints, there are qualitative ones. There is the internal requirement of coherence: the abilities should enable us to improve our knowledge, the knowledge should enable us to perfect our abilities. There is the more external requirement of isolation: a scientific discipline should be a world unto itself, as independent as possible from the rest. The degree to which a topic can be studied in isolation is a major test for how appropriately the partitioning has been chosen.

To the experienced system designer, this too sounds very familiar. He recognizes "information hiding", alias "abstraction", and furthermore knows full well that an inappropriate modularization can drastically complicate life at both sides of the fence. This phenomenon of mutual complification is (regrettably) also only too familiar to the ordinary citizen, who has to comply with all the rules and regulations of the various "services" of his government: first the citizen has a hard time filling out all the forms, and then the service has a hard time checking all the data.

A new class of considerations enters the picture when we take into account that viable scientific disciplines exist for long periods of time, during which they first emerge and then evolve. (Some of them we have seen disappear for lack of interest in the area.) Notice that these long periods are intrinsic: no substantial body of knowledge was ever concocted on a rainy afternoon and the scientific enterprise is intrinsically a very long-range one.

Consequently, this restricts the area of a viable scientific discipline to those in which the proverbial "lasting contribution" can exist, and those concerned with the evolution of a viable scientific discipline don't waste their efforts on anything the obsolescence of which is in sight.

These days, one often encounters the opnion that "scientific progress is so fast that a well-trained scientist's half-life is of the order of 5 years". What nonsense! If, indeed, a scientist's half-life is only 5 years, that should not be taken as a symptom of the speed of scientific progress, but of the deterioration of an educational process that crams the poor graduate's head with perfect ignorabilia. It is a symptom of teaching divorced from a scientific discipline, of which it is a major purpose to prevent such waste of effort.

Before continuing this discussion of the phenomenon of scientific disciplines, I must acquaint you with the "Buxton Index", name after John Buxton, who discovered that a —if not the— most relevant one-dimensional scale along which to place and compare individuals, organizations, industries, and movements is to how far in the future their planning extends; the Buxton Index expresses the length of that period, measured in years. Its significance is that cooperation between persons or groups with very different Buxton Indices leads to mutual (moral) reproaches as long as the partners are unaware of the difference: the partner with the small Buxton Index is accused of short-sightedness and opportunism, the one with the large Buxton Index is accused of hobbyism and a lacking sense of responsibility. The Buxton Index being just a number without moral values attached to it, knowledge of it can greatly contribute to clearing up the sky.

I mentioned the Buxton Index because it gives me a way of discussing in a detached manner the love-hate relationship between the world of science and the world "out there", and the closely related schism between "pure" and "applied" science. (In some societies that schism is stronger than in others.)

The relation is often uncomfortable. The world "out there" presents problems to which —if they are solvable at all— only science can offer an effective solution. The dependence on science is quite often resented. (Over and over again one will hear unsupported claims that an unscientific shortcut will do the job just as well or even better. These claims, and the ready audiences that can be found for them, are symptoms of this resentment.) When, in response to such urgent challenges, science seems to ignore them and to go quietly its own way, this may be interpreted as adding insult to injury and further fuel the resentment. Science, from its side, is not attracted to problems it is not ready for, is repelled by a customer base that prefers to listen to the quacks, and, in exasperation, will point out that many "real-world" problems only exist because its teachings have been ignored. In short, a fertile ground for drama and conflict.

The resolution of the conflict requires the understanding of two things, the first one has to do with the difference in Buxton Index. On the time scale of the scientific enterprise, utility criteria, as dictated by the fads and fashions of the fickle public, lack the necessary stability to be used for long-term guidance: one day, robotics has to save our economy, the next day it is the biggest threat to full employment. The other thing we must understand is why science has so often been so extremely successful, why it can provide answers and solutions that cannot be obtained by any other means. The explanation has always been that science has stuck to its own rules.

No scientific breakthrough has ever been obtained because some benefactor ordered it. Besides hard —sometimes even very hard— work by its most gifted practitioners, a flourishing and vigorous scientific discipline requires a very careful choice of what to try. The successful scientist is very pragmatic —otherwise he would not be so successful—. He knows he should not waste his effort on trivia in the sense that, if he does not do them, someone else can be trusted to do them. He also knows he should not waste his time on trying the impossible. Consequently, after very careful evaluation, he embarks on what he sees as in all probability just possible. It is in a subtle balance between courage and cowardness, between vision and caution that the improbable is achieved. Science is more opportunity-driven than demand-driven. It has to be, because this is one of the corner elements of its success. That is why each successful scientific enterprise always emerges as a so strongly autonomous acitivity. A society eager to reap the benefits from the science it supports or tolerates should leave the scientists the choice what to tackle, and it will be rewarded many times over; needless to say, this is anathema to the managerial mind. [E. T. Bell remarks about some European monarchs that "these rulers were clear sighted enough to see that the simplest way of getting mathematics out of a mathematician is to pay his living expenses".]

We have seen the large Buxton Index as an intrinsic characteristic of scientific disciplines; this is the place to point out that it does not come without a price: in their course, our scientific disciplines have as little flexibility and as much inertia as intellectual supertankers. Our scientific disciplines evolve, the attention shifts from old topics to new ones, and it is in particular the increasing mastery of the new topics that gives the feeling of progress. But the inertia is enormous, and from a somewhat larger distance the progress looks like "more of the same": the scientific discipline remains steady on its course.

The steadiness was eloquently reflected in an interview with Herbert Robbins, in which he explained why he did not expect mathematics to change dramatically during the next century, computers or no computers. His argument was that mathematicians had always worked at the limits of capacity of their brains, that the human brain had not changed much over the last 5000 years and that it was a safe prediction that it would not do so over the next 100. Fair enough. But at the same time the argument reveals what would be involved in revolutionizing mathematics: a drastic reduction of the reliance on our brains, e.g. by replacing more and more of our human reasoning by calculation and so letting the symbols do the work.

In the same book —"Mathematical People"— Donald E. Knuth —I quote by heart as someone borrowed my copy— remarked about Computing Science that it had provided a home for otherwise homeless mathematicians (like him) whose interests —and way of working?— deviated too much from what contemporary mathematicians are used to.

At least speculatively, I am willing to go a lot further. We are ready to realize most of Leibniz's Dream, we are, in fact, realizing more and more of it by designing and learning how to use the formal technqiues that offer an alternative that, in effectiveness, is far superior to traditional mathematical reasoning. The revolution that Robbins excluded is in full swing.

More exactly, Robbins did not exclude it, he only said not to expect mutiny on his ship, and it looks as if he is right. The speed with which cultures —scientific subcultures not excluded— can absorb change is, even in the case of progress, strictly limited, the mathematical supertanker proceeds on its steady course as supertankers have to, and it required a new scientific discipline to realize the Dream of Leibniz.

That the job fell to the scientific discipline also known as Computing Science is not surprising: (i) computing scientists are in daily need of the effectiveness only formal techniques can provide, (ii) professionally, computing scientists are quite familiar with the manipulation of uninterpreted formulae, and (iii) theirs is the technology of mechanizing the manipulation (if such mechanization is needed).

From Robbins and his confraters on the supertanker, we can expect the protest "But that is not what mathematics is about!". Right! That is precisely why a new ship had to be built. If we honestly believe in our mission we should answer "But it is what mathematics will be about a century from now.".

All the above was written for my own illumination. I needed a satisfactory answer why computing science research is each time drawn to mathematical foundations. The conclusion —drawn on other grounds— that we are in the process of realizing the Dream of Leibniz provides a more than satisfactory answer.

Austin, 12 October 1986

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

Transcribed by Michael Lugo
Last revised Thu, 27 May 2010.

EWD988a

How experimental is computing science?

Several years before I came to Austin I paid a visit to Cornell University, where the people informed me about a US movement to push computing science as an experimental science. They asked me for my opnion, and I remember Juris Hartmanis nodding in emphatic agreement when I told them that it struck me as absurd. By the way: it still does.

American computing science never having been for me a source of inspiration, I did not pay much attention to it. Moreover, with my background in physics, I had a way of understanding the phenomenon. You know, there are such things as experimental physicists. In the physics community in which I grew up, in fact the majority of the students in physics were diverted into experimental physics and only a select minority was allowed to specialize in theoretical physics. But from these student ratios no one ever concluded that physics was primarily an experimental subject! Of course not, because we all knew the reasons: the physics laboratory could make good use of the cheap labour provided by graduate students and, more fundamentally, in physics —like elsewhere— the fountain pen is harder to handle than the soldering iron. Experimental physics was very much kept alive to provide an outlet for the less able students. Another reason to keep experimental physics alive I learned later: it is a way of getting lots of money. At the time I assumed similar mechanisms at work in American computing science, and I think that I was not completely wrong.

Since I arrived in Austin I discovered that the notion of computing science being an experimental one is quite widespread, a fact with quite strange consequences: for instance, the NSF acts as if —and, I presume, honestly believes that— it supports computing science by providing the funding for supercomputers on a number of selected(!) campuses, and that while it is totally unclear how in the world the vicinity of a supercomputer can contribute to the health and vigour of a CS Department. [ It is much more readily an impediment, and we should consider ourselves fortunate in that UT's supercomputer is located at the other end of town. ]

The circumstances invited me to reconsider my judgement of the appropriateness of the notion of computing being an experimental topic. I did so, and my judgement did not change.

Proponents of experimental computing science have an argument, which is as follows. The original von Neumann machine was an imperative of the technology at the time, as indeed it was. In those days it was absolutely necessary to partition the machine into two distinct components, each of them meeting its own challenge, viz. the active logical engine, which had to be as fast as possible, and the passive store, which had to be as big as possible. These technological constraints are no longer as strong as they were, and therefore we should investigate alternatives, such as radically different architectures and equally radically different programming languages. Technological constraints are, in fact, now so weak that we have a wealth of possibilities to explore. Grading them, however, is way beyond our analytical abilities and the only effective way of singling out the most promising opportunities is by trying them out. Hence the intrinsically experimental way of approaching these current issues in computing.

So far, the argument is flawless. The question, however, is, how much it has to do with computing science. And, once more, the analogy with physics may be illuminating.

Physical measurements, no matter how easy or difficult to perform, are taken for mainly two completely different reasons. The one reason comes from technology, the other one from curiosity and scientific concern. A technical application might need some material with properties within strict and perhaps unusual limits, and if our theoretical understanding of how these properties are determined is insufficient to predict them, we have to measure possibly large numbers of candidates. Such measurements are not considered to contribute to the intellectual discipline called physics. The other reason for measuring emerges in the crucial experiment that could refute a proposed theory: theoretical physicists propose "laws of nature", but the physical subculture owes its vigour and respect to the fact that making such proposals is not a free-for-all, as it has adopted the discipline of designing and carrying out the potentially refuting experiment. The main role of such experiments is to maintain the intellectual integrity of an otherwise only speculative community.

And now we have reached the heart of the dilemma: the quoted argument in favour of experiments being fully granted, has this any bearing on computing science? It does if you accept as its role to answer as many questions related to computing as possible. It does not, if you require from an academic discipline the internal (conceptual and methodological) coherence referred to by terms like "insight". The question raised in the title, how experimental computing science is, has little to do with computing, but everything with our conception of science.

A scientific discipline is a module of human knowledge and abilities. But, as I wrote in 1974, "of course, any odd collection of scraps of knowledge and an arbitrary bunch of abilities [...] do not constitute a scientific discipline: for the separation to be meaningful, we have also an internal and an external requirement. The internal requirement is one of coherence: the knowledge must support the abilities and the abilities must enable us to improve the knowledge. The external requirement is one of what I usually call "a narrow interface": the more self-supporting such an intellectual subuniverse, the less detailed the knowledge that its practitioners need about other areas of human endeavour, the greater its viability.".

Any mathematician of some fecundity can cook up a combinatorial game, the statistical properties of which are utterly untractable and unrelated to anything else. Mathematicians are fully justified in ignoring such games when their study has no significance beyond the game studied: their study is a scientifically barren activity. Proposed experiments in computing, for instance to compare the efficiency of alternative implementation techniques, explore a number of just such untractable combinatorial games. The outcome of the experiment may be of external interest, from the point of view of computing science the experiment is a barren activity.

Once it has been pointed out that computing science is much more an intellectual discipline than a collection of experimentally established facts, a utilitarian society may believe that the facts suffice and may decide not to be interested in computer science after all. According to all experience gathered so far, however, such a society would make a grave mistake, because in the production of tangible results —the kind of results the dyed-in-the-wool utilitarian recognizes— the introverted, seemingly disinterested scientist has no equals. The most effective way of being useful is not trying to be useful but intertwined perfection of your knowledge and honing of your abilities.

Many CS departments in this country were founded before clear visibility of the outlines of the intellectual discipline we now call computing science. In that sense they were erected prematurely. For lack of anything better they were no more than a cocktail of presumably computer-related topics, but certainly not related to each other. Subsequently we had the years during which in the columns of the Communications of the ACM people that knew what science is would argue that no such thing like Computing Science existed, and from the perspective of their own department they were probably right. Today those departments face the challenge of freeing themselves from their inadequate past: they have to recognize that eventually the intellectual discipline emerged. This is a tough job, for new intellectual disciplines are no more welcome than an unwanted child. Pushing the view of computing science as an experimental discipline can, alas, be interpreted as an effort at postponing the painful recognition.

The NSF funded supercomputers in an effort to cure the relative insignificance of American computing science; it did, however, prescribe a remedy without a proper diagnosis having been made.

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

(The above was written in October 1986, the decision to give it an EWD-number was taken on 30 November 1991.)

transcribed by Martijn van der Veen
revised Thu, 27 May 2010

EWD 989

Proving Gupta’s Theorem

[actually de Ceva’s]

For an arbitrary triangle ABC a point P is chosen such that the points D, E, and F are well-defined as the above points of intersection. Gupta’s Theorem states

BD � CE � AF |  = −1        .

 CD � AE � BF 

The minus sign emerges by assigning to segments in opposite directions lengths of opposite sign and the theorem also holds for P outside the triangle. In the following we shall ignore this finesse and work with absolute values.

How do we prove this theorem? With due recognition of the symmetry, three ways seem to be open:

(i)   we try to prove

BD � CE � AF = CD � AE � BF

by independently dealing with both sides, i.e. “computing” them in such a fashion that their equality is apparent.

(ii)   we try to prove

( | BD | ) |  �  | ( | CE | ) |  �  | ( | AF | ) |   = 1
CD | AE | BF

by independently dealing with each of the three fractions, i.e. “computing” them in such a fashion that it is apparent that their product equals 1.

(iii)   we try to prove

( | AF | ) |  �  | ( | BD | ) |  �  | ( | CE | ) |   = 1
AE | BF | CD

by independently dealing with each of these three fractions.

Of these, (i) seems the least attractive: firstly, volumes are more complicated than dimensionless ratios and, secondly, in (i) the three-fold symmetry has not been factored out. Of the remaining two, (ii) is the most attractive, as a ratio of segments along the same line is “more dimensionless” than that of segments in different directions. (Here it shows that we made a mistake by immediately switching to absolute values: had we consciously kept our segments directed and our lengths signed, the definition of the signs in the fractions of (iii) would have caused trouble.) So we opt for (ii).

The three-fold symmetry having been factored out, it suffices to compute only one of the three fractions, say BD/CD. To begin with, we extract from our picture the part that defines that ratio by containing the two segments:

              .

If nothing more has been given about these two segments, there is nothing more to be said about their ratio. Points B, D, and C being points of intersection, let us include in our figure those three intersecting lines:

              .

This enables us to express our segment ratio as the ratio of the areas of two triangles, viz.

BD |  =  | BDA |         .
 CD  |  CDA 

Staying with the above picture, there is little opportunity for rewriting the ratio of the two areas; we do observe, however, that the two triangles have the side AD in common. We include P in the picture and the lines BP and CP that divide the two triangles in the same ratio:

With our previous equality we now derive

BD |  =  | BPA |       and       | BD |  =  | BDP |         .
 CD  |  CPA  |  CD  |  CDP 

The last equality is useless: it could have been deduced from

from which the information that we had 3 lines meeting in A has been lost. The first equality, however, does the job; this is nicely illustrated if we (i) remove the segment PD that is no longer needed and (ii) introduce E and F analogously to D :

*         *         *

The above was a sheer joy to write. (Yesterday evening I went to bed with an unfinished letter on my desk and I could have completed that letter. Instead, I followed Schubert’s example and composed an EWD after breakfast.)

I learned Gupta’s Theorem and the above proof from a book (co?)authored by Coxeter and remember being tickled by the elegance of the argument. Coxeter needed no more than half a page (picture included) and quite uninhibitedly pulled a few rabbits out of a hat. It was a pleasure to see how one rabbit after another could be exorcized, for that, of course, is what this whole exercise was about.

Gupta’s Theorem is of mild interest because to the best of my knowledge the Greeks missed it (which in all probability explains why to this very day it is still missing from almost all secondary school curricula in geometry!). And this Greek failure is more than a historical curiosity: it is a lesson. They paralyzed themselves by not treating products in their own right but forcing upon them the interpretation of areas and volumes.

Austin, 17 October 1986

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD991

Why Johnny can't understand

Years ago I heard a lecture on the structure of proofs. Without hesitation the speaker became very pictorial and proofs became directed graphs with arrows from antecedents to consequents. [Mathematics Inc. would market the product these days as Computer-Aided Understanding by Means of Argument Animation.] After fifteen minutes the speaker drew our attention to the fact that some proofs were planar while others were not. Next he showed how simple transformations of proofs into logically equivalent ones could change the proof's planarity, but instead of concluding that proofs planarity therefore was probably not a very relevant concept, he then embarked on a study of intrinsically non-planar arguments, etc.

It was the most nonsensical lecture I had heard in years. (That's why I still remember it.) The poor bloke was a serious victim of his education: he confused the directed graph as subset of the ordered pairs with the pictorial representation of arrows between points. [Had the same mind been educated on incidence matrices, he might have lectured on the eigenvalues of proofs.]

This is what happens to us over and over again. When a new concept is introduced we are given a few examples from a hopefully familiar context, or we are given one or two models in which the new formalism, its objects and its operations can be "understood". And we are actually encouraged to make these interpretations to convince ourselves that the new formalism "makes sense". They fail, however, to warn us that such interpretations tend to be misleading because the models are overspecific, that such habits of understanding are utterly confusing when the accompanying visualizations baffle the imagination and that the mental burden of translating back and forth between formula and interpretation had better be avoided. In fact one can only hope that with a growing familiarity with the formalism the model gently fades away from our consciousness.

It already began when we were taught the natural numbers. We did not learn 2 + 3 = 5 , we learned first —pictorially!— that two apples and three apples is five apples, and then for pears, for plums, for cats, trees and elephants. The apple model is woefully inadequate as, in order to accommodate a product, the apple had to be squared, and consequently —and fortunately— it did fade away, but not before it had created a hurdle for the negative integers. It can be argued that we continue to pay the price, viz. if we judge zero's in the apple model responsible for all the mathematical complication caused by considering 1 the smallest natural number. (Compared with the Greeks we have been fortunate: with their line segments they could multiply a little bit, unfortunately just enough not to kick away their model. And eventually Greek mathematics was killed by conceptual poverty and pictorial complexity: a lesson for us all.)

I seriously doubt that the detour via the apple model is essential for teaching little kids the integers, but even if it were I see no reason why a learning process that might be appropriate for little kids should also be appropriate for the adult mind. And yet this seems the assumption on which most writers and many adult readers operate. My —sad— conclusion is that the most widespread patterns of understanding have not been consciously selected for their effectiveness and had better be described as addictive habits, many of which deserve a General Surgeon's Warning.

My most common observation is seeing people feeling more comfortable with the needlessly specific. When confronted with a partially ordered set, they mentally supply "for instance, the integers". While I have been trained to skip the examples when reading a text —because they should be superfluous and are in any case distracting— I see people getting most uncomfortable when faced with a text without examples. People having difficulty in understanding a construction that contained a natural parameter k have assured me that that parameterization presented an additional obstacle that they could remove by initially substituting for k a small value, 3 say. I have no reason to doubt their word; the strange phenomenon was probably connected to the fact that k did not occur in a very arithmetical context but as length of strings or as number of edges meeting at a vertex, i.e. context they were used to deal with in terms of pictures. Halfway the text an "arbitrary" permutation created similar problems: they would have preferred a specific one, possibly followed at the end by a remark that the choice of permutation did not really matter. It is very strange, disconcerting even, to see people disturbed when questions are left open whose answers are irrelevant.

A final observation suggest that indeed our educational system is to blame. I remember very well the introduction of the idea that it was the professor's duty to motivate his students. (I remember it very well because I thought the idea so absurd.) I now encounter young scientists educated under the motivating regime, and they have a quite noticeable handicap: their ability of absorbing unmotivated information is limited to about 10 lines. The object and its purpose are different things, but they have not learned to distinguish and are now unable to separate the corresponding concerns. It is a frightening example of how education can instill psychological needs that turn out to be a serious handicap.

Austin, 5 November 1986

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

Transcription by Javier Smaldone.

Revised Thu, 27 May 2010.

EWD 992

Difficult is easy

This note has been triggered by a recent text, whose authors will remain unmentioned. After introducing "tableaux" with separate column for "assertions" and "goals", the text continues as follows:

"Any tableau is equivalent to the one obtained by removing an assertion and adding its negation as a new goal [...]. Similarly, any tableau is equivalent to the one obtained by removing a goal and adding its negation as a new assertion. Thus we could manage with a system that has no goals or a system that has no assertions, but the distinction between assertions and goals does make derivations easier to understand."

While reading the introduction of tableaux, I had already been worried by the distinction between assertions and goals because it seemed a superfluous distinction whose main effect was to double the length of many sentences (e.g. "the tableau is true if some instance of at least one of the assertions is false or some instance of at least one of the goals is true"), and I was wondering whether I was missing something. Quod non. The quoted paragraph nicely settles that, indeed, we don't need both assertions and goals, but it makes the question why the superfluous distinction was introduced in the first place —or, as the case may be, was kept— only more burning.

And then comes the answer: "the distinction [...] does make derivations easier to understand". Now I ask you, how can an intelligent reader be expected to buy that nonsense? It has just been established that the distinction is so meaningless that we have no criterion to choose which column to use! The distinction has been identified as mental lumber; yet we are supposed to accept that carrying the burden around makes understanding easier.

The answer is so patently nonsensical that one begins to wonder how such a text could have been written at all. One possibility is that the authors have acted on the principle "complexity sells better" and that, in an effort at promoting what they perceive as their careers, have welcomed the opportunity of lengthening their article by a suitable dose of obfuscation. Another possibility is that they acted on the principle that the average reader's mind is so muddled that you should not confuse it by clarity. In both cases their scientific integrity is at stake.

Let me close by quoting Strunk and White —mostly White in this case—: "No one can write decently who is distrustful of the reader's intelligence, or whose attitude is patronizing."

Austin, 9 November 1986

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

transcribed by Tristram Brelstaff
revised Thu, 27 May 2010

EWD993

The nature of my research and why I do it.

(Luncheon speech for Las Cruces, 14 November 1986.)

In 1955, as a young and promising theoretical physicist, I decided to devote my scientific life to programming instead, because I felt that programming well presented the greater intellectual challenge.

The next decade was devoted to gathering experience by designing and implementing systems of increasing size, ambition and sophistication. By 1965 I could forcefully argue that the ability of detecting in an early stage the need for some special-purpose theory was one of the programmer's most important assets.

Another five years later I formulated the core of the programming challenge as how to prevent the generation of unmanageable complexity. It became clear —to me at least— that the challenge was a mathematical one. By 1975 I had developed a formal system in which the program and its correctness proof could be designed hand in hand.

I was very excited because that was really great: another area of human endeavour had been shown to be in principle amenable to mathematical treatment.

From a purely technical point of view it is in retrospect amazing that it took me no less than two decades to reach that stage. From a sociological point of view, this slowness is easy to understand: the conclusion was almost universally unpopular. Programmers, and even more so their industrial managers, decried the whole idea as too academic to be of any practical significance. (Many of them still do.) The mathematicians ignored or denied the conclusion, because the type of mathematics was so different from what they were used to that they hardly recognized it as mathematics. (Many of them still don't.) At the time I did not understand the vigour of their academic opposition, but it quickly convinced me that computing science had to develop itself the type of mathematics it needed. In retrospect I can understand the rejection: the stress must have seemed all wrong. In a nutshell: whereas during the last century mathematics as an intellectual discipline has become more and more knowledge-oriented, most of that knowledge was totally irrelevant for us; for us, for instance, the choice of notation seemed much more often to be the crucial decision.

So I found myself analyzing which habits and which precautions should be cultivated for the mathematical answer to the programming challenge. In the beginning I booked these explorations under the familiar heading of "programming methodology".

But then all sorts of things started happening. By virtue of its mechanical interpretability, a programming language inevitably represents a formal system of some sort, and hence program derivation is unavoidably a highly formal activity. But this activity is only doable provided we find ways of preventing the amount of formal labour needed from exploding. As soon as brevity became a conscious goal, one begins to ask oneself "What makes formal derivations lengthy?" Not surprisingly, case analysis emerges as the main culprit. So one asks oneself "What techniques do we have for avoiding case analysis?". And one finds a few, some of then sometimes even very effective. (Later in this talk, as time permits, I shall mention some of them.)

Shortly thereafter, the reading of a well-known, generally recommended and widely used mathematical textbook leaves one completely aghast! The arguments —and even the formulations of the theorems— are often so incredibly clumsy that one is forced to conclude one's explorations have a bearing on mathematics in general.

Example. In "An Introduction to Number Theory" by Harold M. Stark, a main theorem is formulated as follows:

"If n is an integer greater than 1, then either n is prime or n is a finite product of primes."

But 1 is certainly finite, and by defining the product of 1 factor —how else?— to be equal to that factor we can do away with the case distinction in the consequent:

"If n is an integer greater than 1, then n is a finite product of primes."

But also 0 is certainly finite and by defining the product of 0 factors —how else?— to be equal to 1 we can do away with the exception:

"If n is a positive integer, then n is a finite product of primes."

Finally we can do away with the identifier n:

"A positive integer is a finite product of primes."

(End of Example)

In connection with the above example I would like to stress that a clumsy formulation of a theorem is a prototype of an unfortunate interface in the sense that it tends to increase labour on both sides of the fence: it makes the theorem harder to prove and harder to use.

Thus I found myself drawn into a wider topic than just "programming methodology". Sometimes I call it —mainly for private purposes— "the streamlining of the mathematical argument", sometimes I call it "mathematical methodology", a name partly chosen to express that we were exploring to what extent the experience gained from programming methodology could be carried over to mathematics in general, and partly chosen because it reflected a shift in emphasis, viz. from polishing existing arguments to the discipline of designing in an orderly fashion new arguments. As time went by heuristics entered the picture.

In these activities we found a new appreciation for formalisms as an alternative to verbal thinking. We learned that formalisms are much more than a shorthand: we now consider them as the main means for freeing ourselves from the shackles of our native tongues.

Let me give two examples of how confusing our languages are. By the Law of the Counterpositive, A ⇒ B is the same as ¬B ⇒ ¬A. The implication is linguistically rendered by prefixing the antecedent with "if", e.g.

"It will rain tomorrow if the wind does not turn.",

a perfectly acceptable sentence. The counterpositive, however, yields:

"The wind turns if it won't rain tomorrow.",

a funny statement, to say the least. Evidently, the conjunctive "if" carries with it a whole extra-logical burden of before/after or cause/effect (a dichotomy for which there is no place in the inanimate world). Verbal mathematics has learned to strip the conjunctive "if" from that extra-logical burden, but only to a certain extent, as is shown by the following example. Logical equivalence, alias the mutual implication, is verbally rendered by "if and only if", as in

"An integer n is even if and only if n+1 is odd."

So far so good, but now have a look at the following sentence:

"I see with both eyes if and only if I see with one eye if and only if I am blind.".

Linguistically, this is complete gibberish because the sentence can be parsed in two different ways. Its blatant syntactical ambiguity prevents it from being an acceptable sentence. Logically, it is of the form A ≡ B ≡ C and we are, indeed, free to omit the parentheses since the boolean operator of equivalence is associative: the continued equivalence means that the number of false operands is even, and since we do not have more than 2 eyes, the above statement, though baffling gibberish, is formally correct.

In mathematical reasoning, the equivalence is a grossly underexploited relation, and there is no doubt in my mind that this is closely related to the linguistic shortcomings on the verbal rendering "if and only if". Consequently, I have come to the conclusion that it is a mistake to teach logic by translating formulae into prose, for that is precisely the vehicle from which we want to increase our distance. My characterization "grossly underexploited" is no exaggeration: the judicious use of the equivalence has reduced many an existing argument by an order of magnitude. (I have seen reduction factors of 16 and 24.) The explanation is probably to be found in the nice properties of the equivalence, such as symmetry, associativity and the fact that disjunction distributes over it; moreover it has the full power of equality, i.e. x = y  ⇒  f.x = f.y .

Formalization, in general the reduction of a greater part of mathematics to calculation, is not our goal. It just happened, and in this connection I would like to stress that our experience is directly opposite to what is commonly held as unshakable dogma, viz. that formal treatments are always long, tedious, laborious, error-prone and what not. On the contrary, a more calculational treatment has invariably led to a crisper argument. My conclusion is that the bad name of formal techniques is undeserved. Our experience is so striking and, at the same time so contrary to what is generally felt that you may have difficulty in believing me. So let me venture an explanation why so many people have such poor experiences with formal mathematics.

(i) Many established notations are not well geared to our manipulative needs, e.g. by being ambiguous or by denying us the combinatorial freedom we need.

(ii) Some calculational styles introduce many steps that are better avoided. When using an associative operator, one may confine oneself to fully parenthesized expressions, explicitly shuffling, when needed, the parentheses by an appeal to

(X ∙ Y) ∙ Z = X ∙ (Y ∙ Z)

Just dropping the parentheses is much simpler.

(iii) Many people have failed to develop sufficiently reliable handwriting: they think that formal mathematics is hard while in actual fact they only lack some simple hand-eye coordination.

It was the dream of Leibniz to reduce all of mathematical reasoning to a universally applicable calculus. Not being Leibniz, we are more modest: we won't hesitate to calculate when it comes in handy.

But Leibniz needs to be mentioned in connection with computing science because it could very well be that the discipline gets the task of realizing most of his dream. The reasons are the following:

The kind of complexity that computing scientists face makes formal techniques indispensable.

From his experience, the computing scientist is intimately familiar with the idea of manipulating uninterpreted formulae.

If the need arises, the computing scientist has the technology for mechanization at his disposal.

If ours is the task of realizing the dream of Leibniz, let us see to it that it does not turn into a nightmare!

prof. dr Esger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188, USA

transcribed by Tristram Brelstaff
revised Thu, 27 May 2010

EWD 996

Courtesy A.J.M.van Gasteren, C.S.Scholten, and J.G.Wiltink

Show that, for any set of grid points in the plane, it is possible to colour each of these points either red or blue such that on each grid line the number of red points and the number of blue points differ by at most 1.

*         *         *

Since constructive existence proofs are nice, we shall design a colouring algorithm; initially all grid points of the set are blank, finally each grid point of the set is either red or blue. Since the final requirement Po:

Po:    | on each grid line the number of red points and the number of blue points differ by at most 1

holds initially as well, we propose that Po be invariant.

We propose the simplest colouring algorithm we can think of, viz. one that colours blank grid points one at a time. Colouring a blank point can violate Po only in the presence of what we call “a surplus”, defined by:

a surplus is a grid line that contains at least one blank point and on which the number of red points and the number of blue points differ by 1.

The invariance of Po would be guaranteed by the permanent absence of surpluses, but since grid points are coloured one at a time, this constraint is stronger than we can live with. We must admit the occurrences of surpluses, but let us investigate the extent in which we can constrain their existence. But what are the relevant concepts in terms of which we can express such a constraint?

To begin with we observe that permuting a number of parallel grid lines would transform a solution into a solution: a reference to, say, “the left-most vertical surplus” would have introduced a concept foreign to the problem statement.

Next we observe that the problem statement is symmetric in vertical and horizontal grid lines. Hence, as far as the direction of surpluses is concerned, the only notion that can be of significance is whether two surpluses are “parallel” or “orthogonal”.

Finally we observe that the problem statement is symmetric in red and blue. Hence, as far as the dominant colour of surpluses is concerned, the only notion that can be of significance is whether two surpluses are “equal” or “opposite”.

Armed with these insights we investigate which surplus configurations we have to allow.

We have to admit state A, given by

A:   there are no surpluses       ,

since this holds initially and finally. Colouring in state A a blank grid point leads to state A, state B or state C, the latter ones being given by

B:   there is one surplus,       and

C:   there are two surpluses that are equal and orthogonal.

Colouring in state B a blank grid point so as to remove the given surplus leads to state A or to state B.

Colouring in state C a blank grid point so as to remove one of the given surpluses leads to state A, to state B, or to state D, given by

D:   there are two surpluses that are opposite and parallel

Colouring in state D a blank grid point so as to remove one of the given surpluses leads to state B or state C.

Thus we have found the closure and shown that it is possible to maintain Po ∧ (A ∨ B ∨ C ∨ D), which concludes our argument.

*         *         *

Wiltink and Scholten solved this problem. (Wiltink did it with nested loops, Po ∧ A being the invariant of the outer one; he fully exploited the symmetries.) Van Gasteren taught us how to look for the concepts in which to conduct the argument.

Rutger M.Dijkstra, who happened to be at home, drew my attention to a shortcoming in my explanation.

Nuenen, 27 December 1986

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD 997

Computing Science in the United Kingdom

This is just a sad reminder that in the Old World not all is well, not even in the United Kingdom that has so often been leading in Computing Science.

In the Computing Newsletter, October 1986 —a publication of The British Computer Society— I encountered in an article titled “Second Manchester Conference on Careers with Computers. Are we Getting it Right” by Geoff Hayes the following:

“From returned questionnaires attempting to gauge interest and relevance, the conference was a singular success, especially as it has also highlighted some significant differences of needs as perceived by educators and employers. Many delegates found this profoundly disturbing [...].”

But the discrepancy between what the world asks for and what the world needs has been computing’s traditional curse for more than a quarter of a century! That “many delegates” can still be surprised when faced with a manifestation of this fact, well, that’s what I think rather disturbing....

In The Computer Journal, Vol.29 No.5, October 1986 —the most prestigious publication of The British Computer Society— I found in an article titled “A Knowledge-Engineering Approach to Instructional Design” by Nick Rushby the following revealing diagram:

For those who think this insufficiently baroque, the text adds: “This shows some of the possible topics and linkages: readers are encouraged to add their own as they read through this paper and further ideas occur to them.”.

Another sentence from that paper to be conserved for posteriority is: “Clearly, there is a need for a better understanding of the learning process, and a need for a language with which to describe it.”.

That same issue of The Computer Journal contains a nice specimen of junk science: IBMology. It is the paper titled “IBM makes usability as important as functionality” by B.Shackel. In its first column it contains what we have to consider an educated guess “In my opinion the decision for usability and human factors was probably taken at the same time.”; in its second column the author gets really scientific: “A corporate decision must have been made in 1980 or early 1981, with substantial funding assigned to various programmes. The result, below, provide the evidence.”. I always thought the “Phenomena breed science” of Newell, Perlis, and Simon (1967) a bit superficial; the Shackel paper is what we get when the dictum is taken to heart.

It is a sad world.

Austin, 8 January 1987

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

transcribed by Bart Vreugdenhil and Corrado Cantelmi
revised 08-Jan-2012

10xx

1000: Twenty-eight years

1003: Graphs of modest diameter and degrees

1006: Trip report E.W.Dijkstra, Stanford/Palo Alto, 26–29 March l987

1008: What computing science is about

1009: On a somewhat disappointing correspondence

1011: Introducing my fall 1987 course on Mathematical Methodology

1012: “Real mathematicians don’t prove”

1013: Position paper on “fairness”

1014: A monotonicity argument revisited

1016: A computing scientist’s approach to a once-deep theorem of Sylvester’s

1018: To the members of the Budget Council

1019: Another filler of the YoP Institute

1024: A new science, from birth to maturity

1026: Trip report E.W.Dijkstra, Marktoberdorf 1988

1027: My methodological blunder with grid polygons

1028: Euclid, Netty, and the prime numbers

1033: Trip report E.W.Dijkstra, Zürich, 15–20 Oct. 1988

1035: On long-range planning for the CS department

1036: On the cruelty of really teaching computing science

1039: Seemingly on a problem transmitted by Bengt Jonsson

1041: By way of introduction

1041a: Factorizing the factorial

1043: A few comments on “Computing as a discipline”

1044: To hell with “meaningful identifiers”!

1046: A tale of two winters

1049: A somewhat open letter to Uri Leron

1050: On the design of a simple proof for Morley’s Theorem

1051: The next forty years

1053: Monochrome pairs in the three-coloured plane

1054: On hygiene, intellectual and otherwise

1055: On the problem of the calissons

1055A: untitled (advice to a young scientist)

1055c: On covering a figure with diamonds

1056: Hoe onbelangrijk het is of duikboten kunnen zwemmen

1057: Andrei P. Ershov in Nuenen

1058: In reply to comments

1059: 0 Preface (Mathematical Methodology)

1060: “Predicate Calculus and Program Semantics”, fall 1989

1066: Hungry? Have a byte ....

1067: A very first introductory example (Mathematical Methodology)

1068: On the quality criteria for mathematical writing (Mathematical Methodology)

1069: Fair gambling with a biased coin

1070: For brevity’s sake (Mathematical Methodology)

1071: Making a fair roulette from a possibly biased coin

1071a: Making a fair roulette from a possibly biased coin

1072: On covering a figure with diamonds

1073: How Computing Science created a new mathematical style

1076: From “Discrete Mathematics with Applications” by Susanna S. Epp

1083: The balance and the coins

1085: Proving the theorem of Menelaos

1092: Two ways of determining an expectation value

1094: The undeserved status of the pigeon-hole principle (Mathematical Methodology)

1095: Are “systems people” really necessary?

1096: Potter’s proof of disjunction’s symmetry

EWD1000

Twenty-eight years

Twenty-eight years ago I wrote EWD0.

It was during a kind of scientific interregnum: my thesis and the basic software for the X1 had been completed and I could not start on the ALGOL compiler because ALGOL 60 had not been defined yet. I did all sorts of unrelated things. It was, for instance, the year that I published —at last!— my algorithms for the shortest path and the shortest spanning tree. It was also a time of explorations. At a given moment I was working on four or five different manuscripts. Of course, the pages of each manuscript were numbered; after I had mixed up pages between manuscripts for the second time, I decided that I had better end that confusion, and numbered the manuscripts as well: EWD0, EWD1, EWD3, EWD4 . And that is how it started.

I don't remember their topics, nor whether they have been completed. The oldest EWD of which I remember the topic is EWD6, on which I worked in Paterswolde in the "Familiehotel", where, in the early summer, I spent a holiday with my young family. It was on my discovery how to implement recursion. I vividly remember my conscious search for a good name for the device, good in the sense that it would yield both a noun and a verb.

At the time, I worked in Dutch and came up with the noun "stapel" and the verb "stapelen", which I subsequently translated into "a stack" and "to stack". (Evidently, the term was fortunate, for within a few years after I had used it in my article "Recursive programming", it had established itself in the working vocabulary of the computing community.)

I then allowed myself the luxury of a portable typewriter, which I still have. [It had square brackets.] {It had braces too.} I could also type -> and => . In early 1960 I used it for, say, a dozen EWD's, which were working documents for our ALGOL compiler and recorded all sorts of conventions and interfaces. This was prior to Xerox machines, but by typing on rice paper with a piece of carbon paper at the back, one could make an original from which copies could be made at a modest cost. The machine was a Hermes Media, the type fount Techno Elite. It was a luxury indeed: I was poor and the machine was very expensive. But it was worth its money, for after many years of intensive use it is still in excellent condition.

Around May 1961, in something like EWD31, I introduced the P- and V-operations on semaphores. By the time I went to the Technological University of Eindhoven —Sept. 1962— I was an expert typist. Asked whether I had any special wishes —in those days new professors were supposed to have special wishes— I shocked my future colleagues by asking an electric Hermes Ambassador with the Techno Elite type fount and special characters according to my specifications. (I shocked them because in those days, professors were not supposed to do their own typing.) I mention my request for an electric typewriter because it shows that already in those days I viewed writing as a major component of working.

EWD123, "Cooperating Sequential Processes" was written in 1965 and served as lecture notes for my course in the fall semester of that year. (The problem of The Dining Quintuple —later dubbed "The Dining Philosophers" by Tony Hoare— was the examination problem at the end of that semester.) The rate with which the EWD-numbers increased was in those days not a measure of my productivity: I assigned numbers when I started on manuscripts and many of them were not completed. (My first year in Eindhoven I suffered from a writer's block. Everything I wrote disappeared before completion into the wastepaper basket, until I discovered the cause: if I geared my text to my former colleagues of the Mathematical Centre in Amsterdam, I realized halfway that my new colleagues in Eindhoven would not understand it, and if I geared my text to my new colleagues, my former ones would think it insipid. I only freed myself from that writer's block by the conscious decision not to write for a target audience but to write primarily to please myself.)

A next milestone was EWD249 "Notes on Structured Programming" written primarily for therapeutic reasons —and partly while I was in hospital— in 1969. In response to the completion of the THE Multiprogramming System —and, I am afraid, in response to its success— the Department of Mathematics had disbanded the group I had built up. My degradation from esteemed colleague to dangerous competitor caused me to suffer from a depression that lasted more than half a year. EWD249 marked my recovery.

The fate of EWD249 revealed that the by then ubiquitous copying machine had profoundedly changed the pattern of scientific communication. I had mailed only 20 copies to friends in Europe and the USA, but it spread around the world like wildfire to the extent that only a few years later IBM felt forced to steal the term. People from far-away places have later told me that in, say, 1971 they had a 6th- or 7th-generation copy! No future history of science can ignore the change the advent of the copying machine has made.

In the meantime I privately owned a second Hermes Ambassador and, but for the copying machine, I was fully equipped for my life as Burroughs Research Fellow, which started in August 1973 around EWD375. Prior to that, primarily my trip reports —in Dutch— were distributed among my colleagues. (I got the idea of writing trip reports from Brian Randell, who had acquired the habit in the years he worked at IBM, Yorktown Heights. It seemed such a good habit that I immediately adopted it.)

The major change was that now I tended to assign EWD-numbers to completed manuscripts. This was facilitated by the fact that uncompleted manuscripts became more rare. For the next five years or so I would decide for each EWD to whom I would send it and would make precisely that number of copies at the Eindhoven branch of Xerox. I still regarded the opportunity of making copies a luxury —many EWD's were typed at single spacing— ; I also prided myself at the low cost with which I ran my little research outfit. Early 1978 I privately bought a 3M copier, I charged the paper to Burroughs and began to maintain a regular mailing list.

The switch from typed to handwritten EWD's took place halfway EWD719-7 —29 Oct. 1979— , when my Hermes developed a technical trouble. The transition became more or less definite when my little 3M copier (which had been too cheap) got more and more problems with the sharp thin lines of the Hermes: Techno Elite was a very nice —distinguished and exclusive!— type fount, but it was hard on copying equipment. After having verified at Burroughs that the people there had not the slightest objection to handwritten EWD's, the transition became almost complete. I was, as said, an expert typist, but I still preferred writing over typing. (The large Hermes with its heavy carriage was very noisy.)

[The only advantage —if it is an advantage— of typing over writing is that typing enables me to cram almost twice as much text on a page. The gain in speed is ignorable. It makes some difference in relaxed letter writing: 1000 words/h when typed, 750 words/h when handwritten. But technical EWD's are written —even after all the mathematics have been done— at a speed of 200 words/h, i.e. about 3 words/minute. The rest of the time is taken up by thinking. In that situation, mechanical aids for getting characters on paper are clearly irrelevant.]

Eventually Burroughs installed a Toshiba copier in my Nuenen office. When UT asked me whether I had any special wishes —occasionally, new professors are still asked that question!— I answered "a copier according to my specifications". A Toshiba now occupies the space originally intended for the washer and the dryer (which have been banished to the garage); by now it has made more than 32,000 copies.

* |  | *
| * |

Well, that's how it all happened. Of course I have been blamed for all my deviations from average behaviour. (The touchy interpret it as implicit criticism.) I have been blamed for typing all my own stuff on a typewriter that was spectacularly different from all other machines in the department. But I really needed a distinction between the digit 0 and the capital letter O. (For that reason, all my Hermes machines had their ten digits from a different type fount.) And I did my own typing for the practical reason that it took me less time than the detour via a typist. I have been accused of showing off my productivity by numbering my manuscripts; I hope to have convinced you that, if you are in the business of writing, it is very practical to have a uniform way of identifying your manuscripts. Lately I have been accused of using my handwriting as a cheap trick to enhance my visibility; I hope to have convinced you that I use it for eminently practical reasons. (Getting a single daisy wheel with the appropriate special characters is not a simple operation; on my fountain pens I get them for free.) So much for some self-defence.

On a more contented note: I am reasonably pleased with life, about as pleased as we poor mortals may be allowed to be, and in this contentment the EWD-series plays a major role. If there is one "scientific" discovery I am proud of, it is the discovery of the habit of writing without publication in mind. I experience it as a liberating habit: without it, doing the work becomes one thing and writing it down becomes another one, which is often viewed as an unpleasant burden. When working and writing have merged, that burden has been taken away.

The habit is also liberating in a much more profound sense. I consider, for instance, EWD975 on the Theorem of Pythagoras —of all theorems!— a major achievement of the last semester. It was an unadulterated pleasure to write it; one of its recipients called it "absolutely bloody marvellous". Had I only written with publication in mind, it would never have seen the light of day. Not only would [the] aforementioned recipient have been denied his enjoyment, I would have been so too: what I sent out was Sunday's version, which I could only write after the discovery that I could still improve on Saturday's version, The only way to discover that a neglected or ignored topic is worth writing about is to write about it.

The EWD-series seems a little unusual. If it is sufficiently unusual to represent a novel style of doing science, the development of that style may be one of my major contributions. (In passing I note that among scientists of the next generation the style has become less unusual than among those of my own generation.)

In any case I thank the recipients of the EWD-series for their patience to bear with me. Without providing much feedback, they proved to be an inspiring audience. But, copying machines being what they are, I have not the foggiest notion of whom I reach. I therefore have an
Important_Request Would everybody —and this time I really mean everybody— who sees this text be so kind as to inform me that he or she has seen it? A postcard stating name (and affiliation) suffices. (End of Important Request.)

Austin, 11 January 1987

prof.dr. Edsger W. Dijkstra,
Department of Computer Sciences,
The University of Texas at Austin,
Austin, TX 78712-1188
United States Of America

Transcribed by Diethard Michaelis.

Last revised Thu, 27 May 2010.

EWD 1003

Graphs of modest diameter and degrees

Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188, USA

The diameter of a graph is defined as the minimum path length, measured in number of edges, that suffices to connect any two nodes; we confine ourselves to undirected connected graphs with at most 1 edge between any two nodes. Nodes connected by an edge are called each other's neighbours. The degree of a node is defined as the number of edges incident on that node; it equals the number of neighbours of that node. Note that summing the degrees of all nodes yields twice the number of edges.

At the one extreme we have the complete graph: it has the minimum diameter, but the maximum number of edges. At the other extreme we have the string: it has the maximum diameter and the minimum number of edges. We are interested in graphs with modest diameter and modest maximum degree.

A well-known example of such a graph is the n-dimensional "cube": its diameter equals n and so does the degree of each of its 2n nodes. To see this, we identify the nodes with the 2n n-digit binary labels and connect any two labels that differ in exactly 1 digit. Thus each node has n neighbours and, hence, degree n; the length of a shortest path between two such labels equals the number of bit positions in which these labels differ and, hence, the diameter equals n. We shall now construct graphs whose diameter is smaller than the ²logarithm of the number of nodes while the maximum degree remains at that bound or is decreased as well.

To this end we generalize the solution presented by the hypercube in three different ways.

Firstly, we replace our binary labels by mixed-radix labels, in which one digit, which we denote as "the leading digit", plays a special role. For the purpose of this exposition, we can confine ourselves to labels consisting of a leading x-ary digit followed by k y-ary digits; the graph has then x∙yk nodes.

Secondly, the edges correspond to a subset of the pairs of labels that differ in exactly 1 digit. (It is this subsetting that allows the departure from binary digits while keeping the degrees down.) Note that, as in the case of the hypercube, a path consists of a sequence of labels in which each next label differs in exactly 1 digit from its predecessor.

Thirdly, the restriction that on the paths considered each digit position is subjected to at most 1 transition —viz. from source value to target value— is waived for the leading digit.

Our construction has the following characteristics:

whether two labels differing only in one of the y-ary digits are connected or not depends on the pair of y-ary digits in that position and on the (common) leading digit; the dependence is such that there exists at least one value for the leading digit such that the two labels would be connected; we refer to such a leading digit value as "enabling" the y-ary transition in question;

whether two labels differing only in their leading digits are connected or not depends only on the pair of leading digit values; among the x possible values of the leading digit these connections form a connected graph, to which we shall refer as "the x-ary connectivity".

To determine a path from a given source label to a given target label, we determine on the x-ary connectivity a shortest path P from source leading digit to target leading digit, such that each of the at most k y-ary transitions required is enabled by at least one x-ary value on P. We can now effectuate the stepwise transformation from source label to target label by performing (in order) the x-ary transitions of P, interleaved with the required y-ary transitions in such a way that each of the latter is enabled by the leading digit of the intermediate label. As a result, the diameter is at most k + the maximum length of P. (The proviso "at most" has been included because for very few required y-ary transitions the above procedure sometimes does not lead to the shortest path between source and target label; only for very small k, the proviso may not be vacuous.) In the following, L will denote the maximum length of P.

The purpose of the remainder of this note is to show how we can choose the parameters —primarily x, y, k, and the enabling rules— so as to gain on the hypercube.

(i)    We begin by exploring the case y = 4 by partitioning the 6 possible y-ary transitions in classes A, B, and C as follows:

.

The property of this classification is that each y-ary value can be subjected to exactly 1 transition from each class. The fact that we have 3 classes suggests that we consider the case x = 3, with as x-ary connectivity

;

here each x-ary value has been marked with the class of y-ary transitions it enables. For sufficiently large k , L is 3, and hence the diameter is 3 + k. The degree is for each node 2 + k. Compared with the hypercube with 2⁵ nodes, the graph with k = 2 has the same diameter (= 5), but more nodes (48 instead of 32) and a lower degree (4 instead of 5). With increasing size, degree and diameter grow for the hypercube twice as fast as for this type of graph. (End of (i).)

(ii)     We now consider y = 4 (with the same classes A, B, and C) and x = 2 The number of classes being one larger than the number of x-ary values, we are led to the x-ary connectivity

.

For k = 1, L equals 2, the diameter equals 3, for 4 nodes the degree is 2 and for the 4 other nodes the degree is 3. Compared with the cube we have saved 2 edges. For even k, we can construct graphs in which each node has the same degree 1 + 1.5∙k by interchanging for half of the y-ary digits the enabling roles of the two x-ary values. For k = 2, this graph has 2 nodes, but diameter and degree both equal to 4 (instead of 5 for the hypercube). Compared with the hypercube, the diameter grows half as fast, the degree with 3/4 of the speed. This example has been included because it illustrates a method for distributing the edges more evenly among the nodes; it does not reduce the total number of edges, nor the diameter, but brings minimum and maximum degree closer to the average degree. (End of (ii).)

(iii)     We now turn to y = 5. A systematic way of partitioning the 10 possible y-ary transitions in classes A and B is as follows:

.

Having two classes, we choose x = 2 with the x-ary connectivity

.

In general, the diameter is 2 + k, whereas the degree is 1 + 2∙k . Because of the latter factor of 2 —in a label each y-ary digit can be subjected to 2 transitions— and 5 is only a little bit larger than 4 , the gain in degree is not spectacular. (E.g. for k = 4 , we have 1250 nodes, degree 9 and diameter 6, which is a uniform improvement over the hypercube with 1024 nodes.) The construction is of particular interest for the case k = 1: 10 nodes of degree 3, but with diameter only 2 because each disabled y-ary transition can be accomplished by two enabled ones. (This is the famous Peterson Graph.) (End of (iii).)

Before showing a few more graphs, we mention two theorems about possible partionings of y-ary transitions.

Theorem 0    For y = 2∙n + 1, the y∙(y–1)/2 y-ary transitions can be partitioned into n classes such that each y-ary value can be subjected to 2 transitions from each class.

(This partitioning is a generalization of the one shown under (iii).)

Proof     Distribute the 2∙n + 1 values evenly along the circumference of a circle. Pairs of values with the same distance belong to the same class; because 2∙n + 1 is odd, each value has the same distance to two other values. (End of Proof.)

Theorem 1     For y = 2∙n , the y∙(y–1)/2 y-ary transitions can be partitioned into y–1 classes such that each y-ary value can be subjected to 1 transition of each class.

(This partitioning is a generalization of the one shown under (i); it is sometimes referred to as The Tournament Problem.)

Proof Place one value at the centre of a circle and distribute the remaining 2∙n – 1 values evenly along the circle's circumference. Draw a line from the centre to one of the values and, in the orthogonal direction, the n – 1 chords that pair the remaining values. The connected pairs belong to the same class; the other classes are obtained by rotation of the line/chords pattern. Because each possible chord length occurs in the pattern, each y-ary value can be subjected to y–1 different transitions, each from a different class. (End of proof.)

(iv)    With y = 6, we get, according to Theorem 1, 5 transition classes. Analogously to (ii) we can construct a graph of 2∙6² = 72 nodes of degree 1 + 2 + 3 = 6 and of diameter 2 + 1 + 1 = 4. (End of (iv).)

For larger values of y, x = 2 is too small if the degree should not be larger than in the comparable hypercube: with x = 2, each next 7-ary digit gives an average degree increase of (7–1)/2 = 3, but 7 < 2³ .

(v)    With y = 7, we get, according to Theorem 0, 3 transition classes. With the x-ary connectivity as in (i) , we get graphs with 3∙7k nodes of degree 2 + 2∙k and with diameter 3 + k. (End of (v).)

(vi)     For x = 3, y = 10 is interesting. We get —Theorem 1— 9 transition classes, and graphs with 3∙10k nodes of degree 2 + 3∙k and with diameter 3 + k, e.g. for k = 2:  300, 8, and 5 respectively. (Here we have extensively exploited the freedom, illustrated in (ii), of allowing x-ary digit values to enable y-ary transition from several classes as presented by our Theorems.) (End of (vi).)

For x = 4 and x = 5 the following x-ary connectivities are worth considering

.

where A, B, C, D, and E stand for the (groups of) classes into which the y-ary transitions have been partitioned. They have the property that L = x can be achieved with degree 2. (Achieving L = x for x = 6 requires nodes of degree 3.)

(vii)    For x = 5, y = 16 we thus generate a class of graphs with 5∙16k nodes of degree 2 + 3∙k and with diameter 5 + k. For larger values of k the gain on the hypercube —both in degree and in diameter— becomes impressive. (So does the size of the graph.) (End of (vii).)

Finally, we mention one further freedom: different x-ary values may enable the same y-ary transition. The 4-ary connectivity

.

gives rise to L = 3. It may be considered as an alternative if three groups A, B, and C are appropriate, but a binary or ternary leading digit is not.

Acknowledgements I am endebted to J.L.A. van de Snepscheut for drawing my attention to the possibility of gaining on the hypercube and to the Austin Tuesday Afternoon Club for its constructive comments on three (very different) versions of the presentation of the above. (End of Acknowledgements.)

Austin, 27 February 1987

transcribed by Martijn van der Veen
revised Thu, 14 May 2009

EWD 1006

Trip Report E.W.Dijkstra, Stanford/Palo Alto, 26–29 March 1987

I had been invited as the keynote speaker at a symposium on "The First Ten Year of Computer Science at Stanford.", in my capacity of "well-qualified observer who was not directly involved in the Stanford program". After I had accepted this invitation, Computer Literacy Book Shop in Sunnyvale asked me whether I would be willing to give as well a talk under their auspices.

Originally I had booked tickets for Ria and me to San Jose with UT's travel agent, Sanborn's; for a round trip (with American Airlines and Continental) they charged $ 430.— . When Jayadev Misra heard this, he picked up the telephone and booked us to San Francisco with Southwest Airlines for $ 198.— per person. That was a difference of $ 464.— and we decided not to complain, not even if Southwest would fly us via Hawaii. (It turned out that this was a good decision as Southwest no longer believes in feeding its passengers: after our first flight to Phoenix, Southwest had even run out of peanuts.)

The Stanford symposium started with a reception on Thursday evening, but we missed that because I had to lecture in Austin on Thursday morning. In the course of the afternoon we left on a flight to Phoenix, where we changed planes. With an intermediate stop in San Diego they flew us to San Francisco, where we were collected by Jim Horning, who took us to Stanford's Faculty Club. There we arrived at 21:45. We had been assured that the Student Union next door was open 24 hours a day, so there we went to eat something. It was spring break, however, and the Union was closed. A little hollow we went to sleep. By way of welcome, the Symposium Committee had adorned our room with a beautiful flower arrangement (which we admired) and a bottle of cooled white wine (which we did not open in view of our more than empty stomachs). We also admired the apartment in the Faculty Club, for it had been very nicely designed.

The next morning at 7:30 we were at the Terman Engineering Building for Registration & Continental Breakfast. The latter gave the usual wrong impression of breakfasts as served on the Continent, but was welcome anyhow. At 8:30, the speeches started. The morning was taken up by

Welcome to the University (James Gibbons, Dean)
Symposium Introduction (John V. Levy, Chairman Symposium)
The Visiting Committee for Computer Science (Cuthbert Hurd)
Origins of Computer Science at Stanford (William F.Miller)
Impact of Stanford CS on Academia and Industry (Thomas H.Bredt)
             Coffee Break
The Early History of the Stanford Computation Center: A Personal Collection (Edward A.Feigenbaum)
Computer Science Today at Stanford (Nils J.Nilsson, Chairman of the Department)

Fortunately, the CS Department at UT had celebrated its 20th Anniversary last fall, and so I knew more or less what to expect. This time, the proceedings did not shock me anymore. It was mostly on money, power, and housing, a little bit on computers and hardly on science. An exception was Thomas H.Bredt, who gave some surprising statistics, e.g. that the overwhelming majority of the Stanford graduates of those first ten years were still with their first or second employer. The overwhelming majority also still lived in California; the latter strengthened my overall impression, viz. that we were witnessing a local event.

In the afternoon we had
Theoretical Foundations: Then and Now (Donald E.Knuth)
Numerical Analysis: Then and Now (Gene E.Go1ub)
Systems and Languages: Then and Now (Forest Baskett)
            Coffee Break
Artificial Intelligence: Then and Now (John McCarthy)
Student Perspectives: Then and Now (Panel of current and former students)
Closing Presentations (which may have been skipped, for I don't remember them)

Knuth and Golub, both very much in their own way, were highly informative. Knuth showed early correspondence concerning his appointment (and that of Robert W.Floyd) and a classification according to subject of the Ph.D. Theses and Technical Reports in his field as they appeared over the years, while Golub had the courage to be technical. Baskett (currently with Silicon Graphics, Inc.) talked about businesses and McCarthy gave a slide show of pictures (the construction and the demolishing of one of their buildings) he did not recognize himself.

The overall impression created by the picture of the past was a systematic neglect of computing science's core. The "theorists" regard machines primarily as tools or as a source of their mathematical problems or as an application area for their mathematical theories; for the others they were only tools. Computing Science as a discipline in its own right hardly emerged. Nilsson gave his vision of the future of the department; I can describe it only as "more of the same". I saw no effort to remedy the situation and that was a bit saddening. I talked about this with a number of people. The general feeling was that the department was saved by the very high quality of its students, 50 % of them being able to find their own way. I found myself dreaming about what the alumni would have been able to achieve, had they been properly educated by the department ....

Afterthought In view of the quality of their students —only a minute fraction of the applicants is admitted— the fact that the output of the graduate program is only 50 % of its intake is a very sobering thought indeed. (End of Afterthought.)

After cocktail party and banquet I addressed an audience of about 180 for about an hour; I did so under the title "How well did we do?". Instead of pronouncing a verdict, I gave them a number of yardsticks. The talk was followed by a lively question-and-answer period and my whole performance was well-received. During the day I had already realized that quite a few of my yardsticks would not show the Stanford Department in a very favourable light; I noticed that none of the faculty members present entered the discussion.

The next morning Dan Doernberg, the founder of the book shop, would collect us at 8:15. We were packed and he arrived at 8:35, having lost his way on campus. (He hardly apologized; is punctuality no longer a Californian virtue?) He took us to The Blue Sky Cafe, where we had a nice, though extremely healthy, breakfast. I had to perform at lO:OO, and we arrived at the place at 9:58.

The duty to address an audience of 350 with a flip chart as only way of showing something severely constrained me in the choice of examples; fortunately this situation did not catch me totally unprepared and my talk went very well, my only purpose being to give the audience some feeling for the nature of the mathematical arguments used in program development. I spoke for about an hour and then we had a very successful discussion session: the audience, which was a pleasure to work with, distinguished itself by departing from my examples no later than at the third question. After more than another hour, while I was answering to questions and signing books, Doernberg took the two of us to Hotel Horning, where we stayed for another 24 hours.

It was a pleasure to see Jim and Jane again. They were perfect hosts: they showed us some of the surroundings, but not too much, they offered us lunch and brunch in pleasant restaurants, and had invited some nice company for Saturday evening dinner. That evening I would have liked to conduct some technical talk with Greg Nelson, but by the time the opportunity was there I was too tired: I had worked with sizeable audiences, and that showed. The night we spent in Hotel Horning is memorable for the fact that I don't remember a single second of it.

Saturday afternoon we paid a short visit to the DEC System Research Center, the interior decoration and the furniture of which we immediately felt at ease with. It was perhaps even nicer than the Faculty Club. The general taste displayed was markedly more "modern", more "cosmopolitan" than we have adapted ourselves to in the mean time. This was confirmed the next day when Jim and Jane took us to one of the Palo Alto book shops: at the entrance, they had about two dozen foreign newspapers. Jim told me some about the work he was doing, and I was, besides instructed, very pleased with what I heard.

We were due to take off at 15:45 from San Francisco, but it was 16:45. Three intermediate stops —San Diego, Phoenix, and El Paso— enables Southwest to catch up with most of the delay, and after a flight of five hours, we arrived at 23:25 in Austin. It was cold, and the next day we heard that we had missed a weekend of foul weather. The next day I had appointments a t 9, 11, 12, 13, and 14:OO. It was one of those days (which, fortunately, are relatively rare).

Austin, 31 March 1987                                  

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750
USA

transcribed by Mario Béland
revised Thu, 14 May 2009

EWD 1008

What Computing Science is about.

When automatic computing equipment began to become available, it quickly became clear that the naive approaches of the day were grossly inadequate for the fruitful exploitation of the new technologies, and Departments of Computing Science were founded in response to that need. They were founded, however, prior to a consensus about what Computing Science as intellectual discipline should encompass. (During its first decade, Computing Science suffered, in fact, from an "identity crisis".)

The discipline was in part shaped by the constraints of academic viability, in particular those of permanence and of coherence.

The requirement of permanence rules out all concerns whose loss of significance is foreseeable in the near future: hence, particular properties of equipment currently on the market could not be allowed to play any role.

Since automatic computing equipment truly deserves the characterization "general purpose", whatever was specific to some application area had to be excluded: for the sake of its own coherence, Computing Science had to focus its attention on the application-independent aspects of automatic computing.

As time went by it became clear that, instead of "automatic computing", the more general term "automatic symbol manipulation" was more appropriate. The act of automation, however, requires programming; programming evolved from a naive activity to the application of formal techniques, and program design itself became more and more a matter of symbol manipulation. Consequently, computing science found itself concerned with the interplay between automatic and human symbol manipulation.

This interplay has profound logical aspects —such as decidability— , but has been shaped in more detail by its quantitative aspects, which in more than one way are overwhelming.

Firstly, there is the question of what we leave to the automaton and what we do ourselves: it may be quite simple to state a desired result as the solution of a mechanically solvable equation, whose mechanical solution, however , would require the storage of more bits of information than there are atoms in the universe. (Also, even a computation that with current technology would take 1000 years is not very interesting.) In such cases some more human involvement is clearly indicated.

Secondly, if we view programming as the human formal labour done in order to keep the mechanical symbol manipulation within doable proportions, there is the urgent question of how to do our programming with enough efficiency.

There is no doubt that programming, viewed as a mathematical activity, has to be a very (if not totally) formal one. Mathematical theorems intended for human usage are appealed to in a modest frequency and, moreover, by mathematicians, who are wise enough not to appeal to a theorem in a situation in which it obviously does not hold. A programmer's theorem that a given repetition maintains a given invariant, however, is appealed to in high frequency ~ thanks to mechanization easily up to 1000 Hertz ~ and, moreover, these appeals take place without a wise mathematician as witness. In this sense, Programming = Mathematics + Murphy's Law. (The latter states "Anything that can go wrong will go wrong".)

Hence, the required trustworthiness makes it mandatory that programs are derived formally. (I think it can be argued that computing scientists have been the first to make intensive, large-scale use of formal logic as an indispensable tool for their daily reasoning.) Viewed as formal objects, however, programs quickly become of an awesome size, representing big, and at the same time compact deposits of our intellectual labour. Hence the great stress on the efficiency with which the programmer does his part of the symbol manipulation.

Computing Science , therefore, finds itself confronted in full force with the problem of the economics of formal reasoning. This can be viewed as a long-standing problem of mathematical methodology, but the point is that in automatic computing it can no longer be ignored: there it becomes the central issue. In addition, the possibility of mechanization adds a totally new dimension to the cost/benefit analysis.

Historical Remark The earlier computer applications were of an obviously repetitive nature: the payroll had to be done each month, and each month the size of the job was linear in the number of employees. What to mechanize was in those days a clear-cut problem. With mechanical proof verification, or a certain amount of mechanized reasoning as component of a general-purpose programming system, the decision what to mechanize is no longer obvious at all. A shift in ambition has caused a shift in perception. (End of Historical Remark.)

A final remark about the role to date of (formal) program derivation, since that role has been played down by the observation that relatively few new algorithms have been designed —or "discovered", if you are a Platonist— that way. The new ones that were designed were way beyond the conceptual limits inherent in the traditional intuitive approach, but, more importantly, it has completely changed the intellectual status of many a published algorithm, viz. from an incompletely formulated or erroneous conjecture to a crisply stated and proven theorem.

Pasadena, 25 May 1987

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

[Written for Harvey Friedman]

Transcribed by Mario BÈland .

Last revised on Thu, 14 May 2009.

EWD 1009

On a somewhat disappointing correspondence

I did not react to Frank Rubin’s letter [0], confident that all my potential comments would be made by others, but in the five letters published two months later [1], I found none of them expressed. So, I reluctantly concluded that I had better record my concerns, big and small.

(0) The problem statement refers to an N by N matrix X; Rubin’s programs refer to an n by n matrix x. In other contexts this might be considered a minor discrepancy, but I thought that by now professional programmers had learned to be more demanding on themselves and not to belittle the virtue of accuracy. I shall stick to the capital letters.

(1) Rubin still starts indexing the rows and the columns at 1. I thought that by now professional programmers knew how much more preferable it is to let the natural numbers start at 0. I shall start indexing at 0.

(2) Rubin’s third program fails for N=0 (in which case his second program succeeds only by accident —see below—). I thought that by now professional programmers would know the stuff the silly bugs are made of.

(3) Rubin’s second program fails to detect the first all-zero row if it is the last row of the matrix.

(4) Rubin’s third program relies —without stating it explicitly— on the “conditional and”, for which, if the first operand is false, the second operand is allowed to be undefined. The conditional connectives —“cand” and “cor” for short— are, however, less innocent than they might seem at first sight. For instance, cor does not distribute over cand: compare

(A cand B ) cor C     with     (A cor C ) cand (B cor C );

in the case ¬A ∧ C , the second expression requires B to be defined, the first one does not. Because the conditional connectives thus complicate the formal reasoning about programs, they are better avoided.

(5) Rubin’s letter effectively conceals that his problem can be solved systematically by a nested application of the same algorithm (sometimes known as “The bounded linear search”). His statement of the problem is: “Let X be an N×N matrix of integers. Write a program that will print the number of the first all-zero row of X, if any.” Now, concentrate to begin with on the “if any”; nothing should be printed if all rows differ from the all-zero row, formally, if

(A i : 0≤i<N : ¬(A j : 0≤j<N : X [i, j] = 0 ))     .

The theorem of “The bounded linear search” states

for any boolean function B on the first N natural numbers (N≥0)

|[ var f : bool; var n : int
; f, n := true, 0 {P}
; do f ∧ n ≠ N → f, n:=B(n), n+1 od
; { P ∧ (¬f ∨ n=N )}
]|

with the invariant P given by

P :     | 0 ≤ n ≤ N     ∧ (f ≡ (Ak : 0≠k<n : B(k)))     ∧ (Ak : 0 ≤ k < n–1 : B(k))

which states that, upon termination

in the case of f | :   | all B’s are true, and
in the case of ¬f | :    | n–1 is the smallest value for which B is false.

Applying the above theorem twice yields for Rubin’s problem

|[ var c : bool; var i : int
 ; c, i := true, 0
 ; do c ∧ i ≠ N→
        |[ var d : bool; var j : int
        ; d, j := true, 0
        ; do d ∧ j ≠ N → d, j := X [i, j] = 0, j+1 od
        ; c, i := ¬d, i+1
        ]|
    od
 ; if c → skip ⌷ ¬c → print (i–1) fi
]|

and for me this settles the problem.

By my standards, a competent professional programmer in 1987

should recognize that Rubin’s problem asks to be solved by a nested application of the same algorithm;

should know the theorem of “The bounded linear search”;

should be able to derive that theorem and its proof;

should not hesitate to use it;

should not waste his time in pointing out that the boolean variable d is superfluous;

should keep his repetitions simple and disentangled;

etc. . .

Evidently, my priorities are not shared by everyone, for Rubin’s letter and most of the five reactions it evoked were conducted instead in terms of all sorts of “programming language features” that seem better ignored than exploited. The whole correspondence was carried out at a level that vividly reminded me of the intellectual climate of twenty years ago, as if stagnation were the major characteristic of the computing profession, and that was a disappointment.

References

[0]       | Rubin, Frank ““GOTO Considered Harmful” Considered Harmful” Commun ACM 30,3 (Mar 1987), 195–196
[1]   | Moore, Donald and Musciano, Chuck and Liebhaber, Michael J. and Lott, Steven F. and Starr, Lee “““GOTO Considered Harmful” Considered Harmful” Considered Harmful?” Commun ACM 30,5 (May 1987), 351–355

                     Pasadena, 25 May 1987

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Mario Béland
revised 20-Dec-2012

EWD 1011

Introducing my fall 1987 course on Mathematical Methodology

The purpose of this introduction is three-fold:
(0)   to give you some idea of what to expect from this course,
(1)   to tell you how I propose to reach my goals, and
(2)   to explain what will be expected from you.

The idea of giving this course has been born out of dissatisfaction with the ways in which mathematics has usually been taught since I was a student. The courses I followed consisted of facts, facts, and more facts: the triple (definition, theorem, proof) repeated ad infinitum. Very useful if you wish to apply or extend the theory presented and totally useless otherwise. Later I saw a different type of mathematics course emerge: tricks, tricks, and more tricks, recipes for solving special types of problems and endless exercises so as to make their execution a routine job. Useful perhaps when that routine job is what you are heading for, but, again, totally useless otherwise. Furthermore, particularly in countries where rhetoric is confused with effective use of language, we have seen courses that are the cult of pure form: the students are only taught a pompous language and mathematics is reduced to mannerisms.

The students that, like the wild animal being prepared for its tricks in the circus called "life", expects only training as sketched above, will be severely disappointed: by his standards he will learn next to nothing.

Let me quote, by way of contrast and for inspiration, what G.R.Elton wrote about the teaching of history:

Three or four years spent at a university cannot teach a man to know history; they cannot train him as a politician or publicist or publisher; they can at best begin to lay some foundation for a view of the world and (universities being what they are) are likely to lay foundations which, as later experience shows, need to be broken up. None of this invites blame: the impossible need not be attempted. But if those years do not produce an effective conditioning of the reasoning mind, if they do not teach a man to think better than otherwise he would have done, they may justly be condemned as a waste of time.

Well, I would be grieved to hear if your years at UT could, in Elton's words, "justly be condemned as a waste of time". In the name of "an effective conditioning of the reasoning mind", in order to teach you to "think better than otherwise you would have done", this course is about the doing of mathematics. It is my purpose to bring into the public domain what in traditional mathematics courses is left implicit.

It is not my purpose to turn, in a one-semester course, all of you into as many excellent mathematicians. Remember: the impossible need not be attempted. But I can and shall try to give you the opportunity of becoming a better mathematician than otherwise you would have been and propose to do so by exposing at least the major components of the mathematical craft and by warning you explicitly for some of the more common mistakes that the experienced competent mathematician avoids out of habit.

How to raise such a course above the level of motherhood statements —the level that is characteristic for the self-improvement or management courses sold by the training industry— has been told to us by William Blake (1757–1827):

He who would do good to another must do it in minute particulars/General Good is the plea of the scoundrel, hypocrite and flatterer/For Art and Science cannot exist but in minutely organized particulars.

The moral of this quotation is that, in principle, no detail will be too small for our attention. I also like this quotation for the way in which it mentions Art and Science in the same breath, for, indeed, the analogy between the performing artist and the productive scientist is not so far-fetched at all. Among the very basic things the young pianist has to learn is how to take care of his finger nails: we shall encounter similar care to be taken, so to speak, of our mathematical fingernails. Also, the performing artist must become very familiar with the potential and the limitation of his instruments; so must we with our instruments, such as pen, paper, and the printed page.

The analogy goes further. Just as a professor at a conservatory represents a musical style (to the extent that it is often possible to identify the master by listening to his pupils), I represent a mathematical style. It is up to you to decide later to what degree to adopt and to improve it. One thing, however, you are not allowed to do, viz. to reject it offhand for the sole reason that it does not reflect the way of doing mathematics you are used to. Of course it doesn't! That is precisely why you are here. This whole course is no more and no less than an invitation to take the experiment of changing some of your reasoning habits and adopting some new modes of expression. As you take the experiment you will notice that it is not acquiring the new habits that presents the greatest problem, for that is getting rid of the old ones. Perfecting oneself is as much unlearning as it is learning.

This is obvious. Yet it needs to be stressed because stupid educationists have invented for the educational process the profoundly inadequate term "knowledge transfer", suggesting a uni-directional stream of knowledge towards an accumulating recipient, who becomes monotonically more knowledgeable. This is a caricature at best.

In general, I would like to reduce the waste of time and effort. I shall not give you the magic formula that will protect you for the rest of your life from exploring dead ends, but should be able to make you alert for the most obvious blind alleys in which the inexperienced problem solver wastes most of his time. I should be able to teach you how to stay away from complicated solutions when a simple one exists. I should be able to make you aware of some of the techniques for designing a crisp argument.

In order to create that awareness, it does not suffice to solve problems or to prove theorems: we have to discuss and compare solutions and proofs. It does not suffice to identify after the fact a blind alley, we have to discuss whether it has some clear characteristics of the dead end and whether we could have seen them beforehand. It does not suffice to say "I like that argument better than that other one." but we must be able to say why we prefer the one argument over the other and must understand the justification for our preference. In the course of the process we should never forget that we are scientists, and that we have the obligation to raise our preferences above the level of personal tastes to choices that have a technical justification.

I can see three ways of doing so. I can present the alternatives, tell you my preferences, and explain their justification. The next way requires a little bit more participation from your side: I provide the alternatives and together we discuss their merits. In the third pattern you provide the alternatives as well. It is the last pattern I prefer most. My target is to leave you at the end of each lecture with a clear question, about which you are supposed to think before the next lecture. Usually different students come at the next lecture with very different answers; and those different answers provide the material for comparison.

This last format implies a multiple obligation from your side. Between lectures you should try to solve the problem I gave you and to think about how you would present your solution. The next lecture you should be willing to come to the blackboard and present your solution to all of us. And finally you must accept that your solution and its presentation is discussed. If I may use the musical analogy again, I would like to conduct part of this course as a "master class" of, say, a teacher of pianists. These could be called "public piano lessons". In such performances you should participate in a non-competitive spirit, eager to learn how what you did can be improved. The ability of discerning high quality unavoidably implies the ability of identifying shortcomings.

(I mentioned the non-competitive spirit explicitly, because these days, excellence is a fashionable concept. But excellence is a competitive notion, and that is not what we are heading for: we are heading for perfection.)

*                         *
*

I hope that I have made it clear that I expect from you active participation. Yours is the role of wetstones and not of sponges; please remember that because when I am addressing sponges I always run dry very quickly. There is one specific I occasion in which you must open you mouth immediately: you have to ask for clarification when you don't know what I am talking about. The technical problem of a course like this is that you are of highly varied backgrounds, with which I am not familiar. When illustrating something with an example I always run the risk of using a term some of you don't know. If so, let me know: interrupt me immediately so that I can supply the missing information.

Let me close this introduction with a final advice, just in case you develop the lurking suspicion that I am giving this course for my own fun. Of course I hope to give this course for my own fun, but remember that I fervently hope to give it for your fun as well. There should be no such thing as boring mathematics.

Austin, 31 August 1987                                  

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Mario Béland
revised Thu, 14 May 2009

EWD 1012

“Real mathematicians don't prove”

Roughly speaking, there are two ways in which people try to reason about programs; I shall distinguish them as “the postulational method” and “the operational method”.

The first method is called “postulational” because it postulates how the program text and the specification define the lemmata to be proved in order to show that the program meets the specification. (In effectively discharging this proof obligation, the predicate calculus has shown itself to be an indispensable tool.) The postulational method treats the program text as a mathematical object in its own right, i.e. semantic equivalence of two programs means that they meet the same specifications.

The second method is called “operational” because it tries to analyse what computations could be evoked under control of the program and to establish that each possible computation is compatible with the given specification. It relies on a computational model with respect to which the program text is interpreted as executable code.

The tragedy of today's world of programming is that, to the extent that it reasons about programs at all, it does so almost exclusively operationally. I call this a tragedy because, from a purely technical point of view, the operational method is by several orders of magnitude inferior to the postulational one. With growing size or sophistication of the program, the operational argument quickly becomes impossible to carry through, and the general adherence to operational reasoning has to be considered one of the main causes of the persistence of the software crisis.

A possibly very fundamental flaw of the operational method is that it begs the question how to reason about algorithms, because it translates the possible effects of a given algorithm into those of another one, viz. the program interpreter (i.e. the abstract machine that underlies the computational model). We shall not pursue that potentially severe shortcoming here. Our current concerns are much more pragmatic: by admitting —or should we say: by generating?— the possible computations into our considerations we open the door to a combinational explosion, the effect of which quickly defies exhaustive analysis. [Remember the archetypical programmer's excuse for a bug “Oh, but that was a very special case.”!] Instead of finding out how to cope with the effects of such combinational explosions, it is much more effective to prevent the combinatorial explosion from occurring in the first place; this is what the postulational method achieves by not taking into account that the program text admits the interpretation of executable code. The postulational method deals with the program text as a parsed but otherwise uninterpreted formula.

As soon as the postulational method began to be forcefully advocated, it met equally forceful opposition, all of which was quite predictable. I mention, by way of illustration

(0) It is of a “theoretical level” that “places it beyond the scope of most amateurs”, or: “but that would require a lot of education”. (Standard answers varying from “I never claimed that amateurs should be able to program well.” to “Well, education is my business.”.)

(1) The postulational method is of no relevance for the real world, for real programmers don't think that way. (Standard counterquestion: “Do you mean to say that I am a virtual programmer?”.)

(2) It cannot be any good because backward reasoning and weakest preconditions are counterintuitive. (Standard answer: “If a simple calculus can achieve what is so ‘counterintuitive’ that it is beyond the unaided mind, so much the better for that simple calculus.”.)

(3) It may be okay for toy programs, but you'll never be able to apply it in the case of real programs. (Standard answer: “Yes, scaling up is a problem, but the operational argument becomes much sooner impossible than the postulational one.”.)

(4) By imposing such strict logical constraints, you stifle the programmer's creativity. (Various answers are possible, such as “Unbridled creativity has done more harm than good.” and “If the programmer really wants to be an impressionistic poet, he is in the wrong business.”. For a more sophisticated audience you can explain that, at each stage of the design, the explicit statement of the designer's obligations is at the same time an explicit statement of his freedom, thereby inviting him to explore alternative designs the traditional programmer almost certainly overlooks. If time permits, you can give an example.)

(5) Etc.

The moral of the story is clear: real programmers don't reason about their programs, for reasoning isn't macho. They rather get their substitute for intellectual satisfaction from not quite understanding what they are doing in their daring irresponsibility and from the subsequent excitement of chasing the bugs they should not have introduced in the first place.

*        *        *

The above battles are only too familiar to anyone with even the faintest acquaintance with programming methodology. The reason why I described them is that they are the battles that pervade the rest of mathematics: the “formalists” that try to do mathematics by manipulating uninterpreted formulae accordingly to explicitly stated rules and the “informalists” —only they don't call themselves by that negative name: presumably they present themselves as “the real mathematicians”— who constantly interpret their formulae and “reason” in terms of the model underlying that interpretation.

After having given examples of “pragmatic demonstration of the creative power of the postulational method”, E.T.Bell continues with “Mathematicians and scientists of the conservative persuasion may feel that a science constrained by an explicitly formulated set of assumptions has lost some of its freedom and is almost dead. Experience shows that the only loss is the denial of the privilege of making avoidable mistakes in reasoning. As is perhaps but humanly natural, each new encroachment of the postulational method is vigorously resisted by some as an invasion of hallowed tradition. Objection to the method is neither more nor less than objection to mathematics.” That last sentence is very clear as to what E.T.Bell thinks worthy of the name “mathematics”. He does not classify himself as one of “the mathematicians of a conservative persuasion”.

Let us quote some of those by way of contrast: Philip J.Davis and Reuben Hersch. They refer to “the error of identifying mathematics itself (what real mathematicians really do in real life) with its model or representation in metamathematics, or, if you prefer, first-order logic.”. In the next paragraph —and now it is beginning to sound very familiar— they dogmatically state “that such [formal] derivations [in first-order logic] are purely hypothetical activities (except for ‘toy’ problems that might be played in a course in logic).”. In the next sentence they refer to “real mathematics, with proofs which are established by ‘consensus of the qualified.’ A real proof is not checkable by a machine... ”. Whereas Bell (in 1940) refers to mathematics as a goal, Davis and Hersch (1981) refer to the average status quo, including all its medieval or older relics.

My trouble with Reuben and Hersch is that their status quo seems so close to their goal. They admit that “a teacher can teach mathematics and a researcher can write papers without paying attention to the problem of intuition” but only do so under the proviso “perhaps it would be foolish and self defeating”. My tentative conclusion is

(i) that they have never tried to teach mathematics formally and explicitly without appeal to intuition —if they had, it would have been a most refreshing experience for them and for those of their students that were sufficiently well-educated to appreciate simplification

(ii) that they have never taken the trouble to learn how to let the rules of the formal game guide their “writing of papers” —if they had, they would have discovered how to do mathematics way beyond their former powers.

(Speaking from experience. I can, of course, not expect to convince anybody.)

The consensus model of mathematics seduced A.J.Perlis et al. to argue the futility of the aim of designing programs proven to meet their specification. What they missed is that computing science is probably one of the least medieval branches of mathematics —not of “real mathematics” of course!—.

*        *        *

For a sociologist of science there is the question why, in contrast to other sciences, in mathematics —I mean “real mathematics as really done by real mathematicians in real life”— the medieval characteristics are still so overwhelming. (E.g. how to do mathematics is not taught explicitly but only by osmosis, as in the tradition of the guilds. The usual excuse —even from otherwise well-reputed professors of mathematics— is that there is no other way.)

I am insufficiently knowledgeable to offer a convincing explanation. I have understood that the renaissance was a traumatic experience for the intellectual establishment of the day. (Vide the fate of Galileo Galilei.) The notion of science (as understood today) was born during the Renaissance (and grew up during the Enlightenment), and the intellectual establishment of the Middle Ages —i.e. theology and mathematics— had to discover how to cope with it. It took theology —at least the popes of Rome— almost four centuries to solve their problem by divorcing their religious teaching from scientific pretension. It is quite possible that mathematics is even more between a rock and a hard place. By its mere utility its divorce from science was not encouraged. (We should note that, by focussing their attention to provability, the formalists have turned away from the fuzzy metaphysical notion of “truth”. This was quite an achievement: we should remember that even as late as in the previous century mathematics still suffered from such a heavy philosophical pollution that no one less than C.F.Gauss thought it wise not to publish his discovery of non-Euclidean geometry and left it to Bolyai and Lobachewski to receive the flak.)

While, in the Renaissance, the other sciences were just beginning or could start over again with a tabula rasa, mathematics was punished with the burden of many centuries of premedieval mathematics that, in a way, maintained its relevance. It is quite understandable that, at the time, it clung to Euclid.

But this historical explanation is no excuse for the fact that today Euclidean geometry, with all its known defects, is still taught as the prototype of a strictly deductive system. It is not. Its reliance on pictures is quoted as evidence for the value of “geometric intuition”, while in fact it is only a symptom of the defects of Euclid's axiomatization. (In passing I would like to add that I see more and more evidence that it is precisely the informality of the pictorial argument that defies the development of heuristics by means of which such arguments can be designed in an orderly fashion. This is in sharp contrast with the highly effective heuristics that could be developed for strictly formal environments.)

The pretence with which Euclidean geometry is taught today (viz. that it is a strictly deductive system) is a great, big lie. Its general acceptance (and the wide-spread praise of “intuition” in its wake) is telling: mathematics today is still a discipline with a sizeable pre-scientific component, in which the spirit of the Middle Ages is allowed to linger on.

| Eventually completed at Austin on 24 Januari 1988

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Javier Smaldone.

Revised 11-Nov-2014 .

EWD 1013

Position paper on "fairness"

Life is a very complicated business if you want to do it well. This is because anything of any importance is always a many-sided affair and none of its different aspects may be neglected, while at the same time, in order to do the whole job well, the different concerns have to be separated as ruthlessly as possible.

Before embarking on a major research topic, you had better choose your target very carefully because the borderline between the insipid and the impossible is very thin. In other words, you had better be fully aware why you engage yourself on the project. At the same time you had better separate that concern entirely from the technical question of how to achieve your goal. The why and the how are completely distinct concerns, and nothing is gained by mixing the two. On the contrary.

Let us accept as Thesis that the research of a Computing Scientist is eventually concerned with automatic computing. That leaves a wide range: from improving the equipment to improving our abilities of using the equipment. In one way or another, automatic computers and their usage provide the soil in which our "why" has its roots. Fine.

But in order to do your research successfully, you also have to think very carefully about how to conduct your research, and this time because the borderline between success and failure is preciously thin. And in carefully thinking about your "how" you will almost certainly discover that in major parts of your investigations automatic computers, with all their quirks and physical limitations, are totally irrelevant and had better be forgotten.

*                              *
*

One area in which it has proved to be very fruitful to forget that automatic computers exist is programming. One forgets that computers exist, one ignores that one's programs admit —in another world, so to speak— the interpretation of executable code and treats the program text as a mathematical object in its own right. All by itself it is not a very interesting object, but in combination with its functional specification, the statement that the program meets its functional specification is a theorem. At that intellectual level, programming is about how to design such theorems and their proofs. And from sad experience we all know that this activity reveals a core challenge, if not the core challenge, of computing science, viz. "How not to make a mess of it and how not to get confused in the complexities of one's own making.".

What is at that level the role of the programming language used? Essentially only one, viz. to define the proof obligations engendered by presenting the combination of program and functional specification as a theorem.

In this part of the exercise it is clearly totally irrelevant whether the programming language used to express this theorem has been implemented. It is even irrelevant whether an economically acceptable implementation is technically feasible.

Let me elaborate for a short while. I have to respect the strictly limited size of my head and can deal with only one thing at a time. This means that in designing my program the fixing of certain details will have to be postponed; it also means that meeting certain proof obligations will be postponed. Such "abstract" programs often distinguish themselves by the inclusion of some powerful statements that almost certainly defy automatic implementation, and they are usually grossly nondeterministic. I may, for instance, meet a proof obligation whose operational interpretation is that the nondeterminacy gives so much freedom that there exists a scheduling that does not lead to deadlock. That at the same time an implementation that would avoid deadlock defies imagination should not deter me at all. Implementation is only an operational concern that plays no role in the theorem I am developing.

A totally new set of considerations enters the picture by the time that I would like to use my theorem in the sense that I would like to have my program executed because I am interested in the result of the ensuing computations. For that purpose the programming language I wrote the program in has to be implemented on a sufficiently powerful machine. And suddenly the language definition appears in a totally different light. It gives the implementer rights and obligations; he has the right to refuse successful completion of the execution of programs in which syntactic or semantic constraints have been violated, he has the obligation to generate —within the capacity of the machine— computations meeting the specification. In this sense, a programming language emerges as a contract between programmer and implementer, stating the rights and the obligations for both partners in the deal. If the programmer has met his proof obligations, he is entitled to the correct results; the implementer has the obligation to see to it that I the correct result is produced, but has the right to refuse programs violating the stated constraints.

Let us now consider the little program fragment

  b := true
; do b → print(0)
  ⌷ b → print(1); b := false
   od

While still dealing with abstract programs I am perfectly willing to accept this as a program that prints an arbitrary number of zeros and stops after the printing of the first one. I am even willing to accept this as a program that under the assumption of a sufficiently benevolent scheduler will, sooner or later, print that one and then stop. Such "behaviour" is thinkable and at that level thinkability is the only thing that matters. (I may add that my willingness has been a very active one. Inclusion of unbounded nondeterminacy amounts to the loss of or-continuity; how to design proofs that do not rely on or-continuity has been one of my more recent contributions.)

So far, so good. But things change drastically as soon as we start talking about an implemented programming language. Then the programming language emerges as a contract stating rights and obligations, and there are such things as void obligations.

I call an obligation void if it is impossible to detect if it has not been fulfilled. I can easily promise to think at least three times per week about you, but that is a very cheap promise because no one will ever be able to show that I failed to fulfil my commitment. As a promise it is void.

Assume now that the language definition is such that above programming fragment is to print a finite string of zeros of arbitrary length followed by a one. This would be the prototype of a void obligation for the implementer. Firstly, nothing prevents him from implementing it in a way semantically equivalent to

  b := true
; do b → print(1); b := false od

As user of his system you may be disappointed that it never prints a zero, but the implementer can shrug his shoulders and say "You must have had bad luck! Try again.". What you may consider as a regrettable breach of contract on his part won't cause the implementer a single sleepless night because he knows that, though his obligation was void, he has fulfilled it. After all, zero is one of the arbitrary numbers.

Secondly, suppose that you pester him and start threatening with a law suit if you don't see any zeros printed. This time the implementer agrees to change the scheduler, and now he implements the fragment semantically equivalently to

  b := true
; do b → print(0) od

And now we are in the paradoxical situation that the implementer knows that he has violated the contract, for he knows that his product will never print a one. At the same time he knows that, no matter how many experiments you take, now matter how many instances of his program you start, you will never be able to produce the evidence that he has violated the contract. So, again you won't cause him a single sleepless night.

The moral of the story is that void obligations should not occur in contracts.

Finally I would like to point out that in the case of fairness the implementor's situation is drastically different from that of the quality controller in a roulette factory. There is no experiment that he can take to assure that a roulette coming out of the factory is unbiased. With a perfectly fair roulette it is possible that each time he turns the roulette and throws the ball, the ball will end up at zero. Unlikely, but perfectly possible. Therefore the quality assurance man from the roulette factory will never tell you that a roulette is unbiased: his experiments will tell him the probability that it is unbiased and if you want that probability to be very high, you will have to pay more because he has to take a longer series of experiments. The dissatisfied customer can still try to sue the roulette manufacturer, not because he has been cheated by the latter but only on account of the very high probability that he has done so. In a case like that, the conscientious judge can give the roulette manufacturer only a probabilistic fine; whether or not it should be paid can be settled by the roulette in question.

But fairness is not a probabilistic notion and if the implementer is sued, he will be acquitted for lack of evidence. My conclusion from the above is that fairness, being an unworkable notion, can be ignored with impunity.

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

Austin, 14 October 1987

transcribed by Mario Béland
revised Thu, 14 May 2009

EWD1014

E.W.Dijkstra Archive: A monotonicity argument revisited (EWD 1014)

(This is derived from AvG36/EWD878 d.d. 22 Feb. 1984.)

Square brackets denote universal quantification over x and y. Function f satisfies

[ x < y ⇒ f.x.y < f.y.x ] (0)

We observe (0) =p < q  ≡  q > p [ y > x   ⇒  f.y.x > f.x.y ] =change dummies x,y := y,x [ x > y  ⇒  f.x.y > f.y.x ] ⇒pair-wise disjunction with (0); p < q  ∨  p > q  ≡  p ≠ q [ x ≠ y ⇒ f.x.y ≠ f.y.x ] =contrapositive [ x = y  ⇐  f.x.y = f.y.x ] =Leibniz: [x = y  ⇒  f.x.y = f.y.x] [ x = y  ≡  f.x.y = f.y.x ](1)

*        *        *

Consider the triangle

We were taught two theorems
"The sides opposite to equal angles are equal" or

α = β  ⇒  a = b (2)

"The angles opposite to equal sides are equal" or

α = β  ⇐  a = b (3)

The theorems were proved separately; both were geometrical proofs using congruent triangles. Prior to that it had already been shown that opposite to the larger angle lies the larger side, i.e.

[ α < β  ⇒  a < b ] . (4)

Consider now, for fixed c, a, and b functions of α and β. For reasons of symmetry a is the same function of (α, β) as b is of (β, α). i.e. for some f we have

a = f.α.β and b = f.β.α

Substituting this in (4) we see that this f satisfies (0), hence, on account of (1) we immediately get, as logical consequence

[ α = β  ≡  a = b ] .

i.e. the conjunction of (2) and (3): the geometrical proofs with the congruent triangles are superfluous. The proofs were an obfuscation.

A similar pair of theorems is

"An isosceles triangle has two angle bisectors of equal length" and
"A triangle with two angle bisectors of equal length is isosceles"

The one is considered easy to prove, the other one difficult. Thanks to the above, both theorems are subsumed in "The larger angle has the shorter bisector.", which follows from the formula for the length of the bisector of α:

√  b∙c∙(1 − (a
b+c)²)

which is a decreasing function of a and an increasing function of b.

The above suggests that, in the way in which geometry is taught, logic is underexploited. Historically understandable, but regrettable all the same.

22 October 1987

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Spenser Max Truex
revised 10-Sep-2020

EWD 1016

A computing scientist's approach to a once-deep theorem of Sylvester's

Well, actually it wasn't Sylvester's theorem, it was only his conjecture —dating from the year 1893—, and it remained so for more than 40 years until T. Gallai (alias Grunwald) "finally succeeded, using a rather complicated argument" [Coxeter]. We shall derive (essentially) the simple argument of L.M. Kelly (1948).

Theorem  Consider a finite number of distinct points in the real Euclidean plane; these points are collinear or there exists a straight line through exactly 2 of them.

To see that this is truly a geometric theorem and not a combinatorial one, we slightly rephrase the setting. Let us assume for a moment that collinearity of points in the Euclidean plane is fully captured by

(i) any pair of points are collinear, and if two collinear triples have two points in common, their four points are collinear.

Let us rephrase this: replace "points" by "people", "lines" by "clubs" and "collinear" by "club-sharing" (i.e., belonging to the one and the same club). Club membership is postulated to satisfy the analogue of (i):

(ii) any pair of people is club-sharing, and if two club-sharing triples have two people in common, their four people are club sharing.

The analogue of Sylvester's theorem would state for a finite population: all people belong to one and the same club or there exists a club with exactly 2 members. Its falsity is shown by the following counterexample of 7 people —numbered from 0 through 6— with the following 7 clubs: {013}, {124}, {235}, {346}, {450}, {561}, and {602}. Postulate (ii) is satisfied because each of the 21 pairs of people occurs in exactly 1 club. Thus we have established that Sylvester's theorem is truly a geometrical one; let us now try to prove it.

Being computing scientists, we love constructive arguments, i.e. we like to show that something exists by designing an algorithm that computes such a thing. We therefore propose to design an algorithm that computes a line that passes through exactly 2 of the points from a given finite, non-collinear set of distinct points. (Legenda: from here on we no longer repeat that the points are distinct, nor that they belong to the given, non-collinear set.)

More precisely, we have to design an algorithm that operates on a variable q of type: line and that establishes the post-condition R, given by

R : q passes through exactly 2 of the points.

The simplest idea is to initialize q by the line through 2 arbitrary points. (This is always possible because, the given set being non-collinear, there are at least 3 points.) If q goes through 3 or more points, it has to be changed, otherwise it can be accepted as final value. That is, with invariant P given by

P : q passes through ≥ 2 points

we propose as first approximation of our algorithm

  establish P by initialization of q
; do q passes through ≥ 3 points →
     change q under invariance of P
  od

Because

P ∧ ¬ (q passes through ≥ 3 points)   ⇒   R

we are done when the algorithm terminates.

Our remaining task is to ensure that it does terminate. To that end we have to exploit the finiteness of the given set and its non-collinearity. Because the exploitation of finiteness is absolutely standard, we first focus our attention on what we can conclude from the non-collinearity. From the latter we can draw only one conclusion in connection with q, viz. the existence of a point through which q does not pass. That is, we propose to introduce a variable E of type: point, and to strengthen P to P1

P1: q passes through ≥ 2 points ∧ q does not pass through E.

The new approximation of our algorithm is

  establish P1 by initialization of q and E
; do  q passes through ≥ 3 points →
  {?} change q under invariance of P1
  od

(Ignore for a moment the assertion "{?}"; the important thing to realize is that with the feasibility of maintaining the stronger P1, the non-collinearity of the given set has been exhausted.)

In the current stage of program design, our only option is a further refinement of the as yet rather nondeterministic

(0)     "change q and E under the invariance of P1"

Because we may have to reduce its nondeterminism lest the algorithm fails to terminate, let us investigate its freedom: what precondition {?} can we guarantee? We know of the existence of 4 points, viz. E and the three points on the current q. Because the new q has to pass through ≥ 2 points and has to differ from the old q, the new q passes through the old E and one of the 3 points on the old q; in each case, one of the remaining 2 points on the old q has to be chosen as the new E. In summary: for the new pair (q, E ) we have 6 possibilities.

For the termination argument we need a variant function of the pair (q, E ); because the number of points is finite, the number of pairs (q, E ) satisfying P1 is finite, and any function of the pair (q, E ) that decreases at each change will do.

What is the simplest function of a line and a point (not on that line) that we can think of? The Euclidean distance between the two!

Let us investigate whether we can refine (0) so as to decrease the distance between q and E. Let us name the three points on the old q: A, B, C, so that A becomes the new E. With that convention, the refinement of (0) that decreases the distance of the pair (q, E ) as much as possible is

(1)    q, E := of BE and CE the nearest to A, A.

Finally we derive a condition on A as our choice for the new E from the requirement that the variant function decreases. With

h = distance between E and q

b = distance between A and BE

c = distance between A and CE

the required decrease of the variant function is expressed by

(2)    b min c < h

In order to derive (2), we proceed as follows

b min c  <  h

=        { definition of min }

b<h  ∨  c<h

=        { similar triangles, see figure }

AB<EB  ∨  AC<EC

⇐        { monotonicity of + }     (See Note)

AB+AC  <  EB+EC

⇐        { P1 ⇒   BC < EB+EC, i.e. the strict triangle inequality }    (See Note)

AB+AC ≤ BC

=        { AB+AC ≤ BC, i.e. trianglular inequality }

AB+AC = BC

=        { AB, AC and BC denote unsigned lengths }

on q, A lies between B and C.

Hence, with for A the point between the two others, (1) does the job. And this concludes our proof of Sylvester's theorem.

Note Since steps that express equivalence don't destroy information, the others need some more justification. We all know the monotonicity of ≥ , i.e. no one doubts

x≥x' ∧ y≥y'   ⇒  x+y ≥ x'+y';

its counterpositive yields the equivalent

x<x' ∨ y<y'   ⇐   x+y < x'+y'

and that is what we used.

To justify the next step, a second look at our demonstrandum (2) suffices: since it is impossible to demonstrate (2) for h=0, we have to use once more that q does not pass through E. Since E occurs in this calculation in the combinations EB and EC, we translate this into the non-degeneracy of triangle BEC. The step eliminates E for the rest of the calculation. (End of Note.)

For the sake of completeness we point out that, after the choice of the variant function, we have made two silent choices. We have chosen —as usual— to decrease the variant function; because of the finiteness, successfully increasing it would also have yielded a valid termination argument. With a huge h and ABC close together, however, the distance between E and q cannot be increased, which settles this silent choice. Moreover, we could have grouped our 6 cases differently, viz. by common new q instead of by common new E. We could have said "Let us name the three points so that AE becomes the new q" and instead of (1) we would have come up with

q,E := AE, of B and C the nearest to AE.

It does not work.

*          *
*

A few methodological remarks are in order, because the theorem certainly deserves the name of a once-deep theorem: after 1933, when Karamata and Erdös revived interest in the problem [Coxeter], it took another fifteen years before L. M. Kelly made essentially the above use of the Euclidean distance and found the simple argument.

It was very gratifying to see that, once the decision had been taken to tackle this problem as a programming task, the job of designing the program was all but standard. I have used this problem in oral examinations for a course on "Mathematical Methodology" for Computing Science graduates. Some needed more prompting or more time than others, but none of them needed any prompting to come up with the Euclidean distance between q and E as candidate for the variant function. They knew that the argument required a variant function and they all suggested the Euclidean distance without hesitation. And that was Kelly's great invention!

A fringe benefit of proving the theorem by designing a program is that it takes away the surprise that in such a non-metric context a metric concept such as the Euclidean distance enters the picture. We all know that a monotonic function of an acceptable variant is again an acceptable variant and that the challenge always is to find a nice one. It is very much like the freedom to chose the most convenient coordinate system.

Acknowledgement That the distance from points to lines through other points could be used in the proof was told to me by Bernhard von Stengel; he told me to look at the shortest such distance. (End of Acknowledgement.)

*          *
*

For Sylvester's theorem to be true it is essential that the points are distinct. (Consider a non-degenerate triangle with each vertex coinciding with a triple of points.) Replace "any 2 points are distinct" by "through any 2 points passes only one straight line". The latter can be generalized to one dimension more "through any 3 points passes only one plane", i.e. "no 3 points are collinear". And now we are ready to generalize Sylvester's theorem to three dimensions.

Theorem   Consider in the real three-dimensional Euclidean space a finite number of points such that no 3 of them are collinear; these points are coplanar or there exists a plane through exactly 3 of them.

(In the three-dimensional case, just requiring that the points be distinct is not enough: consider two non-intersecting, nonparallel lines with 4 distinct points on each.)

Proof sketch  Select one of the points and a plane outside. Project, with the selected point as center, the remaining points on the selected plane, to which projection Sylvester's theorem is applied. (End of proof sketch.)

*          *
*

Coxeter mentions no more-dimensional generalization of Sylvester's theorem. Maybe he did not think it sufficiently interesting. Maybe he could not comfortably generalize because none of his formulations mentions explicitly that the points have to be distinct.

Coxeter's passage is interesting for historical reasons. He quotes Sylvester's original statement of the problem:

Prove that it is not possible to arrange any finite number of real points so that a right line through every two of them shall pass [sic] through a third, unless they all lie in the same right line.

Fortunately we don't formulate problems like that anymore. I could not read it and ended up looking up "unless" in the COD, which gave two interpretations "if not" (which boils down to ∨) and "except when" (which boils down to ≢). I felt excused. (Actually, Sylvester used "unless" in the meaning ∨).

A few lines further, Coxeter gives credit to T. Motzkin (1951):

Sylvester's 'negative' statement was rephrased 'positively' by Motzkin:

If n points in the real plane are not on one straight line, then there exists a straight line containing exactly two of the points.

It is not quite clear for which achievement Motzkin receives credit. He replaces Sylvester's contorted

¬(∀ line: line passes ≥ 2: line passes ≥ 3 )

thanks to de Morgan by

(∃ line: line passes ≥ 2: line passes < 3 )

which can be simplified (arithmetically!) to

(∃ line:: line passes = 2 )

which in the statement of the theorem is certainly a simplification. (But note that in the proof one immediately uses

line passes =2   ≡   (line passes ≥ 2) ∧ ¬(line passes ≥ 3). )

Or did Motzkin get credit for replacing Sylvester's disjunction by an implication? You never know with Coxeter. (I dislike in Motzkin's formulation, besides the dangling n, the implication: compared to Sylvester's disjunction, I consider that a step backwards. Please note that the implicative formulation introduced —in "not on a straight line"— a negation.)

Coxeter's section opens with a quotation from G.H. Hardy (1940):

Reductio ad absurdum, which Euclid loved so much, is one of a mathematician's finest weapons. It is a far finer gambit than any chess gambit: a chess player may offer the sacrifice of a pawn or even a piece, but a mathematician offers the game.

No matter how hard I try, almost half a century later I am unable to give even a mild sensible interpretation to the above quotation of Hardy's, but, in 1961, Coxeter evidently felt he could: his proof gloriously ends with the now infamous "which is absurd".

(Coxeter focuses his attention on the pair (q, E ) with minimum distance and derives a contradiction from the assumption that q passes through at least 3 points. The choice of the pair with minimum distance is overspecific: it is only a device to construct the avoidable contradiction. Tellingly, he concludes

"This completes the proof that there is always a line containing exactly two of the points. Of course, there may be more than one such line [...]".)

Fascinating to analyze mathematical style from such a recent past!

Reference

Coxeter, FRS, H.S.M., Introduction to Geometry, 2nd Ed., John Wiley & Sons, Inc., New York etc., pp 65–66.

Austin, 5 February 1988

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Xiaozhou (Steve) Li
revised Sun, 9 Dec 2007

EWD 1018

To the members of the Budget Council

It is my firm intention not to get personally involved in campus politics, but this should not prevent me from pointing out some of the basic rules for building up a first-rate institute. I know that their applicability can be questioned. It can, for instance, be argued that in the second half of the 20th Century, university education has become such a massive undertaking that the training of second-rate scientists has become the major task. Perhaps the major one, but not the primary one, I hope. In any case I would hate the thought of attracting second-rate professors for the purpose. But whatever the applicability of the basic rules, we should be aware of them: when, for whatever other reasons, we feel compelled to violate them, we should at least know that we do so.

Rule 0  | Select your scientists for their ability and not for their specialty.
Rule 1 | Don't "manage" your scientists: they know better what to tackle and how.
Rule 2 | Remember that the institute should serve its scientists, and not the other way round.
Rule 3 | Develop your own judgement so as to become independent of peer review.

*                *
*

In reference to Professor Holst, Professor Sir Hermann Bondi, KCB, FRS remarks about Rule 0:

"It has been my misfortune to have had to do with a good number of laboratories that do not follow this simple rule, but specify the one particular person who has worked for instance on infrared spectroscopy, defining a wavelength to within five percent. Once you know that is how it recruits its staff, it is hardly worth visiting that lab. It may, with great effort, manage to be second-rate but very likely will be less.

When you come to a place that says never mind what our present pressing needs are, we must recruit the ablest person we can find irrespective of specialty, then it is going to be a first-rate laboratory. Nothing else matters and Holst knew this, but it is sad to see that his knowledge has not spread more widely, anything else is a denial of that most characteristic of human properties and that is adaptability. It is not surprising to me that he was so very successful here, I only wish the lesson he taught were more widely appreciated." [Holst was the first director of Philips Research Laboratories.]

Rule 0 is more than an antidote against fragmentation. It also implies that it would be a mistake to plan the scientific future of the department under the assumption that computing science's components have been identified. I trust that the discipline will evolve into unforeseen dimensions and we must hope that at least one of such developments takes place in our department.

*                *
*

Rule 1 used to be particularly relevant in the industrial environment. With the increasing dependence of the universities on money that comes from grants with strings attached, it becomes of equal relevance for the academic world. No breakthrough ever took place because some "benefactor" ordered it. We should not seek to provide what the world asks; a leading institute should provide what the world needs—whether it is welcome or not! It is my strong impression that in our area all significant progress has primarily been opportunity-driven —rather than demand driven—, the opportunity each time having been created by the combination of vision and superb mastery of one's technologies. The doing of successful scientific research is a very subtle balancing act between doing something insipid and trying something impossible.

We might in this light reconsider how happy or unhappy we are with some of our grants and to what extent the attached strings are shackles. Quite a few grants could very well turn out to be curses in disguise. (I am not a historian of science but sometimes ponder about possible explanations of the in general sorry state of American computing science; "too many grants" is one of them.)

*                *
*

For the industrial environment, for instance, Rule 2 implies that an important task of the manager of a research outfit is to shield his people from interference from Company Headquarters. But its relevance was driven home to me while I was still full-time in Eindhoven. It began with a scientifically sterile colleague who maintained his self-esteem by explaining that he had no time for research because "he sacrificed himself for the department"; by the time my work began to draw international attention he had manoeuvred himself into the position in which he had to accuse me of neglect of my educational obligations so that I could publish articles for my own greater glory. (He was a bitter man.) This was an isolated incident, but it turned out to be symptomatic; later, raising the contents and requirements of a programming course —by which it became for mediocre students a difficult course to pass— was resented by the mathematicians as "not in the interest of the department": the department was more interested in raising its output, even if it had to be done by lowering the standards. I learned one lesson: the department is not a goal in itself, and as soon as you allow it to become so, the door through which educational fraud can enter is set ajar.

Consequently I was taken somewhat aback by some of the criteria by which younger faculty was judged. Our scientific activities —in teaching and in research, I prefer not to separate the two— are the only significant ones; to attach any weight —even if it is done with the best of intentions—to tertiary criteria —visibility, grantmanship, service to the department, whether someone is a father for his students, etc.— is deadly dangerous. I am sorry if this sounds cruel, but this is the unavoidable price for excellence.

*                *
*

When I asked the director of a large —and successful— British software house his most serious problem, he said without hesitation "how to prevent clusters of incompetence from emerging". I was reminded of that when I noticed the —for me unusual— weight given to the "peer review". What, if the peers aren't any better? The mechanism does not protect us from harbouring fragments that are too shallow, too speculative, or —as the case may be— too fraudulent to merit the name of science. (And let us have no illusions: such topics abound! We are fortunate in not having professors in software metrics, animation or key-wording!)

Not only does the mechanism of peer review fail to protect us from disasters, in a certain way it guarantees mediocrity: the genius has no peers. And to make matters worse, his publication record does not reflect his work either. At the time it is done, truly original work —which, in the scientific establishment, is as welcome as unwanted baby— is very hard to publish as it takes at least another ten years for the appropriate journal to be founded. (I sooner blame someone for his publication list being too long than being too short.)

The moral is that we cannot delegate our responsibility to judge ourself. We can forsake it, but not delegate it. By hiding behind the excuse "But that is not my specialty" we degrade ourselves to lame ducks, and we should not do so. A good young scientist is able to explain

what he is trying to achieve

why he is tackling this in the way he is

why he believes he can do it

the criterion by which he will decide whether he has succeeded or failed.

He is, in fact, able to explain this to his next-door neighbour. If we are too lazy or too stupid to follow such an explanation, we should resign. By urging young scientists to submit papers for publication and to apply for grants so that we can rely on the judgements of others we make ourselves ridiculous.

Nuenen, 21 December 1987      

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Kevin Hely
Last revised Thu, 14 May 2009

Copyright Notice

The following manuscript,

EWD 1019: Another Filler of the YoP Institute

was published as

Edsger W. Dijkstra, ed., Formal Development of Programs and Proofs. Addison-Wesley, 1990: 209-227.

� Addison Wesley Longman Inc. Reproduced by permission of Addison Wesley Longman. All rights reserved.

EWD 1019

Another Filler of the YoP Institute

Why numbering should start at zero

When we have to characterize a set of adjacent natural numbers, say {2, 3, 4, 5, 6, 7, 8, 9, 10}, we have four options, depending on whether the bounds are included or not:

(a)          | 1 < x < 11
(b) | 1 < x ≤ 10
(c) | 2 ≤ x < 11
(d) | 2 ≤ x ≤ 10

Natural numbers have the property that there is a smallest natural number. Different civilizations have made different choices for that minimum value; for the classical Greeks, for instance, it was 2, because, for them, 1 was not a number. (Consequently, Euclid had to introduce a case analysis in the justification of his algorithm for the greatest common divisor of two numbers, viz. the case that the two numbers had a common divisor versus the case that they had not, i.e. were relatively prime.)

This observation makes the convention of excluding the lower bound, as illustrated in (a) and (b) unattractive: if the range includes the smallest natural number —as the example would for Greeks— the convention of excluding the lower bound requires the introduction of an unnatural lower bound —as the examples (a) and (b) would do for the Greeks— . This is certainly inelegant and hence we adopt the principle of inclusion of the lower bound.

So we are left with the choice between (c) and (d). If we include the upper bound and consider the generalization 2 ≤ x ≤ n, we see that for n=2 the range still contains the value 2. If we wish to represent the empty range by shrinking n still further, it would require n=1, which would be very unnatural for the Greeks. In general, the convention of including the upper bound requires the introduction of an unnatural upper bound; since this is certainly inelegant, we adopt the principle of exclusion of the upper bound.

In short, (c) is the winner: ranges of natural numbers will be indicated by

m ≤ x < n

with natural bounds m and n, with m ≤ n. Further advantages are

the number of values in the range equals the difference of the bounds

if the upper bound of one range equals the lower bound of another range, the ranges are contiguous.

After these preliminary investigations we ask ourselves how we characterize the first n natural numbers. For the classical Greeks this would be

2 ≤ x < n+2       ;

were we to adopt the convention that the natural numbers start at 1, we would get the equally ugly

1 ≤ x < n+1       .

Obviously,

0 ≤ x < n

is the most elegant formula; it corresponds to accepting zero as the smallest natural number. (This choice has further advantages.)

And now you know why my manuscripts start with page 0. It is really quite easy. When writing a manuscript, I have the completed pages behind me, spread out on the floor. The number on each new page equals the number of completed pages on the floor.

Austin, 1988 Jan. 25

prof.dr. Edsger W.Dijkstra
Department of Computer Science
The University of Texas at Austin, Austin, TX 78712–1188, USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1024

A new science, from birth to maturity

(Talk held at the Anniversary Celebration of the Department of Computing Science, ETH Zürich, on 19 October 1988.)

If we put the birth of Computing Science at the advent of the program-controlled computer, the topic is about four decades old. These have been exciting decades and I am grateful for my good fortune of having been involved for most of that period, grateful because this involvement enabled me to observe that whole process of growth from close quarters. My observations cover the whole gamut, ranging —as they do— from the stage that Computing Science hardly existed to the current stage in which Computing Science is a vigorous and flourishing discipline whose academic viability is no longer in doubt. An additional reason for personal gratitude is that, during most of my involvement, my travels frequently took me to the other side of the Atlantic Ocean. Such mobility has been essential for observation "from close quarters" because American and European Computing Science evolved quite differently. We shall return to that difference extensively.

Of course I realize that reducing the globe to just two continents is a rather strong simplification of geography, and that, in a comprehensive study of the history of computing science, much finer distinctions would be needed. But I am not a professional historian and hope that you will allow me to make this geographical simplification. In the same vein I hope that you forgive me when, for the sake of simplicity, I cut the forty-year period up into four decades, each of them with a rough characterization: we could characterize the fifties as the decade of hardware, the sixties as the decade of syntax, the seventies as the decade of semantics, and the eighties —tentatively, for the decade is still young— as the decade of synthesis.

The fifties

My characterization of the fifties as the decade of hardware is not surprising and easily justified. The whole field began with the conception of the program controlled computer for which von Neumann got the credit that may be due to Turing. Building such a machine so that it was sufficiently reliable was, at the time, at the limits of technology —if not beyond!— and it is only too understandable that, at the beginning, the physical equipment attracted all the attention.

Accordingly, most of the inventions of the fifties were aimed at higher speeds, larger stores, and greater reliability. I mention as examples: transistors and ferrite cores, the parity check, the B-line —later known as the index register—, the real-time interrupt, automatically managed multilevel store, and the timid beginnings of multiprocessing. Those were the days when the goals could easily be quantified: speeds in number of operations per second, store size in bits, and reliability in MTBF. (The last term, standing for "Mean Time between Failures", strongly suggests that machines continued to be expected to fail frequently.) The significance of this decade is best appreciated by realizing how many of these innovations are still with us, in one form or the other.

In all three technical respects, progress was impressive indeed. To give you one example: I remember that we accepted, almost as a Law of Nature, that machine speeds doubled each year, and all of you know that that amounts to a factor of one thousand over the decade. But there is no such thing as a free lunch, and the price we paid was heavy: programming remained a haphazard activity. Firstly, programming was hardly seen as a problem; most people felt that programming required no more than accuracy and enough computer access and sufficiently short turn-around time to debug your programs. Secondly, in those equipment-oriented days, the greatest expert in the cunning exploitation of specific machine features was regarded as the best programmer. To put it bluntly, the distinction between a programmer and a hacker had not yet been made.

For the sake of completeness: it was not a decade of hardware progress only. The fifties saw a number of efforts to ease the coding problem, such as autocoders and FORTRAN, but, true to the spirit of the decade, each of these coding aids was aimed at a very specific machine. Consequently, it remained very hard to see programming as something to which science could contribute. Finally, the fifties gave us the professional societies such as the ACM and the BCS; true to aforementioned spirit of the decade, their names refer explicitly to the equipment. They were not scientific societies, but professional ones, in which practitioners could exchange their experience.

The sixties

Let us turn our attention to the next decade, the sixties. Its first month witnessed an amazing landmark in the international history of computing, viz. the publication of the ALGOL 60 Report, edited by Peter Naur. Three facts stand out: firstly, ALGOL 60 was truly the outcome of international cooperation in the best sense of the word, secondly, it has never been doubted that it was an achievement of the highest scientific standard, and thirdly, at either side of the Atlantic Ocean, its fate was totally different. At both sides it was instrumental in giving shape to a young science, but the shapes were very different.

ALGOL 60 was a breakthrough by virtue of

0. | its block structure
1. | its parameter mechanism
2. | its inclusion of recursion
3. | its inclusion of the type Boolean
4. |  its "cleanness" (e.g. the absence of special constraints on index expressions)
5. | the formal definition of its syntax
6. | the nonoperational definition of its semantics (to the extent that it was not immediately clear how to implement it)
7. | its stability (due to very few trouble spots)
8. | its machine-independence.

Compared to the culture of the day, this is a truly impressive list! Allow me to highlight three seemingly minor points. With its unambiguous identity and scope of local variables, the block structure incorporated a radical improvement over standard mathematical practice in which both identity and scope of dummies are often not defined beyond "but every mathematician knows what is meant". As to recursion, the mathematical definition of a continued fraction was "a fraction whose numerator is an integer and whose denominator is an integer plus a fraction whose numerator is an integer and whose denominator is an integer plus a fraction and so on". The proper definition of a continued fraction is of course "a fraction whose numerator is an integer and whose denominator is an integer plus a continued fraction". [For heaven's sake, don't underestimate the quantum leap of this improvement. A few years ago, I quoted these two definitions of a continued fraction as an example of progress. I later heard that from this example a famous scientist in my audience, Fellow of the Royal Society and all that, had concluded that I was mathematically incompetent because everyone knew that circular definitions did not make sense.] The introduction of the type Boolean as a first class citizen is a similar milestone: to this very day, the standard mathematician cannot read a Boolean expression without interpreting it as a statement of fact, and for him 0 = 1 is "wrong", rather than one of the many expressions that has the value false.

ALGOL 60 was conceived at a time that business administration and numerical computations were viewed as the main computer applications, but the mere presence of the ALGOL 60 Report made it immediately obvious that there was more to the programming than coding for these two types of applications: some people would have to write the ALGOL compilers! Besides being viewed as data processor and as calculator, the computer became more widely viewed as symbol manipulator as well. The formal definition of the syntax was an invitation to approach the compilation problem in a less ad-hoc manner. Moreover, the combination of block structure, parameter mechanism, and recursion offered the possibility of a clean presentation of algorithms of a novel degree of sophistication. The topic was no longer "trivial" and computing science became conceivable as an academically respectable discipline. ALGOL 60 has been more than a scientific landmark: politically, it has been an indispensable stepping stone for Computing Science on its way to academic respectability.

As said, the two sides of the Atlantic Ocean received ALGOL 60 very differently. The superficial story is that ALGOL 60 was widely received in Europe but rejected in America, where it failed to dislodge FORTRAN. IBM had penetrated the American system of higher education by giving the more prestigious universities its machines almost for free, thereby hooking those universities, while European academia had had the good fortune of having been spared that largesse and had remained free, etc. Though not without a germ of truth, this story is really too superficial, for even American universities can unhook themselves if they really wish to do so. The story of ALGOL 60's different fates needs refinement, and so does its explanation.

In America, where, within a few years, Perlis coined the term "ALGOL-like languages", the study of formal languages quickly emerged as a scientific topic in its own right and ALGOL 60's main role was to provide the initial paradigms for that scientific inquiry. It was hardly viewed as a vehicle for serious programming. And it is precisely in that last capacity that ALGOL 60 drew most of the European attention. Europe quickly implemented ALGOL 60 in its full glory and used it; Tony Hoare's "quicksort" convinced the last doubters that the inclusion of recursion was more than a whim, "Jensen's Device" showed the full power of the parameter mechanism, and, thanks for ALGOL 60, programming could, and did, become serious business.

The next decade would drive that difference in attitude home to me. At conferences in the USA, the following conversation became a standard ingredient.
Question: "And, Mr. Dijkstra, what are you currently working on?"
Answer: "Programming."
Reaction: "Ah, I see: Programming Languages. How interesting."

But I am rushing ahead. Both camps took ALGOL 60 seriously, both viewed it as an opportunity and incentive for scientific investment, but they stressed different aspects, viz. formal languages versus programming. How come?

There was an obvious difference in timing. World War II had left the USA with a thriving economy and industry, while those were a shambles in Europe. By 1960, Europe's recovery was well under way, but powerful computers were still much less common than in America. It is understandable that the need for something that would deserve the name of Computing Science was felt more urgently in America than in Europe. Moreover, the fence around the campus that separates the academic world from the rest of society is traditionally much lower than in Europe. Finally, the legal status of most European universities is such that establishing a new academic discipline usually requires a few decades of lawmaking. Finding out how the techniques of scientific thought could be applied to meet the programming challenge was a less tangible and more distant goal than developing formal language theory: the latter topic was much more in line with the mathematical tradition of the day and thus a target within reach. Urgency and opportunity thus made it in the sixties a cornerstone of America's budding computing science. So much for the difference in timing.

Another explanation for the different reactions to ALGOL 60 can be found in a traditional difference in technological priorities. Right from the start, American computing has been much more concerned with attaining speed than with reducing equipment, be it circuitry or storage size. There is a very simple economic/technological explanation for this: after World War II, none of the European laboratories had the resources needed for the development of the fastest machines conceivable at the time. But that is only part of the explanation, for there is also a cultural difference, as mentioned in passing by Alice S. Rossi in 1964: "Americans are easily impressed by large numbers.". By the time ALGOL 60 came around, this aspect had already created two completely different computing cultures. I remember a conversation in 1962, in Rome. We were sitting around a coffee table. One American boasted that he had made an "algebraic translator" of 50,000 instructions, only to be immediately outdone by one of his compatriots, whose algebraic translator comprised no less than 80,000 instructions. Peter Naur broke the subsequent silence of awe by remarking that he had written an ALGOL translator of 5,500 instructions, upon which I could outdo him with a compiler of only 2,700 instructions. In short: our yardsticks for achievement measured in opposite directions!

The American priority to speed had two direct consequences. Firstly, American computing all but ignored, as too time-consuming, the closed subroutine, which, right from the start, was the cornerstone of European computing. This attitude would culminate in the design of the IBM/360 whose large number of explicitly named registers actually defined a reasonable implementation of closed subroutines. Secondly, American computing ignored ALGOL 60 as a serious programming vehicle because —rightly or wrongly— it was felt that ALGOL implementations were too slow.

The sixties were the decade in which automatic computing began to gain academic respectability, and academic departments started to emerge. The American departments were, on the whole, sooner to be institutionalized. They were also more ready to incorporate application areas as part of the departmental responsibility, and to this very day you can find in American universities areas such as numerical analysis and artificial intelligence being a part of the CS Department.

Further American contributions from the sixties were symbolic processing —I mention LISP— and complexity theory. They were gratefully incorporated in the American CS curriculum. Were the American departments premature? Many people felt that way and the question whether Computing Science deserved the name of a science was raised over and over again. Newell, Perlis, and Simon have tried to settle that discussion at the end of the decade by "Facts breed science. Computers exist. Ergo.". Needless to say, this did not end the discussion.

European universities too started to think about computing science. They, too, thought deep and hard about forging an academic discipline worthy of the name. But they were less in a hurry to institutionalize and eventually they embarked with a probably somewhat more conscious design. For an academic discipline to be viable, its areas should be coherent and should mutually reinforce each other; moreover, the material taught should have a staying power of, say, fifty years. For the sake of coherence, and in recognition of the fact that the automatic computer really deserves the name "general purpose", it was generally decided that the application areas had better not be included in computing science. For the sake of staying power, it was generally decided that computing science should dissociate itself from the fickle market place: teaching how to make do with the equipment currently on the market was not the calling of European computing science, and all material with a half-life of five years was banned. In passing I mention that COBOL and FORTRAN were viewed as industrial products, and therefore not taught.

Europe's contribution to computing in the sixties consisted mainly in improving the art of design, such as design of operating systems, of programming languages and of their implementations. Quite a few of such designs were engineered with a novel delicacy. Furthermore, thinking removed itself from the physical equipment, and programming languages were no longer understood in terms of their implementation. (When Perlis called ALGOL 60 "a very inefficient language", the Europeans in his audience were shocked by his patent lack of separation of concerns.)

To complete the picture of the sixties, in 1968, the existence of the software crisis was admitted at the NATO Conference on Software Engineering in Garmisch- Partenkirchen, and Wirth started the implementation of PASCAL. In 1969, C.A.R.Hoare published his "An axiomatic approach to computer programming" and I circulated my "Notes on structured programming". Let us move on to the next decade.

The seventies

I called the seventies the decade of semantics: the interest in syntax and parsing tapered off, Dana Scott's denotational semantics provided the logical foundation for recursion in all its glory, and formal proofs of program correctness entered the picture.

In hindsight, the reduction in interest in syntax and parsing was more than justified. Programs that, on account of complexity of the syntax, are hard to parse mechanically are correspondingly hard to compose correctly; consequently, a straightforward syntax that simplifies the parsing eases the programming task (something the designers of Ada overlooked).

As in the mean time can be expected, the American and European interests in proofs of program correctness differed greatly: the American interest focused on the mechanization of a posteriori verification of given programs, written in given languages; the European interest was more in a constructive approach to the problem of program correctness, and turned to design methodologies or calculi for the derivation of programs that would be correct by construction. From the European perspective, a posteriori program verification amounted to putting the cart before the horse; from the American perspective, the constructive approach of the Europeans was hopelessly idealistic, because it was mathematical. This was the decade in which I began to stress that as scientists we should clearly distinguish between the intrinsic problems of automatic computing and the problems caused by shortcomings of the American educational system, which traditionally does not consider intellectual advancement its primary concern.

On the American academic scene, complexity theory continued to flourish; automatic theorem proving attracted a lot of attention and got off the ground. A serious concern during the seventies was how to prevent a sizeable part of Computing Science from deteriorating into the dishonourable art of "How to live with the IBM/360"; in winning this battle, the less infected and intellectually more autonomous universities in Europe played a considerable role. Finally, the advent of the personal computer revived most of the mistakes of the fifties —but now on a more grandiose scale—. Today, the ubiquitous personal computer has created an equally ubiquitous misunderstanding of what computing science is about. (At a party, two years ago, Tony Hoare and I were approached by a mathematician who expressed his delight in meeting two such outstanding computing scientists for he had never been able to understand what he had to do in order to save a file on his personal computer, model so-and-so. We could not help him and Tony asked him, whether he could recommend a book on category theory; he could not help Tony either.)

The seventies were a decade of frantic and expanding activity; at the same time it revealed symptoms of decay and showed that in the academic community some intellectual rot was setting in. Also in this respect, America was leading: it became highly productive in rather uninspiring papers, ranging from boring to utterly foolish. Soon, Europe would follow this example.

In the seventies, universities all over the Western world had a hard time. Firstly, lecturing style deteriorated when chalk and blackboard were ousted in favour of the overhead projector with prepared foils: instead of lectures, students got presentations. Secondly, life on campus had been totally disrupted by the student revolts of the late sixties, which breathed an anti-intellectualism as vigorous as Chairman Mao's Cultural Revolution of which they were the echo. All disciplines have suffered from these two calamities; we must bear in mind that they hit Computing Science at a very vulnerable stage, and there are reasons to suspect that American computing suffered even more than its European counterpart.

The American universities are generally praised for the fact that they are much less a world apart and that the barriers to communication across the campus boundary are much lower than in Europe. It has its charms, but the price can be heavy. For a university to be leading, it must offer what society needs, rather than what society demands. The lower barriers make that the direct demands of society are heard much more loudly and it is not surprising that American computing science, on the whole, became more led than leading.

I am not referring to the local banker's pressure for more "Advanced COBOL" in the curriculum: all but the very smallest institutions can resist such pressure. I am referring to the conflicting pressures from a society that is traditionally ambivalent about technology, that welcomes gadgets almost without restriction but equates technological expertise with the loss of innocence that is an essential ingredient of The American Dream. In the case of Computing Science I am referring to the pressures from a society that is structurally unable to include in its vision a view of programming as a branch of formal mathematics and applied logic, and that therefore is forced to ask for snakeoil. If, then, the campus is insufficiently shielded from those pressures and the market forces are given too free a reign, you can draw your conclusion: a flourishing snakeoil business, be it in "programming by example", "object-oriented programming", "natural language programming", "automatic program generation", "expert systems", "specification animation", or "computer-supported co-operative work". (I am not inventing these slogans: they are all honest quotations.) I used the term "decay" and am forced to conclude that I did not exaggerate.

A more universal problem is presented by the negative effects of academic institutionalization: in the seventies, they became quite visible for computing science. Firstly, the ridiculous fragmentation: these days we see special professors in "local-area networks", "compiler construction", or "support environments". Secondly, the diversion into elaborate trivia, caused by the Ph.D. mechanism that requires a steady stream of well-delineated and obviously solvable problems (if you care for them). Thirdly, the need for an outlet for your less than gifted students (which has introduced such topics as "human factors", "software metrics" and "experimental computing science"). As computing scientists, we don't need to feel particularly guilty: no academic discipline has found a truly satisfactory solution for the education of the unavoidable second- and third-rate researchers. Hence, we usually ignore the dilemma, or deny its existence, but it is a negative effect of academic institutionalization.

The eighties

Let us now switch to the current decade. I shall be less elaborate on that one for two obvious reasons: firstly, it is not over yet, and, secondly, it is still too close to have established its significance.

European computing science suffered from more than the traditional problems caused by institutionalization, because many departments were founded in such a hurry that quite a few vacancies were filled by so-called "instant professors". Moreover, many a government forced its universities into co-operative efforts with industry (a trend from which Computing Science suffered more than, say, Assyrian Linguistics). As a result, even genuine research potential has been diverted to the ephemeral, shallow, or foolish. Confining myself to Computing Science proper, I shall ignore these aberrations.

Tentatively, I called the eighties the decade of synthesis. I did so because Computing Science and Formal Mathematics got more and more intertwined, and did so in a variety of ways.

Firstly, mechanical theorem proving or proof verification came of age. It has definitely left the youthful stage of toy problems: successful applications have ranged from deep theorems such as Gödel's Theorem, to practical challenges such as proving the correctness of circuitry and special-purpose operating systems. The appearance of a journal dedicated to Automated Reasoning is a clear signal.

Secondly, the fundamentally close connection between proving and programming, as revealed by Constructive Type Theory, is beginning to have its impact: programs are deduced from constructive existence proofs and vice versa.

Thirdly, logic programming has established a visible link between proving and computing, a link that also emerges in the application of complexity theory to the notion of provability. The discovery of the existence of correct theorems that shall never be proved because the price of the proof is prohibitive —and that is putting it mildly— caused some rethinking about the scope and purpose of mathematical reasoning.

Fourthly, it is beginning to be realized, mainly on campus but even in some pockets in industry, that the programming task presents a fertile field for the application of the techniques of scientific thought. The emergence of the journals "Science of Computer Programming" at this decade's beginning and "Structured Programming" at its end are clear symptoms. It is fascinating to observe how this development works both ways and how, in the wake of Programming Methodology, the somewhat wider topic of Mathematical Methodology is emerging. [Since this was written in first draft, Springer announced yet another journal: "Formal Aspects of Computing", with the telling subtitle "The International Journal of Formal Methods".]

It is fascinating to observe how a breakthrough in our manipulative abilities has created the opportunity of realizing an increasing portion of Leibniz's Dream of presenting calculation, i.e. the manipulation of uninterpreted formulae, as an alternative to traditional mathematical reasoning. Because the Dream of Leibniz aims at providing an alternative for traditional mathematical reasoning, traditional mathematics did not provide the most hospitable environment for its realization; this, therefore, had to take place in a separate discipline, which is now known as Computing Science.

It is not surprising that the computing scientist picked up this gauntlet. By virtue of its mechanical interpretability, each programming language presents a formal system of some sort, and so the notion of a formal system is something he grew up with. He is very familiar with formal methods because they provide the only sufficiently reliable way of designing programs. Knowing, for instance, how compilers work, he is familiar and totally at ease with the idea of manipulating uninterpreted formulae. Finally, he has good reason for not sharing the common fear of symbol manipulation because he has the tools for mechanization at his disposal.

It is my conjecture that meeting the challenge, embodied in the Dream of Leibniz, will provide the ultimate justification for the existence of Computing Science as a scientific discipline in its own right. We have to show that it is possible to be precise and complete without making a mess of it.

Let me quote Leibniz to wish us well for the next forty years and beyond: "Calculemus!".

I thank you for your attention.

____________
* In fact in a footnote to her article "Equality between the Sexes: An Immodest Proposal".

| Austin, 2 October 1988

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
United States of America

Post-delivery comment  My Zürich audience was generally of the opinion that I had been too kind to the Europeans, and I agree. For instance, I forgot to mention all the interdisciplinary nonsense done in the wake of the official French definition of "l'Informatique". European computing science has been disgracefully slow in dissociating itself, for instance, from business administration; for this, the absence of Business Schools was no excuse. (End of Post-delivery comment.)

Transcribed by Mikhail Esteves
Last revised on Thu, 14 May 2009.

EWD 1026

Trip report E.W.Dijkstra, Marktoberdorf 1988

J.C.S.P. van der Woude and I had arranged to drive together the 750 km to Marktoberdorf and van der Woude had agreed to collect me on Sunday 24 July at 5:00 in the morning; he made the mistake of being 40 minutes late. Alternatingly, we took the driver's seat for two-hour intervals. We arrived at the Marktoberdorf Gymnasium in the course of the afternoon; a violent thunderstorm, that had travelled over Europe in the same direction, reached Marktoberdorf two hours later. (From Richard Bird and Tony Hoare I heard that the storm had reached Munich Airport in all its violence ten minutes after their plane had landed.)

The schedule of the Summer School was heavy as usual: 6+4 days with in total more than 50 lectures and 8 discussion sessions. The programme was perhaps heavier than usual: we had a set of high-powered speakers, who together had too much to tell. Their saving grace was the high level of care with which many of the visuals had been prepared and their obvious effort to be as clear as possible. (They were really grown-up: no matter how hard they worked on their lectures, they did not compete with each other for the favour of the audience.)

The theme of the Summer School was "Constructive Methods in Computing Science", but traditionally the theme is no more than a flag and the speakers are encouraged to talk about what is dearest to their hearts. The first days, the topics seemed to be of a bewildering variety; as the school progressed, an amazing number of (unplanned) links emerged.

Roland Backhouse (University of Groningen) talked about "Constructive Type Theory". In an early stage, he lost his audience when he lingered too long on the propositions-as-types paradigm, but he worked very hard and re-established contact. Mathematically, I don't feel attracted to constructive type theory because of its close links to Gentzen's "Natural Deduction", which is usually much more clumsy than equational reasoning. By showing the link with programming methodology, Backhouse convincingly argued the legitimacy of the computing scientist's interest in constructive type theory.

Richard S. Bird (University of Oxford) talked about "Constructive Functional Programming", and did so with contagious enthusiasm. His generalizations from dealing with lists to dealing with bags, sets, or trees revealed the well-educated mathematician. I doubt whether at my age I will take the trouble of getting his formalism at my fingertips; I'll know how to justify my abstinence by remarking that it is too much attention to too tiny a topic. But I am very glad that the next generation of computing scientists has been exposed to it: it was nicely calculational and constructive, it demonstrated the importance of having theorems, and it showed how much can be achieved when notational courage and care are well-balanced.

Manfred Broy (University of Passau) spoke under the title "Towards a Design Methodology for Distributed Systems". I am afraid that he failed to reach me. For one thing, his visuals were very hard to read from the rear; moving to the front, I could read the characters, but not yet his formulae, as relative binding powers of infix operators and scopes of dummies usually had to be guessed. When he seemed to use his formalism primarily for descriptive purposes (rather than for manipulation) my interest waned.

Robert L. Constable (Cornell University) had as topic "On the Design and Construction of Problem Solving Environments". To begin with, I was —perhaps more than mildly— annoyed by his violation of the tradition that all speakers attend the complete Summer School: he showed up during the fourth day, thereby missing what Backhouse had told about a closely related topic. In his first lecture, his visuals were hardly readable; he somewhat redeemed himself by working very hard on the visuals for his later lectures. He was a conscientious lecturer and reached part of his audience; others had the uncomfortable feeling that here logic was parading as computing science. I was put off by his notational immodesty and the repeated intrusions of philosophy.

I gave this time only four lectures: I proved a conjecture of Sylvester's by deriving a program, I derived a proof of J.C.S.P. van der Woude, minimizing the number of rabbits to be pulled out of the hat and finally derived two prototype programs, building up specification or invariant as I went along. The lectures were well-received because everybody could follow them and could see that the arguments were elegant. I am afraid I failed to make clear why I had chosen to give these lectures.

C.A.R.Hoare (University of Oxford) was the only director of the Summer School that gave seven lectures; he gave them on "Approach to Category Theory for Computer Scientists". We had been given 44 pages of lecture notes —rich in examples— at the end we received copies of 100 beautiful visuals mostly made during the Summer School. His reason was to give "the reason why theoretical computer scientists should be interested in (and enjoy) category theory". In this respect he succeeded as far as I am concerned much better than R.M.Burstall several Summer Schools ago. He used preorders and monoids as stepping stones to categories, and spent most of his time on the stepping stones. He had abolished the traditional diagrams and worked with formulae instead; all his proofs were short calculations and I fervently hope that this innovation of his is as great an improvement as I think it is. I have my doubts about his way of denoting functional composition, and his density of definitions was sometimes higher than I could cope with. His lectures were undoubtedly among the high points of the Summer School.

The alphabetically next speaker was Butler W.Lampson (Digital Equipment Corporation), whose topic was "Specifying Distributed Systems". He was the other speaker that arrived four days late. In doing so, he had missed my introduction in which I had asked the speakers to be constantly aware of the linguistical barriers and to speak therefore slowly and clearly. I blame myself for not having repeated the warning to Lampson, for now his first talk was somewhat of a disaster; moreover the lettering on his visuals was too small. He enlarged his visuals somewhat and spoke in later talks more slowly. In order to be "understood" back home, he had adapted his style of specification and his notational conventions to the tastes and expectations of his American colleagues. The resulting texts hardly seemed to lend themselves to manipulation; when too many errors showed up, my fears were confirmed and I lost interest.

Jayadev Misra (University of Texas at Austin) had as title "Parallel Program Design: A Foundation". He spoke on the principles of UNITY, which he illustrated by developing quite a number of ambitious parallel programs. His lectures had been prepared with great care, and were received accordingly. The information flow, however, was very dense, and it might have been kinder to the audience if he had shown fewer examples at a somewhat more leisurely pace; but the audience did not seem to mind. During one of the discussions, he was attacked by W.P.de Roever, who, having failed to catch the distinction between "ensures" and "leads to", had rushed to the conclusion that what Misra had done was all wrong; given the floor, de Roever completely discredited himself by making —pictorially and notationally— an unbelievable mess of his visual. I was somewhat shocked by the technical incompetence with which he tried to make his point; Misra dealt with him quietly and effectively.

J Strother Moore (University of Texas at Austin) described under the title "Computational Logic" the recent inclusion of quantification in the Boyer/Moore theorem prover, and he did so very well. For most of the audience, this was the first more detailed exposure to automatic theorem proving; moreover, the majority had no active experience in using LISP. Moore successfully overcame both handicaps. His lectures were most instructive and gave the audience a clear impression of the power of the theorem prover and of the constraints it imposes on its users. He made no secret of his unwillingness "to abandon the fruits of 18 years of investment". The extent to which the existing theorem prover might be a millstone around their necks was not so clear; the alternative of designing a completely new theorem prover seemed to have been rather rejected than seriously considered.

The last speaker was Jan L.A. van de Snepscheut (University of Groningen) on "Design of Concurrent Programs". He devoted two lectures on concurrent programs synchronized by means of semaphores and two on systolic computations. His visuals were done very well and contained precisely the information needed, and his arguments were terse and nicely calculational, but as a speaker he was not his usual, relaxed, self. He sometimes seemed unhappy, as if he felt a mismatch between the examples he had chosen and the interests of the audience. In his first lecture, when introducing semaphores, he made the tactical mistake —I trust he will never make it again— of calling the defining postulates "axioms". This is something you can do in front of a Dutch audience, but, in front of an international audience, the mere use of the term "axiom" immediately triggers all the pollution of Platonic philosophy. To his utter amazement, people started complaining that his axioms were not "self-evident". He was taken aback, and I don't think he fully recovered.

*                           *
*

The Summer School provided overwhelming evidence for the profound similarity between the design of a (proven) program and a (proven) theorem, and in doing so it did a great job. This emphasis, however, has also been experienced as misrepresentation, and not without justification: the practical differences remain underemphasized. On the one hand we should not forget that, viewed as a theorem, many a program is rather boring; on the other hand we should not forget that programs need to meet a greater scala of quality requirements than theorems: they need to be efficient and informal proofs rarely suffice for them. (The other day, a very recent Computing Science Master's Thesis at the Technical University of Eindhoven turned out to be seriously flawed; his supervisor —a mathematician still in the process of being retreaded as computing scientist— had erroneously assumed that his traditional standards of rigour would suffice.)

*                           *
*

Regrettably —for he had very much looked forward to it— one of the speakers who had been planned for four lectures, viz. David Gries, was prevented from attending. Fortunately, even without David Gries the scientific program was rather over- than underloaded. In this respect the Summer School was "as usual": too much of everything, except sleep.

                  Nuenen, 23 August 1988

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Tristram Brelstaff and Mario Béland
revised Tue, 12 May 2009

EWD 1027

My methodological blunder with grid polygons

A "grid polygon” is defined as a plane polygon whose vertices are the only grid points on its edges.

Lemma   Consider a grid triangle with 1 interior grid point; the interior point is the centre of gravity of the triangle.

I thought for a while and constructed

[picture] |         and         | [picture] |            .

Asked about my progress, I showed these two, adding “but I hate the case analysis and have as yet not shown that it is exhaustive”. How right was I about my caveat! The above case analysis is not exhaustive —there are infinitely many such triangles— and, moreover, it is totally superfluous.

I constructed these examples with the intention of convincing myself that grid triangles with 1 interior grid point do indeed exist. A stupid exercise, for if they don’t exist, the theorem is vacuously correct; furthermore, it is notoriously ineffective to study a non-empty set by looking at some of its members.

So we start afresh. The antecedent is about a grid triangle with 1 interior grid point, and the consequent is about a triangle and its centre of gravity. Start at the least familiar side, which is the antecedent. What can we say about a grid triangle with 1 interior point? By connecting the interior point with the vertices, we partition the original triangle into three grid triangles without interior grid points? A simpler concept!

What can we say about a grid triangle without interior grid points? In a way, it should not be too big, but if we are at a loss as how to make this constraint more precise, we can look at the consequent: what can we say about the size of the three triangles a big triangle is partitioned into when the centre of gravity is connected to the three vertices? The three small triangles have the same area, and, conversely, when a triangle is thus partitioned into three triangles of equal area, the interior point is the centre of gravity.

Since a grid triangle cannot be too small either we make a leap of faith and try to prove our theorem by showing that all grid triangles without interior grid points have the same area. Looking at the simplest example

we conclude that that area would have to be �. This fractional value begs to be eliminated, for, after all, grid points are about integer values. Fortunately, each grid triangle is half of a grid parallelogram

and if the grid triangle is without interior grid point, so is the grid parallelogram. So we are left with the obligation to show that a grid parallelogram without interior grid points has an area 1. This is most briefly shown by tiling the plane by such parallelograms, thus establishing a one-to-one correspondence between parallelograms and grid points — say, each parallelogram and its top-right vertex.

I am endebted to Wolfgang Hinderer (from Karlsruhe) for drawing my attention to this argument.

Nuenen, 23 August 1988

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD1028

Euclid, Netty, and the prime numbers

Euclid’s proof that there is no largest prime has always struck me as a shining gem from antiquity; I have often used it as example when arguing that I could consider a proof a greater contribution to our culture than the theorem proved by it. I still think it a gem, but this should not close our eyes for the fact that, by now, we can do much better.

In its ugliest form, Euclid’s proof is rendered along the following lines. Assume that N is the largest prime. By considering G = 1 + the product of the primes up to N, one can then establish, depending on whether G is prime or not, the existence of a prime that in either case exceeds N, thus contradicting the assumption.

Netty van Gasteren rendered Euclid’s proof along the following lines. Let S be a finite set of primes. Consider G = 1 + the product of the primes in S. None of the primes in S then divides G or any of its factors. Write G as a product of 1 or more prime factors: these do not occur in S. Having thus established that no finite set S contains all primes, we conclude that the set of primes is infinite and, hence, has no largest element.

Three improvements are worth noticing:
(i) the reductio ad absurdum has been eliminated
(ii) the case analysis on whether G is prime or not has been eliminated
(iii) lower or upper bounds on primes have been eliminated from the argument.

*                       *
*

None of the above is very surprising; my only reason for returning to this topic is that there is good reason to believe that by now we should be able to synthesize most of the argument. Here we go!

Our demonstrandum is “There is no largest prime number.”, something we obviously cannot prove without taking some properties of prime numbers into account. What is the simplest property of prime numbers we can think of? Defining a multiple to be an integer ≥ 2, we can state

Property 0 Each prime is a multiple.

What can we do with that in view of our demonstrandum? Well, the primes being a of integers bounded from below, we can conclude — denoting the set of prime numbers by P —

(there is no largest prime number) ≡
(P is empty) ⋁ (P is infinite)            ,

and, from Property 0 all by itself, there seems little more to be concluded. Strongly suspecting P to differ from the empty set, we head for the new demonstrandum

“P is infinite”.

How does one show that a set is infinite? For instance by showing that it has an infinite subset, but in a way that is begging the question, for then one has to show that that subset is infinite. I can think of only one way, viz. showing that each finite subset is a true subset. Hence our demonstrandum becomes:

“For each finite set S of prime numbers there exists a prime number that is not an element of S.”

So we have to show the existence of a prime. Do we know a property of prime number implying existence? Yes, we do

Property 1 Each multiple is a product of one or more factors, each of which belongs to P.

(In fact, it is possible to define the set of prime numbers as the smallest set P of multiples that satisfies Property 1. Note that we neither state nor use that each multiple has a unique prime factorization.)

The important thing in Property 1 is the “one or more”: each multiple m leads to one or more primes that divide it. Since we are interested in the existence of a prime that does not belong to some finite S, we are interested in some multiple that no element of S divides.

Separating our concerns: for a finite set S of primes, we are looking for a G such that
(i) G is a multiple, and
(ii) no element of S divides G.

Requirement (ii) excludes 1 ∈ S, so the least we can do is to constrain S to a set of multiples. In view of Property 0, that is a constraint we can live with. Now, a value meeting requirement (ii) is easily found — even independently of S —, viz. 1, but, in view of (i), 1 is not a suitable candidate for G. But our finding

(Am: m ∈ S: ¬ (m|1) )

is a stepping stone since

(m|a ⋀ ¬ (m|b) ⇒ ¬ (m|a±b)          (0)

Hence       (Am: m ∈ S: m|a) ⇒ ¬ (m|a±1)       .
Since S is finite, we can choose an a ≠ 0 so as to satisfy the antecedent, say the product of the elements in S: (πm: m ∈ S: m) = a       .
Since G ≥ 1, a + 1 ≥ 2, and G = a+1 meets both requirements (i) and (ii). Which completes the proof.

*                       *
*

In the above, the introduction of (0) still counts as a Rabbit. Apart from that I am pleased with the synthesis of the argument. The construction of G makes quite clear

(a) that elements of S don’t need to be primes and that it suffices that they are multiples

(b) that, instead of the product of the elements of S, any common multiple would have done

(c) why the 1 is added and not subtracted.

The argument also reflects nicely — as it should — that it is irrelevant that the prime numbers are smallest set P satisfying Property 1.

                          Austin, 19 September 1988

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Jonathan David Arndt
revised 12-Dec-2020

EWD 1033

Trip report E.W.Dijkstra, Zürich, 15–20 Oct. 1988

ETH Zürich had invited Ria and me to assist them in a three-fold celebration: the fortieth anniversary of their Institute for Applied Mathematics, the twentieth anniversary of their institutionalization of Computing Science, and the completion —well, ..... almost!— of the new Informatics Building.

Because the Swiss were paying our tickets, we decided to do both Atlantic crossings by Swissair, which fully lived up to its name and fame. (Like KLM, Swissair cannot be blamed for the inconvenience that is only to be expected, viz. that all seats are occupied.) In both directions, the schedule gave the best connections via Chicago, O'Hare, an airport I had managed to avoid for at least nine years, but, apparently, Americans don't fly on Saturdays. Early Saturday afternoon we had with AA an uneventful flight from Austin to Chicago, where we leisurely changed planes at an amazingly quiet airport; a glorious thunderstorm delayed our departure by about 45 minutes (and the next morning we arrived in Zürich a little bit late). The next Thursday, our departure from Zürich was delayed by a similar amount, this time by a strike of —whom else!— French air traffic controllers, but the wind was so favourable that we arrived 15 minutes ahead of schedule, which was nice, because, this time, we had the tightest possible connection. Americans do fly on Thursdays! This time, O'Hare was crowded (and the indications when to leave the elevator for Terminal 1 were not too clear.) But the crowd was under control: we were impressed when, only 35 minutes after touchdown, we had passed immigration and Customs and placed our suitcase on the transfer belt. (It made the connection.) The last leg was with UA: less than 14 hours after take off in Zürich, we landed in Austin. In short, our air travel had been very smooth.

In Switzerland, we stayed with Niklaus and Diana Wirth, at their home in Forch, just outside Zürich. Niklaus was at the airport to collect us. At home, Diana served us a light lunch, after which the four of us went for a strenuous walk through the beautiful countryside. (I was grateful for all the training I had had, climbing up to "Jester Estates", just above Robbie Creek Cove!) Ria and I managed to stay awake until ten o'clock in the evening.

On Monday evening, we were invited out for dinner by Prof. Bühlmann, the President of ETH, and on Tuesday evening, Diana had organized a dinner party at her home. At both occasions, we enjoyed excellent food in most pleasant company. On Wednesday evening, we had the official banquet in the restaurant on top of the Uetliberg, but by that time, I was too tired to enjoy the food. It was also too noisy. We were given the "table of honour", i.e the one with minimum distance from the music; moreover we shared it with the politicians who "talked of their affairs in loud and strident voices" —and in their home dialects(presumably they did not know that we Americans would have been able to understand them without problems, had they spoken Hochdeutsch)—. Niklaus had to collect his car in Zürich; Diana and we got a —very smooth!— ride home from Prof. Frei.

I spent all three days in the Institute, where I had been in the visitor's office. On Monday, at 16:15, I gave a well-attended seminar on Sylvester's conjecture (See EWD1016). It turned out to be the inauguration of their new auditorium, which has been equipped with beautiful blackboards. (I praised them for the quality of their boards and for the absence of any mechanical "aids" by which to slide them up and down: Germans would almost certainly installed all sorts of confusing buttons to be pushed.) I had prepared the rear board and worked on the other two. I gave a beautiful lecture in spite of the fact that it was (again) a very hard audience to work with. I like a somewhat Socratic lecturing style in which I solicit from the audience suggestions as to what to do next, but —as at previous occasions— the Swiss student thinks it safer to sit and listen. Moreover, ETH seems very much the type of engineering school at which mathematics —if admitted at all— is at most a "Hilfswissenschaft" to be applied in the most straightforward, unthinking manner. It is certainly not something to be played with! Only now I am writing this, I realize how strongly earlier impressions have been confirmed. Just as at an earlier visit, Niklaus had announced that I was available for people who would like to speak to me and I kept my door open; but, as before, only very few people came by. (I had plenty of time to write a four-page letter.)

On Tuesday afternoon —same time, same place— Gaston Gonnet from Waterloo, Canada, gave a nice lecture on how he used his interactive formula manipulator to do what he called "experimental mathematics". He used the overhead projector. A few of his results were impressive and his enthusiasm was convincing: he had certainly had his well-deserved fun! Doing mathematics, however, seems to have contracted his vision to solving problems from the American Mathematical Monthly, and i found that depressing.

On Wednesday, we had the official celebration with in the morning three talks —in order, by F.L. Bauer, by me, and by Niklaus—, and in the afternoon lectures, presentations, and demonstrations by members of the Institute. Bauer tried to argue the relevance of algebra for informatics, which turned out to be an unsuitable topic to get across the limelight in an oral presentation and i must reserve the right to remain unconvinced until I have read his text. After the coffee break, I presented —with a few extempore additions— EWD1024, which was well-received, though —as in Bauer's case— there was no discussion afterwards. Finally, Niklaus talked, mainly on ETH history, and he did a difficult job extremely well. The simple way out would have been to pretend that there had been nothing rotten in the state of Danmark. Instead, he clearly described the obstruction from ETH's establishment from informatics becoming more than an organization giving low-level programming courses that were supposed to satisfy the needs of other departments. He did not hide the department's current weaknesses and made clear that just buying more equipment would not cure automatically ETH's ills. A difficult message, but he brought it very nicely. After his talk there was a discussion, but, since it was more political then technical, I could not follow it.

In the afternoon I did not attend the demonstrations. I did not feel too well —it was very warm in the new building— and stayed mostly in my room. At six o'clock, Niklaus came to take me to the restaurant. Contrary to his intentions, he had had to be busy most of the afternoon, and his temper had suffered from these unexpected obligations.

The next morning, Niklaus had a meeting at the ETH, and we said goodbye. At the end of the morning Diana took us to the airport, where we took leave from our host. That last morning it rained. Niklaus Wirth and Jürg Gutknecht had been the only two colleagues of the ETH with whom I had talked about technical matters, and I drew my conclusions.

                          Austin, 22 October 1988

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
United States of America

transcribed by Tristram Brelstaff
revised Tue, 12 May 2009

EWD1035

Confidential

On long-range planning for the CS department

There are two related, but distinct topics: the future of CS and the future of the CS department. They are distinct topics because the former can be discussed independently of local constraints, while the latter one cannot. Let us briefly discuss the future of CS first, because, without a clear view of that, I cannot meaningfully discuss the future of the department.

The future of Computing Science

To avoid misunderstanding, when I refer to CS I do not refer to its social aspects (such as how it can be sold, how it can supposedly be useful, what benefits are expected from it, etc.). Nor do I refer to it as viewed by the politicians, the majority of the laymen (or by the majority of the not-so-layman for that matter). Instead, when I refer to CS I refer to an intellectual discipline as characterized by its internal structure (which gives it its coherence), its challenges, and its opportunities, to which list I should add �because we are discussing CS� its novelty.

As a further preliminary, I should point out two different ways of coping with novelty. Most �novelty� is not radical but gradual. To cope with the latter, we can try to understand it in terms of what is familiar and to relate it to past experience: using metaphors and analogies we can plan today for tomorrow in yesterday's terminology. This is by far the most common situation, and therefore the situation most people are most comfortable with. In the case of radical novelty, however, this familiar way of �understanding� does not work, because our past experience is irrelevant and the analogies are so shallow that they become more misleading than illuminating. Radical novelty can only be approached with a �tabula rasa�, by not trying to relate it to earlier experience but by trying to come to grips with it via its internal structure, properties, consistency, what have you. (The latter way of understanding is less popular because it requires hard work.)

Technology is expert at inflicting radical novelties upon mankind. Nuclear weapons and the pill are examples from the last 50 years; so is in my opinion the automatic computer, and this not so much in its capacity of a tool �in that capacity it causes only a ripple on the surface of our culture� as in its capacity of a challenge that is absolutely without precedent in the history of Mankind.

Radical novelties are, almost by definition, rather unsettling. There are people for whom gradual change is the only paradigm of history and incremental improvement the only paradigm of progress. For them, radical novelty is most unsettling, because invisible.

The combined assumption that, for the majority of people, gradual change is their primary historical paradigm and that computers embody a radical novelty explains all sorts of strange phenomena. I mention a few examples.

(i) The popularity of �Software Engineering�. Millions of dollars �and pounds, for that matter!� have been poured into it without any tangible benefit. It will never bear fruit, as analysis of the SE literature reveals that it has accepted as its charter the self-contradictory target �how to program if you can�t�, and that, by calling it �software production�, it treats programming as a production process �in which programmer productivity is measured in SLOC�s ( = Source Lines of Code) per month�. This grandiose idiocy, however, is popular because it has couched the frighteningly unfamiliar in reassuringly familiar terms, no matter how inadequate.

(ii) The mathematician�s neglect of automatic computing. Naively one would have expected the mathematical community to have welcomed this new opportunity to show the indispensable value of its well-honed intellects, but nothing of the sort! Instead, it regularly declares that CS is so trivial that it neither deserves the name of a science, nor any of their valuable attention. In fact, they skirt the issue because facing it would frighten the wits out of them.

(iii) The popularity of AI. One would expect people to feel threatened by �the giant brains�. In fact, the frightening computer becomes less frightening if it is only used to simulate a familiar noncomputer (no matter how imperfectly).

So much for radical novelty and the general difficulty �including our own� of dealing with it. Let us turn our attention to our announced topic, the future of Computing Science.

When all is said and told, the only thing a computer can do for us is to manipulate symbols, but it does so on a scale that is without precedent. To do so, it has to be programmed, and the only known way of getting these programs is ...... by symbol manipulation, which, for a sizeable program, is of an uncommon amount. For me, this observation forces two conclusions, a qualitative and a quantitative one. The qualitative one is that CS is unavoidably concerned with the interplay between mechanized and human symbol manipulation. The quantitative one is that CS is unavoidably concerned with the effective application of formal techniques on a scale very few people, as yet, have dreamt of. Whether we like it or not, here is the core challenge that Computing Science as intellectual discipline faces: how to apply �mechanized or humanly� formal techniques effectively and on a much larger scale than ever envisaged before. By its availability, the equipment provides both the challenge and the opportunity. The challenge is unavoidably ours because neither the mathematicians nor the logicians are inclined to pick up the gauntlet.

The mathematicians don�t pick up the gauntlet because, by and large, the mathematical guild is very informal. Whole books have been devoted to the right of the �real mathematician� to wave his hands. They are the prisoners of a tradition of more than 25 centuries and continue to cling, but for a small minority, to the consensus model of mathematical truth.

The logicians don�t pick up the gauntlet either. They are in the process of transferring logic from �the handmaiden of philosophy� and a mimicking of human reasoning to an alternative to human reasoning. Their focus, though, is on what logical systems can and can not achieve �in principle� and the effective application of formal techniques; �logic as engineering discipline�, so to speak, is beyond the commitment of their community as a whole.

In short, I present a vision of CS as a branch of formal mathematics and of applied logic that will in due time transcend its parent disciplines by effectively realizing a significant part of Leibniz�s Dream of providing symbolic calculation as an alternative to human reasoning.

Needless to say, this vision is not universally shared. On the contrary, it has met wide-spread �and sometimes even violent� opposition from all sorts of directions. I mention

the mathematical guild that would rather continue to believe that the Dream of Leibniz is an unrealistic illusion

the business community that, having been sold to the idea that computers would make life easier, is mentally unprepared to accept that they only solve the easier problems by creating much harder ones

computer engineering that would rather continue to act as if it is all only a matter of bitrates and flops

all soft sciences for which computing now acts as some sort of interdisciplinary haven

the educational business that feels that, if it has to teach formal mathematics to CS students, it can as well close its schools.

Wide-spread as it is, the opposition is no ground for concluding that there is something wrong with the vision in question. The opposition merely reflects that there is a definite upper bound for the rate at which society as a whole can absorb intellectual progress (if it can do so at all). Intellectual revolutions are as unwelcome as political ones.

I should add that the vision is by no means universally rejected. In some form or another, it is a source of inspiration for quite a few colleagues � here and elsewhere �, who act accordingly, both in their teaching and in the direction of their research. (Admittedly, they are a minority, but so was Galileo Galilei.)

Educational policy

Educational policy is trivial if the needs of society coincide with what society ask for. Such coincidence, regrettably, is extremely rare. In the case of computing science �and in view of the topic�s radical novelty, this is not amazing at all� the discrepancy between needs and requests is truly dramatic. I have seen requests for more �Advanced COBOL� in the curriculum, general complaints that the undergraduate curriculum is �too innovative� and neglects �fundamentals� such as �basic business practice and awareness, the invoice cycle and the nominal ledger�; we should pay more attention to the teaching of �communication skills�, �teamwork�, �group dynamics�, �human psychology� and �innovation management�. If these noises come primarily from computer users, those from computer manufacturers are equally ignorable. (For instance, in 1975, IBM has explained at length to the �Canadian� universities that they should not teach operating systems principles, because �work on OS is not an entry-level job�. IBM was clearly afraid of employees knowing how operating systems should be constructed. I trust that the rest of the computer industry is somewhat more enlightened, but have all reason to assume that on the whole it is not significantly so. Certainly where programming is concerned, the computer industry �with the possible exception of INMOS� has not yet fathomed the consequences of being involved in a high-technology industry.) So, by and large, we are on our own!

We are faced with the traditional teacher�s dilemma that whenever we succeed in doing our job well, we have delivered misfits. We may be faced with the dilemma in extreme form; yet I call the dilemma �traditional�, because no one can found a new �school of thought� without delivering graduates that differ.

One of the ways of solving the dilemma is by avoiding it: don't rock the boat! An extreme example is provided by the ultraconservative university of Cervera, Spain, whose Rector reassured the visiting monarch Ferdinand with the words, �Far be from us, Sire, the dangerous novelty of thinking.�. (This was in the previous century, around the time Texas gained its independence from Mexico. Cervera did not become a leading university and, were UT to follow its example, it could be argued that the war with Mexico has been fought in vain.)

Another way of trying to solve the dilemma is by joining an established �school of thought� that still shows signs of vigour, and by trying to find recognition in that league. In our industry I think it is known as �the Amdahl strategy�. For an American CS department, the analogue would be cloning, say, Stanford/MIT/CMU/Berkeley, all rolled into one. If we wish to consider the Amdahl strategy for the CS department at UT we must consider at least two issues, a tactical one and more fundamental one.

The tactical one is concerned with our chance of success, in particular: is there any chance of successfully competing with those four (i) as long as Texas is viewed in the USA as Down Under is viewed in the world, and (ii) when, competing for the same competence �both in faculty and students� as those four, we can expect to have to recruit from their leftovers? (I am still a stranger to these shores and, hence, without such a thing as a considered opinion on this question. My impression in that the answer might very well turn out to be negative.)

The more fundamental point is: do we really believe that those four have faced the dilemma, to provide what society needs and serve computing science as it deserves to be served? If not, there is little point is just offering more of the same.

Finally, if the best we can reach via the Amdahl strategy is becoming the leading clone, it raises the question whether we can thus meet our charter of becoming �a leading department�.

If the conditions are satisfied �or seem satisfiable� we can try the complement of the Amdahl strategy; we might call it the anti-clone strategy. Instead of trying to imitate the big four, one tries to distinguish oneself from them, the clearer, the better. To be successful, it has to be done clearly, for it boils down to a �redefinition� of CS as popularly conceived.

Two technical conditions have to be satisfied. Firstly, there are one or more areas or aspects that are neglected by the big four while deserving a better fate. Secondly, our department must have the corresponding strengths or it must be conceivable to build them up. (Cornell seems to have opted for such a strategy when it decided to focus on �robotics�; I have second thoughts about that choice: the topic is a bit small and rather peripheral, and �cf. MIT and CMU� only mildly different. I am afraid that time will show that Cornell has been too timid.) We should realize that such areas �if they exist� are of necessity unfashionable and unpopular. (Note that the unpopularity would also be our protection: it will delay the moment others join the bandwaggon, and when they do, we know, in a way, that we have succeeded.)

Off hand, I can think of one candidate that seems to meet the technical conditions, viz. �the effective, large-scale application of formal methods�: it is neglected by the big four; it lies at the core of computing science; UT�s department has considerable strength in this direction; it is sufficiently unpopular �it is in fact more unpopular in the USA than elsewhere, and that is good: it will delay the big four in joining the bandwaggon while our graduate population is sufficiently international not be hurt by it, probably on the contrary.)

We would not be alone either: it would put us in league with Oxford and Edinburgh (and later, as the case may be, Groningen or perhaps CalTech). None of those I consider deadly competitors.

Whatever area is chosen, the adoption of an anti-clone strategy will cause internal problems in any department that adopts it. Individuals can take more extreme positions than whole departments can, and it is therefore a safe assumption that only a part of the faculty will be affected by or involved in such an anti-clone strategy. The danger that others feel left out in the cold is only too real. The challenge is how to avoid needless pain in the implementation of such a strategy without sabotaging it.

                          Austin, 7 November 1988

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Jonathan David Arndt
revised 01-Nov-2019

EWD 1036

On the cruelty of really teaching computing science

The second part of this talk pursues some of the scientific and educational consequences of the assumption that computers represent a radical novelty. In order to give this assumption clear contents, we have to be much more precise as to what we mean in this context by the adjective "radical". We shall do so in the first part of this talk, in which we shall furthermore supply evidence in support of our assumption.

The usual way in which we plan today for tomorrow is in yesterday's vocabulary. We do so, because we try to get away with the concepts we are familiar with and that have acquired their meanings in our past experience. Of course, the words and the concepts don't quite fit because our future differs from our past, but then we stretch them a little bit. Linguists are quite familiar with the phenomenon that the meanings of words evolve over time, but also know that this is a slow and gradual process.

It is the most common way of trying to cope with novelty: by means of metaphors and analogies we try to link the new to the old, the novel to the familiar. Under sufficiently slow and gradual change, it works reasonably well; in the case of a sharp discontinuity, however, the method breaks down: though we may glorify it with the name "common sense", our past experience is no longer relevant, the analogies become too shallow, and the metaphors become more misleading than illuminating. This is the situation that is characteristic for the "radical" novelty.

Coping with radical novelty requires an orthogonal method. One must consider one's own past, the experiences collected, and the habits formed in it as an unfortunate accident of history, and one has to approach the radical novelty with a blank mind, consciously refusing to try to link it with what is already familiar, because the familiar is hopelessly inadequate. One has, with initially a kind of split personality, to come to grips with a radical novelty as a dissociated topic in its own right. Coming to grips with a radical novelty amounts to creating and learning a new foreign language that can not be translated into one's mother tongue. (Any one who has learned quantum mechanics knows what I am talking about.) Needless to say, adjusting to radical novelties is not a very popular activity, for it requires hard work. For the same reason, the radical novelties themselves are unwelcome.

By now, you may well ask why I have paid so much attention to and have spent so much eloquence on such a simple and obvious notion as the radical novelty. My reason is very simple: radical novelties are so disturbing that they tend to be suppressed or ignored, to the extent that even the possibility of their existence in general is more often denied than admitted.

On the historical evidence I shall be short. Carl Friedrich Gauss, the Prince of Mathematicians but also somewhat of a coward, was certainly aware of the fate of Galileo —and could probably have predicted the calumniation of Einstein— when he decided to suppress his discovery of non-Euclidean geometry, thus leaving it to Bolyai and Lobatchewsky to receive the flak. It is probably more illuminating to go a little bit further back, to the Middle Ages. One of its characteristics was that "reasoning by analogy" was rampant; another characteristic was almost total intellectual stagnation, and we now see why the two go together. A reason for mentioning this is to point out that, by developing a keen ear for unwarranted analogies, one can detect a lot of medieval thinking today.

The other thing I can not stress enough is that the fraction of the population for which gradual change seems to be all but the only paradigm of history is very large, probably much larger than you would expect. Certainly when I started to observe it, their number turned out to be much larger than I had expected.

For instance, the vast majority of the mathematical community has never challenged its tacit assumption that doing mathematics will remain very much the same type of mental activity it has always been: new topics will come, flourish, and go as they have done in the past, but, the human brain being what it is, our ways of teaching, learning, and understanding mathematics, of problem solving, and of mathematical discovery will remain pretty much the same. Herbert Robbins clearly states why he rules out a quantum leap in mathematical ability:

"Nobody is going to run 100 meters in five seconds, no matter how much is invested in training and machines. The same can be said about using the brain. The human mind is no different now from what it was five thousand years ago. And when it comes to mathematics, you must realize that this is the human mind at an extreme limit of its capacity."

My comment in the margin was "so reduce the use of the brain and calculate!". Using Robbins's own analogy, one could remark that, for going from A to B fast, there could now exist alternatives to running that are orders of magnitude more effective. Robbins flatly refuses to honour any alternative to time-honoured brain usage with the name of "doing mathematics", thus exorcizing the danger of radical novelty by the simple device of adjusting his definitions to his needs: simply by definition, mathematics will continue to be what it used to be. So much for the mathematicians.

Let me give you just one more example of the widespread disbelief in the existence of radical novelties and, hence, in the need of learning how to cope with them. It is the prevailing educational practice, for which gradual, almost imperceptible, change seems to be the exclusive paradigm. How many educational texts are not recommended for their appeal to the student's intuition! They constantly try to present everything that could be an exciting novelty as something as familiar as possible. They consciously try to link the new material to what is supposed to be the student's familiar world. It already starts with the teaching of arithmetic. Instead of teaching 2 + 3 = 5 , the hideous arithmetic operator "plus" is carefully disguised by calling it "and", and the little kids are given lots of familiar examples first, with clearly visible such as apples and pears, which are in, in contrast to equally countable objects such as percentages and electrons, which are out. The same silly tradition is reflected at university level in different introductory calculus courses for the future physicist, architect, or business major, each adorned with examples from the respective fields. The educational dogma seems to be that everything is fine as long as the student does not notice that he is learning something really new; more often than not, the student's impression is indeed correct. I consider the failure of an educational practice to prepare the next generation for the phenomenon of radical novelties a serious shortcoming. [When King Ferdinand visited the conservative university of Cervera, the Rector proudly reassured the monarch with the words; "Far be from us, Sire, the dangerous novelty of thinking.". Spain's problems in the century that followed justify my characterization of the shortcoming as "serious".] So much for education's adoption of the paradigm of gradual change.

The concept of radical novelties is of contemporary significance because, while we are ill-prepared to cope with them, science and technology have now shown themselves expert at inflicting them upon us. Earlier scientific examples are the theory of relativity and quantum mechanics; later technological examples are the atom bomb and the pill. For decades, the former two gave rise to a torrent of religious, philosophical, or otherwise quasi-scientific tracts. We can daily observe the profound inadequacy with which the latter two are approached, be it by our statesmen and religious leaders or by the public at large. So much for the damage done to our peace of mind by radical novelties.

I raised all this because of my contention that automatic computers represent a radical novelty and that only by identifying them as such can we identify all the nonsense, the misconceptions and the mythology that surround them. Closer inspection will reveal that it is even worse, viz. that automatic computers embody not only one radical novelty but two of them.

The first radical novelty is a direct consequence of the raw power of today's computing equipment. We all know how we cope with something big and complex; divide and rule, i.e. we view the whole as a compositum of parts and deal with the parts separately. And if a part is too big, we repeat the procedure. The town is made up from neighbourhoods, which are structured by streets, which contain buildings, which are made from walls and floors, that are built from bricks, etc. eventually down to the elementary particles. And we have all our specialists along the line, from the town planner, via the architect to the solid state physicist and further. Because, in a sense, the whole is "bigger" than its parts, the depth of a hierarchical decomposition is some sort of logarithm of the ratio of the "sizes" of the whole and the ultimate smallest parts. From a bit to a few hundred megabytes, from a microsecond to a half an hour of computing confronts us with completely baffling ratio of 10⁹! The programmer is in the unique position that his is the only discipline and profession in which such a gigantic ratio, which totally baffles our imagination, has to be bridged by a single technology. He has to be able to think in terms of conceptual hierarchies that are much deeper than a single mind ever needed to face before. Compared to that number of semantic levels, the average mathematical theory is almost flat. By evoking the need for deep conceptual hierarchies, the automatic computer confronts us with a radically new intellectual challenge that has no precedent in our history.

Again, I have to stress this radical novelty because the true believer in gradual change and incremental improvements is unable to see it. For him, an automatic computer is something like the familiar cash register, only somewhat bigger, faster, and more flexible. But the analogy is ridiculously shallow: it is orders of magnitude worse than comparing, as a means of transportation, the supersonic jet plane with a crawling baby, for that speed ratio is only a thousand.

The second radical novelty is that the automatic computer is our first large-scale digital device. We had a few with a noticeable discrete component: I just mentioned the cash register and can add the typewriter with its individual keys: with a single stroke you can type either a Q or a W but, though their keys are next to each other, not a mixture of those two letters. But such mechanisms are the exception, and the vast majority of our mechanisms are viewed as analogue devices whose behaviour is over a large range a continuous function of all parameters involved: if we press the point of the pencil a little bit harder, we get a slightly thicker line, if the violinist slightly misplaces his finger, he plays slightly out of tune. To this I should add that, to the extent that we view ourselves as mechanisms, we view ourselves primarily as analogue devices: if we push a little harder we expect to do a little better. Very often the behaviour is not only a continuous but even a monotonic function: to test whether a hammer suits us over a certain range of nails, we try it out on the smallest and largest nails of the range, and if the outcomes of those two experiments are positive, we are perfectly willing to believe that the hammer will suit us for all nails in between.

It is possible, and even tempting, to view a program as an abstract mechanism, as a device of some sort. To do so, however, is highly dangerous: the analogy is too shallow because a program is, as a mechanism, totally different from all the familiar analogue devices we grew up with. Like all digitally encoded information, it has unavoidably the uncomfortable property that the smallest possible perturbations —i.e. changes of a single bit— can have the most drastic consequences. [For the sake of completness I add that the picture is not essentially changed by the introduction of redundancy or error correction.] In the discrete world of computing, there is no meaningful metric in which "small" changes and "small" effects go hand in hand, and there never will be.

This second radical novelty shares the usual fate of all radical novelties: it is denied, because its truth would be too discomforting. I have no idea what this specific denial and disbelief costs the United States, but a million dollars a day seems a modest guess.

Having described —admittedly in the broadest possible terms— the nature of computing's novelties, I shall now provide the evidence that these novelties are, indeed, radical. I shall do so by explaining a number of otherwise strange phenomena as frantic —but, as we now know, doomed— efforts at hiding or denying the frighteningly unfamiliar.

A number of these phenomena have been bundled under the name "Software Engineering". As economics is known as "The Miserable Science", software engineering should be known as "The Doomed Discipline", doomed because it cannot even approach its goal since its goal is self-contradictory. Software engineering, of course, presents itself as another worthy cause, but that is eyewash: if you carefully read its literature and analyse what its devotees actually do, you will discover that software engineering has accepted as its charter "How to program if you cannot.".

The popularity of its name is enough to make it suspect. In what we denote as "primitive societies", the superstition that knowing someone's true name gives you magic power over him is not unusual. We are hardly less primitive: why do we persist here in answering the telephone with the most unhelpful "hello" instead of our name?

Nor are we above the equally primitive superstition that we can gain some control over some unknown, malicious demon by calling it by a safe, familiar, and innocent name, such as "engineering". But it is totally symbolic, as one of the US computer manufacturers proved a few years ago when it hired, one night, hundreds of new "software engineers" by the simple device of elevating all its programmers to that exalting rank. So much for that term.

The practice is pervaded by the reassuring illusion that programs are just devices like any others, the only difference admitted being that their manufacture might require a new type of craftsmen, viz. programmers. From there it is only a small step to measuring "programmer productivity" in terms of "number of lines of code produced per month". This is a very costly measuring unit because it encourages the writing of insipid code, but today I am less interested in how foolish a unit it is from even a pure business point of view. My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger.

Besides the notion of productivity, also that of quality control continues to be distorted by the reassuring illusion that what works with other devices works with programs as well. It is now two decades since it was pointed out that program testing may convincingly demonstrate the presence of bugs, but can never demonstrate their absence. After quoting this well-publicized remark devoutly, the software engineer returns to the order of the day and continues to refine his testing strategies, just like the alchemist of yore, who continued to refine his chrysocosmic purifications.

Unfathomed misunderstanding is further revealed by the term "software maintenance", as a result of which many people continue to believe that programs —and even programming languages themselves— are subject to wear and tear. Your car needs maintenance too, doesn't it? Famous is the story of the oil company that believed that its PASCAL programs did not last as long as its FORTRAN programs "because PASCAL was not maintained".

In the same vein I must draw attention to the astonishing readiness with which the suggestion has been accepted that the pains of software production are largely due to a lack of appropriate "programming tools". (The telling "programmer's workbench" was soon to follow.) Again, the shallowness of the underlying analogy is worthy of the Middle Ages. Confrontations with insipid "tools" of the "algorithm-animation" variety has not mellowed my judgement; on the contrary, it has confirmed my initial suspicion that we are primarily dealing with yet another dimension of the snake oil business.

Finally, to correct the possible impression that the inability to face radical novelty is confined to the industrial world, let me offer you an explanation of the —at least American— popularity of Artificial Intelligence. One would expect people to feel threatened by the "giant brains or machines that think". In fact, the frightening computer becomes less frightening if it is used only to simulate a familiar noncomputer. I am sure that this explanation will remain controversial for quite some time, for Artificial Intelligence as mimicking the human mind prefers to view itself as at the front line, whereas my explanation relegates it to the rearguard. (The effort of using machines to mimic the human mind has always struck me as rather silly: I'd rather use them to mimic something better.)

So much for the evidence that the computer's novelties are, indeed, radical.

And now comes the second —and hardest— part of my talk: the scientific and educational consequences of the above. The educational consequences are, of course, the hairier ones, so let's postpone their discussion and stay for a while with computing science itself. What is computing? And what is a science of computing about?

Well, when all is said and done, the only thing computers can do for us is to manipulate symbols and produce results of such manipulations. From our previous observations we should recall that this is a discrete world and, moreover, that both the number of symbols involved and the amount of manipulation performed are many orders of magnitude larger than we can envisage: they totally baffle our imagination and we must therefore not try to imagine them.

But before a computer is ready to perform a class of meaningful manipulations —or calculations, if you prefer— we must write a program. What is a program? Several answers are possible. We can view the program as what turns the general-purpose computer into a special-purpose symbol manipulator, and does so without the need to change a single wire (This was an enormous improvement over machines with problem-dependent wiring panels.) I prefer to describe it the other way round: the program is an abstract symbol manipulator, which can be turned into a concrete one by supplying a computer to it. After all, it is no longer the purpose of programs to instruct our machines; these days, it is the purpose of machines to execute our programs.

So, we have to design abstract symbol manipulators. We all know what they look like: they look like programs or —to use somewhat more general terminology— usually rather elaborate formulae from some formal system. It really helps to view a program as a formula. Firstly, it puts the programmer's task in the proper perspective: he has to derive that formula. Secondly, it explains why the world of mathematics all but ignored the programming challenge: programs were so much longer formulae than it was used to that it did not even recognize them as such. Now back to the programmer's job: he has to derive that formula, he has to derive that program. We know of only one reliable way of doing that, viz. by means of symbol manipulation. And now the circle is closed: we construct our mechanical symbol manipulators by means of human symbol manipulation.

Hence, computing science is —and will always be— concerned with the interplay between mechanized and human symbol manipulation, usually referred to as "computing" and "programming" respectively. An immediate benefit of this insight is that it reveals "automatic programming" as a contradiction in terms. A further benefit is that it gives us a clear indication where to locate computing science on the world map of intellectual disciplines: in the direction of formal mathematics and applied logic, but ultimately far beyond where those are now, for computing science is interested in effective use of formal methods and on a much, much, larger scale than we have witnessed so far. Because no endeavour is respectable these days without a TLA (= Three-Letter Acronym), I propose that we adopt for computing science FMI (= Formal Methods Initiative), and, to be on the safe side, we had better follow the shining examples of our leaders and make a Trade Mark of it.

In the long run I expect computing science to transcend its parent disciplines, mathematics and logic, by effectively realizing a significant part of Leibniz's Dream of providing symbolic calculation as an alternative to human reasoning. (Please note the difference between "mimicking" and "providing an alternative to": alternatives are allowed to be better.)

Needless to say, this vision of what computing science is about is not universally applauded. On the contrary, it has met widespread —and sometimes even violent— opposition from all sorts of directions. I mention as examples

(0) the mathematical guild, which would rather continue to believe that the Dream of Leibniz is an unrealistic illusion

(1) the business community, which, having been sold to the idea that computers would make life easier, is mentally unprepared to accept that they only solve the easier problems at the price of creating much harder ones

(2) the subculture of the compulsive programmer, whose ethics prescribe that one silly idea and a month of frantic coding should suffice to make him a life-long millionaire

(3) computer engineering, which would rather continue to act as if it is all only a matter of higher bit rates and more flops per second

(4) the military, who are now totally absorbed in the business of using computers to mutate billion-dollar budgets into the illusion of automatic safety

(5) all soft sciences for which computing now acts as some sort of interdisciplinary haven

(6) the educational business that feels that, if it has to teach formal mathematics to CS students, it may as well close its schools.

And with this sixth example I have reached, imperceptibly but also alas unavoidably, the most hairy part of this talk: educational consequences.

The problem with educational policy is that it is hardly influenced by scientific considerations derived from the topics taught, and almost entirely determined by extra-scientific circumstances such as the combined expectations of the students, their parents and their future employers, and the prevailing view of the role of the university: is the stress on training its graduates for today's entry-level jobs or to providing its alumni with the intellectual bagage and attitudes that will last them another 50 years? Do we grudgingly grant the abstract sciences only a far-away corner on campus, or do we recognize them as the indispensable motor of the high-technology industry? Even if we do the latter, do we recognize a high-technology industry as such if its technology primarily belongs to formal mathematics? Do the universities provide for society the intellectual leadership it needs or only the training it asks for?

Traditional academic rhetoric is perfectly willing to give to these questions the reassuring answers, but I don't believe them. By way of illustration of my doubts, in a recent article on "Who Rules Canada?", David H. Flaherty bluntly states "Moreover, the business elite dismisses traditional academics and intellectuals as largely irrelevant and powerless.".

So, if I look into my foggy crystal ball at the future of computing science education, I overwhelmingly see the depressing picture of "Business as usual". The universities will continue to lack the courage to teach hard science, they will continue to misguide the students, and each next stage of infantilization of the curriculum will be hailed as educational progress.

I now have had my foggy crystal ball for quite a long time. Its predictions are invariably gloomy and usually correct, but I am quite used to that and they won't keep me from giving you a few suggestions, even if it is merely an exercise in futility whose only effect is to make you feel guilty.

We could, for instance, begin with cleaning up our language by no longer calling a bug a bug but by calling it an error. It is much more honest because it squarely puts the blame where it belongs, viz. with the programmer who made the error. The animistic metaphor of the bug that maliciously sneaked in while the programmer was not looking is intellectually dishonest as it disguises that the error is the programmer's own creation. The nice thing of this simple change of vocabulary is that it has such a profound effect: while, before, a program with only one bug used to be "almost correct", afterwards a program with an error is just "wrong" (because in error).

My next linguistical suggestion is more rigorous. It is to fight the "if-this-guy-wants-to-talk-to-that-guy" syndrome: never refer to parts of programs or pieces of equipment in an anthropomorphic terminology, nor allow your students to do so. This linguistical improvement is much harder to implement than you might think, and your department might consider the introduction of fines for violations, say a quarter for undergraduates, two quarters for graduate students, and five dollars for faculty members: by the end of the first semester of the new regime, you will have collected enough money for two scholarships.

The reason for this last suggestion is that the anthropomorphic metaphor —for whose introduction we can blame John von Neumann— is an enormous handicap for every computing community that has adopted it. I have now encountered programs wanting things, knowing things, expecting things, believing things, etc., and each time that gave rise to avoidable confusions. The analogy that underlies this personification is so shallow that it is not only misleading but also paralyzing.

It is misleading in the sense that it suggests that we can adequately cope with the unfamiliar discrete in terms of the familiar continuous, i.e. ourselves, quod non. It is paralyzing in the sense that, because persons exist and act in time, its adoption effectively prevents a departure from operational semantics and thus forces people to think about programs in terms of computational behaviours, based on an underlying computational model. This is bad, because operational reasoning is a tremendous waste of mental effort.

Let me explain to you the nature of that tremendous waste, and allow me to try to convince you that the term "tremendous waste of mental effort" is not an exaggeration. For a short while, I shall get highly technical, but don't get frightened: it is the type of mathematics that one can do with one's hands in one's pockets. The point to get across is that if we have to demonstrate something about all the elements of a large set, it is hopelessly inefficient to deal with all the elements of the set individually: the efficient argument does not refer to individual elements at all and is carried out in terms of the set's definition.

Consider the plane figure Q, defined as the 8 by 8 square from which, at two opposite corners, two 1 by 1 squares have been removed. The area of Q is 62, which equals the combined area of 31 dominos of 1 by 2. The theorem is that the figure Q cannot be covered by 31 of such dominos.

Another way of stating the theorem is that if you start with squared paper and begin covering this by placing each next domino on two new adjacent squares, no placement of 31 dominos will yield the figure Q.

So, a possible way of proving the theorem is by generating all possible placements of dominos and verifying for each placement that it does not yield the figure Q: a tremendously laborious job.

The simple argument, however is as follows. Colour the squares of the squared paper as on a chess board. Each domino, covering two adjacent squares, covers 1 white and 1 black square, and, hence, each placement covers as many white squares as it covers black squares. In the figure Q, however, the number of white squares and the number of black squares differ by 2 —opposite corners lying on the same diagonal— and hence no placement of dominos yields figure Q.

Not only is the above simple argument many orders of magnitude shorter than the exhaustive investigation of the possible placements of 31 dominos, it is also essentially more powerful, for it covers the generalization of Q by replacing the original 8 by 8 square by any rectangle with sides of even length. The number of such rectangles being infinite, the former method of exhaustive exploration is essentially inadequate for proving our generalized theorem.

And this concludes my example. It has been presented because it illustrates in a nutshell the power of down-to-earth mathematics; needless to say, refusal to exploit this power of down-to-earth mathematics amounts to intellectual and technological suicide. The moral of the story is: deal with all elements of a set by ignoring them and working with the set's definition.

Back to programming. The statement that a given program meets a certain specification amounts to a statement about all computations that could take place under control of that given program. And since this set of computations is defined by the given program, our recent moral says: deal with all computations possible under control of a given program by ignoring them and working with the program. We must learn to work with program texts while (temporarily) ignoring that they admit the interpretation of executable code.

Another way of saying the same thing is the following one. A programming language, with its formal syntax and with the proof rules that define its semantics, is a formal system for which program execution provides only a model. It is well-known that formal systems should be dealt with in their own right, and not in terms of a specific model. And, again, the corollary is that we should reason about programs without even mentioning their possible "behaviours".

And this concludes my technical excursion into the reason why operational reasoning about programming is "a tremendous waste of mental effort" and why, therefore, in computing science the anthropomorphic metaphor should be banned.

Not everybody understands this sufficiently well. I was recently exposed to a demonstration of what was pretended to be educational software for an introductory programming course. With its "visualizations" on the screen it was such an obvious case of curriculum infantilization that its author should be cited for "contempt" of the student body", but this was only a minor offense compared with what the visualizations were used for: they were used to display all sorts of features of computations evolving under control of the student's program! The system highlighted precisely what the student has to learn to ignore, it reinforced precisely what the student has to unlearn. Since breaking out of bad habits, rather than acquiring new ones, is the toughest part of learning, we must expect from that system permanent mental damage for most students exposed to it.

Needless to say, that system completely hid the fact that, all by itself, a program is no more than half a conjecture. The other half of the conjecture is the functional specification the program is supposed to satisfy. The programmer's task is to present such complete conjectures as proven theorems.

Before we part, I would like to invite you to consider the following way of doing justice to computing's radical novelty in an introductory programming course.

On the one hand, we teach what looks like the predicate calculus, but we do it very differently from the philosophers. In order to train the novice programmer in the manipulation of uninterpreted formulae, we teach it more as boolean algebra, familiarizing the student with all algebraic properties of the logical connectives. To further sever the links to intuition, we rename the values {true, false} of the boolean domain as {black, white}.

On the other hand, we teach a simple, clean, imperative programming language, with a skip and a multiple assignment as basic statements, with a block structure for local variables, the semicolon as operator for statement composition, a nice alternative construct, a nice repetition and, if so desired, a procedure call. To this we add a minimum of data types, say booleans, integers, characters and strings. The essential thing is that, for whatever we introduce, the corresponding semantics is defined by the proof rules that go with it.

Right from the beginning, and all through the course, we stress that the programmer's task is not just to write down a program, but that his main task is to give a formal proof that the program he proposes meets the equally formal functional specification. While designing proofs and programs hand in hand, the student gets ample opportunity to perfect his manipulative agility with the predicate calculus. Finally, in order to drive home the message that this introductory programming course is primarily a course in formal mathematics, we see to it that the programming language in question has not been implemented on campus so that students are protected from the temptation to test their programs. And this concludes the sketch of my proposal for an introductory programming course for freshmen.

This is a serious proposal, and utterly sensible. Its only disadvantage is that it is too radical for many, who, being unable to accept it, are forced to invent a quick reason for dismissing it, no matter how invalid. I'll give you a few quick reasons.

You don't need to take my proposal seriously because it is so ridiculous that I am obviously completely out of touch with the real world. But that kite won't fly, for I know the real world only too well: the problems of the real world are primarily those you are left with when you refuse to apply their effective solutions. So, let us try again.

You don't need to take my proposal seriously because it is utterly unrealistic to try to teach such material to college freshmen. Wouldn't that be an easy way out? You just postulate that this would be far too difficult. But that kite won't fly either for the postulate has been proven wrong: since the early 80's, such an introductory programming course has successfully been given to hundreds of college freshmen each year. [Because, in my experience, saying this once does not suffice, the previous sentence should be repeated at least another two times.] So, let us try again.

Reluctantly admitting that it could perhaps be taught to sufficiently docile students, you yet reject my proposal because such a course would deviate so much from what 18-year old students are used to and expect that inflicting it upon them would be an act of educational irresponsibility: it would only frustrate the students. Needless to say, that kite won't fly either. It is true that the student that has never manipulated uninterpreted formulae quickly realizes that he is confronted with something totally unlike anything he has ever seen before. But fortunately, the rules of manipulation are in this case so few and simple that very soon thereafter he makes the exciting discovery that he is beginning to master the use of a tool that, in all its simplicity, gives him a power that far surpasses his wildest dreams.

Teaching to unsuspecting youngsters the effective use of formal methods is one of the joys of life because it is so extremely rewarding. Within a few months, they find their way in a new world with a justified degree of confidence that is radically novel for them; within a few months, their concept of intellectual culture has acquired a radically novel dimension. To my taste and style, that is what education is about. Universities should not be afraid of teaching radical novelties; on the contrary, it is their calling to welcome the opportunity to do so. Their willingness to do so is our main safeguard against dictatorships, be they of the proletariat, of the scientific establishment, or of the corporate elite.

Austin, 2 December 1988

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Javier Smaldone.
Revised Tue, 12 May 2009.

EWD 1039

Seemingly on a problem transmitted by Bengt Jonsson

The other Tuesday, at the end of his lecture, Bengt Jonsson (Swedish Institute for Computer Science/University of Uppsala) left the audience with the following problem. Consider the 8 by 8 square; can it be covered by 21 bars of 3 by 1 and 1 little square of 1 by 1?

[In the following, I shall try to ignore that this problem is a variation of a problem I know very well. If the reader knows so too, I ask him to follow my example.]

My first proposal is not to try at this stage to cover the big square by the 22 pieces, and this for the following reason: if the answer is "Yes”, we could be fortunate and establish this by hitting upon a solution of our jig-saw puzzle; if, however, the answer is “No”, establishing it by such an exhaustive search is prohibitively expensive.

My second proposal is therefore to look whether we can reduce the search space effectively by means of a (preferably simple) argument. Note that we can do so without committing ourselves to whether we are heading for “Yes” or “No”: our argument could be so effective in ruling out all sorts of covering efforts that it becomes feasible to try the remaining —possible zero— efforts.

Reducing the search space means being able to characterize barren placements, i.e. a placement of part of the pieces that cannot be extended to a solution of the jig-saw puzzle by placing the remaining pieces in the as yet uncovered part of the 8 by 8 square.

Remark   If 3 × 21 + 1 were different from 8 × 8, the placement of no pieces at all would be barren and the answer would be “No”, but you have probably already verified that, regrettably, these two expressions have the same value (End of Remark.)

Here a general remark about the effectiveness of barren placements is in order. Consider a barren placement that leaves so little of the big square uncovered that it cannot be extended with a single piece; such a barren placement is minimally effective in the sense that rules out itself only. Since extensions of barren placements are barren as well, a barren placement is the more effective, the more extensions it permits. For reasons of effectiveness, we therefore favor barren placements of as few pieces as possible. The placement of no pieces at all —see above Remark— would be the most effective barren placement for all, but we don't have an argument that it is barren (and perhaps it isn't).

My third proposal is therefore to look for barren placements of a single piece. Which piece? The single little square, of course. Had we chosen a bar, then we would need an argument whether the remaining area could be covered by 20 bars and the little square, a question so similar to the original one that it is hardly a conceptual simplification. If we choose as candidate for a barren placement a placement of the single little square, however, we are faced with the question whether the remaining area can be covered with 21 bars; the homogeneity of “bars only” might create the opportunity for an elegant argument.

Our attention having thus been directed to the remaining area to be covered by the 21 bars, I could raise the question “What can we say about areas covered by 21 bars?”, but in explorations like these, 21 is a very large integer, which would be reached most nicely by an inductive argument of some sort. As we are still hoping for a simple argument, my fourth proposal is to look for what we can say about areas covered by bars only.

The obvious remark is that, each bar being 3 by 1, the total number of squares covered by a bunch of bars is a multiple of 3, but —see above Remark— we have already established that this conclusion is too weak to be helpful. It takes into account the area of a bar. but not its shape, i.e. not the fact that it covers three adjacent squares in a line.

So, more precisely, what can we say about areas covered by bars only, taking into account that each bar covers three adjacent squares in a line? Using programmer’s jargon (to capture an inductive argument): while placing the bars one by one, can we find a stronger invariant than just that the squares covered can be partitioned into three partitions of the same size? Yes, we can, if we can characterize such partitions independently of the placement of the bars, more precisely, if we succeed in partitioning the 64 little squares of the 8 by 8 square, say by painting each of them red, white, or blue, in such a way that, by virtue of its shape, each bar covers one little square of each colour. Areas covered by bars only then comprise equal numbers of squares of each colour. (The decision to try to partition the 64 little squares represents The Great Leap Forward.)

It is possible to colour the 64 squares so that each bar covers each colour once? A little reflection shows that for the 3 squares closest to the bottom-left corner, there are, but for the renaming of colours, essentially only two possibilities

A little more reflection shows that each of these two patterns admits a unique extension with monochrome lines parallel to a diagonal: starting from pattern A this runs from top-left to bottom-right, from pattern B from top-right to bottom left. I have chosen the colours in such a way that in each case #r=21, #w=22, #b=21. These numbers tell us that the single little square in a position that is red or blue in at least one of the two colourings is a barren placement. To put it positively: we need investigate those placements only in which the position of the single square is white in both colourings. Apart from symmetry, that position is unique:

We still have not found our answer yet. Since “No” would, again, need an argument, whereas “Yes” can be established by a witness, I opt for the latter option, just hoping that the prescribed position of the single little square gives me enough guidance.

By surrounding the prescribed position by a 5 by 5 square I partitioned the remaining area in a way as symmetric as possible;

moreover, 8-5=3, so that covering II presents no problem. The effort of covering I invites us to maintain its cyclic symmetry:

So the answer to Jonsson's question is “Yes”.

Remark   As the reader may have noticed, there was no reason to distinguish between red and blue. I could have rushed ahead, asking “Can we colour 22 squares white and 42 black so that each bar covers exactly one white square?” I preferred not to do so. (End of Remark.)

*         *         *

The problem I alluded to in the beginning is the (well-known) demonstration that the truncated chessboard

cannot be covered by 31 dominos, the two fields removed having the same colour. For anyone knowing that solution it is hard not to use it as a source of inspiration when faced with Jonsson’s problem. Those familiar with chessboard/domino problems might even consider Jonsson’s problem too trivial to devote a technical note to. If so, they have missed my point: this note is not about Jonsson’s problem, but about problem solving. I have tried to remove from the development as many rabbits as possible. With the exception of The Great Leap Forward, I think I have been successful in doing so. I may have another go at that last rabbit by the time I can be more explicit about the structure and role of counting arguments. They are general enough to deserve our attention.

Austin, 22 Januari 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1041

By way of introduction

Because most of this introduction is non-technical and yet I want you to believe me, I feel compelled to offer you my credentials. I have now been employed for 37 years, 30% at a Government-sponsored Research Institute, 30% at a computer manufacturer, and 40% at Universities, and most of this at both sides of the Atlantic Ocean. I want you to be convinced that I know what I am talking about.

If we want to understand the world around us, we must be willing to face the facts, even facts we usually don’t talk about because we have been educated to be a little bit ashamed of them. Here is one such fact:

Science is hated because its mastery requires too much hard work, and, by the same token, its practitioners, the scientists, are hated because of their power they derive from it.

Let me repeat this, so as to help it to sink in:

Science is hated because its mastery requires too much hard work, and, by the same token, its practitioners, the scientists, are hated because of their power they derive from it.

I should repeat it a third time because whatever I say three times is true. Deem that done.

From the above, please don’t conclude that I am bitter, for I am not; I am just realistic: destroying scientists and their work is a time-honoured tradition. Archemedes was murdered by the Romans, Hypatia was murdered by the Christians, the Moslims burned down the library of Alexandria, and in 1794, Lavoisier lost his head on the guillotine because of the verdict of the populace that the French Revolution had no use for scientists. (Less than a decade later, France had its next dictator, but the rabble never made the connection.)

For reasons I don’t quite understand —partly, probably lack of instrumentation— the science of chemistry was very slow to emerge. So slow, as a matter of fact, that in the first decade of this century, Albert Einstein developed the theory of Brownian motion because of the large number of chemists that still refused to believe in the atomicity of matter. Because Brownian motion can be seen through the microscope and “seeing is believing”, Einstein naively thought that the atomistic explanation of the quantitative, observable aspects of the phenomenon would be convincing. This was very naïve —but don’t blame Einstein, who was very young— for he only convinced the already converted; the stubborn chemists found it much easier to declare Einstein’s theory of Brownian motion to be “too mathematical”.

When the science of chemistry eventually emerged, alchemy had already all but disappeared. Chemically speaking, there has been an intellectual interregnum, but I invite you to join me for a short while in the thought experiment of envisaging chemistry with alchemy still in existence. Needless to say, almost all the funding goes to the alchemists, who, in their effort to make gold from cheap base materials, at least attack a problem of the highest social relevance, viz. enable the government to finance its wars without inflicting poverty on the people. The chemists are derided because none of their work has contributed anything to the central problem of gold-making. When chemistry then makes assumptions about matter that would exclude gold-making, it is accused of being counterproductive, demoralizing, and harmful to the national interest. By the time chemistry accurately predicts the failure of alchemy’s next attempt, derision turns into open hostility, and, accused of wasting the taxpayer’s money, several state universities are forced to close down their chemistry departments. Well, I think that that is enough for our thought experiment: phantasy has already come too close to reality.

Well, we all know what happened. Chemistry is accepted as a science: we hate it for its pollution and our dependency on its products, but we no longer blame it for not trying to make gold. Medicine has been accepted as a science: we hate it for the overpopulation and the soaring medical bill but no longer blame it for not producing the Elixir that gives eternal youth. Astronomy has been accepted as a science; we hate it for removing the earth from the center of the universe but no longer blame it for not realizing the astrologer’s dream of accurate prediction of the future. They are accepted as sciences; at the same time, the flourishing business in Healing Gems and Crystals, the horoscopes in otherwise respectable magazines, and governments relying on astrologers are a healthy reminder that Science as such remains rejected and that the old dreams linger on. Finally, one general remark about how sciences emerge: sciences become respectable by confining themselves to the feasible and successful by allowing themselves to be opportunity-driven rather than mission-oriented. (This, by the way, is why managers hate successful science: because it is not mission-oriented, they cannot manage it.)

Let us now turn our attention to computing science. It is hated, of course, like any other science. In order to understand the specific distaste it evokes, and along with it all the pressures exerted on it, we should be aware of all the unrealistic dreams it failed to realize, for, unrealistic as they might be, the dreams linger on. The dreams have been so many, that I must restrict myself to the major ones.

Surely, our computers would unscramble all the secret code of all our enemies and guide our missiles with unfailing precision right on their targets. Robots would take over the tedium of production, guaranteeing a positive balance of trade for all nations. Office automation would multiply the productivity of the white-collar worker, information systems would enable management to avoid waste and to make the right strategic decisions, and finally, the giant brains would not only relieve us from the tedium but also from the obligation to think about hard problems and from the painful responsibility to take difficult decisions. In short: computers were tolerated because they promised a well protected and prosperous paradise for the lazy, the incompetent, and the cowardly.

I cannot repeat often enough that, unrealistic as they are, these dreams continue to be dreamt. Their lure is too strong. For instance, the well-documented decline of productivity of the American white-collar worker has convincingly been linked to over-automation of the American office, but the “negative” outcome of this study has been totally ignored, in fact so much that many people involved in computing cannot believe it.

So much for the unrealistic dreams. But even the majority of at face-value feasible projects went awry. As said before, sciences become respectable by confining themselves to the feasible, and that is precisely what computing science did: it focussed its attention on the intellectual challenge of how to specify and design reliable software systems of great sophistication. In doing so, it came to a few unescapable conclusions, all clarifying and inspiring for the computing scientists involved, and each of them unacceptable to the world at large, that refused to part from its cherished dreams.

For instance, an early conclusion was that the only effective way of winning the battle against unmastered complexity requires that one prevents the latter from entering the design in the first place, or, in more technical terms: mathematical elegance is not a dispensable luxury but a factor that decides between success and failure.

Mathematical elegance, conceptual simplicity, and their companion, brevity of an unambiguous reference manual, are a condition sine qua non for any product reliable enough to attain stability.

Needless to say, this sober message is unacceptable. Simplicity requires hard work to be obtained and education for its appreciation, and complexity sells much better. I quickly learned this about twenty years ago when I presented orderly program design techniques for the first time in a foreign country. My audience was the personnel of a software house and, in my innocence, I expected for economic reasons this audience to be highly receptive for techniques for making flawless software. I gave a beautiful lecture, which fell flat on its face. The managers were horrified at the suggestion that flawless software should be delivered since company derived its stability from the subsequent maintenance contracts. The programmers were horrified too: they derived their intellectual excitement from not quite understanding what they were doing and their professional satisfaction from finding weird bugs they had first introduced in their daring irresponsibility. Teaching the competence to program boils down to the training of misfits.

A more technical finding of computing science was that the reliable design of sophisticated digital systems requires much more formal manipulation than any design task faced before. Moreover, the job requires a degree of formalization in comparison to which classical mathematical reasoning becomes slipshod handwaving. Unavoidably, programming is becoming applied logic, but this time applied on a scale that was never envisaged by the logicians. So, computing science found itself faced with the task of figuring out how to apply logic effectively on an unprecedented scale. By now, the competent computing scientist has greatly improved his insight in how to exploit his powers of abstraction for the effective disentanglement of his formal derivations and knows how to design his notations so that his formulae are geared to his manipulative needs and he can let the symbols do the work.

All this is very encouraging and inspiring for the computing scientists involved, but for the world-at-large the message that competent programming is —and unavoidably has to be— VLSAL ( = Very Large-Scale Application of Logic) is unpalatable. So what does the world-at-large do? Quite predictably, it tries to ignore the message, and each time the message raises its ugly head it desperately tries to argue that the message is false or irrelevant. It is really quite pathetic, but any argument, no matter how crooked, that we can do without VLSAL is so welcome that any snake oil merchant in programming methodology finds a ready market for his wares, no matter how ridiculous.

I am not exaggerating. Let me give you a few examples of how expert we have become in sweeping the programming problem under the rug.

Just when the computing science community has agreed that simplicity is an essential ingredient of reliability, the DoD adopts Ada! What more can I say? When the late Andrei Ershov from Novosibirsk asked my opinion about Ada, I told him that I shuddered at the thought that Western security would depend on it and that I would feel much better if I knew that the Red Army had adopted Ada as well. Andrei smiled and said “Don’t worry.”

Our own ACM is also great at skirting the programming problem. Did you ever notice that there is no Special Interest Group on programming? Did you ever notice that the ACM’s youngest journal , TOPLAS, is not on programming but on Programming Languages and Systems (whatever the latter may be)? Did you notice that the report on the CS curriculum that was recently published in the CACM carefully spent more space to arguing that the importance of programming should not be overemphasized than to arguing the need to include logic? Such a report, written by many people is, of course, a political compromise, but this compromise was very revealing. Also a bit sickening.

Another revealing phenomenon was the welcome with which the paper was greeted in which Lipton, Perlis and De Millo tried to argue why proving the correctness of programs was a misguided effort. Thank God that programming had nothing to do with Mathematics! In their eagerness to believe these authors, people failed to notice that the argument was based on the consensus model for informal classical mathematics, i.e. the way of doing mathematics that computing science had already identified as inadequate. Program derivation is not a social process but a formal calculation. The paper was nonsensical.

A very different way of arguing the irrelevance of striving for flawless programs I learned the other month from Jim Gray. Though he addressed an academic audience, he did not give a lecture but a sales talk for “fault tolerance”. Well that need not deter us: their unashamed appeal to our base instincts makes sales talks at least as interesting as the average lecture. His great theme was that software correctness did not matter at all — and I must confess that this idea seemed very attractive to quite a number of our students. His first argument was a familiar one: the fact that there is at least one known bug for every thousand lines of its software did not bother IBM at all. Now, firstly, this is a lie for the company is worried by the run-away complexity of its software and the ever more daunting task of more or less “maintaining” that software. Secondly, I can recommend to no one to adopt IBM’s quality standards as his own. Gray’s second argument was new for me: most software errors were soft. By this he meant that if something did not work as it should, you could either avoid using it or try again, for if malfunctioning was due to an unproperly resolved race condition, the error may not show up the second time. Here the answer is that the theory of how to design systems without race conditions is well-known and that it is much more efficient —and cheaper!— to apply it than to ignore it. To Gray’s advantage I should add that he was quite honest about his position: his only concern was that his systems remained “working”, and whether the results they then produced were any good was not his department. As long as your stuff was better than what an army of COBOL programmers would build on top of it, you were okay. (By the time he made this remark I felt free to leave the lecture hall.)

As final example of skirting the programming issue I mention “software engineering”, the IPSE’s, the ASPE’s, the FRIPSE’s and the GRIPSE’s and all further animation tools you can think of. They come from a world that has accepted its charter “How to program if you cannot.”. The best of these efforts just confuse composing with the physical act of writing the score, others are foolish at best, and some are criminal.

So much for the world in which we are supposed to educate young people in computing.

*                  *
*

How well did our departments of computing science educate? As I said before, the training of the competence to program boils down to the training of misfits, and under the circumstances sketched above it is only to be expected that our departments of computing science did not educate too well. Regrettably, I feel compelled to put it much stronger: they failed miserably in their educational task by not taking the intellectual challenge of programming seriously and by not changing the layman’s view of programming, but by adopting it instead.

That layman’s view was driven home to me almost a decade ago when I gave a one-week course on programming methodology. I had in my audience the manager of software at a huge bank and I knew he was in trouble. After three days he told me that, as far as he was concerned, I was teaching useless stuff, though he fully agreed that if their software had been developed in the way shown, most of the problems would not have emerged. Yet he rejected my recommendations because they would have required him to train his programmers better and he did not dare to do so for fear of losing them to the competition. Today’s manager is so horrified at the suggestion of depending on the competence of his programmers that it is psychologically impossible for him to admit that programming should be regard as a high-technology activity, as an area par excellence for the application of the most effective techniques of scientific thought. His conclusion is that programming does not require any sophistication because it should not, and this is the attitude that is faithfully reflected in many computing science curricula. Introducing programming courses have, in fact, become a prime target of curriculum infantilization and, instead of teaching the Very Large Scale Application of Logic, they give the student no more than the most primitive operational arguments for thinking about his programs. No wonder that the “Laboratory” in which the student can “test” his programs becomes an essential ingredient of the educational machinery. No wonder that such introductory courses —insipid, inadequate, obsolete, and time-consuming— “turn away the best students, who want a greater challenge”. [0]

Dealing in our curriculum with programming as a scientific challenge of high calibre is easier said than done: besides the resistance in the rest of the world, you would have to overcome the resistance in your own department.

Firstly, the average computing science faculty member considers the problem of programming decently far below his dignity, while at the same time he has not the foggiest notion of how to do it. Again I am not exaggerating: I have taken extensive experiments with CS faculty members from all over the world, and the vast majority of them —I mean about 95 % of them— cannot program a Binary Search. It is a very shocking percentage, but you can take my word for it. This wide-spread incompetence is, of course, a severe problem for educating students may be hard, but, as we all know, educating faculty members is near to impossible.

A second source of resistance within your department will be formed by those colleagues that have unwisely based their research efforts on the assumed dogma that competent programming is an illusion. Really teaching how to program would dissolve their research topic and the significance of their expertise would evaporate. You cannot expect them to take kindly to that.

[0]  | "Computing as a Discipline", P.J. Denning et al., CACM, Jan. 1989 (32, 1) pp. 9-23

Austin, 12 February 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Tue, 12 May 2009

EWD1041a

Factorizing the factorial

Let n be a natural number; let p be a prime;

m = the exponent of p in the prime factorization of n! ;

s = the sum of the (p-ary) digits of n’s representation in base p.

Theorem      m = ( n - s ) / ( p - 1 )

Because of the usual recursive definition of n!, an inductive proof over n seems indicated. Since for n = 0, m = 0 ∧ s = 0, the theorem holds for n = 0.

Consider now the transition from n to n + 1; let k be the exponent of p in the prime factorization of n + 1.

Because ( n + 1 )! = ( n + 1 ) ∙ n! and p is prime

(0)      Δ m = k .

Because ( n + 1 ) - n = 1

(1)      Δ n = 1 .

Because the p-ary representation of ( n + 1 ) ends on exactly k zeros

(2)      Δ s = 1 - k∙( p - 1 )

Combining (1) and (2) yields

(3)      Δ (( n - s ) / ( p - 1 )) = k .

Combining (0) and (3) yields the induction step, and thus the proof is completed.

Edsger W.Dijkstra                     

transcribed by Jose Alejandro Ruiz Delgado
revised Sun, 31 Aug 2008

EWD 1043

A few comments on "Computing as a Discipline"

The following remarks have been triggered by the report "Computing as a Discipline" by Peter J. Denning (Chairman), Douglas E. Comer, David Gries, Michael C. Mulder, Allen Tucker, A. Joe Turner, and Paul R. Young (see CACM, Jan, 1989, Vol. 32, No 1, pp. 9-23). Criticisms from my side should not be interpreted as my judgement that, under the circumstances, the authors could have done much better: they had to please each other and there was politically no point in departing too far from the status quo.

I like its title, both for containing the word "computing" rather than "computer" and for containing the word "discipline" (which is dear to my heart). Regrettably, its title is the part I like best.

My doubts already start at the first question it poses: "Is computer science a science?" From my strictly personal point of view, that question has been answered a long time ago in the following sense: I have now been involved for more than 37 years, at least 80% of my professional activities were related to automatic computing, and I have never doubted that I was a scientist. So, what's the fuss about? For me, the fuss can mean only one thing, viz. that in the past we have been too liberal in applying the name "computer science": under its auspices we have activities that are scientifically not up to par.

Such a conclusion, of course, invites the proposal to prune the junk away; personally, I would whole-heartedly support such a proposal, but —regrettably and understandably— the task force did not make it. It came, instead, with a picture in which computer science is mathematics, natural science, and engineering, all rolled into one.

But even when I take into account that all important words (such as mathematics, natural science, engineering, university, and education) subtly change their meaning when one crosses an ocean, I find their synthesis most unconvincing. They give paradigms for work in mathematics, in natural science, and in engineering, but I don't recognize them at all! That is, even if we take the width of oceans into account, a bit alarming, for I worked in all three areas. (For your information: my degree is in theoretical physics, the degree of my students in Eindhoven was that of "mathematical engineer".)

At least as revealing as the absurdity of the three four-step paradigms are the sentences by which they are followed: each of them, the mathematician, the scientist, and the engineer, "expects to iterate these steps". Not necessarily so! There is no reason why one should not try and later learn to expect to be almost always right the first time. It is van Beethoven, who was a very iterative, almost painful composer, versus Handel, Haydn, Mozart & Schubert. I encountered the cult of iterative design for the first time when I came in contact with Anglo-Saxon colleagues; later I learned how deeply ingrained it is in the Anglo-Saxon character: specifically in the Anglo-Saxon world, the suggestion to take not van Beethoven but rather the other four as you role model has, over and over again, been rejected as an indecently presumptuous proposal. In short: the picture the task force presents is parochial and distorted.

Consequently, their plea for an "experimental" component of computing science remained, as far as I am concerned, unconvincing. Nor did they succeed in making me believe in the desirability of computing laboratories for educational purposes, despite such sentences as "[Laboratories] should provide concrete experiences that help students understand abstract concepts." Everybody knows that programming is most easily and effectively taught to students that have never touched a machine and are not given access to a computer as long as the course lasts. The explanation is simple: for them it is much easier to ignore that a program admits the interpretation of executable code and thus to part from operational reasoning. And as far as "understanding abstract concepts" is concerned, you should help your students to understand them in their own right, and not in terms of a (computational) model a laboratory confronts the students with. Because departmental investments act as status symbol, it is probably politically suicidal to suggest that most educational equipment be kicked out; I guess the task force had no choice but to concoct a rationale for the goodies.

For the sake of completeness I mention that the report is rather silent on the lack of coherence displayed today: cognitive psychology has as much to do with formal logic as bacteriology with the study of music.

They are right in decrying the current level of introductory programming courses that turn away the best students, who want a greater challenge. They include, however, in their proposal "walk-through" and "hand simulation"; this inclusion hardly suggests that the programming challenge be faced more seriously.

*                *
*

In one respect, I think, the report is fundamentally flawed. They present computing as the synthesizing continuation of established disciplines such as mathematics, natural sciences, and engineering, as the result of a smooth evolution. They stress computing's structural similarity to those older disciplines.

I think that they are profoundly mistaken, that the automatic computer embodies such a radical novelty that the analogies between computing science and the older disciplines are too shallow to be of any help. It is great to be in computing science, and not because it is just like mathematics, natural science, and engineering, but because it is radically different. It is so fascinating because the computer's existence has faced us with an intellectual challenge without even the vaguest precedent in our cultural history. None of the scope of this challenge is reflected in the report, and that is what makes the report so bland. But, please, don't blame the authors. You cannot ask a task force to spell out a truth that is too disturbing.

Austin, 13 February 1989                 

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas as Austin
Austin, TX 78712-1188

Transcribed by Alan Arvesen.
Revised Tue, 12 May 2009.

EWD 1044

To hell with “meaningful identifiers”!

This is about the construction of a bag of natural numbers with given sum and maximal product. In the following, a maximal bag means a bag that realizes for the sum of its content the maximum value of the product; for any given sum at least one maximal bag exists because the number of bags with given sum is finite.

The first argument begins by characterizing bags that are not maximal. All characterizations follow the same pattern: non-maximality is demonstrated by showing how to construct a bag with the same sum and a larger product.

Lemma 0 A bag containing 0 is not maximal

Proof Removing all zeros from the bag increases the product. (End of Proof.)

Lemma 1 A bag containing 1 and at least one further element is not maximal.

Proof Replacing the 1 and another element by their sum increases the product. (End of Proof.)

Corollary For a sum ≥ 2, a bag containing a 1 is not maximal.

Lemma 2 For x > 4, a bag containing x is not maximal.

Proof We analyze the condition that splitting up x into 2 and x – 2 increases the product

|  | 2∙(x – 2) > x
= |  | 2∙x – 4 > x
= |  | x > 4

(End of Proof.)

For sums 0 and 1 the problem has been settled —{} and {1} respectively—; for larger sums the search is restricted by the above to bags built from 2's, 3's, and 4's. One way to proceed is to remark that, since 2 + 2 = 4 and 2 * 2 = 4, bags containing a 4 are disposable. Narrowed down to bags built from 2's and 3's, the observations 2 + 2 + 2 = 3 + 3 and 2 * 2 * 2 < 3 * 3 settle the problem.

The ruling out of bags with elements > 4, followed by the disposing of bags with a 4, makes it very tempting to combine those argument and state

(0)   “For x ≥ 4, a bag containing x is disposable”

Proof We analyze the condition that splitting x up into 2 and x – 2 does not decrease the product

|  | 2∙(x – 2) ≥ x
= |  | 2∙x – 4 ≥ x
= |  | x ≥ 4

(End of Proof.)

Neat as this may seem, the argument is now —as Paul Pritchard made me see— fallacious, as we can see from the following simplified example.

Let us consider bags whose elements add up to 2∙N.

•     Bags containing even elements are disposable.

Proof   Each even element can be written as the sum of two odd values. (End of Proof.)

•     Bags containing odd elements are disposable.

Proof Since 2∙N is even, the number of odd elements is even; hence the odd elements can be eliminated by replacing pairs of them by their sum. (End of Proof.)

And now the conclusion is, of course, that we can restrict the search space to bags of natural numbers that are neither even nor odd, i.e. to the empty bag!

Back to our problem of maximizing the product. It seems instructive to analyze what went wrong when we introduced our disposable bags. To simplify the discussion I restrict myself to bags of “plurals” with a “plural” sum. (“plural” means “integer and ≥ 2”; like “integer” and “natural” it is both a noun and an adjective.)

The trouble has been invited by the fact that we did not give a precise definition of the notion “disposable.” Reformulating (0) for plurals and without the adjective “disposable” yields, for instance,

(1)   For every bag of plurals there exists a bag of plurals <4, with the same sum and at least the same product.

There are two ways of looking at this theorem: it is a theorem about all bags of plurals to be proved by mathematical induction, or it is an existence theorem that we can demonstrate by developing a terminating algorithm that constructs a witness. Both views boil down to the same thing as both require a well-founded order on finite bags.

[When we characterize each bag by its —natural— frequency function f: f.x is the number of occurrences of x in the bag, the well-founded order is the lexical order on the sequences f.x in the order of decreasing x. Splitting up x into x – 2 and 2 corresponds to

f.x, f.(x – 2), f.2    :=    f.x –1, f.(x – 2) + 1, f.2 + 1

which represents a lexical decrease of the sequence. Or simpler: sum – #elements in the bag.]

Compared to (1), the weaker Lemma 2

(2)   For every bag of plurals, there exists a bag of plurals ≤ 4 with the same sum and at least the same product.

does not require mathematical induction for its proof. The existence of maximal bags not being in doubt, it suffices to demonstrate that a bag with a plural > 4 is not maximal.

With the replacement of Lemma 2 and a separate treatment of 4's in the bag by (1), we have eliminated a case analysis at the price of a proof by mathematical induction. I consider that price rather heavy.

The clearest moral of the above is never to introduce terms (like “disposable”) on the basis of “you know I mean, don't you?” To hell with the “meaningful identifiers!” The havoc they create is not confined to programming but extends over all of mathematics.

Austin, 17 February 1989

prof. dr. Edsger W Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Alan Arvesen
revised 10-Apr-2016

EWD1046

A tale of two winters

I had to go to Louisville (pronounced "Louvel"), Kentucky in order to deliver on Thursday morning the opening keynote address for the three-day SIGCSE conference of 1989. I was obliged to do so in return for their Award for Outstanding Contributions to Computer Science Education. That Thursday was also the last day of the Computer Science Conference, which had started that Monday. This arrangement enabled me to address the combined participants of both conferences. (It turned out that I would have an audience of well over 1500, probably the largest audience I ever addressed; the PA system was up to it.) The Turing Award Lecture was late Wednesday afternoon, so that it could be attended by the SIGCSE participants that had arrived early enough; my impression was that quite a few of them had done so.

Ria and I left sunny Austin on Tuesday, 18:15 (with Northwest Airlines via Memphis); we returned in sunny Austin on Friday 12:02 (with American Airlines via Dallas.) As far as transport was concerned, the flights were perfect: we flew on time, caught out connections and did not lose our luggage; moreover, none of the planes lost part of its fuselage. The food served need not be mentioned. The four cab rides to and from the airports were also perfect. In short: we travelled smoothly. Whereas the taxis were cheap —at least by Dutch standards: a dollar the mile—, the flights were outrageously expensive: they did cost more than our recent return tickets from Austin to Amsterdam. (My ticket to Louisville will be paid by SIGCSE; 80% of Ria's ticket I can pay from my prize.)

Fortunately, one of my students, who had lived in Louisville, had warned me that, in February, Kentucky could still be quite cold. So we arrived well-prepared. But it was grim! The distance between the Galt House, where we slept, and the conference centre was only two blocks, but each time we gratefully used the shuttle bus. The busses came by once every four minutes, but one quickly learned to wait inside the building for the arrival of the next bus. Ria's original intention had been to see something of the town, its exhibitions and its craft shops; it was too cold, and she stayed with me instead.

For a variety of reasons, we slept very little in Louisville. On Wednesday morning, we observed the congestion at the "River Grill" where the Galt House served breakfast. On Thursday morning I had to perform, on Friday morning we had to catch a nine-o'clock flight, so those mornings we rose shortly after 6:00 (which is 5:00 Texas time). The night before my performance I hardly slept. I was cold and shivering. I put it all down to nerves, until the curtains began to move and, a moment later, the wind blew open one of the windows: they had not been properly locked! Moreover I suspected the Galt House of conducting a controlled experiment in order to determine whether guests really want to have a say about the temperature in their rooms, and of having equipped all the even-numbered rooms with a genuine thermostat and all others with a placebo. Needless to say, our room number was odd: we never observed any effect of our temperature settings! (Honesty compels to add that, 15 minutes before our departure, we discovered that we had overlooked an On/Off switch underneath the thermostat; it was in the Off position.)

On Wednesday morning we attended (for our instruction) a joint presentation by funding agencies (NSF, DARPA, ONR, NASA, etc.) which described their views of their support of computer science. It was instructive, but not reassuring. My impression was that these institutions rather strengthen than try to weaken the phenomenon of "fads in computer science". Moreover, they did not seem to make a sufficiently clear distinction between computer usage and computing science, and seemed unaware of the fact that the latter is hardly served by funds earmarked for equipment (Money earmarked for ridiculing the way in which physicists think they can become instant experts in computing science by getting a supercomputer would be better spent.)

Wednesday afternoon we attended a session chaired by David Gries. As an outcome of the Snowbird conferences, the Ph.D.-granting departments of computing science have decided to set up a representation in Washington. (This primarily in reaction to the fact that there is no body representing the American computing scientists; ACM is a professional society, not a scientific one.) The purpose of the Wednesday afternoon meeting seemed to be to reassure the non-Ph.D.-granting departments that they would not be left out. I did not really understand what was going on. The latter outnumber the former by a factor 8; most of them must almost exclusively be engaged in vocational training and representation in Washington should represent the science and the scientists. Yet, David repeatedly asked suggestions from the floor for ways in which all those other departments could be "represented" as well. That evening we had dinner with David but talked about other matters.

Then we went to the Conference Center to attend the Awards Ceremony and, primarily, to listen to the Turing Lecture, delivered by Ivan Sutherland, who received the Turing Award for his pioneering contributions to computer graphics. Though I could easily understand the motivations for the choice, I had my doubts about it: computer graphics lacks the depth needed to be considered a part of "the heart of the matter". The lecture was not on computer graphics but on "micropipelines" —a special class of self-timed circuits— and was disappointing. The topic (of how to make a nice usage of the two-phase protocol in the context of self-timed circuits) was rather narrow, the talk was very technical, but at the same time detailed and superficial, he showed pictures of circuits most of the time and the way in which he tried to explain them was hopelessly old-fashioned and operational. Ria had difficulty in staying awake; quite a few people left the hall before he had finished - either because it was too much, or because they had expected more, I don't know. Furthermore I advise the next Turing lecturer not to show irrelevant pictures of his grandchildren. Apart from such blemishes, the whole performance was in good taste; his diction was admirably clear and his English was often a pleasure to listen to.

I had to perform the next morning at the ungodly hour of 8:30. At 7:54, while still in the hotel, I fortunately discovered that the presentation of the award would begin at 8:15. At the queue at the cloakroom, we were given priority and thus we just made it. My text "On the cruelty of really teaching computing science" had been handed out. I dislike delivering a talk that my audience can read at the same time —it is just as if you are addressing illiterates—, so I replaced more than 60% of my original text by different material. I made some new enemies, but some new friends too.

While, afterwards, I was surrounded by people that wanted to voice their reaction or ask me for clarification, Ria discovered that three graduate students from Harvard would like to speak to me and hadn't had breakfast yet. So we joined them in a nearby restaurant, where we drank coffee while they had their meal. We left them at 11:50, thinking that, perhaps, we had had too much coffee, but it must have been a very weak brew for it did not prevent us from taking a nap of several hours in the afternoon. The evening we had a relaxed dinner with the officers of SIGCSE: reasonable food in most pleasant company. The next morning we flew home; that afternoon we took another nap, but this time in our own bed. And then we were back to normal.

*                     *
*

One week later, Friday 3 March 1989, I had to perform at Ada, Oklahoma. There, Bill K. Walker, the chairman of the department of computer science of East Central University, had invited me to address faculty members in the morning and students in the afternoon.

The distance from Austin to Ada being something like 360 miles, and Oklahoma being a beautiful state, we planned to combine this with a small camping trip; we thought about returning Sunday or, if the weather was very nice, on Monday. (I would pack my ink pot and enough blank paper.)

On Wednesday, our "Turing Machine" was packed but for the food, which Ria packed on Thursday morning while I gave my lecture at UT. (Ham Richards had given me a lift to UT.) At 11:00, when I had finished my lectures and left Taylor Hall, Ria was waiting there with our VW Westfalia, and five minutes later we were on IH35, heading North. It was a beautiful day, we drove in turns, and still before sunset we arrived in Ada, where Walker had offered us the hospitality of his home. His wife had prepared a nice (and welcome!) meal. We had had a long day and had a long day ahead of us; we went to bed on time and rose the next morning at 7:00. At 8:15 we were at the University, where I signed all sorts of papers and then prepared my 10 o'clock performance on "The mathematics of programming".

It had been widely publicized: there were at least 50 faculty members, some of whom had come from as far as Dallas. The morning session was quite animated. For the afternoon session we were joined by, say, a hundred students. It was held in a larger room with two temporary blackboards that were a bit small for the size of the room; the PA system —I am happy to say— was adequate. The afternoon was hard work: I faced all the problems of addressing a very mixed audience. I gave a formal derivation of a binary search, applying the rules I had first given. Most students having followed an introduction to programming via BASIC, they formed an audience that was very hard to work with. My title had been something like "Formal program derivation in action" and my impression was that I succeeded in getting the message across; again the discussion was quite lively. Afterwards I spoke for an hourlet with half a dozen of Walker's older students. Walkers's wife having gone off to Dallas, we had dinner in town, where we were joined by one of Walker's colleagues. The day ended with several hours of discussion in Walker's —very pleasant!— library; sitting at a table I showed to Walker's delight the construction of a number of very nice arguments. I felt satisfied by what I had done and, looking forward to our camping trip, we went to bed.

The next morning, a coldfront had passed and the temperature had dropped so low that we had to cancel our camping trip and headed South, homewards. But the roads got so icy that after 112 miles we did not dare to continue and were glad to find a room in the Gainesville Holiday Inn. We had seen enough cars in the ditch. That night, a second cold front came along, covering the inch of ice with half a dozen inches of snow! We had to stay another two days in the hotel. On Tuesday morning the sun was shining, the air temperature rose above freezing and we decided to try to continue our journey at 11:30. As we could see from our hotel window that IH35 was still all but blocked, we headed for the 82 to Sherman. Leaving the parking lot of the hotel was terrible, driving through Gainesville was bad, but, once we were on the 82, conditions became much better and early in the evening we were home.

Going from our room to the restaurant or back meant an outside work. These walks were most unpleasant and very dangerous; fortunately we could use a corridor so narrow that we could support ourselves at both walls. We managed never to fall. We admired the hotel staff: the whole organization could cope with this invasion of stranded passengers. After the rooms had filled up, people went to sleep on the ballroom floor. We enjoyed the luxury of a room, moreover a room with a table at which I could comfortably write; I had packed an inkpot and enough blank paper. We had a book with us, Ria had knitting materials with her and we played a few games of Scrabble (in English, but I had also packed a dictionary). We never discovered how to get up to date information on road conditions and that became a bit annoying; otherwise we had a quite pleasant confinement.

*                  *
*

On Friday afternoon I had explained that I had chose to derive a binary search because (i) everybody (thought he) knew the algorithm, and (ii) I knew that the vast majority —say 95%— of CS faculty was unable to write down the program. Despite that last warning, I received a week later a letter from a man who had been in my audience and felt that he could improve the efficiency of my program. Needless to say, his program was wrong!

Austin, 10 March 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas as Austin
Austin, TX 78712-1188, USA

Transcribed by Alan Arvesen
Last revised Tue, 12 May 2009

EWD 1049

A somewhat open letter to Uri Leron

Dear Colleague,

you end your letter of March 30, 1989, with:

“I finish with a puzzle, that somehow seems to me related to your Sylvester's theorem (EWD1016). Consider two finite, equinumerous sets of points in the plane. Assume there are no colinear triples. Show that there exists a pairing (bijective correspondence) between the two sets, so that no two line segments connecting corresponding points intersect. (This theorem has a very short, elegant, “existential” proof that mathematicians love and, I suspect, you won’t.)”

The relation to Sylvester’s conjecture is quite close indeed: rephrased as a programming problem —“design an algorithm that constructs a pairing without intersecting segments”— it is solved by standard programming methodology. It is much simpler than Sylvester’s problem in the sense that, in refining the repeatable statement, it will turn out that there is no nondeterminism to be restricted; nor does it require the introduction of a variable (like E in EWD1016) to be incorporated in the invariant. In this case we have a variable q and the invariant P is

P:   q represents a pairing of the two sets

and the simplest program structure to be tried is

| “initialise q so as to establish P” {P}
;   | do there exists a pair of intersecting segments
|     → {?} “change q under invariance of P” {P}
| od

and now we have to prove termination of the algorithm. At the place marked with {?}, the only thing that can be asserted besides P are two intersecting segments, say A0-B0 and A1-B1

and no three points (of these four) are colinear. This information allows only one way of changing q under invariance of P: “flip” the pairs as indicated by the dotted segments

In order to prove termination we have to find a function on q that is decreased by such a flip, which replaces in q’s set of pairs/segments two of those by two others. If replacement of a few elements of an otherwise unknown set has to decrease the value of a function on the set, the latter had better be a monotonic function —such as the sum— of a function on the individual elements. (This rules out the number of segment intersections as choice for decreasing function, since that one is defined on the pairs of elements.) What is the simplest function of a pair/segment? The length of the segment, or any function thereof, but the identity function will do: the triangular inequality tells us that the sum of the lengths of the dotted segments is less than the sum of the lengths of the solid segments (the absence of collinear triples guaranteeing that the triangles involved are nondegenerate). The sum of the lengths of the segments is thus a function on q that meets all the requirements for our proof of termination.

*         *         *

My guess is that your “very short, elegant, “existential” proof that mathematicians love” begins like “Consider a pairing with minimal total length of the corresponding segments and assume now that two line segments intersect.” Etc. Such a presentation starts by pulling a gigantic rabbit out of a hat and, indeed, I don’t like that. The above program derivation shows that the choice of decreasing function (which embodies the proof’s invention) is all but forced.

*         *         *

In defence of vague notions such as “intuition” and “understanding” you wrote

“Formal, rigorous terminology are not nearly powerful enough to capture the richness and complexity of [human thought] processes.”.

I don’t and won’t deny you the right to be intrigued by what you perceive as the richness and complexity of human thought processes; it just so happens that I am more interested in increasing the power and simplicity of mathematics. The extent to which we live in different worlds is amply illustrated by the fact that you introduced your problem as “a puzzle”, something I would never have done. For the noun, the Concise Oxford Dictionary gives “problem or toy designed to test knowledge, ingenuity, or patience”, for the verb, Webster’s New Collegiate Dictionary gives “1: to be uncertain as to action or choice   2: to attempt a solution of a puzzle by guesswork or experiment”, for me reasons enough to avoid the term in this context. I definitely prefer a much more conscious approach to problem solving, avoiding trial and error as much as possible.

With my greetings and best wishes, and in gratitude for drawing my attention to your problem,

yours ever,

Edsger W.Dijkstra

Austin, 12 April 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
United States of America

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1050

On the design of a simple proof for Morley’s Theorem

The general opinion —with which I concur— is that Frank Morley’s Theorem about the angle trisectors of a triangle is a geometrical curiosity that is of historical interest at best. Independently of the (in)significance of the theorem proved by it, a proof may deserve our attention, for instance, by virtue of its structure, its simplicity, or its brevity. For the proof to be shown below, such a claim can be made: requiring no auxiliary lines or points, it is so simple that the theorem’s late discovery (1899) and the elapsed decade before the first proofs were published (1909) become the more striking. When I found this proof years ago, I was only too willing to ascribe that discovery to my great ingenuity and all that. The purpose of this note, however, is to show how, in the mean time, the art and science of proof design have advanced to a stage in which the design of such proofs almost become a routine exercise, requiring the usual care in arrangement and notation, but a minimum of invention.

Consider a plane figure —consisting of 6 distinct points and 12 straight line segments— of the following configuration —

Morley’s Theorem states that △XYZ is equilateral if, in this figure, the angles of △ABC are trisected.

Note that there are all sorts of nonredundant ways of defining that a triangle is equilateral, such as
(0)   its edges are of equal length
(1)   its angles are of equal size
(2)   it is isosceles, and its top angle equals 60�.

Definition (1) makes it clear that Morley’s Theorem can be formulated in terms of angles only, i.e. that in the above figure we can isolate size from shape.

Let us call the above configuration with the angles of △ABC trisected a Morley Figure. The simplest way of giving the shape of a Morley Figure independently of its size is to give the angles of △ABC. The simplest way of giving the size of a Morley Figure independently of its shape is to give the size of △XYZ.

This is a very nice disentanglement. To do justice to it, we propose to prove Morley’s Theorem by showing

For any triple (α,β,γ ) of positive angles whose sum equals 60� and for any equilateral triangle, one can erect on the three sides of the equilateral triangle triangles with top angles α, β, γ respectively so that the angles of the triangle formed by their tops are trisected.

The existence of these three triangles will be demonstrated by showing how to erect them. To this end we shall derive how to erect them. We exploit the cyclic symmetry (which we have been careful not to destroy) in order to avoid repetition, and focus our attention on side AB

We have marked with α ! and β ! the two target sizes, with α and β the two given sizes, and in view of the many alternative definitions we have left open how we are going to take into account that △XYZ is equilateral. In the above picture, we can draw our immediate conclusion from the target sizes: ∠AZB = 180�−α −β. Because the remainder of the picture has to be taken into account, we have to conclude that its full complement equals 180�+α +β. Now it stands to reason to draw XZ and YZ and to take into account that ∠XZY = 60�

From ∠XZY = 60� we thus conclude

            (α +β = the sum of the angles marked 1) ≡
            (120�+α +β = the sum of the angles marked 2)   .

A prescribed sum of two values gives a one-dimensional degree of freedom, for which we now have to find the most suitable parameterization. For the angles marked 1, the simplest parameterization is

        ,

since that translates our target into φ = 0. For reasons of symmetry it stands to reason to split 120�+α +β into 60�+α +ψ and 60�+α −ψ, but which is which? Because of α +β +γ=60�, we get the nicest fit if we allocate 60�+α +ψ in the triangle with top β. Thus we find ourselves contemplating the following parameterized figure:

Were we to complete it, we would find in clockwise direction 60�+α +ψ, 60�+β −ψ, 60�+γ +ψ, 60�+α −ψ, 60�+β +ψ, 60�+γ −ψ. Our remaining duty is to show that φ =0 follows.

Looking at our last diagram, we should realize that, so far, we have used from geometry no more than the fact that the angles of a triangle add up to 180�. We should be willing to use a little bit more so as to be able to exploit that the three triangles share two sides. Parameter φ (for which =0 has to be concluded) occurs only twice in the above picture, more precisely, in △AZB opposite to the shared sides. So we are looking for a fact from geometry that links angles of a triangle to their opposite sides. Here the Rule of Sines is supposed to come to the reader’s mind. Furthermore, of the fact that △XYZ is equilateral, so far we used only ∠XZY = 60� and thus can expect to have to use XZ = YZ.

So, let us start with the expression in φ that we can manipulate with the Rule of Sines

 sin(α +φ) 

sin(β −φ)

=   {Rule of Sines in △AZB}

 BZ 

AZ

=   {Rule of Sines in △BZX/△AZY so as to introduce XZ/YZ}

 sin(60�+γ −ψ) • XZ / sin(β ) 

sin(60�+γ +ψ) • YZ / sin(α)

=   {XZ=YZ}

 sin(60�+γ −ψ) � sin(α) 

sin(60�+γ +ψ) � sin(β ) |           ,

In summary

(3)     |  sin(α +φ)  |  =  |  sin(60�+γ −ψ)  |  •  |  sin(α) 
sin(β −φ) | sin(60�+γ +ψ) | sin(β )

Now the question has become: can we substitute in (3) such a value for ψ that φ =0 follows? Substituting into (3) φ :=0 yields

(4)     |  sin(60�+γ −ψ)  |   = 1         ,

sin(60�+β +ψ)

a solvable equation (e.g. ψ =0). Substituting (4) into (3), we get

       sin(β ) • sin(α +φ) = sin(α) • sin(β −φ)
=       {addition formula for sin}
       sin(β ) • (sin(α)•cos(φ) + cos(α)•sin(φ)) =
       sin(α) • (sin(β )•cos(φ) − cos(β )•sin(φ))
=       {algebra}
       (sin(β )•cos(α) + sin(α)•cos(β )) • sin(φ) = 0
=       {addition formula for sin}
       sin(α +β ) • sin(φ) = 0
=       {0 < α +β < 60�}
       sin(φ) = 0
=       { α +φ ≥ 0 ⇒ φ > −60�; β −φ ≥ 0 ⇒ 60� > φ }
       φ =0   ,

which concludes the proof. (To solve the last equation with the addition formula for the sine, rather than via a monotonicity argument, was suggested to me by Ambuj Kumar Singh.)

*         *         *

For a traditional presentation of a geometric proof, see [0] —Coxeter amazingly contrasts “a trigonometrical proof” with “an elementary proof”— ; for a compact presentation of the above trigonometrical proof, see [1] (where the proof is reduced to almost a one-liner). This note is a critical comment on such proof presentations, which are correct, but rather uninstructive.

Coxeter starts his proof with “Much trouble is experienced if we try a direct approach, but the difficulties disappear if we work backwards, beginning with an equilateral triangle and building up a general triangle which is afterwards identified with the given triangle ABC.”. Coxeter at least mentions the “trouble” —be it as a fact learned from unanalysed experience gained from trying to prove Morley’s Theorem—; Dijkstra does not even mention the trouble and just announces “We start in our proof not with the arbitrary triangle, but with the equilateral one.”

They both pull the same big rabbit out of their mathematical hat. Above we showed how this rabbit can be avoided. In order not to interrupt the flow of the presentation, we mentioned the catchword “disentanglement” —see [2]—; here is the place to point out that it refers to a general principle. The idea is to write in particular the information to be used as a conjunction of as many independent terms as possible because this is a precondition for subsequently being able to indicate precisely what is appealed to where. (If a datum can be factored differently —such as “△XYZ is equilateral”— the advice is to list the options and to postpone the choice until it emerges which one is appropriate.) The decision not to fix the size of the Morley Figure by, say, the length of AB rests on the principle —see [2]— not to destroy symmetry lightly.

The second big rabbit that [0] and [1] share is the choice of very special angles that new lines make with the edges of the equilateral triangle. The above analysis, based on angles alone, shows that we are essentially left with one degree of freedom, viz. the relative orientation of the two triangles; hence ψ. The magician’s proof immediately substitutes for ψ its proper value (so that ψ need not be mentioned at all), thus suggesting that without such spark of genius one cannot find such proofs. It is good to know that a whole class of such sparks are superfluous: in case of freedom, capture that freedom by the introduction of as yet undetermined parameters, which, if not truly arbitrary, will be later constrained by the needs of the subsequent proof.

The third big rabbit in [0] and [1] is the absence of any motivation for the choice of mathematical fact to exploit. In [0], out of the blue Coxeter refers to a theorem about the incenter of a triangle that I was not aware of. In [1], Dijkstra writes equally unmotivated “Using the rule of sines three times (in triangles AXB, BXZ, and AXY) we deduce [....]”, leaving the reader in awe for the miracle how subsequently all nasty terms cancel out. If we wish to teach our students how to design proofs we should teach them how to let their logical needs guide them through their mathematical knowledge.

Finally I would like to point out that the above design has been driven by different concerns. Using that AZ is a shared edge of two triangles was a logical necessity, our choice or parameters was a matter of experience. Instead of angles α +φ and β −φ we could have introduced φ' and α +β −φ'; it would have uglified the later development.

[0]    | Coxeter, H.S.M., Introduction to Geometry, John Wiley & Sons, Inc., New York, 1969, pp.23–25.
[1] | Dijkstra, Edsger W., Selected Writings on Computing: A Personal Perspective, Springer-Verlag New York Inc., 1982, pp.182–183.
[2] | Gasteren, A.J.M. van, “On the shape of mathematical arguments”, Ph.D. Thesis, 20 December 1988, Technical University Eindhoven.

Austin, 23 April 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 15-Mar-2012

EWD1051

The next forty years

Last fall, I was invited to Zürich to assist the ETH in all sorts of celebrations: a new building, the 20th anniversary of their Institute of Informatics, and the 40th anniversary of their Institute of Applied Mathematics. Moreover it was 40 years ago when the ETH acquired a Z4 as its first computing engine. The combination of the occasion and my long involvement in the topic seduced me to present my biased version of what really had happened during the last four decades of automatic computing. This was at the beginning of the Academic Year; wouldn’t it be nice to end this year with a talk about the next four decades of automatic computing?

When the idea first entered my head, I wrote it off as utterly preposterous: which sane scientist purports to be able to see so far into the future? But, preposterous or not, the idea did not leave me, and, as time went by, I caught myself inventing all sorts of reasons why it should be possible to say something of such long-range relevance. Instead of telling you all the ways in which I deluded myself, I shall confine myself to one of them, addressed to all of you that are engaged in education. When designing our courses, we do dare to decide what to teach and what to ignore, and we do this for the benefit of people, many of whom will not have retired yet by the year 2029. Clearly, some vision of the next 40 years of computing science is operational.. To this I should add that it is all right if the crystal ball is too foggy to show much detail. Thirty years ago, for instance, I had no inkling of how closely program design and proof design would come together, and in such a detailed sense my life has been full of surprises. At the same time these surprises were developments I had been waiting for because I knew that programming had to be turned into an endeavour amenable to some sort of mathematical treatment, long before I knew what kind of mathematics that would turn out to be. In other words, when building sand castles on the beach, we can ignore the waves but watch the tide.

*           *
*

Fortunately, there are few things that we can learn from the past, for instance that the rate at which society can absorb progress is strictly limited, a circumstance that makes long-range prediction a lot easier. The other month I was told of a great invention called “the register window”. My spokesman was young but in my ears it sounded very familiar because I remembered the Burroughs B5000 of 30 years ago. So, if you have a bright and sound idea now, you can expect it to be hailed as novelty around the year 2015.

Another thing we can learn from history is the failure of characterizations like “Computing Science is nothing but X”, where for X you would substitute your favorite discipline, such as numerical analysis, electrical engineering, automata theory, queuing theory, lambda calculus, discrete mathematics or proof theory. I mention this because of the current trend to equate computing science with constructive type theory.

Computing’s core challenge is how not to make a mess of it. If people object that any science meets that challenge, we should give a double rebuttal. Firstly, machines are so fast and store capacities are so huge that we face orders of magnitude more room for confusion, the propagation and diffusion of which are easily inadvertently mechanized. Secondly, because we are dealing with artefacts, all unmastered complexity is of our own making; there is no one else to blame and so we had better learn how not to introduce the complexity in the first place.

The history of the real-time interrupt is in this connection illuminating. It was invented for the purpose of facilitating processor sharing; its effect was the introduction of nondeterminism and endless headaches for many an operating systems designer. We have seen two reactions to it. For the purpose of debugging OS/360, IBM built special-purpose monitors that exactly recorded when the central processor honoured which interrupt; when something had gone wrong, the monitor could be turned into a controller, thus forcing a replay of the suspect history and making the “experiment” repeatable. The other reaction was to determine the conditions under which one could feasibly and safely reason about nondeterministic programs, and subsequently to see to it that those conditions were met by both hardware and software. OS/360 was a mess forever after; the THE Multiprogramming System, in contrast, was so robust that no system malfunctioning ever gave rise to a spurious call for hardware maintenance. Needless to say, the whole episode has made a lasting impression on me.

One moral is that the real-time interrupt was only a wave, whereas the tide was the introduction of nondeterminism and of system invariants as a means of coping with it. A wider moral is the constructive approach to the problem of program correctness, to which we can now add the problem of system performance as well. It is only too easy to design resource-sharing systems with such intertwined allocation strategies that no amount of applied queuing theory will prevent most unpleasant performance surprises from emerging. The designer that counts performance predictability among his responsibilities tends to come up with designs that need no queuing theory at all. A last, and this time recent, example is the design of delay-insensitive circuitry, which delegates a whole class of timing difficulties to the class of problems better avoided than solved. The moral is clear: prevention is better than cure, in particular if illness is unmastered complexity, for which no cure exists.

The above examples point to a very general opportunity, in broad terms to be described as designs such that both the final product and the design process reflect a theory that suffices to prevent a combinatorial explosion of complexity from creeping in. They are many reasons to suppose that this opportunity will stay with us for a very long time and that is great for the future of computing science because, all through history, simplifications have had a much greater long-range scientific impact than individual feats of ingenuity.

The opportunity for simplification is very encouraging because in all the examples that come to mind the design process cost much less labour and led to a much better final product than its intuitively conceived alternatives. The world being what it is, I also expect this opportunity to stay with us for decades to come. Firstly, simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated. Secondly we observe massive investments in efforts that are heading in the opposite direction. I am thinking about so-called design aids such as circuit simulators, protocol verifiers, algorithm animators, graphical aids for the hardware designer, and elaborate systems for version control: by their suggestion of power they rather invite than discourage complexity. You cannot expect the hordes of people that have devoted a major part of their professional lives to such efforts to react kindly to the suggestion that most of these efforts have been misguided, and we can hardly expect a more sympathetic ear from the granting agencies that have funded all these efforts: too many people have been involved and we know from past experience that what has been sufficiently expensive is automatically declared to have been a great success. Thirdly, the vision that automatic computing should not be such a mess is obscured, over and over again, by the advent of a monstrum that is subsequently forced upon the computing community as a de facto standard. Ten years ago it was ADA; now it seems to be the software for desktop publishing. Whether the academic community will resist and ignore the latter as successfully as it did the former, remains to be seen; I have my doubts.

In short, the opportunity to simplify will remain with us for many years, and I propose, in order to maintain our sanity and enthusiasm, that we welcome the long duration of that opportunity rather than to suffer from impatience each time the practitioners deride or discard our next successful pilot project as a toy problem: they will do so, even if you have achieved what, shortly before, they had confidently predicted to be impossible.

*         *
*

By now we all know that programming is as hard or as easy as proving, and that if programming a procedure corresponds to proving a theorem, designing a digital system corresponds to building a mathematical theory. The tasks are isomorphic.

We also know that, while from an operational point of view a program can be nothing but an abstract symbol manipulator, the designer of the program had better regard the program as a sophisticated formula. And we also know that there is only one trustworthy way of designing a sophisticated formula, viz., derivation by means of symbol manipulation. We have to let the symbols do the work. Computing and computing science unavoidably emerge as an exercise in formal mathematics or, if you wish an acronym, as VLSAL ( = Very Large Scale Application of Logic).

The extremely close connection between program design and proof design has revived interest in automatic programming and mechanical theorem proving. We now understand that both goals embody the same dream. But this insight does not make the dream more realistic than before. I have no first hand experience with automatic theorem proving, but have an impression from looking at it from some distance, and am willing to share that impression for what it is worth.

Firstly, mechanical proof verification seems a more apt description than mechanical theorem proving. Secondly, the use of a mechanical proof verifier requires a great amount of human symbol manipulation of a usually painful kind. Thirdly, mechanical proof verifiers are primarily praised for being totally unforgiving: their users tell me that, over and over again, the purported proofs they offer to the verifier turn out to be incomplete. Fourthly, the formalisms their user communities have adopted invariably seem to be notationally atrocious.

I am sometimes wondering how these efforts will be evaluated one or two decades from now. You see, right from start, the opinion that formal mathematics is by definition too laborious, too tedious, too lengthy, and hence too error-prone to be done by hand, has been raised to a dogma, but as time goes by, I find this dogma becoming more and more suspect. Firstly, it was politically too convenient: the AI community has used it extensively to justify these efforts at mechanized symbol manipulation, thus losing all interest in the simplification of doing formal mathematics. I have, indeed, seen the mechanical production of pages of verification conditions, much longer than anyone would care to produce by hand; very impressive until you realized that they should not have been produced in the first place. Secondly, it is quite likely that the doing of formal mathematics as commonly perceived is needlessly cumbersome. Over the last decade I have gained considerable experience in the design of purely calculational proofs. It may, of course, be due to the topics I have dealt with, but I find the dogma not confirmed; on the contrary, I find my calculational proofs shorter than any alternative I can think of. To which I should add that, in order to reach this goal, I had to deviate, over and over again, from established notational practice and had to learn a bunch of little general theorems about classical logic that are by no means common knowledge. From this experience I can only draw one conclusion: thus far, formal mathematics has never been given a fair chance. Inescapably I must conclude that, by and large, the art and science of letting the symbols do the work is still in its infancy.

The above conclusion has all sorts of consequences. A few decades from now, current efforts at mechanical theorem proving are likely to be characterized as premature in the sense that they attempted to mechanize what we did not yet ourselves how to do it well.

Much further reaching are its consequences for our conception of doing mathematics and, eventually, for our practice of designing proofs and programs. Seventeen years ago I have pointed out that computers would have their greatest impact on our culture, not in their capacity of tools, but in their capacity of intellectual challenge; at the time, my vision of that challenge was focussed on the programming task, but now I can be at the same time more specific and more general.

By their mere existence, computers are a daily reminder of their healthy limitations and drive home the full implication of the realization of Leibniz’s Dream of presenting the manipulation of uninterpreted formulae as an alternative to human reasoning. The challenge of turning that Dream into reality, however, will certainly keep us busy for at least four decades.

It is not only that the design of an appropriate formal, notational, and conceptional practice is a formidable challenge that still has to be met; it is worse because current traditions are hardly helpful. For instance, we know that the transition from verbal reasoning to formal manipulation can be appreciated as narrowing the bandwith of documentation and documentation, whereas in the name of “ease of use” a lot of effort of the computing community is aimed at widening that bandwith. Also, we know that we can only use a system by virtue of our knowledge of its properties and, similarly, pay the greatest possible care to the choice of concepts in terms of which we build up our theories: we know we have to keep it crisp, disentangled, and simple if we refuse to be crushed by the complexities of our own making. But, obviously, the market pulls in the opposite direction. The other day I found in the University bookstore in Eindhoven a book on how to use “Wordperfect 5.0” of more than 850 pages, in fact a dozen pages more than my 1951 edition of Georg Joos, “Theoretical Physics”. It is time to unmask the computing community as a Secret Society for the Creation and Preservation of Artificial Complexity. And then we have the software engineers, who only mention formal methods in order to throw suspicion on them. In short, we should not expect too much support from the computing community at large. And from the mathematical community I have learned not to expect too much support either, as informality is the hallmark of the Mathematical Guild, whose members —like poor programmers— derive their intellectual excitement from not quite knowing what they are doing, and prefer to be thrilled by the marvel of the human mind. For them, the Dream of Leibniz is a Nightmare. In summary, we are on our own.

But that does not matter. In the next forty years, Mathematics will emerge as The Art and Science of Effective Formal Reasoning, and we shall derive our intellectual excitement from learning How to let the Symbols Do the Work.

I thank you for your attention.

Nuenen, 14 June 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Thu, 3 Apr 2008

EWD 1053

Monochrome pairs in the three-coloured plane

A few months ago I encountered the following

Theorem   If each point in the Euclidean plane is red, white, or blue, there exists a monochrome pair of points with mutual distance 1.

This morning I looked at it again, and designed the following proof.

Consider the three-coloured plane. According to the pigeonhole principle, 4 points suffice to guarantee the existence of a monochrome pair among them. Regrettably, we cannot arrange them in such a way that all pairs are at distance 1. The best we can do is 5 pairs at distance 1 and 1 pair at distance √3:

          .

Using the term “d-pair” to denote a pair of points with mutual distance d, we have to show: (there exists a monochrome 1-pair). The above configuration only allows us to conclude

Lemma    |   In the three-coloured plane
| (all √3-pairs are monochrome) ∨
| (there exists a monochrome 1-pair)

Consider now an isosceles triangle ABC.

Then
      ¬ (there exists a monochrome 1-pair)
⇒       {Lemma}
      (all √3-pairs are monochrome)
⇒       {instantiation: AB and BC are √3-pairs}
      (AB and BC are monochrome)
⇒       {transitivity of equality}
      (AC is monochrome)
⇒       {instantiation: AC is a 1-pair}
      (there exists a monochrome 1-pair)   ,
and, since [¬P ⇒ P] ≡ [P], the above observation proves the theorem.

(End of Proof.)

*         *         *

When I encountered the theorem, I had convinced myself that the vertices of the complete triangular grid

  etc.

admit a three-colouring without monochrome neighbours. Consequently, I knew this morning that, of the Euclidean plane, something more than the existence of vertices of complete triangular grids had to be taken into account. (This turned out to be the existence of triangles of the shape of △ABC.)

We had to demonstrate the existence of monochrome 1-pairs. The above observation suggested the consideration of monochrome d-pairs with d≠1; that is how the monochrome √3-pairs entered the picture. The introduction of △ABC was then suggested by trying to exploit the meaning of the adjective “monochrome”, i.e., trying to exploit the properties of equality.

Nuenen, 18 June 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA.

P.S.   In details, the above is a bit clumsy.

Sept. 1989   EWD

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1054

On hygiene, intellectual and otherwise

The purpose of this short talk is to help you understand the world we live in, the world that some people honour with the adjective "real". The reason to present it is that I observed at the two discussions earlier this week a general uneasiness as to whether what we are doing really makes sense. We know that no responsible scientist guesses his formulae but derives them and in the same vein we derive our programs by formal calculation. This is a time-honoured tradition, formalization is just a matter of intellectual hygiene, and we should be quite confident that, indeed, this undertaking makes all the sense in the world, but we hesitate and are ambivalent about it because, all around us, our hygienic practices are opposed, derided and ridiculed. For your illumination and comfort I would like to point out that exactly the same opposition was evoked a century ago when it was suggested that surgical cutlery such as needles, knives, and scissors be sterilized by putting them in boiling water. The opposition was as violent as the hygienic practice was sensible.

Medical science had an irrefutable argument against it: sterilization of surgical cutlery would have no beneficial effect at all because, if it had, the practice would have been introduced a long time ago. After all, boiling water was already available at the time of Hippocrates.

Medical research was a little bit more tolerant in the sense that they admitted that, yes, perhaps some of such hygienic practices could be allowed in the case of novice surgeons, whose work was anyhow confined to toy operations. Research, however, would not pursue it since it was ridiculous to believe that the sterilization of their cutlery would enable surgeons to cure all diseases.

Strong opposition came from the surgeons themselves. The Royal Surgical Society even issued a strongly worded Manifesto against sterilization, arguing, firstly, that imposing such artificial disciplines in the operating rooms would stifle the surgical creativity of its members, and, secondly, that, if sterilization of the knife really helped, everybody would be able to operate and that would be totally intolerable. Furthermore, what was then known as operational research had shown that the proposed sterilization procedures would be much too complicated for the average nurse.

Emotional protest came from the nurses themselves, who loved to take care of the very sick and whose devotion rose in those days to unfathomed heights each time a young patient died in their arms. The spectre of routine operations was a threat to their job satisfaction, greater than they could endure.

Next, the Department of Defence declared a moratorium on all funding of sterilization research, frightened as it was of the possible outcome of being obliged to equip all its field hospitals with the necessary boiling equipment. Needless to say, the thought of having to subcontract the design of a portable boiler was more than the DOD could endure. For years, medical researchers applying for funding had to sign a form on which they declared that their research could not be used to foster the case for sterilization of surgical cutlery.

Eventually, emotions ran so high that the Church could not remain silent any longer. It settled the matter on moral grounds: since it is Man's predicament to die, it would be immoral even to try to reduce the natural mortality rate of the surgical wards by such unnatural and counterintuitive acts as boiling a pair of scissors: the sole purposes for which God had created hot water were the cooking of food and the boiling of heretics such as the practitioners of greater hygiene, be it surgical or otherwise.

                          Enschede, 28 June 1989

prof.dr.Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Mario Béland
revised Thu, 3 Apr 2008

EWD 1055

On the problem of the calissons

In the American Mathematical Monthly (May 1989, pp 429-431), and under the title “The Problem of the Calissons”, Guy David and Carlos Tomei present the following theorem.

Let a “calisson” be a diamond formed by two equilateral triangles with sides of length 1 that share a side. Let a regular hexagon with sides of length n be covered by (3n�) calissons; in such a covering the calissons occur in the three possible orientations in equal numbers.

In the following, a placed calisson is identified with a pair of adjacent equilateral triangles of the regular triangularization of the plane. Generalizing the hexagon, we call the set of triangles covered by a set of calissons a “box” that is “filled” by those calissons. A filling of a box has a “spectrum”, i.e., the triple of natural numbers counting the numbers of calissons in the three orientations. The theorem presented by David and Tomei is an immediate consequence of the more general

Theorem   All fillings of the same box have the same spectrum.

(Because of the rotational symmetry of the hexagon, the theorem tells us that the spectrum of a hexagon filling remains unchanged under cyclic permutation of its elements.)

To prove the theorem we consider an arbitrary box with two possibly different fillings. We partition the triangles of the box into the smallest subboxes that are common to both fillings; the theorem then follows from the fact that each subbox has the same spectrum in either filling, a fact we shall now demonstrate. In this demonstration we shall encounter two types of subboxes and for each type of subbox we shall argue separately that it has the same spectrum in either filling.

The one possible type of smallest common subbox is a pair of adjacent triangles: it corresponds to a calisson occurring in both fillings. Such a subbox admits only one filling, and hence all its fillings trivially have the same spectrum. This deals with any triangle that both fillings cover by the same calisson.

To investigate the other possible type of smallest common subbox, we consider a triangle that the two fillings cover by different calissons. For such a triangle we can identify two of its (three) adjacent triangles as its “neighbours” in the sense that they belong to the same subbox, the triangle being paired to the one neighbour in the one filling and to the other neighbour in the other filling, and each neighbour has again the property that the two fillings cover it by different calissons. The total number of triangles being finite, we conclude that the other possible type of smallest common subbox is a cyclic path of triangles such that neighbours on the path are adjacent.

We next observe that —in analogy to the chess board— the triangles of the regular triangularization can be coloured black and white, such that adjacent triangles differ in colour. This gives triangles in the same orientation the same colour and each calisson covers two differently coloured triangles. On the cyclic path the colours alternate, hence the cyclic path contains an even number of triangles and allows precisely two fillings: traversing the cyclic path in some direction, each black triangle is either paired to its white predecessor or to its white successor.

Consider now a grid line that cuts the cyclic path. Because the path is cyclic, the grid line cuts the path an even number of times and traversal of the path crosses the grid line as many times in the one direction as in the other direction, i.e., as many times from black to white as from white to black (triangles at one side of the grid line adjacent to it having the same orientation, and hence the same colour). Associating with each crossing the calisson that “sits astride” we now see that half of them belong to the one filling and half of them belong to the other filling. As all calissons astride the same grid line have the same orientation we conclude that the two possible fillings of a cyclic path have the same spectrum. And this observation concludes the proof.

*         *         *

David and Tomei give a very unsatisfactory treatment of this problem. I quote

“The idea of the proof is to reduce the problem to a very intuitive fact in three dimensions. We do not give complete details of a formal proof for two reasons. First, we do not want to spoil the simplicity of the basic intuitive idea. Furthermore, the result is an example of a proof by picture that does not translate immediately into precise mathematics.” Etc.

And then they come with an elaborate nonproof.

Their whole idea of interpreting the plane figure as a picture of a simple three-dimensional structure is, however, misguided as is shown when we generalize the hexagon to, for instance, the following ring-like structure:

M.C. Escher would be delighted.

I am indebted to the members of the Eindhoven Tuesday Afternoon Club, in particular to R.W. Bulterman for drawing our attention to the problem and to J.C.S.P. van der Woude for introducing the spectrum and conjecturing our theorem.

Nuenen, 5th of July 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD1055A

●    Raise your standards as high as you can live with, avoid wasting your time on routine problems, and always try to work as closely as possible at the boundary of your abilities. Do this because it is the only way of discovering how that boundary should be moved forward.

●    We all like our work to be socially relevant and scientifically sound. If we can find a topic satisfying both desires, we are lucky; if the two targets are in conflict with each other, let the requirement of scientific soundness prevail.

●    Never tackle a problem of which you can be pretty sure that (now or in the near future) it will be tackled by others who are, in relation to that problem, at least as competent and well-equipped as you are.

●    Write as if your work is going to be studied by a thousand people.

●    Don't get enamored with the complexities you have learned to live with (be they of your own making or imported). The lurking suspicion that something could be simplified is the world's richest source of rewarding challenges.

●    Before embarking on an ambitious project, try to kill it.

●    Remember that research with a big R is rarely mission-oriented and plan in terms of decades, not years. Resist all pressure —be it financial or cultural— to do work that is of ephemeral significance at best.

●    Don't strive for recognition (in whatever form): recognition should not be your goal, but a symptom that your work has been worthwhile.

●    Avoid involvement in projects so vague that their failure could remain invisible: such involvement tends to corrupt one's scientific integrity.

●    Striving for perfection is ultimately the only justification for the academic enterprise; if you don't feel comfortable with this goal —e.g. because you think it too presumptuous—, stay out!

Transcription by Hai Zhou.
Last revised on Thu, 3 Apr 2008.

EWD 1055c

On covering a figure with diamonds

In the American Mathematical Monthly (May 1989, pp 429-431), under the title “The Problem of the Calissons”, Guy David and Carlos Tomei present the theorem given below. Before formulating the theorem, we introduce some terminology.

We consider a regular triangularization of the Euclidean plane, the grid lines of which cut up the plane into equilateral triangles with sides of length 1; in the following, “triangle” refers to such an equilateral triangle. A pair of triangles being “adjacent” means that they are different and share a side; such a pair of adjacent triangles is also referred to as a “diamond”, and a moment’s reflection tells us that each diamond has one of three possible orientations. A "figure” is a finite set of triangles; a “covering” of a figure is a partitioning of the figure’s triangles into diamonds.

The theorem presented by David and Tomei states that in any covering of a regular hexagon with sides of length n (and comprising 6n� triangles), the diamonds occur in the three orientations in equal numbers.

*         *         *

Because of the rotational symmetry of the hexagon, the above theorem is an immediate consequence of the following one.

Theorem   Consider a figure that admits one or more coverings. Each covering yields a triple of frequencies, each counting the diamonds in one of the considered yield the same triple.

To prove this theorem, we consider a figure that admits two possibly different coverings A and B, and show that A and B yield the same triple of frequencies. To this end we partition the triangles of the figure into two groups, (i) and (ii); note that each triangle of the figure belongs to a diamond in A and to a diamond in B.

(i)   The triangles belonging to the same diamond in both coverings. Their contribution to the A-triple is by definition equal to their contribution to the B-triple.

(ii)  The triangles belonging in A and B to two different diamonds. To investigate this latter case, we visualize for a moment the following graph: its vertices “are” the triangles in group (ii) and its edges “are” the diamonds in A and B. This graph is finite (because a figure was defined to be a finite set of triangles) and each vertex is connected to exactly two others (by edges corresponding to the diamonds to which the triangle belongs in A and B respectively). Graph theory tells us that such a graph falls apart into cycles. We conclude that the triangles in group (ii) are partitioned into cyclic paths of adjacent triangles, pairs of neighbours alternatingly forming diamonds from A and B. The graph we visualized can now be forgotten. We can now meet our proof obligation by proving the following lemma.

Lemma   Let a “cyclic” path be a set of triangles that can be arranged cyclically so that each pair of neighbours in the cycle is adjacent. A cyclic path admits two coverings, which yield the same triple of frequencies.

To prove this lemma, we observe that the regular triangularization contains triangles in only two orientations and that two adjacent triangles are of different orientation. In honour of the chessboard we call the triangles of the two orientations “black” and “white” respectively. (Like the domino on the chessboard, the diamond pairs fields of opposite colour.) That the cyclic path admits exactly two coverings is obvious, but now we can be more precise: in the cyclic path, colours alternate, and in the one covering each black triangle is paired with its white successor, while in the other covering each black triangle is paired with its white predecessor. It is this observation that gives the clue to the argument that both coverings yield the same triple of frequencies.

We demonstrate this sameness by showing how to establish a one-to-one correspondence between equally oriented diamonds from the two coverings of a cyclic path. Take an arbitrary diamond from one of the coverings and consider the grid line that separates the two triangles of that diamond: we say that, in that diamond, the cyclic path “crosses” that grid line. In a complete traversal of the cyclic path, that grid line is crossed as many times in the one direction as it is crossed in the opposite direction, that is: as many times from a black triangle to a white one as from a white triangle to a black one, that is: half of the diamonds in which the grid line is crossed come from the one covering of the cyclic path and half of them from the other. Furthermore, all diamonds thus halved by a grid line have the same orientation, and this concluded the proof.

*         *         *

I am indebted to the members of the Eindhoven Tuesday Afternoon Club, in particular to R.W. Bulterman for drawing our attention to the problem —David and Tomei had given an elaborate nonproof— and to J.C.S.P. van der Woude for conjecturing our more general theorem. I am indebted to the members of the Austin Tuesday Afternoon Club, in particular to Vijaya Ramachandran for simplifying my argument, to Jayadev Misra for suggesting improvements in the presentation, and to the graduate students for their invaluable assistance in the final editing of this note.

Austin, 11 October 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD1056

Hoe belangrijk het is of duikboten kunnen zwemmen

Het is nu al weer een jaar of wat geleden dat de redactie van een wat vaag tijdschrift mij om een bijdrage verzocht over de vraag of computers konden denken. Daar had ik geen zin in en ik lichtte mijn weigering toe met de opmerking dat ik het gesuggereerde onderwerp net zo onbelangrijk vond als de even brandende vraag of duikboten konden zwemmen. (Ik had buiten de waard gerekend: de redacteur —een socioloog— schreef mij terug, dat hij die laatste vraag óók heel interessant vond!)

De vraag of computers kunnen denken is heilloos, want wie zich er in verdiept is binnen de korst mogelijke tijd met een enkele reis op weg naar de filosofie. De vraag is bovendien overbodig in die zin dat wij ons in computers —hun mogelijkheden, hun beperkingen en hun invloed op de cultuur— kunnen verdiepen zonder te hoeven kiezen wat wij onder "denken" zouden moeten, willen of kunnen verstaan.

De mystieke nonsens, varierend van electronische breinen tot monsters van Frankenstein, waarmee de volksmond en de populaire pers computers hebben omgeven, hoef ik niet te detailleren, want die is genoegzaam bekend. Veel belangrijker is het verschijnsel van de overvloed en de hardnekkigheid van deze nonsens, want als symptoom is dit verschijnsel maar op één manier uitlegbaar: het vertelt ons dat computers bij hun verschijnen een radicale nieuwigheid waren die niet adequaat begrepen kon worden in termen van ons al vertrouwde verschijnselen en begrippen. Vergelijkingen met dingen van vroeger gingen allemaal mank, analogieën met wat we kenden bleken keer op keer te oppervlakkig om niet misleidend te zijn.

De radicale nieuwigheid had twee aspecten. Het bekendst daarvan was de onvoorstelbare snelheid: computers rekenden eerst duizend maal sneller dan voordien mogelijk, daarna miljoen, en tenslotte miljard maal sneller. Het probleem is dat dergelijke snelheidsverhoudingen, hoewel makkelijk op te schrijven in een heel reële zin onvoorstelbaar zijn en het heel moeilijk is je voor te stellen hoe onvoorstelbaar iets onvoorstelbaar is.

Een enkele factor tien maakt al een verschil tussen dag en nacht; eens heb ik een vriendin om haar daarvan te overtuigen gevraagd hoeveel kinderen ze had —ik wist dat het er zes waren en ze begreep wat ik bedoelde. En een baby die duizend keer zo snel leert kruipen haalt straaljagers in! Volledigheidshalve vermeld ik dat eveneens de capaciteit voor informatieopslag —in antropomorfe terminologie ook wel "geheugenomvang" genoemd— in de loop der jaren onvoorstelbaar is toegenomen. Kortom: bij zo drastische quantitatieve verschillen laten alle analogiën het afweten.

Het andere aspect van de radicale nieuwigheid trad aanvankelijk iets minder op de voorgrond, maar de repercussie ervan zijn er niet minder om. Om dit aspect over het voetlicht te krijgen moet ik mij enige dichterlijke vrijheid —c.q. wiskundige abstractie— veroorloven en ik hoop dat de lezer mij dat gunt. Ik wil refereren naar "formules" die zijn opgebouwd uit "symbolen" uit een eindig "alfabet". Dat "alfabet" is niet beperkt tot de 26 letters, daar mogen we de leestekens, allerlei haakjes en wiskundige symbolen en de cijfers 0 t/m 9 ook bij doen. Het voordeel van deze dichterlijke vrijheid is dat hij ons in staat stelt een algebraische uitdrukking als (a+b)/c, een programmafragment als x:=x+1, en een decimaal getal als 729 alle drie onder hetzelfde hoedje "formule" te vangen.

De zojuist geschetste beeldspraak stelt mij in staat de tweede nouveauté aan te geven: met computers is een universum geschapen waarin niet anders gebeurt dan dat volgens stricte regels uit reeds voorkomende formules nieuwe formules worden afgeleid. Dit universum is theoretisch van diepe betekenis omdat alles wat afleidbaar is op deze manier kan worden afgeleid; de electronische versie is van grote practische betekenis omdat hij zo snel werkt dat zelfs het resultaat van lange afleidingen binnen afzienbare tijd gereed kan komen.

Een dergelijk formeel universum is daarom als nieuwigheid radicaal omdat het lijnrecht indruist tegen al onze vroeger opgebouwde intuities. Omdat bv. alle formules zijn opgebouwd uit de symbolen van een eindig alfabet, bestaat er niet zo iets als continue verandering. We zouden kunnen proberen te praten over "kleine" veranderingen —bv. de wijziging van maar één enkel symbool—, maar weer laat onze intuitie ons in de steek doordat er geen metriek bestaat volgens welke "kleine" veranderingen ook "kleine" effecten hebben.

De meest saillante eigenschap van het formele universum is evenwel dat er niets anders dan formulemanipulatie in plaats vindt; zelfs de kleinste fractie van een verbaal betoog is daarmee uitgesloten. Voorzover wij "begrip" en "inzicht" met verbale redenering identificeren zijn begrip en inzicht dus van het formele universum uitgesloten. Een klein voorbeeld moge dit toelichten: als wij in het kader van een groter betoog moeten vaststellen dat 812 een veelvoud van 7 is, dan is dat niets iets dat we proberen te "begrijpen" of "in te zien", maar iets dat we vaststellen door even een staartdelinkje uit te voeren, door —in onze beeldspraak— even wat formules te manipuleren.

Onze traditionele betogen zijn gemengd, dwz. deels formeel en deels verbaal, en verbaal redeneren is ons zo met de paplepel ingegoten dat totale uitbanning van de verbale component velen op het eerste gezicht als ongewenst, zo niet als onmogelijk voorkomt. Nadere analyse leert evenwel dat het altijd de verbale component is die vaag, onbegrijpbaar en dubbelzinnig is. Traditioneel heeft de wiskunde zich er toe beperkt voor anders te subtiele redeneringen door gedeeltelijke formalisering de verbale component iets terug te drukken; het formele universum, zoals dat door computers wordt belichaamd, is uitdaging en aansporing hierin veel verder te gaan, uiteindelijk totdat de verbale component volledig is uitgebannen. Deze uitdaging is niet onbeantwoord gebleven, en het resultaat is dat er op het gebied van de wiskundige methodologie zich een stille revolutie voltrekt waarin volledige formalisering steeds aantrekkelijker wordt.

Hoe "belangrijk" is dit allemaal? Wie om te beginnen de wetenschap ziet als een activiteit waar slechts een verwaarloosbare fractie van de bevolking actief aan deelneemt, en vervolgens de wetenschap ziet als een versnipperd geheel waarin de wiskundige subcultuur zich in een soort intellectueel ghetto heeft gemanoeuvreerd, die zal op zijn best "tja, tja, heel interessant" mompelen en schouderophalend overgaan tot de orde van de dag.

Men kan ook om te beginnen de wetenschap beschouwen als een van de belangrijkste pijlers van onze cultuur en vervolgens —men zou niet de eerste zijn!— betogen dat van elke wetenschappelijke discipline intellectuele standing en gewicht bepaald worden door zijn wiskundig gehalte. In die visie zou een radicale koersverandering in de wiskunde op den duur in het overgrote deel van ons intellectuele leven zijn sporen nalaten.

Ik houd het op zo'n radicale koersverandering. Nu nog definieert de Concise Oxford Dictionary wiskunde als "abstract science of space, number, and quantity"; als voormelde stille revolutie zich heeft voltrokken, zal "art and science of effective reasoning" een adequatere definitie van wiskunde zijn. Ik zal het niet meer meemaken, maar als het een beetje meezit, is over honderd jaar de vraag of computers kunnen denken niet meer dan een historisch curiosum uit de twintigste eeuw.

                               Nuenen, 15 juli 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by F. Koenders
revised Thu, 13 Nov 2008

EWD1057

Andrei P. Ershov in Nuenen

Whenever Andrei visited the Netherlands in the seventies or early eighties, he tried to extend his visit with a few days so that he could stay the weekend with me and my family in Nuenen, the little village in the Southern part of the country where we lived at the time. It became a standard ingredient of those visits that I would make him copies of all the EWD's I had written since his previous visit so as to keep the people in Novosibirsk up to date on the work I had done. He always was a most welcome guest.

Once, when he was not quite sure how to use the preposition "except" in an English sentence, I gave him my old edition of the Concise Oxford Dictionary, and we still remember his keen delight when he discovered there Fowler's exemplary sentences "we are all fallible, except the pope" but "not excepting the pope"! He would have been disheartened to learn that those beautiful examples are no longer included in the sixth edition.

At one of his visits, Andrei asked my opinion about Ada. I told him that Ada was such a mess that I shuddered at the thought that Western security would depend on it and that I would feel much safer if the Red Army were to adopt it as well. Andrei smiled and gave the now famous answer "Don't worry....".

On a Saturday afternoon, when the weather was very nice, we took him out for a little trip. Seemingly aimlessly the car wound its way through the peaceful country-side, but I had a surprise in store for him: at a given moment I told him "Now we are in Belgium.". "But I don't have a Belgian visa! And I have left my passport at your home!". He was reassured when we told him that we had left our passports at home too. On our way back we took a lovely little sand road. The scenery is still vividly in my mind: at the left a little forest and at the right mostly heather. Suddenly, Andrei said "Do you know that you are the first European who took me on an unpaved road when he showed me his country?". We were back home in time for tea.

I have had one somewhat frightening experience with Andrei. In the mean time we had acquired a tandem and it had become some sort of tradition that —weather permitting— visiting foreign computing scientists would be shown the village and its immediate surroundings from the tandem's second seat. The invitation was sometimes accepted with some hesitance, but when Andrei's turn had come and I proposed the tandem trip to him, he accepted the invitation with great enthusiasm and immediately went to his room to dress for the occasion while I took the tandem out of the garage. When we were ready to depart, Andrei said to me "Do you know why I am so excited about this tandem trip? I cannot cycle.", thereby turning my innocent proposal into a risky adventure. I immediately got most uncomfortable visions of falls and broken hips, but Andrei looked forward to it so much that I did not have the heart to cancel the trip. The first corners we took were for me a nerve-wrecking experience, but we managed not to lose our combined balance and returned unscathed.

One of my last memories is of Andrei conversing for more than an hour in Russian with my daughter, who studied Slavonic languages at the time. (It was a strange experience, seeing one's daughter and one's friend having a great time together, but not having the foggiest notion of what they were talking about.) She told me later that he had been very sweet, speaking carefully with a clear diction until he had found out how much she could cope with. On that visit he left his toothpaste behind; she tried it once.

Austin, 27 August 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

transcribed by Tristram Brelstaff
revised Fri, 14 Mar 2008

EWD 1058

In reply to comments

Dear Colleagues,

Since your comments are not disjoint, allow me to address you in principle collectively.

Of course there is more to digital system design than the formal derivation of programs from their equally formal specifications; accordingly I expect a full-blown CS curriculum to comprise more than an "an introductory programming course for freshmen". Please remember that my modest proposal only pertained to the latter.

The choice of functional specifications —and of notation to write them down in— may be far from obvious, but their rôle is clear: it is to act as a logical firewall between two different concerns. The one is the "pleasantness problem", i.e., the question of whether an engine meeting the specification is the engine we would like to have; the other one is the "correctness problem", i.e., the question of how to design an engine meeting the specification. I firmly believe that whenever we succeed in erecting such a firewall, the effort will pay off handsomely. The reason for this belief of mine is that the two concerns deserve separation because the two problems are most effectively tackled by totally different techniques. (They are currently psychology and experimentation for the pleasantness problem and symbol manipulation for the correctness problem.)

The above, I think, is noncontroversial. The issue seems rather to be whether the above observation justifies the proposal to focus an introductory programming course on formal program derivation, while in the software industry the presupposed separation of concerns is rarely carried through (and perhaps never will be.)

Before rushing to a conclusion, I would like you to be aware of two facts, one obvious and one shocking. The obvious fact is that, after sufficient analysis, even the software industry is full of programming problems that don't defy functional specification at all. The shocking fact is that the majority of computing professionals —be they academic or industrial— cannot be trusted to program things as simple as a binary search. (To which I should add that they are usually thrilled when you show them how crisp an argument can maintain complete control over the derivation. But to have it sink in takes more than a single lecture: after a lecture, it is a common experience to receive from a fellow professor who was in the audience for one of the programs I derived a suggested "improvement", justified in the usual handwaving fashion, but invariably in error.) Since formal derivation is by far the simplest and most effective way of constructing such programs and the techniques involved are eminently teachable (and fun to apply) I don't think we should deny them to our students. And I trust the better ones to apply such techniques on a more grandiose scale as they see fit.

While writing the above I observe that I am unable to consider the last conclusion under dispute: no responsible scientist that I know of guesses formulae of any sophistication, he derives them instead. If we agree —if necessary only for the sake of the argument— that the techniques of program derivation should be part of the computing professional's intellectual baggage, the only remaining question is: should it be covered in the first course on programming?

My answer is "Yes" because in my perception the hardest part of the educational process is not the acquiring of new habits but the getting rid of the old, inadequate ones: our past is our inalienable treasure or burden. I therefore see no justification in not teaching the most effective techniques available right from the start.

Several of you have voiced a wider concern, viz. serious doubts about the viability of a much more formalized mathematics. I can understand your concern because, for many years, I shared your doubts. Over the last decade, however, those doubts have largely evaporated, to the extent that I expect, say fifty years from now, the mathematical informality of today definitely to be a thing of the past. (I realize that this is a somewhat gratuitous statement because, if my expectation will not be fulfilled, I won't be there to be confronted with my mistake. But I cannot help having expectations beyond my lifetime.) The expectations are based on the experiences and observations collected since I started to explore the extent to which the experience gathered in programming methodology could be transferred to mathematical methodology in general. I shall indicate them briefly.

The presumed dogma that calculational proofs are an order of magnitude too long to be practical has not been confirmed by my experience. On the contrary, well-chosen formalisms provide a shorthand with which no verbal rendering can compete.

Through most of this century, mathematical logic has primarily been used for soul-searching. As a tool for daily, practical proof design it has hardly been given a fair chance. To realize its potential, it seems essential to view the purpose of logic not as mimicking human reasoning but as providing a calculational alternative to it.

In proof design, strong heuristic guidance can be extracted from a syntactic analysis of the theorem and from (baby) proof theory. Both possibilities require formalization of the proof structure for their exploitation.

While informal mathematics, with its ties to elusive entities such as "intuition" and "the human mind", is a hard topic to teach explicitly, symbol manipulation is tangible. The effective techniques of symbol manipulation are well within the teachable domain. Hence my estimate of only fifty years.

The possible future of mathematics that I envisage is very different from what the dyed-in-the wool member of the mathematical guild of today is used and probably attached to: my dream could very well be his nightmare. So be it. I cannot consider such discrepancy my fault. If you have a technical argument why my expectation of the future of mathematics cannot come true, please let me know, for it would save me a lot of work and a lot of animosity.

Finally, allow me to express my appreciation for the care with which you phrased your comments.

With my greetings and best wishes,

Yours ever,

Edsger W. Dijkstra             

prof.dr.Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Mario Béland
revised Thu, 3 Apr 2008

EWD1059

0 Preface

Practising mathematicians are supposed to do mathematics, i.e., to design and to present solutions, theorems, proofs, algorithms, and, in the more ambiguous case, whole theories. Amazingly —and regrettably— this is hardly reflected in the traditional mathematical curriculum. The traditional curriculum teaches mathematical facts, i.e., it teaches existing theories, concepts, and methods that have withstood the test of time; on the doing of mathematics, however, it is almost totally silent.

For centuries, we can now distinguish two extremes of the spectrum of different ways in which one generation tries to transfer to the next its knowledge and its abilities.

At the one end of the spectrum we have the educational practice of the guilds. The original guild was an association of people for whom the secrets of their common craft were of great, usually economic value; consequently, secrecy and restricted membership were typical characteristics of the guilds. Membership was restricted by erecting barriers for the admission of new members, who first had to join for seven —often very!— meagre years a master as his apprentice. Secrecy was maintained by never explicitly formulating or recording the secrets of the craft: the apprentice had to pick them up from his master by imitation and osmosis.

At the other end of the spectrum emerged what, for lack of a better name, I shall call the practice of the universities. The relation between the professor and his students is very different from the relation between the master and his students. It is the professor's task to formulate knowledge and methods as explicitly as possible, thereby bringing them into the public domain, and it is the task of the students to act for their teacher as a challenging whetstone. The absence of secrecy is the hallmark of the university tradition and I don't think it is an accident that the universities as we know them now started to emerge when the art of printing became established.

Many a discipline occupies in this spectrum a multiple position. Medicine is a very clear example: pathology and physiology are taught in the university tradition, whereas clinical medicine is almost exclusively taught in the tradition of the guilds. (It is in this connection revealing that, at some US universities, the School of Medicine is "associated with" but not "part of" the university.) In the case of medicine, this need not amaze us: here, the same economic forces that led to the original guilds are at work today.

A little bit more surprising is that mathematics occupies a similar multiple position: existing mathematics is taught quite openly, while the doing of mathematics remains covered by a shroud of mystery. If design and presentation get any attention at all, they are treated as separated issues: the process of mathematical invention is viewed as belonging to the realm of psychology, and presentation is considered a matter of personal style (or of pandering to the taste of the target audience). As will become clear, this attempt at separating form from content is unfortunate.

Remark. In the software industry, the situation is even worse in the sense that design and documentation are often done by different persons. The design is done by "software engineers" who are assumed to be illiterate, and the subsequent documentation is attempted by "technical writers". Experience has shown —over and over again— that in this division of labour nothing prevents the software engineers from coming up with designs so complex that they, in fact, defy documentation. As we shall see, the same mistake is made by the mathematician that tries to solve a problem without paying attention to the question of how to record his solution. (End of Remark.)

Our purposes are manifold: we wish to streamline the mathematical argument, to demystify the process of mathematical invention, and to turn the design of crisp arguments into a teachable discipline. To this end we shall have to make a lot explicit that the mathematical guild traditionally leaves unsaid, and we want this explicitness to cover both the crisp argument itself and the considerations that went into its design.

In pursuing these goals, we became more and more aware of the virtues of calculational arguments, carried out in a formalism that reduces proof obligations to targets to be reached by formula manipulation.

When rendered in a strict format, such calculational arguments strongly discourage all sorts of fudging that is only too common in the traditional guild member's "Emmenthaler proofs" —full of holes— and they therefore tend to be advocated for their greater security against oversights. A further —and perhaps more interesting— virtue of calculational arguments is that, because one's freedom is so clearly delineated , they are much easier to design in a systematic manner. Symbol manipulation is refreshingly tangible in comparison to the Emmenthaler proof, which is too elusive an object to develop a teachable design methodology for. (This experience is similar to the one in computing science, where programming methodology could only come off the ground after programs had been accepted as formal objects.)

A completely different advantage of calculational proofs with their limited repertoire of manipulations is the new light they shed on notational conventions, an issue that is in design and presentation of equal importance. As long as formulae are used for descriptive purposes only, choice of notation remains primarily a matter of taste, style and convention. Calculational arguments, however, provide a context in which one can raise the question how well a proposed notation is geared to our manipulative needs and, with this question, choice of notation suddenly becomes a technical issue. Here is one of the areas in which we must be prepared to see the meanings of "conventional" and of "convenient" diverge. (As long as numbers are only used to chisel on buildings the years in which they were built, Roman numerals are fine; as soon as we want to do arithmetic with numbers, the Hindu/Arabic decimal system —though unconventional when it was introduced in Europe— is objectively more convenient.)

*                *
*

Life would be much easier if the proposal to develop such a mathematical methodology were less controversial, for now I am in constant danger of being dragged into polemics (which I dislike). This, however, seems the place were I cannot avoid the discussion, so let me give you a catalogue of the most frequently heard objections and let us try to analyse how valid they are.

The simplest objection to deal with is an indignated "But that is not how mathematicians work!", against which one could retort that, while many people profess to be in favour of progress, some of them are even more in favour of progress without change.

The second objection is that, by playing down or perhaps even denying a rôle for such things as "intuition" or "mathematical insight", (i) I distort the "true nature of mathematics" and (ii) I had better read my Hadamard, because my proposals are completely at odds with how great mathematicians of previous generations have described the process of invention. Here the answer is "Hark, the guild member speaks.". What other perception of the "true nature of mathematics" and what other description of the process of invention can you expect from people trained to see such things as a matter of "intuition" and "insight"? Note that these terms, that hide more than they reveal, can be viewed as tools of secrecy, used by the guild to prevent the feared explicitness from emerging. (Recently, one of my proposals was called "dangerous". I am not amazed: you cannot expect guilds but to feel threatened when someone tries to blow the gaff.)

The third objection is one of the historical necessity of failure: "It won't work because if it could, it would have been developed a long time ago.". This objection (which is often misused as general-purpose dismissal) does not hold water because it is quite possible that something has not been pursued in the past because the people that could have done so just disliked the idea. In the current case, such a dislike is more than likely. I have discussed these matters over the years with many colleagues and have often encountered the feeling that the gaps in the Emmenthaler proofs are at least half the fun. They have told me that as readers of proofs they are tickled by the challenge of detecting the gaps and then figuring out how they should be filled and that they would be bored by reading a proof for which the author has done all the work. As authors of proofs they are tickled by the challenge of sketching proofs without having actually constructed them. I have no reason to doubt their words, but it raises the question of what we are doing: are we tickling our colleagues and ourselves, or are we doing mathematics? Besides this rather technical appreciation of Emmenthaler proofs I often encountered a more romantic one. It comes from people who are overwhelmingly thrilled by the mysteries of the human mind and of how one human communicates his "insights" to another; for them, the miracle of mathematics culminates in these mysteries. (This attitude is primarily voiced by Roman Catholics and in Anglo-Saxon countries, where "the humanities" are more rampant than on the European continent.) Not denying the mysteries, I would prefer to move mathematics away from them, rather than enforcing the link; my main reason, of course, is teachability. Finally, I also found that efforts like mine, striving at greater perfection and greater control, can be strongly condemned on moral grounds. In a confusion between the goal of perfection and the claim of infallibility, reproaches of intolerance, presumption, and arrogance, I learned, are easily made; one of my colleagues —admittedly of a rather orthodox Protestant background— characterized my aim of imparting a greater intellectual control to our students as indecent, immoral and dangerous (essentially because one should not put so much raw reasoning power at people's disposal). To my taste, such rejection smacks too much of a defence of mediocrity.

A much more serious objection is "Your dream has been proved to be unrealistic; great men, like Leibniz and Hilbert, for instance, have had similar dreams, and it did not work.". This is a much more serious objection, because now we have to give a technical reason why the current generation could succeed where previous ones failed. In the case of Leibniz, the general consensus is that, with his "Characteristica Universalis" and its "calculus ratinicator", he was at least two centuries ahead of his time. But why should we stand a better chance than, say, Hilbert and his contemporaries?

An undeniable difference between them and us is that their work predates the automatic computer, which is now with us for, say, four decades and is quickly becoming ubiquitous. If the "computer revolution" is really the revolution it is supposed to be, it should have a major impact on our perception of what the doing of mathematics could be. At the turn of the century, the reduction of mathematical reasoning to systematic formula manipulation —i.e., the manipulation of uninterpreted formulae— emerged as an intriguing possibility, but primarily as a possibility of something that could be done "in principle". For the first half of this century, mathematical logic was hardly used: mainstream mathematics felt entitled to ignore it as utterly impractical and the soul-searching logicians did not use it either because they were primarily engaged in exploring its limits. But the advent of the automatic computer has changed all that: when all is said and done, the systematic manipulation of uninterpreted formulae is the only thing these gadgets do for us. By their mere presence and our efforts at using them, they have really driven home the message of what is meant and implied by the manipulation of uninterpreted formulae. We now live in a different culture.

Let me report to you two personal experiences that made me aware of the extent of that cultural difference. The one was when —I guess around 1970— I read Polya's "How to solve it". I read it with sympathy and admiration because the topic was dear to my heart and because I was reading the work of a pioneer. In succession, I noticed the following reaction of mine: "It is nice, but also very dated.", "Obviously, he has never programmed.", and "He would have been an absolutely terrible programmer!". The other experience I had with Whitehead, who had my full sympathy for the eloquence with which he argued the advantages of "letting the symbols do the work". Can you imagine my utter amazement when, half a page later, he praises the mathematical community for economies it had obtained by the introduction of the invisible multiplication sign? The remark was very revealing, for it showed that he lived in a world upon which the full implications of systematic formula manipulation had hardly dawned.

These are just two of the many experiences that have convinced me that we do indeed live in a different culture and have a better chance than our predecessors. In particular, unfortunate former experiences with a more calculational approach should not deter us in our search for a teachable mathematical methodology since there is ample evidence —notational and otherwise— that formal techniques have never been given a fair chance.

Let me end this section with a somewhat sad anecdote. In the sixties —I was then with a department of mathematics— I conducted an investigation among my colleagues. I phrased it as a hypothetical question: "Suppose we knew how to give a solid two-semester course on Thinking, how would you feel about including it in our freshmen curriculum?". Asked in private, quite a few ended up with an answer along the line: "Well, if such a course could be given, I would personally be in favour of it but, to say the honest truth, I don't think the colleagues would allow it.". The last one happened to be faced with the question in public: he panicked and gave an impromptu harangue in which he began with arguing that such a course was obviously impossible and ended up this was precisely the type of course he had been giving all the time.

*               *
*

At first thought one might think that, in order to really sell the message, I should show the relevance of my considerations in mathematical areas as many and as varied as possible, but at second thought that suggestion has to be rejected.

Firstly, I find the underlying suggestion that the specialist is only willing to look at things that are presented in direct connection with his specialty rather offensive.

Secondly, the effort would be vain, for, in its diversity, the field of mathematics is so vast that no single person can be familiar with more than a negligible fraction of it.

Thirdly, the effort would be ill-directed because a few areas, almost all of them familiar to almost all of us, suffice to provide a carrier for an illustrative example. Extending the amount of mathematical knowledge and terminology involved would only make the book harder to write or to read.

Finally, I would prefer to maintain the distinction between the scientist and the salesman. I feel —and try to honour— a professional obligation to offer the fruits of my considerations and to do so as clearly as I can, but prefer to do so neutrally, on the basis "Take it or leave it.".

For all those reasons I tend to confine my universe of discourse to those domains that are reasonably familiar, such as Booleans, integers, reals, sets, graphs, and some Euclidean geometry. (At this stage I cannot promise that this enumeration will turn out to be exhaustive.)

In short, in the choice of mathematical areas, I accept the type of constraints accepted in Mathematical Olympics and similar contests. This choice could therefore easily create the impression that this book is primarily a guide to problem solving and that the youngsters preparing themselves for such contests are my primary target audience, but they are not. If I help them in their contest, that is fine, but I would like to help them in the rest of their mathematical lives.

This book is how to keep things as simple as possible, on what it means for arguments to be crisp, and how to make them so; it so happens that the knowledge of how to pursue these goals greatly enhances one's problem–solving ability, but the latter is a —be it welcome— byproduct.

My target is to write a book that deserves to be read slowly, not as slowly as it has been written, but markedly slower —say at half the speed— than the average technical text, not because I am aiming at a difficult text —on the contrary!— but because I hope to relieve the reader from the job of filtering out the noise by not including it. Whenever you notice that I fail to keep your full attention, you probably started skipping formulae —always the first victims— some time before. Put the book away and when you resume reading it, do it at an earlier point than where you stopped.

Above all, however, I hope that you will read the book with as much pleasure as I intend to write it with.

*               *
*

[To be completed later.]

Austin, 22 September 1989                     

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

Mathematical Methodology

transcribed by Mario Béland
revised Mon, 28 Jan 2008

EWD 1060

"Predicate Calculus and Program Semantics", fall 1989

Our position is —and has now been for a long time— that it does not suffice for a programmer to deliver a program text with the message "here is my program and I hope that people will like it," in very much the same way as a composer delivers his score with the message "here is my symphony and I hope people will like it". There is more to programming.

It does not suffice either if a programmer just says "here is my program and that is what it can do for you" if the latter claim has no convincing support and is therefore no more than a hope.

It is our position that a solid product consists of a triple: a program, a functional specification, and a proof that the program meets the functional specification. Design disciplines for such triples exist, but are not the topic of this course. (In the case of imperative programs, it is the topic of one of my courses.) Such proofs are based on laws about the programming language in question. This course is about such laws in the special case of imperative programming; for the sake of clarity we shall confine ourselves to what seem about the simplest programming languages that are still interesting.

Using "Hoare triples" to pose them, examples of such laws would be answer to such questions as

     Is

          {P } S {Q ∧ R }

the same as

          {P } S {Q } ∧ {P } S {R } ?

And, if so, does the same hold for conjunction's generalization the universal quantification, i.e. is —with dummy x over some range—

          {P } S {(∀x:: Q.x)}

the same as

          (∀x:: {P } S {Q.x}) ?

Because, in reasoning about programs, we rely on such laws all the time, one of our purposes is to put them on a firm footing. (For instance, the laws that Hoare originally postulated as inference rules will either be subsumed in the predicate calculus, or appear as theorems in our theory.)

If past experience is any guidance, the theory and the way in which it is developed will be most unfamiliar to most of you. It has, however, a major advantage over all alternatives I am aware of: it is so simple that almost all of its proofs need not be "discovered" by a spark of genius or a flash of insight but can be designed quite systematically. All of this convenience could only be reached by adhering all through the theory to a strict calculational proof format, and a major secondary purpose of this course has become to familiarize the student with the benefits that can be derived from a proper formalization, rendered in a notation that is geared to our manipulative needs. Whenever possible I shall draw attention to the conceptual and notational choices that made these simplifications possible. The core challenge of computing science has been summarized as "how not to make a mess of it"; it could very well share this challenge with formal mathematics.

Austin, 4 September 1989.

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Hasnain Mujtaba
revised Mon, 28 Jan 2008

EWD1066

Hungry? Have a byte....

On Tuesday morning a mr. Peled from IBM gave the keynote address at the Department's annual Research Review. Ten years from now, with fibre optics, 64Mbyte chips, computing power galore, and flat high-resolution colour screens, we would have the most fantastic machines all over the place and in high-bandwidth communication with us and each other. In this Walhalla, flow of information would provide the fuel for the economy. So that this Great Dream may become reality, he urged computer science research to concentrate on applications. All this was packaged in colour slides —computer-generated or not— of IBM laboratories, machine rooms and teapots; he even managed to smuggle in the two Nobel laureates from the Zürich laboratory.

The lecture was not up to par; I did not go to it with high expectations for I had never heard of mr. Peled —and I know why—, yet I was disappointed. But as phenomenon it was not without interest.

• Quoting one of my colleagues, the presentation was of the level of Newsweek; the characterization "fast food for thought" crossed my mind. To address an academic audience at that level is offensive. Yet our mr. Peled thought it appropriate. Could this be indicative for the industry's esteem for the academic enterprise?

• To call flow of information the "fuel" for the economy is ludicrous —it is lubrication at best—. His example was correspondingly unconvincing: a sales organization that bought what it could sell with profit. He displayed the attitude that sees nothing wrong in referring to banking and the stock exchange as "the financial industry".

• He was an undiluted advocate of "Big is beautiful, and more tastes better". At least four times he characterized the hardware explosion he predicted as "progress", blissfully unaware of the fact that the declining productivity of the American white-collar worker has convincingly been linked to over-automation of the office. If the suspicion that the ubiquitous personal computer actually represents a drain on the economy ever entered his head, he did not show it.

• His vision of the rôle of the academic enterprise was somewhat narrow. His view was purely technology-driven: the equipment was coming and it was therefore the duty of the universities to develop the applications that would enable the industry to push the equipment down our throats. He seemed totally unaware of the fact that the health of a flourishing science primarily depends on its internal structure (or of the fact that the parallelization of "old FORTRAN programs" is an activity void of scientific significance). There has been a time that we had to fight a battle on campus to prevent computing science from deteriorating into the art of living with the IBM/360, but the battle has been won more than a dozen years ago. Has this escaped mr. Peled's attention?

• The quality of today's mechanization leaves much to be desired. (Error correction increases the probability of wrong results, systems do crash, etc.; I do not need to elaborate.) All sorts of conceivable safeguards have never been explored because the amount of hardware needed was prohibitive. Can we use some of the surplus of hardware for improving drastically on the quality with which computations are mechanized? I expect this question to require the conceptualization of architectures very different from the von Neumann machine we have been rebuilding all the time and to raise some deep logical problems (for instance in the area of "type theory"). Pointing out that the pending gate glut might enable us to do things better and suggesting to explore how this opportunity could be exploited would have been a worthy advice to the scientific community. Instead mr. Peled suggested closer cooperation with industrial users..... He seems to live in a world unaware of Sir Hermann Bondi's verdict that of the problems encountered "out there", 80% is trivial and 20% is patently unsolvable.

• If I were his boss I would not have allowed him to give the impression that IBM Research was such an uninspiring —if not downright suffocating— place

*        *        *

Such silly talks should not be allowed. My main consolation is that only silly people follow silly advice.

Austin, 19 October 1989

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Austin at Texas
Austin, TX 78712-1188
USA

Transcription by Javier Smaldone.

Revised Mon, 28 Jan 2008.

  EWD 1067

A very first introductory example

Each morning a plant manager, who comes to work in a combined train/car ride, arrives by train at the railway station at 8:00 in the morning, where he is picked up by the company driver. Not wanting to keep his boss waiting nor liking to wait himself, the driver leaves the plant each morning so as to arrive exactly at 8:00 at the station.

One morning the manager happens to catch an earlier train, which arrives at the station at 7:00. Instead of waiting an hour for his driver to arrive, he starts walking to the plant. When he meets his driver on the road, he steps into the car and together they return to the plant. That day, the manager arrives at the plant 20 minutes earlier than usual. For long has the manager been walking? (As usual in such problems, each person or object moves at its own constant speed, events such as leaving the train or turning the car, are instantaneous, etc.)

Before reading on, you might want to tackle this problem yourself. If so, look now at your watch.

*                           *
*

The driver saved 20 minutes on the round trip, so he saved 10 minutes on his way out. He had planned to turn at 8:00, so this day he turned at 7:50. Hence the manager, who started at 7:00, walked for 50 minutes.

Some may think this solution cute, surprising, or ingenious, but I would like to point out that there is nothing ingenious about it, because the argument is all but forced. Let me show you how.

Since we know when the manager started walking, we have to determine when he stopped doing so. The only other definitions of that moment are the moment when the manager and driver met and the moment the driver turned. Moreover we know that we have to relate this moment to 8:00, the only other moment in the data. That day, the only significance of 8:00 is that it was the moment at which the driver had planned to turn. So the question has become: by how much was the driver’s trip to the station shortened? This interval has to be related to the only interval in the data, the 20 minutes the manager arrived earlier. This is also the shortening of the driver’s round trip, which is twice the amount by which his trip out was shortened, and now we have the solution. Experience has shown that people used to the above type of problem analysis solve this problem within 2 to 60 seconds.

There is another approach. One just introduces variables for all unknown quantities (car speed, train speed, walking speed of the manager, distance between plant and station, etc.), writes down as many equations as one can think of, and solves those equations, which are all linear, so that should be no problem. In practice it does.

Firstly, almost all our training in solving systems of equations dealt with systems in which all roots could be determined. Secondly, we have not been trained in how to be sure that we have written down all equations relating the unknowns.

The person following this approach typically grabs pencil and paper within 1 minute and complains a few minutes later that he has been given insufficient data, It is then very tempting —I never did— to give him more data like “Oh yes, sorry! I forgot to tell you that the manager’s train ride takes 30 minutes.” or “The distance between station and plant is 15 miles.”, thereby only adding to the confusion. His problem is, firstly, that by his random start he has lost track of what he really needs and, secondly, that he is under the misapprehension that, the more he knows, the better off he is.

In the latter approach, the solution requires at least 10 minutes, if reached at all.

*                         *
*

You may feel tempted to complain that this problem was too simple to deserve a whole chapter of what purports to be a serious book on mathematical methodology. Yet its inclusion is justified, for the simpler the problem, the more alarming the following observation: of the scientists the problem is posed to, the fraction that solves it within 1 minute is no more than a few percent. Evidently this little problem embodies some trap and we have not learned how to avoid being trapped by it; perhaps we have even been conditioned to fall into the trap. In any case it presents a reason why a book like this one seems so needed.

Austin, 19 October 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Mathematical Methodology

transcribed by Mario Béland
revised Mon, 28 Jan 2008

EWD1068

On the quality criteria for mathematical writing

My first months with my second employer were very frustrating: whatever I started to write disappeared before completion into the wastepaper basket, as it always seemed too terse or too tepid. This lasted until I had identified the underlying mechanism. Until that moment I had always at least subconsciously written with a very specific audience in mind, and all those months I had alternated between writing for my old buddies and writing for my new colleagues. With the former I had shared a common culture that was foreign to the latter; explaining that common culture and justifying its tacit assumptions was ridiculous when addressing the ones and indispensable when addressing others. Hence my bind.

My temporary solution was to select a few inspiring people from my new environment and to write mentally for them. Freeing myself from the habit of addressing a specific audience took me much longer. In the first stage I replaced the audience consisting of people I personally knew by a hypothetical audience with carefully postulated characteristics. As time went by, that audience faded away, only its just demands on my writings remained. One’s target audience has to fade away, one has to learn to write detachedly “to whom it may concern”, if writing is to become an integral part of one’s doing in mathematics, independently of whether one has publication in mind or not.

The remainder of this chapter is devoted to a description of the hypothetical audience I found the most rewarding to write for. The main rôle of this hypothetical audience is to serve as a frame of reference in terms of which we can phrase, explain, and justify its “just demands”. It is a main binding element for the many choices I have made, which pervade the rest of this book. By the end of this chapter I hope to have convinced my readers that theses choices are more than just personal whims.

*                            *
*

Assume our audience to be

• Large,

• Ignorant of the jargon and tacit assumptions that are specific to your topic,

• Sympathetic, curious, intelligent and demanding.

The assumption of a large readership is, of course, almost always wrong, but that is irrelevant. (By writing something intended for a large audience, one probably increases the expectation value of the number of people that will read it, but that is irrelevant too.) The assumption should be made for its wholesome influence on the writer. It discourages sloppy writing and it should discourage verbiage: with 100 readers, the overall efficiency of communication is served if an author’s hour spent on the careful phrasing of a passage saves his average reader one minute. The assumption of a large readership nicely invalidates the author’s excuse that such careful writing would take too much time, as this would now imply that the author’s time is much more valuable than the time of its readers which is an unacceptable proposition. Moreover, if wide adoption of the assumption of large readership would reduce scientific “productivity”, this would be a further gain.

Also the assumption of reader ignorance can be justified in the name of overall efficiency of communication. It is a plea to make your texts as self-contained as possible. If you have to use a technical term that can be defined in a single sentence, please include that definition: the reader that is already familiar with the term will have no difficulty in skipping that definition. Also, if you use infix operators, state their relative binding power so as to enable the unfamiliar reader to parse your formulae. Also, avoid undefined metaphors. Etc. The assumption of reader ignorance can be defined as a matter of mere politeness as well. Its importance, however, lies in its influence on the author.

If the explanation of all the jargon we feel tempted to use becomes too cumbersome, this is a warning not to be ignored: all too often, most of the jargon should not have been introduced in the first place, and the discipline of defining your terms helps in developing the habit of not introducing superfluities into your argument. Also, the discipline of stating explicitly how your formulae should be parsed is the best possible safeguard against the introduction of ambiguity in your formulae. Also, the temptation to escape from precise definitions into catchy metaphors should be resisted: invariably, he who introduces a “self-explanatory” term is its first victim.

Finally our target audience is postulated to be curious, sympathetic, intelligent and demanding.

Without curiosity, the audience is not inspiring. Without sympathy, it is depressing. It has to welcome well-considered notational innovations, new proofs for old theorems, papers in which the proof method is more important than the theorems, you name it. (I find little more depressing that the attitude that a mathematical paper is only worth writing if the “result” is new and thus “extends our mathematical knowledge”; it ignores that mathematics is more about simplifying than about problem solving or accumulation of facts. I am all in favour of Reusable Theorems, i.e., theorems that can be proved more than once.)

That the audience should be intelligent is obvious. To quote Strunk and White —mostly White in this case—: “No one can write decently who is distrustful of the reader’s intelligence, or whose attitude is patronizing.” The fact that I mention the intelligence explicitly is probably the result of my involvement in computing science, where many texts —and even the motivations underlying the research reported— are disgracefully condescending. Computer science suffers from a strong taboo on anything beyond the powers of comprehension of “the average programmer” and “the user”. These literary figures though morons, have been allowed to set the standard to the extent that much worthwhile research has not been attempted. We make our audience intelligent so as to avoid a similar paralysis in mathematics. Again the choice is made for the sake of the author: it liberates him from the pressure —from educationists or publishers— to resort to “the intuitive appeal of easy-to-understand pictures”.

Finally, our audience is as demanding as we can possibly conceive it. It wants the whole truth and nothing but the truth. It rejects noise, verbiage and needless complication. It favours brevity but rejects it when obtained by committing the sin of omission. (For practical purposes a useful criterion —which I owe to A.J.M. van Gasteren— is that our texts should be completely readable without pen and paper.) It does not like the author pulling ad libitum rabbits out of his hat. (“Rabbit” is the technical term for the unmotivated and surprising turn in an argument that eventually and miracously “does the job” but leaves the reader with the gnawing question of how, the hell, the trick was invented.) All these demands raise technical issues with which we shall deal in due time. Again, our audience makes these demands for the benefit of the author: for instance, the successful avoidance of rabbits amounts to the orderly design of otherwise surprising arguments.

As a last remark about the audience, it should be stressed that the audience is hypothetical. If you wish to view the writing of mathematics as a challenge in communication, it is you communicating with a piece of initially blank paper.

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Mathematical Methodology

transcribed by Mario Béland
revised Mon, 28 Jan 2008

EWD 1069

Fair gambling with a biased coin

Given a coin such that the two faces show up with probabilities p and q  (p+q = 1), can we generate a fair random sequence of 0s and 1s? If the coin is fair, i.e., p=�, q=�, the answer is simple: associate 0 with the one face and 1 with the other, and throw the coin once per digit to be produced. But what if the coin could be biased? Note that we are only given the possibly biassed coin, and not the actual p,q-values.

The only thing we can do with the coin is throwing it repeatedly. Our task is to design an experiment with two possible outcomes of equal probability.

Our first observation is that this endeavour is bound to fail if the coin is so extremely biased that one of the faces never shows up —i.e. p•q=0— , because in that case only one sequence of throws is possible and there cannot be two possible outcomes of the experiment. To phrase it differently: we have to design a deterministic algorithm intended to produce a 0 or a 1 when fed with a sufficiently long sequence of faces, but on a constant input sequence —i.e., all heads or all tails— the algorithm should fail to terminate. Because there are many such algorithms, we do some more observing.

Our second observation is that it does not matter which side of the coin we call “head” as long as we call the other “tail”. The simplest —and therefore standard— way of doing justice to such a binary symmetry is to consider pairs of faces, and to distinguish them according to being a pair of equal faces or a pair of different faces.

The combination of these two observations suggests to investigate the algorithm that starts

|[  | var x,y: face;
| repeat   | record throw in (x);
|  | record throw in (y)
| until x ≠ y |
; | ..... |

It fails to terminate if p�q = 0 —it has been designed that way— and, if p�q > 0, it terminates with probability 1. (The expectation value of the number of double throws is (p�q)⁻¹ .) Moreover it solves our problem, since the above can terminate in two ways, (x,y) = (head,tail) or (x,y) = (tail,head), and both outcomes are equally likely.

*         *         *

It took me very long to design the above solution. After having made the first observation but before having made the second one, I started to study all sorts of algorithms that failed to terminate on the constant input sequence. And that while the second observation is absolutely standard (vide the bichrome 6-graph). I find it shocking that at my age I allowed myself to be lured into the wild search I embarked upon. As soon as I became very stern with myself and told myself not to behave like an uneducated idiot, the above solution was designed.

The problem seems very well known; somehow I had missed it. I was quite thrilled by it! Making a fair “physical” coin is quite hard, for how does one establish that one has one? You cannot test it. Here we have a “mathematical” coin that is fair by construction! Two cheers for mathematics.

Inks Lake State Park,
on the 30th anniversary of my Ph.D.

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1070

For brevity's sake

Since the turn of the century, Russell's Paradox is a standard ingredient of all texts on the foundation of mathematics. Its purpose is to illustrate the trouble one can run into by admitting the seemingly innocent notion of "the set of all sets". We shall not pursue that trouble here, since this is not a book on the foundation of mathematics. Today we are not interested in Russell's Paradox, we are solely interested in its presentation. Being essentially a one-liner, it is a very simple example to make our point; it has the added advantage of being familiar to many. Its usual presentation is along the following lines.

A set may be a member of itself or not. Consider now the set of all sets that are not a member of themselves. Calling this set R, its formal definition would be

(0)     R = { x | x ∉ x }

—to be read as "the set of all sets x such that x ∉ x —. The question we now try to answer is: "Is R a member of itself?". Suppose that R is not a member of itself"; since, according to (0), R contains all such sets , R would contain itself, which contradicts our assumption that R is not a member of itself. Conversely, assume that R is a member of itself; since, according to (0), R contains only sets that are not members of themselves, R would not contain itself, which contradicts our assumption. So, our question "Is R a member of itself?" admits neither answer.

This concludes the first presentation of Russell's Paradox. Consider now the following alternative.

A set may be a member of itself or not. Consider now the set of all sets that are not a member of themselves. Calling this set R, the formal definition of membership of it would be

(1)      x ∈ R = x ∉ x     for all x     .

Instantiation of (1) with x:=R yields

R ∈ R = R ∉ R ,

which is a contradiction.

This concludes the second presentation of Russell's Paradox. It is so much shorter and simpler than the first one that we had better fully understand how this tremendous gain could be obtained.

A major difference between (0) and (1) is that (0) states the equality

R = { x | x ∉ x } ,

in which x is a "bound variable" —i.e., local to the right-hand side— whereas (1) states the equality

x ∈ R = x ∉ x

in which x is a "free variable" —i.e., global to the whole expression—. The latter equality can now be instantiated by substituting an arbitrary set for x! The latter manipulative freedom is exploited to great advantage by the instantiation x:=R. Instantiation is a very simple operation, and the example suggests that free variables in definitions (axioms, theorems, etc.) are an asset. (Later examples will confirm this as yet tentative moral: the availability of free variables can significantly contribute to the economy of manipulation.)

Another major difference between (0) and (1) is the different status of their equality signs. In (0), the equality sign expresses equality between sets and is only acceptable after sets have been admitted as first-class citizens; in (1), the equality sign expresses equality between boolean expressions and is only acceptable after boolean expressions have been admitted as "first-class citizens". Let me explain what is meant here by "first-class citizens".

Prior to the introduction of the boolean domain, people used what we now recognize as boolean expressions, but they were viewed as statement of facts  — 3<4 —  or as condition — x>0 —  or as equation  — x²+bx+c=0 —  or as laws  — (a+b)²= a²+2ab+b² —  , and things like 3>4, 2+2=5 and n=n+3 were considered "wrong". All this changed with the introduction of the two-element boolean domain {true, false} which provides the vocabulary needed to assign values to boolean expressions: 3<4 is a way for writing true, 3>4 is a way for writing false , whereas the value of x>0 depends on the value of x: for positive x it yields true, for nonpositive x it yields false. As syntactic units, boolean expressions existed after 1558, when Robert Recorde introduced the now familiar equality sign = as infix operator; they became "first-class citizens" in 1858, when George Boole introduced the possibility of evaluating them.

In retrospect, one might be tempted to regard the introduction of something as simple as the boolean domain as a minor invention, but I think that that would be a grave mistake: it is a great invention because, being so simple, it is such a powerful simplifier. It is of the same level as the introduction of natural numbers, which enabled us to add 3 to 5, regardless of whether we are adding apples or pears.

George Boole made a radical invention, so radical, in fact, that now, more than a century later, the scientific community has not absorbed it yet. (To stay with the metaphor: officially, boolean expressions may have reached the status of first-class citizens, in practice —because old habits and prejudices die hard— they are still the victims of discrimination.) Let me give you a few examples.

In the programming language FORTRAN, as conceived a century after Boole published his invention, boolean expressions are allowed, but there are no boolean variables! Their introduction into programming had to wait until the design of ALGOL 60. (In fact, the inclusion of boolean variables and operators has been one of the main reasons for the educational significance of ALGOL 60; the inclusion of recursion was another reason.) Very tellingly, their inclusion as first-class citizens did not prevent programmers —even programmers that had skipped FORTRAN— from writing

if h ≥ N then eq:= true else eq:=false

instead of the so much crisper

eq := h≥N

or from writing

if eq ≡ true then . . .

instead of the simpler

if eq then . . .

Not only as programmers, but also as mathematicians we have to learn to avoid such spurious case analyses and superfluous comparisons.

Another example of the slow acceptance of the boolean domain is provided by the tacit assumption of the mathematical community that the Pythagorean Theorem is a theorem about right-angled triangles. But is it? In the usual terminology for sides and angles it states

γ=90° ⇒ a²+b²=c²

and the right angle seems to stare you in the face. But everyone familiar with boolean expressions knows that the above has the same value as

a²+b²≠c² ⇒ γ≠90°

The Pythagorean Theorem is a theorem about all triangles (and there exists a nice, elementary proof of it for which the complementary picture displays an arbitrary triangle).

The last remark to be made about the two presentations of Russell's Paradox is that the instantiation of (1) enabled us to establish the contradiction without the case analysis of the first presentation.

*                *
*

In the last programming example from ALGOL 60 I wrote eq ≡ true , using ≡ to denote equality of boolean operands rather than the = I used before. In a moment we shall see why a special equality sign in the case of boolean operands could be justified. For this purpose, I turn to a problem I owe to Roland C. Backhouse.

We are shown a golden vase and a silver vase, each carrying an inscription. We are told that one of the two vases contains a treasure, placed so that the two inscriptions don't lead to a contradiction. The two inscriptions are:

on the silver vase: | "The treasure is not in this vase."
| and
on the golden vase: | "Of these two inscriptions precisely 1 is true."

Can we locate the treasure?

Denoting the truth values of these two statements by S and G respectively, the challenge is to determine the value of S. To this end we turn to the inscription on the golden vase, which in this terminology can be rephrased as

(2)     S ≡ ¬G

(The symbol ¬ denotes negation, and saying that of two boolean values precisely 1 is true is the same as saying that the one is the negation of the other.)

Expression (2) being a formalization of the statement we had defined to have the same value as G, we conclude

(S ≡ ¬G) ≡ G

Besides being symmetric, the operator ≡ , denoting equality of boolean operands, has the nice property of being associative, i.e., it does not matter how we place the parentheses, and our conclusion could also have been formulated as

(3)     S ≡ (¬G ≡ G)

which immediately yields

S ≡ false,

i.e., the treasure is in the silver vase.

Equation (3) in the unkowns S and G determines the value of S, but leaves the value of G undetermined. The above argument is so short because it avoids a spurious case analysis on the irrelevant value of G.

In a way, this example is very similar to the previous one: they both employ

¬X ≡ X ≡ false ,

whatever the value of X (thereby avoiding an avoidable case analysis). It has been included because it illustrates more.

I would like you to know that when I called the above argument —which has been designed by G. Wiltink— "so short". I did not exaggerate. Backhouse draws attention to the fact that about two dozen steps are required if one tackles this problem in the style of Gentzen's "Natural Deduction", whereas Wiltink solves the problem in two (no less formal) steps. Backhouse concludes from the two dozen steps "It is clear from this example that a large amount of detail is required in a completely formal proof".

Wiltink's alternative strongly suggests that Gentzen, who tried to formalize "the natural way of drawing conclusions" —in German: "das natürliche Schliessen"—, neglected the economy of manipulation. (Before having seen Wiltink's alternative, Backhouse already suspected something of this sort: the quoted problem and its cumbersome solution occur in a section, tellingly titled "Natural Deduction?".) I am afraid that by neglecting the economy of manipulation, Gentzen has done the mathematical community a disservice: calculational proofs have got an undeserved bad name.

The fact that equality between boolean operands is associative, i.e., has a property not enjoyed by equality in general, justifies a special name and a special symbol for it. A usual name is "equivalence" and a usual symbol is "≡". I adopt both and propose to pronounce the symbol as "equivales".

Remark One also encounters the symbol "⇔", pronounced as "if and only if", but I shall not follow that example. Symbol and name promote the view of equivalence as a shorthand for mutual implication, and it is precisely that view that tends to induce the case analyses that I would like to avoid. Moreover the "if and only if" linguistically hides the associativity of the equivalence so effectively that many people are unaware of it. Just try to understand the sentence "John sees with both eyes if and only if he sees with one eye if and only if he is blind." . According to all linguistic standards, this sentence is, by virtue of its syntactic ambiguity, total gibberish. (End of Remark.)

Wiltink's solution for locating the treasure makes one more thing clear. It shows that it does not suffice to be familiar with just the idea of the boolean domain. To really reap the benefits, we also have to be familiar with the boolean operators —such as equivalence, negation, etc.— and with their algebraic properties —such as symmetry, associativity, etc.— . Acquiring that familiarity requires what in these financial times is known as "intellectual investment"; you can take my word for it that this investment quickly pays off.

Austin 15 November 1989

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

_____________
Mathematical Methodology

transcribed by Mario Béland
revised Mon, 28 Jan 2008

Copyright Notice

The following manuscript,

EWD 1071: Making a fair roulette from a possibly biased coin

was published as

Information Processing Letters 36: 193, copyright � 1990.

It is reproduced here by permission of the publisher, Elsevier Science.

Single copies of the manuscript may be downloaded and printed for the reader�s personal research and study.

EWD 1071

Making a fair roulette from a possibly biased coin

We are given a possibly biased coin, that is, a coin that, when flipped, shows head or tail with the probabilities p and q respectively, with p+q = 1 but not necessarily p=q. We don't know the values of p and q, we only know that the coin remains “the same”, i.e., that p and q are constant in time. The problem is to design an experiment with 37 different outcomes of equal probability.

In a variable A of type “sequence of 37 faces”, we record 37 flippings of the coin; if all the faces in A are the same, we start afresh, otherwise we accept the value of A. This first stage of the design is inspired by (i) the consideration that the experiment has to fail (to terminate) if the coin is so extremely biased that one of the faces never shows up, and (ii) the fact that (Fermat) 2³⁷-2 is a multiple of 37.

With A thus determined, we consider the sequences   rot.k.A   for 0 ≤ k < 37, where   rot.k.A   is obtained by rotating A over k positions (to the left say). Because A is not periodic with period 1 and 37 is prime, the 37 sequences   rot.k.A   (0 ≤ k < 37) are all different. Moreover, since they all contain the same number of heads (and the same number of tails), they are 37 equally likely A-values. And this solves our problem but for a convention that establishes a 1–1 correspondence between those 37 sequences and the numbers from 0 to 36, e.g. the value of k for which   rot.k.A   is the lexical minimum, i.e., with A thus determined, we deliver   r   satisfying

0 ≤ r < 37   ∧   (∀k: 0 ≤ k < 37:   rot.r.A ≼ rot.r.A)   .

Remark   In the above analysis it is irrelevant that the coin has only 2 faces; with a possibly loaded die, one can proceed in exactly the same manner. Essential use has been made of the primality of 37, but the generalization to a composite number is not difficult: we can make a fair die out of a fair binary roulette and a fair ternary roulette. (End of Remark.)

Austin, 15 November 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

Copyright Notice

The following manuscript,

EWD 1071: Making a fair roulette from a possibly biased coin

was published as

Information Processing Letters 36: 193, copyright � 1990.

It is reproduced here by permission of the publisher, Elsevier Science.

Single copies of the manuscript may be downloaded and printed for the reader�s personal research and study.

EWD 1071a

Making a fair roulette from a possibly biased coin.

We are given a possibly biased coin, i.e., a coin that, when flipped, shows head or tail with the probabilities p and q respectively, with p+q = 1, but not necessarily p=q. We don't know the values of p and q, we only know that the coin remains “the same”, i.e., that p and q are constant in time. The problem is to design an experiment with 37 different outcomes of equal probability.

In a variable B of type “sequence of 37 faces”, we record 37 successive flippings of the coin; if all the faces in B are the same, we start afresh, otherwise we accept the value of B. This first stage of the design has been inspired by (i) the consideration that the experiment has to fail (to terminate) if the coin is so extremely biased that one of the faces never shows up, and (ii) the fact that 2³⁷-2 is a multiple of 37. (One of Fermat's theorems states that for prime p, np-n is divisible by p.)

With B thus determined, we consider the 37 sequences obtained by rotating (to the left, say) for   0 ≤ k < 37   the sequence B over k positions. Because B is not periodic with period 1 and 37 is prime, these 37 sequences are all different. Moreover, since they all contain the same number of heads (and the same number of tails), they are 37 equally likely B-values. To complete our design, we have to introduce a convention that establishes a 1–1 correspondence between those 37 sequences and the numbers from 0 to 36. We can, for instance, associate with B the number of positions B has to be rotated over so as to yield the lexical minimum of those 37 sequences. (With 37 replaced by 2, the above yields a well-known method for making a fair coin from a possibly biased one.)

Remark   In the above analysis it is irrelevant that the coin has only 2 faces; with a possibly loaded die, one can proceed in exactly the same manner. Essential use has been made of the primality of 37, but the generalization to a composite number is not difficult: we can make a fair die out of a fair binary roulette and a fair ternary roulette. (End of Remark.)

Austin, 21 November 1989

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1072

On covering a figure with diamonds

In the American Mathematical Monthly (May 1989, pp.429–431), under the title “The Problem of the Calissons”, Guy David and Carlos Tomei present the theorem given below. Before formulating the theorem, we introduce some terminology.

We consider a regular triangularization of the Euclidean plane, the grid lines of which cut up the plane into equilateral triangles with sides of length 1; in the following, “triangle” refers to such an equilateral triangle. Note that triangles occur in two orientations and that we can colour them accordingly, e.g.

A pair of differently coloured triangles that share a side is referred to a “diamond”, and a moment’s reflection tells us that each diamond has one of three possible orientations, viz.

A “figure” is a finite set of triangles; a “covering”of a figure is a partitioning of the figure’s triangles into diamonds.

The theorem presented by David and Tomei states that in any covering of a regular hexagon with sides of length   n   (and comprising 6n� triangles), the diamonds occur in the three orientations in equal numbers.

*         *         *

Because of the rotational symmetry of the hexagon, the above theorem is an immediate consequence of the following one.

Theorem   Consider a figure that admits one or more coverings. Each covering yields a triple of frequencies, each counting the diamonds in one of the orientations. All coverings of the figure considered yield the same triple.

With the aid of some colleagues, we found for the latter theorem an argument so sweet that it was submitted to the AMM and accepted for publication. But then I withdrew it when I learned that undergraduate students at the Pontif�cia Universidade Cat�lica do Rio de Janeiro knew the following, much shorter proof.

Consider a covering of the figure. Draw in each diamond a vector from the centre of its white triangle to the centre of its black triangle. Denote the three possible vectors by   ξ,η,ζ   and the triple of their frequencies by  x,y,z . By adding all these vectors in the covering of the figure, we get the vector equation

x∙ξ + y∙η + z∙ζ = (the sum of the black centres) – (the sum of the white centres) .

Moreover we have the scalar equation

x + y + z = half the number of triangles in the figure .

These three independent linear equations in x,y,z have right-hand sides wholly determined by the figure, and hence determine the triple of frequencies independent of the covering.

I thought the above, as yet anonymous argument too beautiful not to be publicly recorded.

Austin, 9 December 1989

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA.

transcribed by Corrado Cantelmi
revised 29-Nov-2011

EWD 1073

How Computing Science created a new mathematical style

by
Edsger W. Dijkstra
University of Texas at Austin

To begin with, I would like to talk to you about equality. I don't know how you were introduced to the notion, I don't even remember how I was introduced to it myself. In our earliest memories, the notion was already there, and all of us must have appealed almost subconsciously to its obvious properties such as symmetry and transitivity. i.e., for all x, y, z

(0) | x = y   ≡   y = x               , and

(1) | x = y  ∧  y = z   ⇒   x = z         ,

respectively. But what status should we give to those mathematical facts we grew up with? Do we make them postulates or theorems?

I am perfectly willing to accept equality's symmetry as a postulate, in fact I prefer it that way. I prefer to view equality as defined on an unordered pair. (I similarly prefer products to be defined on bags of factors rather than on sequences of factors. In the last case, one of the first things one has to do is to point out that as far as the value of the product is concerned, the order in which the factors occur in the sequence is irrelevant. Why then order them in the first place?) The presence of (0) as rewrite rule merely reflects the absence of a canonical representation for the enumerated unordered pair which forces upon us the irrelevant choice between writing x=y or y=x.

Equality's transitivity, however, I prefer to prove. Equality and function application are closely tied by Leibniz's Principle, i.e., the postulate that function application is equality-preserving: for all x, y, f of the appropriate types

(3) | x = y    ⇒    f.x = f.y

It is understood that expressions can be viewed as functions applied to their sub-expressions, so that

| a = b     ⇒    (a+3)² = (b+3)²

is an instantiation of (3) —without invoking the whole mechanism of the λ-calculus—.

Leibniz's Principle (3) can be rephrased equivalently by stating that for all x, y, z, f of the appropriate types

(4) | x = y    ∧    f.y = z       ⇒      f.x = z

(a kind of reformulation we shall return to later). Instantiation of (4) with for f the identity function yields (1). In other words: the transitivity of equality is a special case of Leibniz' Principle.

The links between equality and function application are very strong: function application preserves equality, conversely: apart from the constant relations true and false, equality is the only relation that is preserved by function application. In the many formal proofs I designed, Leibniz' Principle is invoked all the time and I believe that the only use I make of the notions of equality and of function application is in appeals to Leibniz's principle.

It is a style of doing mathematics that is rather different from what was deemed acceptable only two decades ago. In his book Graphs and Hypergraphs (1970), Claude Berge introduces the following graph

and then is willing to code the fact that arc 9 goes from c to d as

| 9 = (c,d)      ;

this notational convention is asking for trouble since it allows us to deduce from the picture 2 = (a,b) and 3 = (a,b), from which 2 = 3 follows!

I think we all agree that Berge's convention is a misuse of Recorde's equality sign. We may have different opinions as to how serious this misuse is. The classical defence of a notation like Berge's is that everybody knows what is meant and that no one worth his keep will derive such obvious nonsense as 2 = 3 . Fair enough, but beside the point. A fundamental and therefore potentially much more serious objection is that such notational conventions create environments hostile to derivations by formula manipulation. We shall return to the possible weight of this objection later, staying a little bit longer with the equality.

It may surprise us at first sight that a relation so simple and familiar as equality has created all sorts of problems, but it has created them precisely because of its familiarity. Since antiquity, mathematicians have never been sure how to indicate it, if it had to be indicated at all: sometimes it was done verbally, sometimes by an acronym of such verbal statement, sometimes equal expression on a page were connected by a line, often there was no more than juxtaposition. The more interesting history of the equality starts 4 centuries ago, in 1557, when Robert Recorde designed the equality symbol as we know it today. It had to wait for more than a century until Leibniz (1646-1710) formulated its crucial property. It had to wait 3 centuries, viz. until 1854, before it acquired in the hands of George Boole the full status of an infix operator that makes A=B an expression which may take on a value. And the speed with which the world can absorb improvements is limited. A century later, the boolean domain was still a second-class citizen of the mathematical world. My comment on Berge's convention is the following: in view of the fact that it has taken the equality sign more than 400 years to occupy in mathematics the position it deserves, we should consider it a mathematical treasure to be protected from pollution.

Let me now illustrate what we can do with the equality and its transitivity when its operands are boolean. In that case it is not unusual —though regrettable— to pronounce it as “if and only if”, as in the following

Theorem (C,<) is well-founded if and only if mathematical induction over C with respect to < is a valid proof technique. (End of Theorem.)

The pronunciation “if and only if” suggests that such a theorem has to be proved by mutual implication, i.e., by demonstrating that either side follows from the other. That such is not the case is shown by the following calculation; for the first transformation one needs to know that well-foundedness means that each non-empty subset contains a minimal element, for the next two predicate calculus suffices, and the last one appeals to the definition of mathematical induction. In the following calculation

• dummies x and y are elements of C

• dummy S is a subset of C

• dummy P is a predicate on C .

| (C,<) is well-founded
= |      {definition of well-foundedness}
| (∀S :: (∃x :: x∈S)) ⇒ (∃x :: x∈S ∧ (∀y : y<x : y∉S))
= |      {contrapositive and Laws of de Morgan}
| (∀S :: (∀x :: x∉S)) ⇐ (∀x :: x∉S ∨ (∃y : y<x : y∈S))
= |      {transforming the dummy: S = {x| ¬P.x}, P.x ≡ x∉S}
| (∀P :: (∀x :: P.x) ⇐ (∀x :: P.x ∨ (∃ y : y<x : ¬P.y))
= |      {definition of proof via mathematical induction}
| mathematical induction over (C,<) is valid .

This is not the place to discuss the above proof character by character. Its combination of brevity and completeness is unsurpassed. (Less than 40 years ago, the proof of this theorem has required two lectures of 45 minutes each: one for each direction of the implication.) Moreover, its design requires no more than experience in formula manipulation.

As next example we show how taking the maximum distributes over taking the minimum. Denoting the maximum of x and y by x↑y and their minimum by x↓y, the theorem to be proved is that for all x,y,z.

(5) | x↑(y↓z)   =   (x↑y) ↓ (x↑z)     .

We use for the definition of ↑ and ↓ that for all a,b,w

(6) | w ≥ a↑b     ≡    w≥a ∧ w≥b

(7) | w ≥ a↓b    ≡    w≥a ∨ w≥b

and in view of the above we prove equality by using

(8) | a = b     ≡    (∀w :: w≥a ≡ w≥b)

To demonstrate (5), we observe for any x,y,z,w

| w ≥ x↑(y↓z)
= |      { (6) with a,b := x,(y↓z) }
| w ≥ x  ∧  w ≥ y↓z
= |      { (7) with a,b := x,z }
| w ≥ x  ∧  (w ≥ y  ∨  w ≥ z)
= |      { predicate calculus, in particular: ∧ distributes over ∨}
| (w ≥ x  ∧  w ≥ y)  ∨  (w ≥ x  ∧  w ≥ z)
= |      { (6) with a,b := x,y and a,b := x,z}
| w ≥ x↑y  ∨  w ≥ x↑z
= |      { (7) with a,b := (x↑y),(x↑z) }
| w  ≥  (x↑y)↓(x↑z) ,

which, in view of (8), proves (5).

A few things should be remarked about this argument, besides the fact that it avoids all case analyses and beyond definitions (6) and (7) does not use a single property of the relation ≤ . Like the argument about mathematical induction it makes extensive use of the notion of equality of boolean expressions. Like reformulation (4) of Leibniz's Principle, our formulae (6), (7), and (8) contain a dummy more than perhaps expected. Such "extra" dummies give us more manipulative freedom, and they are often the key to surprisingly crisp arguments. (It helps to know besides (8)

(9) | a ≥ b   ≡   (∀w :: w ≥ a  ⇒  w ≥ b) .)

To close this section, let me tell you an experiment all of you can take when you are home again. Ask the average —and even not so average— mathematician to prove or refute for real a,b

| a+b ≥ max(a,b)   if and only if  a≥0 ∧ b≥0

and you will be surprised by the inefficiency of his argument compared to

| a+b ≥ a↑b
= |      { (6) with w := a+b }
| a+b ≥ a ∧ a+b ≥ b
= |      { arithmetic }
| b≥0 ∧ a≥0

The explanation for the usual inefficiency of the argument is that it starts with a definition of max like

|  | ⎧ a if a ≥ b
| max(a,b)   = | ⎨
|  | ⎩ b otherwise ,

a definition which is not nice to manipulate, and therefore invites case analysis. (As my Eindhoven colleague W.H.J. Feijen, to whom I owe this example, writes in reference to the above definition: "The reader should try to use it in proving the associativity of max".).

*                       *
*

I hope that the above little examples give you some idea of the calculational style of reasoning that computing science developed and adopted, but before we try to estimate the wider significance of that development, we had better understand why computing science chose that path.

There is a combination of reasons, ranging from need to opportunity.

The need emerged because computers are so unforgiving: They execute programs as written, and not programs as dreamt. Getting our software correct turned out to be surprisingly hard. Closer scrutiny revealed that it was not just a matter of inaccuracy, of typing errors that better proofreading would have caught. The situation was much more serious: the programming challenge confronted us with a type of complexity we did not know how to cope with. If the amount of reasoning that a program requires for its justification explodes with the program length, only the tiniest programs will be free of bugs!

Computing scientists quickly discovered that the amount of reasoning required could critically depend on nature and structure of the interfaces between modules; the competent system designer therefore designs his interfaces with the utmost care. In mathematics, definitions and theorems are interfaces; they should be chosen with similar care, but are they? Not always. (Hardy and Wright: “Every positive integer, except 1, is a product of primes”, Harold M. Stark: “If n is an integer greater than 1, then either n is prime or n is a finite product of primes.”. These examples —which I owe to A.J.M. van Gasteren— both reject the empty product, the last one also rejects the product with a single factor.)

The other technique used to reduce the amount of reasoning needed was not to try to prove the correctness of existing programs, but to design correctness proof and program together. More precisely: one designs the correctness proof and derives the program from that proof. (That then the correctness proof tends to be simpler than the correctness proof for an intuitively conceived program is not surprising. What is surprising is that such proof-driven programming often leads to the more efficient program.)

Next I ask you to realize that, by virtue of the possibility of mechanical interpretation, each programming language represents a formal system (of sorts). That means that programs can —and in a way have to— be viewed as formulae. In the previous paragraph I spoke about “deriving programs from proofs”; we now see that that means that formulae have to be derived from the proofs. Without further detail, the above should explain why formula manipulation is so often the computing scientist's preferred way of proving the theorems.

This preference is also understandable in the light of the rest of his professional experience. If we believe Halmos, the manipulation of uninterpreted formulae plays a very minor role in the life of the classical mathematician: he has not been trained to do it, he does not like it, and he is not sure that he considers calculational proofs really convincing. The manipulation of uninterpreted formulae is, however, a most familiar operation for the computing scientist: it is the one and only operation computers are very good at.

Moreover, the computing scientist is spared an emotional barrier. Almost all formalisms used daily by the classical mathematician are at least ambiguous. But that does not hurt the classical mathematician because he does nothing with a formula without interpreting it and part of his professional competence consists in subconsciously rejecting all unintended interpretations. (If you show him

| sin(α+β)      versus       sin(s+i+n) ,

it depends on his sense of humour whether he is amused.) The manipulation of uninterpreted formulae requires unambiguous formalisms; I have observed more than once that the classical mathematician experiences such disambiguations as irritating priggery. The hurdle is understandable, but the computing scientist has taken it a long time ago.

*               *
*

How relevant is the above mathematical experience of the computing scientists for mathematics in general? Rather relevant I think, and I do so for mainly two reasons.

The one reason is that the calculational proofs are almost always more effective than all informal alternatives, the other reason is that the design of calculational proofs seems much more teachable than the elusive art of discovering an informal proof.

Let me elaborate on the first reason first. When I called calculational proofs more “effective”, I meant that they tend to be shorter, more explicit, and so complete that they can be read and verified without pencil and paper. To find the calculational proofs we had to design so effective was a very pleasant surprise, and it was a surprise indeed, because we too had been subjected, over and over again, to the rumour that formal methods were too clumsy to be used in practice. My conclusion is that that rumour is wrong.

I think I know how the misconception of this rumour emerged: the initial experiences with formality were very discouraging indeed. These unfortunate experiences were due to our lack of manageable formalisms geared to our manipulative needs and to our lack in expertise in using formalisms. Our disappointing experiences with formality should not be interpreted as something being wrong with formality; the experiences were disappointing because we were incompetent amateurs. But this has been changed by our exposure to computing because experience gained there can indeed be carried over to mathematics in general. Let me give you two examples.

In order to prove that a compiler currently parses the program texts it processes, one needs a formal grammar for the syntax of the programming language in question. To formal language theory we owe the distinction between grammars that are “context-free” and those that are not. Next we observe that the manipulating mathematician does not manipulate just strings of symbols but manipulates formulae parsed according to the underlying grammar. Since the parsing problem is simpler for context-free grammars, the moral is simple: choose for ones formalisms context-free grammars.

The other example is the notion of abstract data types —stacks, trees, permutations, bags, configurations, what have you—. Identifying an appropriate data type and some operations on it is often essential in preventing a program form becoming totally unwieldy. In exactly the same way calculational proofs of the desired brevity and clarity can often be obtained by the use of a specifically designed, special-purpose calculus. I said “exactly the same way” because I see no difference between the virtues of a data type in a program and the virtues of a calculus in a proof.

That concludes what I wanted to say about the effectiveness of calculational proofs. Let me now turn to the second reason why I think that our experience with calculational proofs is relevant, viz. the teachability of their design.

Compared to the stern discipline of formality, informal mathematics is a free-for-all. Because of the very strict requirements a formal proof has to meet, the design of a formal proof is widely felt to be a more demanding task than the design of an informal proof.

This feeling, however, is not justified: formal proofs are in a very precise way easier to design than informal ones. Because the requirements of formality restrict our freedom, we have fewer options for trials that turn into errors: our “search space” has been reduced, and that helps. Furthermore, accepting the requirements of formality means reducing the bandwidth of what we have to write down, a bandwidth reduction that allows us to adopt for our calculations a strict format. The advantages of such a strict format are considerable. Firstly, it makes proofs of different theorems more similar, and also the tasks of designing those proofs: problems from different areas can easily lead to similar challenges in formula manipulation, thus increasing the probability that the proof design can be guided by the same heuristics. Secondly, the strict format makes that many a design decision can be taken on syntactic grounds alone.

Let me give you an example. I know that it may be too simple to be impressive. It has the advantage that it can be related to the material mentioned before.

Let function f distribute over max, i.e. for all a,b

(10) | f.(a↑b)   =   f.a ↑ f.b      ;

show that f is monotonic, i.e. for all x,y

(11) | x ≥ y   ⇒   f.x ≥ f.y          .

The proof uses how to express ≥ in terms of ↑, i.e., for all a,b

(12) | a ≥ b     ≡    a = a↑b

| f.x ≥ f.y
= |      {(12) with a,b := f.x , f.y}
| f.x = f.x ↑ f.y
= |      {(10) with a,b := y,y}
| f.x = f.(x↑y)
⇐ |      {Leibniz}
| x = x↑y
= |      {(12) with a,b := x,y}
| x ≥ y

It is worth noticing that this proof is forced. Look at our proof obligation (11). Going from consequent to antecedent, two f applications have to be eliminated, so we have to apply the Principle of Leibniz, because that is the only one that can achieve that for us. The structure of the proof is now dictated: (11)'s consequent has to be massaged into the equality of two f-values, and after the elimination of the two f-applications, the equality sign has to be eliminated. Moreover, we have to use (10), which mentions ↑, which does not occur in (11). So, as =, ↑ has to be introduced and eliminated again. This raises the question: how can we exchange an ≥ for an ↑ and an = ? Formula (12) gives the answer; if we don't know it, we can decide most of its structure beforehand: for the sake of applicability of (10), the right-hand side of (12) has to contain a↑b. The proof of (12) is left as an exercise to the reader; besides predicate calculus and (6), he needs that ≥ is reflexive and antisymmetric, i.e. for all a,b

| a=b    ≡    a≥b ∧ b≥a

*               *

*

When your Mathematische Gesellschaft in Hamburg was founded, your countryman Gottfried Wilhelm Leibniz was in the prime of his life. For centuries, his dream that calculation should provide an alternative to human reasoning remained a dream. I hope to have shown you how the existence of automatic computers and the challenge of using them has changed this: simplifications that Leibniz had in mind are now within reach. The moral of my story is that if we treat our formalisms with the care and respect that we pay to our other subtle artifacts, our care and respect will be more than rewarded. Calculemus!

I thank you for your attention.

                Austin, 4 March 1990

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Xah Lee
revised Thu, 4 Nov 2010

EWD 1076

From "Discrete Mathematics with Applications" by Susanna S. Epp.

On p.439 of her recent book Discrete Mathematics with Applications, Susanna S. Epp presents the following problem:

There are 42 students who are to share 12 computers. Each student uses exactly one computer and no computer is used by more than six students. Show that at least five computers are used by three or more students.

My solution:

Let k be the number of computers serving at least three students; as each computer serves at most 6 students, these k machines serve at most 6k students. Each of the remaining 12–k computers serves at most 2 students; the remaining machines therefore serve at most 24–2k students. Adding these results, we conclude that the number of students served is at most 24+4k 

Since 42 students are served, we conclude 42 ≤ 24 + 4k or 18 ≤ 4k and, since k is integer, 5 ≤ k, which completes the proof.

The author of the book, however, proceeds as follows:

Solution:

[Use an argument by contradiction.] Suppose that only four computers were used by three or more students. [A contradiction must be derived.] At most six students are allowed to share any computer, making a total of at most 24 students using these four computers. Since there are 42 students in all, that would leave at least 18 students to share the remaining eight computers with no more than two students per computer. But the generalized pigeonhole principle guarantees that if 18 students share eight computers, then at least three must share one of them. [The pigeons are the 18 students, the pigeonholes are the eight computers, and 18 > 2 ∙ 8.] This is a contradiction. thus the supposition is false, and so at least five computers are used by three or more students.

This is not the kind of proof I encourage my students to write; they could, in fact, immediately recognize it as not written by one of them:

(i) | for the avoidable reductio ad absurdum;
(ii) | for the two occurrences of “must”, which they have learned to avoid —“A contradiction has to be derived” and “then at least three share one of them”—
(iii)   | for the loose “This” in “This is a contradiction.”.

Upon somewhat closer inspection they should see that the argument as given by Epp does not hold water: it does not exclude that only three (or fewer) computers serve three or more students. The above “solution”contains a bug so serious that it sends the author back to the drawing board.

I am very grateful to Susanna Epp for her bug. You see, her book is no joke. As she wrote in her covering letter to me: “This book represents a serious effort to reveal the unspoken, often unconscious, conventions of mathematical thought to the uninitiated.”, a characterization that is fully confirmed by the book. As such this little incident confirms my suspicion that “the unspoken, often unconscious, conventions of mathematical thought” are not good enough.

Austin, 27 March 1990

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1083

The balance and the coins

All true coins have the same weight, a false coin is too heavy or too light. Given (3n-1)/2 coins of which at most 1 coin is false, we have to determine whether they are all true, and, if not, we have to identify the false coin and to determine whether it is too heavy or too light. Our equipment consists of an additional coin known to be true and a balance that may be used for n weighings.

Let us denote (3n-1)/2 by s.n. Then s.(n+1) = 3∙s.n + 1. We show how to solve the problem for s.(n+1) coins in n+1 weighings in terms of a solution of n weighings for s.n coins.

Our first weighing involves 2∙s.n + 1 of the coins to be investigated. With the balance we compare s.n+1 of those with the other s.n, complemented with the coin known to be true.

If the two sets are of equal weight, we use the remaining n weighings to solve the problem for the s.n coins that have not been on the balance yet.

If the two sets are of different weight, we have 2∙s.n + 1 suspect coins, more precisely, s.n+1 suspects of the one polarity and s.n suspects of the other polarity. We make s.n “double coins” by pairing suspects of different polarity; this leaves one suspect of known polarity unpaired. We now use the remaining n weighings to solve the problem for the s.n “double coins”. If all double coins are “true”, the unpaired suspect (whose polarity is known) is the false coin. If one of the double coins is “false”, the polarity of its falseness determines which of its two constituent suspects is the false coin.

Note For n>0, s.n ≥ 1. In that case we have enough —i. e. 2— coins known to be true to make a true “double coin” when we need it. (End of Note.)

The above takes care of the induction step. For the base it suffices to observe that s.0=0 and that for 0 coins, 0 weighings suffice to determine that all the coins are true.

*                       *
*

Variations of this problem circulated in the United Kingdom during WWII, and after the war in the rest of Europe — e.g. 12 coins, one of which is false, 3 weighings, but no 13th coin known to be true. It surfaced this week in the department and turned out to be new for my graduate students. The reason that I took the trouble of writing down the above, is that it provides a nice example of a forced argument.

With s.n possibilities for the false coin, 2 possibilities for the polarity of its falseness, + the possibility of all coins true, our weighing algorithm has to distinguish between 2∙s.n + 1 cases. But, 2∙s.n + 1 being equal to 3n, and a weighing having 3 possible outcomes, the only way in which an algorithm of n weighings can give rise to 3n different computations is if for each weighing, all 3 outcomes are possible. There is no slack.

In other words: faced with s.(n+1) coins, for which we have to distinguish between 3n⁺¹ cases, each outcome of the first weighing has to reduce the number of possibilities to 3n, no more and no less. Hence the number of coins not involved in the first weighing (which can imply: no false coin on the balance) has to be s.n, no more and no less. Because s.(n+1)-s.n —being 2∙s.n + 1— is odd, the need for a coin known to be true follows. The introduction of the s.n “double coins” is undeniably an invention, but I claim that it is only a minor one: if we wish to keep things simple, we should reduce the s.(n+1)-problem to the s.n-problem, irrespective of the outcome of the first weighing. In the one case —equal weights— we get this reduction for free, in the other case —different weights— we have to construct the reduction. I call the invention “minor” —“minuscule” is perhaps better— because I cannot think of any other way of constructing this reduction. The hallmark of the experienced avoider of avoidable complications is probably the immediate awareness that, also in the case of different weights in the first weighing, we should leave ourselves with an s.n-problem. In more than one sense the construction of the above solution has been a balancing act.

Austin, 1 September 1990              

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Xiaozhou (Steve) Li
revised Mon, 28 Jan 2008

EWD 1085

Proving the theorem of Menelaos

For non-degenerate triangle ABC and D, E, F collinear as in above figures the theorem of Menelaos states

BD
–––
DC

�

CE
–––
EA

�

AF
–––
FB

  =  –1       .

In terms of λ, μ, ν, defined by

| D = λB + (1–λ)C,     E = μC + (1–μ)A,     F = νA + (1–ν)B

we have to conclude

1–λ
–––
λ

�

1–μ
–––
μ

�

1–ν
–––
ν

  =  –1       or

(0) | (1–λ) � (1–μ) � (1–ν) + λ�μ�ν = 0

from the fact that D, E, and F are collinear. This is expressed by

(1) | Det. P = 0   where   P =   | Dx | Dy | 1
|  | Ex | Ey | 1
|  | Fx | Fy | 1 |             .

Writing Dx = λBx + (1–λ)Cx, etc. we can factorize   P = Q �R   where

Q =   | λ | 1–λ | 0 |  |         R =   | Bx | By | 1
| 0 | μ | 1–μ |  |  | Cx | Cy | 1
| 1–ν | 0 | ν |  |  | Ax | Ay | 1

From this factorization we conclude

(2) | Det. P = (Det. Q) � (Det. R)           .

Triangle ABC being non-degenerate is expressed by

(3) | Det. R ≠ 0           ,

and from (1), (2), (3) we conclude

| Det. Q = 0           ,

which, in view of Q’s definition, equivales (0).

I designed the above proof in reaction to a very classical argument in which the above two figured had to be dealt with separately. I like the proof for the way R enters the picture. (And just in case you feel tempted to send me shorter proofs of Menelaos’s theorem: I know all about barycentric coordinates.)

Austin, 10 October 1990

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1092

Two ways of determining an expectation value

A trial succeeds with probability p and fails with probability q; p + q = 1, and we confine our attention to 0 < p < 1 (i.e. ignore the extreme cases in which a trial certainly succeeds or certainly fails).

An experiment is a sequence of trials up to and including the first trial that succeeds. The number of trials in an experiment is called the length of that experiment. We are asked to determine the expectation value of the experiment length, i.e. the average length, each length being weighted with the probability of the corresponding experiment.

In the following, k ranges over the positive integers. Since an experiment of length k consists of k–1 failing trials, followed by 1 trial that succeeds, and the successive trials are independent, probability theory tells us that

(0) | the probability of an experiment of length k equals qk–1p  .

Hence, the expectation value x we were asked to determine is given by

(1) | x = (p + 2qp + 3q�p + .... )

and we are left with the duty to sum this series. To this end we observe

| x =  | (1 + 2 | q + 3q� + .... ) p
q | x = | ( | q + 2q� + 3q� + .... ) p

and find by subtracting

(2) | (1–q)x = (1 + q + q� + .... ) p           .

There are now three ways in which we can proceed.
•   we know the sum of the geometric series, i.e. (1+q+q�+....) = 1/(1–q)    .
•   we don’t know the above, and repeat the trick above, observing for y given by

| y =  | (1 +  | q + q� + .... )
q | y = | ( | q + q� + q� + .... )

by subtracting the two

| (1–q)y = 1

•   we interpret the right-hand side of (2):

| p + qp + q�p + ....

in view of (0) as the probability that an experiment terminates. Because 0 < p, i.e. q < 1, the probability of the experiment not terminating equals 0, hence the right-hand side of (2) equals 1.

Because of 1–q = p, we find in all three cases x = 1/p.

This result is so simple that there must be a simpler way to derive it. There is. The equation

| x = 1 + qx

follows because an experiment consists of 1 trial to begin with, followed with the probability q by a new experiment.

The moral of the story is that there are advantages in being a computing scientist, more precisely in remembering at the right moment that potentially infinite objects are most appropriately given recursive definitions. (Remember SASL’s definition of an infinite sequence ONES of ones: ONES = 1: ONES .)

Austin, 4 February 1991

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1094

The undeserved status of the pigeon-hole principle

Right at the moment I was introduced to the pigeon-hole principle, I understood that there was something very special about it, for the Englishman from whom I learned it told it to me under its German name "das Schubfach prinzip". Later I learned that also in other languages it is honoured by a special name. It is, indeed, surrounded by some mystique, for proofs using it are often regarded as something special, something particularly ingenious. This feeling of awe is, for instance, nicely reflected by Ross Honsberger when he concludes one of his examples with the characterization "another triumph of the pigeon-hole principle". (Earlier he has called it "a fundamental tool of combinatorics".)

It is my feeling, however, that this mystique and the surprise when we see the pigeon-hole principle being applied successfully are closely connected to the clumsiness of the usual formulations of the principle: they contain a lot of misleading noise, are overspecific, and hide the principle's arithmetic nature. Instead of composing an average formulation, I quote a typical one verbatim from the literature:

(0) | "if more than n objects are distributed into a set of n compartments, some compartment must receive more than one of the objects".

(Instead of the above "more than n", one often encounters the more specific "n+1".) We shall compare (0) with the alternative

(1) | "for a nonempty, finite bag of real numbers, the maximum is at least the average (and the minimum is at most the average).

Comparing (1) and (0), we observe to begin with that the "distributing" and "receiving" have disappeared, and rightly so, for they are just noise: the pigeon-hole principle is equally applicable when no process of distribution and reception is involved, e.g. when we wish to conclude, from the fact that a month is longer than a week, that in a month some weekday occurs more than once.

The second thing we observe is that the "objects" and the "compartments" have disappeared. That is a great improvement, for it saves us the needless trouble of making a painful identification in all those circumstances in which (for visual or linguistic reasons) the metaphor of objects and compartments does not fit nicely. In the previous example, for instance, we should not talk about a month containing a number of Tuesdays, but about Tuesday ( = compartment ) containing a number of days-of the-month ( = objects ). The whole metaphor of objects and compartments is just a pain in the neck.

Another regrettable consequence of the metaphor is that it invites a misleading visualization. Formulation (0) is in the form of an implication; the contrapositive states equivalently

(2) | "if each of n compartments contains at most one object, they contain together at most n objects".

Formulation (0) evokes a picture of cramped, overstuffed compartments —2 or more pigeons squeezed into a 1-pigeon hole— , whereas formulation (2) rather evokes a picture of underoccupied compartments. The difference between the pictures hides the fact that (0) and (2) are equivalent.

Remark It is not uncommon to see people distinguish —not in meaning, but in rôle— between x≤y and y≥x . The former they read as expressing (in terms of y) an upper bound for x , the latter as giving (in terms of x) a lower bound for y . I advise against trying to make such distinctions: the charm of

           average ≤ maximum                  and
           maximum ≥ average

is that they state exactly the same and need not evoke different connotations as (0) and (2) seem to do. (End of Remark.)

Finally, the traditional pigeon-hole principle is much less general than it should be: expressed in average and maximum, (0) yields

      average > 1 ⇒ maximum >1

which is much weaker than (1)'s

      average ≤ maximum ;

this is why (1), being really stronger than (0), is referred to as the Generalized Pigeon-hole Principle.

As an example in which the Generalized Pigeon-hole Principle comes in handy, we consider now what is known as the Problem of the German Soccer Lotto.

Variables of type "outcome" have 1 of 3 possible values; variables of type "column" consist of 13 variables of type "outcome". In the following, dummies c and d range over type "column" and W is a set of constants of type "column". We are asked to construct a set W, as small as possible, such that

      (A d :: (E c : c ∈ W : (N i : 0 ≤ i < 13 : d.i = c.i) ≥ 5))

In words: W should be such a set of columns that, whatever column we choose for d, W contains a column c that coincides with d in at least 5 positions.

Set W contains at least 3 columns, for with at most 2 columns in W it is possible to choose d such that it coincides in no position with a column in W. But 3 columns suffice. Let x, y, z be the three columns in W; we can choose them such that for any i in the range 0 ≤ i < 13

          { x.i, y.i, z.i }

is the triple of possible outcome-values. With such a choice, each value d.i coincides with one of the three { x, y, z }; 13 coincidences in 3 columns yields an average of 4⅓ coincidences per column, and hence at least 1 column coincides in at least 5 positions with d . And thus the Problem of the German Soccer Lotto has been solved.

The example has been included for two reasons. Firstly it is an example for which the traditional (0) does not suffice and the stronger (1) is really needed. Secondly, it shows the arithmetic reason for the surprise that the use of the pigeon-hole principle often evokes: the three constants 3, 13 and 5 of the problem statement fortunately satisfy the magical relation that 5 is the smallest integer that is at least 13/3. It is this arithmetic accident that makes the Problem of the German Soccer Lotto trivial. Replacing 5 by 6 we get a completely different problem, which is much harder to solve! Another way to phrase the same observation is that if you can get away with an argument as simple as the pigeon-hole principle, you have just been lucky.

*                    *
*

Another, I think unpleasant, property of the pigeon-hole principle is that it seems to invite the reductio ad absurdum. Take this simple problem:

On the ranch, each cowboy is the exclusive owner of at least one horse. Show that on the ranch

# cowboys ≤ # horses   .

It is not unusual at all to encounter an argument of the following shape. Assume that the conclusion is false, i.e., assume that # cowboys > # horses; now put each cowboy (= pigeon) into one of the horses (= holes) he owns; then the pigeon-hole principle tells us that there is a horse owned by at least two cowboys, which contradicts the exclusive ownership. Hence the conclusion is true, i.e. # cowboys ≤ # horses.

[Compare the argument with the following one. Since the minimum number of horses per (i.e. exclusively owned by a) cowboy is at least 1, the average number of horses per cowboy is at least 1, i.e.

  # horses  

# cowboys

≥  1               .]

The former argument is hardly a parody. In a recent textbook on discrete mathematics, I encountered the following problem

"There are 42 students who are to share 12 computers. Each student uses exactly one computer and no computer is used by more than six students. Show that at least five computers are used by three or more students."

Let k be the number of computers serving at least three students; since each computer serves at most 6 students, these k machines serve at most 6k students. Since the remaining 12–k serve at most 2 students each, the latter machines serve at most 24–2k students. Adding these results, we conclude that the number of students served is at most 24 + 4k. Since 42 students are served, we conclude 42 ≤ 24 + 4k or 4½ ≤ k and, since k is integer, 5 ≤ k , which completes the proof.

The textbook, however, proceeds as follows —ignore that, instead of 5≤k, it only shows k ≠ 4— :

"[Use an argument by contradiction.] Suppose that only four computers were used by three or more students. [ A contradiction must be derived]. At most six students are allowed to share any computer, making a total of at most 24 students using these four computers. Since there are 42 students in all, that would leave at least 18 students to share the remaining eight computers. But the generalized pigeon-hole principle guarantees that if 18 students share 8 computers, then at least three must share one of them. [The pigeons are the 18 students, the pigeon-holes are the eight computers, and 18 > 2∙8.] This is a contradiction. Thus the supposition is false, and so at least five computers are used by three or more students."

Remark Both arguments contain the number 24, but this is an accident: in the former argument, 24 emerges as twice the number of machines, in the latter as four times the maximum number of students served by a single machine. (End of Remark.)

In the problem statement, it is inessential that each student uses "exactly" one computer: with each student using "at least" one computer, the conclusion would have been valid as well. Is it far-fetched to assume that the overspecific "exactly" sneaked into the problem statement because a pigeon can occupy only 1 pigeon-hole at a time? We have now spotted (i) a needlessly weak theorem to be proved, (ii) an avoidable reductio ad absurdum, and (iii) an error in the purported proof (for k≥5 does not follow from k≠4). I am afraid that the desire to use the pigeon-hole principle can be blamed for all three shortcomings. The argument in terms of k is just an order of magnitude cleaner than the solution of the textbook.

The moral of the story is that we are much better off with the neutral, general standard procedure: name the unknown(s) so that you can formalize all conditions given or to be established and simplify by formula manipulation, unencumbered by imagery as tends to be imposed upon you by catchy names like "The Pigeon-hole Principle".

            Austin, 21 March 1991

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA
_____________
Mathematical Methodology

transcribed by Mario Béland
revised Fri, 18 Jan 2008

EWD1095

Are "Systems people" really necessary ?

There is something strange going on that may be related to the sinking of the dollar (for to the business mind, a declining economy always suggests that first-class science is not what we need and more than we can afford). For Department of Computer Science, this is recruiting time, and it is always instructive to see how the vacancies are described; the 1991 High Fashion is clear: “systems people” are in.

I cannot help considering the phenomenon strange. You see, it took me more than 30 years of involvement in computing before I was introduced —during a visit at MIT— to the term “systems people”, and I still would not know how to translate the term into Dutch. (To which I should add that I have learned to be very suspicious of ideas I cannot express well in both Dutch and English: as nice as it is to have the union at one’s disposal, it is wise to confine oneself to the intersection.)

At MIT, the term “systems people” was definitely pejorative. It was used to describe faculty that had stopped growing at least 15 years earlier, and their students. (A term of opprobrium was needed indeed; I overheard a technical discussion among three younger “systems people”, and it was as if a time machine had moved me into my distant past.)

Five years later, while I visited Stanford, the term “systems people” surfaced again, and again in a pejorative sense: hard to get, hard to keep, universally disgruntled, impossible to satisfy, scientifically of dubious quality, and probably not worth all the trouble they caused. No names were mentioned and I did not get any further information from seeing the Department in action —it was the Department’s birthday party— , but I recorded the use of the term because, in the mean time, I have heard it used at UT and other places.

It is clear that, despite the 1991 High Fashion, the notion “systems people” still lacks respectability: in a recent e-mail broadcast —I don’t participate in that, but get what is now known as “hard copy”— a colleague refers to them by the even more dubious term “system type people”! (This was not derogatory: it occurred in a message in their defence.) To which I should add that it could be argued that this lack of respectability is partly self-inflicted, because only too often industrial acceptance seems to be one of their more dominant quality criteria; one can also observe them arguing that “because they primarily build things” the more scholarly academic quality criteria are inappropriate for judging them and their work.

As a group, the “systems people” community suffers from a —sometimes loudly overcompensated— inferiority complex, which creates all the usual political problems and friction inside the departments. All this is not amazing, but what I do find amazing is that, over and over again, by themselves and by others, the “systems people” are treated as a mentally handicapped minority that needs special protection. What, the Hell, is going on?

*                 *
*

In the medieval guilds, shared knowledge and abilities were protected by secrecy, and the apprentice that joined a master had to learn, to absorb by osmosis. At the universities, it is the task of the professor to formulate knowledge and techniques as explicitly as possible, thereby bringing them into the public domain; furthermore, in view of the changing spectrum of possibilities and challenges, the professor is expected to keep his message up to date by designing new knowledge and by developing new techniques. Note that the two traditions of transmission to the next generation tend to be followed in different context: the teaching in the guilds is fully justified by the needs of the craft, the university curriculum is more constrained by the requirement of teachability.

The distinction between the two styles of teaching is of potential relevance in this discussion. Firstly, when the importance of laboratories is stressed “to give the student hands-on experience”, we see a tradition of the guilds. (I remember that, during a public curriculum discussion in my second year, I violently disagreed with our professor of experimental physics, C.J. Gorter, who wanted us to understand the working of various radio tubes; I told Gorter —with the wonderful conviction of a 19 year old— that I had come to Leyden to study nature, not artefacts.) Secondly, that when people —and “systems people” often do so— explain that they should not be judged by the little they have written but by the systems they have wrought, we again see a tradition of the guilds, for “bringing into the public domain by means of explicit formulation” is the core of the university professor’s business. The special consideration with which “systems people” should be treated can be defended by pointing out that their craft is exceptionally difficult to teach; alternatively, one can remark that they have chosen an area and a way of working in which the process of turning experience into a teachable discipline is very inefficient if not ludicrously expensive.

Remains the question why “systems people” is primarily an American problem. A minor explanation could be provided by a historical accident: American computing science emerged when America was rich. European computing science emerged when that continent still suffered from the damage of WWII (and a certain amount of poverty concentrates the mind wonderfully).

We can find a deeper explanation in ”the American paradox of apparent scientific excellence and the overwhelming anti-theoretical emphasis on applied technology” [Wyn Wachhorst, Thomas Alva Edison, an American Myth, The MIT Press, 1981]. With the walls around the American campus as low as they are, one can only expect an academic community more strongly infected by society’s prejudices. And if it is society’s perception that doers are more important than thinkers, you get on the faculty “systems people” (who feel themselves the backbone of computing) and “theorists” (who have acquiesced in a rôle of insignificance and are not ashamed of their inability to design a beautiful implementation).

Returning to the original question of whether “systems people” are really necessary, the answer seems to be “Not in a society with a healthy tradition of applied science.”. (I mean, for instance, countries in which “mathematical engineer” is a well-understood academic title that is not viewed as a contradiction in terms.) And if “systems people” are needed, this need can be interpreted as a symptom that the remaining faculty is too one-sided, too narrow; and also: nothing short of establishing a tradition of applied science will save the situation.

Finally, let me end with a quotation:

Dijkstra: I would like to comment on the distinction that has been made between practical and theoretical people. I must stress that I feel this distinction to be obsolete, worn out, inadequate and fruitless. It is just no good, if you want to do anything reasonable, to think that you can work with such simple notions. Its inadequacy, amongst other things, is shown by the fact that I absolutely refuse to regard myself as either impractical or not theoretical.

That this quotation dates from 1969 is a sobering thought.

Austin, 25 February 1991

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Fri, 18 Jan 2008

EWD 1096

Potter’s proof of disjunction’s symmetry

Dr. Walter M. Potter of Southwestern University, Georgetown, TX 78626, taught me that the symmetry of the disjunction can be derived from my other axioms:

        P ≡ Q
=         {idempotence of ∨}
        (P ≡ Q) ∨ (P ≡ Q)
=         {∨ distributes forwards over ≡}
        (P ≡ Q) ∨ P ≡ (P ≡ Q) ∨ Q
=         {∨ distributes backwards over ≡, twice}
        P ∨ P ≡ Q ∨ P ≡ P ∨ Q ≡ Q ∨ Q
=         {idempotence of ∨, twice}
        P ≡ Q ∨ P ≡ P ∨ Q ≡ Q       ;

From the first and the last line (and the properties of ≡) follows
        [Q ∨ P ≡ P ∨ Q]      .

Q.E.D.

Austin, 4 March 1991

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

11xx

1100: The computing habit

1101: Triangles in graphs: a sharp bound

1103: For the record: ETAC and the couples

1104: So much for scientific visualization

1105: For Bill Walker a sequel to EWD1099

1108: Too much PSST in Texas

1109: Simplifying a proof in our book

1110: To the members of the budget council (Confidential)

1112: Why “up to equivalence”

1113: A somewhat open letter to Ben Kuipers

1117: Monotonic demonstranda and dummy introduction

1121: Covering rectangles with bars of length 3

1126: Who failed?

1129: Why “heavy-weight” bits are unavoidable

1131: Bulterman’s theorem on shortest tree

1132: Introducing a course on the design and use of calculi

1134: The checkers problem told to me by M.O. Rabin

1135: The knight’s tour

1137: Computing the future?

1140: The arithmetic mean and the geometric mean

1142: It is all distributivity

1145: A somewhat open letter to Cathleen Synge Morawetz

1151: A terrible Thursday

1152: Het intellectuele gehalte van informatica

1155: A prime is in at most 1 way the sum of 2 squares

1155a: A prime is in at most 1 way the sum of 2 squares

1156: Voorwoord (voor jaarboek studievereniging UT)

1157: Introducing a course on program design and presentation

1161: How promiscuous are the French ?

1165: There is still a war going on

1166: “From my Life”

1170: Equilateral triangles and rectangular grids

1171: The argument about the arithmetic mean and the geometric mean, heuristics included

1175: The strengths of the academic enterprise

1177: In Memoriam Jan L.A. van de Snepscheut

1179: A sorry parade

1180: Heuristics for a very simple Euclidean proof

1181: Don’t mix unary pre- and postfix operators

1188: A problem from Zhendong Patrick Su (including an alternative solution by R.Boute

1190: Problem 10406 from The American Mathematical Monthly, Volume 101, Number 8 / October 1994

1193: On arcs and angles

1194: Z.P. Su’s second problem

1198: Jan van de Snepscheut’s tiling problem

1199: A supplement to EWD1140 and EWD1171

EWD1100

The computing habit

Using computers becomes a habit, and after a while people forget how they, their organization, or their discipline ever did without them. Computers are habit-forming and lead to electronic dependence. Habit-forming is, of course, only a euphemism for addictive, and, indeed, computers are addictive in the most alarming sense of the word; the first stage, in which it is no longer possible to function properly without them, is followed by the second stage in which the proper functioning becomes more and more threatened by the dependence. Think, for instance, of the large organizations, totally dependent on hundreds and hundreds of ill-documented "existing programs" no one understands, dares to touch or to replace: the very fabric of which the organization has been built has become very fragile indeed. (So much for the competence of the MBAs who have allowed this situation to develop.)

How should we react to this computer addiction? Should we fight it or should we exploit it? Fighting addiction is always a thankless task. In this case, it would evoke opposition in the Department itself —faculty and staff feeling that their employment was in jeopardy— , it would evoke violent opposition in all other departments —which thought they did something smart by making computers an integral part of their research and their teaching— and it would not endear us to the computer industry —that these days is supposed to finance us— .

It is much less risky —and almost certain to evoke universal applause and support— if we aim at adding revolutionary new dimensions to the addiction. We could, for instance, head for some sort of electronic LSD. If we really wish to do a spectacular job, we should not confine our system to just a mainstream multimedia extravaganza, for our clients should see colours never seen before, should smell odours never smelled before, should hear noises never heard before, should experience orgasms of demoniac fear and spiritual power never experienced before: on order to communicate with the client's inner self in a bandwidth truly without precedent, we should bypass the old-fashioned senses and the constraints of language in a direct interaction with the client's nervous system. Besides the above outstanding technical merits, this research proposal has the political advantage that, because of its obvious interdisciplinarity, it will position the CS Department at the very center of the UT Campus.

Needless to say, the project would be of enormous educational value for the Department itself: it would drive home the message that, if you really give your mind to it, anything can be considered Computer Science.

Austin, 4 April 1991

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas as Austin
Austin, TX 78712-1188 USA

Transcribed by Guy Haworth

Last revised Sun, 6 Jan 2008.

EWD1101

Triangles in graphs; a sharp bound

We consider undirected graphs without autoloops and without multiple edges—i.e. each edge connects a pair of different vertices, and a pair of vertices is connected by at most 1 edge—. A triangle is a set of 3 vertices such that any two of them are connected by an edge of the graph; the graph is then said to "contain" that triangle.

Theorem     Let M.V be the maximum number of edges of a graph with V vertices such that the graph need not contain a triangle; then M.(2k) = k² and M.(2k-1) = k∙(k-1)         .

Proof          Both equations for M have the form M.(a+b) = a∙b.  Showing that a graph with a+b vertices and a∙b edges need not contain a triangle is done by constructing a witness. Paint a of the vertices red and the remaining b vertices blue; introduce a∙b edges by connecting each red vertex with each blue vertex. Since in the resulting (bipartite) graph colours along a path alternate, cycles have even length and hence the graph contains no triangle.

That a graph with more edges —if feasible— contains a triangle is shown by mathematical inductions.

We confine our attention to graphs with at least 3 vertices, and for the base of the induction we consider (a, b) = (1, 2) and (a, b) = (2, 2).  In the first case, we have to show that a graph with #vertices = 1+2 and #edges > 1∙2 contains a triangle: such a graph has 3 vertices and 3 edges and is a triangle. In the second case, we have to show that a graph with #vertices = 2+2 and #edges > 2∙2 contains a triangle:  such a graph has at least 5 edges and hence contains the complete 4-graph with 1 edge missing, which contains even 2 triangles.

For the induction step we show for any a, b:

(any graph with #vertices = a+b and #edges > a∙b contains a triangle)      ⇒

(any graph with #vertices = (a+1)+(b+1) and #edges > (a+1)∙(b+1) contains a triangle).

To this end we consider a graph with (a+1)+(b+1)   —= a+b+2—   vertices and more than (a+1)∙(b+1)   —= a∙b+a+b+1—   edges and focus our attention on one of its edges e.  Now we consider two cases: e is or is not an edge of a triangle. In the former case the graph obviously contains a triangle. If e is not the edge of a triangle, however, it is connected by at most a+b edges to the subgraph spanned by the remaining a+b vertices; the total graph having more than  a∙b+a+b+1 edges, we conclude that in this case the subgraph of a+b vertices has more than a∙b edges and, according to the antecedent of the demonstrandum, contains a triangle. In view of the base we have demonstrated the presence of a triangle for a+1=b or a=b and b≥2.

(End of Proof).

The above proof is noteworthy for two reasons, firstly because even and odd number of vertices could share the same induction step, and secondly because the presence of a triangle in a graph with 4 vertices and 5 edges has been demonstrated without case analysis. (Take the experiment and ask your friends.)

                                                                            Austin, 5 May 1991

prof.dr. Edsger W.Dijkstra,

Department of Computer Sciences,

The University of Texas at Austin,

Austin, TX 78712 – 1188

USA

Transcribed by Guy Haworth

Revised Sunday, 29-Dec-2013 .

EWD1103

For the record: ETAC and the couples

ETAC learned the following problem from JLA van de Snepscheut (who probably heard it from J Misra). Of a finite number of couples we are told the following two things:

(i) | the oldest man is as old as the oldest woman
(ii) | if two couples swap wives, the youngest of the one new couple is as young as the youngest of the other new couple.

Show that in each couple, man and woman have the same age.

The ETAC came with the following solution. Let dummies x, y range over the couples; let the ages of man and woman of couple x be denoted by m.x and f.x respectively. Our proof obligation is then

(0)     (Ax :: m.x = f.x)

while we have been given

(1)     (↑y :: m.y) = (↑y :: f.y)            and

(2)     (Ax, y :: m.x↓f.y = f.x↓m.y)

Note that (ii) states (2) with the range x≠y, but that the range can be extended to include x=y.  

We observe for any x

m.x  = f.x

=        { ↑↓ calculus: p ≤ p↑q and a ≤ b ≡ a = a↓b}

m.x↓(↑y :: m.y) = f.x↓(↑y :: f.y)

=        {(1)}

m.x↓(↑y :: f.y) = f.x↓(↑y :: m.y)

=        {↑↓ calculus: ↓ distributes over ↑}

(↑y :: m.x↓f.y) = (↑y :: f.x↓m.y)

=        {(2)}

true   ,

and thus (0) has been proved.

The first step is not surprising: in order to use (1) and (2), ↑ and ↓ have to be introduced into the calculation.

                                                                           Nuenen, 29 June 1991

prof.dr. Edsger W.Dijkstra,

Department of Computer Sciences,

The University of Texas at Austin,

Austin, TX 78712–1188

USA

Transcribed by Guy Haworth

Revised Sun, 6 Jan 2008.

EWD1104

So much for scientific visualisation

An undirected graph without self-loops and without multiple edges contains a triangle if it has 4 vertices and 5 edges. the simplest proof observes that the graph in question is the complete 4-graph from which 1 edge has been removed: any triple vertices that does not contain both endpoints of the removed edge yields a triangle. If you insist on making a picture, you may consider

[picture] | or | [picture]

I would have asked quite a few people how they would prove the existence of a triangle with 4 vertices and 5 edges. The majority found itself observing both

[picture] | and | [picture]

seduced to make the “distinction” of whether the missing edge was a side or a diagonal.

A sobering observation!

Nuenen, 9 July 1991

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Guy Haworth
revised Sat, 13 Dec 2008

EWD1105

For Bill Walker a sequel to EWD1099

When I showed to Bill Walker my arguments for demonstrating [R ] in the form [¬R ⇒ R ], he said he would like to see an example. My first remark is that a proof by case analysis can serve as example:

[¬Q ⇒ R ]   ∧   [Q ⇒ R ]   , hence [R ]    ;

taking the contrapositive of the first conjunct, and appealing to the transitivity of implication we get the scheme

[¬R ⇒ Q ]   ∧   [Q ⇒R ] ,  hence [¬R ⇒ R ]     .

*                   *
*

Here is my example for Bill Walker (see EWD1053). Our universe of discourse is a Euclidean plane in which each point is red, white, or blue. Our proof obligation R is

R :      there exists a monochrome pair of points with mutual distance 1.

The intermediate predicate Q is

Q :      all pairs of points with mutual distance √3 are monochrome.

In the following pictorial hints, drawn lines connect points, distance 1 apart, and dotted lines points at distance √3.

Note Monochrome means "of equal colour". The only significance of equality is that it is preserved in function application (Leibniz). The only function defined on our colour domain is equality, and applying Leibniz's principle to it yields that equality is transitive. And that is why an appeal to the transitivity of = has to occur in this proof. (End of Note.)

¬R

⇒             { , pigeon-hole principle }

Q

⇒             { , transitivity of equality }

R            .

          Nuenen, 10 July 1991

prof.dr. Edsger W.Dijkstra

Department of Computer Sciences

The University of Texas at Austin

Austin, TX 78712–1188

USA

transcribed by Guy Haworth
revised Sat, 13 Dec 2008

EWD1108

Too Much PSST in Texas

"and these rulers were clear sighted enough to see that the simplest way of getting mathematics out of a mathematician is to pay his living expenses."

E.T. Bell

These days, supporting science is more complicated than it was for the rulers E.T. Bell refers to: they could restrict their support to people like Euler and Lagrange. In the name of progress, a much larger proportion of the population is now involved in the scientific endeavour. But is it progress? By necessity, the majority of the people involved now lacks the proper credentials, and the result is a lot of PSST.

Concerning computer-related PSST at UT, it goes without saying that an overwhelming amount can be found in the Departments of Management Science & Information Systems and of Electrical & Computer Engineering respectively, since both lack the proper tradition of research. Moreover, with their close ties to industry, these departments are structurally unable to nurture on a regular basis the type of intellectual radical, the type of "misfit" that is needed to change the status quo. Personally I am always amazed that such departments do not understand themselves that they lose most of their credibility by the respective additions "& Infromation Systems" and "& computer", since these make it so obvious that they jumped on a bandwaggon. But my amazement is naive, for PSST cannot be separated from bandwaggons.

Our own Department of Computer Sciences —note the plural!— is not free from PSST either. It would be a miracle, if it were. For instance, whenever in an area the teaching is kept primitive so as not to frighten away our unsophisticated students, PSST can be observed, and PSST comes in by the carload when an area is promoted because it yields so many thesis topics that are popular with average graduate students and employers. (So-called Experimental Computer Science, specifically created to help the universities to compete for young CS graduates, is particularly vulnerable to infestation with PSST.)

Besides UT, Austin has many industrial organizations involved in computing (IBM, TI, Motorola, Lockheed, you name them). My knowledge about them is fragmentary, very dependent on whom I happened to meet under what circumstances. My overall impression of the industrial organizations is —not surprisingly— that they display the usual kind of incompetence, ignorance, backwardness, and short-sightedness, but less of the dishonesty that fosters PSST at political bodies like MCC (and, in all probability, Sematech). Those that have joined the Software Engineering Movement are, of course, deeply involved in PSST.

Please don't think that the high frequency and the degree of acceptance of PSST are harmless. They have been a major consideration in the decision of colleagues to leave UT —people don't say so in public because they don't want to be unnecessarily offensive— , may cause others to leave, and have almost certainly thwarted more than one recruitment effort: since PSST corrupts, it is particularly repulsive to scientists of integrity.

We have no influence on what happens outside our Department, and only little influence on what happens inside. But we can discourage internally PSST as much as possible, and dissociate ourselves as clearly as possible from the PSST happening elsewhere. For instance, all over the world EE Departments, sensing their academic respectability in jeopardy, have been observed eager to merge with or rather to absorb the local CS Department so as to boost their academic status; the message, loud and clear, that we are not available would create a clarity that never hurts. When, for instance, the Institute for Creative Capitalism organizes a workshop on the Crucial Importance of the Software Industry for the Austin Area and the Essential Role of The University of Texas at Austin as Technological Support for Etc. Etc. Etc., I don't think we should be involved. It was, by the way, most heartening to see how many people, on seeing its announcement, instantaneously wrote off this workshop as one more PSST-promoting event.

Finally, human nature being what it is, we can fight in the Austin area PSST as fiercely as we like without the danger of reducing it to an acceptable level before the end of the century.

Post Scriptum At the beginning of this text you may have noticed that I did not define PSST. I hope that, as you continued reading, you have noticed that the absence of that definition did not matter. You are perfectly free to use the term PSST for the rest of your life: I donate it herewith to mankind. If you insist on seeing it as an acronym, I can divulge the secret: it actually emerged as an abbreviation for Pompous Simulation of Science and Technology. (End of Post Scriptum)

Austin, 23 September 1991

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Hai Zhou.

Last revised on Sun, 6 Jan 2008.

EWD1109

Simplifying a proof in our book

In [0], pp.66-69, we show how the conditional distribution of  ∧  over  ∀  can be derived from the one-point rule and the other axioms. I dragged sets into the picture, for which misbehaviour I apologize; here is a simpler argument. Representing “the non-empty range” for the dummy  x  by r.x  ∨  [x=y] we show

[〈∀x : r.x ∨ [x=y]: t.x ∧ Q〉 ≡ 〈∀x : r.x ∨ [x=y]: t.x〉∧ Q ]

To this end we observe

〈∀x: r.x ∨ [x=y]: t.x ∧ Q〉

=         {splitting the term}

〈∀x: r.x ∨ [x=y]: t.x〉 ∧ 〈∀x: r.x ∨ [x=y]: Q〉

=         {see (*) below}

〈∀x: r.x ∨ [x=y]: t.x〉 ∧ Q

(*) We observe

〈∀x: r.x ∨ [x=y]: Q〉

=         {splitting the range}

〈∀x: r.x: Q〉∧〈∀x: [x=y]: Q〉

=         {one-point rule}

〈∀x: r.x: Q〉∧ Q

=         {see (**) below)

Q

(**) We observe

[Q ⇒〈∀x:r.x: Q〉]

=         { ⇒ distributes —like ∨— over ∀ in consequent}

[〈∀x: r.x: Q ⇒ Q〉]

=         {pred. calc}

[〈∀x: r.x: true〉]

=         {pred. calc., e.g. [0], p.66, (90)]

[true]

=         {pred. calc.}

true

[0] Edsger W. Dijkstra & Carel S. Scholten Predicate Calculus and Program Semantics, Springer-Verlag New York Inc., 1990

Austin, 25 September 1991

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Guy Haworth
revised Sat, 13 Dec 2008

EWD1110

To the members of the budget council (Confidential)

The following comments have been triggered by our recent meetings on promotion and tenure.

•     There is no intrinsic connection between scientific significance and industrial interest, the one being a cultural concern, the other a financial matter. With the greatly different time range of their planning —say, five years versus fifty— the correlation is, in fact, negative. Since science is the University's primary responsibility, a candidate that tries to recommend himself by stressing the industrial interest in his work disqualifies himself for an academic position and is just applying for the wrong job.

•     Similarly, there is no connection between scientific significance and degree of acceptance of ideas or sales figures of books. In fact, again the correlation is negative; whether we like it or not, the “Vulgus Studiosorum” applauds the vulgar, and this is the reason why a scientist’s scientific integrity tends to get corrupted when he adopts the morals of the best-seller society. We have to make a clear distinction between the scientist and the salesman.

•     Industry is so incredibly backward and its quality standards are so disgracefully low that, if there is to be a bridge between the industrial world and the academic world, we have to ensure that that bridge will be used for one-way traffic only. Since experience has shown that this last traffic regulation is almost impossible to enforce, it can be argued that we are much better off without the bridge.

•     Note how rarely a letter of recommendation gives the considered opinion of the letter writer. Recommendations for mr.X seem to follow the following pattern. Mr.A writes “Mr.X is great for Mr.B thinks highly of him.”. And this you may check, and you will find A’s letter confirmed: Mr.B, in fact, had written “Mr.X is great, for Mr.C thinks highly of him.” etc., until you reach mr.Z who writes “Mr.X is great, for Mr.A thinks highly of him.”. All this delegation of judgement only adds more layers of dishonesty to an already very dishonest process. (I call it dishonest because each time verbal inflation occurs and candidates of well-established mediocrity are discussed in a terminology that would fit semigods.)

•     For any candidate one can raise the question whether he is an intellectual. We have either to answer the question or to decide that the answer to this question is irrelevant. I seem to observe a preference for the last option in the case of so-called “systems candidates”, thereby granting them the privilege that we seem to owe these days to the minority of the mentally handicapped.

•     One can hear the remark that we should not frighten away our students —for instance by making the undergraduate curriculum more substantial— because it is to their large numbers that we owe our positions. My comment is that the university was not created to fill the pockets and purses of faculty.

•     One can also hear the remark that we need more faculty of such and such type because of the teaching load caused by the huge enrollment for such and such courses. At first hearing it sounds reasonable but it raises the question who decides our curriculum. If what society needs coincides with what society asks for, one is in educational heaven, but we are faced with a huge discrepancy. Since it is still our charter to become a Leading Department, we have no choice: we have to lead, rather than be led, we have to give what society needs rather than what society asks for, and curriculum determination by public demand is out.

•     A few times in the discussion, a science-versus-engineering controversy surfaced. I am all in favour of science, I am all in favour of engineering, I am all in favour of their happy marriage. (For more than twenty years I was engaged in the education of Mathematical Engineers and “Informatics” was a topic par excellence for the Mathematical Engineer.) He who feels a controversy between the two has too low a conception of one of the two (or both): it is the poor engineer who has no use for scientific method, it is the poor scientist who cannot contribute to engineering.

Austin, 2 October 1991

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcribed by Hamilton Richards
Revised 05-May-2016

EWD 1112

Why "up to equivalence"

Let ⊑ be a preorder, i.e. a reflexive, transitive relation. Then relation ⋍, given by

p ⋍ q   ≡  p ⊑ q  ∧  q ⊑ p    ,

is reflexive, transitive and symmetric, i.e. it is an equivalence relation. In category theory, one encounters all the time conclusions valid "up to equivalence", a caveat that acts as a reminder that ⋍ is weaker than =   .  It makes one wonder why ⊑ is not strengthened into a partial order, i.e. is postulated to be anti-symmetric as well:

p = q  ⇐  p ⊑ q  ∧  q ⊑ p .

The following consideration gives a possible explanation.

*                     *
*

In the usual model of our predicate calculus, our atoms —P, Q, R, say— stand for boolean expressions in some variable, x say, and when we write

[P ≡ Q ∧ R ]      ,

the square brackets denote universal quantification over x.  For the purpose of this discussion I shall tag the square brackets with the name of the variable(s) quantified over;  the above is then rewritten as

[P ≡ Q ∧ R ]x

Let now x' be a fresh variable of some non-empty type. Then, for instance,

[P ≡ Q ∧ R ]x  ≡  [P ≡ Q ∧ R ]x, x'

since quantification over a fresh variable of a nonempty type is the identity operation. In other words, in the usual model of our predicate calculus we are free to view our atoms as expressions in a fresh variable as well, provided we reinterpret the square brackets accordingly. We try to capture this nice property by saying that our usual model of the predicate calculus is "insensitive to Cartesian extension".

Let us now investigate to what extent the usual model of the relational calculus is sensitive to Cartesian extension. The relational calculus is predicate calculus enriched with a unary operator called "transposition" (~), a binary operator called "composition" (;) and a constant (J) which  is composition's identity element. In the usual model for the relational calculus, the atoms are viewed as boolean expressions of two variables of the same (nonempty, but I am not going to repeat that all the time) type; we shall begin by denoting them by x and y respectively. That transposition is an involution we can express by

[P  ≡  ~~P ]x, y  ;

if you think it helpful, you can view the underlying space as a Cartesian square.

The transposition ~ is in the model

[~P  ≡  (x,y := y,x).P ]x,y   ,

and for this operation, the model is insensitive to Cartesian extension, since for fresh x', y'

[(x,x',y,y' := y,y',x,x' ).P   ≡  (x,y := y,x).P ]x,x',y,y'.

The composition  ;  is in the model

[P ;Q ≡〈∃z :: (y:=z).P ∧ (x:=z).Q〉]x,y    ,

and also for composition, the model is insensitive to Cartesian extension, since for fresh x', y'

[〈∃z :: (y:=z).P ∧ (x:=z).Q〉  ≡

〈∃z,z' :: (y,y':=z,z').P ∧ (x,x':=z,z').Q〉]x,x',y,y'.

Since "R is transitive" is formally expressed by

    [R ;R  ⇒  R ]

the notion of transitivity is insensitive to Cartesian extension.

    With the constant J, however, things are different. It is "the diagonal" x=y of the underlying Cartesian square; after extension with the fresh variables x',y', it is x=y ∧ x'=y'  . For fresh variables x',y' we observe

[ J ⇒ R ]x,x',y,y'

=         { extended def. of J }

[x=y ∧ x'=y' ⇒ R ]x,x',y,y'

=         { pred. calc. }

[[x=y ⇒ R ∨ (x'≠y' )]x',y']x,y

=         {x',y' are fresh}

[x=y ⇒ R ∨ [x'≠y' ]x',y']x,y

=         {x',y' of nonempty type}

[x=y ⇒ R ]x,y

=         { def of J }

[ J ⇒ R ]x,y

    Since "R is reflexive" is formally expressed by [ J ⇒ R ]     , the above shows that also the notion of reflexivity, and hence the notion of a preorder, is insensitive to Cartesian extension.

    The formal expression of "R is antisymmetric" is [R ∧ ~R  ⇒  J ]. This, however, is not insensitive to Cartesian extension, as is shown by the following observation for fresh variables x',y' (which we take from a nontrivial type, i.e. with at least 2 distinct values)

[R ∧ ~R ⇒ J ]x,x',y,y'

=         { extended def. of J }

[R ∧ ~R ⇒ x=y ∧ x'=y' ]x,x',y,y'

=         {pred. calc., x',y' fresh}

[R ∧ ~R ⇒ x=y ]x,y ∧ [x'=y']x',y'

=         {def. of J; fresh type nontrivial}

[R ∧ ~R ⇒ J ]x,y ∧ false

=         {pred. calc.}

false   ;

in other words: Cartesian extension destroys antisymmetry and turns a partial order into a preorder.

                                Austin, 6 November 1991

prof.dr Edsger W.Dijkstra

Department of Computer Sciences

The University of Texas at Austin

Austin, TX 78712 – 1188

USA

Transcribed by Guy Haworth.

Last revised on Sun, 6 Jan 2008.

EWD1113

A somewhat open letter to Ben Kuipers

Dear Ben,

you speculated why theorists are tempted to regard experimental CS as a second-class effort.  I think there is more to it.  By virtue of the calling of the universities, academic disciplines are teachable disciplines and the primary purpose of academic research is to contribute to the improvement of teachable disciplines.  A major objection to "experimental CS" is that it is a relatively very expensive and inefficient way of improving our teachable discipline: the equipment and its maintenance are expensive, the programs to be written cost an inordinate amount of effort, and the contribution to what we can and should teach is meagre.  [Lest you misunderstand me:  I did not start as a "theorist" and still refuse to be characterized as such.  For 15 years I was in the fortunate situation that I could try out novelties using each time the most powerful equipment then available in my country.  But a quarter of a century ago, I saw funding problems lurking around the corner, and I bought my intellectual freedom by concentrating on work that would not require equipment or assisting staff. My now not using machines is a direct consequence of my decision to reduce the expense and increase the effectiveness of my research.]

The whole idea of experimental CS has one of its seeds in the position paper by Newell, Simon and Perlis, the tenor of which was "Facts breed science; computers exist, ergo!".  The weakness of their argument is that one can substitute "postage stamps" for "computers" and then use it to defend a Department of Philately.  Having listened to so-called "experimental computer scientists", I have come to the conclusion that the term "experimental CS" is a gross misnomer.

In the natural sciences, experiments are indispensable to check whether informal nature provides an acceptable model for your theory.  With modern technology we can easily build artefacts that –though formally definedÑ are of such a structure that a derivation of their relevant properties is way beyond our analytical abilities, but can such artefacts play the role of "informal nature", as mentioned in the previous sentence?

Hardly. You see, experiments involve measuring, but to think that the measurements constitute the experiment is like equating composing with the writing of the score.  It is always the theory at stake that lends the experiment its significance. Think of the experiment of Michelson and Morley, refuting a "stationary aether" or the one of Millikan, which to all intents and purposes only admits models with discrete electrons.  That, in passing, the speed of light and the charge of the electron were measured, was of secondary significance. (This "secondary" is no exaggeration:  you can teach the whole of the Theory of Relativity, complete with all the experimental evidence, without ever mentioning the actual value of the speed of light:  just  c  will do.)  What I have seen so far in "experimental CS" is measuring without any theory that could be refuted or supported by the outcome of the measurements;  consequently, the latter are at most of very local significance and hardly contribute to "the improvement of our teachable discipline".  In all cases I remember, "performance measurement" would have been a much more appropriate term than "experimental CS".

The answer to the question to what extent we should try to teach our students how to measure performance probably depends on the extent to which we think that a first-class university should be involved in vocational training.

In the early 1960s, I have been involved in what now perhaps would be called "experimental CS".  Friends were designing a floating point arithmetic unit and wanted to know the probability distribution of the difference of the exponents in the floating point representation of the addenda. (They would like to know this in order to decide what additional hardware would be defensible for speeding up the mantissa alignment.) The brilliant physicist I then thought I still was tried to solve this problem theoretically, but no matter what ingenious ensemble of almost infinitely many computations I created, I got nowhere.  This, of course, should have made me very suspicious, but it did not, and, unable to determine the distribution on theoretical grounds I decided to measure it.  I had access to the ALGOL 60 implementation of the Mathematical Centre in Amsterdam and could mechanically observe all floating point additions performed in that institute.  I collected my statistics.  Due to storage constraints I could only collect the histograms per program, rather than have the machine produce the collective histogram for a full day's work.  As a result I saw that between programs the histograms varied wildly!  The whole idea of "an average program" was a complete fiction and the probability distribution sought just did not exist.  And then, somewhat belatedly, I realized that I had expected a meaningful result from averaging operators, but in the absence of the equivalence of the Theorem of Liouville that lends significance to (at least classical) statistical mechanics.  Without such an underlying theorem, averaging has about as much significance as a Gallup poll.

You mentioned "investigation of a general phenomenon by empirical study of particular instances of that phenomenon", and I think I can join you in that, but would like to point out that something "specific" can only be viewed as a particular instance of something more "general" after the introduction of the concepts in which the generalisation or particularization can be expressed and reasoned about.  Otherwise the whole process is intellectually as shallow as trying to answer the question "How do we generalize broccoli?".Recently we have been exposed to lectures by all sorts of computing experimentalists.  I don't remember if you attended all of them, but if you did you could have observed that in the vast majority of cases the speaker talked for more than an hour without introducing a single new concept;  no wonder the talks were not fully satisfactory.  In fact, the way in which some of the distinguished speakers disqualified themselves can not be expected to spread the opinion that experimental CS is a first-class effort.

*                *
*

The other weekend I spent a few hours reading in "Over Statistische Methoden in de Theorie der Quanta" (On statistical methods in quantum theory), the 1927 Ph.D. thesis of George Eugène Uhlenbeck, a thesis of which I happen to own a copy.  I read it for a variety of reasons, among others as a reminder of the meticulous care with which our great scientists proceed.  It was very refreshing.

Greetings! | Yours ever, <signed> Edsger Austin, Tuesday 19 November 1991

prof.dr.Edsger W.Dijkstra

Department of Computer Sciences

The University of Texas at Austin

Austin, TX 78712 – 1188

USA

Transcribed by Guy Haworth.

Last modified Sat, 5 Jan 2008.

EWD1117

Monotonic demonstranda and dummy introduction

When we have to prove  

                   [f.exp]

for some exp and some monotonic f, it can help to know the following theorem

Theorem For monotonic f

(0)     [f.exp]  ≡  〈∀z : [exp ⇒ z]: [f.z] 〉     and

(1)     [f.exp]  ≡  〈∃z : [z ⇒ exp]: [f.z] 〉

A reason to use (0) is that [exp ⇒ z] is the form of expression in which we can manipulate exp  . An example is given in EWD1118.

A reason to use (1) is that [z ⇒ exp] is the form of conclusion we can draw about exp; if it exists, the strongest z satisfying [f.z] is a good candidate for a witness. An example is given in EWD1116.

This theorem is very simple, very general and probably equally applicable and useful. Why did it take me a lifetime to formulate it?

                                                                            Austin, 1 December 1991

prof.dr E.W.Dijkstra, CS Dept., UT, Austin TX 78712 - 1188

Transcribed by Guy Haworth.

Last modified Tue, 1 Jan 2008.

EWD 1121

Covering rectangles with bars of length 3.

In EWD1039 “Seemingly on a problem transmitted by Bengt Jonsson” I wrote on the following problem. Consider the 8×8 square; can it be covered by 21 bars of 3×1 and 1 little square of 1×1? Recently I heard a 3-dimensional variation: if a 4×4×4 cube is filled by 21 bars of 3×1×1 and 1 cube of 1×1×1, show that the little cube is situated in one of the corners of the big cube. In short, time to solve the problem in N dimensions.

I was struck by the inadequacy of the usual metaphors. Arguments about covering rectangles by 2×1 dominoes are traditionally carried out in terms of chess boards, and the above 8×8 problem was accordingly solved by colouring squares red, white, or blue. But we are used to painting surfaces and not to painting volumes. Another awkwardness is that in the one case we talk about “covering” and in the other case about “filling”. Even more seriously, our bars differ: from bars of 3×1 we went to bars of 3×1×1.

All these (linguistic) problems can be overcome by switching to an N-dimensional rectangular array of grid points or, equivalently, their N-tuples of coordinates. Covering and filling became partitioning, a bar becomes a triple with consecutive values in the only coordinate in which they differ. It now stands to reason to "colour" each point by 0, 1, or 2, viz. the sum of its coordinates reduced modulo 3.

If at least one of the lengths of the rectangle is a multiple of 3, partitioning in bars is obviously possible and, hence, the three colours occur with the same frequency. If none of the lengths of the rectangle is a multiple of 3, the total number of grid points is not a multiple of 3 and, hence, the colours do not occur with the same frequency. The frequencies, however, differ at most 1. (The proof is by mathematical induction over the number of dimensions. An (N+1)-dimensional rectangle with no length divisible by 3 can be turned into an (N+1)-dimensional rectangle with one length divisible by 3 by addition or removal of an N-dimensional rectangular slice with no length divisible by 3.)

With the total number of grid points equal to 3k � 1, we allow one “exceptional” point (of the colour that occurs k � 1 times): in the case 3k + 1, the exceptional point of a “partitioning” is the one that occurs in no bar —in the 4×1 rectangle, one of the end points is exceptional—, in the case 3k-1, the exceptional point of a “partitioning” is the one that is allowed to occur in two bars —in the 5×1 rectangle, the mid-point is exceptional—.

The possible positions of the exceptional point are further restricted by the consideration of symmetry that tells us that the colour of the exceptional point remains unchanged by reflection, i.e. if one coordinate, instead of numbering from m to n, is made to number from n to m. In particular:

a)    | in a direction in which the length of the rectangle is of the form 3p + 1, the difference between extreme and exceptional coordinate is of the form 3q. (This deals with the 4×4×4 cube.)
b) | in a direction in which the length of the rectangle is of the form 3p+1, the difference between extreme and exceptional coordinate is of form 3q+2. (This deals with the 8×8 square.)

For instance, in the 4×5 rectangle, one of the two marked positions occurs in two bars.

Nuenen, 3 January 1992

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 29-Nov-2011

EWD1126

Who failed?

In "Analysis and Refutation of the LCAS" (= Language Compatible Arithmetic Standard), ACM SIGPLAN Notices, Vol. 27, No. 1 (Jan 1992), pp. 61-74, a certain Prof. W. Kahan of the University of California at Berkeley, USA, writes:

"An earlier attempt similar to the LCAS was A. van Wijngaarden's "Numerical Analysis as an Independent Science" in BIT 6 (1966) pp. 68-81. It failed for two reasons. First, it was mathematically intimidating with 32 axioms couched even more inscrutably than the LCAS. Second, it did not cover the CDC 6600, which was the CRAY of its time."

Now this is strange.

(i) Van Wijngaarden's attempt is blamed for not having achieved what was not attempted: the paper did not propose a standard, which would have been a political act, but proposed an axiomatic basis for the mathematical discipline of numerical analysis, which was a scientific act.

(ii) The paper is blamed for being "mathematically intimidating". What Prof. W. Kahan here complains about is that van Wijngaarden has taken the trouble to act as a respectable and conscientious scientist: omitting a number of axioms or skirting rigour w[h]ere rigour was required, all in an effort to make his text less "intimidating", would have been scientifically dishonest.

(iii) The paper is blamed for not "covering" the CDC 6600, which in Kahan-speak means that the floating-point operations of the CDC 6600 did not meet van Wijngaarden's requirements. As these requirements were very modest, this was an implicit indictment of the CDC 6600, but that is what CDC deserved. In creating Computing Science as a viable scientific discipline, a major effort of the 60s went into keeping Computing Science independent of the (only too often ill-considered) equipment that happened to be on the market. The goal of this independence provided the main motivation behind the whole paper! (In the introduction, van Wijngaarden points out that it is unattractive "to base a science on a particular make of apparatus, presumably obsolete before long".)

We are left with the riddle of how an academic author of presumably some rank can cram so much misunderstanding in only 4 sentences. Part of the explanation may be that Prof. W. Kahan is an extreme victim of the American habit of calling the topic "Computer Science" (in contrast to the more usual "Computing Science" or "Informatics" elsewhere). The habit is unfortunate as it tends to direct too much attention towards the ephemeral and nurtures the misapprehension that one can be a good Professor of CS by being a Professor of Current Computers and Packages.

*               *
*

The above has been written to regain my peace of mind and to shock my professional friends that are not regular readers of ACM SIGPLAN Notices.

Austin, 28 February 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Science
The University of Texas at Austin
Austin, TX 78712 - 1188 USA

Transcribed by Guy Haworth

Last revised Tue, 1 Jan 2008.

EWD 1129

Why "heavy-weight" bits are unavoidable.

The following statement from my "On the cruelty of really teaching computing science" was recently challenged in an as yet private communication:

"In the discrete world of computing, there is no meaningful metric in which "small" changes and "small" effects go hand in hand, and there never will be.".

Here is the type of reasoning that led to the above conclusion.

We restrict ourselves for simplicity's sake to a store of n bits, for which we consider the inversion of a single bit as the smallest possible change. With each storage configuration we associate a value, and on the corresponding value space we envisage a metric that defines a distance d(x,y) for any pair of values (x,y). Besides the obvious d(x,x) = 0 and d(x,y) = d(y,x) , the metric being "meaningful" is meant to imply the validity of the triangular inequality, viz. d(x,y) ≤ d(x,z) + d(z,y).

Assume now that our metric is such that the distance between two values that correspond to storage configurations that differ in precisely one bit is (at most) 1. (This assumption is intended to model that "small" changes and "small" effects go hand in hand.) From the fact that the store has n bits and the triangular inequality we now deduce that the distance between any two values that correspond to storage configurations is at most n. But this upper bound is much too small to be economically acceptable: instead of storing in n bits one of the values from 0 through n , we know how to store in those n bits one of the values from 0 through 2n-1. So, in my quoted statement "never" means "not as long as we refuse to pay an exponential price while a linear one is feasible".

Austin, 30 April 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Tue, 1 Jan 2008

EWD 1131

Bulterman’s theorem on shortest tree

We consider a finite complete graph in which each edge has a length; as usual, the length of a tree is defined as the sum of the lengths of its edges. The shortest subspanning tree of such a graph is not necessarily unique. At the last meeting of the ETAC, however, Ronald W. Bulterman pointed out that all shortest subspanning trees give rise to the same bag of edge lengths. Here is a proof.

*         *         *

Lemma   A subset of nodes that in the complete graph can be connected by edges of minimum length only, is so connected in a shortest subspanning tree.

Proof   Consider for a given subspanning tree a nonextensible set Q of nodes, connected in the tree by edges of minimum length only. Let Q be a true subset of P, a set of nodes that can be connected in the complete graph by edges of minimum length only. The lemma is then proved by constructing a subspanning tree shorter than the given one.

Q being a true subset of P, there exists an edge from a node in Q to a node in P-Q and of minimal length. Because Q is nonextensible in the given tree, adding that edge to the given tree closes a cyclic path that contains a longer edge. Removal of the latter yields a tree that is shorter than the given tree. (End of Proof.)

This lemma gives rise to a (for me at least) new algorithm for shortest subspanning trees. To begin with we only consider the edges of minimum length; they partition the vertices in connected components —and because at least 1 component contains at least 2 vertices, there are fewer components than the original graph has vertices—. To construct the shortest subspanning tree we first select for each component of p vertices p-1 edges of minimum length that form a subspanning tree for the p vertices of that component. The remaining edges are produced as solution of the shortest tree problem for a reduced graph. The above components are the vertices of the reduced graph, whose edges are the shortest edges connecting any pair of components.

Because the number of minimum length edges and the reduced graph are both only dependent on the partitioning and hence independent of how the nondeterminacy is resolved, all shortest subspanning trees yield the same bag of edge lengths. And this concludes my proof of Bulterman’s theorem.

The theorem is not surprising at all: it holds in the extreme cases —all edge lengths different and all edge lengths equal— and for sufficiently incommensurable edge lengths I guess that additive decompositions are unique anyhow. This note has been written because the proof is very satisfactory: it disentangles precisely what has to be disentangled.

Nuenen, 20 July 1992

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 27-Nov-2011

EWD 1132

Introducing a course on the design and use of calculi

My reason to give this course is my conviction that power and crispness of well-designed calculi is, in general, underestimated, and that in the science and practice of programming, calculi have an increasingly important role to play. How to design a calculus so as to make it geared to our manipulative needs, and how to design for a calculus a strategy for its effective use thus become significant methodological issues.

We shall illustrate what we have understood of these issues by discussing what can be viewed as a family of calculi: the classical predicate calculus, generalized to a boolean algebra, the relational calculus and the regularity calculus (i.e. the calculus of regular expressions). There is a very personal justification for this choice of illustrative material: my own familiarity with and intellectual investment in these calculi; but fortunately, there is a much more objective justification. The predicate calculus is so general that, of course, we can encounter it all over the place: there is (Naur/Floyd/Hoare/ Dijkstra/ Gries/Owicki) a long tradition of reasoning about programs, sequential or not, in terms of predicates on the state space, which also (Hoare/Dijkstra & Scholten/Morgan) form the basis for theories about semantics and program refinement. The relational calculus and the regularity calculus are a little bit more specific, but still very frequently relevant: for the regularity calculus this is illustrated by the close link between regular expressions and finite-state automata, for the relational calculus by its links with demonic nondeterminacy (Rutger M. Dijkstra/Nguyen), with logic programming (Cousot & Cousot) and with functional programming/type theory (Backhouse). In short, for computing scientists, these calculi are of interest in their own right.

These calculi are so general and ubiquitously useful because they can be defined by such a modest number of —pleasant!— postulates. The modest number of postulates, moreover, makes them most suitable for illustrative material. This suitability is enhanced by the fact that the little bit of underlying lattice theory that will be used all the time is extremely elegant. It is, in a way, perhaps surprising that in all their simplicity, these calculi are "rich" enough so that the design of effective calculations poses a strategic challenge.

We shall try to rely on as few definitions as possible and to keep our notational conventions as homogeneous as possible. Which concepts to define, and which notational conventions to adopt, should, however, be questions of explicit concern. (This is obvious: since the availability of an adequate notation can make a difference as between night and day, we had better be able to judge the adequacy of proposed or considered notations. Also, in each theory, superfluous distinctions, concepts and theorems are a real encumbrance.)

We shall try to make our calculational proofs as short as possible —without committing the sin of omission!— and hope to come very close to our aim of designing almost all our proofs without pulling a single rabbit out of the hat.

Austin, 26 August 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Tue, 1 Jan 2008

EWD 1134

The checkers problem told to me by M.O.Rabin

Last week, during the annual seminar at the University of Newcastle-upon-Tyne, Michael O. Rabin told me the following problem.

Consider an infinite checkers board, of which the columns and rows are identified by the integer coordinates  x  and  y  respectively. Initially, there is a piece on each square whose coordinates satisfy   (even.x ≡ even.y) ∧ y ≤ 0.   Pieces can be moved "upwards" by the usual "capturing moves": from to and from to . The question posed is whether there is an upper bound on the y-coordinates of the squares that may be occupied.

*         *         *

Because the question asked is about y-coordinates, we abstract for a moment from the x-coordinate. The two original moves then become one and the same move: from to . In order to capture that a high piece is created from ("is as good as", "corresponds to") its two successors —those who know him see Fibonacci lurking around the corner!— , we give a piece (on a square) at height  y  a weight  φy  with  φ  the positive root of   φ² = φ + 1 . The equation is chosen so that the weight of the new piece equals the weight of the two pieces it replaces, i.e. a move is neutral as far as total weight is concerned. By restricting ourselves to the positive root, we keep all weights positive, i.e. total weight a monotonic function of the number of pieces involved. Solving the equation yields

φ = (1 + √5)/2       .

The fact that a move is neutral as far as total weight is concerned, means that the creation of a piece at height  Y  (with Y>0) uses from the original configuration a set of pieces with total weight φY. This "target weight", being φY and φ being positive, grows exponentially with Y. We shall next observe that, in view of the shape of the two moves —x re-enters the picture— , the original pieces involved in the creation of a piece at height  Y  come from a restricted area. Calling their total weight the "available weight", we shall show that the latter grows linearly with Y. Hence, the condition

target weight ≤ available weight

imposes an upper bound on Y: the answer to the question posed is "Yes".

In order to establish the available weight we observe the moves for small values of Y.

Y=1 requires a single move, say    .

Y=2 requires two moves, say    ,
the one thin dot above the
line indicating a square
that has been temporarily
occupied.

Y=3 requires two moves more.    

For the restricted areas from which the original pieces have to be recruited we take infinite (truncated) triangles

For Y=1 , the available weight (∑n: n≥0: (n+1)∗φ-n) is finite, and so is the increment (∑n: a≥0: φ-n). Summing the sequences one finds for the available weight

 4 + 2√5 + Y∗(3 + √5) 
2

The smallest value for  Y  such that the target weight φY exceeds the available weight is  7 : then the target weight equals (29+13√5)/2, the available weight is only (25+9√5)/2 .

For Y=6, the target weight (18+8√5)/2 is less than the available weight (22+8√5)/2 , but this does not justify the conclusion that Y=6 is attainable. Y=6 can be achieved, but the only way of showing this that I know of is showing a game that does the job. The required game turns out to have 53 moves, which makes finding it and reporting it somewhat of a challenge. I could convince myself that Y=6 could be reached only

(i) after having realized that the constraint of at most 1 piece per square is inessential and can be stopped

(ii) after having decided to play the game backwards

Below, we show successive stages of the backwards game: in the centre the configuration of the pieces, to the left the y-coordinates of the rows in question and —by way of check— to the right for each row the total number of pieces in it.

6                               1                            1

5                             1                              1
4                           1                                1

4                           1   1                            2
3                                 1                          1

3                         1   1   1                          3
2                       1   1                                2

2                         1   2   1   1                      5
1                               1   1   1                    3

1                       1   1   2   2   2                    8
0                     1   1       1   1   1                  5

0                     2   2   2   2   3   2                 13
-1                   1   1   2   1   1   1   1                8

0                     1   1   1   1   1   1                  6
-1                   2   2   3   2   2   2   2               15
-2                 1   1   1   1   1       1   1              7

0                     1   1   1   1   1   1                  6
-1                   1   1   1   1   1   1   1                7
-2                 2   2   2   2   2   1   2   2             15
-3               1   1   1       1   1   1   1   1            8

and now not repeating all the constant rows

-1                   1   1   1   1   1   1   1                7
-2                 1   1   1   1   1   1   1   1              8
-3               2   1   2   1   2   2   1   2   2           15
-4             1           1   1   1   1       1   1          7

-2                 1   1   1   1   1   1   1   1              8
-3               1   1   1   1   1   1   1   1   1            9
-4             2       1   1   2   2   1   1   1   2         13
-5           1       1       1   1       1           1        6

-3               1   1   1   1   1   1   1   1   1            9
-4             1   0   1   1   1   1   1   1   1   1          9
-5           1   1   1       2   1   1   1       1   1       10
-6                 1       1           1       1              4

-4             1   0   1   1   1   1   1   1   1   1          9
-5           1   1   1       1   1   1   1       1   1        9
-6                 1       1   1       1       1              5
-7                               1                            1

There may exist a game of 51 moves, but I am not interested in that optimization. The above is already more elaborate than I had hoped.

Austin, 20 September 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD 1135

The knight's tour

Early September, after 2 weeks in Austin, I was for a few days back in the Netherlands, where even Netty van Gasteren's excellent hospitality did not prevent me from suffering from jet lag. Hopelessly awake during the 2nd night in Waalre, I was reminded of the problem of the knight's tour, a problem at which I had looked a number of times, but each time only to turn away from it because I found it too ugly. This time, I was in a very different mood: with so much experience now in the conscious avoidance of complications, I felt that now I should be able to solve the problem. Here is how I arrived at a solution.

*         *         *

The move of the knight changes one of the coordinates of its position by 2, the other coordinate by 1; thus, from a square sufficiently far from the edge of the board, 8 different moves are possible. Show that there exists a knight's path that visits each square of the 8x8 chessboard exactly once.

My first decision was to show the existence by constructing a witness, my second decision was to aim (for a start) at a cyclic path, the cyclic path being simpler because it has no endpoints.

Next I tried to "simplify" the knight's move by looking for an environment in which I could concentrate on the coordinate being changed by 2 and in which the change by 1 of the other coordinate was a (temporarily) ignorable perturbation. I obtained that environment by

(i) covering the chessboard by 16 "supersquares", each formed by 4 adjacent original squares

(ii) by restricting myself to moves between supersquares that share a side — these are called the "straight" moves, the others are called the "skew" moves.

ad (i) |  | [picture]

ad (ii)

the 4 straight moves |  | the 4 skew moves

For the straight moves the set of reachable supersquares is independent of the internal position within the starting supersquare: they are (in the usual wind nomenclature) N, W, S and E. This independence is not found with the skew moves. This observation justifies a (temporary?) restriction to straight moves.

When we name the subsquares of a supersquare and give reachable subsquares in W and S the corresponding names, we observe

      ,

that is, a horizontal step —to W— corresponds to an interchange of the 2 rows, and a vertical step —to S— corresponds to an interchange of the 2 columns. These two interchanges are commuting involutions, and hence we can thus name the subsquares of the whole board. To give an alternative phrasing: reachability via straight moves generates 4 equivalence classes, which we labelled a, b, c, and d.

As the adjoining maze —a so-called "Gomory maze"— shows, the 16 supersquares can be arranged in cyclic paths so that neighbours in the path share an edge on the board. In other words: using straight moves only the original problem of all 64 squares on a single cycle cannot be solved, but the 4x16 squares divided over an a-cycle, a b-cycle, a c-cycle and a d-cycle is easily solvable (in many ways even: the different cycles don't need to use the same Gomory maze.).

The remaining problem is to combine these 4 cycles into a single one. From each of the 4 cycles at least 1 straight move has to be taken away and an equal number of skew moves have to be added. I tried what seemed the simplest: remove from each of the 4 cycles precisely 1 straight move. We get a single cycle if and only if the 4 straight moves taken away and the 4 skew moves added form a cyclic path (on which, by necessity, the two types of move alternate):

This was the moment I left my bed for now I needed pencil to construct the following cycle of length 8:
drawn moves are straight, dotted ones are skew. In particular the analysis that the 4 straight moves were from the 4 different cycles was much more than I could do in my head. The above configuration of straight moves can for instance be found when the 4 cycles are formed with the same Gomory maze, and this observation concludes my proof.

The above solution is nice because it is so simple that people can remember it, and as such it is cause of some satisfaction, if not pride. That it was constructed following the discipline that is now so well-known, tempers the pride, but strengthens the satisfaction.

Austin, 26 September 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 20-Sep-2011

EWD1137

Computing the future?

I read almost all of "Computing the future: a broader agenda for computer science and engineering", edited by Juris Hartmanis and Herbert Lin, for the National Research Council. The book is printed with soy ink on acid-free recycled stock (and that is perhaps the best we can say about it).

One way of writing a book by a committee is to restrict its contents to the intersection of the various opinions; it is a technique that tends to lead to short texts of high quality, and has the advantage that in the case of a sufficiently diverse committee, it leads to no text at all. The current book seems more to have been compiled by the dual technique that includes the union of various opinions; it is a fat report —100,000 words— of uneven quality and —as is only to be expected under such circumstances— most of it is of dubious nature.

It is depressing literature because major parts of it have been written with so little competence, so little idealism, and so little respect for its readers. For me personally, it was particularly disturbing as it challenged the wisdom of my decision to emigrate to the USA: it mostly offers recommendations for mediocrity and worse, urging the American CS departments to strengthen their worst characteristics.

Compared to the European Universities in whose climate I grew up, the American University is much less isolated from the society surrounding it. I knew this before I came, I observe here the experiment (sometimes bewildered!) with interest and conclude that the US campus is insufficiently protected against outside pressures and fads. But The Book recommends to strengthen the ties with the computing industry even further. In view of the divergent goals, the cooperation is, of course, doomed: the main purpose of industry is to make money and, for the sake of its continuity and stability, industry tries to do that in a way that makes it as independent as possible of the special competence of individual employees, whereas the primary purpose of the university is to lay for its students the basis for an intellectually rewarding life.

My former responsibilities for Dutch academic Computing Science implied that I had to study what made tentative academic disciplines viable and what constraints were indispensable for the creation of a first-class department.

One requirement that stood out was coherence of the subject matter: in the knowledge and abilities to be transmitted to the next generation, the knowledge should enable to improve one's abilities, and the application of the abilities should improve one's knowledge. Consequently, it was decided that "applications" were not part of computing science: since computers are truly "general purpose equipment", inclusion of computer applications would destroy the coherence and thereby fatally hurt CS as a scientific discipline. It was the right decision, and it was possible to take it by delaying the creation of separate Departments of Computing Science until the nature of its intellectual contents stood out with enough clarity. The American Universities were less fortunate and they were forced to start prematurely: for lack of alternative, they started with cocktail-departments, many of which —in spite of efforts towards intellectual consolidation— still lack the required coherence. And what does The Book recommend? To "broaden the agenda", to embrace all sorts of applications in interdisciplinary efforts! Years ago, I have learned to interpret pleas for interdisciplinary science as symptoms of anti-intellectualism, and I found the recommendation to "broaden the agenda" in the way proposed just sickening.

A second requirement for the viability of a tentative scientific discipline is the "staying power" of its subject matter: material whose relevance has a half-life of five years is better ignored than taught. (The European conclusion was to exclude, in view of the fickleness of the market place, industrial products from the curriculum.) Here, The Book is mostly ridiculous. It recommends to support CS&E as "a laboratory discipline (i.e. with both theoretical and experimental components)", while admitting that upgrade is "especially important on systems that retain their cutting edge for just a few years". (The Book complains about the difficulties of working in such a fast-changing discipline, but it only changes fast if one fails to ignore the —evidently— irrelevant.)

The Book is quite explicit —p.154— : "In the fast-changing CS&E environment, laboratories must be completely revised frequently, i.e. every several years.", but I expect the trained politician to become very suspicious that the stress on the supposedly experimental nature of CS&E is primarily a political device to extort money, for, moreover, the argumentation of why CS&E should be viewed as "a laboratory discipline" is, of necessity, as weak as the suggestion is dubious: the only argument in favour I found on p.26 "Many operating systems [...] such as MS-DOS and Unix make use of many years of experimental CS&E.". The suggestion —p.149— that the traditional quality criteria for promotion and tenure have to be revised for "CS&E experimentalists" should make the trained politician extra suspicious.

To quote a few offensive/ridiculous sentences:

academic CS&E must increase the number of applications of computing [...] in areas of economic, commercial, and social significance —p.141—

Research can thus be viewed as providing a "service function" to those who develop the nation's computing capability, i.e. the product developers. —p.40—

Intellectually, CS&E includes programming, which allows a programmer's thoughts to spring to life on the screen. —p.213—

Abstraction is a generic technique that allows the human scientist or engineer to focus on certain features of an object or artifact while hiding the others. —p.169—

Let me quote, in contrast, one of the most sensible sentences I found, tucked away on p.132: "Efforts should be made to reduce the distance between theory and practice, to develop researchers who can do both."

Fortunately, the Appendix "Contributors to Computing the Future" mentions only one faculty member of UT Austin.

Austin 15 October 1992

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188 USA

Transcribed by Guy Haworth
Last revised Tue, 1 Jan 2008.

EWD 1140

The arithmetic mean and the geometric mean

From the well-known algebraic identity

(x+y)� ≡ (x–y)� + 4�x�y

we conclude that, when we bring two numbers closer together without changing their sum, we increase their product. Let us call such a transformation “a contraction” of the two numbers. We furthermore observe:
(i)   when we start with two positive numbers, they remain positive when we contract them.
(ii)  let c lie between the two numbers we start with; then it is possible to contract this pair of numbers so that c occurs in —or, equivalently, “is an element of”— the resulting pair.

Consider now a bag containing n positive numbers, with n ≥ 2 (n=0 is not interesting, n=1 is trivial). Let c be their average, i.e. n.c = the sum of the n numbers in the bag.

For such a bag we observe:
(iii)  either all numbers in the bag equal c or the bag contains a pair of numbers ≠ c, such that c lies between them.

We now consider the following algorithm, operating on the bag in question

do  | ¬ (all numbers in the bag are equal to c) →
| select a pair of numbers different from c,
|   such that c lies between them;
| replace in the bag the pair selected by
|   their contraction in which c occurs
od

and we observe:
•   the step replaces in the bag a pair of numbers by a pair of numbers with the same sum as the pair replaced, hence:

the bag continues to contain n numbers and c remains their average

•   because of (i), all numbers in the bag remain positive
•   because of (iii), the selection of a pair —the first statement of the step— is possible
•   because of (ii), the second step is possible.
•   because of the increase of the product of a contracted pair, and because all other numbers in the bag are positive, the step increases the product of the n numbers in the bag.
•   the step decreases in the bag the number of numbers that differ from c by at least 1, hence the above algorithm, terminates.

So, for any initial bag B containing n positive numbers, we can construct a final bag B� of n positive numbers such that
•   sum.B = sum.B�
•   product.B ≤ product.B�
•   all elements in B� are equal to each other

The last implies that the “arithmetic mean” of B� —i.e. (sum.B�)/n— equals the “geometric mean” of B� —i.e.

n
√

 product.B�  —.

And now we observe —B and B� containing the same number of elements—

        the geometric mean of B
≤         {product.B ≤ product.B�}
        the geometric mean of B�
=         {all elements in B� are equal to each other}
        the arithmetic mean of B�
=         {sum.B = sum.B�}
        the arithmetic mean of B   .

The above proof was designed during the last session of the ETAC, and it is recorded because we thought it much nicer than Cauchy’s proof that J.Misra subsequentially showed us.

Lost Maples, 24 October 1992

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD1142

It is all distributivity

Let • be a binary infix operator. Depending on how we Curry, we can form two classes of unary operators from , the general elements of which are often denoted by (x•) and (•y), defined

(x•) = 〈λy: x•y〉      (•y) = 〈λx: x•y〉

We call them in this note "the derived unary operators".

To begin with we observe —with apologies for the two different usages of parentheses—

(x•z)•y = x•(z•y)

=        {definition of derived operators}

(•y).((x•).z) = (x•).((•y).z)

=        {definition of functional composition}

((•y)◦(x•)).z = ((x•)◦(•y)).z  ,

hence, that a binary operator is "associative" means that its derived unary operators commute.

To say that • "distributes over" some binary operator is really a statement about its derived unary operators: "• distributes from the left over □" means that for all x, y, z:

  (x•).(y □ z) = (x•).y □ (x•).z   ;

distribution from the right means similarly

  (•x).(y □ z) = (•x).y □ (•x).z   .

Both formulae are of the form

  f.(y □ z) = f.y □ f.z  ,

which captures "f distributes over □". But what comes of this formula if □ turns out to be unary? Replacing in the last formula p□q by g.p, we get

  f.(g.y) = g.(f.y) or f◦g = g◦f .

Hence, that two unary operators "commute" means that they distribute over each other. Hence, that a binary operator is associative just means that its derived unary operators distribute over each other.

Austin, 2 November 1992

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas as Austin
Austin, TX 78712-1188 USA

Transcribed by Guy Haworth.

Last revised Mon, 31 Dec 2007.

EWD 1145

A somewhat open letter to Cathleen Synge Morawetz

"I would like to say a word or two about the subject applied mathematics.

[...]

I wish I could avoid the expression "applied" altogether, but it's there and the meaning that I attach to it is:

It is mathematics.

It is connected to some other science including engineering science.

          I then proceed to strip it down and I exclude statistics. If I did not want to talk about v. Neumann I would also exclude computer science. And I think computer scientists would most definitely agree."

from C.S. Morawetz, Giants, Amer. Math. Monthly, 99 (1992) 819 - 828.

Dear Professor Morawetz,

please allow me to point out that there exists at least one computing scientist that most definitely disagrees, viz. yours truly.

Digital systems, whether circuitry or programs, are not born, they have to be designed, and in particular designed in such a way that they demonstrably meet their specifications. We know of only one genuine way of giving that demonstration: a mathematical proof. To which I can add, firstly, that only very formal, calculational mathematics is up to this challenge, and, secondly, that it is the designer's responsibility to choose such interfaces between the modules that the proofs remain physically feasible. It is the combination of these two aspects that makes digital system design an area par excellence for the mathematical engineer, and in those countries where "mathematical engineer" is a well-established academic title, its bearer is obviously and most definitely considered an applied mathematician, and rightly so.

Consequently, I find the last sentence quoted rather baffling; moreover, when I take into account that you are a recent director of the Courant Institute at N.Y.U., the sentence becomes so disturbing that I almost regret having read it.

With my greetings and best wishes,

yours truly,

                               Edsger W. Dijkstra

Austin, 22 November 1992

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Mon, 31 Dec 2007

EWD 1151

A terrible Thursday

Due to a conference on discrete algorithms, held here in town, the Department is flooded by speakers that "are in Austin anyhow". This morning, we had a speaker on the —I guess asymptotic— complexity of scheduling divide-and-conquer algorithms on a hypercube machine. He tried to convey his message via a mixture of sentences, gesticulations, formulae, and pictures; the design of a "language" adequate for the presentation of his material seemed to me to be his most urgent task. The end of his talk was particularly unintelligible; here I confine myself to something I saw earlier.

I had noticed that in almost all his formulae "p" occurred in the combination "log p", so that his formulae could be shortened by expressing them in y instead, with y and p linked by "y = log p". But then he showed the formula —well, not really!—

log p log logx p

Could this be expressed in y ? And, if so, how? The answer is "yes", and in the speaker's notation the result be

y logx y !

The explanation of this miracle is to be found in the intended parsing of the original formula, viz.

(log.p).(log.(log.p))x .

My question on how to parse his formula was considered irrelevant since, in the mean time, it had been shown that x=1 could be chosen.

*          *
*

Later that day we had a Distinguished Lecturer with a survey of the complexity results for approximations. There were obvious linguistic problems. Concerning the feasibility of something, he should have written

"There exists a δ for which it cannot be done"

or perhaps

"For some δ, it cannot be done"

or perhaps

"It cannot be done for all δ";

he wrote

"It cannot be done, for some δ",

in view of the preceding formulation clearly an unfortunate choice: it should be absolutely —i.e. syntactically— clear whether the clause about {delta} is within or without the scope of the negation, and the answer now depends on the absence or presence of a comma.

More suspicious I became at the visual stating that something

"maximizes the number of random strings R such that [...]"

where this was the only occurrence of the identifier R. This sentence was repaired by removal of the superfluous identifier "R" and the here nonsensical adjective "random". (Note that also the word "random" requires some sort of scope: when you introduce "a random bit" into something, this is short for introducing 2 somethings, one with a 0 and one with a 1. The scope of the duplication has to be clear.)

I became totally desperate at the introduction of something of the syntactic form

CPC [s(n),q(n),e(n)] .

Here, "n" was of type "natural number", because that was the type of the argument of functions s, q and e. I think that CPC was an identifier, global to the definition being given, that s, q and e were formal parameters —dummies, local to the definition— of type function, and that the mentioning of n was just a mistake —a convoluted way of typing s, q and e—. I think that an "instantiation" like

CPC [s(7),q(7),e(7)]

would be completely meaningless, because the something introduced should have been of the form

CPC [s,q,e] .

I underline "think" because I am not sure, since I could not get the clarification I sought. When the speaker gave the expression "log(n)" as example of a function, I gave up.

I had forgotten how incredibly and unforgivably sloppy the average mathematician is, how inconsistent about his syntax and how vague about the scopes of definitions and quantifications. I love mathematics, but it's mathematicians I cannot stand, for since ALGOL 60 there is no longer an excuse. By the time I came home, I was deeply depressed.

Austin, 28 January 1993

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Tristram Brelstaff
revised Wed, 7 Oct 2009

EWD 1152

Het intellectuele gehalte van informatica

Op de vraag wat het vak "informatica" behelst, kan je de meest verschillende antwoorden krijgen, en dat is dan niet doordat je zegslieden niet weten waarover ze praten, maar doordat de op verschillende plaatsen geaccepteerde definities inderdaad ver uiteenlopen. Dm te beginnen zullen wij daarom enige aandacht schenken aan de aard van die diversiteit en aan de historische omstandigheden, die hiertoe aanleiding hebben gegeven.

Van historisch belang zijn vooral de eerste drie decaden na de oorlog: in de 40er jaren de bouw van de eerste "laboratorium computers", in de 50er jaren de eerste industriële machines, universitaire rekencentra, en de opkomst van professionele genootschappen zoals de ACM (= Association for Computing Machinery, USA), de BCS (= British Computer Society, UK) en het NRMG (= Nederlands Rekenmachine Genootschap, NL), en in de (late) 60er jaren de benoeming van speciale hoogleraren, hetzij ondergebracht in bestaande faculteiten, dan wel in de nieuwe afdelingen die opgericht gingen worden. Die benoemingen waren in elk geval een weerspiegeling van de opvatting dat er specialistische kennis gedoceerd diende te worden, wilde de nieuwe technologie zijn beloofde vruchten afwerpen. Een en ander werd vergemakkelijkt doordat de decade begonnen was met de publicatie van de programmeertaal ALGOL 60, waarvan de geformaliseerde syntax de weg vrijmaakte tot wetenschappelijk onderzoek naar het automatisch genereren van compilers: met ALGOL 60 kreeg het vak aan beide zijden van de Atlantische Oceaan een academische respectabiliteit waarvan —universiteiten de instelingen zijnde die ze zijn— het belang niet onderschat moet worden.

Het Amerikaanse hogeronderwijs reageerde op dit alles vroeger dan het Europese. Dit was primair het gevolg van de na-oorlogse ontreddering van Europa, waardoor de wederopbouw voor jaren de aandacht opeiste, een secundaire factor was de plaats van de universiteit in de Amerikaanse samenleving. De Europese academische traditie de campus als een wereld op zichzelf te beschouwen heeft in Amerika nauwelijks wortelgeschoten, de academische gemeenschap is er meer verweven met de omringende maatschappij, is opener, maar ook minder afgeschermd. Het heeft er toe geleid, dat in de USA allerlei "Departments of Computer Science" zijn opgericht voordat duidelijke intellectuele contouren voor het vak al getekend konden worden. Dit heeft geleid tot afdelingen die weinig meer waren dan een onsamenhangend allegaartje van disciplines, die wel iets met rekenmachines te maken hadden, van bouwers tot gebruikers. In de daaropvolgende kwarteeuw zijn de ergste uitwassen getrimd: "computer engineering" heeft een onderdak gevonden bij de afdeling electrotechniek, en de administratieve toepassingen zijn afgeschoven naar de afdeling bedrijfskunde, maar allerlei sporen van de wat overijlde oprichting zijn nog steeds duidelijk zichtbaar: er is nog veel onsamenhangendheid, en de aandacht is nog steeds heel sterk op de hardware gericht (en dat terwijl in 1956 de president van de ACM al de algemene consensus constateerde, dat de ACM zich niet meer met hardware moest bezighouden!).

Door de omstandigheden ging Europa wat minder overijld te werk, wat al in de naam van het vak wordt weerspiegeld: in de UK is het overwegend "Computing Science", terwijl het continent voor "Informatica" heeft gekozen. Vergeleken met de USA weer: spiegelt de Europese ontwikkeling heel duildelijk twee verschillen: minder fascinering met contrapties, en een grotere neiging academische activiteiten op hun academische merites te beoordelen. Bij de vormgeving van het vak is op de Europese campus gemiddeld meer aandacht besteed aan de levensvatbaarheid van de academische discipline, en om der wille van de levensvatbaarheid hebben samenhangendheid en bestendigheid hoog in het vaandel gestaan. In naam van de samenhangendheid zijn alle specifieke machinetoepassingen er buiten de deur gehouden —in de USA vallen numerieke wiskunde en "artificial intelligence" normaliter onder "Computer Science", terwijl ik me uit Europa nog levendig te tijd herinner dat geen zinnig mens er over dacht die tot de "Informatica" te rekenen—. In naam van de bestendigheid werd het marktartikel geschuwd, want dat is binnen een paar jaar door iets anders vervangen —in Noord-Amerika waren universiteiten, waar elke nieuwe versie van OS/360 aanleiding gaf tot een herziening van het curriculum, maar wie interesseert het nu nog waar "JCL" een acronym voor was?—. Europa werd hierin bijgestaan door IBM, die Europa toen nog niet als belangrijk afzetgebied beschouwde en het daarom niet nodig vond de Europese universiteiten op grote schaal zijn product op te dringen, een verwaarlozing waarvoor we nog steeds dankbaar mogen zijn.

Het bovenstaande maakt begrijpelijk dat zich navelstarend afvragen of "Computer Science" eigenlijk wel een wetenschap was, in eerste instantie een Amerikaans verschijnsel is. Newell, Perlis & Simon hebben geprobeerd die twijfel weg te nemen door te verklaren: "Feiten geven aanleiding tot wetenschap; computers bestaan, ergo!", maar dat heeft natuurlijk nooit overtuigd: het gedrag van je eigen artefacten wordt niet interessant omdat je het niet voorzien hebt of niet begrijpt

De twijfel aan het wetenschappelijke gehalte van haar "Informatica" werd Europa bespaard zolang, door het stellen van kwaliteitseisen, wildgroei en fragmentatie konden worden voorkomen, maar na 1970 was nergens meer aan deze voorwaarde voldaan. De jonge informatica werd meegesleurd in de maalstroom van grotere gebeurtenissen. Ingeleid door de studentenonlusten van de late 60er jaren heeft een Westerse versie van Mao's Culturele Revolutie op de universiteiten een voorlopig blijvende schade aangericht, en kwaliteitseisen zijn sindsdien, als "elitair", ideologisch suspect. De volgende aanslag kwam van de eerste oliecrisis, waardoor grote groepen en organisaties zich plotseling in hun bestaanszekerheid bedreigd voelden: waar grote studentenaantallen gewenst werden om de hooggeleerde werkgelegenheid te waarborgen, gingen kwaliteitseisen als politiek inopportuun overboord. (Er is wereldwijde schade aangericht door de bange wiskundigen die zich uit vermeend lijfsbehoud als kant-en-klare informatici hebben gevestigd.) In landen zoals Engeland en Nederland, waar de overheid enthousiast aan deze afbraak heeft meegewerkt, is de academische verloedering een voldongen feit, en wij moeten vrezen, dat de jongere disciplines daardoor zwaarder zijn aangetast dan zij, wier tradities nog hecht verankerd zijn in de tijd van voor Mao. Als laatste handicap voor de informatica moet ik noemen dat het als wetenschappelijke discipline zijn tradities nog moest vormen toen op de campus bord en krijt al waren verdrongen door de "overhead projector", het apparaat waarmee iedereen, die geen voordracht kan houden, denkt te kunnen doen alsof, maar dat haast elke voordracht verlaagt tot het niveau van een presentatie.

Wat mij in de informatica altijd zo heeft aangetrokken is dat wat conceptueel mooi in elkaar zat, in de praktijk onmiddellijk eminent bruikbaar was, terwijl elk niet triviaal practisch project onmiddellijk aanleiding was om diep en indringend te denken. De opkomst van wat zich als "theoretisch informatica" aandiende heb ik dan ook altijd betreurd: vergeleken bij "informatica" tout court is het mij een te beperkte, om niet te zeggen bekrompen, activiteit. Maar het kwaad is geschied, en dat het tot even betreurenswaardig tegengif aanleiding zou geven was te voorzien. Wat ik niet voorzien heb, was dat het tegengif onder zoveel verschillende namen zou worden ingespoten: "toepassingsgerichte informatica", "experimentele informatica", "software engineering", "systems", "architectuur", etc., activiteiten waarvoor de theoretisch informaticus zijn neus pleegt op te halen, doorgaans terecht, maar doorgaans ook zonder zich te realiseren dat zijn eigen keuze een symptoom vandezelfde ontaarding is.

Wie aan het wetenschappelijke gehalte van de informatica twijfelt, moet twee dingen bedenken. Voor zo ver die twijfel is ingegeven door het feit dat vele beoefenaren der informatica niet tot de intellectuele elite behoren —met alle gevolgen van dien— moet bedenken dat de informatica dit lot met de hele academische wereld deelt. (Onlangs bekloeg zelfs een theoretisch physicus zich tegenover mij over het aantal charlatans in zijn vak!) Voorts moet de wetenschap niet beoordeeld worden op het gehalte van de commerciële activiteit: de gigantische hoeveelheid dubieuze boeken en tijdschriften die de markt overstroomt —met meer nieuwe titels dan de categorie "fiction"!— is beschamend, maar niet voor de wetenschap, want die heeft hier part noch deel aan.

Austin, 5 februari 1993

(Op verzoek geschreven voor De Automatiseringsgids.)

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Mon, 31 Dec 2007

EWD 1155

A prime is in at most 1 way the sum of 2 squares

EWD1154 dealt with D.Zagier’s proof that a prime of the form 4k+1 is the sum of 2 squares. In fact, such a prime is in only 1 way the sum of 2 squares. In this note we show this by proving that if an odd n is the sum of 2 different pairs of squares, then that n is not prime.

Let an odd n be the sum of 2 squares; then the one square is odd, the other is even: the squares are of different parity. Let n be the sum of 2 squares in 2 ways; then there exist positive a, b, c, d such that

(0) | (a + b)� + (c – d)� = n
| (a – b)� + (c + d)� = n

(Here a is the average of the numbers of the one parity, c is the average of those of the other parity. Because we are considering distinct square decompositions, also b and d can be chosen positive.)

Eliminating n from (0) by equating the left-hand sides, we deduce after simplification

(1) | ab = cd       ,

from which we deduce the existence of positive r, s, t, v such that

(2) | a = sv
| b = rt
| c = st
| d = rv

(Consider “s := a gcd c;   v := a/s;   t := c/s;   r := b/t”.)

Now we observe
        n
=         {(0)}
        (a + b)� + (c – d)�
=         {(1)}
        a� + b� + c� + d�
=         {(2)}
        s�v� + r�t� + s�t� + r�v�
=         {algebra}
        (s� + r�) ∙ (t� + v�)

and because the 4 variables are positive, the two factors are each at least 2, and hence n is not a prime number.

*         *         *

The above was written down in Abilene State Park. In contrast to the proof discussed in EWD1154, I designed this proof myself, but the title of this note does not mention “derivation” of the proof, since I did not “derive” it in any technical sense.

I have considered investigation of the situation x�+y� = n ∧ u�+v� = n ∧ prime.n with the aim of showing (x,y) = (u,v) ∨ (x,y) = (v,u), but rejected that approach for the disjunction, and for the fact that I saw no way of using n’s primality. So I did some shunting and set myself to show that n was composite by writing it as a product of 2 plurals. I knew my complex numbers, in particular, that the modulus of a product is the product of the moduli, and then discovered that there was no point in looking at (x+yi)�(u+vi). Hence

(3) | (sv – rt)� + (st + rv)� = (s� + r�) � (t� + v�)

—the 2 expressions for the modulus of (s + ri) � (t + vi), which do equate a sum of squares to a product— has to be used differently. The right-hand side being even in r, it also equals (sv + rt)� + (st – rv)�, and now we see the a, b, c, d entering the picture. The introduction of a � b and c � d circumvented the disjunctive complication of comparing unordered pairs.

I think I knew (3) outside the context of complex numbers as well; it is very common to separate in (a � b)� the squares from the cross product, as in

| (a + b)� = (a – b)� + 4ab
| (a + b)� + (a – b)� = 2(a� + b�)       .

The proof reported provides a striking example of a proof in which the algebra is totally trivial while all subtlety has been invested in the decision what to name.

Austin, 7 June 1993

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1155a

A prime is in at most 1 way the sum of 2 squares

In EWD1154 we dealt with D. Zagier’s proof that a prime of the form 4k+1 is the sum of 2 squares. For such a prime, this “square decomposition” is, in fact, unique. Here we show this by proving that an odd number is not prime if it is the sum of 2 different pairs of squares. Proving than a number is not prime will be done by rewriting that number as the product of 2 plurals. (A “plural” is a natural number ≥ 2.)

Remark   The definition of primality that we use —and which I often found to be the nicest one— is

| prime.n  ≡〈∀x,y: x ≥ 2 ∧ y ≥ 2: x∙y ≠ n〉   ;

the existential quantification expressing non-primality is demonstrated by constructing a witness. (End of Remark.)

*         *         *

There are two distinct aspects to this problem. There is the algebraic aspect of expressing the sum of 2 squares as the product of 2 plurals, and there is the notational question of how to express that a number admits 2 different square decompositions.

Let us look at the algebraic aspect first. The simplest formula I know that equates the sum of 2 squares to a product

(0) | (a + b)� + (a – b)� = 2�(a� + b�)       .

Remark   This formula is of independent interest in the context of square decompositions: regardless of primality it establishes for any n a one-to-one correspondence between the square decompositions of n and those of 2n. (End of Remark.)

We cannot use (0) “as is”, for we have to write odd numbers as the sum of 2 squares. So we generalize the left-hand side to (a + b)� + (c – d)�, but restrict ourselves to the situation with

(1) | a�b = c�d       ,

so that we inherit from (0) that the 2 cross-products cancel:

(2) | a�b = c�d   ⇒   (a + b)� + (c – d)� = a� + b� + c� + d�       .

Note that the right-hand side of the consequent is an even function of the variables. So much for the algebraic aspect.

We now turn to the question of how to express that an odd n admits 2 different square decompositions. Here the problem is that x�+y� and y�+x� count as the same square decompositions. We can, however, exploit that n is odd; hence, when n is written as sum of 2 squares, the one square is odd and the other square is even. Consequently, if odd n admits 2 different square decompositions, we can choose positive a, b, c, d such that

(3) | (a + b)� + (c – d)� = n   ∧
| (a − b)� + (c + d)� = n         .

Here a is the average of the numbers of the one parity, and c the average of those of the other parity; because we are considering different square decompositions of n, also b and d can be chosen positive.

Eliminating after this choice n from (3) by equating the left-hand sides, we deduce after simplification a�b = c�d, i.e. (1), and then, combining (1), (2), and (3)

(4) | n = a� + b� + c� + d�       ,

thus reducing our proof obligation to showing that, thanks to (1), the right-hand side of (4) can be factorized as the product of two plurals.

We meet this last proof obligation in a totally classic manner: we exploit (1), i.e. a�b = c�d, by solving the equation

(5) | a,b,c,d   :   a�b = c�d      ,

then substitute the general solution into the right-hand side of (4) and look what we can do with the resulting expression.

Multiplication being symmetric and associative, we have for any q,r,s,t

| (q�r) � (s�t) = (q�s) � (r�t)

and hence, (5) is solved by

(6) | a = q�r |  | (i)
| b = s�t |  | (ii)
| c = q�s |  | (iii)
| d = r�t |  | (iv)   ,

but this observation only tells us that (6) is a particular solution of equation (5), and we need the latter’s general solution. We shall now show that (6) is also the general solution of (5) by showing that for any solution of (5), there exist natural q, r, s, t satisfying (6). We show the existence by constructing a witness:

| q := a gcd c  
;   | r := a / q   {(6) i}
;   | s := c / q   {(6) iii}
;   | t := b / s   (or t := d / r)   {(6) ii and (6) iv}

Because q is a divisor of a and c, q, r, and s are integer; moreover, since q is the greatest common divisor of a and c,

(7) | r gcd s = 1       .

With (i) and (iii) satisfied, we deduce from (1) —and q≠0—

| r�b = s�d

from which we conclude, in view of (7), that r divides d and that s divides b, and in general —r≠0 and s≠0— b/s=d/r. So either assignment to t does the job.

And now we are essentially done, for

        a� + b� + c� + d�
=         {(6)}
        (q�r)� + (s�t)� + (q�s)� + (r�t)�
=         {algebra}
        (q� + t�) � (r� + s�)

and the parameters q, r, s, t differing from 0, the factors are plurals.

For devastating comments on an earlier version —gross omissions and major rabbits— I am indebted to the ETAC, to Wim H. Hesselink and Rutger M. Dijkstra. Lex Bijlsma was so kind to retrieve that —apart from less fortunate notation— my proof, originally conceived between Amarillo and Abilene, had also been designed by Euler.

The above argument is reported because it provides a striking example of a proof in which the algebra is totally trivial, while all subtlety has been invested in the decision what to name.

Austin, 19 August 1993

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1156

Voorwoord

Het is een voorrecht op ietwat oudere leeftijd een voorwoord te mogen schrijven voor het jaarboek van een studievereniging, die "introspectie" als thema voor 't jaarboek heeft gekozen. Naarmate de periode waarop een mens kan terugblikken langer heeft geduurd, wordt de neerslag daarvan namelijk eenvoudiger: de tijd filtert. Een nevenattractie is dat het een studievereniging betreft aan de Universiteit Twente, bij wier initialen ik me na bijna een decade aan de University of Texas voortreffelijk thuisvoel.

Mijn eerste punt is dat ik alle studieverenigingen met klem zou willen aanraden zich in te spannen voor hun leden, en de Universiteit te laten voor wat zij is, en dit om de prozaische reden dat, terwijl de Universiteit —alle UT's natuurlijk uitgezonderd?— in het maatschappelijke gesol waarschijnlijk al reddeloos verloren is, individuele studenten wel geholpen kunnen worden. In het geval van informatica is dat gesol door twee oorzaken namelijk extra erg.

De ene oorzaak van ellende is dat door verweving met (vermoede) economische belangen het veld van de slogans, reclamekreten, misleidende termen en valse beloften is vergeven: Expert Systems, Learning Machines, Thinking Machines, Automatic Programming, Higher-Order Languages, Visual Programming, Program Animation, Software Engineering, het is allemaal humbug. Een van de belangrijke bijdragen van een studievereniging (en dat is mijn tweede punt) is daarom het koesteren en bevorderen van de immuniteit harer leden voor al deze geavanceerde vormen van kwakzalverij. Deze ontmaskering is van origine natuurlijk een taak van de Universiteit, maar met zoveel schertsdisciplines op de campus is haar vermogen daartoe ernstig geschaad.

De andere oorzaak van de ellende ligt in de ongebreidelde heilsverwachting waarmee de maatschappij (in haar wanhoop en onnozelheid) de informatica heeft opgezadeld. Een positieve handelsbalans voor alle landen, een perfect werkende democratie overal, onmiddellijke beschikbaarheid alom van alle wetenschappelijke resultaten, wereldvrede en universele mondigheid voor ieder vanaf het vijfde levensjaar zijn nog maar de kleinere wonderen die we geacht worden voor het einde van de eeuw te realiseren. Uit vrees hun financiering aan te tasten, zwijgen de universiteiten over de irrealiteit van deze dromen. Een studentenvereniging (en dat is mijn derde punt) zou de intellectuele sfeer kunnen zuiveren door niet klakkeloos het dogma te aanvaarden dat meer en snellere computers en netwerken per definitie een vooruitgang betekenen.

Ik denk dat in de komende decaden de studenten een belangrijke taak krijgen in het voorkomen dat het universitaire bedrijf aan oneerlijkheid ten gronde gaat. Moge de studievereniging "Inter-Actief" tegen deze uitdaging opgewassen zijn!

PS. Ik hoop dat U begrepen hebt dat ik er op reken dat de studievereniging zich inzet voor de instelling van een leerstoel in de Senioreninformatica, zodat ik die t.z.t. kan bekleden. Dat ik mij dan zal belasten met de oprichting van een subvereniging Inter-Semiactief, waarvan de 60+ers dan voor half geld lid kunnen zijn, spreekt vanzelf. (Einde PS)

Austin, 9 June 1993

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

(Written at the request of A.P.Bulthuis, vice-chairman of the student society for informatics "Inter-Actief" at the University Twente, The Netherlands)

transcribed by Martijn van der Veen
revised Mon, 31 Dec 2007

EWD1157

Introducing a course on program design and presentation

Historically, the nature of the programming challenge has been widely misunderstood and the difficulty has been grossly underestimated.

The first program fed into the first stored-program controlled computer —the EDSAC in Cambridge, England— was supposed to cause the machine to print a table of squares, which was duly printed. The second program, which was for table of prime numbers, was, however, wrong. Consequently, right from the beginning, the academic community had been warned and should know better than to belittle the programming challenge. It did know better and warned, but for decades its warnings have been suppressed and drowned out by the propaganda machines of the computer industry —in particular IBM— and of the Pentagon. For the protection of their interests, these organisations thought it vital to convince the general public that programming was no serious problem, that it required no intelligence and certainly no education. With the appropriate programming languages —such as COBOL, PL/I, and ADA— programming’s problems would melt as snow in the sun.

Under these pressures it has been difficult to get Programming Methodology accepted as a topic of academic research and teaching. The barriers were a little less unsurmountable in those societies in which IBM and the Pentagon had less power; the fact that, in recent developments, both organizations have lost all of their surplus credibility (if not more) should in this respect assist American Departments of Computing Science in catching up.

*                *
*

This course is given from the position that an academically educated computing scientist should be able to program at least an order of magnitude better than the average programmer or the hacker without formal training. Note that this is a direct consequence of my positions that (i) the programming challenge is of sufficiently high calibre to merit academic concern and that (ii) having absorbed an academic education or not should make a substantial difference. (Note that neither of these positions is necessarily shared by all my academic colleagues.)

There are at least three different ways in which the term “computer program” is used; since I shall use it in this course only in the last of these three senses, let me list them. They could be called the artistic, the legal, and scientific interpretation.

(i) Artistic. Here the program is an automaton created out of curiosity, with the intention of observing its behaviour when exercised. A program in this sense has the intellectual status of The American Flag —“Let us hoist it and look how many salute.”—. People in AI and in Experimental CS have a tendency to consider such “artistic programs” worthy objects of academic concern.

(ii) Legal. Here the user is not supposed really to know what he wants or needs, and the programmer is not supposed really to know what the user wants or needs. Consequently the programmer does not really know what he delivers, nor does the user really know what he gets. Here programs and their documentation have the intellectual status of the texts lawyers compose: of course you cannot expect these texts to be clear, unambiguous and free from contradictions, but if due care has been applied, you cannot complain. The major shortcoming of the legal interpretation —which is the predominant one in today’s software industry— is that it precludes technical improvement of the product. People in Software Engineering —should I say SE ?— tend to adopt the legal interpretation.

(iii) Scientific. Here the program is viewed as a statement in a formal language, i.e., as a formula. When the program’s specification has been stated in an equally formal language, the question of whether the program meets the specification is then a mathematical question. Here, the program is one of the triple: program, specification, and proof that the program meets the specification. Because such a triple is a sound and solid mathematical edifice, I had expected in my innocence that this view of programs would appeal to the mathematical community, but it does not, the reason being that the required proof style leaves no room for handwaving and the mathematical guild has developed no appreciation for such a style. We stick to this third interpretation of the term “program”: we are heading for programs that are part of the statement of proven theorems.

*               *
*

The idea of mathematically proving the correctness of programs is now more than 30 years old. American Computing Science has tried to realize this in the form of “program verification” —automated or not— : given a program and its specification, prove that the former satisfies the latter, the idea being that the programmer (whom you cannot bother with mathematics) would provide the program, while the mathematician (whom you cannot bother with the tedious trivialities of programming) would provide the correctness proof. This ridiculous division of labour —it is really putting the cart before the horse— condemned the verification project to failure. The proper way of doing it is the other way round; given the specification, one designs the correctness proof and, as that design progresses, derives the program to which the proof is applicable, a method known as “designing proof and program hand in hand”. That this is a much more promising way of doing things than the “a posteriori verification” was well known and understood a quarter of a century ago, but victimized by IBM, the Pentagon, and its failing system of primary and secondary education, the USA has, alas, been unable to hear the message. Be it slowly, things seem to be changing, which could be a consequence of growing internationalization (with my apologies for this appalling noun).

I expect the main ingredients of this semesters course to be the following ones.

A replacement of the (still!) traditional “operational semantics” by what is known as “postulational semantics”, as they provide a compact basis for correctness proofs without exploding case-analyses.

The essentials of the predicate calculus, which I intend to present as a very simple and general, and thus powerful calculational tool for the actual construction of proofs and programs.

The application of the above to the design and presentation of (far from trivial) sequential (and if time permits, parallel) programs.

And, all the time, the critical consideration of decisions taken and conventions adopted.

Austin, 25 August 1993

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Mon, 31 Dec 2007

EWD 1161

How promiscuous are the French?

Some time last summer the paper published without comment the following fact. Asked at the end of his (active) life with how many Frenchwomen he has slept, the average answer of the Frenchman is 14; ask the Frenchwoman with how many Frenchmen she has slept, and her average is 7.

Let M be the number of Frenchmen that have lived, say since 1500 and let F be the number of Frenchwomen that have lived since the same moment. Let P be the number of pairs in that whole population that have slept together. The average number of Frenchwomen a Frenchman has slept with equals P/M, and similarly the average number of Frenchmen a Frenchwoman has slept with is P/F. With P/M = 14 and P/F = 7, the unavoidable but somewhat startling conclusion would be F = 2M, i.e. in the French population twice as many females as males! [The most likely explanations are general dishonesty or between the sexes a different definition of "having slept with", but that is neither here nor there.]

I would not have written this note, had it not been for the reaction of one of my friends. As an example (probably of people not understanding what they talk or write about) I had quoted my paper in one of my letters to him. But, somehow, my friend had no problems at all with the quoted statistics! He saw no discrepancy.

It is amazing, but probably an example of what studying Law, and then leading a Life in Business, can do to an otherwise subtle and intelligent mind.

And for us scientists, it should be a reminder, each time we don't understand the world we live in.

Austin, 11 October 1993

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Tristram Brelstaff
revised Sun, 30 Dec 2007

EWD 1165

There is still a war going on

The mediocre mistrust the exceptional man because they don’t understand him, and they fear him because he can do things beyond their comprehension. As far as human memory is concerned, this circumstance has led to bloody conflicts — Christ was neither the first nor the last excentric to be crucified.

The 20th century has created new battlefields for this old conflict in the form of the high-technology industries; there, the battles are between the managers/beancounters on the one hand, and the scientists/technologists on the other. As a service to my younger readers I point out that these battles are fierce and that no quarter is given. We regularly have to be reminded of these battles because the scientists have a tendency to lose them: firstly, they are a minority, and secondly, their primary interest is their science and not these battles, this in contrast to the manager, who considers this battle his main challenge.

The battle-cries of the managers are absolutely standard, they have not changed since WWII. The scientist is attacked as individual —unruly, rugged individualists being much harder to control than committees— by organizational insistence on teamwork. The scientist is attacked in his professional competence by organizational insistence on interdisciplinary research. Finally, the scientist’s right of existence is denied by the postulate that there is nothing really left to be discovered. [We hear all these slogans now, but they are carefully described in [0] d.d. 1956]

It seems that, these days, the managers are winning the battle: even high-technology companies are now shedding their scientists and engineers at a high rate. [I had already decided to write this note when I found in the International Herald Tribune (no. 34,429 d.d. 1993.11.08, p 13) in an article about the current internal organization of the Matsushita company: “Marketing and sales people have won out over the engineering/production side,” Mr. Goto said.] You can ask how these managers now intend to run their business, but the answer is quite simple: more like trading companies and some sort of financial institutions, these at least being activities the managers think they understand.

An unpleasant complication is that the world of finance is so disreputable and that a whole bunch of new euphemisms has to be introduced to cover up this new layer of dishonesty. For instance, there is no such thing as “making money”: some people succeed in transferring money out of the pockets of others into their own. A number of years ago, the institutions that try to become rich by speculating at someone else’s expense —in Western Civilization known as a “bank”— needed a new euphemism to cover their activities and they started to refer to themselves as “the financial industry”. Lately, they have started to refer to their more elaborate extortion schemes as "(sophisticated) banking products”! Industries are expected to produce something, aren’t they?

All this is particularly grievous for the computing scientist. For 40 years, the computer industry has completely ignored the findings of computer science, and, now the computer industry is in trouble, its management gives the blame to the computer science community! We failed to do the relevant research, failed to train the work force that would solve industry’s problem, etc.. But the managers themselves are, of course, a major part of the problem, something I was relatively slow to discover.

Decades ago I realized (in Europe) that we should not confuse the intrinsic difficulties of automatic computing with the problems engendered by the shortcomings of the US educational system. Too many US Colleges of Education have operated on the principle that it is more important that their students learn to teach than that they master the material to be taught, an underestimation of the significance of the intellectual contents of proper teaching that has, for instance, led to a general abhorrence of mathematics (and the corresponding incompetence) that must be seen to be believed. (Needless to say, in the century in which the widespread availability of programmable computers has made familiarity with formal techniques more rewarding than ever, this progressive demathematization of the USA is a particularly tragic development for that country.)

Later I learned that we should neither confuse the intrinsic difficulties of automatic computing with the problems generated in industry by the prevailing managerial preconceptions. Analogous to the Colleges of Education, too many of the Schools of Business Administration operate on the principle that it is more important their students learn how to manage than that they acquire any understanding of the process to be managed. Consequently, software managers who have not the foggiest notion of what programming is all about, are only too common. To compound the problem, many managers still strive for the traditional goal of making (in the name of stability) the company as independent as possible of particular abilities of its employees — even if this seems hard to defend in any high technology industry; they tend to attract incompetent programmers as they would not know how to employ competent ones. (A recent CS graduate got her first job, started in earnest on a Monday morning and was given her first programming assignment. She took pencil and paper and started to analyse the problem, thereby horrifying her manager 1½ hours later because “she was not programming yet”. She told him she had been taught to think first. Grudgingly the manager gave her thinking permission for two days, warning her that on Wednesday she would have to work at her keyboard “like the others”! I am not making this up.) And also the programming manager has found the euphemism with which to lend an air of respectability to what he does: “software engineering”.

When the term was coined in 1968 by F.L. Bauer of the Technological University of Munich, I welcomed it. I was at the time at the Department of Mathematics at the Eindhoven University of Technology, our department’s graduates earned the academic title of “Mathematical Engineer”, and I interpreted the introduction of the term “software engineering” as an apt reflection of the fact that the design of software systems was an activity par excellence for the mathematical engineer.

But that interpretation of the term did not sail well. As soon the term arrived in the USA, it was relieved of all its technical content. It had to be so for in its original meaning it was totally unacceptable: firstly, mathematics (and certainly formal mathematics) was widely considered impractical and irrelevant, secondly, the public at large had been brainwashed by IBM. (1968 was also the year of the IBM ad in Datamation, showing in full colour a smiling Susie Mayer, who had solved all her programming problems by switching to PL/I !) The dilution was further eased by the fact that the Anglo-Saxon “engineer” is more vocational, is closer to the “technician” and is of much lower intellectual (and social) status than his Continental counterpart. (I did some probing on how university departments are ranked in the USA; my impression is Education and Business Administration at the bottom, with Engineering as a close third.)

In the mean time, software engineering has become an almost empty term, as was nicely demonstrated by Data General who overnight promoted all its programmers to the exalted rank of “software engineer”! But for the managing community it was a godsend which now covers a brew of management, budgeting, sales, advertising and other forms of applied psychology.

Ours is the task to remember (and to remind) that, in what is now called “software engineering”, not a single sound engineering principle is involved. (On the contrary: its spokesmen take the trouble of arguing the irrelevance of the engineering principles known.) Software Engineering as it is today is just humbug; from an academic —i.e. scientific and educational— point of view it is a sham, a fraud.

Universities are always faced with something of a problem when there is a marked discrepancy between what society asks for and what society needs. In our case the need is clear: the professional competence of the Mathematical Engineer, familiar with discrete systems design and knowing how to use formal techniques for preventing unmastered complexity from creeping in. But said war “out there” all but prevents this need from being perceived, and what our immediate industrial environment overwhelmingly seems to ask for is different brands of snake oil, Software Engineering, of course, being one of them. And as, with the recession lasting longer and longer, the external pressures on the Universities to do the wrong things only mount, it is only to be expected that part of the campus is going to be included in the battlefield.

The task of the first-class University, however, is absolutely clear. Industry being its customer, consultancy must tell industry what it wants to hear; it is the task of the first-class University to tell industry what it does not want to hear, whereby it is the rôle of its scientific authority to ensure that the sting of the academic gadfly really hurts.

In my experience —gathered on different continents—, it is impossible to completely prevent all snake oil peddling on campus, but by openly despising it one can at least save the integrity of the academic enterprise as a whole.

[0]  | Whyte, William H., The Organisation Man, Simon & Schuster Inc., New York 1956

Austin, 3 December 1993

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Sun, 30 Dec 2007

EWD1166

"From my Life"

(Written because people ask me for these data.)

I was the third of four children. My father was an excellent chemist, who worked in the town of Rotterdam, first as a teacher of chemistry at a secondary school, later as its superintendent. His knowledge was vast and he was perfectly able (and willing) to teach cosmography or physics when needed. He made a few inventions, one of them really sophisticated. Among chemists all over the country he was well-known —he had, for instance, been President of the Dutch Chemical Society— but steadfastly refused all forms of scientific promotion, explaining that he would rather be the first among the counts than the last among the dukes, but the net effect of adhering to this lofty principle was that he lost the colleagues that were intellectually his equals to the university campus. In the vague idealism after WWII Dutch secondary education deteriorated to such an extent that he forbade me to become a schoolteacher. My mother was a brilliant mathematician who had no job —as was customary in those days, even for most women with a college degree— . Her mind was much less encyclopaedic than that of my father but very quick; she had a great agility in manipulating formulae and a wonderful gift for finding very elegant solutions, and I learned a lot from her though she had not the patience to be a good teacher.

During the last class of the Gymnasium —that was 1947/48— I considered going to University to study law, as I hoped to represent my country in the United Nations. Then we did our final exams. Before we got our grades and were told whether we had passed, I was very depressed, for I reviewed all the mistakes and stupidities I had committed and I got convinced that I would fail. (MY consolation was the conviction that I would get a second chance, always having been the best pupil in the class.) My grades turned out to be better than most teachers had ever seen at a final examination, and older and wiser people convinced me that it was safer to base my choice on ability than on idealism, and that it would be a pity if I did not devote myself to science. So I went to Leyden University to study mathematics and physics during the first years, and theoretical physics during the latter part

On the whole I enjoyed the years at the university very much. We were very poor, worked very hard, never slept enough and often did not eat enough, but life was incredibly exciting. (Now, more than 40 years later, I still remember the first "international" piano recital I attended: Clara Haskil playing Mozart!) Another thing I remember —because it surprised me— was that a number of my professors —Kloosterman, Haantjes, Garter, Kramers— took me seriously.

My father, who was a subscriber to "Nature", had seen the announcement of a three-week course in Cambridge on programming for an electronic computer (for the EDSAC, to be precise), and when I had passed the midway exam before the end of my third year —which was relatively early— he offered me by way of reward the opportunity to attend that course. I thought it a good idea, because I intended to become an excellent theoretical physicist and I felt that in my effort to reach that goal, the ability to use an electronic computer might come in handy. The course was in September 1951; by accident, A.van Wijngaarden, then Director of the Computation Department of the Mathematical Centre in Amsterdam, heard of my plans, invited me for a visit, and offered me a job. Due to obligations in Leyden I could accept that invitation only in March 1952, when I became the first Dutchman with the qualification "programmer" on the payroll. Professor H.A.Kramers, who had accepted me as student of theoretical physics, died, I did not like his successor, and for a while I considered continuing my studies in Utrecht, but it turned out that the laboratory work I would have to do in Utrecht was incompatible with my halftime job at the Mathematical Centre. That was the moment I had to choose between theoretical physics and computing; I chose the latter and my study of physics in Leyden became a formality. I got my degree in the spring of 1956, moved immediately from Leyden to Amsterdam, and from that moment on I worked full time at the Mathematical Centre

My closest collaborators there were Bram J.Loopstra and Carel S.Scholten, who had been hired (while they were still students of experimental physics at the Municipal University of Amsterdam) to build a computer for the Mathematical Centre. They were about five years older than I, had been close friends since the age of 12, and had already worked on their machinery for quite a few years when I joined them. When I came their machine did not work, but they had learned a lot; among the things they had learned was to recognize that their first effort contained too many technological mistakes to be salvageable, and that they should start afresh. So, early in the game I became involved in the design of "the next machine", something that would be repeated a number of times. In retrospect, the most noteworthy aspect of that cooperation is that we accepted without any discussion a discipline that seems rare today: the very first thing we did was to write a programmer's manual for the next machine, including its complete functional description. (For some reason, I was always the one that wrote that document.) This document then served as a contract between them and me: they knew what they had to build and I knew what I could build upon. And about a year later, we would be both ready: they had built their machine and I had all the basic software finished. (Not tested, of course, but that turned always out to be superfluous. At the time I did not realize how valuable this training was of programming for a machine that did not exist yet; now I know.)

I designed my first nontrivial algorithms. The algorithm for The Shortest Path was designed for the purpose of demonstrating the power of the ARMAC at its official inauguration in 1956, the one for The Shortest Spanning Tree was designed to minimize the amount of copper in the backpanel wiring of the Xl. In retrospect, it is revealing that I did not rush to publish these two algorithms: at that time, discrete algorithms had not yet acquired mathematical respectability, and there were no suitable journals. Eventually they were offered in 1959 to "Numerische Mathematik" in an effort of helping that new journal to establish itself. For many years, and in wide circles, The Shortest Path has been the main pillar for my name and fame, and then it is a strange thought that it was designed without pencil and paper, while I had a cup of coffee with my wife on a sunny cafe terrace in Amsterdam, only designed for a demo....

Life became serious when Bram and Carel embarked on the design of the Xl, which after a while they conceived with a real-time interrupt. I was frightened out of my wits, only being too much aware that this would confront me with a machine which was to all intents and purposes nondeterministic. For about three months I was able to delay the decision to include the interrupt, until eventually, they flattered me out of my resistance. (Their plea was along the lines "Yes, we understand that this makes your task much harder, but surely someone like you must be up to it, etc.". ) The real-time interrupt handler became my thesis topic; I earned my Doctorate in late 1959.

In the mean time, the ALGOL project was underway. I had attended a few conferences outside the Netherlands, but it was ALGOL that introduced me to frequent foreign travel. Those trips were very tiring, for my English was untrained. (I am very grateful to Mike Woodger from the National Physical Laboratory, who quickly started correcting my English, but in the beginning only the errors he had heard me make more than once.) In the summer of 1959 I had discovered how to implement subroutines that could call themselves, by the end of the year I saw how to use a stack for the evaluation of expression and how to translate expressions from the usual infix notation into "reverse Polish" (only we did not call it that). For several months, Harry D.Huskey had been working at the Mathematical Centre, having been invited by van Wijngaarden in the hope that he would teach us how to write what was then called "an algebraic translator". Van Wijngaarden wanted us to base our ALGOL 60 compiler on Huskey's work, which was a mess (Huskey being an experimental programmer); I had seen that work and knew that we had to ignore it, but in order to convince van Wijngaarden I had to bang my fist on his table. (I remember this, because this has been the only time that I did so.) Late December I started with J.A.Zonneveld on an implementation of ALGOL 60 for the Xl. We coded the translator in duplo, fully aware that we were making history: each evening each of us took his own copy of the manuscript home so that in case of a fire at the Mathematical Centre our translator would not be lost. (There was no fire.) In August 1960 our implementation was working, more than a year before the one of our nearest competitor, the group of Peter Naur in Copenhagen. In May 1960 I submitted the short article “Recursive Programming" to "Numerische Mathematik", which published it quickly; here I introduced the term "stack" , while describing the quintessence of our implementation. For many years I thought that that paper had been ignored in the USA, but later I learned that it had established my name among America's scholarly computing scientists.

The ALGOL compiler had been a major effort on which I had worked day and night for 8 months, and I needed to recover; more than anything I needed to be free from the responsibility for a large project. For a few years I did not build anything sophisticated and ambitious, but thought, mainly about the logical intricacies of multiprogramming. This was when I formulated the Mutual Exclusion Problem, thought about synchronizing primitives and designed "semaphores" for that purpose. I did not publish that last invention because the company "Electrologica", for which I was a consultant, was going to incorporate them in their next machine, but I freely lectured about the topic. In 1961, at Brighton, Peter Naur and I lectured on ALGOL 60 and its implementation; at that occasion, Tony Hoare and I met for the first time.

At the end of the summer of 1962 I attended the IFIP Congress in Munich, where —thanks to van Wijngaarden— I was given the opportunity to deliver an invited speech. My speech was well-received, and the congress was the occasion at which Niklaus Wirth and I met each other for the first time. When I came back from Munich, it was September, and I was Professor of Mathematics at the Eindhoven University of Technology.

Later I learned that I had been the Department's third choice, after two numerical analysts had turned the invitation down; the decision to invite me had not been an easy one, on the one hand because I had not really studied mathematics, and on the other hand because of my sandals, my beard and my "arrogance" (whatever that may be). I have also been told that I should be very grateful to the Department because it had taken a great risk by appointing me. For two years I gave the courses in Numerical Analysis because they had no one else to do so, and at the same time I began building a little group of computing scientists, In the years that followed, I built with Cor Ligtmans, Piet Voorhoeve, Nico Habermann and Frits Hendriks what became known as the "THE Multiprogramming System" for the X8 (the next machine of Electrologica, of which the university had ordered a copy); machine and operating system served the computation centre of the university very well for about half a decade, until the X8 had to be replaced by a more powerful engine.

With the THE Multiprogramming System we also knew we were making history, because it was the world's first operating system conceived (or partitioned) as a number of loosely coupled, explicitly synchronized, co-operating sequential processes, a structure that made proofs of absence of the danger of deadlock and proofs of other correctness properties feasible. I presented the quintessence of this design in Teddington, in Edinburgh, and in Gatlinburg, Tennessee, (at an ACM Conference on Operating Systems Principles), and it got all the attention and recognition it deserved. The Department saw it differently and disbanded the little group, in reaction to which most of them left the University. It was obviously too difficult for the Department to honour what had been achieved: as classical mathematicians they were not used to group efforts at all, and furthermore it had no connection to the kind of mathematics they were used to. In addition, some began to fear that, instead of a strong component of the Department, Computing Science could become too powerful a competitor for the true mathematics that were the Department's real concern. For me, life became a little bit difficult.

For more than half a year I suffered from a rather severe depression, but things became better when I realized that I was frightened by the next challenge, viz. the study of difficulty as such, and of how to overcome it. How do we do difficult things? My previous more ambitious projects acquired the status of finger exercises, and for therapeutic reasons I wrote "Notes on Structured Programming"; as far as my depression was concerned, the therapy worked.

Of the "Notes on Structured Programming " I sent only about 20 copies to friends abroad, but by that time the copier had become ubiquitous, and (without my knowledge) the text spread like wildfire: later I met people in faraway places who treasured a fifth- or sixth-generation copy! It was not a great text and its spontaneous wide distribution surprised me when I heard of it; the only explanation I have been able to think of is that it was the first text that openly took the programming challenge very seriously. It has certainly played a role in the founding of the IFIP Working Group 2.3 on "Programming Methodology", a topic that would only in the 70s become a subject of academic concern.

Late one afternoon in 1972, the telephone in my office at the University rang; I picked up the receiver, and this was Franz L.Alt of the ACM, calling from the USA to tell me that I had won the ACM Turing Award. It took me by complete surprise for I had never considered myself as a potential recipient of that most prestigious award, and I could hardly believe it, but Alt convinced me that it was really true, and then we disconnected. When I realized that my six predecessors had all been native English speakers working at famous institutes in the USA or the UK, I got even a bit overwhelmed. When I had calmed down I went to the office of the Department's Chairman to inform him if he was still in. He was, and I told him. His first reaction was "In the world of computing, they are rather lavish with prizes, aren't they?". When in the fall of that year, another colleague, N.G.de Bruijn, launched a plan in which a massive undergraduate course in programming would earn the money for the graduate program in "genuine mathematics", I knew it was time to go. After having given Philips the first right of refusal, I became Burroughs Research Fellow on the 1st of August 1973.

That same summer I designed the first so-called "self-stabilizing systems". It was a new problem of which no one knew whether it could be solved at all, and the solutions were at the time a tour de force. I submitted a short article to the Communications of the ACM, which published it in 1974; it was ignored until Leslie Lamport drew attention to it in 1984, and since then it has added a new dimension to ways of dealing with error recovery.

In the fall of 1973 I designed "predicate transformers" as a tool for defining program semantics in a way that would provide a suitable basis for a calculus for the derivation of programs. In the late 6Os, Tony Hoare had provided a basis for this work: he taught us the relevance of the predicate calculus for reasoning about programs and showed us how inference rules could be tied to the formal syntax of the programming language, but it was at the time not clear to which extent his "axiomatic basis " defined the programming language semantics. I tightened that up and introduced in passing nondeterminacy. This formed the starting point for the book "A Discipline of Programming", which kept me busy for the next few years. Prentice-Hall published it in 1976, it is still for sale, and it has been quite influential; the organization that publishes the Science Citation Index has identified it as a "Citation Classic".

I did the "On-the-fly garbage collection", which at the time was quite a feat of fine-grained interleaving, and the distributed termination detection of diffusing computations, which emerged as a fundamental problem. In 1981 I designed a surprising sorting algorithm.

On the whole, my years as Burroughs Research Fellow were a wonderful time. I would visit the company in the USA a few times a year and my further assignment was to do my own thing, which I did in the smallest Burroughs research outfit in the world, viz. my study on the second floor of our house in Nuenen. I maintained my contacts by mail, by going to the University once a week, and by travelling all over the world. I lectured all over the world, but foreign travel lost what little attraction it had (I never was a very good tourist: I managed to visit Moscow without being dragged to the Kremlin). Whenever I was in the country, I would work on Friday with Carel S.Scholten; others I saw as regularly were W.H.J.Feijen, A.J.M.van Gasteren and Alain J.Martin.

It was too good to last, and it didn't. When Michael W.Blumenthal took over, Burroughs Corporation changed from an enlightened computer manufacturer into a financial organization, and precisely the kind of people I had established relations with were the first to leave the company: I lost my audience there. Whereas Burroughs's intellectual horizon was shrinking, my own was widening, as my interests shifted from computing and programming methodology to mathematical methodology in general. A return to the University Campus seemed appropriate, and when The University of Texas at Austin offered me the Schlumberger Centennial Chair in Computer Sciences, the offer was actually welcome. The offer was not so surprising, nor my acceptance, for I knew Austin, I knew UT and they knew me. All through my years at Burroughs I had made it a rule to visit, wherever I went, the local university and since the late 70s Burroughs had had an Austin Research Center, a visit to which was included in most of my trips to the USA.

In my interest in mathematical methodology I had been encouraged by a grant that I received thanks to the efforts of Dr.Donald W.Braben of the Venture Research Unit of BP, a grant that enabled me to offer a position to Netty van Gasteren (who thus became the first BP Venture Research Fellow). Another strong stimulus came from my efforts —in which I would soon be joined by Carel S.Scholten— to give my "predicate transformer semantics" of the 70s the necessary mathematical underpinning; these efforts became an exciting experience when we discovered (after a few notational innovations) the surprising utility of calculational proofs. In 1988, Netty van Gasteren successfully defended her Ph.D. thesis "On the shape of mathematical arguments".

In the summer of 1984 we moved to Austin, Texas, where we have been happy ever since, partly by the simple device of having warned ourselves beforehand that The University of Texas at Austin would not be Heaven-on-Earth. (It is not.) With the prolonged recession, the pressures to do the wrong things, always already strong, are mounting, and part of the university gives in. And in computing, the excessive preoccupation with speed is, of course, a little bit vulgar.

Austin, 29 November 1993

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Adobe Capture™
Copy editing by Ham Richards.
Revised Wed, 14 Nov 2007.

EWD 1170

Equilateral triangles and rectangular grids

The other day, I encountered the following problem: “Does there exist an equilateral triangle whose vertices have integer (orthogonal Cartesian) coordinates?”. The problem is, indeed, as elementary as it looks, but in solving it, I had a few pleasant surprises; hence this note. I urge the reader to think about the problem before reading on.

*         *         *

My first concern was how to characterize the notion “equilateral triangle”: all edges of the same length, all angles of the same size, or a mixture of the two. Considering that, in analytical geometry, lengths are more readily expressed than angles, I chose the first characterization, i.e. upon the triangle with with vertices (0,0), (a,b), (c,d) I imposed the requirement that its sides be of equal length. More precisely, my interest turned to integer quintuples (a,b,c,d,k) satisfying (0) ∧ (1) ∧ (2) with

(0) | a� + b� = k
(1) | c� + d� = k
(2) | (a� − c)� + (b� − d)� = k       .

Using (0) and (1), (2) can be simplified to

(2�) | 2�(a�c + b�d) = k       .

Seeing that k is even, we turn our attention in view of (0) and (1) to squares and factors of 2. And here we have to make a little jump. It does not suffice to observe (the correct) even.x� ≡ even.x, which for a sum of 2 squares only implies even.(x�+y�) ≡ even.x ≡ even.y. We have to reduce squares modulo 4 and use

(3a) | x� mod 4 = 0   ≡   even.x
(3b) | x� mod 4 = 1   ≡   odd.x

from which we conclude about the sum of squares

(4a) | (x� + y�) mod 4 = 0   ≡   even.x ∧ even.y
(4b) | (x� + y�) mod 4 = 1   ≡   even.x ≢ even.y
(4c) | (x� + y�) mod 4 = 2   ≡   odd.x ∧ odd.y       .

And now we observe of an integer solution (a,b,c,d,k) of (0) ∧ (1) ∧ (2�):

        k mod 4 ≠ 0
=         {(2�), in particular even.k}
        k mod 4 = 2
=         {(0) and (1)}
        (a�+b�) mod 4 = 2 ∧ (c�+d�) mod 4 = 2
=         {(4c) twice}
        odd.a ∧ odd.b ∧ odd.c ∧ odd.d
⇒         {arithmetic}
        even.(a�c + b�d)
=         {(2�)}
        k mod 4 = 0       .

Having thus proved

(5) | k mod 4 = 0       ,

we conclude on account of (0), (1), (4a)

(6) | even.a   ∧   even.b   ∧   even.c   ∧   even.d       .

If (a, b, c, d, k) is an integer solution of (0) ∧ (1) ∧ (2), (a/2, b/2, c/2, d/2, k/4) obviously solves that equation as well; (5) and (6) tell us now that the latter is again an integer solution. By mathematical induction we conclude that any solution of (0) ∧ (1) ∧ (2) is divisible by any power of 2 (4), and hence equal to (0,0,0,0,0), 0 being the only integer with an unbounded number of divisors. All zeros is indeed a solution, i.e. there exist equilateral triangles whose vertices have integer coordinates, but such a triangle is degenerate and its vertices coincide.

*         *         *

For several reasons I was pleased with the above argument. Of course I regret the rabbit embodied by (3a)(3b), but I console myself with the thought that it is a fairly small one. The proof of k mod 4 = 0 is a nice example of proving P by constructing a weakening chain from ¬P to P, and the final part of the argument nicely exploits that only 0 has an unbounded number of divisors.

Remark   The latter observation can be turned into a heuristic: a good way of showing that a Diophantine equation has no other solution than 0, it suffices to show that any solution p can be divided by some n (n>1) such that p/n is again a solution. (End of Remark).

Inks Lake State Park,
12 January 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1171

The argument about the arithmetic mean and the geometric mean, heuristics included.

We consider nonempty bags of n non-negative numbers. A bag B’s “arithmetic mean” AM.B is defined as one n-th of the sum of the numbers in bag B; a bag B’s “geometric mean” GM.B is defined as the n-th root of the product of the numbers in bag B. An immediate consequence of these definitions is that if we modify the values in a bag without changing their sum (product), the arithmetic (geometric) mean of the bag remains unchanged. The theorem to be proved is

(0)         AM.B ≥ GM.B     for any B   .

Note.   The way to remember which of the two means is the greater one, is to consider a bag (with n ≥ 2) that contains exactly one zero. (End of Note.)

*         *         *

The first thing we ask ourselves is if   AM.B = GM.B   is possible.

Note   If not, the theorem could be strengthened to AM.B > GM.B; inspection if a theorem can trivially be strengthened should be a routine matter. (End of Note.)

Because

n � c
––––
n

= c       and      

n
√

 cn  = c     ,

the answer is affirmative: for a bag containing equal values, arithmetic and geometric mean are both equal to that value and hence equal to each other.

But this observation gives us a strong hint as how to compare AM.B with GM.B: we create a bag B� of equal elements, so that we can compare AM.B� with GM.B�, but create B� in such a fashion that AM.B can be related to AM.B� and GM.B to GM.B�. In diagram

AM.B |    ?    | GM.B
| |  | |
| |  | |
AM.B� |    ?    | GM.B� |         .

The existence of B� enables us to replace (0), i.e. the comparison of the different means of the same bag, by (twice) the comparison of the same mean of different bags.

We try the simplest thing, and try to construct a B� such that B and B� have one of the means equal. Arbitrarily we choose the geometric mean for that purpose.

Note   In EWD1140, the arithmetic mean was chosen. (End of Note.)

The overall structure of our proof is now

        AM.B
≥         {by virtue of the construction of B�}
        AM.B�
=         {all elements of B� are equal to c}
        GM.B�
=         {by virtue of the construction of B�}
        GM.B           .

Our remaining task is to construct a program operating on a variable of type bag with B as initial and B� as final values. In order to justify AM.B ≥ AM.B�, we require

(1)         no step increases the sum.

In order to justify GM.B� = GM.B, we require

(2)         no step changes the product.

In order to assume termination, we require

(3)         each step decreases the number of elements ≠ c by at least 1.

Note that, in view of GM.B� = GM.B and GM.B� = c, c is defined as GM.B. Let c≠0.

Taking (2) and (3) into account, a first approximation of the program is

do  | ¬ (all elements in the bag are equal to c) →
| increase the number of elements = c
| by 1 under invariance of the product
od |         .

Increasing the number of elements = c is done by only changing elements ≠ c. Because the product has to remain constant, increasing one element implies decreasing another, Fortunately, because c is the geometric mean of the bag, the presence of an element different from c implies the existence of an element at c’s other side. The step therefore replaces a pair (x,y) such that c lies between x and y; it replaces the pair (x,y) by the pair (c, x�y/c). Note that, because originally c was between the elements of the pair, the minimum of the pair has been increased, the maximum of the pair has been decreased, in short: it has been a contraction, i.e. the elements of the pair have become closer to each other.

The program now becomes

do  | ¬ (all elements in the bag are equal to c) →
| select a pair (x,y) such that c lies between them;
| replace this pair by (c, x�y/c)
od |         .

Our remaining proof obligation is (1): we have to show that above step does not increase the sum. (In fact it decreases it.) We have to find a relation between

the sum, because we have to show that the step decreases it

the product, because the step leaves it invariant

the difference, because its decrease distinguishes the step from its inverse.

In view of the product we are talking about a relation of the second degree, in view of the unsigned difference, we have its square, and we come up with

(4)         (x + y)� = (x − y)� + 4�x�y         ,

which is the rabbit with which EWD1140 started. It expresses that, for positive x,y, under constant product, shrinking difference and shrinking sum go hand in hand.

And this concludes our proof of (0).

Apology   I am sorry I was too late in seeing that here (in contrast to EWD1140) the case c = 0 has to be treated separately. (End of Apology.)

I am grateful to Wim H.J.Feijen for having drawn my attention to the underlying heuristics.

Austin, 19 January 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1175

The strengths of the academic enterprise

In the Western world, 66 institutions have enjoyed a continuously visible identity since 1530. Among those 66 are the Roman Catholic Church, the Lutheran Church and the Parliaments of Iceland and the Isle of Man. What makes these 66 so interesting —and I owe the knowledge of this fact to our President Dr. Berdahl— is that the remaining 62 are all universities! It strikingly demonstrates that universities have a potential for "longevity", but we should not make the mistake of concluding that they are "immortal" or invulnerable, for they are not: if they have existed for centuries, that is because successive generations of scholars and students have nurtured them well and with devotion. It is the obvious task of the current generation to hand over to the next what it got from the previous one, and in order to do so well, we had better understand how the strengths of the academic enterprise are maintained most effectively. Hence my title.

But before I can turn to my topic proper, I must make a few introductory remarks lest I be misunderstood.

The first one is that when we move from one society to another, all important words subtly change their meaning, and in connection with today's topic I must mention: university, education, training, teaching, scholar, scientist, engineer, theoretical, experimental, and applied. This was brought home to me in 1968 at a conference in Garmisch-Partenkirchen. I worked at the time at the Department of Mathematics of the Eindhoven University of Technology in the Netherlands, and told at that conference that the official academic title our graduates earned was 'Mathematical Engineer", and most of the Americans began to laugh, because for them it sounded as a contradiction in terms, mathematics being sophisticated and unpractical, engineering being straightforward and practical. To give you another example, in the early 80's I learned that professors at Stanford University could use their grant money in the name of their research to pay someone else to do their teaching. When I heard that, I was shocked, when my wife heard it, she could not believe it, because we grew up with an academic culture in which teaching and research were considered warp and weft of the same fabric. In that view, a professor who does not get valuable inspiration from his own lectures and therefore does not regard his teaching as a precious experience, is just in the wrong business: he should teach at a vocational school or work at a research laboratory. So please, keep in mind that all important words I use may mean something different from what you are used to.

My second warning remark is that I shall refuse to discuss the academic enterprise in financial terms. The first reason is that the habit of trying to understand, explain, or justify in financial terms is unhealthy: it creates the ethics of the best-seller society in which saleability is confused with quality. The other day we had to discuss the professional quality of one of our colleagues, in whose favour it was then mentioned that one of his Ph.D.s had earned lots and lots of money in the computer business, and few people seemed to notice how ridiculous a recommendation this was. We also know that the financial success of a product can be totally independent of its quality (as everyone who remembers for instance the commercially successful IBM360 should know). The second reason for my refusal is that the value of money is a very fuzzy notion, so fuzzy in fact, that efforts to understand in financial terms always lead to greater confusion. [Remember this, for it is quite likely that this afternoon will give you the opportunity to observe the phenomenon. Note that money need not be mentioned explicitly for the nonsense to emerge, a reference to "the taxpayer" can do the job. The role of "the taxpayer" then invariably leads to the conclusion that of State Universities at least the undergraduate curriculum has to be second- or third-rate.] The final reason for my refusal is that the habit appeals to the quantitative mind and I come from a culture in which the primarily quantitative mind does not evoke admiration. [A major reason that we considered Roman Catholics to belong to a lower class was precisely their quantitative bent: they always counted, number of faithful, number of days in purgatory, you name it.....]

My third remark introduces you to the Buxton Index, so named after its inventor, Professor John Buxton, at the time at Warwick University. The Buxton Index of an entity, i.e. person or organization, is defined as the length of the period, measured in years, over which the entity makes its plans. For the little grocery shop around the corner it is about 1/2,for the true Christian it is infinity, and for most other entities it is in between: about 4 for the average politician who aims at his re-election, slightly more for most industries, but much less for the managers who have to write quarterly reports. The Buxton Index is an important concept because close co-operation between entities with very different Buxton Indices invariably fails and leads to moral complaints about the partner. The party with the smaller Buxton Index is accused of being superficial and short-sighted, while the party with the larger Buxton Index is accused of neglect of duty, of backing out of its responsibility, of freewheeling, etc.. In addition, each party accuses the other one of being stupid. The great advantage of the Buxton Index is that, as a simple numerical notion, it is morally neutral and lifts the difference above the plane of moral concerns. The Buxton Index is important to bear in mind when considering academic/industrial co-operation.

My fourth and last introductory remark draws attention to a whole spectrum of techniques by which one generation transmits its insights and abilities to the next. At the one extreme we have the techniques of the guilds which treat their insights and abilities as valuable property, as a treasure to be kept secret. Their technique for protecting the secrecy is by keeping the secret knowledge unformulated; therefore, the apprentice has to join a master for seven meagre years, during which he can absorb the craft by osmosis, so to speak. The university is at the other end of the spectrum: it is the professor's task to bring the relevant insights and abilities into the public domain by explicit formulation. It is no accident that the universities as we know them started to flourish after the art of book printing had been established. There is more to be said about that spectrum of educational techniques, but I shall not do so now; I mentioned it to remind you why the absence of secrecy, or, more positively formulated, openness and honesty are characteristics that touch the heart of the academic enterprise: a university that hides or cheats can close its doors. The essential role of openness is something to remember when considering academic/industrial co-operation; it should also be remembered whenever a government invents reasons of national security or prosperity for the prevention of free publication of the results of academic research. Universities are not part of the nation's security organisation, they are not the nation's research laboratory either: they are the nation's universities.

In passing I would like to mention that in a rather different sense such openness is a precondition for academic survival. Just for being different and doing things the uneducated cannot understand, the academics are hated and feared, vide Socrates, executed in 399 BC, Archimedes, killed in 212 BC, and, more recently, Hypatia, AD 415 barbarously murdered by a Christian mob. The original Oxford Colleges were buildings fortified in order to protect the students against the rabble, and if you think that that is old hat, I refer you to the DDR or the People's Republic of China of only 25 years ago. It is a miracle whenever, these days, the academic world is tolerated at all; personally I am convinced that what tolerance there is would completely disappear, were the academic world to become secretive.

*            *
*

The University with its intellectual life on campus is undoubtedly a creation of the restless mind, but it is more than its creation: it is also its refuge. Regrettably, neither all professors nor all students are brilliant, but quite a few are and the unique thing is that, on campus, being brilliant is socially acceptable. Furthermore, the fabric of the academic world is such that it can absorb the most revolutionary ideas. And how essential that refuge is, we realize when we remember that many organizations impose a conformism that precludes even such deviant behaviour as wearing a moustache! (If you even wondered why I did not join Disneyland or IBM, you now know why. )

It is not only a refuge for the restless minds, it is also a reservation. It does not only protect the restless minds, it also protects the rest of the world, where they would create havoc if they were let loose. To put it in another way: the fence around campus is essential because it separates two worlds that otherwise would harm each other. The fence ensures that we have relatively little influence on the world "out there", but we would be foolish to complain, for our freedom to be as original or as radical as we like is based on the fact that industry and the world-at-large ignore our work anyhow. Currently there seems a world-wide tendency to try to lower the fence; the effort strikes me as ill-directed.

The unruly nature of academic life, of course, offends the orderly mind, and more than one regime has tried to deal with the problem by doing away with the restless minds, but the measure never had the effect the regime intended: destroy the campus, muzzle your intellectuals, and rapidly life deteriorates in all respects. The explanation is that, with all its aloofness, the university has an essential role to play, viz. to explain to the world the foolishness of its ways. Of course, all religions always try to do that, but religions being what they are, no pope, patriarch, ayatollah or dalai lama has enough authority to be taken seriously. Only the academic gadfly has so much authority that its sting really hurts.

President Reagan did not seem to see it that way, but even regimes of modest insight seem to understand that, as a corrective measure, the gadfly's sting is indispensable. The university has therefore the task to nurture the authority of the sting, both for its own protection and as a service to mankind. Aforementioned openness and honesty, though essential, are not enough; we should add a ruthless striving for perfection, ruthless in the sense that, on campus, there is no academically valid excuse for compromises.

The sting also defines the social responsibility of the universities. The question is: do we offer what society asks for, or do we offer what society needs? If the two coincide, there is no problem, but often they don't, and in computing such coincidence is extremely rare. In case of discrepancy, you must ignore what they ask for and give what they need, ignore what they would like and tell them what they don't want to hear but need to know. There are two compelling reasons for this uncompromising position.

The first one is that a leading university has no choice: to be leading means in this context showing new and better ways and possibilities no one else has dreamt of; if you give society what it asks for, you are not leading but led, viz. led by the demands of society as it sees them.

The second reason is that what society overwhelmingly asks for is snake oil. Of course, the snake oil has the most impressive names —otherwise you would be selling nothing— like "Structured Analysis and Design", "Software Engineering", "Maturity Models", "Management Information Systems", "Integrated Project Support Environments" "Object Orientation" and "Business Process Re-engineering" (the latter three being known as IPSE, OO and BPR, respectively). The external pressures to do the wrong thing are enormous, but yielding to them would be fatal for the academic enterprise, while resisting the pressure reinforces its strengths. The pressures are, in fact, so strong that I do not know a university where there is not some faculty or some department that has yielded, but there should be no mercy for snake oil pedlars on campus. [When a professor is no better than James Martin, he should start a business instead.]

*            *
*

In the wake of the Cultural Revolution and now of the recession I observe a mounting pressure to co-operate and to promote "teamwork". For its anti-individualistic streak, such a drive is of course highly suspect; some people may not be so sensitive to it, but having seen the Hitlerjugend in action suffices for the rest of your life to be very wary of "team spirit". Very. I have even read one text that argued that university scientists should co-operate more in order to become more competitive..... Bureaucracies are in favour of teamwork because a few groups are easier to control than a large number of rugged individuals. Granting agencies are in favour of supporting large established organizations rather than individual researchers, because the support of the latter, though much cheaper, is felt to be more risky; it also requires more thinking per dollar funding. Teamwork is also promoted because it is supposed to be more efficient, though in general this hope is not justified. I have no first-hand experience with the ESPRIT projects of the European Community, as they started after I had left. Involvement of universities from different member states is, I believe, a conditio sine qua non, and here the purpose of the co-operation seems more to force the researchers to broaden their outlook than to increase the efficiency of the research. My impression is that regular contacts with academic colleagues from other countries are experienced as valuable, but that actual co-operation becomes extremely sticky each time industrial partners are included. And everybody complains about the amount of red tape and travel.

Interdisciplinary efforts on campus, that is co-operation between different departments of a university are almost always failures, and the reasons are clear. Why should a vigorous, flourishing department seek co-operation when it is doing just fine all by itself? It is the weak departments that are more tempted to seek each other's support and to believe that there is might in numbers. But such co-operation is of course based on the theory that, when you tie two stones together, the combination will float. Another reason is that the boundaries between our scientific disciplines are not arbitrary at all: the different disciplines represent a modularization of science that has been introduced for the sake of efficiency.

Co-operation between corresponding departments of different universities seems to work quite well, co-operation between the university and industry, however, is so much harder that it usually fails. We might even conclude that the effort is hopeless.

To begin with, there is the great difference in Buxton Index. For industry, the Buxton Index is less than 10, probably closer to 4 or 5, whereas for the academic scientist the Buxton Index is closer to, say, 50, for what you offer your students should last a lifetime, their lives, to be precise.

The second problem has to do with the openness, which is a hallmark of the university, whereas, like the guilds, industry tends to see its knowledge as trade secret. People have tried to find legal solutions for this dilemma, but I am afraid that such solutions only touch the surface: at a more profound level, either one of the parties forsakes its duty, or the co-operation collapses.

But the greatest limitation on the usefulness of co-operation between industry and academia is almost certainly that the two have completely different purposes. To quote Harvey Earl of GM: "General Motors is in business for only one reason. To make money. In order to do that we make cars. But if we could make money by making garbage cans, we would make garbage cans.". Some people might argue that they even tried to make money by making garbage. But the product is secondary; to quote Harvey Earl again: "Listen, I'd put smokestacks right in the middle of the sons of bitches if I thought I could sell more cars.". These quotations are from the fifties, but things have not changed that much. For instance, computing science has very convincingly shown that simplicity is a necessary precondition for reliability, but industry willfully complicates products so as to make them proprietary. The disgraceful state of affairs is fully revealed by the traditional disclaimer with which industrial software is sold.

Under current circumstances I would not even attempt to promote co-operation between the academic and the industrial worlds, because it seems pointless and dangerous. I have come to the conclusion that, industrial management being what it is, it is extremely unlikely that computing science can save the computing industry. Conversely, the computer industry can severely damage computing science; it does so quite regularly by the donation of equipment that had better be ignored. [To avoid misunderstanding, what I just said does not necessarily represent the official opinion of my employer!] So, the less contact we have, the better.

*            *
*

Academic computing science is doing fine, thank you, and unless I am totally mistaken, it will have a profound influence. I am not referring to the changes that result from computers in their capacity of tools. Okay, the equipment opens new opportunities for the entertainment industry, but who cares about that anyhow. The equipment has enabled the airline industry to make its rates so complicated and volatile that you need an expert to buy a ticket, and for this discouragement of air travel we can be grateful, but the true impact comes from the equipment in its capacity of intellectual challenge.

Thanks to the existence of computing equipment we have, for the first time in the intellectual history of mankind, an environment in which the large-scale application of formal techniques is feasible and necessary. Not too long ago, formal reasoning was regarded merely as a theoretically intriguing possibility, but so utterly unpractical that it was totally irrelevant for real mathematicians. Peano was ridiculed for his axiomatization of something as trivial as integer arithmetic! But it is precisely because of these "trivialities" that we can now do things of a power and a beauty, way beyond the wildest dreams I had as a youngster.

As a mathematician I enjoy the same type of excitement as the theoretical physicists enjoyed in the first decades of this century. The analogy is apt in more than one way. In either case the results were obtained not by mission-oriented research, but by trying to achieve the just feasible. If academic research is often astonishingly successful, it always is because the researchers had the wisdom and the opportunity to avoid both the trivial and the impossible, and to follow the very narrow path in between. It is that narrow path in between that defines the intellectual autonomy of successful scientific research.

The major strength of the academic enterprise is that in a very technical sense scientific progress is unique in a way that neither political nor commercial interests can change.

*            *
*

Let me end by quoting, by way of contrast, from the C²E Report from the IC² Center for Commercialization and Enterprise, The University of Texas at Austin, Winter 1993-94. [I draw your attention to the "class-room theory": just "theory" was not bad enough! ]

"In order to supply businesses with the managers they need in an ever-changing world, it is critical that the University maintain direct ties with the business community. These ties give students real-world experience in which to apply class-room theory — to help them to be more effective on the job and to provide feedback to the University to ensure that its curriculum is meeting the needs of business."

Did the writer not know that the use of the term "the real world" is usually interpreted as a symptom of rabid anti-intellectualism, or did he not mind? It is not amazing that people wonder whether the School of Business Administration belongs on campus at all.

The above was written for our "Industrial Forum" on Monday 7 February 1994. The quotations of Harvey Earl were taken from The Fifties by David Halberstam Villard Books, New York 1993. Other recommended literature is The Organization Man by Willian H. Whyte, Simon & Schuster Inc., New York, 1956.

Austin, 9 February 1994

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Sun, 30 Dec 2007

EWD 1177

In Memoriam
Jan L. A. van de Snepscheut

On the 23rd of February, 1994, a tragic death put a sudden end to the life of Jan L.A. van de Snepscheut, professor of Computing Science at the California Institute of Technology, a death that sent a shock wave through the computing community, first of disbelief, then of unfathomed sadness.....

Born on the 12th of September, 1953, Jan was not yet 17 years of age when he enrolled in 1970 at the Eindhoven University of Technology in the EE Department. In 1977 he graduated as Electrical Engineer, but did so on a Thesis supervised by Frans E. J. Kruseman Aretz of the Department of Mathematics. In that Thesis, he gave the scientific justification and the text of a beautifully structured compiler with truly exemplary error handling. The EE graduate had already become an expert compiler writer and implementor in general, thereby setting a pattern for the rest of his life: he would use with equal agility and competence the soldering iron and the fountain pen (and, for that matter, any tool in between).

On the theoretical side this work would find its continuation in the design of such things as a generator for error handling parsers and a beautiful algorithm for the minimization of finite automata —a result that would later be included in his Ph.D. Thesis—.

But he lived in more than one world. Without us noticing much of it, he co-founded at that time the first of two companies in microprocessor-based control systems, for which he did both hard-and software design (for instance an unusually efficient Pascal implementation). I don't think he had much of a financial incentive for these activities; his main incentive seemed to be that he hated to see things done clumsily when he knew how to do them much better.

For a year, the young graduate joined the scientific staff of the Twente University of Technology, but in 1978 he was happy to return to Eindhoven, where, in the next five years, he would earn his Ph.D. with a Thesis, supervised by Martin Rem, titled "Trace Theory and VLSI Design". As familiar with reasoning about concurrent programs as with the physics of semiconductor technology, he designed a style of intellectually manageable concurrent programs such that these could be used as blueprints for VLSI chips. He was just 30 years of age when he got his Ph.D.. Later researchers have improved the quality of chips thus produced, but his was pioneering work, and I can think of no one, at the time better equipped to do it than Jan.

For the rest of the academic year the whole family went to Pasadena, where Jan visited CalTech. in a recent past he had been very much inspired by the work of Alain J. Martin, and I think he was intrigued by Chuck L. Seitz's undertakings. He recognized competence when he saw it and wrote about Carver Mead "I think he understands the physics of semiconductor chips better than anyone else.", but it was Jan who became Richard Feynman's closest collaborator in the latter's exploration of the quantum mechanics of computing. (Feynman also recognized competence when he saw it.)

But the world became more pressing with its demands, and, as of September 1984, Jan agreed to a professorship at the University of Groningen. In Groningen, his task was daunting, for he became responsible for a group that, as a result of earlier misfortunes, had lost its sense of direction. Jan offered a vision. As he wrote in his Curriculum Vitae:

"Overall, my research is directed to the design of elegant and useful computer programs. A driving thrust is my strong persuasion that practical and theoretical concerns are not mutually exclusive. I am most stimulated by problems having a practical motivation and try to construct mathematically elegant techniques for their solution."

(That, in this single paragraph, both "practical" and "elegant" occur twice is typical.) From Pasadena he wrote to me how much he looked forward to his professorship in Groningen, where he felt that he might be able to accomplish more than at CalTech (where his contributions, though welcome, were at the time not that urgently needed).

By all standards, he did extremely well in Groningen. Not everybody shared his vision with the same "strong persuasion", but on the whole his always active, playful intellect was so contagious and inspiring that he quickly turned Groningen into the Mecca of Dutch Computing Science. To this very day, the University of Groningen treats learning how to program well as a very essential and serious component of the Informatics curriculum. At the other end of the spectrum he saw a sensible place for performance experiments, and got the group equipped with a transputer network for which he wrote with Johan J. Lukkien a Pascal translator to support the experiments he envisioned. In addition, he supervised 14 Masters Theses and 2 Ph.D. Theses.

Regrettably, his technical satisfaction could not continue to compensate his growing frustration with the University, which did not recognize Informatics as a scientific discipline in its own right and continued with interferences he felt highly inappropriate. After "a miserable summer" in 1988, he recovered and refound his scientific zest, but largely thanks to the decision that the limit had been reached and that he wanted to move to a more congenial environment. Eight years after the Martins, five years after us, they moved to the USA; he expressed his admiration for our wives' readiness to join us in such adventures by "geen zee gaat ze te hoog, die Nederlandse meisjes".

Despite all the distractions of moving, the years at CalTech have been remarkably productive. He supervised two Ph.D. students and a number of undergraduates, where in all cases that I am aware of, his supervision entailed active co-operation, often leading to joined papers or reports. The spectrum became wider, as next to his old loves of program construction (for all sorts of environments) and semantic theories he became involved in lattice theory and the mechanization of Wim H. J. Feijen's proof format.

His Magnum Opus of these years, however, is his book "What computing is all about", published by Springer-Verlag in David Gries's Series "Texts and Monographs in Computer Science". As it says on the cover:

"It is unique in its choice of topics [...] The coverage is broad but not shallow [...], ranging from the physics that allows us to build electronic computers to the mathematics that allows us to understand our programs."

It is an absolute treasure, strongly reflecting both his excitement as a scientist and his dedication as an educator. It is also a very personal book: while reading it, I often see his eyes twinkling and hear his voice.

For those who loved and admired Jan, for those for whom he was a regular source of inspiration and intellectual delight, it will take a long time to fully absorb that those eyes will twinkle no more, that that cheerful, slightly mocking voice will no longer be heard. The challenge is clear: all the practical and mathematically elegant work that, otherwise, Jan would have done, now has to be done by us. (And we may not yet be up to it, but the same holds for all the little jokes..... ) Jan's memory cannot be served better than by trying to meet that challenge.

                        Edsger W. Dijkstra
                         Austin, 25 April 1994

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Sun, 30 Dec 2007

EWD1179

A sorry parade

I still remember the introduction of the overhead projector on the campus. Its fortunately rare users solicited general scorn and contempt, because the gadget was considered a crutch for incompetent speakers that could not deliver a good lecture on their own. The crutch was perhaps okay for presentations by computer salesmen, but for lectures by scientists it was considered profoundly inappropriate. This condemnation of the gadget was only vindicated by its most common defence , viz. that it enabled the speaker to show much more than he would be able to do with chalk and blackboard.

*                 *
*

In the early 70’s, I performed once or twice in London under the auspices of “Infotech”. I remember it because it was my introduction to the commercial lecturing circuit (and its only thinly disguised fraud). Infotech specialized in very expensive “State of the Art Reports” and conferences where, for large amounts of money, the lesser mortals could listen to the words of wisdom of the semi-gods. Telling you, that Infotech-speak for attendees or participants was “delegates”, should suffice to characterize the organization. In my innocence I was shocked by the Company’s instructions to speakers; one thing was very clear: we had to treat the delegates as morons. (They were treated as morons and did not rebel, so Infotech was probably right , but that is here beside the point.) We were actually instructed to be quite offensive, as we were instructed to be condescendingly repetitive: we were not allowed just to give our lecture, we had first to announce what we were going to say, then we were allowed to say it, and finally we had to summarize what we had said. Needless to say, the whole performance was a travesty of what it pretended to be.

*                 *
*

I was reminded of the above by our yearly spring ordeal, the Parade of the Faculty Candidates. Apart from minor differences in vocabulary, they essentially give the same presentation.

Not having the faintest notion how to give a decent lecture, these poor kids present a show of their foils instead, a show to which they add little more than gesticulation and a reading aloud of key sentence fragments. They sometimes try to say something that is not on their foils, but such effort is courting disaster since they have never been taught to speak in complete, unambiguous sentences.

For the structure of their presentations, they religiously adhere to the Infotech pattern. At the end they complete their disqualification by announcing for the years to come a proposal to do more of the same. One of them had a special way of insulting the audience: for a small section of his talk he felt obliged to apologize in advance because of its “academic content”.

This is not the end of the tragedy. After these pitiful performances, the Department, true to the American tradition of ambivalence towards competence, declares almost all candidates “above the hiring threshold”, but God help our students!

PS. Sorry, but I had to get this out of my system.

Austin, 1 May 1994

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Sun, 30 Dec 2007

EWD 1180

Heuristics for a very simple Euclidean proof

We consider 3 points on a given circle, A and B fixed and P movable along the clockwise circle segment from A to B. (See fig. 0)   At my recent oral examinations “Mathematical Methodology”, the students I asked did not know the theorem that ∠APB is constant, i.e. independent of the position of P. So we designed the proof in as systematic a manner as possible.

*         *         *

•   As a matter of routine we checked the relevance of the data. Is it essential that A is fixed? Yes, obviously. Is it essential that P is confined to the circle? Yes. (Some let ∠APB shrink by moving P outside the circle, some let it increase by moving P inside.) Moral: we have to take the circle into account.

•   How is a circle defined? As a set of points equidistant to the centre. So we had better introduce the centre C and the three radii of equal length. (See fig. 1)

•   Since it is only essential that A, B, and P lie on the circle and this fact has been captured, the circle is now erased. (See fig. 2)

•   Three distances are the same, but usually equality is considered to be a binary relation. If the fact that x, y, z are all equal has to be captured by the pairwise equalities x=y, y=z, z=x, then 2 of the 3 suffice (since = is transitive). Which of the two pairs should we choose in fig. 2? For reasons of symmetry these are AC=PC and BC=PC. Let us concentrate on the first one. (See fig. 3)

•   What can we conclude from AC=PC? This was invariably the moment some mathematical knowledge was introduced: an isosceles triangle has equal base angles. Together with the other case this leads to fig. 4, in which equal angles have been marked equally.

•   At this stage, most students remarked without prompting that a vital step had been made: from a given in terms of lengths a conclusion about angles has to be drawn, and the last step is vital because it provides the transition from lengths to angles. This is the moment to decide to remove the markings of equal lengths and to conduct the remainder of the argument in terms of angles.

•   We have to show that ∠APB is constant. We have not used yet that A, B, C, are fixed, and that therefore ∠ACB is constant. This observation draws our attention to the angles around C. (Had we not made this observation, we could have observed that the angles around C are in fig. 4 the only unmarked ones.) And this was the moment of the second introduction of some mathematical knowledge: most students chose to use that the angles of a triangle add up to π (which they called 180�). This leads to the marking as in fig. 5 and we conclude that ∠APB = � ∠ACB, which proves the theorem.

Note   None of the students appealed to the theorem captured by

      ,

extended PC and produced the marking as in fig. 6. It has the advantage of not mentioning π*), and is suggested by the observation that, at P, we have a constant angle with a variable partitioning: by extending PC, we create another constant angle with variable partitioning.

*) The problem of introducing a constant (like π) is that then one has to use its properties. (End of Note.)

The problem was nice for warming up!

Winding Stairs Campground,
14 May 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD1181

Don't mix unary pre- and postfix operators

One of the operators of the relational calculus is the negation (or "complement") which I denote by a prefix  ¬ . Another unary operator is the transpose (or "converse"), which I denote by a prefix ~ . The two operators commute, so one never knows whether to write ¬~X or ~¬X . It has been suggested to eliminate this dilemma by making one of the two, say ~ , a postfix operator. This allows us to write ¬X~ , leaving open whether this is to be parsed (¬X)~ or ¬(X~).

Commuting operators at different sides of the operand! ("A neat idea!" as Ollie North would say.) But you run into difficulties with the introduction of the first unary operator that commutes with neither. It fits at neither side and precedence rules or parentheses are needed for disambiguation. With all unary operators at the same side, There would have been no problem at all. Moral: Beware of neat ideas.

Winding Stair Campground
14 May 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-118, USA

transcribed by Tristram Brelstaff
revised Sun, 30 Dec 2007

EWD 1188

A problem from Zhendong Patrick Su

The other week, my student Zhendong Patrick Su showed me the following problem.

Consider the following quadrilateral with a diagonal, in which the sizes of the angles are indicated in units of π/36

We are asked to determine the angle marked below, and suggest that you think about the problem before turning the page.

One thing that strikes the reader is that one of the sides connects two equal angles (of 22 each), and the question is whether we can exploit that symmetry. The suggestion is to try to do that by introducing a symmetric trapezium (a quadrilateral with 1 pair of parallel sides)

Filling in the angle sizes, we see that the figure is very special indeed: the figure has been partitioned into a symmetric trapezium and an isosceles triangle.

The symmetry of the trapezium can be exploited by observing that as a result its 4 vertices lie on a circle; consequently the two marked angles are equal.

The isosceles triangle with top of size 22 is exploited by considering the circle through its other 2 vertices and with the top of size 22 as centre. Because of the angle marked 11, the 4th vertex lies on that circle (and because of the fact that the vertices of the angles of size 11 and 22, respectively, lie at the same side of the line connecting the other two vertices in the picture), we can thus mark a 3rd segment // and we have found 2 other isosceles triangles. Either of them suffices to conclude that the size of the marked angle, i.e. the requested answer, is 8 (36−2*14 or 36−2*3−22).

*         *         *

I thought that the very first step was a rather big rabbit, but while I was writing this note, my wife Ria tried to solve this problem, and the partitioning into a symmetric trapezium and an isosceles triangle was the very first thing she did!

That I used the theorem —proved in EWD1180— that a circle is the locus of points from which 2 given points are viewed under a constant angle, etc., is not surprising: it is a sophisticated packaging of the equal lines and the equal angles of the isosceles triangle.

I wrote this down for the sake of presentational experiment of not naming the components of the picture.

Austin, 30 September 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Supplement

An alternative solution to Zhendong Patrick Su’s problem

The solution proposed in EWD1188 exploits the symmetry induced by two specific angles of size 22.

The solution proposed here exploits the more direct symmetry with respect to the “major diagonal” bisecting one of these angles. This symmetry is completed by connecting the mirror image of the vertex with angle of size 21 to all vertices of the quadrilateral, as shown in the following picture:

The resulting isosceles triangle with top angle marked 11 + 11 obviously has base angle 18 − 11 = 17, as indicated. Since the angle marked 7 equals the angle marked 3 + 4, the four points highlighted by dots are on a circle. Hence the angle between the base of the isosceles triangle and the minor diagonal equals the angle marked 1. Therefore the angle marked ? has size 7 + 1 = 8.

Discussion. Consider the generalization of this problem where the given values 11, 3, 4 are replaced by arbitrary values α, β, γ respectively. The condition for the 4 dots being on a circle is 18 − α = β + γ, i.e. α + β + γ = 18. Clearly the unknown angle = (γ + β) + (γ − β) = 2 � γ, resulting in a triangle with angles 2 � α, 2 � β and 2 � γ. This generates a family of equivalent problems, even if we require that γ − β = 1 as in the original problem statement.

In EWD1188, the existence of the isosceles triangle used in the derivation requires 2 � α + (β + γ) + (β + γ) = 36, hence α + β + γ = 18 as before. The symmetry arguments based on the equality of two specific angles of the quadrilateral results in the extra condition α + 2 � α + β = 36, i.e. 3 � α + β = 36. If we also require γ − β = 1, then the only possibility is α, β, γ = 11, 3, 4.

R. Boute, 1995/01/24

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1190

Problem 10406 from The American Mathematical Monthly, Volume 101, Number 8 / October 1994

10406. Proposed by David C. Fisher, University of Colorado, Denver, CO, Karen L. Collins, Wesleyan University, Middleton, CT, and Lucia B. Krompart, Rochester, MI.

Show that a path on an m by n square grid which starts at the northwest corner, goes through each point exactly once, and ends at the southeast corner divides the grid into two equal halves: (a) those regions opening north or east; and (b) those regions opening south or west.

(10406) A path meeting the conditions of the problem on a 5 by 8 grid is shown in figure 10406 below.

We confine our attention to paths from NW to SE that do not necessarily go through each point; the off-path points are called free. Directing the paths from NW to SE, I identify (here without proof) the region(s) “a” with those to the left of the path, and the regions “b” with those to its right.

A path, along which turns to the left and turns to the right alternate, is a shortest path; we give a simple example (in the same 5 by 8 grid).

For the m by n grid with a shortest path we observe
•   # points = m * n
•   # unit squares = (m−1) * (n−1)
•   # edges on shortest path = (m−1) + (n−1)
•   # points on shortest path = m + n − 1
•   # free points = (m*n) − (m+n−1) = (m−1) * (n−1)

in short: the number of unit squares equals the number of free points. But we can go further: this equality holds for the separate regions! We can establish in the a-region a 1-1 correspondence between each unit square and its NE corner, and in the b-region between each unit square and its SW corner.

Introducing
Fa and Fb : # free points in a-region(s) and b-region(s) respectively
Sa and Sb : # unit squares in a-region(s) and b-region(s) respectively,
we can now formulate

Lemma 0   In the case of a shortest path Fa = Sa ∧ Fb = Sb.

The idea of the proof is to start with a given path that visits each point exactly once —i.e., Fa = 0 ∧ Fb = 0—, and to transform it in a finite number of moves into a shortest path for which Fa = Sa ∧ Fb = Sb holds. Initial and final state are then to be linked via an invariant that is maintained by each move.

For the move we consider that, as said, a path, along which turns to the left and turns to the right alternate, is a shortest path. Consequently, if the path is not of minimal length, it contains at least one pair of successive turns in the same direction. With those turns k edges apart it means that there exists a rectangle —a “bar”— of k (k ≥1) unit squares such that 3 of its sides are formed by 1, k, 1 edges of the path, e.g. for k = 5:

We can —and will— always choose a rectangle such that the k−1 interior points of the 4th side are free. The move shortens the path by 2 edges in the obvious way; in the same example, the above configuration is transformed into

With x,y = a,b or x,y = b,a, we observe for the transformation by the move:

∆ Sx = −k ∆ Fx = −(k−1) ∆ (Sx−Fx) = −1 |  | ∆ Sy = +k ∆ Fy = +k+1 ∆ (Sy−Fy) = −1

The above transformation reduces at both sides of the path the difference S−F by 1, and hence

(Sa−Fa) − (Sb−Fb) = q   ,

if initially true, is an invariant of our total transformation process (which obviously terminates since each move reduces the path by 2 edges).

From Lemma 0, which is applicable in the final state, we conclude q = 0. Therefore initially, with Fa = 0 ∧ Fb = 0, we have Sa−Sb = 0 or Sa = Sb. Quod erat demonstrandum.

*         *         *

It took me several hours to design the move of the previous page; for quite a while I considered 2 unparameterized moves: the current one with k =1 and , which changes the shape of the path without shortening it. The mere fact that the second move complicates the termination argument should have made me reject it much faster.

I liked the problem.

Austin, 17 October 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 24-Dec-2011

EWD 1193

On arcs and angles

For the sake of comparison I shall give two presentations of (almost) the same theory. It is about a little corner of Euclidean geometry, relating the size of angles to the length of arcs of circles. When measuring the length of such arcs, we take the radius of the circle as our unit of length.

I shall first present the theory as I remember it from half a century ago.

Lemma 0 was about angles with their vertex at C (= the centre of the circle) and states that in fig. 0

⌢

⌢

α = β   ≡   
AA
´ = 
BB
´

or “equal angles, equal arcs”. This theorem was proved via the congruence △ACA´ ≌ △BCB´, and allows us to introduce the radian as unit of angle size: the size of an angle with vertex at C equals the length of the corresponding arc. This last formulation I consider a rephrasing of Lemma 0 :

⌢

∠ACA´ = 
AA
´

Lemma 1 was concerned with the size of ∠APA´ with all three points on the circle: it states

⌢

∠APA´ = � 
AA
´      .

The proof identifies two isosceles triangles and then establishes ∠ACA´ = 2 ∗ ∠APA´ ; with Lemma 0, Lemma 1 then follows.

The mathematics is already getting slightly unattractive, for the argument based on fig. 1 is not immediately applicable to fig. 2. This can be remedied by giving the analogous argument for fig. 2, but we are then still left with the question of whether fig. 1 and fig. 2 cover all cases.

Lemma 2 deals with the case that the vertex is an arbitrary point P inside or on the circle, as in fig. 3: it states

⌢

⌢

∠APB = � (
AB
 + 
A´B
´)   .

The proof is by observing

∠APB = ∠B´BA´ + ∠BA´A

and then applying Lemma 1 twice. Here we didn’t struggle with the position of the circle’s centre, but do face the question of P lying outside the circle:

My highschool textbook solved this problem by introducing a new theorem —Lemma 3— stating that in fig. 4

⌢

⌢

∠APB = � (
AB
 – 
A´B
´ )   ,

and proving this theorem afresh (again by drawing the auxiliary line A´B).

The above is not too satisfactory for a variety of reasons.

Lemmata 0 and 1 are special cases of Lemma 2.

Lemmata 2 and 3 ask to be merged into a single lemma, e.g. by the introduction of something like a negative arc.

There is no uniform, nonpictorial definition of which arcs have to be added or subtracted to yield which angle.

A closer inspection tells us that the notion of an angle, as used thus far, is probably too crude for our purposes.

For instance, the traditional definition of a circle is the locus of all points at given distance from a given point; Lemma 2 invited the alternative definition as the locus of points from where a given line segment is seen under the same angle or something like that, but our definition should reject fig. 5 as our circle thus defined! (The vertical line is the segment in question.)

Our notion of “angle” as used thus far is based on the notion of the angle between two rays, both starting at the vertex, as in fig. 6. It is a symmetric function of the two rays that delineate it.

We now present an alternative. We don’t know its original inventor(s) but do know that no one has promoted it more vigorously or explored it more extensively than S-C Chou, X-S Gao, & J-Z Zhang in their book Machine Proofs in Geometry [0].

We tentatively call it “line angle” because it associates an angle not with two rays but with two full lines, each of them extending in both directions to infinity. (This is perhaps why Chou, Gao, & Zhang speak of “full angles”.) We denote it —equally tentatively— by the infix “⌿”. It is not a symmetric function of its arguments: in fig. 7,

p⌿q = α   and   q⌿p = β . In words:   p⌿q   is the angle over which p must be rotated clockwise so as to make it parallel to q. The picture in fig. 7 strongly suggests p⌿q + q⌿p = π, but that is an equality we shall return to later.

What we have gained can be seen by observing how the notion of the line angle does away with the anomaly signalled in fig. 5. Consider two given points P and Q, and line p through P and line q through Q such that for some given α,  p⌿q = α; the locus of the intersection point of p and q is a circle through P and Q:

In short, the problem is solved by distinguishing the endpoints of the line segment —e.g. by naming them differently— and subsequently distinguishing the lines of a pair by the endpoint through which they pass. The convincing elegance reflected in fig. 8 is strong evidence in favour of the notion of the line angle.

We now turn our attention to fig. 3 and fig. 4, and observe that in fig. 3, in which the arcs had to be added, the arcs from A to B and from A´ to B´ are both in the clockwise direction, whereas in fig.4, where we had to take the difference of the arc lengths, one of the two —viz. from A´ to B´— goes counter-clockwise. This observation invites the introduction of the notion of the directed arc, tentatively denoted by

⌢◂

PQ

, whose length is counted positively or negatively depending on whether the traversal of the arc from P to Q is clockwise or not. Directed arcs thus have the property

⌢◂

⌢◂

PQ
 = –
 QP
       .

We still have to decide in which direction we count the arc length as positive. We decide that when the arc from P to Q goes in the clockwise direction, the value of 

⌢◂

PQ

 is the (positive) length of that arc from P to Q.

Clocks being what they are, arcs 

⌢◂

AB

 and 

⌢◂

A´B
´

 in fig. 3 are both positive, whereas arc 

⌢◂

A´B
´

 in fig. 4 is negative. With these conventions, Lemma 2 and Lemma 3 become a single theorem:

Let line a intersect a circle in point A and A´; let line b intersect that same circle in points B and B´. Then

(0)           a⌿b = (

⌢◂

AB

+

⌢◂

A´B
´

)/2       .       

In the above there is one issue I skimmed over. Its first manifestation is with the definition of the directed arc. The notion 

⌢◂

PQ

 strongly suggests that for given P and Q the directed arc 

⌢◂

PQ

 is defined, but the endpoints do not determine whether “the arc from P to Q” is traversed clockwise or counterclockwise. To the question which direction we should choose, the proper answer is “either”. The two options differ by 2π and we postulate that real values differing by an integer multiple of 2π correspond to the same directed arc.

Its second manifestation is with the formulation of the theorem: if line a intersects a circle, there are two points of intersection, which is A and which A´? The answer is again “either”: the difference it makes in the sum

⌢◂

⌢◂

AB
 + 
A´B
´

is, again, an integer multiple of 2π, i.e. ignorable. (Observe the following calculation, be it written down with some notational licence:

⌢◂

⌢◂

AB
 + 
A´B
´

=                

⌢◂

⌢◂

{ 
PQ
 = – 
QP
 }

⌢◂

⌢◂

⌢◂

⌢◂

(
AB
 + 
BB
´) + (
A´B
´ + 
B´B
)

=                

⌢◂

⌢◂

⌢◂

{ 
PQ
 + 
QR
 = 
PR
 }

⌢◂

⌢◂

AB
´ + 
A´B

           .         )

Its third manifestation is with the definition of the line angle: in fig. 7 we defined p⌿q to be equal to α, the clockwise rotation from p to q. But the alternative would have been a counter-clockwise rotation over β, or, equivalently, a clockwise rotation over – β. We observe π–β = α, in general: real values that differ by an integer multiple of π represent the same line angle. With directed arcs being defined up to multiples of 2π, formula (0) now makes perfect sense, thanks to the division by 2.

Finally, a single argument to prove lemmata 1, 2 and 3. Let us move, as in fig. 10, a line parallel to itself; the observation is that, for reasons of symmetry —and here you may be as explicit as you like— the one point of intersection moves in the counter-clockwise direction exactly as far as the other point of intersection does in the clockwise direction. Hence, if we move the line pair (a,b) parallel to itself, not only a⌿b is constant, but also 

⌢◂

⌢◂

AB
 + 
A´B
´

.  Hence, if (0) holds to begin with —e.g. when (a,b) intersect in C— , (0) continues to hold (as long as both lines intersect the circle).

*         *         *

Having seen the alternative, the reader should realize how clumsy a theory I learned when I was young: when using Lemma 2 and/or Lemma 3, one either has to show that the intersection point lies inside/outside the circle, or one has to make a case analysis.

The point I wanted to make is that in designing a mathematical theory, the choice of concepts and definitions is crucial. I thought this was a very nice and simple example with which to drive the message home. Somehow, this note got longer than I had expected.

[0]   | Machine Proofs in Geometry, Shang-Ching Chou, Xiao-Shan Gao, Jing-Zhong Zhang, World Scientific Publishing Co, Singapore, 1994

Austin, 24 December 1994

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 28-Nov-2011

EWD 1194

Z.P.Su’s second problem

The other day Zhendong Patrick Su showed me the following problem of the last Putnam Competition, in which he had participated. (He had solved the problem, I did not.)

Consider the points in or on the right-angled triangle with hypotenuse of length √2:

.

Let each of these points have 1 of 4 colours. Show the existence of a monochrome pair with mutual distance ≥ 2 − √2.

Let us call that critical distance r, i.e. r = 2 − √2 ; let us call a monochrome pair at mutual distance ≥ r a “desired pair”.

If A belongs to a desired pair, we are done; similarly for B. If neither A nor B belongs to a desired pair, we proceed as follows.

To begin with we observe that r satisfies r = √2 � (1−r), from which we

conclude that, with AP = r and BQ = r, we have PQ = r. Completing the diamonds with AR = r and BS = r, we conclude RQ = r and PS = r. Being the hypotenuse of a right-angled triangle with side = r, RC and SC are both > r.

In the case that neither A nor B belongs to a desired pair, A and B —more than r apart— are of different colour, and P, S, C, R, Q —all ≥ r apart from A and B— are all of the remaining 2 colours. Consequently, in the cyclic arrangement P, S, C, R, Q of these 5 points, 5 being odd, two successive points are of the same colour. Their mutual distance being at least r, they form a desired pair. QED.

*         *         *

In the above argument we have appealed to the following theorem:

Consider a finite undirected graph in which each vertex is of degree 2. If each vertex is of one of 2 colours and the number of vertices is odd, there exists an edge that connects a vertex to a vertex of the same colour.

The proof is by double application of the pigeon-hole principle. Let the number of vertices —which equals the number of edges— be 2n+1. Since there are 2 colours, there are at least n+1 vertices of the dominant colour; as they are all of degree 2, they give rise to 2n+2 endpoints of the dominant colour. Since there are “only” 2n+1 edges, at least 1 of them has 2 endpoints of the dominant colour.

Austin, 25 December 1994

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 26-Dec-2011

EWD1198

Jan van de Snepscheut's tiling problem

When a 6×6 square is covered by 18 2×1 dominoes, each domino is "cut" into 2 unit squares by one of the (5 + 5 =) 10 grid lines. Show that there is a grid line that cuts no domino.

Proof   Define for each grid line its "cut frequency" as the number of dominoes it cuts. For an arbitrary grid line we observe

(i) it divides the 6×6 square into two rectangles, each of an even number of unit squares.

(ii) each domino it cuts covers in both rectangles 1, i.e. an odd number of unit squares.

(iii) each domino it does not cut covers in both rectangles an even number of unit squares

From (i), (ii), (iii) we conclude

(iv) cut frequencies are even.

Because 10 grid lines cut 18 dominoes, the average cut frequency equals 1.8. Hence —on account of the generalized pigeon-hole principle—

(v) the minimum cut frequency is ≤ 1.

From (iv) and (v) we conclude that the minimum cut frequency equals 0, which proves the theorem. (End of proof.)

*               *
*

A minor reason for writing down the above is the consideration that the homework I give to my undergraduate students should be done by me as well. In addition I would like to show them, by way of example, one of the ways in which I might present the argument.

The main reason for writing down this argument, however, is that it is shorter and simpler than what I remember having seen. I remember arguments concluding the existence of at least 1 non-cutter from the existence of at most 9 cutters, whereas the above argument avoids the partitioning of grid lines into cutters and non-cutters.

Finally, the above argument is a nice example of using the pigeon-hole principle in the form

the minimum ≤ the average.

Austin, 3 February 1995            

prof.dr.Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Alejandro Ruiz
revised Wed, 12 Nov 2008

EWD 1199

A supplement to EWD1140 and EWD1171

In EWD1140 we proved that the arithmetic mean is at least the geometric mean; in EWD1171 we returned to that problem, including most of the heuristics. One rabbit, though, remained: the choice of c between x and y so that

(0)         x,y := c, x+y−c

will decrease the distance between x and y. I know why the rabbit remained: in my first effort I hit upon a case analysis too ugly to include in my text, and so the coward waved his hands. (The case analysis was generated by the value of x < y before and after.)

All this was a little bit stupid (and dishonest, but that is another story) since the whole argument —see the opening sentence of EWD1140— is built on the identity

(x+y)� = (x−y)� + 4�x�y

and instead of worrying about decreasing the distance between x and y, we should focus our attention to decreasing (x−y)�.

The following simple calculation massages the initial condition under which (0) decreases (x−y)�   :

        (c − (x+y−c))� < (x−y)�
=         {algebra}
        (2c−x−y)� < (x−y)�
=         {algebra: a < b+c ≡ a−b < c}
        (2c−x−y)� − (x−y)� < 0
=         {algebra: a�−b� = (a−b)(a+b)}
        (2c−2x)(2c−2y) < 0
=         {algebra}
        (c−x)(c−y) < 0

which compactly and without case analysis characterizes the situation in which c lies between x and y.

For the modification chosen in EWD1171:

(1)         x,y := c,  x � y/c

the analogous calculation leads to

(c�−x�)�(c�−y�) < 0       ,

which is only equivalent to  (c −x)�(c−y) < 0  if  (c+x)�(c+y) > 0. The whole problem is in terms of positive numbers, so this condition is satisfied. The observation, however, confirms my impression that the choice of (0) in EWD1140 —i.e. increasing the product under constant sum— is to be preferred over the choice of (1) in EWD1171 —i.e. decreasing the sum under constant product—.

Austin, 15 February 1995

PS   The algebra on the previous page is somewhat elaborate. It just shows how one is affected by lecturing for American undergraduates.

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 26-Dec-2011

12xx

1200: Only a matter of style?

1202: The complete (n + 1)-graph in n-dimensional space

1203: Primes once more (re Kac & Ulam)

1204: Complete DAGs

1205: A trip to Harvard Law School, 10–11 April 1995

1206: An unfortunate use of symbols

1207: A theorem about “factors” perhaps worth recording

1209: Why American Computing Science seems incurable

1210: The non-unique node multiplicity

1211a: On some very binary patterns (dedicated to F.E.J. Kruseman Aretz)

1212: For the record: painting the squared plane

1213: Introducing a course on calculi

1214: The marriage agency

1215: Courtesy Dr. Birgit Schieder

1216: The equation x: [x]

1217: Comments on a Review of the Department

1219: “I have a proof that ....”

1220: Honors course “Mathematical Methodology”, Spring 1996

1224: Hm++, a new Professional Standard (From the desk of the chairman of the Board of Mathematics Inc.)

1226: A simple geometrical theorem I did not know

1227: A somewhat open letter to David Gries

1228: Sylvester’s theorem used (see EWD1016)

1229: Nondeterministic construction of an arbitrary witness

1231: The arithmetic and geometric means once more

1232: My simplest theorem

1235: Een scheve schaats

1237: Elegance and effective reasoning (Fall 1996)

1238: Foreword

1239: A first exploration of effective reasoning

1243: The next fifty years

1243a: The next fifty years

1245: A kind of converse of Leibniz’s Principle

1248: Homework #1 (See EWD996)

1250: The couples, the river, and the little boat

1251: Two problems derived from Hugo Steinhaus

1252: Convocation speech, December 8, 1996

1253: Mathematical induction’s fixpoint

1255: Pruning the search tree

1256: Mathematical Methodology, Spring 1997

1258a: The ladder theorem

1260: The marked coins and the scale

1261: The angle bisectors of a triangle

1268: The Mathematical Divide

1273: On Dijkstra’s Lemma and Kruskal’s Algorithm

1277: Society’s role in mathematics

1282: On graphs whose nodes are Black or White

1283: How “they” try to corrupt “us”

1284: Computing Science: Achievements and Challenges

1285: To Cambridge by mistake (13–18 April 1999)

1287: Dear Tony, dearest Jill, and other people, dear or not

1288: Ulrich Berger’s argument rephrased

1290: Eliminating cascading carries

1292: When a symmetric operator distributes over (up) and (down)

1297: Triggered by a high-school exercise

1298: Under the spell of Leibniz’s Dream

EWD 1200

Only a matter of style?

For educational purposes we analyse the opening pages of an 11-page article that appeared in The American Mathematical Monthly, Volume 102 Number 2 / February 1995. We added line numbers in the right margin.

line 4: Since in this article, squares don’t get alternating colours, it could be argued that the term “chessboard” is misplaced.

line 4: The introduction of the name “B” seems unnecessary: it is used —in the combination “the board B”— in the text for Figure 1 and in line 71; in both cases just “the board” would have done fine. In line 77 occurs the last use of B, viz. in “X ⊂ B”, which is dubious since B was a board and not a set; in line 77, I would have preferred “Given a set X of cells”.

line 7/8: The first move, being a move like any other, does not deserve a separate description. The term “step” is redundant.

line 8: Why not “a move consists of”?

line 10/11: At this stage the italics are puzzling, since a move is possible if, for some i, j, cell (i, j) contains a pebble and cells (i+1, j) and (i, j+1) are empty.

line 10: Twice the term “positions” for what everywhere else is called “cells”.

line 12: Why not “After k moves the board had k+1 pebbles on it”?

line 12/14: In the one sentence, k counts moves, in the other k counts pebbles. Since the prose does not indicate the scope of dummies, this double use of the same k is a little bit unforgivable.

line 14: “and we set R := ∪k≥1 R(k)”. We remark
•   the use of the verb “to set” when defining (the set!) R can be considered unfortunate
•   since “R” is not used on the next two pages, the name seems to be introduced too early
•   the introduction of the name R seems unnecessary; in the rest of the paper I saw it used once in “any C ∈ R”, where “any reachable configuration” would have done. (Note. In the context in question —p 116— the reachable context can remain anonymous: the quoted occurrence of C is the only occurrence of the identifier C in that context. My conclusion is that the reachable configuration has been called C only in order to admit the boolean expression C ∈ R.)
•   the authors have chosen a special symbol for what is sometimes referred to as “definitional equality”; they are not the only ones to do so, but I would like to remark that I have never seen a proper justification of the convention (nor can I think of one)
•   after the introduction of ALGOL60, the mathematical community has adopted the latter’s assignment operator as symbol for “definitional equality”, thereby only adding to the confusion since assignment has nothing to do with equality (vide x:=x+1)
•   identifier R has been given two meanings, in particular the type of R is no longer defined: the one R is of the type “set of cells”, the other R is of type “natural number” → “set of cells”.

line 15: Why not “the eight reachable configurations”? The printed text raises the question of how a reachable configuration can be impossible.

line 17: The printed text refers to an obligation for pebbles; had it been “some cell having coordinates (i, j) with i+j ≤ 3 must contain a pebble”, we would have had an obligation for cells! It is better to avoid this spurious dilemma by deleting “must” —a verb that is usually better avoided— and to write “some pebble occupies a cell” or “some cell contains a pebble”.

line 17/18: I think the authors meant “This fact seems to have noted first by M.Kontsevich.”

line 19/22: We remark
•   in a sentence of the structure “If L(k) denotes the set {(i, j): i + j = k} then [.....].” the scope of the convention stated in the antecedent ends at the end of the consequent; in this paper, the scope of L’s definition extends through the whole paper!
•   in line 20, L(1) ∪ L(2) ∪ L(3) should be L(0) ∪ L(1) ∪ L(2) ∪ L(3); L(0) is also missing in Lemma 2.
•   in line 21, delete “must always”: “any reachable configuration has a pebble...”. [Now I come to think of it, “some cell” is okay, for the cells are distinguished by their coordinates; “some pebble” is nonsense, for the pebbles are as indistinguishable as the electrons in the helium atom.]

line 38, 45, 47 & 49: add “L(0) ∪”.

line 39: It is a pity that the weight of cell (i, j) has been given as 2−(i+j), instead of as (�)i+j or rather (�)i � (�)j, the latter being a special case of pi�qj with p+q=1. (The latter equality equivales the requirement that a move does not change the total weight covered.) The unproved statement about the boundaries —line 53/55— follows via (p, q)=(1,0) and (p, q)=(0,1)

line 42: I would prefer “the total weight of the cells covered”; as printed, it might be misread as “the weights of cells covered”. I would also prefer “covered” replaced by “occupied”, the term used before.

line 52, 56, 58, 60: add “L(0) ∪”.

line 55: replace “which” by “that”. (That was easy.).

line 55/59: These two sentences have baffled me for at least 15 minutes —and this was when I really got cross with the authors—. Forget about minor problems such as “weight covered” —on top of this page [line 42], cells were the things being covered—; what hit me was “can” in line 55 and “these cells” in line 58. Eventually I realized that the verb “can” hints at a hidden inequality: the conclusion that should have been drawn is that the total weight of the cells outside L(0) ∪ L(1) ∪ L(2) but with only one cell from each of the boundaries is at most 1. From line 58, “must” is again a candidate for deletion. Furthermore, authors should know that an obscure notion like “these cells” is not clarified by printing the preceding “all” in italics.

line 67/71: “It might be helpful”: helpful for what purpose and how? “in this model”: in which model? “the pebbles first move”: what is the meaning of “first”? The text mentions no “later” or “second”; “are identified in the obvious way”: how obvious?

line 74: delete “in fact”, as it does not contribute anything

line 75: the introduction of the adjective “standard”, which is used nowhere else, serves no purpose.

line 72: This sentence has no connection to what precedes it, and is closely connected to what follows it; this is not reflected in the vertical spacing, which obscures the logical structure of the text. Moreover, it would have been nice if “the easy induction argument” had been shown: a few colleagues and I spent 1� hours on not finding it.

line 75: The introduction of the adjective “standard” as technical term is superfluous, since the term is not used in the rest of the paper.

line 77/81: • This paragraph displays the (not uncommon) shortcoming that its logical relation to the rest of the text requires the study of its contents. Is it going to demonstrate Lemma 3 or is it an introduction to Theorem 1? (At first reading, I assumed the former, and got puzzled.)
•   It is elliptic: line 77 announces the definition of the set M(X), but lines 78 through 81 formally don’t do so (they don’t mention M(X) ).
•   It is very obscure. The notation M(X) strongly suggests that the paragraph should define a function of type: “set of cells” → “set of moves”. The text, however, describes a process that seems to depend on an initial distribution of pebbles. But there is more ambiguity. Suppose there are 2 cells, one in X and one not in X, but both containing pebbles; we are then to remove pebbles either from the one or from the other: how do we choose? Also, how do we “remove all but at most one of the pebbles”? For me, “at most one” is in natural numbers “zero or one”, but the removal of “all but zero or one of the pebbles” is too nondeterministic to define a function. For the dependence on the initial pebble distribution I can suggest a fix, but not for the rest of the ambiguities.

It is here that I gave up. When studying a paper I don’t consider it my duty to conjecture what should have been written down.

*         *         *

The above has been written for my students with the intention of helping them to improve the quality of their writings.

Austin, 22 February 1995

(Followed by EWD1200-8, 9, 10)

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

[The American Mathematical Monthly, Vol.102 No.2 / February 1995, pages 113-115]

Pebbling a Chessboard

Fan Chung, Ron Graham, John Morrison,
and Andrew Odlyzko

1. INTRODUCTION. The following puzzle has attracted some attention recently.
We first learned of it through Martin Gardner [6]. A version of it appeared in
Omni magazine in 1993 [11]. However, it was proposed over 10 years ago by
Kontsevich [9], and a partial analysis of it was published shortly thereafter by
Khodulev [8]. We begin with an infinite “chessboard” B covering the first quad-
   0

rant. The cells of the board are labelled by integer coordinates (i, j) with i, j ≥ 0.
Initially, a single “pebble” is located in cell (0,0) (the lower left corner; see Figure
1). The first step or “move” consists of replacing this pebble by two pebbles,
located at cells (1,0) and (0,1), respectively. In general, a move will consist of
removing some pebble, say in cell (i, j), and replacing two pebbles on the board, in
   5

positions (i + 1, j) and (i, j + 1), provided each of these positions is not already occupied. |    10

    After k steps the board will have k + 1 pebbles on it. We call such configura-
tions of pebbles reachable configurations. We will denote by R(k) the set of
reachable configurations with k pebbles, and we set R := ∪k≥1 R(k). In Figure 2,

we show the eight possible reachable configurations with at most four pebbles.
    A little experimentation convinces one that in any reachable configuration,
some pebble must occupy a cell having coordinates (i, j) with i + j ≤ 3. This fact
first seems to have been noted by M. Kontsevich [9]. We give the “book” proof of
this in the next section. If L(k) denotes the set (or “level”) {(i, j): i + j = k} then
   15

we can express the above assertion by saying that L(1) ∪ L(2) ∪ L(3) is unavoid-
able, i.e. any reachable configuration must always have some pebble in a cell in
L(1) ∪ L(2) ∪ L(3). In general, an unavoidable set is one which intersects every
reachable configuration. Of course if  S  is unavoidable and  T ⊇ S  then  T  is
unavoidable. Let us call S a minimal unavoidable set if S is unavoidable but no
   20

proper subset of S is, and let M(k) denote the family of minimal unavoidable sets
with k cells.
    In this note we will characterize the elements of M(k) and give a polynomial
time algorithm for recognizing such elements. Many of these results were first
proved by Khodulev [9], and we present them here for completeness, since the
   25

paper [8] is not widely available and contains only sketches of proofs. We will also
determine the asymptotic growth rates of r(k) := |R(k)| and m(k) := |M(k)|, the
sizes of R(k) and M(k), respectively, as k → ∞. (These results are all new.) It
turns out that the analysis of r(k) and m(k) leads to some interesting problems in
asymptotic enumeration.
   30

    Further results on this problem, including generalizations to arbitrary partially
ordered sets, have been obtained by Eriksson [4].

2. PROPERTIES OF UNAVOIDABLE SETS

Lemma 1. [9] The set L(1) ∪ L(2) ∪ L(3) of all (i, j) with i + j ≤ 3 is unavoidable.
Proof: To each cell (i, j) assign the weight 2−(i+j). Observe that:
   35

(i) 
The total weight covered by pebbles in any reachable configuration is 1.
This is so since the starting cell (0,) has weight 1, and a move does not
change the weight of cells covered, i.e.,

2−(i+j) = 2−((i+1)+j) + 2−(i+(j+1)).

(ii) 
The total weight of all cells in the board is ∑i, j ≥ 0 2−(i+j) = 4.

   40

(iii) 
The total weight of L(1) ∪ L(2) ∪ L(3) is 13/4. Thus, the weight of the
complement of L(3) is only 3/4, and since that is less than 1, cannot
contain all the pebbles of a reachable configuration. Thus L(1) ∪ L(2) ∪
L(3) is unavoidable.∎

    However, L(1) ∪ L(2) ∪ L(3) is not a minimal unavoidable set. The following
   45

result was proved by Khodulev [8]. It was independently conjectured by Martin
Gardner [6]. The proof given here is due to Harold Reiter [14].

Lemma 2. L(1) ∪ L(2) is unavoidable.

Proof: As before, assign the weight 2−(i+j) to the cell (i, j). Observe now that any
reachable configuration  C  has exactly one pebble on each of the boundaries

   50

{(i,0): i ≥ 0} and {(0, j): j ≥ 0}. Thus, the total weight which C can cover outside of L(1) ∪ L(2) is |    55

This implies that if C is to avoid L(1) ∪ L(2), it must cover all these cells, which is
impossible since C is finite.∎    

    However, L(1) ∪ L(2) is not minimal either, as we will see later.
    We should observe that for any reachable configuration C, the set of moves
needed for reaching C is unique. Only the order in which these moves are
executed can vary in the different ways of reaching C.
    Suppose now that we relax the rules for moves by allowing the replacement of a
   60

pebble at (i, j) by pebbles at (i + 1, j) and (i, j + 1) even when these positions
might already be occupied by pebbles. In other words, we allow the accumulation
of multiple pebbles in cells during the process of reaching C. It might be helpful
for this model to imagine that the pebbles first move onto the vertices of an
infinite binary tree rooted at (0,0). Then the 2k vertices in the kth level of the
   65

tree are identified in the obvious way with the k + 1 cells in the kth level L(k) :=
{(i,j): i + j = k} of the board B.
    An easy induction argument now establishes the following result

Lemma 3. If a configuration of pebbles (with at most one pebble per cell) can be
reached by moves which allow accumulations of pebbles in cells, then in fact it can
   70

also be reached by the “standard” moves, i.e., those which do not allow accumu-
lation.

    Given a set X ⊂ B, we define the set M(X) of moves recursively as follows.
Starting at level 0 and proceeding one level at a time by increasing levels, perform
the moves required either to remove all pebbles from a cell in X, or to remove all
   75

but at most one of the pebbles from a cell not in X. Continue through the last
level L(h(X)) containing a cell of X.

Theorem 1. X ⊂ B is unavoidable if and only if after executing the moves in M(X),
some cell contains at least 3 pebbles.

   80

(End of EWD1200)

transcribed by Corrado Cantelmi
revised 26-Dec-2011

EWD1202

The complete (n+1)-graph in n-dimensional space

We can embed the complete 2-graph with labelled vertices in a 1-dimensional world

  or  

and if the two "ends" of that 1-dimensional world are distinct, the above 2 embeddings are different.

We can embed the complete 3-graph with labelled vertices in a 2-dimensional world

  or  

and if the two "sides" of the plane are distinct, so are the 2 embeddings.

Similarly —and this will be our last example— the completed 4-graph can be embedded in 2 ways in directed 3-space —i.e. a 3-dimensional world that is distinct from its mirror image—

  or     .

The first question to be raised and answered is: how do we distinguish, for each number of dimensions, between the 2 embeddings? Moreover we would like to do so in a manner that does not destroy the symmetry between the vertices.

Here the theory of inversions —i.e. (the number of) pairs of elements out of order— gives the answer. For any k, k ≥ 2, the k! permutation of k elements can be partitioned into 2 classes of equal size such that a single swap transforms any permutation of the one class into a permutation of the other class. For elements A, B, the classes are {AB} and {BA}, for elements A, B, C, the classes are {ABC, BCA, CAB} and {ACB, BAC, CBA}, for elements A, B, C, D, the one class is {ABCD, ACDB, ADBC, BADC, BCAD, BDCA, CABD, CBDA, CDAB, DACB, DBAC, DCBA} and the construction of the other class is left to the reader. I would like to stress that the existence and "shape" of these classes have nothing to do with the labels A,B,C,… or their alphabetic order: they are intrinsically generated by the process of permuting. The two classes provide the answer to our first question: for any k, we associate the one class with the one embedding, and the other class with the other embedding.

The "oriented" (n+1)-graph has n+1 "faces", one opposite to each vertex. The way to give those faces an orientation in a systematic manner is, for instance, as follows: choose from the representative class for the (n+1)-graph a permutation that starts with the opposite vertex and select the rest of that permutation. So the oriented 3-graph with class {ABC, BCA, CAB} has face BC opposite to A, face CA opposite to B and face AB opposite to C; the 4-graph corresponding to ABCD has the 4 oriented faces corresponding to BCD, ADC, ABD, and ACB respectively, and any 2 of them contain the subface they share in opposite orientation: e.g. BCD and ADC contain CD and DC respectively, the one having been obtained by truncating a leading AB (from ABCD, as a matter of fact), the other by truncating a leading BA (from BADC). Generalization to more dimensions is left to the reader.

Austin, 16 March 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188. USA

transcribed by Joel Neely
revised Fri, 14 Mar 2008

EWD1203

Primes once more (re Kac & Ulam)

The plurals are defined as the integers ≥ 2. The plurals come in two sorts, the composite numbers, i.e. the plurals divisible by a smaller plural, and the prime numbers, i.e. the plurals not divisible by a smaller plural.

Lemma 0     Each plural has a prime divisor.

Proof     By mathematical induction over the plurals. Consider plural n. Either n is prime, in which case it has the prime divisor n, or it is composite, in which case it has a smaller plural divisor x which (because x < n) has "ex hypothese" a prime divisor that (since x divides n) is a prime divisor of n as well. (End of Proof.)

Remark     The above is a nice example of what is sometimes called "course-of-values induction", in which the proof obligation is (for arbitrary n)

〈∀x: x < n: hyp.x〉 ⇒ hyp.n

Notice in the above proof the absence of separate treatments of "base" and "step". (End of Remark.)

Lemma 1     There is no finite set of all primes.

Proof     Let S be a finite set of prime numbers and consider k given by k = 1 +〈Πx: x ∈ S: x〉 —because S is finite, the product of the numbers in S is defined—. By construction, k is not divisible by any of the primes in S —notice〈∀x: x∈ S: 2≤x〉—; by Lemma 0, however, k has a prime divisor that is not an element of S. (End of Proof.)

(Courtesy A. J. M. van Gasteren)

*                  *
*

The above has been written down so that we may compare it with how Mark Kac and Stanslaw M. Ulam treat the matter on the 1st page of Chapter 1 of their "Mathematics and Logic":

The following proof, probably still the simplest, asserts the mere existence of arbitrarily large primes. Suppose the number were finite; there would then be a largest prime p. Consider now the number n = p! + 1 (p! is read "p factorial" and equals 1 ∙ 2 ∙ 3 … p). This number is not divisible by any prime up to p. If there is no prime between p and n, as we have assumed, then n itself would be prime, contrary to our assumption that p is the largest one.

The authors hesitate between dealing with the number of primes and the value of primes: the first sentence deals with their values, the second one mentions their number. The conclusion of the second sentence is unwarranted: suppose there were no primes at all, then their number would have been finite (viz. zero), but there would not have been a largest prime p. (I would like the reader to appreciate that the argument in our proof of Lemma 1 is perfectly valid when S is empty.) The second sentence would have been better had they just written: "Suppose there were a largest prime p.".

The third sentence introduces n, the fourth sentence is the first one whose correctness depends on the concept "prime". Unfortunately, the authors opened their chapter a little earlier with:

1.  The Infinity of Primes
Among the so-called natural numbers (1, 2, 3, and so on) are some that are divisible only by 1 and by themselves; these are called the prime numbers. The prime numbers are the building blocks of all the numbers in the sense that every natural number is the product of powers of the primes that divide it. For instance 60 = 2²∙3∙5. The first several primes are 1, 2, 3, 5, 7, 11, 13, 17. It can be asked whether the series goes on forever, or, in other words, whether there is a largest prime. The answer is that there is no largest prime. This has been known since the golden age of Greece. It was proved by Euclid in the 3rd century B.C. His argument is as clear and fresh today as ever.

So, 1 is included in their primes, and the conclusion in their fourth sentence is just wrong. [This is another illustration of the fact that including 1 among the prime numbers is an unfortunate interface.]

The fifth sentence is supposed to conclude the proof, but it is very elliptic as it does not mention which property of prime numbers should justify the conclusion. It looks as if we are invited to conclude from the fact that none of the numbers between p and n is prime that none of these numbers divides n, and I hope that we are not supposed to use that "Every natural number is the product of [positive] powers of the primes that divide it", for otherwise we could apply the possibility of that factorization to n directly and conclude, without the assumption that p was the largest prime, because n ≥ 2 the existence of a prime larger than p. The last step of the quoted proof needs a possibly unstated and in any case unproven lemma (whose proof almost certainly requires mathematical induction). What an awful mess! And that in a book with the title "Mathematics and Logic"!

Now we are at it, I draw the reader's attention to the following sentence from the second quotation:

"It can be asked whether the series [of primes] goes on forever, or, in other words, whether there is a largest prime."

However, the answer to the first question is "yes", and to the second one "no".

Mark Kac and Stanislaw M. Ulam, "Mathematics and Logic", originally published: New York: Praeger, 1968, in series: Brittanica perspective. Dover Publications, Mineola, NY, 1992.

Austin, 17 March 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Ben Bacarisse
revised Mon, 28 Jan 2008

EWD1204

Complete DAGs

[DAG is just another TLA I don't approve of; it stands for "Directed Acyclic Graph .]

In a recent manuscript —in the literal sense of the word— : "Some properties of the relative converse" (March 1995), Tony Hoare plays with tetrahedra of which the edges may be directed. (As by-product of his considerations he finds, for instance, that "any non-cyclic ascription of directions to any five of the edges can be non-cyclically extended to the sixth edge.") Here is a little bit of related theory.

*                *
*

Let K be the complete graph with n vertices, in which each edge has a direction. Then the following 3 statements are equivalent

(i)    K contains no cyclic paths

(ii)   K contains no cyclic paths of length 3

(iii)  the outdegrees of the vertices of K are the values 0 through n-1

The equivalences hold for n=1, since for n=1, (i), (ii), and (iii) are all true. For general n, the proof proceeds by mathematical induction. The induction step itself is done by cyclic implication: we now consider the complete (n+1)-graph K' with directed edges, and observe for it

(i) ⇒ (ii)

This follows —independently of the induction hypothesis— from the fact that "of length 3" is a restriction.

(ii) ⇒ (iii)

Let A be of K' a vertex of maximum outdegree; let K be the n-graph that remains after removal of A and its n connecting edges. Because of (ii), also K contains no cycles of length 3 and, ex hypothese, the outdegrees of its vertices are the values 0 through n-1; consequently we are done when we show that A has outdegree n (note that then the vertices of K have the same outdegree in K as in K').

Let B be the vertex with outdegree n-1 in K; since, by construction, A is not a vertex of K, A and B are different vertices. We now first deal with
the edge AB, and then with the remaining edges connecting A to K.

The direction of edge AB is A→B for the assumption B→A   leads to a contradiction: then B would have in K' the (maximum) outdegree n, and so would A (by virtue of how it has been chosen: outdegree A ≥ outdegree B), but in the directed complete (n+1)-graph, at most 1 vertex has the maximum outdegree n.

Let C be a third vertex; then, because C is a vertex of K, in which B has the maximal outdegree n-1, the direction of edge BC is B→C. From A→B, B→C, and the absence of cycles of length 3 in K', we conclude that the direction of AC is A→C. (Note that, so far, we had only used the absence of cycles in K.) Hence, A has outgoing edges only, quod erat demonstrandum.

(iii) ⇒ (i)

Assume (iii) for K'; let A be the vertex of maximum outdegree n; let K be the n-graph that remains after removal of A and its n connecting edges. Possible cyclic paths in K' are then of two kinds, either they include A, or they lie in K.

Because A has outgoing edges only, no cyclic path leads through it; because of assumption (iii) for K' and of the fact that A has outgoing edges only, we conclude (iii) for K and, ex hypothese, that no cyclic paths lie in K. So, K' contains no cyclic paths, quod erat demonstrandum.

*                *
*

The absence of cyclic paths in the complete graph tells us —with apologies for the picture!— that each triangle is of the form , i.e. → is a transitive relation. Hiding this fact so far could be considered a conscious obfuscation on my part.

Austin, 29 March 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Joel Neely
revised Fri, 14 Mar 2008

EWD1205

A trip to Harvard Law School, 10-11 April 1995

I had been invited to participate in the session on "Intellectual Property" of the "Seminar on Information, Law and Technology", organized this semester at the Harvard Law School.

The session was due to start at 16:30. I rose at 5:30 and left home at 6:00 so as to catch my 7:06 flight to Boston; we had an intermediate stop in Chicago, where frozen rain induced a delay of half an hour. Since, in Boston, there was no one to meet me at the airport, I took a cab, but its driver was so incompetent that he dropped me at the wrong side of campus; fortunately, the weather was nice and my little suitcase was light. I arrived at what is now called "Hauser Hall" early in the afternoon.

Shortly after my arrival, two students recorded on video-tape an interview of me; they interviewed me quite nicely, posing sensible questions I could do something with. I am afraid that the interview was the nicest part of my visit.

When we returned from the interview, some more legal professionals had arrived and there was a lively discussion going on. For me the exposure was a cultural shock, instructive, but also rather disorienting. Of course I knew that lawyers are not scientists, yet the atmosphere of a trade school took me by surprise. Of course I knew that lawyers mainly deal with national law, yet I was unprepared for the prevailing parochialism. (Now I come to think of it, the system of common law, based —as it is— on custom and precedent, could very well strengthen this phenomenon.) but the most disorienting thing was that I found myself suddenly submerged in a verbal tradition that was totally foreign to me! They were on the average very verbose —some even repetitive—, they had a tendency to "reason" by analogy and more than once I felt that speakers cared more about the potential influence of their words than about what they actually said. (Are these common professional deformations of the trial lawyer?) I spoke for ten minutes, that is, I tried to do so: after several hours of exposure I no longer knew how to address this crowd.

I gathered that the situation is roughly as follows. There are ideas and these can be expressed. Patent law covers the protection of ideas, copyright law covers the protection of expressions. In order to make copyright law applicable to the protection of software, we are invited to regard programs as "literary works", in particular, to view the binary code as distributed as the "expression" that is protected by copyright law. I think that the analogy between programs and literary works would be considered weak even by medieval standards. For one thing, the analogy fails to reflect that the mechanical transformation of such an "expression" into a semantically equivalent one is now standard practice for more than several decades. (I got the impression that they try to patch this by disallowing such "decompilation"!) The whole effort seems one more demonstration that you cannot adequately deal with radical novelty by analogy.

I spent the night in the Sheraton Commander Hotel. Because the bar keeper assumed that I wanted to look at and listen to a television program, I went to bed without a nightcap. When I opened my door the next morning, I saw on the floor that the hotel management thought that I would like to read "USA Today". The music I could not escape at the breakfast table was similarly offensive. The previous day the responsible person at Harvard Law School had told me that the hotel had been instructed to send the bill to them; possible, but it was not known at the cashier's desk when I tried to check out.

Due to bad weather in Texas, my return flight via Dallas/Fort Worth had been cancelled. I was rerouted via Nashville, Tennessee. By the time we came there, winds were so strong that only one landing strip could be used. I caught my connection and was home in time for dinner.

Austin, 20 April 1995

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcription by James Lu.

Last revised on Sun, 30 Dec 2007.

EWD1206

An unfortunate use of symbols

I quote from a recent note “A Graphical Calculus” by Sharon Curtis and Gavin Lowe [Oxford University Computing Laboratory, Parks Road, Oxford, OX1 3QD, UK], just to bring you in the picture:

Formally, we consider graphs of the form (V, s, t, A) where V is a finite set of vertices, s∈V is the source, t∈V is the target, and A∈P(V×S×V) is a finite set of edges labelled with elements of S representing relations: the edge (v, R, v') represents an edge from v to v' labelled R.

So far, so good (that is, as long as the use of the verb “to represent” does not bother you). But half a dozen lines further they continue

| We can now formally define the way in which a graph represents a relation. Definition 1  The graph G = ({v₀,..., vn}, v₀, vn, A) represents the relation R where
(0) | xRy iff (∃x₀,...,xn • x = x₀ ∧ y = xn ∧                       ∀(vi, S, vj)∈A • xi S Xj).
| We call R the interpretation of G."

Remark  In the printed note from which I quote, (0) occupied a single line and the outer parenthesis pair was lacking. (End of Remark.)

There are all sorts of things wrong with “formula” (0). Minor things are that the use of x in the same context with and without subscript can be viewed as a “clash of identifiers” and that the use of the ellipse “,...,” almost certainly takes this character sequence outside the range of well-defined formulae. Much worse is the crummy use of quantification. Given an expression, one can quantify over one of its global (= free) variables, which then becomes a dummy, i.e. a local (= bound) variable of the quantification, in exactly the same way as in which lambda abstraction turns a global variable into a local one. I know how to deal with dummy variables but there are no such things as dummy expressions.

This immediately disqualifies the existential quantification as soon as we decide to view subscription as a notational alternative to function application (which is the only way in which I can cope with subscription). The universal quantification suffers from the added complication that the syntactic status of i and j is a complete mystery.

It was Rutger M. Dijkstra who, at the ATAC session of 25 April 1995, pointed out that the source of the trouble is the definition of G with its numbered vertices, which then calls for the numbered x-values. He eliminated those two functions on numbers (and the numbers themselves) ℕ→V and ℕ→X by introducing the (dummy) f : V → X :

Definition 1  The graph G = (V, s, t, A) represents the relation R where

xRy iff 〈∃f :: x = f.s ∧ y = f.t ∧〈∀v, S, w : (v, S, w) ∈ A : (f.v) S (f.w)〉〉.

By their poor use of symbols, the authors unnecessarily enfeeble their plea for their graphical calculus, but we can be grateful to them for reminding us once more of the penalty that subscription tends to entail.

Austin, 14 May 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Swarup Sahoo
last revised Tue, 7 Jun 2011

EWD1207

A theorem about "factors" perhaps worth recording

Let \ be defined by

(0)    [x;y ⇒ z]  ≡  [y ⇒ x\z]

(0) defines x\z as the weakest solution of

      y:  [x;y ⇒ z]

and yields with instantiations  y := x\z  and  z := x;y  respectively

(1)    [x; x\z  ⇒  z]

(2)    [y ⇒ x\(x;y)]

(We have given \ a higher binding power than ; .)

About the transpose ~ (prefix) —which others call the converse º (postfix)— I shall use the Dedekind Law

(3)   [x;y ∧ z  ⇒  x; (y ∧ ~x; z)]  .

*                 *
*

We shall now prove

(4)    [p;q ∧ ~p\r  ⇒  p;r ]

To this end we observe for any  p, q, r

p;q ∧ ~p\r

⇒       { (3) with x, y, z := p, q, ~p\r }

p ; (q ∧ ~p ; ~p\r )

⇒       {monotonicities, (1) with x, z := ~p, r }

p;r

I used (4) to prove the theorem of section 2.3 of "A Graphical Calculus" by Sharon Curtis and Gavin Lowe, Oxford University Computing Laboratory, Parks Road, Oxford, OX1 3QD; the formulation of (4) was triggered by their note.

An alternative formulation of (4) that incorporates the antimonotonicity of \ in its left argument is

(5)    [~p ⇒ s]  ⇒  [p;q ∧ s\r  ⇒  p;r]

I think the theorem is worth recording though not worth remembering.

Austin, 15 May 1995

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188 USA

Transcribed by Guy Haworth.

Lastr revised Sun, 30 Dec 2007.

EWD1209

Why American Computing Science seems incurable

Discussing how well academic Computing Science fares, we have, in the USA, to pay more attention to the Computing Industry than in other countries, and we have to do so for two reasons: firstly, compared to other countries, there is hardly a fence that separates the American university campus from the society that surrounds it, secondly, most, if not almost all, of the world's Computing Industry is concentrated in the USA. Consequently, opinions and prejudices prevailing in the American Computing Industry are here for academic Computing Science an undeniable force, be it driving or paralyzing.

For the sake of the stability of the enterprise, the ideal of its manager is an organization that is as independent as possible of specific abilities of individual employees. The predominance of this ideal is a well-documented, international phenomenon; the ideal itself predates the high-technology industry, in which it could very well be inappropriate, and has discouraged the industrial employment of scientists, in particular of the brilliant and original ones.

The American situation is aggravated by a total lack of faith in its educational system and a deep-rooted mistrust of intellectuals.

Aside How typically American this mistrust is, is illustrated by the fact that the American word "egghead" has no Dutch translation. I looked it up in my Webster's New Collegiate Dictionary (1973), which in its quotation fully captures the untranslatable connotation:

"egghead  n: INTELLECTUAL, HIGHBROW <practical men who disdain the schemes and dreams of ~s   — W.L.Miller>".

By Dutch standards, Miller's quotation is an unambiguous disqualification of "practical men". (End of Aside.)

Accordingly, prevailing industrial attitude exerts a strong pressure on the University not to indulge in such hobbies as scientific education, but to confine itself to vocational training of some sort or another.

But in the case of Computing Science, it is not only the teaching that is influenced by the industrial prejudices, research suffers as well. I remember, for instance, a so-called "faculty candidate" who talked about his Ph.D. work — they usually do—, which was a system for the "parallelization" of a modest class of Fortran programs. The speaker did not claim that he had gained any new insights or that you could learn anything interesting from studying his thesis, and the sole justification of his work was to be found in his final product, viz. his Fortran program parallelizing software. And this software was very important because (i) there were thousands of Fortran programs "out there", and (ii) the system was fully automatic, an absolute requirement for industrial acceptance. (I am not making this up!)

I thought that the main criterion by which to judge our academic research is how it improves our teachable material, but this poor bloke had adopted "industrial acceptance" as quality criterion, and as a result his gadget worked in such a small set of circumstances that its main feature became that one could apply it unthinkingly.

There are other instances of how research suffers from industrial pressure.

Being a better programmer means being able to design more effective and trustworthy programs and knowing how to do that efficiently. It is about not wasting storage cells or machine cycles and about avoiding those complexities that increase the number of reasoning steps needed to keep the design under strict intellectual control. What is needed to achieve this goal, I can only describe as improving one's mathematical skills, where I use mathematics in the sense of "the art and science of effective reasoning". As a matter of fact, the challenges of designing high-quality programs and of designing high-quality proofs are very similar, so similar that I am no longer able to distinguish between the two: I see no meaningful difference between programming methodology and mathematical methodology in general. The long and the short of it is that the computer's ubiquity has made the ability to apply mathematical method more important than ever.

In a cruel twist of history, however, American society has chosen precisely the 20th Century to become more and more a-mathematical (a phenomenon, for instance observed —and bemoaned— by Morris Kline), and we have reached the paradoxical state that, of all so-called developed nations, the USA is the most dependent on programmed computers and intellectually the worst equipped to be so. The suggestion that the programming problem could be amenable to mathematical treatment is, if heard at all, instantaneously rejected as being totally unrealistic.

As a result, Program Design is prevented from becoming a subdiscipline of Computing Science. There is considerable concern for correctness, but almost all of it has been directed towards a posteriori program verification because, again, that more readily appeals to the dream of complete automation. But, of course, many —I included— regard a posteriori verification as putting the cart before the horse because the whole procedure of programming, first and verifying later raises the burning question where the verifiable program comes from. If the latter has been derived, verification is no more than checking the derivation. And in the mean time, programming methodology —renamed "software engineering"— has become the happy hunting-ground for the gurus and the quacks.

Deprived of what is generally considered computing's core challenge, American Computing Science is the big loser, and we cannot blame the universities, for when the industry most in need of their scientific assistance is unable to face that they are in a high-technology business, even the best university is powerless. Universities should be more enlightened than their environments, and they can, but not much(that is, not openly). In the current political climate, it is unlikely that things will improve soon; in the near future we shall have to live with the superstition that also programming is "so easy that even a Republican can do it".

Austin, 26 August 1995

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcription by James Lu.
Last revised on Sun, 23 Dec 2007.

EWD1210

The non-unique node multiplicity

For N ≥ 2, we consider a graph of N "nodes" with any pair of nodes being connected by an "edge" or not —in the jargon: an undirected graph without multiples edges and without autoloops—; the number of edges meeting at a node is called that node's "multiplicity".

Consider now two nodes. The difference between their multiplicities is determined by how they are connected to the other N-2 nodes, and is maximal if the one is connected to all other N-2 nodes, and the other to none of them. Hence, the difference between two multiplicities is at most N-2; hence there are at most N-1 different multiplicities, and hence, with N nodes, there are at least 2 nodes with the same multiplicity.

*                 *
*

I would like my readers to appreciate that the argument in the previous paragraph —which is only 74 words long— contains neither a case analysis, nor a reductio ad absurdum.

It has been written in reaction to P.R. Halmos's treatment of this problem, a treatment which I think very ugly. By assigning a special role to nodes with multiplicity 0, Halmos immediately destroys the symmetry between presence and absence of edges. He then embarks on a three-fold case analysis: no such node, 1 such node, or at least 2 such nodes. in the final argument, which is phrased for N=100 but is supposed to hold for N=99 as well, it is no longer clear where 100 ≥ 2 is used. Note that in the following quotation from Halmos, "to be acquainted with" is supposed to be a symmetric relation.

Suppose that a bunch of us are together in a room, 100 of us, say, and we form temporarily a small society of our own. In this closed society there are a certain number of acquaintanceships: some of us are acquainted with some others. I don't know which ones of us are acquainted with which others, but I'm sure of one thing: I'll bet that there are at least two of us that have the same number of acquaintances.

Believe it? Let's see if I can make it convincing. Suppose that someone asked us, each of us, myself included: "How many other people in this closed society are you acquainted with?" We could all tell him an answer, somewhere between 0 and 100. No, wait a minute. If there are exactly 100 of us, then nobody is acquainted with 100 OTHER people: the largest number can be no larger than 99. As fas as 0 is concerned, that's all right, there could well be some hermits among us, but it is not likely, and, in any event, I can easily settle that case. If there are two or more hermits, then I've already won my bet: any two hermits have the same number of acquaintances. If there is only one hermit, then let's ostracize him —let's not count him— let's go so far as to pretend that he isn't here. I must still prove that among the remaining 99 there are two of us with the same number of acquaintances, and I'll do so — but because 100 is easier to say than 99, let me assume that even if the possible hermit is not counted there are still 100 of us left.

So then, what possible numbers will each of the 100 of us give to the questioner? Answer: any number between 1 and 99 inclusive. What is it that I am betting? Answer: that two of us will give the questioner the same number. Indeed: how could we fail? There are only 99 numbers to tell him and there are 100 of us telling: there must be at least one repetition. (Quoted from [1].)

The shape of the above argument is crummy, its presentation is perhaps even worse. To turn the nodes into persons is no improvement, on the contrary, since the anthropomorphic terminology invited the introduction of a contradiction. On the one hand, Halmos the author belongs to the "100 of us", on the other hand, Halmos the mathematician makes a bet. In the latter capicity he states "I don't know which ones of us are acquainted with which others", in the former capacity he can tell the questioner the number of his acquaintances! In short, total confusion.

There is no point in blaming Halmos, for he is of an older generation and from a different culture; moreover, he is not obliged to pretend to be better than he is. What worries me is that a sizeable fraction of the mathematical community thinks his performance good enough. In [0], A. Dijksma writes in his "Laudatio" about Halmos: "Throughout his career, which now comprises more than 50 years, he has maintained a high standard. As a result he has become renowned as an educator and teacher […] brilliant expositor […]". The reader cannot help wondering what the old man is being praised for. Talking down to his audience?

We all know that the mathematical community feels threatened, but it should understand that it does not improve its intellectual standing by lowering its standards of rigour and clarity.

[0] | Dijksma, A. "Paul R.Halmos: A Complete Professional Mathematician", Nieuw Archief voor Wiskunde, Vierde serie Deel 13 No.1 maart 1995, pp. 49-60
[1] | Halmos, P.R. "To Count or to Think, That is the Question", Nieuw Archief voor Wiskunde, Vierde serie Deel 13 No.1 maart 1995, pp. 61-7

Nuenen, 14 July 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Joan Llosas Colongo
revised Wed, 2 Dec 2009

EWD1211a

On some very binary patterns

dedicated to F.E.J. Kruseman Aretz

In his last manuscript “A collection of nice problems”, Jan L.A. van de Snepscheut described the following one-person game. There is a table with four coins in the positions north, east, south and west, and the player’s goal is to get them all in the same orientation, i.e. all heads or all tails. The player never sees the coins but will be informed as soon as he has reached his goal. A move consists of the player mentioning one or more positions in which the coins will then be turned over; the complication is that, prior to each move, the table is rotated by a multiple of 90°; the multiple remains unknown to the player and may vary from move to move.

The version of the problem that Rutger M. Dijkstra told me after the 3rd International Conference on the Mathematics of Program Construction at Kloster Irsee, Germany — where it had apparently circulated — had been sanitized in that the player’s goal had been simplified to “all coins in a given orientation, say heads”. Moreover, Rutger had generalized the number of coins from 4 to any power of 2, a generalization that was extremely helpful because it was an irresistible invitation to look for a nicely recursive solution.

There are three reasons for writing this note. Firstly, when I had designed a winning strategy, I did not know how to present it nicely. Secondly, my solution’s correctness implied a theorem (of sorts) that I did not yet know how to formulate decently. Finally, there is my hope that Frans E.J. Kruseman Aretz, to whom this note is dedicated, will appreciate my efforts.

*                       *
*

In order to avoid all ambiguity, let us formulate the game as a program of which termination has to be guaranteed.

We introduce the type BV of bit vectors of length n (n ≥ 1 ; in Jan’s original problem, n = 4), and two constants ZEROS and ONES of type BV (viz. the sequence of n 0s and the sequence of n 1s respectively). On arguments of type BV, we denote the bit-wise addition modulo 2 (also known as “the carry-less sum”) by an infix ∔ ; as any sum, it is symmetric and associative. Finally, we introduce a function

rot: int → (BV → BV)

of which we know that rot.i.bv is some rotation of bv. We have no further knowledge how rot.i depends on i (which will act below as move number).

In the following program block, the state of the table with its coins is represented by an initialized global variable

t: BV

The player’s strategy is represented by a global function

ps: int → BV          ,

where the 1s in the bit vector ps.i identify the positions in which the coins are turned over in the i-th move.

In the original problem we were interested in the termination of

(0)      |[ var i: int; i ≔ 1
         ;  do t ≠ ZEROS ⋀ t ≠ ONES →
       t ≔ rot.i.t ∔ ps.i ; i ≔ i + 1
    od
]|

but in the rest of this note we deal with the “sanitized” version

(1)      |[ var i: int; i ≔ 1
         ;  do t ≠ ZEROS →
       t ≔ rot.i.t ∔ ps.i ; i ≔ i + 1
    od
]|

Remark Note that in simplifying the guard we have weakened it. Hence, termination of the sanitized version (1) implies termination of the original program (0). (End of Remark.)

The challenge now is to design such a function ps that (1) terminates independently of the initial value of t and independently of how rot.i depends on i.

The purpose of our next massaging is to facilitate keeping track of the identity of the coins so as to ease tracing the influence of a change in the initial value of t.

We observe that as far as the identity of the coins turned over in a move is concerned, the effect of how far the table has been turned clockwise can also be obtained by the corresponding anti-clockwise turn of the player’s move. More precisely: because

(i) | rotation distributes over bit-wise addition
(ii) | ZEROS is a fixpoint of any rotation, and
(iii) | we have to guarantee termination whatever rot’s dependence on its first argument,

our concerns about termination of (1) are equivalent to the concerns about termination of

(2)      |[ var i: int; i ≔ 1
         ;  do t ≠ ZEROS →
       t ≔ t ∔ rot.i.(ps.i) ; i ≔ i + 1
    od
]|     ,

viz. for all rot, and for all initial t. The gain of this rewriting is that it makes it easier to separate these two universal quantifications.

Consider now a terminating computation of (2) and let fi be the final value of i. Because ∔ is associative and ZEROS has the property

u ∔ v = ZEROS ≡ u = v       ,

we can conclude that the carry-less sum of rot.i (ps.i) for 1 ≤ i < fi equals the initial value of t. Termination of (2) for any initial value of t is thus equivalent to stating that during execution of

(3)      |[ var i: int; s: BV; i,s ≔ 1, ZEROS
         ;  do i ≠ N →
       s ≔ s ∔ rot.i.(ps.i); i ≔ i + 1
    od
]|

with sufficiently large N, variable s successively takes on all possible value of type BV. Because type BV comprises 2n distinct values, “sufficiently large” is at least 2n. As we will show, we don’t need a larger value; for the rest of this note we choose

N = 2n

Now our challenge is to define N-1 values ps.i (1 ≤ i < N) such that, in the execution of (3), for any rotation function rot, variable s successively takes on all its N possible values. We shall solve the problem for n=1, and shall show how, from a solution ps for n, we can construct a solution ps′ for n′, provided n′=2n . We thus solve the problem for n an arbitrary power of 2.

Remark Since — as the reader may verify — the problem is unsolvable for n=3, there is probably no point in trying to be more ambitious. (End of Remark.)

For n=1, N=2 and ps.1=1 does the job: rotating a big vector of length 1 leaves it unchanged and in the one and only step of the execution of (3), the single bit s is inverted.

For n′=2n, type BV′ comprises the N′ bit vectors of length n′ with N′=2n′ or N′=N². Variable s′ is of type BV′ and function ps′: int → BV′ is to be defined under the hypothesis that ps solves the problem for bit vectors of length n.

For the purpose of our discussion we introduce variables u,v: BV such that

s′ = u ⫲ v

(where ⫲ denotes catenation). The above relation implies that s′ determines the pair (u,v) and vice versa. We observe that this also holds for s′ and the pair (u ∔ v , v). (This observation captures the core of our solution.) In our solution, ps is used at two levels, so to speak. At one level — see below at "r = 0" — ps is used to generate all possible values for u ∔ v; at the other level — see below at "r ≠ 0" — ps is used to generate, for each value of u ∔ v and under invariance of it, all possible values for v. The two levels thus generate all (u ∔ v , v) pairs, i.e. all s′-values. More precisely, with 1 ≤ q * N + r < N² ⋀ 0 ≤ r < N , ps′ is defined by

ps′.(q * N + r) = if r = 0 → ZEROS ⫲ ps.q
                  ⫾  r ≠ 0 → ps.r ⫲ ps.r
                  fi

We have to check that the rotations in (3′) of bit vectors of length 2n can be interpreted as rotations of bit vectors of length n, so as to make ps applicable as generator of all BV values. On the first level, the symmetry of u ∔ v takes care of that, on the second level the symmetry of ps.r ⫲ ps.r does so.

For the sake of illustration, we tabulate ps for small values of n in fig.0. (For n=8, we give only the beginning of the table, which has 255 entries.)

In the column marked “ps” we have tabulated the ps-values as bit vectors of length n. In the column marked “gr” we have tabulated the corresponding “generators”, which are more compact characterizations of ps-values. Starting with a bit vector of length 1, consisting of a single 1, we can construct any ps-value by successively subjecting our bit vector to operation x or to operation y:

x: double its length by prefixing zeros
y: double its length by catenating a copy

The generator records in order from right to left the sequence of operations that construct the ps-value. (Hence, 01010101 has generator yyx, while 00001111 has generator xyy.) Note that each y in the generator doubles the number of 1s in the bit vector.

For the sake of completeness we give a recursive definition, which is completely analogous to that of ps.

For n=1, gr.1 = “the empty string”; for n′, with 1 ≤ q * N + r < N² ⋀ 0 ≤ r < N

gr′.(q * N + r) = if r = 0 → x⋅ gr.q
                  ⫾  r ≠ 0 → y⋅ gr.r
                  fi

where x⋅ and y⋅ denote prefixing by the indicated singleton.

The advantage of generators is that they are nonredundant: not every bitvector is a ps-value, but every x/y-sequence is a generator. Generators, more precisely, the function gr will be explored for its own sake in the next section.

*                       *
*

The tabulated generators admit an alternative interpretation, viz. as identifiers of the bits whose inversions generate what is known as the “Gray Code”, e.g. for n=4:

That the Gray-Code table of width n and height N, as generated above, contains all N values, can be demonstrated by showing that any two entries in the table differ.

To this end we define for generators of equal length a total order < by the alphabetic order, i.e. with P and Q generators of equal length

(4a)     x⋅P < y⋅Q
(4b)     x⋅P < x⋅Q ≡ P < Q
(4c)     y⋅P < y⋅Q ≡ P < Q

and now we can formulate

Lemma 0 In the sequence gr.i , h ≤ i < j with 1 ≤ h < j < N , the alphabetic minimum of the values in the sequence occurs exactly once.

Proof sketch In view of the recursive definition of gr, the proof is by mathematical induction on the length of the generator, with a case analysis in the induction step.

Either some value in the sequence starts with an x, or all values in the sequence start with y.

In the first case, (4a) tells us that we can configure our attention to the values of the form x⋅ gr.q ; the q-values being consecutive, (4b) thus reduces the demonstrandum for gr′ to the demonstration for gr.

In the second case we have a sequence of values of the form y⋅ gr.r with consecutive r-values; this time, (4c) performs the reduction.

(End of Proof sketch.)

Lemma 0 implies the absence of duplicates in the table we generated for the Gray Code: in the sequence of transitions that transforms the one entry into the other, the unique minimum identifies a position in which one inversion takes place, and in which therefore the entries differ.

*                       *
*

After the above interlude about the Gray Code, we return to our original problem. We have shown earlier that all the 5-values generated by (3) are distinct, whatever rotations for the ps-values are chosen, but now the obvious challenge is to prove this as well in a way analogous to our demonstration of the absence of duplicates in the Gray Code.

To this end, we associate with each generator its “patterns” and its “partition”; we discuss the patterns first. The patterns are the corresponding ps-value in its various rotations. For instance, generator yxy yields ps-value

         00110011              (0, 1, 4, 5)

and by rotation the further patterns

         01100110              (1, 2, 5, 6)
         11001100              (2, 3, 6, 7)
         10011001              (3, 4, 7, 0)       .

Next to each pattern we have recorded — numbering them in the patterns from right to left — the bit positions of its 1s. They are of interest because, modulo n, their differences are unaffected by rotation. Note that the positions of the 1s in the ps-value are obtained by substituting in the generator 0 for x, and for each y a 0 or a 1, and reading the result as a binary number. For instance, in the above example, generator yxy yields 1s in positions 000(=0), 001(=1), 100(=4) and 101(=5).

The partition associated with a generator partitions the bit positions and has as many cells as an associated pattern has 1s. Each cell contains the values whose binary representations coincide in the y-positions of the generator. For instance, generator yxy yields the partition

Lemma 1 An arbitrary pattern associated with a generator has exactly one 1 in each cell of the partition associated with that generator.

Proof Since the number of 1s in the pattern equals the number of cells in the partition, it suffices to show that no cell contains two 1s. We show this by demonstrating that no distance between two 1s in a pattern equals the distance between two positions in a cell of that partition.

We use two little theorems about binary arithmetic of natural numbers
(i) the least-significant 1 in the difference of two distance numbers occurs in a position where one of the numbers has a 1, the other a 0
(ii) two numbers whose least-significant 1s occur in different positions, differ.

The distance between two 1s in a pattern equals modulo n (which is a “higher” power of 2) the distance between two 1s in the ps-value (e.g. in our last example 7 - 0 = (8 + 4) - 5). The ps-value has its 1s in positions whose binary numbers have their 1s in the y-positions of the generator. From little theorem (i) we conclude that the least significant 1 in the binary representation of the distance between two 1s in a pattern occurs in a y-position of the generator.

By construction, a cell contains values that in binary only differ in x-positions of the generator, and thus we conclude from little theorem (i) that the least-significant 1 in the binary representation of the distance between two positions in a cell occurs in an x-position of the generator.

Thanks to little theorem (ii), the last two conclusions imply that no distance between two 1s in a pattern equals the distance between two positions in a cell of the partition.

(End of Proof.)

Lemma 2 Let generator G0 be alphabetically less than generator G1; then each pattern associated with G1 has an even number of 1s in each cell of the partition associated with G0.

Proof This proof is a little bit more complicated because the notion of alphabetic order has to be taken into account. The proof is by mathematical induction over the length of the generators. In base and step, P and Q are generators of the same length b and n = 2b.

Base The base case — see (4a) — are two generators whose left-most characters differ, i.e. G0 = x⋅P and G1 = y⋅Q .

By construction, the 1s in a pattern associated with y⋅Q can be grouped in pairs of 1s that are n apart. Also by construction, positions that are n apart occur in the same cell of the partition associated with x⋅P. From these two observations, the theorem follows for the base case.

Step Here — see (4b) and (4c) — we consider two generators whose left-most characters are equal. With P < Q we distinguish two cases.

(i) G0 = x⋅P ⋀ G1 = x⋅Q   .

Patterns associated with x⋅Q are twice as long and have the same number of 1s as those associated with Q and are obtained from the latter by moving a number of its 1s at the right-hand side over n places to the left. In the transition from P to x⋅P, each cell is doubled in size by taking its union with the image obtained by moving it over n places to the left. Consequently, a new pattern has as many 1s in a new cell as some original pattern had in some original cell.

(ii) G0 = y⋅P ⋀ G1 = y⋅Q   .

Patterns associated with y⋅Q are twice as long and have twice as many 1s as those associated with Q and are obtained from the latter by prefixing each pattern with a copy of itself. In the transition from P to y⋅P, cell size remains unchanged but their number is doubled: each original cell spawns the image obtained by moving it over n places to the left. Again a new pattern has as many 1s in a new cell as some original pattern had in some original cell.

And thus Lemma 2 has been proved for generators of arbitrary length. (End of Proof.)

Consider now a sequence of moves in (3). According to Lemma 0, there is in that sequence a unique move with the alphabetically smallest generator. Now focus on the parities of the cells of the partition of that generator. According to Lemma 1, that unique move changes these parities, while according to Lemma 2, all other moves leave them unchanged.

Acknowledgements I thank Rutger M. Dijkstra for drawing my attention to the problem and for generalizing four to any power of two. In matters of presentation I am endebted to the Tuesday Afternoon Clubs of Eindhoven and Austin.

                          Nuenen/Austin, August/September 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Jonathan David Arndt
revised 01-Mar-2021

EWD1212

For the record: painting the squared plane

Thanks to Richard S. Bird, the following problem circulated at the 3rd International Conference on the Mathematics of Program Construction, Kloster Irsee, Germany, 1995.

Starting with a sufficiently large piece of (white) squared paper, we play the following one-person game, that consists of two phases. In the first phase, we may select 9 squares and colour them red. In the second phase, we may repeatedly colour a white square red provided it already has at least 2 red neighbours (where being neighbours means sharing an edge). The question to be answered is "Is it possible to colour the 10 by 10 square?"

*              *

*

When, in the second phase, a white square may be coloured on account of exactly two "enabling" neighbours, we can draw the topological conclusion that there are two possibilities for the relative position of those two enabling neighbours: either around a corner or opposite to each other. When we demonstrate a possibility by showing how to do it, we can hardly avoid that each move in our witness is of some type. For instance: in order to show that the 9 by 9 square can be coloured, we can colour in the first phase the squares along a diagonal; in the second phase the enabling neighbours are then always situated around a corner. (For the 9 by 9 square there are also solutions in which opposite enabling neighbours occur as well.)

When demonstrating an impossibility, we consider no solutions because there aren't any, and in this type of argument it would be very nice to avoid the case analysis by not drawing the topological conclusion at all, i.e. by ignoring the cyclic arrangement of the four neighbours and of the four edges they share with the square they surround. In short, for an impossibility argument it is very tempting to try to get away with the simplicity of a counting argument. The only still open question is then what to count.

Counting red squares is too crude: their number increases by 1 at a time, which is only mildly interesting; worse is that the notion "red square" says nothing about the notion of being neighbours. In order to capture the latter, we have to turn to the edges.

How do we relate edges to colours of squares? Each edge is identified by --and identifies-- the pair of squares that share it. This enables us to define three "edge colours":

an edge is red, when shared by two red squares,

an edge is white, when shared by two white squares, and

an edge is pink, when shared by a red square and a white square.

Accordingly, a white square has no red edges, and a red square has no white edges. More precisely: colouring a white square red, turns its pink edges into red ones, and its white edges into pink ones. The rule in the second phase of "at least two red neighbours" means that at least 2 pink edges turn red, and at most 4-2 white edges turn pink. In other words: in the second phase, the number of pink edges does not increase. Since the first phase does create at most 36 pink edges, we never end up with the 40 pink edges that would occur in a red square of 10 by 10, and thus the question is settled.

*              *
*

Faced with a problem, people usually react as follows. In their first explorations they try to colour the 10 by 10 square, and, finding they cannot do it, they change to trying to show the impossibility, but in that second effort they drag all the topological ballast into the argument, make pictures, talk about "occupied colums and rows" etc. In that second effort they are heading for a counting argument, but are insufficiently aware that avoiding case analysis is counting's major purpose.

*              *
*

The final argument nicely illustrates the linguistic demands that the doing of mathematics makes: a term for what we called "pink edges" is absolutely essential.

Austin, 30 August 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Jennifer Lu Greene.
Last revised Sun, 30 Dec 2007.

EWD1213

Introducing a course on calculi

The functions I grew up with, such as the sine, the cosine, the square root, and the logarithm were almost exclusively real functions of a real argument. Sometimes, but not very explicitly, the argument could be allowed to be a little bit more complicated, such as the maximum of two values, a real function defined on a pair of real values, or on two values: whether the maximum was a function of one argument (which had to be a pair) or was a function of two arguments (each of which was a real number) was a question that was avoided. Didn't we talk about the types of the function arguments, we did not talk about the types of the function values either: we did not need to, for to all intents and purposes, all our functions were of type real. (Later this was extended to the type complex, but that was about it.) The nett effect was that I was extremely ill-equipped to appreciate functional programming when I encountered it: I was, for instance, totally baffled by the shocking suggestion that the value of a function could be another function.

Outstanding features of functional programming are (i) the rich type structure needed to make the paradigm of function abstraction and function application sufficiently flexible, and (ii) the predominance of functional composition as structuring device. The clarity and economy of expression that the language of functional programming permits is often very impressive, and, but for human inertia, functional programming can be expected to have a brilliant future, the more so because today's computers admit quite efficient implementations of functional programming languages.

But this is not the complete story. You see, there are people —and I am one of them— that think they have a good reason for not wanting to delegate all calculation to our machines, because they see a role for unprogrammed calculations done by themselves —for instance in the deriviation of proofs and programs—. Whether certain operations are convenient to carry out or not, of course greatly depends on the tools one has to do it with, and in this context we have to accept that a random-access store and the combination of pen and paper are two storage media with totally different characteristics. In particular, evaluating a functional program with pen and paper is a pain in the neck! In contrast, this course focusses our attention on calculi, geared to the use of pen and paper (a medium that has more virtues besides being traditional).

I expect most of our time to be spent, first on the predicate calculus, and then on the relation calculus. For the sake of greater utility, we shall immediately introduce a generalized predicate calculus which later will be used as the framework [sic!] in which to define the relation calculus.

The traditional boolean type is two-valued: {true, false}. If so desired we can model these two values by the 2 subsets of a 1-element universe, the traditional association being that of true with that universe and of false with the empty subset. Our generalization consists of a (still boolean) type whose values can —but don't need to— be modelled by the subsets of a larger universe. As a result, this calculus is widely applicable; for those familiar with it, it often becomes the tool of almost daily reasoning.

The reason to deal with the relation calculus is two-fold. Firstly, relations are a mathematically succinct way of capturing the semantics of not necessarily deterministic programs, secondly, because the relation calculus is more structured than just the predicate calculus, it provides an ideal terrain for the development of heuristics for proof design.

*          *
*

I think it wise, and only honest, to warn you that my goal is immodest. It is not my purpose to "transfer knowledge" to you that, subsequently, you can forget again. My purpose is no less than to effectuate in each of you a noticeable, irreversable change. I want you to see and absorb calculational arguments so effective that you will never be able to forget that exposure. I want you to gain, for the rest of your lives, the insight that beautiful proofs are not "found" by trial and error but are the result of a consciously applied design discipline. I want to inspire you to raise your quality standards. I mean, if 10 years from now, when you are doing something quick and dirty, you suddenly visualize that I am looking over your shoulders and say to yourself "Dijkstra would not have liked this.", well, that would be enough immortality for me. Your obligation is that of active participation. You should not act as knowledge-absorbing sponges, but as whetstones on which we can all sharpen our wits. If you don't understand me, ask for clarification; if I am going too fast, slow me down. (If I am going too slow, you may try to speed me up, e.g. by yawning?) Finally, don't expect me to motivate you, but during "office hours" I would like to get personally acquainted with you.

Austin, 30 August 1995

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78750 - 8138 USA

Transcriber: Andy Fugard
Last revised on Sun, 30 Dec 2007.

EWD1214

The marriage agency

A marriage agency has in its files 25 men and 25 women and aims at acquainting the men with the women by organising dinner evenings, each one involving 12 tables, seating 2 men and 2 women. (Consequently, at each dinner evening, 1 man and 1 woman have a day off.) The question is how many of such dinner evenings the marriage agency can schedule without some man and woman sharing a table twice.

*                *
*

Frans van der Sommen raised this problem at the end of the ETAC session of 8 August 1995. Rutger M. Dijkstra, who happened to attend that session, immediately showed how to schedule 12 dinner evenings: partition the men into a singleton and 12 pairs numbered [0...12), do the same with the women, and let on the nth evening the men of pair i share a table with the women of pair (i+n) mod 12.

The demonstration that 12 is indeed the maximum took a litle bit longer. Consider a sequence of 13 dinner evenings. Then at most 13 men have had an evening off, and therefore at least 12 (= 25 - 13) men dined all 13 evenings. Such a man enjoyed 26 (= 2 × 13) times the company of a woman; the number of women being 25, there is —pigeon-hole principle— at least one woman whose company he enjoyed at least twice. [As said, this took a little bit longer. We first tried too crude a counting argument in terms of man-woman combinations. Their total number is 625 (= 25 × 25), each evening 48 (= 4 × 12) combinations are getting acquainted. Since 625/48 = 13+1/48, this rules out a schedule of 14 or more evenings, but the feasibility of a schedule of 13 dinner evenings it leaves open.]

This is actually a sequel to EWD1212: feasibility is shown by means of a witness, infeasibility by a counting argument.

Austin, 5 September 1995   

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188 USA

Transcribed by Guy Haworth
Last revised Sun, 30 Dec 2007.

EWD1215

Courtesy Dr.Birgit Schieder

This note deals with the proof of the following

Theorem Given are N blue and N red points in the Euclidean plane such that no 3 of them are collinear; then blue and red points can be connected one-to-one by straight line segments such that no segments intersect.

The proof is by showing the termination of the following repetition, operating on an arbitrarily initialized variable of type “one-to-one correspondence between the given N blue and N red points”:

do  | there are intersecting segments →
| flip two intersecting segments od            ,

where the operation “flip” replaces as illustrated below two intersecting segments (the solid ones) by two non-intersecting segments (the dotted ones):

We can not conduct the proof of termination by stating that the flip reduces the number of segment/segment intersections, for it need not do so: the “dotted” segments may introduce new intersections with other segments.

The famous termination argument observes (i) that the number of possible states is finite (viz. N!), so that a real variant function will do, and (ii) that the flip decreases the sum of the lengths of the N connecting segments (and it is here that the noncollinearity is used to rule out all sorts of “pathological” cases). This argument is famous because it is also a little bit scandalous because of its illicit affaire with the notion of Euclidean distance. (It is most definitely not a metric theorem we are dealing with.) So, when I showed th above argument in 1994 at the Marktoberdorf Summer School, I challenged the audience to design a “decent” proof (i.e. using only concepts of affine geometry.) The challenge was most elegantly met by Dr.Birgit Schieder (of the “Institut für Informatik der Technischen Universität München”), who constructed a counting argument. The challenge is, firstly, to choose what to count and, secondly, to design a crisp argument for the decrease.

The changing state of the computation is characterized by the one-to-one correspondence, i.e. by the set of N connecting segments. Below, we shall use the term “segment” to denote the so-called “open” segment, i.e. its two coloured endpoints are not included. We shall use the term “line” to denote any of the N 2 infinite lines through 1 blue and 1 red point; this set of N 2 lines is as fixed as the 2N coloured points. Finally, a line and a segment are said to be “intersect”, or to give rise to an “intersection”, when they have exactly 1 point in common.

Lemma 0 For no line the number of segments it intersects is increased by a flip.

Proof

For a line whose number of intersections is possibly increased by the flip, we can confine our attention to lines that intersect at least 1 of the segments created by the flip. Representative instances are line p (intersects 1 dotted segment) and line q (intersects 2 dotted segments). But —not thanks to Euclid, but thanks to Hilbert— they intersect as many solid segments, so the flip does not increase their number of intersections. (End of Proof.)

Lemma 1 For two lines, the number of segments intersected is decreased by 1.

Proof Line (B0, R0) loses its intersection with segment (B1, R1), which disappears, and intersects neither of the new segments. Similarly for line (B1, R1) (End of Proof.)

From the lemmata we conclude that each flip decreases the number of line/segment intersections, and this concludes Birgit Schieder’s counting argument.

*            *
*

I posed the problem to the Tuesday Afternoon Clubs in Eindhoven and Austin; both solved the problem. At the ETAC, we then investigated how the case analysis could be reduced, and how the argument that it is exhaustive could be simplified. (The argument as given above, however, was designed later.) At the ATAC, we afterwards looked for heuristics that would have led to the idea of counting segment/line intersections. In retrospect we could make all sorts of explanatory and justifying remarks, but none of them could in honesty be dressed up as heuristic principle.

The counting argument annoys me because my “proof” of Lemma 0 relies so heavily on that part of geometry with whose axiomatization I am so unfamiliar: I know Euclid’s axioms, but for a proof of Lemma 0 they don’t suffice.

Austin, 17 September 1995

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD1216

The equation x:[x]

For equality between "predicates' x and y we introduce the notation [x ≡ y]. For f a function of type predicate→predicate Leibniz's Principle is accordingly expressed as

      [x ≡ y]  ⇒  [f.x ≡ f.y]   .

We now dissect this notation into

(i) the square brackets [ ], which denote a function of type predicate→{true, false}

(ii) the infix operator ≡ which is of type predicate²→predicate and is postulated to be associative and symmetric.

Parsing the relation [(x ≡ y) ≡ (y ≡ x)] that expresses the symmetry as [x ≡ ((y ≡ y) ≡ x)] and [(x ≡ (y ≡ y)) ≡ x], we see that y ≡ y is both left and right identity element of ≡ . Since for an infix operator that has a left identity element and a right identity element, these are equal and unique, we can name the unique identity element of ≡, say by TRUE:

      [x ≡ TRUE ≡ x]

This immediately leads to

   [x] ⇒ [x ≡ TRUE]

i.e. equation x:[x] has a unique solution which equals the identity element of ≡ (and hence, [x] is false for all other values of x).

Remark. It is usual to write TRUE in lower case. (End of Remark.)

The above has been written for David Gries.

Austin, 17 September 1995

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas as Austin
Austin, TX 78712-1188 USA

Transcribed by Guy Haworth.

Last revised Sun, 30 Dec 2007.

EWD1217

Comments on a Review of the Department

In the section "Endowed Chairs", the Review remarks "Indeed, the question of modifying the conditions of the professorships, e.g. size, citizenship requirements, etc., seems to focus attention on the problems of recruiting, rather than the opportunity." I fear that this remark fails to reflect how serious it is that we have endowed chairs for US citizens only. The requirement restricts us, as intended, in our choice, but it hurts us much more severely: by accepting such a constraint, UT has disqualified itself by the standards of the world of scholarship and science; if we are treated as outcasts and first-class scientists refuse to join us, we have only ourselves to blame.

The Review's conception of the rôle of the department is rather parochial (and the parish can get quite small).

It states that we should create "one of the strongest, balanced, computer science departments in the nation," but why not in the world?

Later it says: "First, since Texas companies pay taxes, this makes local industry part of the department's constituency. Understanding their problems and anticipating their future needs must surely impinge on curriculum development.". Sorry gentlemen, but there ain't no such thing as Cowboy Computing: if Texas companies have special problems that non-Texan companies don't have, these problems would have more to do with Texas than with computing science and fall outside our professional competence. We can — and should — zoom in on the foreseeable (technical and methodological) problems worldwide (and I think that that's what we are doing).

Finally, in the introduction and in the appendix, the Review seems to suggest that we get involved in all sorts of computer usage on campus (e.g. "the importance of the department's subject matter to the institution" and "Computer science should be at the heart of this development of [communication] technology, particularly the development of technology for educational delivery."). When, about 30 years ago, the University Computation Centers were split off from the Departments of Computer Science, this separation was a great improvement — you don't ask the Biology Department to be involved in campus landscaping either — but the Review seems to suggest to undo this improvement by re-involving the Department in all sorts of campus matters.

Aside I consider "knowledge transfer" a travesty of teaching. Teaching has much more to do with inspiring and with helping students to change their habits than with letting them absorb more knowledge or information. The term "educational delivery" was new for me and makes me wonder what view of education underlies the Review. (End of Aside.)

The Review describes in glowing terms the fruits to be harvested from close cooperation with local industry, but I fear that in this respect the Review is hopelessly optimistic. Universities are about quality and competence, industries are about earning money, a goal that is hardly related to the quality of the product: the two types of institutions diverge, and "industrial acceptance" is an irrelevant yardstick for the significance of scientific work.

When what society asks for coincides with what society needs and academia can provide it, the latter's position is easy. Today we have a conflict: society needs competence and asks for quackery (for instance in the form of Software Engineering). In a sad way, academia has the last word: it can provide both.

But — as I wrote in EWD920, 1985 — we have no choice: "[The university] has to refine and to teach to the best of its abilities how computing should be done; would it ever yield to the pressure to propagate the malpractice of today, it had better fold up.".

In these anti-intellectualistic days it is fashionable to accuse professors of neglecting their educational obligations. Accordingly, the Review recommends that our lecturers currently involved in undergraduate teaching be gradually replaced by "regular faculty" — presumably our premier teaching force — , a change that might require that regular faculty be tripled. But society being as fickle as it is, the pendulum will swing back, and long before that extra tenured faculty will have retired, spending your premier teaching force on The Great Unwashed will be considered a waste of its talents.

The Review assumes that the replacement of lecturers by regular faculty will improve the undergraduate curriculum and its teaching, but this assumption is unwarranted, to say the least. The recommendation in question is too ill-considered to be taken seriously.

The Review is obsessed with the Department's interaction with all sorts of entities in its environment, and that it was supposed to review a scientific enterprise is hardly visible. This is probably the reflection of the opinion of one of the authors that all fundamental problems of CS have been solved and that CS departments therefore should switch to applications. (It is an opinion I emphatically do not share.)

The Review ignores science to such an extent that it strikes me as a recipe for mediocrity. Consequently, I shall ignore the Review.

Austin, 28 September 1995
prof. dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Spenser Max Truex
revised 27-Jul-2020

EWD1219

"I have a proof that...."

This is about an observation of a type that I don't particularly like to make, but once the observation has been made, it had better be recorded. In the following, A and B stand for propositions for which I may have a proof.

Consider statements a0 and a1:

(a0) I have a proof that true (holds)
(a1) true (holds)   .

Then, a0 and a1 are equivalent. (Since —by definition— the proof that true (holds) is empty, it is impossible not to have it.)

Consider statements b0 and b1:

(b0) I have a proof that false (holds)
(b1) false (holds)   .

Then b0 and b1 are equivalent. (Since —by definition— the proof that false (holds) does not exist, it is impossible to have it.)

From the above we conclude by case analysis the equivalence of c0 and c1:

(c0) I have a proof that I have a proof that A (holds)
(c1) I have a proof that A (holds)   .

Consider statements d0 and d1:

(d0) I have a proof that A∧B (holds)
(d1) I have a proof that A (holds) and I have a proof that B (holds)   .

Then d0 and d1 are equivalent. (Well, that is what "∧" (="and") means.)

This last law can be generalized to universal quantification. Consider statements e0 and e1 (in which the range for n is implicitly understood):

(e0) I have a proof that, for all n, A.n (holds)
(e1) For all n, I have a proof that A.n (holds)   .

Then e0 and e1 are equivalent.

Remark: As a result it is semantically irrelevant that the sentence "I have a proof of A.n for all n" is syntactically ambiguous. (End of remark.)

Consider the statements f0 and f1:

(f0) If I have a proof that A (holds) then I have a proof that B (holds)
(f1) I have a proof that, if I have a proof that A holds, then B (holds)

Then f0 and f1 are equivalent. (If I don't have a proof that A (holds), f0 and f1 are both "vacuously" true; if I do have a proof that A (holds), both f0 and f1 reduce to "I have a proof that B (holds)".)

Remark: As a result it is semantically irrelevant that the sentence "I have a proof that B holds if I have a proof of A." is syntactically ambiguous. (End of remark.)

But consider now statements g0 and g1:

(g0) I have a proof that A ∨ B (holds)
(g1) I have a proof that A (holds) or I have a proof that B (holds) or I have both proofs.

In this case, the two statements are not equivalent: g1 implies g0, but it is in general not the other way round.

*          *
 *

Let us now do away with all the above verbosity and abbreviate "I have a proof that A (holds)" to "[A]". Our laws about having proofs can then be summa rized as follows:

(a) [true] ≡ true

(b) [false] ≡ false

(c) [[A]] ≡ [A]

(d) [A ∧ B] ≡ [A] ∧ [B]

(e) [〈∀n :: A.n〉] ≡ 〈∀n :: [A.n]〉

(f) [A] ⇒ [B] ≡ [[A] ⇒ B]

(g) [A ∨ B] ⇐ [A] ∨ [B]

The moral of the story is that "I have a proof that..." has all the algebraic properties of the "everywhere" operator, i.e. of universal quantification over a non-empty domain (see [DS90]).

[DS90] Dijkstra, Edsger W. and Scholten, Carel S., Predicate Calculus and Program Semantics, Springer-Verlag, New York, 1990.

Austin, 15 October 1995

Prof. Dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

Transcription by Mikhail Esteves.
Last revised on Thu, 27 Dec 2007.

EWD1220

Honors course "Mathematical Methodology", Spring 1996

Prerequisites:

•  a playful mind,

•  a mathematical inclination,

•  a good mastery of English, i.e. the ability to write it well, to read it well, to speak it well, and to understand it well.

This course is not about mathematical results but about doing mathematics, about wasting neither your own time, nor the time of your readers. Mathematics will be treated as the art and science of effective reasoning, the latter encompassing the design, recording and explanation of arguments.

The most common form of homework is to give one-page solutions to (well-chosen) problems; co-operation with a fellow student is encouraged, competition is frowned upon.

Each student ends the course with an oral examination of (at most) two hours. I can not accommodate much more than sixteen students in this class, but what they will have learned is immediately applicable and will never get obsolete.

Transcribed by Jennifer Lu Greene.
Last revised Thu, 27 Dec 2007.

EWD1224

Hm++, a new Professional Standard
(From the desk of the Chairman of the Board of Mathematics Inc.)

It was the French pilot/philosopher Antoine de Saint-Exupéry, who drew attention to a tragic aspect of the human predicament, viz. that we have to make today our plans for tomorrow with yesterday's words. For the Universities all through the Western World, the predicament is orders of magnitude worse, for they have to make today their plans for the next 50 years while still using a vocabulary that is more than half a century old, and in the mean time totally out of date. It is really pathetic! For instance, recruitment, appointment, promotion and recommendation of faculty is still carried out in terms of the elevated scientific and scholarly values of the late Enlightenment, in complete disregard of the academic explosion after WWII , which has turned the campus into an intellectual morass where, overwhelmingly, the mediocre teach the mediocre and where all forms of scientific originality and technical perfectionism are met by grave suspicion. (Professors of today, of course, don't know their de Saint-Exupéry, but much of the dishonesty in today's promotional process can be traced back to the linguistic dilemma he pointed out.)

Of all the Departments of the University, those of Mathematics are, all over the world, in the greatest difficulties, for while the other disciplines only evolved, Mathematics was just revolutionized: from an uncontrolled, unpredictable and ill-directed hobby of a bunch of admittedly in their own way sort-of brilliant, but otherwise irresponsible and unaccountable amateurs, Mathematics has been turned around into a reliable, well-controlled, goal-directed, predictable, and hence manageable industrial activity. This drastic change has taken place all over the civilized world, i.e. wherever Mathematics Inc., the world's leading manufacturer of mathematical products, has extended its market. Whereas now science & technology, research & development, and business & commerce all over the world can in principle benefit from the empowering force of our products, it pains us to see that in many places such organizations are denied the benefits of our products, only because of the inadequate and misleading training of the local mathematicians. How often have we not seen that a local mathematician, when faced with an industrial problem, would start thinking, just hoping that "by intuition" the solution would fall into his lap! In a well-run organization, focussed on its mission, it is obviously fatal to have in a crucial position such a dreamer as your employee.

A field study of our Department of Market Penetration has revealed what I had already suspected: the real culprits are the mathematical faculty members, who are teaching mathematics as if it is still 1900 and as if no Mathematics Inc. has created a totally new technological process! For two years we studied the recruitment, promotion and appointment process, and as a service to the educational mathematical community we can now offer a set of world-wide integrated professional standards, strict adherence to which is guaranteed to lead your Department with flying colours into the 21st Century. These standards are marketed under the name "Hm++" and bona fide educational institutions —I mean those that don't fire their teaching staff within 3 years— can get a 10% discount.

These internationally acclaimed standards for Professors of Mathematics, as they will be applied and maintained by Mathematics Inc., will make a great difference all over the world, and will rejuvenate the teaching of the Queen of Sciences. Of course, there have been standards —sort of, at least— in the past, but they hurt more than they helped. They were informal, unwritten, and on the whole unrealistically strict, and many Departments of Mathematics felt inferior, only because they suspected that they did not meet those standards, but with the new Hm++ standards, no institute will need to feel inferior any more: no more deviant "super-stars" in the departments of your competitors, and thanks to the reliable and perceptive control by Mathematics Inc.'s inspectors, no unplanned developments that could disturb the subtle balance of intellectual and social powers, which is so essential for the flourishing of well-managed and focussed development of mathematics.

Mathematics Inc. does not use the New Hm++ standards only for a greater homogeneity in the educational field, so that employers in the mathematical industry know better what to expect; we also use the opportunity to adapt the general educational mission so that we can present mathematics as "Rigour with a Human Face", a campaign to support the relaxation of the oppressively stringent requirements of yore.

This is a development that the Universities, contemplative, conservative and looking backwards as they are, have not seen yet, but with which we at Mathematics Inc., pioneering at the Frontier of Mathematical Innovation, are only too familiar. The traditional requirements are so constraining that they are hurting mathematical productivity: the set of remaining conclusions that can still be drawn in the old ways is dwindling rapidly, and before this was going to show up on our balance sheet, we had to do something about it, and, I am happy to add, we have been as successful as usual. Hesitating between Creative Logic and Experimental Logic, we implemented both, and have been fortunate to see a fruitful synergy emerging: Experimental Logic comes with the new results, for which Creative Logic then provides the embedding context. This is no minor matter! I would like you to know that in the estimation of our Office of Strategic Planning —and usually they are remarkably accurate!— this broadening of the vision of what mathematics can be will create room for another 150 to 200 years of mathematical growth! But with such a clear vision of the potential industrial and cultural future of Mankind, it would obviously have been totally irresponsible, had Mathematics Inc. left the Course of History to the uncontrolled forces of the market place, and that is why, in full accordance with its humanitarian calling, the necessary steps were taken by Mathematics Inc.. Semper floreat et crescat!

Hosanna Building
Plataanstraat 5
5671 AL  Nuenen
The Netherlands

1 December 1995
prof. dr. Edsger W. Dijkstra
Chairman of the Board of
Mathematics Inc.

transcribed by Martijn van der Veen
revised Thu, 27 Dec 2007

EWD1226

A simple geometrical theorem I did not know

Given:

        AE = α•AC
        ED = β•EB
        FD = γ•FC

Denoting with (PQR) the area of ΔPQR, we observe

(ADB) = γ•(ACB)                 and also

(ABD) = (1–β)•(AEB)
           = (1–β)•α•(ACB)

from which we conclude   γ = (1–β)•α     .

[ The theorem we used thrice—say (PQR)•RS/QR = (PRS)—is no more than adding metric to —see EWD1221b—

   R ≠ S ∧ col.R.S.Q ∧ tri.R.Q.P ⇒ tri.R.S.P ]

The theorem proved in this note is of no importance; it is recorded here because I don't remember this proof technique from my school-days.

Nuenen, 22 December 1995

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188

transcribed by Swarup Sahoo
last revised Sun, 26 Jun 2011

EWD1227

A somewhat open letter to David Gries

Dear David,

thank you for your letter d.d.15 December 1995 —postmarked in Elmira a week later— which arrived the other day here in Nuenen.  Yes, Rutger has shown me the discussion you and he have had;  I could just follow it but (for lack of competence) I shall not join it.  But I can react to the letter you wrote to me, and with your permission I shall do that here.

You wrote "Edsger, all I have been trying to do is to present the calculational system so that (0) students can learn it easily, and (1) logicians find it palatable, respectable, whatever.", a sentence as illuminating as it is honest.  It evokes two comments.

•     The Cornell students you are so used to are not an international standard.  Before my migration in 1984, I used to urge my European colleagues regularly not to confuse the intrinsic problems of Computing Science with the havoc created by the American educational system, and the same warning now seems appropriate for Mathematics.  I beg you to remember that what seems appropriate for you in your circumstances can be inappropriate for an equally devoted educator that operates in a different culture.

•     I never felt obliged to placate the logicians.  I (kindly!) assume that their customary precautions are needed and sufficient for reaching their goals.  If they can help and correct me by pointing out where my precautions have been insufficient and where my own discipline has led or will lead me astray, they are most welcome: I love to be corrected.  (Besides being a most instructive experience, being corrected shows that the other one cares about you.)  If however, they only get infuriated because I don't play my game according to their rules, I cannot resist the temptation to ignore their fury and to shrug my shoulders in the most polite manner.  (The other day I was shown —in Science of Computer Programming 23 (1994) 91-101—  a Book Review by Egon Börger; it was a nice example of that fury.)  I have come to the conclusion that there are such things as "disabling prejudices".

There is another sentence that evokes two comments, viz. "Well, I happen to think that Fred and I have a logic with four inference rules that explains your calculational system (without the everywhere operator)."

•     From the last restriction I conclude that the inclusion of the everywhere operator presents problems for your "logic" or for your method of "explanation".  If so, I am forced to conclude that what Fred and you have is not adequate for the task at hand.

•     I do not understand what you mean by "explaining" my calculational system; an algebra is not "explained", it is "postulated"!  One postulates a domain with a few operators and relations with certain properties, and usually there are a few existence axioms as well, and the result can be viewed as a calculational system.  But Peano's Axioms don't need further "explanation", do they?  Nor do the axioms that introduce (Boolean) lattices, do they?  And I may be very naive —if I am, I would like to keep it that way— but I never saw that the definition of an algebra also needed "inference rules".  Tony had inference rules in his Axiomatic Basis of 1969; when, four years later, predicate transformers enabled me to eliminate Tony's inference rules by subsuming them in the predicate calculus and junctivity properties, I felt that that was a great simplification.  Somehow, you seem to have been induced to undo that simplification.

*            * 
*

You seem to doubt Rutger's statement "...when it comes to being short, simple, illuminating, and convincing, algebraic proofs and logical deductions are simply not in the same league."  Since I started on this note, I visited the ETAC session of Tuesday 2 January 1996, where we started the study of Burghard v. Karger's draft "Temporal Logic via Galois Connections", in which he promises to show "that all seventeen axioms of the sound and complete proof system of temporal logic given in Manna and Pnueli's book [11] can be derived from just two postulates, namely (i) (⊕, ̃⊖) is a Galois connection, and (ii) (⊖,⊕) is a perfect Galois connection" and later —section 2.11— he remarks explicitly "Another advantage of algebra over logic is the ease with which one can define new algebras from old, for example by forming direct products and function spaces."  I quote von Karger to show that Rutger is not alone in his judgement.  There is a new, bright generation emerging, and as long as they calculate as effectively as they are doing now, you won't convince them.

*            * 
*

You write that I have been turned off by the logicians.  That observation is correct, and I can give you a number of reasons why they turned me off.

•     Notational conventions of Whitehead and Russell —for many logicians a bible— are absolutely horrendous.  I do not blame them so much for the fact that they had not the foggiest notion of how to define their "dot notation", for BNF only came more than half a century later.  It is the dot notation itself I object to since it makes the operation of substitution a pain in the neck.  Here, Whitehead and Russell reveal themselves as complete amateurs; I don't blame them —on the contrary, for I have a weakness for amateurs— but I do blame the logicians that followed and thought this acceptable.

•     The majority of logical texts, including modern ones, that I have seen treat formulae as strings of symbols and accordingly treat formula manipulation as string manipulation.  I consider that a lack of separation of concerns.  The only thing that matters is the parsed formula —the "tree", if you wish— , all meaningful manipulations are always in terms of syntactical units, so are all meaningful definitions (like scope of dummies or the definition of the free variables of an expression), and are independent of the specific conventions that may be chosen for a linear coding of such trees.  Again, I don't blame the logicians that struggled their struggle before the notion of a formal syntax became available, but I do blame the logicians that came later and thought this failure to abstract from the specifics of the linear syntax acceptable.

•     I get completely confused as soon as logicians drag "models" and "interpretations" into the picture.  I thought that the whole purpose of the creation of a formal system in which one can calculate was to create something independent of any model or interpretation.  Doing mathematics is one thing, applying one's mathematics to a more or less real world out there is an extra-mathematical activity, and never, I think, should the two be confused.  Again, most of the logical literature I have seen and the criticism of logicians on what I (and others) are doing strikes me as a lack of separation of concerns.  As a matter of fact, the still often repeated requirement that axioms should be "self-evident" strikes me as a medieval relic; to the extent that they take philosophy seriously it is impossible for me to take the logicians seriously.  (Again this may be a cultural difference: it seems there are societies in which philosophers still have some intellectual standing.)

I never formulated it explicitly, but I could very well have the feeling that the average citizen of the logical community is not brilliant enough to make that community really interesting.

prof.dr.Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA
Nuenen, 1995.12.31 - Austin, 1996.01.11

Transcription by Andy Fugard.

Last revised on Mon, 10 Dec 2007.

EWD 1228

Sylvester’s theorem used (see EWD1016)

On Tuesday 2 January 1996, Ronald W. Bulterman told me the following theorem.

Consider, for n ≥ 2, n distinct points in the plane; let k be the number of all distinct lines such that each of them contains at least 2 of those points. Then   k = 1 ∨ k ≥ n   .

*         *         *

Proof   The proof is by mathematical induction on n. There are two reasons for trying this proof structure, firstly the shape of the disjunct k ≥ n in the demonstrandum and secondly the fact that (Euclid’s Axiom)   n = 2 ⇒ k = 1   immediately establishes the base.

With   nʹ = n +1, we consider for the induction step nʹ distinct points, giving rise to kʹ  lines. We have to show   kʹ = 1 ∨ kʹ ≥ nʹ, where we may use k = 1 ∨ k ≥ n “ex hypothese”. In view of our demonstrandum being a disjunction, we introduce a case analysis, viz. kʹ =1 versus kʹ ≠1.

kʹ = 1

In this case, the demonstrandum   kʹ = 1 ∨ kʹ ≥ nʹ   follows directly (i.e. by predicate calculus alone).

kʹ ≠ 1

In this case, the demonstrandum   kʹ = 1 ∨ kʹ ≥ nʹ   simplifies directly to kʹ ≥ nʹ. The remainder of the proof is devoted to showing how, for nʹ noncollinear points, kʹ ≥ n follows from the induction hypothesis.

In order to be able to appeal to the induction hypothesis, we single out one of the nʹ points —let us call that point “A”— and consider the remaining n points and the k lines they give rise to all by themselves. Ex hypothese we may use k = 1 ∨ k ≥ n; we exploit the two disjuncts separately.

In the case k = 1, the n (distinct) points lie on a single line, and, because the nʹ points are noncollinear, that line does not contain A. Hence kʹ = n + 1, and since nʹ = n + 1, kʹ ≥ nʹ has been established.

In the remaining case k ≥ n —or, since nʹ = n + 1, equivalently k + 1 ≥ nʹ — , our demonstrandum kʹ ≥ nʹ follows from kʹ ≥ k + 1 or, equivalently, kʹ  > k. How do we establish kʹ  > k? Or, in other words, how can we conclude that the removal of A reduces the number of lines? Well, since a line has to go through at least 2 points of the set, such a line disappears if A is one of the only 2 points it goes through. Hence we can assert kʹ  > k by a proper choice of A provided:

“For any number of distinct, noncollinear points in the plane, there exists a line through exactly 2 of them.”

But this was Sylvester’s conjecture, which since then became a theorem, so we are done.

(End of Proof.)

Austin, 13 January 1996

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Corrado Cantelmi
revised 18-Mar-2012

EWD 1229

Nondeterministic construction of an arbitrary witness.

A series of problems that is well-known in educational circles starts with the following one: “Does the 8-by-8 square admit a tiling with 32 dominoes of 2-by-1?”. The answer is “Yes”, the existence of such a tiling is traditionally demonstrated by displaying what is called “a witness”, i.e. a way of tiling the square with the dominoes. The most common witness is:

The argument that it is possible to tile the square is utterly convincing, and traditionally one immediately moves to the next problem in the series.

But, short and convincing as the above argument may be, it has what can be viewed as a shortcoming: it is grossly overspecific! The 8-by-8 square can be tiled in thousands and thousands of ways and there is no way of justifying the specific choice made above. This consideration raises the following question: can we design a program that (i) provably constructs a tiling of the square, and (ii) is so nondeterministic, that any tiling may be constructed?

*         *         *

In order to reduce the number of ways in which our program may generate a specific tiling, we rank the dominoes of a tiling with natural numbers such that for any pair of neighbours the southern or the western one has the lower rank, for instance for a 4-by-4 square

(Note that the tiling need not determine the ranking uniquely: in the above example, ranks 3 and 4 could have been interchanged, and so could ranks 4 and 5.)

Our program will “place” the dominoes of the tiling it generates in the order of increasing rank, but in order to be sure that it can generate any tiling, we have to convince ourselves of

Lemma 0   Each tiling admits a ranking of its dominoes.

Proof   Consider the path from the SE corner to the NW corner with precisely the dominoes with rank < n to its left. In the above example we show the cases n=0, n=4, and n=8:

It suffices to show that for any specific tiling we can assign the ranks in increasing order. Consider now the paths with n equal to the number of dominoes ranked. Note that all these paths have the same length: by the definition of ranking, the “vertical” segments are traversed towards the North, the horizontal ones from East to West.

Assigning the next rank, including the increase of n by 1 and the adjustment of the path, is by ranking a “horizontal” or “vertical” domino:

horizontal:    | [picture] | becomes    | [picture]
vertical: | [picture] | becomes | [picture]

Such a move is possible provided there exists an unranked domino with its West side and its South side entirely along the path. We have to show the existence of such a domino when not all dominoes have been ranked.

When not all dominoes have been ranked, the path contains at least 1 right turn:  

These turns come in two flavours, depending on the orientation of the adjacent unranked domino:

H-turn:    | [picture] | V-turn:    | [picture]

If on the path from the SE corner to the NW corner, the first right turn is an H-turn, the adjacent horizontal domino can be ranked; if the last right turn is a V-turn, the adjacent vertical domino can be ranked. If neither is the case, the path contains a V-turn followed by an H-turn:

or further apart, always at least one of the adjacent dominoes can be ranked. (End of Proof.)

The proof of Lemma 0 was the hard part because I needed —at least: used— all those pictures; now comes the simple part, surprisingly simple even. Thanks to Lemma 0, and in terms of the concepts introduced in its proof, our task is now to design a program that transforms, in any possible way, but without backtracking, in 32 instances of the ranking step the path for n=0 into the path corresponding to n=32.

I propose to characterize the shape of the path by listing in succession, for instance in the order from the NW corner to the SE corner the direction of the 16 edges along the path with s (for south) and e (for east). The initial path is
        s s s s s s s s e e e e e e e e ,
the final path is
        e e e e e e e e s s s s s s s s .

The two ranking steps operate —see the bottom of EWD1229-2— on three successive elements of this sequence:

horizontal:    | .... s e e ....     | becomes:    | .... e e s ....
vertical | .... s s e ....     | becomes: | .... e s s ....

But these two steps are both of the form

        .... s ? e ....     becomes     .... e ? s ....      !

Any pair that is one apart and “out of order” may be interchanged. We see an arbitrary interleaving of two copies —one applied to the elements in the even positions and one applied to the elements in the odd positions— of the nondeterministic algorithm that transforms sssseeee into eeeessss by 16 steps of neighbours, each replacing ...se... by ...es... . Our program terminates without backtracking in 32 swaps.

Austin, 21 January 1996

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 26-Dec-2011

EWD 1231

The arithmetic and geometric means once more

In the following,  x, y, c  are positive.

In EWD1140, I used

(0)         (x+y)� = (x−y)� + 4 � x � y

to argue that

(1)         x,y = c, x+y−c       ,

which does not change x+y, increases x � y provided c lies between the initial values of x and y.

In EWD1171, I used (0) to argue that

(2)         x,y := c, x � y/c       ,

which does not change x � y, decreases x+y provided c lies between the initial values of x and y.

In both cases the use of (0) came a little bit as a rabbit and the link between the condition on c and the decrease of the distance between x and y remained informal. Last Thursday, when I asked for an expression that contained both x+y and x � y, my [student] An Thai Nguyen suggested that we look at (c−x)�(c−y), and this expression indeed plays a central role in the derivations from which all rabbits have been removed.

*         *         *

We want to change x,y such that (i) their sum is not changed, and (ii) their product is increased. Any assignment satisfying (i) can be written like (1); in order to satisfy (ii) we now observe for any c

        “(1) increases x � y”
=         {program semantics, (1)}
        x � y < c �(x+y−c)
=         {algebra}
        (c−x)�(c−y) < 0      .

We now consider the change of x,y such that (iii) their product is not changed, and (iv) their sum is decreased. Any assignment satisfying (iii) can be written like (2); in order to satisfy (iv) as well, we observe for any positive c

        “(2) increases x+y”
=         {program semantics, (2)}
        c + x � y/c < x+y
=         { c > 0 }
        c� + x � y < c �(x+y)
=         { algebra }
        (c−x)�(c−y) < 0      .

So, in both cases, the completely forced calculations lead in exactly the same form to the conclusion that c should lie between the initial values of x and y. The secret is that Nguyen’s expression can be rewritten as

        x � y − c �(x+y−c)

and as

        (c� + x � y) − (c � x + c � y)       ,

i.e. the difference of two products with equal sums of their factors, and the difference of two sums with equal products of their addenda. I was surprised.

Austin, 10 February 1996

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

transcribed by Corrado Cantelmi
revised 26-Dec-2011

EWD1232

My simplest theorem

Theorem Any natural number that has a divisor greater than itself equals zero.

Proof We observe for any natural n, d, q

n = d∙q  ∧  d > n

=        { Leibniz }

n = d∙q  ∧  d > d∙q

=        { d > 0 }

n = d∙q  ∧  1 > q

=        { q is natural }

n = d∙q  ∧  q = 0

⇒        { Leibniz }

n = 0

( End of Proof )

At least twice —EWD1088 & EWD1170— I had used that 0 is the only natural number with infinitely many divisors —e.g. 2k for any k— but I never took the trouble to prove it, and that probably explains why I missed the above.

Austin, 10 February 1996

prof. dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Tristam Brelstaff
modified Mon, 10 Dec 2007.

EWD1235

Een scheve schaats

In [0], een Liber Amicorum uitgegeven ter gelegenheid van de pensionering van collega Kruseman Aretz, kunnen wij op p. 159 de volgende historische schets lezen:

"In Eindhoven is van het begin van de jaren 60 tot medio (de) jaren 80 een monocultuur gegroeid onder leiding van Dijkstra. Deze monocultuur duiden wij vaak aan als de Eindhovense programmeerstijl of de Eindhovense school. In een monocultuur passen geen andere gewassen en deze worden door de kwekers van de monocultuur al snel onkruid genoemd. Velen die iets ander wilden kweken zijn in die tijd gesneuveld, maar jij niet."

* |  | *
| * |

Het is moeilijk hier anders dan beschuldigingen van ongezonde eenzijdigheid en verstikkende intolerantie in te lezen.

Het verwijt van eenzijdigheid bevreemdt aangezien Dijkstra (reeds in 1984) professioneel een breder terrein bestreek dan de meesten onzer, en het roept dan ook de vraag op of de Auteur wellicht niet verder heeft gekeken dan zijn neus lang is. Het is natuurlijk waar dat Dijkstra zich niet op alle deelgebieden van de informatica actief bewogen heeft —wij denken bv. aan bestandsbeheer, "trace" theorie en de studie van vertalerbouw—, maar fatsoenshalve dienen we er rekening mee te houden de deze abstinentie zijnerzijds een bewust gekozen werkverdeling tussen hem en zijn collegae weerspiegelt.

Het verwijt, even ongestaafd als ongefundeerd, van de dodelijke intolerantie verbaast nog meer: aangezien het een volslagen mysterie is wie deze "velen" die zouden zijn "gesneuveld" dan wel zijn geweest, kunnen wij niet anders dan concluderen dat de Auteur deze slachtoffers uit zijn duim heeft gezogen. Natuurlijk heeft Dijkstra, gelijk elke vakman, geoordeeld en gewogen, want dit is wat de maatschappij (terecht) van haar experts verlangt; misschien heeft de Auteur nagelaten zich te realiseren dat een oordeel dat in naam van tolerantie altijd alles goedkeurt, geen informatie geeft en dus niks voorstelt. (Een andere verklaring is dat de Auteur zich nauwelijks bewust is geweest van de insinuerende nonsens die hij opschreef.)

Het geciteerde stuk is zover beneden peil dat we de Auteur met een gerust geweten kunnen afschrijven als een rancuneus stuk snot. Moeilijker te verteren —want verontrustender— is dat dit schendschrift heeft kunnen verschijnen in een officiële uitgave van de Technische Universiteit Eindhoven. Gelukkig is met vooruitziende blik de colofon afgesloten met:

"Hoewel dit boek met zeer veel zorg is samengesteld, aanvaarden schrijver(s) noch uitgever enige aansprakelijkheid voor schade ontstaan door eventuele fouten en/of onvolkomenheden in dit boek."

[0]  E.H.L. Aarts et. al. (Ed.) Simplex Sigillum Veri, Een Liber Amicorum voor prof. dr. F.E.J. Kruseman Aretz, TU Eindhoven, 1995
ISBN 90-386-0197-2

Austin, 14 maart 1996

Prof. dr. Edsger W. Dijkstra,
Department of Computer Sciences,
The University of Texas at Austin,
Austin, TX 78712-1188
USA

Transcription by Patrick Tingen.

Last revised on Fri, 12 Dec 2008.

EWD1237

Elegance and effective reasoning  (Fall 1996)

Here, the noun "elegance" should be understood in the sense of the second meaning of "elegant", as given in the Concise Oxford Dictionary (6th Edition, 1976): "ingeniously simple and effective".

The practical significance of elegance has been contested, but that is only a social phenomenon caused by the fact that elegance requires great care to be achieved and education to be appreciated. In contrast we shall stress that in sophisticated designs, elegance is not a dispensable luxury, but a factor that often decides between success and failure.

The course has at least four goals:

•  to identify the salient features of elegance

•  to understand how these features make elegance so effective

•  to learn how to design elegant solutions wherever they are feasible

•  to learn how to form a considered opinion as to which problems are better ignored than solved

5 May 1996         

prof.dr. Edsger W. Dijkstra
The Dept. of Computer Sciences, UT Austin
Austin, TX 78712-1188. USA

Transcribed by Jennifer Lu Greene.
Last revised Mon, 10 Dec 2007.

EWD1238

Foreword

So-called "natural language" is a wonderful for the purposes it was created for, such as to be rude in, to tell jokes in, to cheat or to make love in (and Theorists of Literary Criticism can even be content-free in it), but it is hopelessly inadequate when we have to deal unambiguously with situations of great intricacy, situations which unavoidably arise in such activities as legislation, arbitration, mathematics or programming. To this perplexing dilemma we can observe three main reactions.

The first reaction is to stick to those activities where unrefined natural language (kind of) suffices (vide the educationalist telling the future social worker to include in her reports no sentences of more than 17 words).

The second reaction is to bend the natural language to one's special purpose, as we can observe in the practice of government, but the resulting language is only superficaially "natural", for it is in fact so unnatural that even the educated layman needs a lawyers or tax consultant to decipher it.

The third reaction is the most drastic one: a completely new language is designed, geared to its purpose and without any pretence to being "natural", as we can see in formal mathematics and programming.

The last approach is, of course, the one with the greatest potential: unfettered by compatibility requirements, freed from the shackles of our native tongues, the new formalism can be designed to facilitate the major manipulations, and can thus become a highly effective, powerful and reliable tool, but experience has shown that it cannot avoid becoming controversial as well. All its technical merits fail to address the social problem that the smooth mastery that enables one to use a calculus with confidence and advantage is not reached without an intellectual investment of exercise and training for which most people are just too lazy: it is much simpler to declare that the formalism is no good and that learning how to use its calculus is not worth the trouble. The majority of people —even in mathematics and computing!— prefer the comfort of a fuzzy language in which cruel precision is impossible.

In this field of tension, on the crossroads of incompatible tendencies, "Teaching and Learning Formal Methods" is a valuable anthology. Most of its authors are seasoned scientists with considerable educational experience. In some of the essays one can read between the lines the sad combination (which is only to be expected) of high expectation of the technology and low expectation of the student body's willingness to turn the dream into reality. The book as a whole contains a wealth of technical or educational material that convinces me that in this area my academic colleagues are doing exactly what they should do: developing and propagating an indispensible technology so that it will be available when "the world out there" undeniably needs it.

Austin, 12 May 1996 | Edsger W. Dijkstra

Transcribed by Jennifer Lu Greene.
Last revised Mon, 10 Dec 2007.

EWD 1239

A first exploration of effective reasoning

My youngest Concise Oxford Dictionary (7th edition, 1982) defines (pure) mathematics as “abstract science of space, number, and quantity”. A long time ago, this definition may have been adequate, but for at least a century this definition is much too restrictive: there are simply too many people considered mathematicians —by themselves, by their colleagues, and by others— whose professional minds are hardly occupied with space, number, or quantity. The topics today’s mathematicians think about are, in fact, so varied that it is no longer realistic to characterize mathematics by its subject matter.

Yet, despite this variation of topics, the mathematician very quickly recognizes his fellow mathematician as such: there is a unity that is not reflected in the diversity of the topics. The unity that constitutes the core of mathematics is not so much the “quod” as the “quo modo”; it is the precision of the concepts, the shape of the arguments and the nature of the use of symbols and language that are characteristic for mathematics. And that is why today a much better definition of mathematics would be “the art and science of effective reasoning”, independent of what that reasoning is supposed to be about.

But in order to reason effectively, the very least we should be able to do is establishing whether two statements mean the same thing or whether two definitions are equivalent, and here we immediately run into trouble with our so-called “natural languages”, which (among other shortcomings) are not very well suited to precision. By human habit, our languages tend to become geared to the major purposes we want to use them for, and consequently they are excellent for being vague in, for telling jokes in, and for making love in; precision, however, is only rarely needed, and as soon as we try to be precise, as for instance in legal documents, the language used quickly becomes most unnatural.

Ambiguity is for instance caused by the unclarity as to how sentence components should be grouped together, the standard example being “pretty little girls school”, which admits five different parsing. (Does “pretty” qualify “little”, “girls”, or “school”? And is it about a little school or about little girls?)

A slightly more subtle example is provided by the two sentences:

“When Jack and Jill went up the hill, they picked 5 pounds of blueberries”
“When Jack and Jill went up the hill, they walked 5 miles”.

I think that the first sentence permits the interpretation that Jack picked 2 pounds and Jill 3, but I am almost certain that the second sentence does not admit the analogous interpretation that Jack walked 2 miles and Jill 3.

Another source of difficulties, which I won’t pursue here now, is that people sometimes don’t distinguish between
        “If the sun shines, I don’t wear my coat.”
and
        “If I don’t wear my coat, the sun shines.”

The above examples of linguistic problems should suffice at this stage; their only purpose was to convince the reader that for truly effective reasoning, natural language is an inadequate vehicle, and I hope they have done so. The moral of the story is that the development of mathematics is partly —and perhaps for a major part!— a linguistic exercise, viz. the design of languages adequate for definitions of and arguments about the artefact we would like to deal with.

A familiar example is provided by the names and notations for numbers as used in counting and arithmetic. Like the rest of natural languages, the names of numbers are originally not the product of careful design: the French name “quatre-vingt-dix” for 90 —in which the first hyphen stands for a multiplication and the second one for an addition— is one of the worst offenders I know, and I can only applaud the later introduction of the simplifications “septante”, “octante” and “nonante”. The English names became more systematic when “four-and-twenty” —remember the blackbirds of the nursery song?— was replaced by “twenty-four”.

Naming is one aspect, manipulation (in this case: calculation) is another case. Though I can read the individual numbers, I have problems reading a sentence like “three hundred and twenty-eight plus one hundred twenty-three equals four hundred and fifty-one”.

Roman numerals, whose general adoption prevented the rise of European science for 15 centuries, are all right for engraving on a building the year of its completion, but “CCCXXVIII + CXXIII = CDLI” is at least as bad as the natural language version. In Roman numerals, the rules for calculation are just too complicated (and if you don’t believe that, just try multiplication and long division in Roman numerals).

The great breakthrough came with the invention of the positional number systems. The sentence “328 + 123 = 451” we can read and check because —particularly in the case of more digits— we can write the numbers on two successive lines:

3 2 8

1 2 3

–––––– |   +

4 5 1

Manipulation is immensely simplified by the possibility of such a column-wise arrangement and the fact that the rules of digit-wise addition don’t change while going from right to left. By an accident of history, I am also perfectly happy with the binary system

1010 01000
11 11011
–––––––––– |   +
1110 00011 |  |             ,

in which the rules for manipulation are even much simpler. (The binary addition table contains only 2� = 4 entries:

0+0 = 00         0+1 = 01         1+0 = 01         1+1 = 10     ;

the decimal addition table contains 10� = 100 entries, from 0+0 through 9+9, and as most designers of automatic computers quickly discovered, a factor of 25 is not something to be ignored.)

Another “language” most of us are familiar with is the one of the pictures we use in plane geometry, triangles, parallel lines and what have you. At first sight, that pictorial language seems completely adequate, for plane geometry is about things like triangles and parallel lines, isn’t it? But at closer inspection there are serious problems.

Tale the following example. In connection with the theorem “In an equilateral triangle, the medians coincide with the altitudes”, one could very well encounter the following picture

but we could equally well have had

        or                 ,

i.e. there is the almost always tacit convention that the orientation and size of the picture don’t matter. It is a little bit of a nuisance that we have to draw the picture in some size and in some orientation, and that in that sense our pictorial language forces us to be a little bit overspecific, but logical problems can be avoided by making the convention explicit that chosen size and orientation are “arbitrary”, are not to be considered “essential features” of the pictures.

So far, so good, but it is not good enough! Because an equilateral triangle is in 3 different ways isosceles, the above theorem is a rather direct consequence of the theorem “In an isosceles triangle, the median from the top coincides with the altitude from the top.” It is fully correct that this theorem says nothing about the top angle being 60� because the theorem holds for any top angle. Your geometry text will probably contain the picture

but could have contained the rather different

as well. Here is the problem: there is no picture of the general isosceles triangle in the sense that we cannot avoid choosing the top acute, right, or obtuse.

In the same sense there is no representative picture of the general triangle and the following example illustrates the damage that may do. There exists the theorem that the 3 angle-bisectors of a triangle are copunctual (i.e. go through a single point), e.g.

        .

Using the above theorem, it has been shown that the altitudes are copunctual:

        .

by showing that the altitudes of a triangle ABC —i.e. AD, BE, and CF— are the angle-bisectors of a triangle DEF (and hence copunctual). The argument, however, breaks down when triangle ABC has an obtuse angle; in that case the altitudes —though still copunctual— are not the angle-bisectors of triangle DEF (at least not in the traditional sense), and a separate argument is required. (Fortunately, the case distinction forced upon us by the pictorial argument can be avoided by the use of vector calculus, which allows a one-line argument which is independent of the absence or presence of an obtuse in triangle ABC. It relies upon the algebraic identity

a � (b−c) + b · (c−a) + c · (a−b) = 0      .)

The main problem with the role of pictures in traditional plane geometry is that each theorem is applicable to an infinite set of figures of great variation, whereas we can only display on or two of them by way of example, leaving to the reader the conceptualization of the general case.

Above, we have given two first examples —one numerical, one geometrical— showing how ease and efficiency of reasoning depend on the “language” used. Later, when we have a clearer picture of the arguments we would like to render, we can and will be more explicit about language characteristics that ease or hamper reasoning. We now turn in this introductory chapter to another aspect of effective reasoning, viz. the subject matter to which the reasoning is applied.

Effective reasoning requires great precision and that explains why I won’t deal with, say, arguments about the nature of the influence of the early singing of folk tunes on the patriotic feelings of mostly rural girls: the concepts involved would be several orders of magnitude too vague to do something rigorous with. Mathematicians prefer to deal with “simple” concepts such as numbers and triangles, rather than with messy “real-world” concepts such as patriotic feelings. This preference is not a matter of cowardice or laziness; on the contrary, and the layman should respect this self-constraint as the mathematician’s analogue of the professional discipline that prevents the competent architect from erecting a high-rise building on quicksand.

The following two examples serve to illustrate that even in such “simple” contexts, our concepts should be chosen with care; again we shall give a numerical and a geometrical example.

We all know the numbers that we use in counting: 1, 2, 3, 4, .... At the right-hand side —the conceptually difficult one!— there is no difference of opinion: the sequence of what the mathematicians call “the natural numbers” goes on without end, amen. The problem is at the other end: where should it start? Should the sequence start at zero: 0, 1, 2, 3, 4, ...., or should it start at two: 2, 3, 4, 5 .... ? For the classical Greeks, for instance, “two” was the smallest number; “one” existed, but was not considered a number.

Remark   We are not that much different from the classical Greeks, for the sentence “Among my well-established colleagues, a number are of a different opinion.” strongly suggests more than one dissenter! Please note that “number” (nous, singular) is followed by “are” (verb, plural). (End of Remark.)

As the term “multiplication” still faithfully reflects, 1 could not occur as a factor of a product —“it would not multiply”—, nor could it be a divisor —“it would not divide, would it?”—. But the Greek exclusion of 1 from the natural numbers created problems for them.

For us, any pair of positive natural numbers has a greatest common divisor, e.g. for the pair (21, 33), the greatest common divisor is 3, for the pair (21, 34) it is 1.

Remark   “greatest common divisor” is both name and definition. The divisors of 21 are {1, 3, 7, 21}, the divisors of 33 are {1, 3, 11, 33}, their common divisors are {1, 3}, of which 3 is the greatest. (End of Remark.)

There is an efficient algorithm that determines for any pair of natural numbers their greatest common divisor (efficient in the sense that it does not require the, in general, much more laborious factorization of the two numbers). The Greeks knew it: the algorithm is, in fact, known as “Euclid’s Algorithm”. Euclid even proves the correctness of this algorithm, but has to give two different proofs, one for the case that —such as with (21, 33)— the given numbers do have at least one common divisor, and a different proof that deals with the case —such as with (21, 34)— that in Greek parlance the numbers have no common divisor. Admission of 1 as divisor completely obviates the proof duplication.

Aside   Definitions of concepts and formulations of theorems act in the modern parlance of the computing scientist as the interfaces between the modules of the argument. Computer scientists had to burn their figures a number of times before they finally understood the critical importance of well-chosen interfaces, and Euclid’s work clearly predates that experience. (End of Aside.)

Let us now turn to a geometrical example. Consider the following figure:

      .

It contains 4 triangles, 3 smaller ones that make up the big one, more precisely, the sum of the areas of the 3 small ones equals the area of the big one. Denoting with △ the area, we have

△PBC + △APC + △ABP = △ABC       .

Remark   Please note that this is a very nice formula: it has such a nice structure that we can remember it. The three terms on the left are obtained by replacing in the right-hand term △ABC in turn A, B, and C with P. (End of Remark.)

We run, however, in trouble when P does not lie inside triangle ABC. Consider for instance the figure

      ,

where we would have

△PBC + △APC − △ABP = △ABC       ,

or the figure

in which case we would have

△PBC − △APC − △ABP = △ABC       .

The beautiful symmetry of our original formula has been destroyed in the latter ones by the occurrence of one or two minus signs at the left-hand side. Can we repair this? Yes, we can. To begin with, we let the triangle’s name define a direction of traversal of the triangle’s sides, to be precise, for △XYZ this will be from X to Y, from Y to Z, and from Z to X:

△XYZ:      

and similarly, naming the same triangle differently

△ZYX:             .

Studying our three formulae and the corresponding figures, we see that in the triangles as named, the triangles with a minus sign in front of them are the ones whose perimeters are traversed counterclockwise (or “widdershins”, if you prefer). And this observation suggests the remedy: we introduce a new concept, called the “signed area”, and denoted by ◬, which is the usual area in the case of clockwise traversal, but is the negative area if the traversal is anti-clockwise.

Remark   Whether the traversal is clockwise, is undefined in the case of the degenerate triangle, i.e. a “triangle” with its vertices on a straight line, but in that case its area equals zero and its sign is irrelevant. Also, please note that the theorems

◬XYZ = − | ◬ZYX
◬XYZ = | ◬YZX

hold independently of the sign of ◬XYZ, i.e.,

for both                 and               .

A picture may be worth a thousand words, a formula is worth a thousand pictures. (End of Remark.)

In terms of the signed area, all three formulae are now expressed by

◬PBC + ◬APC + ◬ABP = ◬ABC       .

The user of the concept of the signed area has to pay a price of not listing after ◬ the vertices in arbitrary order, but the concept is so much cleaner than the traditional area, that he should pay this price gladly. The traditional, unsigned area has the absolute value built in, and it is a clumsy concept because the absolute value is such an ugly function. The traditional unsigned area forces us to deal with different cases that should not have been distinguished in the first place.

The above two examples of how an unfortunate choice of concepts can complicate the reasoning should suffice at this stage, as we now pay some attention to a last aspect of effective reasoning, viz. the structure of the argument.

The purpose of the argument is always to draw a conclusion, but we wish to do so in the most trustworthy manner conceivable and we wish to present the reasoning that led us to the conclusion as convincing as possible. Mankind knows of only one way to reach those goals: constructing the argument as a finite sequence of small, explicit steps from a modest repertoire.

It has to be a finite sequence so that the reader can check them the one after the other. The steps have to be small and explicit so that they can be checked without guesswork. Finally the repertoire of permissible steps has to be modest, firstly because it must be humanly possible to have it in our fingertips, and, secondly, because we have to accept all the steps in the repertoire as trustworthy.

Remark   It is the finite repertoire of permissible steps that defines the class of valid arguments, that defines what a “proof” is. If the repertoire is empty, we can argue nothing, hence are automatically protected from the mortal sin of concluding nonsense. The larger the repertoire, the weaker the corresponding notion of “proof”, and by the time the repertoire admits any step, we can conclude nonsense in a single step —we can prove anything in a single step!— and the notion of proof has become void. (End of Remark.)

Let me give here an informal illustration of a main reasoning step, known as “substituting equals for equals”. Suppose that we are invited to conclude

(i)         a fortnight is longer than a week.

Well, we certainly cannot do that if we don’t have the foggiest notion of what fortnights and weeks are —coming from another country, we could have a very limited English vocabulary—, i.e. something about fortnights and weeks has to be given. Let these givens be

(ii)         a fortnight is fourteen days

(iii)        a week is seven days       .

Thanks to (ii) and (iii) we can eliminate the technical/mysterious/unknown terms/concepts “fortnight” and “week” from our demonstrandum (i), which, thanks to (ii) and (iii) is equivalent to

(iv)         fourteen days is longer than seven days       .

We won’t pursue this example: if (iv) is an axiom, we are done. The point was to show that (ii) and (iii) yield the equivalence of (i) and (iv).

Please notice that these manipulations have very little to do with the truth of the statements manipulated. I mean, (ii) and (iii) can be used as above, to yield the equivalence of (v) and (vi) with

(v)         a week is longer than a fortnight

(vi)        seven days is longer than fourteen days

or to yield the equivalence of (vii) and (viii) with

(vii)         a fortnight is cheaper than a week

(viii)        fourteen days is cheaper than seven days.

It does not matter that (i) and (iv) seem right, that (v) and (vi) seem wrong, and (vii) and (viii) seem neither: in the context of the established equivalences, “is longer than” and “is cheaper than” are unanalysed relations, and what they seem is totally irrelevant.

As we continue our explorations, the distinction between “calculating” and “concluding” will get more and more blurred. This is to be expected; asked about the product of 17 and 323, we can “calculate” that that product is 5491, we can also “conclude” that that product is 5491: we cannot do the one without the other. We shall not hesitate to refer to the transformation of

a�(b+c)

into

a�b + a�c

as “calculations”, we shall not hesitate to regard decimal numbers such as 17, 323 and 5491 as “formulae”, thus including calculation in the more general notion of “formula manipulation”. This was largely a remark about terminology, our next remark, with which we close this chapter, will be regarded by some as more fundamental.

The final remark is that the reasoning we are discussing deals with validity, not with truth. We may build up a theory about pyrodions, which we can do provided pyrodions have been defined in a useful manner. In order to be able to reason about pyrodions, earlier generations would say that we would need to know how to interpret statements about pyrodions, but we —as will become clear in subsequent chapters— just need to know the properties of pyrodions, i.e. no more and no less than how we may manipulate formulae containing elements that denote pyrodions.

For the purpose of our reasoning, the pyrodions are what our postulates define them to be, and it is about those that we can design a, let us hope beautiful, Theory of Pyrodions. And now someone familiar with our Theory encounters things very similar to what he always thought pyrodions looked like, and he would like to apply our Theory to them. If so, it is his responsibility to establish that his things enjoy all the characteristic properties that have been postulated for our pyrodions. Another way of saying that our reasoning does not justify its own application, an observation that can create wonder that for any beautiful theory there seem to be Pyrodions all over the place.

Nuenen, 18 July 1996

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Corrado Cantelmi
revised 26-Dec-2011

EWD1243

The next fifty years

When the idea to write about the next fifty years of computing first entered my head, I wrote it off as utterly preposterous: which sane scientist purports to be able to see so far into the future? But then I realized that in a way that is precisely what educators do all the time: when designing our courses, we do dare to decide what to teach and what to ignore, and we do this for the benefit of people, many of whom will still be active forty to fifty years from now. Clearly some vision of the next half century of computing science is operational. To this I should add that it is all right if the crystal ball is too foggy to show much detail. Thirty-five years ago, for instance, I had no inkling of how closely program design and proof design would come together, and in such a detailed sense my life had been full of surprises. At the same time these surprises were developments I had been waiting for, because I knew that programming had to be turned into an endeavour amenable to some sort of mathematical treatment, long before I knew what kind of mathematics that would turn out to be. In other words, when building sand castles on the beach, we can ignore the waves but should watch the tide.

*      *      *

Fortunately, there are a few things that we can learn from the past, for instance that the rate at which society can absorb progress is strictly limited, a circumstance that makes long-range prediction a lot easier. Earlier this decade I was told of a great invention called "the register window"; my spokesman was very young, but in my ears the invention sounded very familiar because I remembered the Burroughs B5000 of 30 years before. So, if you have a bright and sound idea now, you can expect it to be hailed as a novelty around the year 2025.

Another thing we can learn from the past is the failure of characterizations like "Computing Science is really nothing but X" where for X you may substitute your favourite discipline, such as: numerical analysis, electrical engineering, automata theory, queuing theory, lambda calculus, discrete mathematics or proof theory. I mention this because of the current trend to equate computing science with constructive type theory or with category theory.

Computing's core challenge is how not to make a mess of it. If people object that any science has to meet that challenge, we should give a double rebuttal. Firstly, machines are so fast and storage capacities are so huge that we face orders of magnitude more room for confusion, the propagation and diffusion of which are easily inadvertently mechanized. Secondly, because we are dealing with artefacts, all unmastered complexity is of our own making; there is no one else to blame and so we had better learn how not to introduce the complexity in the first place.

The history of the real-time interrupt is in this connection illuminating. It was invented for the purpose of facilitating processor sharing; its effect was the introduction of nondeterminism and endless headaches for many an operating systems designer. We have seen two reactions to it. For the purpose of debugging IBM built special-purpose monitors that exactly recorded when the central processor honoured which interrupt; when something had gone wrong, the monitor could be turned into a controller, thus forcing a replay of the suspect history and making the "experiment" repeatable. The other reaction was to determine the conditions under which one could feasibly and safely reason about nondeterministic programs, and subsequently see to it that those conditions were met by both hardware and software. OS/360 was a mess forever after; the THE Multiprogramming System, in contrast, was so robust, that no system malfunctioning ever gave rise to a spurious call for hardware maintenance. Needless to say, the whole episode has made a lasting impression on me.

One moral is that the real-time interrupt was only the wave, whereas the tide was the introduction of nondeterminism and of system invariants as a means of coping with it. A wider moral is the constructive approach to the problem of program correctness, to which we can now add the problem of system performance as well. It is only too easy to design resource-sharing systems with such intertwined allocation strategies that no amount of applied queuing theory will prevent most unpleasant performance surprises from emerging. The designer that counts performance predictability among his responsibilities tends to come up with designs that need no queuing theory at all. A last, and this time fairly recent, example is the design of delay-insensitive circuitry, which delegates all timing difficulties in clocked systems to the class of problems better avoided than solved. The moral is clear: prevention is better than cure, in particular if the illness is unmastered complexity, for which no cure exists.

The above examples point to a very general opportunity, in broad terms to be described as designs such that both the final product and the design process reflect a theory that suffices to prevent a combinatorial explosion of complexity from creeping in. There are many reasons to suppose that this opportunity will stay with us for a very long time, and that is great for the future of computing science because, all through history, simplifications have had a much greater long-range scientific impact than individual feats of ingenuity.

The opportunity for simplification is very encouraging because, in all examples that come to mind, the design process cost much less labour and led to a much better final product than its intuitively conceived alternatives. The world being what it is, I also expect this opportunity to stay with us for decades to come. Firstly, simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated. Secondly we observe massive investments in efforts that are heading in the opposite direction. I am thinking about so-called design-aids such as circuit simulators, protocol verifiers, algorithm animators, graphical aids for the hardware designer, and elaborate systems for version control: by their suggestion of power, they rather invite than discourage complexity. You cannot expect the hordes of people that have devoted a major part of their professional lives to such efforts to react kindly to the suggestion that most of these efforts have been misguided, and we can hardly expect a more sympathetic ear from the granting agencies that have funded these efforts: too many people have been involved and we know from past experience that what has been sufficiently expensive is automatically declared to have been a great success. Thirdly, the vision that automatic computing should not be such a mess is obscured, over and over again, by the advent of a monstrum that is subsequently forced upon the computing community as a de facto standard (COBOL, FORTRAN, ADA, software for desktop publishing, you name it).

In short, the opportunity to simplify will remain with us for many years, and I propose, in order to maintain our sanity and enthusiasm, that we welcome the long duration of that opportunity, rather than to suffer from impatience each time the practitioners deride and discard our next successful pilot project as a toy problem: they will do so, even if you have achieved what, shortly before, they had confidently predicted to be impossible.

*      *      *

By now we all know that programming is as hard or as easy as proving, and that if programming a procedure corresponds to proving a theorem, designing a digital system corresponds to building a mathematical theory. The tasks are isomorphic. We also know that, while from an operational point of view a program can be nothing but an abstract symbol manipulator, the designer of a program had better regard the program as a sophisticated formula. And we also know that there is only one trust-worthy way for the design of sophisticated formulae, viz. derivation by means of symbol manipulation. We have to let the symbols do the work, for that is the only known technique that scales up. Computing and Computing Science unavoidably emerge as an exercise in formal mathematics or, if you wish an acronym, as an exercise in VLSAL (= Very Large Scale Application of Logic).

Because of the very close connection between program design and proof design, any advance in program design has a direct potential impact on how general mathematics is done. Since the time computing scientists have built compilers, they are very used to the idea of mechanical manipulation of uninterpreted formulae, and I am sure that they will significantly contribute to a further realization of Leibniz's Dream of presenting calculation, i.e. the manipulation of uninterpreted formulae, as an alternative to human reasoning. The challenge of turning that Dream into reality, however, will certainly keep us busy for at least five decades.

It is not only that the design of an appropriate formal, notational, and conceptual practice is a formidable challenge that still has to be met; it is worse because current traditions are hardly helpful. For instance, we know that the transition from verbal reasoning to formal manipulation can be appreciated as narrowing the bandwidth of communication and documentation, whereas in the name of "ease of use" a lot of effort of the computing community is aimed at widening that bandwidth. Also, we know that we can only use a system by virtue of our knowledge of its properties, and, similarly, pay the greatest possible care to the choice of concepts in terms of which we build up our theories: we know we have to keep it crisp, disentangled, and simple if we refuse to be crushed by the complexities of our own making. But, obviously, the market pulls in the opposite direction. I still remember finding a book on how to use "Wordperfect 5.0" of more than 850 pages, in fact a dozen pages more than my 1951 edition of Geord Joos, "Theoretical Physics"! It is time to unmask the computing community as a Secret Society of the Creation and Preservation of Artificial Complexity. And then we have the software engineers, who only mention formal methods in order to throw suspicion on them. In short, we should not expect too much support for the computing community at large. And from the mathematical community I have learned not to expect too much support either, as informality is the hallmark of the Mathematical Guild, whose members —like poor programmers— derive their intellectual excitement from not quite knowing what they are doing and prefer to be thrilled by the marvel of the human mind (in particular their own ones). For them, the Dream of Leibniz is a Nightmare. In summary, we are on our own.

But that does not matter. In the next fifty years, Mathematics will emerge as The Art and Science of Effective Formal Reasoning, and we shall derive our intellectual excitement from learning How to Let the Symbols Do the Work.

Calculemus!

Edsger W. Dijkstra

(Note. The above is an adapted version of EWD1051.)

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin,
Austin, TX 78712-1188
USA

transcribed by Martijn van der Veen
revised Mon, 10 Dec 2007

EWD1243a

The next fifty years

When the idea to write about the next fifty years of computing first entered my head, I wrote it off as utterly preposterous: what sane scientist purports to be able to see so far into the future? But then I realized that in a way that is precisely what educators do all the time: when designing our courses, we do dare to decide what to teach and what to ignore, and we do this for the benefit of students, many of whom will still be active forty to fifty years from now. Clearly some vision of the next half century of computing science is operational. To this I should add that it is all right if the crystal ball is too foggy to show much detail. Thirty-five years ago, for instance, I had no inkling of how closely program design and proof design would come together, and in such a detailed sense my life has been full of surprises. At the same time these surprises were developments I had been waiting for, because I knew that programming had to be made amenable to some sort of mathematical treatment long before I knew what type of mathematics that would turn out to be. In other words, when building sand castles on the beach, we can ignore the waves but should watch the tide.

*        *        *

Fortunately, there are a few things that we can learn from the past, for instance that the rate at which society can absorb progress is strictly limited, a circumstance that makes long-range predictions a lot easier. Earlier this decade I was told of a great invention called "the register window"; my informant was very young, but in my ears the invention sounded very familiar because I remembered the Burroughs B5000 of 30 years before. So, if you have a bright and sound idea now, you can expect it to be hailed as a novelty around the year 2025.

Another thing we can learn from the past is the failure of characterizations like "Computing Science is really nothing but X", where for X you may substitute your favourite discipline, such as numerical analysis, electrical engineering, automata theory, queuing theory, lambda calculus, discrete mathematics or proof theory. I mention this because of the current trend to equate computing science with constructive type theory or with category theory.

Computing's core challenge is how not to make a mess of it. If people object that any science has to meet that challenge, we should give a double rebuttal. Firstly, machines are so fast and storage capacities are so huge that we face orders of magnitude more room for confusion, the propagation and diffusion of which are easily inadvertently mechanized. Secondly, because we are dealing with artefacts, all unmastered complexity is of our own making; there is no one else to blame and so we had better learn how not to introduce the complexity in the first place.

In this connection the history of the real-time interrupt is illuminating. This was an invention from the second half of the 50s, which enabled the completion of a communication with the external world to interrupt the execution of one program in favour of another. Its advantage was that it enabled the implementation of rapid reaction to changed external circumstances without paying the price of a lot of processor time lost in unproductive waiting. The disadvantage was that the operating system had to ensure correct execution of the various computations despite the unpredictability of the moments at which the interrupts would take place and the central processor would be switched from one computation to another; the nondeterminism implied by this unpredictability has caused endless headaches for those operating system designers that did not know how to cope with it. We have seen two reactions to the challenge of this added complexity.

The one reaction was to enhance the debugging facilities, as IBM did for the design of OS/360. (This was the operating system IBM tried to design for its 360-Series of machines, which were introduced in the first half of the 60s; IBM's problems with this design facilitated in 1968 the recognition of the world-wide phenomenon that became known as "the software crisis".) IBM built, in fact, special-purpose monitors that exactly recorded when the central processor honoured which interrupt; when something had gone wrong, the monitor could be turned into a controller, thus forcing a replay of the suspect history and making the "experiment" repeatable.

The other reaction could be observed at the THE (Technological University Eindhoven), viz. to determine the conditions under which one could feasibly and safely reason about such nondeterministic programs and subsequently to see to it that these conditions were met by hardware and software. The difference was striking, showing once more that debugging is no alternative for intellectual control. While OS/360 remained a mess forever after, the Multiprogramming System designed at the THE was so robust that no system malfunction ever gave rise to a spurious call for hardware maintenance. Needless to say, the whole episode has made a lasting impression on me.

One moral is that the real-time interrupt was only the wave, whereas the tide was the introduction of nondeterminism and the development of the mathematical techniques to cope with it. A wider moral is the constructive approach to the problem of program correctness, to which we can now add the problem of system performance as well. It is only too easy to design resource-sharing systems with such intertwined allocation strategies that no amount of applied queuing theory will prevent most unpleasant performance surprises from emerging. The designer who counts performance predictability among his responsibilities tends to come up with designs that need no queuing theory at all. A last, and this time fairly recent, example is the design of delay-insensitive circuitry, which delegates all timing difficulties in clocked systems to the class of problems better avoided than solved. The moral is clear: prevention is better than cure, in particular if the illness is unmastered complexity, for which no cure exists.

The above examples point to a very general opportunity, in broad terms to be described as designs such that both the final product and the design process reflect a theory that suffices to prevent a combinatorial explosion of complexity from creeping in. There are many reasons to suppose that this opportunity will stay with us for a very long time, and that is great for the future of computing science because, all through history, simplifications have had a much greater long-range scientific impact than individual feats of ingenuity.

The opportunity for simplification is very encouraging, because in all examples that come to mind the simple and elegant systems tend to be easier and faster to design and get right, more efficient in execution and much more reliable than the more contrived contraptions that have to be debugged into some degree of acceptability. (One of the reasons why the expression "software industry" can be so misleading is that a major analogy with manufacturing fails to hold: in software, it is often the poor quality of the "product" that make it so expensive to make! In programming, nothing is cheaper than not introducing the bugs in the first place.) The world being what it is, I also expect this opportunity to stay with us for decades to come. Firstly, simplicity and elegance are unpopular because they require hard work and discipline to achieve and education to be appreciated. Secondly we observe massive investments in efforts that are heading in the opposite direction. I am thinking about so-called design aids such as circuit simulators, protocol verifiers, algorithm animators, graphical aids for the hardware designers, and elaborate systems for version control: by their suggestion of power, they rather invite than discourage complexity. You cannot expect the hordes of people that have devoted a major part of their professional lives to such efforts to react kindly to the suggestion that most of these efforts have been misguided, and we can hardly expect a more sympathetic ear from the granting agencies that have funded these efforts: too many people have been involved and we know from past experience that what has been sufficiently expensive is automatically declared to have been a great success. Thirdly, the vision that automatic computing should not be such a mess is obscured, over and over again, by the advent of a monstrum that is subsequently forced upon the computing community as a de facto standard (COBOL, FORTRAN, ADA, C++, software for desktop publishing, you name it).

In short, the opportunity to simplify will remain with us for many years, and I propose, in order to maintain our sanity and our enthusiasm, that we welcome the long duration of that opportunity, rather than to suffer from impatience each time the practitioners deride and discard our next successful pilot project as a toy problem: they will do so, even if you have achieved what, shortly before, they had confidently predicted to be impossible.

*        *        *

By now we all know that programming is as hard or as easy as proving, and that if programming a procedure corresponds to proving a theorem, designing a digital system corresponds to building a mathematical theory. The tasks are isomorphic. We also know that, while from an operational point of view a program can be nothing but an abstract symbol manipulator, the designer had better regard the program as a sophisticated formula. And we also know that there is only one trustworthy way for the design of sophisticated formulae, viz. derivation by means of symbol manipulation. We have to let the symbols do the work, for that is the only known technique that scales up. Computing and Computing Science unavoidably emerge as an exercise in formal mathematics or, if you wish an acronym, as exercise in VLSAL (Very Large Scale Application of Logic).

Because of the very close connection between program design and proof design, any advance in program design has a direct potential impact on how general mathematics is done. Since the time computing scientists have built compilers, they are very used to the idea of mechanical manipulation of uninterpreted formulae, and I am sure that they will significantly contribute to a further realization of Leibniz's Dream of presenting calculations, i.e. the manipulation of uninterpreted formulae, as an alternative to human reasoning. The challenge of turning that Dream into reality, however, will certainly keep us busy for at least five decades.

It is not only that the design of an appropriate formal, notational and conceptual practice is a formidable challenge that still has to be met; the challenge is worse because current traditions are hardly helpful. For instance, we know that the transition from verbal reasoning to formal manipulation can be appreciated as narrowing the bandwidth of communication and documentation, whereas in the name of "ease of use" a lot of effort on the computing community is aimed at widening that bandwidth. Also, we know that we can only use a system by virtue of our knowledge of its properties, and, similarly, pay the greatest possible care to the choice of concepts in terms of which we build up our theories: we know we have to keep it crisp, disentangled, and simple if we refuse to be crushed by the complexities of our own making. But complexity sells better and the market pulls in the opposite direction. I still remember finding a book on how to use "Wordperfect 5.0" of more than 850 pages, in fact a dozen pages more than my 1951 edition of Georg Joos, "Theoretical Physics"! It is time to unmask the computing community as a Secret Society for the Creation and Preservation of Artificial Complexity. And then we have the software engineers, who only mention formal methods in order to throw suspicion on them. In short, we should not expect too much support from the computing community at large. And from the mathematical community I have learned not to expect too much support either, as informality is the hallmark of the Mathematical Guild, whose members —like poor programmers— derive their intellectual excitement from not quite knowing what they are doing and prefer to be thrilled by the marvel of the human mind (in particular their own ones). For them, the Dream of Leibniz is a Nightmare. In summary, we are on our own.

But that does not matter. In the next fifty years, Mathematics will emerge as The Art and Science of Effective Formal Reasoning, and we shall derive our intellectual excitement from learning How to Let the Symbols Do the Work.

Calculemus!

Edsger W.Dijkstra

prof.dr Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Javier Smaldone.
Revised Mon, 10 Dec 2007.

EWD1245

A kind of converse of Leibniz’s Principle
by
Edsger W. Dijkstra

    We owe to Gottfried W. Leibniz the principle that is informally known as "substituting equals for equals" and is formally expressed by

                    x = y ⇒ f.x = f.y   ,

which we can also read as "function application is equality-preserving".  This note proves the

Theorem Besides the two constant relations, equality is the only relation preserved by function application.

    In this note, function application is denoted by an infix dot (period); for the sake of simplicity we restrict ourselves to "endofunctions", i.e. functions for which argument and function value are of the same type, which is also the type of the variables (a, b, c, d, x, y) and the type on which the binary relations are defined.  Boolean negation will be denoted by ¬ , boolean equality by ≡ , which is given the lowest syntactic binding power ; the dot of function application has the highest binding power.

    For the rest of the note, R denotes – in the usual infix notation – a binary relation

• that differs from the constant relation T, given by 〈∀ x,y :: x T y〉, and

• that differs from the constant relation F, given by 〈∀ x,y :: ¬(x F y)〉, and

• that differs from equality.

    To prove our theorem we have to show that, in general, R is not preserved by function application, i.e. that there exist an a,b and f such that

                    a R b and ¬(f.a R f.b)    .

    We take care of the existential quantification over f by using the lemma – not proved here –

                    〈∃ f :: f.a = c ∧ f.b = d〉  ≡   a = b  ⇒  c = d    ,

which allows us to rewrite our proof obligation as follows:

    Show the existence of a quadruple a, b, c, d such that

(i)   a R b
(ii)  ¬(c R d)
(iii) a = b  ⇒  c = d

We now show this existence by constructing a witness.

    That R differs from equality enables us to postulate (for the rest of this note) for some x,y

                    x R y ≢ x = y

and now we distinguish two cases.

Case 0:    x R y ∧ x ≠ y
    Choosing a,b := x,y ensures that (i) and (iii) are satisfied; because R differs from T, c,d can be chosen so as to satisfy (ii).  (End of Case 0)

Case 1:    ¬(x R y) ∧ x = y
    Choosing c,d := x,y ensures that (ii) and (iii) are satisfied; because R differs from F, a,b can be chosen so as to satisfy (i).   (End of Case 1)

    Since the case analysis was exhaustive, our proof obligation has been discharged.

Remark    The unproved lemma can be demonstrated by mutual implication.  The one direction – left ⇒ right – follows directly from Leibniz's Principle; the other direction – the one needed in this note – requires case analysis, say a=b versus a≠b.   (End of Remark.)

                        Austin, 17 September 1996

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Hasnain Mujtaba revised 19-Jul-2019

EWD1248

Homework #1         (See EWD996)

Show that, for any finite set of grid points in the plane, we can colour each of the points either red or blue such that on each grid line the number of red points differs by at most 1 from the number of blue points.

*             *
*

A snake is a non-empty sequence or cycle of distinct grid points to be coloured such that

(i) adjacent points in the snake can be connected by a grid line such that along the snake horizontal and vertical connections alternate, and

(ii) a sequential snake is maximal in the sense that neither endpoint can be further connected.

We observe that, if there are points to be coloured, a snake can be formed: start with a point and extend in both directions the snake as long as possible; when no new points can be added to the snake, it is made into a cycle, if that is possible.

Through each endpoint of a sequential snake passes a grid line containing an odd number of “snake points”; on account of (ii), these lines contain no further points to be coloured. All other grid lines contain their snake points partitioned into pairs of “snake neighbours”.

Since on account of (i) each cycle contains an even number of points, we can colour the points along a snake alternately red and blue, and we do so, thereby only creating differences of 1 on grid lines with no uncoloured points left.

The algorithm that produces a colouring with the required properties consists of repeatedly —i.e., as long as not all points of the given set have been coloured— creating a snake and then colouring it. The invariants of this algorithm are

(iii) on a grid line that contains an uncoloured point the number of red points equals the number of blue ones

(iv) on no grid line the number of red points differs by more than 1 from the number of blue ones.

Note The above argument has a bit more structure than the one in EWD996, which did not contain the concept of a snake. EWD996, however, was free from rabbits. (End of note.)

Austin, 9 October 1996
(Written manu sinistra with a
Parker roller ball, Fine.)

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Mario Béland
revised Mon, 10 Dec 2007

EWD1250

The couples, the river, and the little boat

Here is the problem:

"Two husbands and two wives have to cross a river in a boat which can only hold two people. How can they cross so that no woman is in the company of a man unless her husband is also present?"

(Copyright (c) 1967 by Morris Kline)

[It is understood that the absence/presence constraint refers to the separate banks as well as to the boat.]

*                   *
*

Request If you think this problem too trivial to waste your time on, please state instantaneously the number of different solutions. Thank you. ( End of Request.)

We can name the four people by considering the couples (H,W) and (h,w); we can then enumerate the disallowed combinations:

wH    wHW    Wh    Whw

(which is shorter than enumarating the allowed ones) and explore the tree of all possible scenarios, an extensive search.

There are two ways of reducing the size of the search tree, viz.

(i)  restoring the symmetry between the couples, a symmetry which has been destroyed by naming them differently, and

(ii)  strenghtening the constraints — which, if done unwisely, may reduce the number of solutions to zero.

Ignoring the distictions between the two couples, i.e. ignoring the distinction betweer upper and lower case in our enumeration of disallowed combinations, there is little else we can do but count the numbers of wives and husbands. We propose the stronger constraint:

the husbands stay together.

(i.e. in each combination, the number of husbands is even). But as soon as the husbands stay together, we don't need to distinguish between them —they could be truly identical twins— , nor between the wives: the pairing, as was represented by the couples, has disappeared from the picture, and after this abstraction there is only one solution left:

two wives go ;
one wife returns ;
two husbands go ;
one wife returns ;
two wives go ,

and since the two wives are as indistinguishable from each other other as the electrons in the helium atom, this is truly 1 solution. (Remember: the instruction "take away one from three" yields "two", and it makes no sense, when instructed to take away one from three, to ask "which one?".)

Aside Wim Feijen solved the above problem in exactly the same way "during a short nap on the coach". (End of Aside.)

            Austin, 13 November 1996

prof. dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188 USA

Transcribed by Gijs Geleijnse
Revised Mon, 10 Dec 2007.

EWD1251

Two problems derived from Hugo Steinhaus

Given 4 points in the Euclidean plane such that their 6 mutual distances are all distinct. (Note that this implies that the 4 points are distinct.) We connect by a drawn line segment any pair of points of which one is the nearest neighbour of the other. Show that no drawn segments intersect each other.

If the points are not the vertices of a convex quadrangle:

the 6 connecting segments don't intersect at all, so no matter which connections are drawn, the theorem holds.

If the points are the vertices of a convex quadrangle, e.g.

the only intersecting pair is formed by the diagonals, and it therefore suffices to show that at least one of the diagonals is dotted, i.e. that at neither of its ends it is the shortest connection.

I have seen several arguments, including a wrong one by myself, in terms of lengths alone; in one way or another they all used the triangular inequality. Not so the argument by Lyn Pierce, which was the shortest of them all.

A diagonal is an edge in two triangles, and it is dotted if it is the longest side of one of those triangles. It is so if, in that triangle, it is opposite to the largest angle. Because the 3 angles of a triangle add up to 180° (and are positive), an angle ≥90° is the triangle's largest. Because the 4 angles of a quadrangle add up to 360°, at least one of them is ≥90°, and hence at least one of the diagonals is dotted, viz. the one "opposite" to a largest angle of the quadrangle. A very nice, constructive existence proof! I was pleased to see "maximum ≥ average" used in a setting different from the pigeon hole principle. Steinhaus, needless to say, gave a proof by contradiction.

*                 *
*

We consider the various (viz. n! to be precise) ways in which one can nail a wire exactly once on each of n posts, put at equal distance along a straight road.

When one wishes to minimize the length of the piece of wire used, one starts at one end, and nails the wire on the posts in order, e.g. (n = 5, and each x standing for a nail)

.

But what if we want to maximize the length of wire? For n = 3, the solution is obviously (apart from reflection)

and for n = 4 (after a moment's thought)

,

but how is it for general n?

The crucial observation is that in a maximal arrangement, at no post the situation

occurs: the wire could have been lengthened by removal of the above nail and connecting the above post to one of the posts where the wire currently ends. This observation leads to the

Lemma 0. At each nail, the wire ends or reverses direction.

In other words — in pictures, to be precise — nails only occur in the following 4 positions

.

We now mark the zones before, between, and after the posts with their "intensities", i.e. the number of

wires passing through each zone. This terminology (with Lemma 0 and the fact that the wire has 2 ends) allows us to formulate

Lemma 1. At two posts, the intensity changes by 1, at all other posts it changes by 2.

The length of the wire equals the sum of the intensities. We maximize this sum when, going in from the outside (where the intensities are 0), we increase the intensities each time by the maximum amount 2 until near the center we accommodate the two changes = 1.

For even n (odd number of zones), the sequence of intensities is unique, e.g. for n = 6 : 0 2 4 5 4 2 0 .

For odd n (even number of zones) there are two solutions which are each other's mirror image, e.g. for n = 7

0 2 4 6 5 4 2 0 and
0 2 4 5 6 4 2 0 .

The sequence of intensities does in general constrain but not determine the shape of the wire: in terms of the wire, the solution is in general far from unique. The above problem is closely related to "The problem of the difficult dartboard" (see EWD1045, dd 27 February 1989).

The problems come from Hugo Steinhaus, "One Hundred Problems in Elementary Mathematics". Dover Publications Inc, New York, 1979

Austin, 25 November 1996

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Spenser Max Truex
revised 27-Jul-2020

EWD1252

Convocation Speech, December 8, 1996

Ladies and Gentlemen,

to begin with I would like to thank the College of Natural Sciences for the most honouring invitation to address its newest flock of Bachelors on this most festive day. I shall do my best.

Your past is your inalienable property, you cannot deny it, and, for better or for worse, it will shape the rest of your lives until death follows. In a sentimental moment, you may long for the lost innocence and bliss of ignorance, but that ignorance is lost forever: you are now Bachelors and you will have to carry the burden of your college education every waking hour of the rest of your lives, nay, even in your sleep you will be pressed to have dreams full of responsibility. A main purpose of this commencement speech is therefore to help you to live with your academic past: I'll try to give you some advice on how to remember your university.

It is not only persons that are shaped by their pasts, so are institutions, so are whole peoples. I am Dutch, and for the Dutch, a formative experience has been how they liberated themselves several centuries ago from the Spanish occupation. (To give you an example: their national anthem dates from those days.) Since that war dragged on for 80 years, you might feel that the Dutch were not very efficient at liberating themselves, but they succeeded with the tools of the time.

In 1574, the Spanish tried to conquer one of our cities, but they could not because the town was defended too well; so they laid siege to it, trying to starve its population, an effort in which they partly succeeded. But water is our foe & friend, and on the 3rd of October 1574 some other Dutchmen caused a flood by the simple device of cutting a few dikes, and the Spanish soldiers that surrounded the city were just washed away.

Because the lifting of that siege was a turning point in our struggle for freedom, William the Silent wanted to reward the city's population for its bravery and endurance, and gave them the choice between two prizes: either a full year freedom from tax paying, or the right to a University, and the citizens chose the latter. Within a year, in 1575, the University of Leyden, my Alma Mater, was started in a former nunnery, a building that, thanks to the Reformation, was on the market anyhow.

I told you this story because it so neatly symbolizes the tight link between the concept of a University and the practice of intellectual freedom. In the dozen years that I am now here, I have learnt to appreciate UT as a place where that link is in full vigour, and my first remark to you, both as advice and as request, is to remember and cherish your university as a place dedicated to the practice of intellectual freedom, where the combination of exercising your brain and opening your mouth is encouraged.

A next characteristic of the University for which it should be cherished and protected is its openness. Let me explain that by referring briefly to the University's place along the whole spectrum of techniques by which one generation transmits its insights and abilities to the next.

At the one extreme we have the techniques of the guilds which treat their insights and abilities as valuable property, as a treasure to be kept secret. Their technique for protecting the secrecy is by keeping the secret knowledge unformulated; therefore, the apprentice has to join a master for seven meagre years, during which he can absorb the craft by osmosis, so to speak.

The university is at the other end of the spectrum: it is the professor's task to bring the relevant insights and abilities into the public domain by explicit formulation. It is no accident that the universities as we know them now, started to flourish after the art of book printing had been established.

There is more to be said about that spectrum of educational techniques, but I shall not do so now: I mentioned it to remind you why the absence of secrecy, or, more positively formulated, openness and honesty are characteristics that touch the heart of the academic enterprise: a university that hides or cheats can close its doors.

I beg you to remember the essential role of academic openness when considering academic/industrial cooperation, I urge you to remember it whenever a government invents so-called reasons of national security or prosperity for the prevention of free publication of the results of academic research. Universities are not part of the nation's security organisation, they are not the nation's research laboratories either: they are the nation's Universities.

In passing I would like to mention that for a completely different reason such openness is a precondition for academic survival. Just for being different and doing things the uneducated cannot understand, the academics are hated and feared, vide Socrates, executed in 399 B.C., Archimedes, killed in 212 B.C., and, more recently, Hypatia, A.D. 415 barbarously murdered by a Christian mob in Alexandria. The original Oxford Colleges were buildings fortified in order to protect the students against the rabble, and if you think that all that is old hat, I refer you to the recent histories of the DDR or the People's Republic of China. These days, it is a miracle whenever the academic world is tolerated at all, and personally I am convinced that what tolerance there is would completely disappear, were the academic world to become secretive.

The University with its intellectual life on campus is undoubtedly a creation of the restless mind, but it is more than its creation: it is also its refuge. The University is unique in that on campus, being brilliant is socially acceptable. Furthermore the fabric of the academic world is so sturdy that it can absorb the most revolutionary ideas.

But it is not only a refuge for the restless minds, it is also a reservation for them. It does not only protect the restless minds, it also protects the rest of the world, where they would create havoc if they were let loose. To put it in another way, the fence around campus is essential because it separates two worlds that otherwise would harm each other. The fence ensures that we have relatively little direct influence on the world "out there", but we would be foolish to complain, for our freedom to be as radical as we like is based on the fact that, for at least the first 25 years, industry and the world-at-large ignore our work anyhow. Currently, there seems to be a world-wide tendency to try to lower the fence; the effort strikes me as ill-directed.

As a very minor, but recent example: you may have heard of efforts, with the catchword "post-tenure review", to change the contract between the university and its faculty. We do not discuss the merits of the case, but I would like you to see it as a symptom of the lowered fence, for one of the underlying feelings is that on campus hiring & firing should be possible like everywhere else, thus ignoring that a university should be as unlike anything else as you can think of.

I think that all students should remember the University as a very special place, but the graduates of the College of Natural Sciences should do so most of all, because it is in thát School that the hard sciences have found a roof above their heads. It puts a heavy responsibility on those who have gone through that school, for the others have no idea of what is going on there, and hence naturally assume that all science is as ephemeral, as transitory and as fashion-dependent as the rest.

It is in this respect not reassuring that so many legislatures and other governing bodies hardly contain any true scientists. Consequently, strange things can happen.

After WW II, the Dutch industries felt the need of a Dutch business school. Because of its purely vocational calling, but more so because of the perceived lack of intellectual content, none of the existing Dutch universities wanted to have anything to do with it, and a separate business school was founded. So far, so good, but a number of decades later, the need was felt to raise the institute's status, and the Dutch government, which did not know or did not care what it was doing, agreed to raise that business school officially to the level of a university.

And in the Austin American-Statesman of November 8, we could read how that newfangled "Nijenrode University" used its academic status: it bestowed an Honorary Doctorate on Bill Gates, of all scholars, and I haven't figured out yet how, as a Dutchman, I am going to atone for that.

Fortunately, encouraging things sometimes happen as well, as we could read in a front page article in the International Herald Tribune of November 27, which reported that Oxford University had just turned down a gift of $34 million because of the strings attached: the gift was intended for a new business school, but Oxford did not want a new business school. Universities can be Very Special Places indeed.

By the way, if you got the impression that I have my doubts about business management as scientific discipline, you are right: it seems too fickle to be taken seriously. In the 70s, the creed was diversification, in the 80s, the gospel said to concentrate on your core business, and in the 90s the world-wide credo seems to be the intellectual cleansing of the high-tech industries.

There seems to be one thing that, independently of the height of the fence that surrounds the campus, any graduating student can take with him into the world outside, and that is the healthy scepticism that goes with a well-kept immunity for hype, for slogans, for fads and for fashions. And that is important, for the latter seem to pass by in ever increasing frequency.

It is quite amazing —and a bit saddening— how the gullible and desperate are willing to expect salvation from the next gadget.

I remember how TV was promoted by the theory that a daily dose of Shakespeare in every living room would elevate the culturally deprived to unfathomed heights, thus curing all ills of society, etc.. And what did we get? Soap operas and quizzes.

I remember how the overhead projector was welcomed as the greatest educational innovation since Socrates, as it allowed a much more detailed preparation, and how the new "audio-visual aids", as they were called in those days, would revolutionize the class room and would bring modern teaching to each little eskimo in his igloo. Well, of what the overhead projector did to teaching, you are, I'm afraid, a better judge than I.

I remember how, with the advent of terminals, interactive debugging was supposed to solve all our programming problems, and how, with the advent of colour screens, "algorithm animation" was supposed to do the same. And what did we get? Commercial software with a disclaimer that explicitly states that you are a fool if you rely on what you just bought.

And now we have the multimedia/communication hype: the best bits are those that just arrived from far away, and if you are not "on line", "on the Net", you just don't count, you are not of this world (which is virtual anyhow...). Apart from a change in vocabulary, it is the same hype, the same snake oil over and over again, and you can do me a favour by not getting excited by all the time you are supposed to save by switching to "home banking".

Recently, James H. Billington, the current Librarian of Congress, remarked that instead of a knowledge-based democracy, we may end up with an information-inundated democracy. I share his concern, so allow me to end with this simple wish.

May, in spite of all distractions
generated by technology, all of
you succeed in turning
information into knowledge,
knowledge into understanding,
and understanding into wisdom.

I thank you for your attention.

*      *      *

The above talk was prepared for the Class Convocation of the College of Natural Sciences on Sunday, December 8, 1996. The notice was so short that I took the liberty of using some passages of EWD1175. The talk was very well received, but my remarks about the overhead projector did not evoke a response: it is quite possible that my youthful audience had never considered the alternative of lectures without overhead projector.

It was a festive ceremony, but to quote Harry S. Truman "I'm glad it's over.".

                          Austin, 9 December 1996

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Martijn van der Veen
revised Mon, 10 Dec 2007

EWD1253

Mathematical induction's fixpoint

Let r be a left-founded relation, i.e. let

(0)          〈 ∀x :: [x ⇒ r ; x] ⇒ [ x ⇒ false ]  〉     ;

an appeal to what is called "mathematical induction" means that a proof obligation of the form

(1)          [ x ⇒ false ]

is replaced by the formally weaker obligation

(2)          [x ⇒ r ; x]      or      [ x ∧ ¬ ( r ; x ) ⇒ false ] .

Proving (2) by mathematical induction leads to the (subsequently simplified) obligation

(3)          [ x ∧ ¬ ( r ; x ) ⇒ r; ( x ∧ ¬ ( r ; x ))]
≡               {shunting}
               [x ⇒ r ; x ∨ r ; ( x ∧ ¬ ( r ; x ))]
≡               { ; monotonic in 2nd argument}
               [x ⇒ r ; x]

i.e. (2)! The decision to prove by mathematical induction is idempotent. With thanks to the ETAC.

Nuenen, 17 December 1996

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188, USA

transcribed by Jose Alejandro Ruiz Delgado
revised Sun, 31 Aug 2008

EWD1255

Pruning the search tree

This note deals with three classical, very similar problems: in a sequence of moves, a bunch of entities have to be transferred across a river. The problem is that the available boat is so small that a number of trips are needed, and that there are curious constraints as to which combinations of entities may occur separated from the rest. For each problem, the challenge os to find an acceptable schedule.

For all problems we adopt the rule of "no cancellation", i.e. we reject any schedule in which a subsequence of successive moves results in no change. Consequently, only a finite number of finite schedules need to be investigated for acceptability, and in that sense our little puzzles are trivial. They become, however, little mathematical problems if we accept mathematics as the art and science of effective reasoning and try to reduce the number of schedules to be inspected. This note is being written because we can use these little problems to illustrate various techniques.

In all our problems, the river runs north-south and has to be crossed from the west bank to the east bank.

*               *
*

In our first problem, the river has to be crossed by a shepherd with a wolf, a goat, and a cabbage. The shepherd is the only one that can operate the boat, which is so small that each time he can take at most one of the three with him across the river. The compatibility constraint is that, in the absence of the shepherd. the wolf would eat the goat, and the goat would eat the cabbage. The challenge is to design (if possible) a schedule in which everything reaches uneaten the east bank.

With an arrow from A to B representing "A eats B", we can represent the incompatibilities by the picturebut this represents more than we are interested in: the important thing is that the shepherd does not leave wolf and goat together and unattended, regardless of whether the wolf could eat the goat or the goat could eat the wolf. The asymmetry of "A eats B" and hence the direction of the arrows is a red herring, and we can simplify the picture thus:   

But now the constraints are symmetric between wolf and cabbage, i.e. also the difference between wolf and cabbage is "noise" and we can regard them as different instances of say, "alphas".

So, in our simplified problem, the shepherd arrives with one goat and two alphas, and the compatibility constraint is that, in the absence of the shepherd, no alpha may be in the company of the goat. The reader is invited to check that, with "no cancellation" as well, there is each time exactly 1 thing the shepherd can do:

(0) eastward with the goat
(1) westward alone
(2) eastward with an alpha
(3) westward with the goat
(4) eastward with an alpha
(5) westward alone
(6) eastward with the goat

Our solution is symmetric around move (3). Please note that at this level of abstraction —in which the two alphas are as indistinguishable as the two electrons in the helium atom— the solution is unique. Not distinguishing between the alphas is another way of achieving the efficiency of the counting argument. Because in this simple problem we only count to two, the abstraction has only halved our search space.

*               *
*

[In view of EWD1250, "The couples, the river, and the little boat", the inclusion here of the following problem exposes me to the accusation of typically Texan crime of self-plagiarism. Ora pro nobis.] Here is how Morris Kline presented the problem in 1967: "Two husbands and two wives have to cross a river in a boat which can hold only two people. How can they cross so that no woman is in the company of a man unless her husband is also present?"

We can name the four people by considering the couples (H,W) and (h,w) and the enumerate the disallowed combinations:

    wH   wHW   Wh   Whw

In this terminology we can explore the tree of all possible scenarios, but that is an extensive search.

The problem is symmetric in the two couples and naming them differently ,as we did above, is of course sowing the seed of a combinatorial explosion. (Note that we had to mention "wH" and "Wh" separately!)

When we wish to ignore the distinction between the two couples, i.e. between upper and lower case in our enumeration of disallowed combinations, there is a little else but count the number of wives and husbands: they contain one or two wives and exactly one husband. Focusing on the latter, the disallowed combinations are ruled out if we impose the stronger constraint:

the husbands stay together  .

But as soon as the husbands stay together, we don't need to distinguish between them —they could be truly identical twins—, nor between the wives. The pairing, as we represent by the couples, has disappeared from the picture, and after this abstraction, there is only one solution left:

(0) westward two wives
(1) eastward one wife
(2) westward two husbands
(3) eastward one wife
(4) eastward two wives

The reader is invited to check that, together with the rule of "no cancellation", the above solution is indeed unique. Our gain is considerable: in terms of the couples (W,H) and (w,h), the original problem admits 8 different solutions.

Two remarks are in order. The minor remark is that the rule of "no cancellation" has been strengthened by the decision not to distinguish between the two wives. Had we maintained the distinction between the two wives, the rule of "no cancellation" would not have ruled out the continuation

(3) eastward one wife
(4) westward the other wife

The more general remark concerns our adoption of the stronger constraint "the husbands stay together". Strengthening the constraints is a perfectly general way of pruning the search tree, but one runs, of course, the risk of choosing the constraints so strong that they can no longer be met. It may be worth noticing that in this example the major effect of the stronger constraint was not so much a direct size reduction of the search tree but rather the introduction of the freedom to eliminate the distinctions between the husbands and between the wives. So much for the problem of the couples, the river, and the little boat.

*               *
*

Our third problem is very well known. "Three missionaries and three cannibals have to cross a river in a boat which can hold only two people. As soon as, at either bank, there would be more missionaries than cannibals, the missionaries would convert the cannibals. How can cross the river so that no cannibal conversions take place?"

The only way in which I could solve this problem, was by formulating some simple theorems, such as

(i) the permissible divisions (1,5) are those in which the single person is a missionary.

(ii) the permissible divisions (2,4) are those in which the pair contains at least 1 missionary.

(iii) the permissible divisions (3,3) are those in which each triple consists of missionaries only or of cannibals only.

In the following solution, m stands for a missionary, c stands for a cannibal, while x and y stand for either. The reader is, again, invited to check that at each step we have no choice: the solution below is unique. (It is only if you feel obliged to choose an x and a y, that you get 4 solutions.)

  (0) → m x
  (1) ← x
  (2) → m m
  (3) ← m
  (4) → c c
  (5) ← m c
  (6) → c c
  (7) ← m
  (8) → m m
  (9) ← y
(10) → m y

The above solution is as symmetric around its midway move as the two previous solutions.

*               *
*

The counting abstraction

In the first problem, we eliminated the distinction between the wolf and the cabbage by the introduction of the alphas, and the solution became unique.

In the second problem we strengthened the constraints, so that we could eliminate the distinction between the husbands and, more importantly, the distinctions between the wives, and, as a result, the solution became unique.

Just maintaining the distinction between the cannibals on the one hand and the missionaries on the other hand yields 4 different solutions. Of course we could distinguish between the cannibals by calling them Ping, Peng and Pong respectively. (This is analogous to distinguishing between the two alphas by calling them "wolf" and "cabbage" respectively.) Similarly we could distinguish between the missionaries by calling them Mark, Luke, and John respectively. I would like the reader to realize that, salvo errore, the number of solutions in terms of named cannibals and named missionaries equals 8100. Compare this number with the original 4 and you see how large the price can be that has to be paid for the introduction of needless distinctions.

It is this observation that should give us a fresh appreciation of the effectiveness of counting arguments. In the traditional reconstruction of Mankind's discovery of the number concept, Man is supposed to observe that "five apples, take away one apple, remain four apples", then "five pears, take away one pear, remain four pears", and then with nuts, pebbles, etc. until the generalization emerges "five, take away one, remain four" or "5-1=4". I remember those reconstructions stressing the abstraction from the difference between apples, pears, nuts, pebbles, etc.

But there is a more profound abstraction going on: there is a profound difference between "the number five" on the one hand and "five things of unspecified nature" on the other. In the case of "five things, take away one thing", it is appropriate to ask for further instructions: "Which of the five things shall I take away?", but when asked to calculate "5-1", the question "Which 1 shall I subtract?" is meaningless.

The essence of counting is not distinguishing between the objects counted, and, conversely, if we have a collection of indistinguishable objects, their number seems to be about the only thing that can matter.

This is nice to know.

Remark I cannot resist the temptation to draw the attention to what now almost strikes me as an anomaly, viz. that in all "fundamental" considerations about "number" and "counting" that I remember, the objects counted are most emphatically distinguishable.

For instance, in 1884, F.L.L. Frege (1848-1925) defined the cardinal number of a given class as the class of all those classes similar to the given class. But when the notion of class was made precise in 1895 by G. Cantor (1845-1918), he defined it thus [translation published by E.T.Bell]: "By a class (Menge) we understand any summary (Zusammenfassung) into a single whole of well-distinguished objects of our intuition (Anschauung) or of our thought (Denken)."

Similarly, counting is always described as counting the objects "in a given order" but if the objects are indistinguishable there is no way of "giving" the order. The order is essential for the counting process, not for the latter's outcome. (End of Remark.)

I gratefully acknowledge my discussion on most of the above with Rutger M. Dijkstra and Silvija Seres.

Austin, 19 January 1997

Prof. Dr. Edsger W. Dijkstra
Department of Computer Science
The University of Texas at Austin
Austin, TX 78712-1188 USA

Transcription by Jorge Andrés Pérez.
Last revised Mon, 10 Dec 2007.

EWD1256

Mathematical Methodology, Spring 1997

Organizational matters.

•   You will be treated as grown-ups, i.e. it is your responsibility to check that you understand what is going on in class. If I use a word you don't recognize or a sentence you cannot attach a meaning to, it is your duty to ask for clarification. If I go too fast, it is your duty to slow me down.

•   During the semester I shall not check your progress. If I give homework, I give you tasks of which I believe that working on them is very instructive for you. Since first-class students can learn a lot from each other, I urge you to try to do the homework in little groups.

•   At the end of the semester there is an oral examination for each of you, the principle being that, after having followed my thoughts for a full semester, you are entitled to two hours of my undivided attention.

•   Once a grade has been given, there is no arguing about it. For those that wonder whether this should make them uncomfortable, it might help to know that I now operate that way for more than 30 years and can remember only one or two conflicts.

•   Handouts, if any, will lie on the corner of the table nearest to the entrance of the seminar room. Please take one.

•   I will not use the overhead projector.

Matters of Substance

I intend to present mathematics not as the "abstract science of space, number, and quantity" (C.O.D.) but as the art and science of effective reasoning. (This view is not new, for it had its champions in the 19th century; it is not universally adopted either, as was shown recently by the anonymous referee who wrote "simplicity is not a scientific concern".)

I expect to cover roughly 3 areas.

(i) the structure of the highly effective argument without avoidable complications

(ii) the design, with a minimum of detours, of such crisp arguments

(iii) the adequate presentation of such arguments.

I shall not try to turn all of you in a single semester into brilliant, expert mathematicians, but what I can probably achieve is showing most of you how to become mathematically much more effective, because the other courses in mathematics may teach you mathematics, but rarely teach you how not to waste your time. I hope to achieve more, but even if you only learn to avoid the most common complifications of arguments, the most common pitfalls in design and the most common forms of obscurity in presentation, the semester will be worth the trouble.

Austin, 14 January 1997

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Jennifer Lu Greene.
Last revised Mon, 10 Dec 2007.

EWD1258a

The ladder theorem

Let p and q be two column vectors of the same (finite) length. Let [p ≥ q] denote that in each row, the p-element is at least the q-element , i.e.

[p ≥ q] ≡ 〈∀i :: p.i ≥ q.i 〉

Let sort.w denote the result of sorting column vector w in ascending order. Then the ladder theorem states

(0)      [p ≥ q] ⇒ [sort.p ≥ sort.q]

Proof   We observe for any x and positive n

the nth element of sort.p is ≤ x

≡    { sort.p is in ascending order }

sort.p contains at least n elements ≤ x

≡    { p is a permutation of sort.p }

p contains at least n elements ≤ x

⇒    { [p ≥ q], the antecedent of (0) }

q contains at least n elements ≤ x

≡    { q is a permutation of sort.q }

sort.q contains at least n elements ≤ x

≡    { sort.q is in ascending order }

the nth element of sort.q is ≤ x ,

and since the above calculation derives that, as a consequence of [p ≥ q], its first line implies its last line for any x , it captures by "indirect order" the elementwise demonstration of [sort.p ≥ sort.q] .

(End of Proof.)

The ladder theorem is well-known. It tells us that if, in a matrix with sorted rows, we sort all the columns, the rows remain sorted. The above proof of the ladder theorem has been recorded (i) because there are such messy proofs of it —I saw one the other month— , (ii) because I don't succeed in viewing it as "intuitively obvious", and (iii) because the above proof is so nicely disentangled: Sorting is permuting and making ascending, and please note the separate appeals to these two properties.

My thanks to the ETAC for turning my first version into a proof by indirect order.

Austin, 19 March 1997

prof. dr Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Diethard Michaelis
revised Mon, 10 Dec 2007

EWD 1260

The marked coins and the scale

Our tool is a simple scale with two plates, as is used by the goddess Justitia; a weighing has one of 3 possible outcomes: the scale balances, or it tips in the one direction, or it tips in the other direction.

All genuine coins have the same weight, a fake coin is heavier or lighter. We are presented with a number of “marked coins” of which we know:

•  exactly 1 of the marked coins is fake,

•  a coin marked as “pluscoin” is genuine or too heavy,

•  a coin marked as a “minuscoin” is genuine or too light.

We are considering the problem of identifying the fake coin in n weighings. Because a sequence of n weighings has 3n outcomes, one cannot guarantee the identification of the fake one among more than 3n coins to be investigated, but this upper bound can be achieved. By mathematical induction, we shall prove that n weighings suffice to identify the fake one among 3n marked coins. At the same time we shall derive all protocols achieving this identification.

Because 3⁰=1, the base (i.e., n=0) is trivial: in the case of 1 marked coin, that one is the fake one and 0 weighings suffice.

For the induction step, we write the number of marked coins among which the fake one is to be identified as

(0)     P + M + p + m + t    ,

where at the first weighing

P = # pluscoins on the left-hand plate

M = # minuscoins on the left-hand plate

p = # pluscoins on the right-hand plate

m = # minuscoins on the right-hand plate

t = # coins left on the table

In order to enable the first weighing to give enough information to localize the fake coin, we insist that both plates contain the same number of coins, i.e.

(1)     P + M = p + m    .

Under that constraint, tipping or balancing of the scale can be related to the place of the fake coin, more precisely:

•  If the left-hand plate goes down, the fake coin is either among the P pluscoins or the m minuscoins, i.e. within a set of P+m coins.

•  If the left-hand plate goes up, the fake coin is either among the M minuscoins or among the p pluscoins, i.e. within a set of M+p coins.

•  If the scale balances, the fake coin is among the t coins on the table.

To maximize (0), we independently maximize P+m, M+p, and t. Since we have still n weighings left, this yields ex hypothese

(2) | P +m = 3n M+p = 3n t = 3n  

which yields that (0) equals 3n⁺¹ as desired, provided (1) and (2) have a solution. Elementary algebra suffices to show that they are equivalent to

(3)
P = p
M = m
P+M = 3n
t = 3n  

which tells us that in the 1st weighing, both sides should contain equal numbers of pluscoins and equal numbers of minuscoins.

Such a solution indeed exists. Start with the plates empty and all 3n⁺¹ coins on the table. A move consists of taking either two pluscoins or two minuscoins from the table and putting one of those on each plate, until (# coins left on the table) = 3n. Because the number of coins on the table is odd, it is ≥ 3 when a move still has to be performed: with 2 markings, and ≥ 3 coins, at least 2 coins have equal marking.

The solution of (3) is not necessarily unique: for instance, with n=2 and the marking +++++----, we have the following two solutions

left | right | table
++- | ++- | +--
+-- | +-- | +++

*                        *
*

Equation (1) can be dropped if we admit (fake) coins of negative weight and have our genuine coins being weightless. The same freedom is obtained by the availability of enough genuine coins: if P+M ≠ p+m, some genuine coins can then be used to make up for the difference, so that both plates carry the same number of coins. (This was the situation that prevailed in EWD1083.)

I gave the problem of EWD1083 (unmarked coins with at most one fake coin, and as many genuine coins as you like) to my students. Almost all of them found solutions, sometimes of considerable ingenuity. The ingenuity was always involved in the creation of a very special solution. The purpose of this note is to draw attention to the fact that finding the most general solution could very well be the simplest task. In the above I did not feel to have to invent anything.

Austin, 31 March 1997

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Xiaozhou (Steve) Li
revised Mon, 10 Dec 2007

EWD1261

The angle bisectors of a triangle

Renewed interest in EWD1014 induced me to look for a nice derivation of the formula for the lengths of the angle bisectors in a triangle. In doing so, I had a few small surprises, but just enough to justify this note.

*        *        *

There is, to begin with, the theorem that the angle bisector divides the opposite side into the same ratio as the adjacent sides, in terms

of the annotation in fig.0 for instance

(0) p/q = b/c

(The usual proof of (0) is by remarking that both expressions equal L/R where L and R denote the areas of the left and right subtriangle respectively; p/q equals L/R because — see fig.1 — the subtriangles share the same (vertical) altitude, while b/c equals L/R because the two remaining altitudes drawn in fig.1, since they intersect on the angle bisector from the top, have the same length.)

We introduced (0) with the clause "for instance" because alternative formulations are

q/p = c/b , b/p = c/q and p/b = q/c ;

please note that these 4 formulations equate 4 different values, while there is no reason to prefer one over the other. Compared to the above four, the fifth

(1) p∙c = q∙b

is canonical! It is a striking example of how much nicer the symmetric product is than the quotient, whose asymmetry creates a spurious diversity. (This in addition to the problems that, in general, may be created by the fact that the quotient is a partial function.) In what follows, we shall use (1).

*        *        *

Next our attention turned to the angle bisector itself. We named it d, as in fig.2:

The two angles known to be equal we named α, and our purpose was to apply the Cosine Law to both subtriangles and then to eliminate α. We observe

 p² = b² + d² − 2∙b∙d∙cos.α
 q² = c² + d² − 2∙c∙d∙cos.α

multiplying the former by c and observing — see (1) — p²∙c = p∙q∙b, multiplying the latter by b and similarly observing q²∙b = p∙q∙c and subtracting we get

p∙q∙(b-c) = b∙c∙(b−c) + d²∙(c−b)

Dividing out the common factor (b−c) we get (as intended)

(2) d² = b∙c − p∙q ,

but the problem with the last step is that it does not work in the case b=c.

It was Rajeev Joshi who observed that there is no need to take again into account that the two angles at the top are equal because (1) already captures that we are talking about the angle bisector of the top. Applying the Cosine Law — see fig.3 — and using cos.(π−β) = -cos.β, we obtain

b² = p² + d² − 2∙p∙d∙cos.β
c² = q² + d² + 2∙q∙d∙cos.β

multiplying the former by q and the latter by p and observing, thanks to (1), this time q∙b² = p∙b∙c and p∙c² = q∙b∙c, and finally adding, we get

 (p+q)∙b∙c = (p+q)∙p∙q + (p+q)∙d²,

which yields (2) without the exception. Not using the equality of the angles at the top a second time is the other charm of the latter argument.

Austin, 17 April 1997
prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Spenser Max Truex
revised 09-Sep-2020

EWD 1268

The Mathematical Divide

This note uses the simplest example I could think of to illustrate an old issue —a bone of contention, one might say— that tends to divide the mathematical world. I shall present two proofs of the well-known equality.

(0)        (a+b)² = a² + 2∙a∙b + b²

We give the intuitive proof first:

<∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ a + b ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙>

<∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙ a ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙> a² | <∙∙∙ b ∙∙∙> a∙b
a∙b | b²

The lefthand side of (0) represents the area of the undivided big square; the righthand side represents the sum of the areas of the four parts as in the above picture. In short: equality (0) stares you in the face!

Now we turn to the calculational proof. As usual, we shall exploit the associativity of the addition —i.e. the equality

(p + q) + r = p + (q + r )        for all p, q, r   —

implicitly by omitting such semantically redundant parenthesis. Here we go! For any a, b,

(a + b)²

=        { definition of exponentiation }

(a + b) ∙ (a + b)

=        { distribution p∙(q + r ) = p∙q + p∙r }

(a + b) ∙ a + (a + b) ∙ b

=        { distribution (p + q) ∙ r = p∙r + q∙r, twice }

a∙a + b∙a + a∙b + b∙b

=        { symmetry of ∙ : p∙q = q∙p }

a∙a + a∙b + a∙b + b∙b

=         { definition of exponentiation twice; property of 2: p + p = 2∙p }

a² + 2∙a∙b + b²

(In the very last line —as in (0)— we have implicitly used that also multiplication is associative.) Compared with the calculational proof, our former intuitive proof is seductively simple, but, though a great lover of simplicity, I think that the temptation should be resisted.

The traditional objection to the intuitive, pictorial arguments is that they raise more questions than they answer because pictures are always over specific. In our example, for instance, we have in the picture the case 0<b<a. Does (0) also hold when 0<a<b? When b<0<a? Or, more precisely, when 0 < a+b < a and when a+b < 0 < a? The intuitive argument does not answer these questions. Because its silent assumptions obscure what is purportedly demonstrated, we can question whether the intuitive argument should be considered a proof at all.

With respect to the above questions, the calculational proof does much better: the transformations used are value-preserving, whatever the signs involved, and, hence, the calculational argument demonstrates at one fell swoop that (0) is valid for all possible sign combinations.

There is one further advantage of this calculational proof. And that concerns the question whether (0) also holds if a, b are matrices. (Not an unreasonable question, for matrices can be added, squared, and multiplied, just like real numbers.) To the answer of this question, the intuitive proof cannot contribute at all. The calculational proof immediately tells us that in general, (0) does not hold for matrices since matrix multiplication is not symmetric (i.e. in general, p∙q ≠ q∙p for matrices p, q). In the intuitive argument, (0)'s dependence on symmetry of multiplication is swept under the rug, and the intuitive argument is error-prone, because its apparent simplicity has been obtained by committing the sin of omission.

So much for the nature of the Mathematical Divide.

*                *
*

Each side of this Mathematical Divide has its fervent advocates. Pictorial arguments are praised for being natural and intuitive, for being short and simple, for providing insight, and for aiding and guiding in the discovery of new mathematics; finally, pictures are deemed less error-prone than calculations. Calculational arguments are praised for their rigour, for their completeness, for their brevity, and lately for their amenability to mechanical verification or even generation; finally, calculations are deemed less error-prone than pictorial arguments.

To the discussion of the pros and the cons I would like to add two remarks, because I do not notice them being made while I do think they are relevant.

The first remark is that, no matter how surprising, tickling, or charming "intuitive proofs" may be, we do not know how to teach their design, this in contrast to calculation, whose design to a very large extent can be taught.

When this alien resident of the USA sees a publisher's catalogue of mathematical textbooks, he cannot fail to notice that "intuitive" occurs as an almost universal recommendation. But these blurbs make him very doubtful, for he knows his Concise Oxford Dictionary, which describes "intuition" as

"immediate apprehension by the mind, without reasoning"

which almost forces one to conclude that either the thing apprehended is totally trivial or the apprehension does not amount to very much.

Another thing this alien resident of the USA cannot fail to notice [is] how the American mathematical community is obsessed with mathematical pedagogy and educational reform. I am not making this up. In the Fall, 1997, Newsletter of the Texas Section of the Mathematical Association of America, the Department of Mathematics and Statistics of Texas Tech University, Lubbock, TX 79409, invites applications for two tenure track assistant professor positions. So far, so good, but the 1st (!) requirement starts with

"The applicant must show strong evidence of research potential in collegiate level mathematics education."

(Anyone interested?) This pedagogical obsession is not just a modern product of Political Correctness ("How to keep girls and other minorities in the mathematical fold", etc.), it already showed its ugly face a hundred years ago, when academic mathematics was hardly established in the USA. I quote

"By 1897, the University [of Chicago] had promoted Jacob Young to an assistant professorship specifically in mathematical pedagogy."

(from Karen Hunger Parshall and David E. Rowe, "The Emergence of the American Mathematical Research Community, 1876–1900: J.J. Sylvester, Felix Klein, and E. H. Moore"). This was shortly after the period that American mathematics had been heavily influenced by Felix Klein, an ardent advocate of intuition and visualization ("Anschauung"). Could it be that America's attraction to the unteachable form of doing mathematics and its persistent but ineffective obsession with mathematical pedagogy are related?

My second remark concerns the extent to which the problems of computing, programming, and digital systems design in general are amenable to mathematical treatment. The answer is "Hardly" when we identify the doing of mathematics with its intuitive, pictorial style, because the latter does not scale up. To return to our earlier example, a pictorial proof of

(a + b)³ = a³ + 3∙a²∙b + 3*a∙b² + b³

has lost most of the attraction of simplicity, while a pictorial proof of the expansion of (a + b)⁴ baffles the imagination. Also in a nonpictorial setting, "immediate apprehension by the mind, without reasoning" does not scale up.

But computing's successful designs are highly sophisticated logical constructs; they are unavoidably large, and a major design concern is always to structure them in such a way that the amount of reasoning needed for their justification remains doable. The use of techniques that do scale up is an essential aspect, which, for instance, has been addressed explicitly under the heading "compositionality". We are getting more and more successful at learning how to keep sophisticated, ambitious systems under control, but invariably (and not surprisingly) this requires the kind of formal calculations Felix Klein disliked and attention to detail he despised.

You see, another thing this alien resident of the USA could not fail to notice was the strong scepticism evoked over here by his —I thought eloquent and convincing— pleas for a more mathematical approach to computing science and programming. An implication of that story is that, in the USA, the term "mathematics" has a meaning that differs from the one I grew up with. I am getting a feeling for how that divergence could occur; the role of education, which differs from country to country, has a lot to do with it.

*                    *
*

The Mathematical Divide also manifests itself in what is considered the role of proofs. At the intuitive side, proofs have to be convincing; at the calculational side, proofs have to be correct.

At the intuitive side there is a whole "philosophy" of mathematics —I guess it has a name, but I don't know it— that pushes mathematics as a social activity: a proof is acceptable if enough people accept it. (Names like Imre Lakatos, Philip J. Davis and Reuben Hersch come to mind.) It is an attitude very similar to the one, not unpopular in software engineering circles, for which "user satisfaction" is the primary quality criterion for a piece of software. The problem with the goal of "user satisfaction", however, is that it provides no technical guidance to the program designer.

In programming, the answer has been the introduction of the functional specification as the embodiment of a separation of concerns: the functional specification acts as a logical firewall between what are now known as the pleasantness problem and the correctness problem. The pleasantness problem deals with the question how satisfactory a system meeting a given functional specification would be; the correctness problem deals with the question whether a given system meets that functional specification. The correctness problem being an entirely technical one, the functional specification can provide strong heuristic guidance for the system designer. (This separation of concerns has provoked strong objections; correctness concerns have been blamed for stifling the programmer's creativity .....).

In the last 120 years or so, an analogous development has taken place in mathematics, where the wooly quality criterion of "convincing enough of your fellow mathematicians" has been replaced by the requirement that the result be derived, according to the rules of an explicitly stated logic, from explicitly stated postulates. Logic and postulates act as the firewall, shielding the proof-designing mathematician from the psychological preferences of his colleagues. And again the formalization provides strong heuristic guidance.

The moral of this story is that the introduction of the functional specification in programming is strongly analogous to, and has undoubtedly been inspired by the transition from the intuitive to the calculational side of the Mathematical Divide. That example is one more debt we owe the mathematical culture, but I should add that not all computer scientists share such feelings of gratitude. The title of the infamous 1977-paper by DeMillo, Lipton and Perlis "Social Processes and Proofs of Theorems and Programs" is revealing. Staying firmly at the intuitive side of the Mathematical Divide, they argue the futility of trying to treat programs as mathematical objects and boldly postulate: "... the transition between specification and program must be left unformalized".

I cannot resist to quote E. T. Bell (The Development of Mathematics, 1940, 1945) on the topic. He leaves no doubt as to which side of the Mathematical Divide has his preference.

"Mathematicians and scientists of the conservative persuasion may feel that a science constrained by an explicitly formulated set of assumptions has lost some of its freedom and is almost dead. Experience shows that the only loss is denial of the privilege of making avoidable mistakes in reasoning. As is perhaps but humanly natural, each new encroachment of the postulational method is vigorously resisted by some as an invasion of hallowed tradition. Objection to the method is neither more nor less than objection to mathematics."

Amen.

Austin, 10 December 1997

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Kevin Beckwith Bush
revised Mon, 10 Dec 2007

EWD1273

On Dijkstra's Lemma and Kruskal's Algorithm

Dijkstra's Lemma    Consider an undirected graph that consists of a single cycle and in which each vertex is marked to be either an A-node or a B-node. Then the number of AB-edges —i.e. edges that connect an A-node with a B-node— is even.

Let, for a given finite set of vertices, for each pair the length of the edge between them be given; for simplicity's sake all edge lengths are assumed to be distinct. We now give two theorems about "the shortest tree", i.e. the spanning tree with the smallest length, where the length of a tree is defined as the sum of the lengths of its edges.

Theorem 0    The longest edge of a cyclic path does not belong to the shortest tree.

Proof    Let e be the longest edge of a cyclic path. We prove Theorem 0 by showing that for any spanning tree T that contains e we can construct a shorter spanning tree. Remove edge e from tree T , which thus falls apart into two subtrees which we call A and B respectively; e being an AB-edge in the cyclic path, Dijkstra's Lemma tells us that the cyclic path contains another AB-edge, which we use to reconnect A and B . The resulting tree is shorter than T because e is the longest edge of the cyclic path. (End of Proof.)

Theorem 1    Partition the vertices into A-nodes and B-nodes. Then the shortest AB-edge belongs to the shortest tree.

Proof    Let, for a given partitioning, e be the shortest AB-edge. We prove Theorem 1 by showing that for any spanning tree T that does not contain e , we can construct a shorter spanning tree. Add edge e to tree T , thus creating 1 cyclic path, which contains e ; e being an AB-edge, Dijkstra's Lemma tells us that that cyclic path contains another AB-edge, which we remove. The resulting tree is shorter because e is the shortest AB-edge. (End of Proof.)

Kruskal's Algorithm constructs the shortest tree by processing —i.e. "rejecting" or "accepting"— the edges in the order of increasing length. At any stage, the accepted edges construct a forest —to begin with as many isolated roots as there are vertices, and finally 1 big tree of accepted edges— . Kruskal's Algorithm rejects a next edge if it forms a cycle with (some of) the edges that have already been accepted, otherwise it accepts it. In terms of the forest: the next edge is rejected if it connects two nodes from the same tree, and accepted if it connects two trees. Rejection is justified by Theorem 0, applied to the cyclic path formed in the tree; acception is justified by Theorem 1 if we partition the forest into A-trees and B-trees such that the edge under consideration is an AB-edge.

Austin, 3 May 1998

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Jennifer Lu Greene.
Last revised Mon, 10 Dec 2007.

EWD1277

Society's role in mathematics

Mathematicians being as human as they are, there is no question that doing mathematics has always been, and will always be be, a social activity: when mathematicians have been productive, they are as excited about their latest creation as musical composers can be about their latest composition, and they are equally eager to share their delight. But it is not only in an artistic or emotional sense that the people doing mathematics form some sort of community for, by and large, they also do so in some very technical respects.

It is, for instance quite common that a number of mathematicians work on closely related problems, for this is all but unavoidable when a theory that is still to be born is in the air; in such a case, new results obtained by one are often of immediate significance for others. It is the circumstance that, over the centuries, has given rise to the phenomenon of scientific correspondence.

Aside Modern communication facilities like e-mail have the potential of highly intensifying scientific interchange and, consequently, have been hailed as of all-pervading scientific significance, but this seems a rash conclusion since, to the best of my knowledge, the modest speed of "snail mail" has never been a serious bottleneck: I at least never got the impression that, say, the development of quantum mechanics in the 20s was seriously hampered by the absence of e-mail. (On the contrary: pressure to conduct the development of quantum mechanics within the confines of ASCII-code could easily have been harmful.) If the modern communication and cooperation are welcomed exuberantly, this unwarranted enthusiasm could very well have a political origin, viz. the collectivist desire to play down the potential role of the individual. (End of Aside.)

Next, the mathematical community got the task of setting and maintaining quality standards, and this happened in a way which, in retrospect, may well be typical for mathematics. In the usual reconstruction of the early history of mathematics, mathematical "truths" —such as, for instance, that a triangle with sides of lengths 3,4, and 5 has a right angle— began as experimental facts gained by observation, until Hellenic genius changed that. The ancient Greeks had at least a double mathematical target: firstly they wanted to generalize and unify —say that they wanted to capture as well that a triangle with sides of lengths 5, 12, and 13 has a right angle— and secondly they wanted certainty and precision: they wanted to know why the ideal triangle with sides of exactly 3, 4, and 5 has an exactly right angle. The pivotal word in the previous sentence is the connective "why": they perceived that such fact[s], instead of being imperfectly established by observation, could and hence should be established perfectly by a convincing argument. But the notion of a "convincing argument" immediately raises the question "convincing to whom?": if the audience to be convinced is sufficiently gullible, the argument can be gloriously defective! It became the task of the mathematical community to cultivate the scepticism against which the quality of the "convincing argument" would be checked.

Thus the so-called "consensus model" of mathematics emerged, in which a proof was deemed correct (be it "up the standards of rigour of the day") when it was accepted by the mathematical colleagues because they saw nothing wrong or fishy with it. The situation was not ideal but for the first 20 centuries after Euclid there was no alternative. The mathematical edifice had been erected by drawing logical conclusions from the axioms and neither the logic nor the axioms were really subject to doubt. The axioms, introduced as "self-evident truths", were supposed to capture a given, fixed reality out there, so there was not much flexibility for them, and in the same vein they seemed to be one "true" logic that had to be used to draw the conclusions, so no freedom there either. Philosophers seemed to occupy themselves with logic, but on closer introspection they struggled with the problems of natural language, a medium now infamous for its obscure semantics. But as long as one searches for convincing "arguments" and the party to be convinced insists on understanding the argument in terms of the almost certainly inadequate vehicles of natural language and pictures, there is little else one can do.

Aside I was shocked when I discovered what can only be called The Great Mathematical Fraud, viz. that on the one hand Euclidean Geometry has been presented to the one generation of schoolchildren after the other as the prime example of a deductive science in all its pure glory, while at the same time all those generations of innocent schoolchildren have been taught to draw geometrical "conclusions" that do not follow from Euclid's axioms! Euclid's axioms just don't suffice, but the fraud could be hidden behind the obscure semantics of prose and picture. (End of Aside.)

With all respect the Greeks have been blamed for not dealing with real numbers in their own right, but dealing with them in the interpretation of lengths, areas and volumes instead. Elementary algebra (about sums, products, ratios, etc.) thus became a branch of geometry and remained so until René Descartes (1596-1650) turned things upside down. Descartes's vision was nothing less than to treat via the introduction of coordinates geometry as a branch of algebra. The conceptual turnabout, which has been hailed as the beginning of modern mathematics, was all the more impressive since Descartes had to create in passing the algebra he needed and its notational conventions. We shall return to these later, here we should mention, again with due respect, Descartes's initial error of judgment.

When Descartes had his vision, he was more than excited, he was ecstatic. You see, there was no systematic methodology for solving geometrical problems, at a given moment geometrical arguments seemed to require the inspired introduction of something like an auxiliary line, a circumstance that kept geometry a magic art. In algebra, however, this phenomenon was unknown: the rules of algebraic formula manipulation being known, algebraic problems were solved by turning the crank, so to speak. So for a short while it was felt that the translation into algebra would do away with the need of invention for which geometry was notorious.

As we shall see later, however, algebraic manipulation is not that mechanical and is more than just turning the crank. As the problems we try to solve become more advanced, the amount of manipulation required quickly becomes totally unmanageable unless we find a sufficiently effective way of reducing it. We effectuate such a reduction for instance by an inspired choice of what to name, and it turns out that such a choice is very similar to the inspired choice of, say, an auxiliary line. The temporary assumption that calculation, because mechanical, was trivial was an illusion based on experience with simple problems only. So much for Descartes's initial error of judgment.

Isaac Newton (1642-1724) and Gottfried Wilhelm Leibniz (1646-1716) were born in the last 10 years of Descartes's life, and the rest of the 17th Century saw a rapid and dramatic development of mathematics indeed. There emerged lots of things the mathematical community had to get used to, had to screen and sometimes had to reject. Seemingly correct arguments had led to obviously erroneous conclusions (e.g. in the case of the sums of infinite sequences), the concepts on which Newton based his differential and integral calculus seemed to some contradictory, in short, the "consensus model" of mathematics was in full force, and consensus was not always obtained.

Things really began to change in the 19th Century, the first half of which was dominated by the towering figure of Carl Frederich Gauss (1777-1855), who —among many other things!— set new standards for mathematical rigour. It were these new standards for rigour that made it possible to wean mathematics from the old intuitive arguments, as a result of which the counter-intuitive result could be established that non-Euclidean geometries could be made consistent and hence were conceivable. (These are geometries that do not include the Euclidean axiom that, through a point outside a line, there exists a unique parallel to that line.)

Since Descartes, who had based geometry on real algebra, the Euclidean axioms had already lost some of their exalted status of "the base of everything", the introduction of non-Euclidean geometries completed their fall from the pedestal. When axioms lost their status of "self-evident truths" that could be taken for granted, they became assumptions or postulates that had to be stated explicitly. It was around the turn of the century that under the guidance of the uncompromising David Hilbert (1862-1943) we got what became known as "the postulational method". Its reception was mixed. To quote E.T. Bell —from "The Development of Mathematics ["] (1945)—

"Mathematicians and scientists of the conservative persuasion may feel that a science constrained by an explicitly formulated set of assumptions has lost some of its freedom and is almost dead. Experience shows that the only loss is the denial of the privilege of making avoidable mistakes in reasoning. As is perhaps but humanly natural, each new encroachment of the postulational method is vigorously resisted by some as an invasion of hallowed tradition. Objection to the method is neither more or less than objection to mathematics."

It were not only the "assumptions" or "postulates", which replaced the axioms, that had to be stated explicitly. In the quest for greater clarity and precision, it soon emerged that the adopted deduction rules, i.e. the "logic" or the "inference rules" had to stated explicitly. In principle it no longer sufficed to say that one had proved a theorem, one had to add whether the argument was kosher according to, say, intuitionistic logic (L.E.J. Browwer); in practice the more demanding logics that were proposed were for many decades largely ignored.

For our current considerations that neglect is not important, for, neglected or not, the existence of alternative —not to say: competing— logics shed a new light on what the role of the mathematical community had been: bringing out a vote on the acceptance of the logic implicitly underlying the (usually verbal/pictorial) argument.

As time went on, the need of greater clarity and precision made the inadequacies of the verbal/pictorial argument more and more obvious, and formulae began to play a greater role. In the beginning, formulae were primarily used for descriptive purposes, to characterize or summarize situations or conclusions, while the step from one situation to the next was still reasoned verbally. (In this stage of formalization, syntactically ambiguous formulae are still quite common: already knowing what is "meant", the "understanding" reader is supposed to disambiguate them so that they make "sense".)

In the next stage, the rules of reasoning became stated and applied as rules of formula manipulation and the (this time syntactically unambiguous) formulae began to carry the argument. A new style of doing mathematics calculationally emerged. Personally I think that the calculatiobnal style of doing mathematics has great advantages. It helps in not making "avoidable mistakes in reasoning", it leads to crisp proofs that are easily checked —if so desired, mechanically— and thus to a superior product, it is more amenable to the scaling up that is required when we wish to treat programs as mathematical objects, and, most importantly, formula manipulation is much better teachable than the elusive cultivation of one's "intuition".

The ultimate consequence of the adoption of the postulational method is the inadequacy and subsequently the irrelevance of the consensus model of mathematics, as the latter reflected a form of interaction with the community which was needed to compensate for the major shortcomings of informal intuitive reasoning.

Not everyone notices that mathematics is evolving in a direction that makes the consensus model obsolete. Computing scientists, as a rule, tend to be aware of it; familiar as they are with manipulation (mechanized or not) of uninterpreted formulae, they tend to feel quite at home with more calculational arguments. Moreover they need the formal arguments as they cope better than the verbal arguments with the scaling up that reasoning about digital systems quickly requires.

Regrettably this evolution seems to be ignored precisely where the awareness of it would be of the greatest importance, viz. mathematical education at large. In the name of attracting females and other minority students, a sort of feel-good mathematics is promoted in which rigorous arguments don't seem to play a role and that utterly fails to prepare its victims for their future. This is a tragedy.

Austin, 21 September 1998

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188 USA

Transcription by Jorge Andrés Pérez
Last revised Mon, 10 Dec 2007.

EWD1282

On graphs whose nodes are Black or White

In this note we consider finite directed graphs. Each edge is considered to be directed from some node, called its source, to some node, called its target. The in-degree of a node is defined as the number of edges that have that node as their target; the out-degree of a node is defined as the number of edges for which that node is the source. Finally we postulate that each node is either black or white. We now observe

(0)        the sum of the in-degrees of the black nodes
    =          {when in doubt, consult the appendix}
             the number of edges with a black target
    =          {a source is white or black}
             #WB + #BB

where #WB denotes the number of edges with a white source and a black target (and for #BB, etc, analogously). By colouring all nodes black, the first equality of (0) yields

(1)        the sum of the in-degrees of all nodes equals the number of edges.

Interchanging source and target we get from (0)

(2)        the sum of the out-degrees of the black nodes equals #BW + #BB

and from (1)

(3)        the sum of the out-degrees of all nodes equals the number of edges.

Combining (0) and (2) we get

Lemma    If the sum of the out-degrees of the black nodes equals the sum of the in-degrees of the black nodes, then

#WB = #BW

Remark    From (1) and (3) we conclude

(4)        the sum of the in-degrees equals the sum of the out-degrees

and hence an alternative formulation for the Lemma is

Lemma'    If the sum of the out-degrees of the white nodes equals the sum of the in-degrees of the white nodes, then

#WB = #BW

(End of Remark.)

The Lemma has the

Corollary    If each node's in-degree equals its out-degree, then #WB = #BW.

Appendix

With finite types node and edge we declare

n : node;

e : edge;

s,t : edge → node  (for “source” and “target” respectively);

in,out : node → nat  (for “in-degree” and “out-degree” respectively)

defined by    in.n = 〈∑e : t.e = n : 1〉
                  out.n = 〈∑e : s.e = n : 1〉;
    b,w : node → bool  (for “black” and “white” respectively)

satisfying      b.n ≡ ¬ w.n   .

For the derivation of (0) we observe

〈∑n : b.n : in.n〉
    =        {definition of in}
        〈∑n : b.n : 〈∑e : t.e = n : 1〉〉
    =        {unnesting}
        〈∑n,e : b.n ∧ t.e = n : 1〉
    =        {Leibniz}
        〈∑n,e : b.(t.e) ∧ t.e = n : 1〉
    =        {nesting}
        〈∑e : b.(t.e):〈∑n : t.e = n : 1〉〉
    =        {1-point rule}
        〈∑e : b.(t.e) : 1〉
    =        {notational liberty}
          #?B

At first sight, the above derivation of

     〈∑n : b.n : in.n〉 = 〈∑e : b.(t.e) : 1〉

seems an overkill. I have tried all sorts of alternatives—counting marks in a 2-dimensional table, mathematical induction over the number of edges or the number of black nodes. All these methods could, of course, be made to work, but if you wanted to eliminate the handwaving, the argument became longer than the above that uses no more than the standard quantification manipulation. I had the privilege of discussing the alternatives with Maarten Boasson and Fred B. Schneider, who happened to visit UT simultaneously.

Austin, 20 February 1999

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Swarup Sahoo
last revised Wed, 8 Jun 2011

EWD1283

How "they" try to corrupt "us"

At my former university it was a firm principle of the informatics group that we would not teach our students how to use industrial products. The main reasons at the time were

•     the quality of industrial products was never up to academic standards, and

•     the market being as fickle as it is, the industrial product was of volatile significance only.

Later I learned how much the purposes of the University and those of industry can diverge. Universities, believe it or not, are interested in education, but I learned of industries that were not interested in education at all, neither in an educated work force, nor in an educated customer base. On the contrary, they preferred a docile, brainwashed work force and undemanding customers hooked on their products.

Another remark is that it is the task of a "leading University" to lead. In particular this means for us that we should give society not what it asks for, but what it needs. This issue is particularly acute for CS because their society asks for snake oil, for more of the same, though we all know that it hardly works.

*                 *
*

The above was triggered by a letter we received from one of our colleagues. I quote from it —"MS" presumably stands for "Microsoft"— :

We had a good meeting with MS representatives [...]. They were open to the possibility of giving us a *significant* number of graduate fellowships [...]. A key thing that MS wants in return is that our students have experience in programming in NT environments; they and other companies want such students. [...]

Well, that was a revealing meeting! For the record I quote from the following paragraph of that letter:

"I believe a key to the MS support for our department will be clear evidence that we are using NT (or related software, e.g. CE). I need to collect information about your use of NT (or intended use of MS software) as part of our proposal."

Since I do not want MS to sue me, I won't tell you how much I appreciate their offer. You must guess. For more detail I refer to the communications of the Chairman of the Board of "Mathematics Inc.", as published in [0]. For dominance of the Universities, see EWD539 in particular.

[0] | Selected Writings on Computing: A Personal Perspective by Edsger W.Dijkstra. Texts and Monographs in Computer Science, Springer-Verlag 1982 [ISBN: 0-387-90652-5]

Austin, 21 February 1999

prof. dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Richard Walker.
Last revised on Sun, 9 Dec 2007.

EWD1284

Computing Science: Achievements and Challenges

When, at the close of the 20th Century, I am supposed to talk about Computing Science, I am immediately faced with the question “Which Computing Science?”. In my personal case I can narrow it down to “European CS or American CS?” but with 32 years of European and 26 years of American employment as computer scientist, I cannot eliminate the dilemma. (As an aside, don’t add the two numbers I gave you, for there was some overlap.) To summarize my position with respect to this transatlantic difference: I cannot ignore it, but am also allowed to address the issue openly (that is, if not qualified, at least entitled).

The major differences between European and American CS are that American CS is more machine-oriented, less mathematical, more closely linked to application areas, more quantitative and more willing to absorb industrial products in its curriculum. For most of these differences there are perfect historical explanations, many of which reflect the general cultural differences between the two continents, but for CS we have also to take into account the special circumstance that due to the post-war situation, American CS emerged a decade earlier, for instance at the time when design, production, maintenance and reliability of the hardware were still causes for major concern. The names of the early professional societies are in this respect revealing: the “Association for Computing Machinery” and the “British Computer Society”. And so are the names of the scientific discipline and the academic departments: in the US, CS is short for Computer Science, in Europe it is short for Computing Science.

The other circumstance responsible for a transatlantic difference in how CS evolved I consider a true accident of history, viz. that for some reason IBM was very slow in getting interested in Europe as a potential market for its computers, and by the time it targeted Europe, this was no longer virgin territory. Consequently, IBM became in Europe never as predominant as it has been in Northern America. Now, several decades later, it is hard to visualize and to believe how strong and how pervasive IBM’s influence has been, but let me relate to you an incident that took place in 1975, at a conference that IBM had organized at Montebello for CS professors from all over Canada. At that moment even IBM knew that OS/360 was a disgraceful mess and realized that it would become increasingly difficult to sell it to knowledgeable customers. And so, with all the sticks and carrots the company could muster, the Canadian Universities were urged to exclude the topic “Operating Systems” from their curricula, the reason given being that “working on the operating system was not an entry-level job”. Having seen IBM in action, I have mixed feelings about today’s fashion of strengthening the links, financial and otherwise, between higher education and industry.

It is a pity that they were called Programming Languages, but apart from that unfortunate name, FORTRAN and LISP have been the great contribution of the 50s.

That name was unfortunate because very soon the analogy with natural languages became more misleading than illuminating. It strengthened the school of thought that tried to view programming primarily as a communication problem, it invited the psychologists in, who had nothing to contribute, and it seriously delayed the recognition of the benefits of viewing programs as formulae to be derived. It was the time of Edmund C. Berkeley’s “Giant Brains or Machines that Think”, it was the time of rampant anthropomorphism that would lead to the false hope of solving the programming problem by the verbosity of COBOL and would seduce Grace M. Hopper to write a paper titled “The Education of a Computer”. Regrettably and amazingly, the habit lingers on: it is quite easy to infuriate computing scientists by pointing out that anthropomorphizing inanimate objects is in science a symptom of professional immaturity.

As said, FORTRAN and LISP were the two great achievements of the 50s. Compared with FORTRAN, LISP embodied a much greater leap of imagination. Conceptually FORTRAN remained on familiar grounds in the sense that its purpose was to aid the mechanization of computational processes we used to do with pen and paper (and mechanical desk calculators if you could afford them). This was in strong contrast to LISP whose purpose was to enable the execution of processes that no one would dream of performing with pen and paper.

At the time LISP’s radical novelties were for instance recognized by its characterization as “the most intelligent way of misusing a computer”, in retrospect we see its radical novelty because it was what is now known as a language for “functional programming”, while now, 40 years later, functional programming is still considered in many CS departments as something much too fancy, too sophisticated to be taught to undergraduates. LISP had its serious shortcomings: what became known as “shallow binding” (and created a hacker’s paradise) was an ordinary design mistake; also its promotion of the idea that a programming language should be able to formulate its own interpreter (which then could be used as the language’s definition) has caused a lot of confusion because the incestuous idea of self-definition was fundamentally flawed. But in spite of these shortcomings, LISP was a fantastic and in the long run highly influential achievement that has enabled some of the most sophisticated computer applications.

I must confess that I was very slow on appreciating LISP’s merits. My first introduction was via a paper that defined the semantics of LISP in terms of LISP, I did not see how that could make sense, I rejected the paper and LISP with it. My second effort was a study of the LISP 1.5 Manual from MIT which I could not read because it was an incomplete language definition supplemented by equally incomplete description of a possible implementation; that manual was so poorly written that I could not take the authors seriously, and rejected the manual and LISP with it. (I am afraid that tolerance of inadequate texts was not my leading characteristic).

It is much harder to get lyrical about FORTRAN, which as a programming language was denied the epithet “higher-level” already in 1962 (in Rome), but I should be grateful for I learned a few things from it. During an oral examination I had a student develop a program which we would now recognize as implementing pointer manipulations using a one-dimensional array. The candidate did very well until at the very end he got mysteriously stuck, neither of us understanding why. It turned out that he should have written down “a[a[i]]:= ....” but that mental block prevented him from conceiving that because FORTRAN (to which he had been exposed extensively) did not allow index expressions as complicated as “a[i]”. It was a revealing warning of the devious influence the tools we use may have on our thinking habits.

I learned a second lesson in the 60s, when I taught a course on programming to sophomores, and discovered to my surprise that 10 % of my audience had the greatest difficulty in coping with the concept of recursive procedures. I was surprised because I knew that the concept of recursion was not difficult. Walking with my five-year old son through Eindoven, he suddendly said “Dad, not every boat has a life-boat, has it?” “How come?” I said. “Well, the life-boat could have a smaller life-boat, but then that would be without one.” It turned out that the students with problems were those who had had prior exposure to FORTRAN, and the source of their difficulties was not that FORTRAN did not permit recursion, but that they had not been taught to distinguish between the definition of a programming language and its implementation and that their only handle on the semantics was trying to visualize what happened during program execution. Their only way of “understanding” recursion was to implement it, something of course they could not do. Their way of thinking was so thoroughly operational that, because they did not see how to implement recursion, they could not understand it. The inability to think about programs in an implementation-independent way still afflicts large sections of the computing community, and FORTRAN played a major role in establishing that regrettable tradition.

But despite its shortcomings, FORTRAN was a great contribution whose significance I realized during aforementioned programming course in the 60s. In that course I developed by way of example the program that transforms a permutation that is not the alphabetically last one into its alphabetical successor. I still vividly remember my excitement that I could do so at the beginning of the 5th lecture for an audience of about 250 novices, and that it took more than 20 minutes. I was so thrilled because, less than 10 years before, I had tackled that problem and, though by then an experienced programmer, I had been unable to design that program, and after a few hours had been forced to give up. For me it was a most vivid illustration of dramatic progress within a decade, and I tried to convey some of that excitement to my audience, but in that effort I was not entirely successful, for while leaving the lecture hall afterward, I overheard one student remarking to another “If Dijkstra couldn’t solve that problem in his student days, he cannot have been a very bright one.”. The reason I had been unable to design that program was that at the time I was programming in a machine code in which, due to the absence of index registers, programs had to modify their own instructions in store, and, as a consequence, my poor, uneducated head did not know how to make the distinction between the program on the one hand and the variables it operated upon on the other hand. In imperative programs, we now take this distinction for granted, but I would like to report to posterity that for me it was like a revelation when I saw the distinction made. And FORTRAN has everything to do with that.

The concept of the self-modifying program has been vigorously promoted by John von Neumann who apparently felt that it was an essential ingredient of the computer’s flexibility; in retrospect it was a pun that has been responsible for a decade of confusion.

And then the 60s started with an absolute miracle, viz. ALGOL 60. This was a miracle because on the one hand this programming language had been designed by a committee, while on the other hand its qualities were so outstanding that in retrospect it has been characterized as “a major improvement on most of its successors” (C.A.R. Hoare). It was created by a half-American, half-European committee of a dozen people. As I was not a member, I don’t know who contributed what, but I know that we owe to John W. Backus that the syntax of ALGOL 60 got a formal grammar, and to Peter Naur that --among probably a whole lot more-- the Report was written so exceedingly well. Several friends of mine, when asked to suggest a date of birth for Computing Science, came up with January 1960, precisely because it was ALGOL 60 that showed the first ways in which automatic computing could and should and did become a topic of academic concern.

The introduction and use of BNF (= Backus/Naur Form) to formalize the syntax was a very courageous novelty, because many feared that it would completely put off the computing community, but the great surprise was that exactly the opposite happened: it was loved by programmers and implementers alike. It turned out to have all the properties of a helpful formalism, viz. compact, unambiguous and amenable to mechanical manipulation: before the end of decade the construction of parsers had been mechanized, an achievement that 10 years earlier would have baffled the imagination. In the case of ALGOL 60, the use of BNF has had one regrettable effect. Its power should have been used exclusively to shorten the language definition, but it made the introduction of new syntactical categories so easy that the final syntax became more elaborate and more complicated than desirable.

A formal tool for the definition of the semantics was not available at the time, and so the semantics were given verbally. (This was definitely one of the places where Peter Naur’s scrupulous use of English paid off.) It was, for lack of an alternative, still an operational definition, but much more abstract and further away from the machine than we were used to. It was definitely not a definition in terms of an implementation, because when the Report was published, its authors did not know yet how to implement the language, and in that sense also the design of the semantics was very courageous. Of the language itself I would like to mention 3 highlights, in order: recursion, the type boolean, and the block structure.

A major milestone of ALGOL 60 was its introduction of recursion into imperative programming.

Aside Its inclusion was almost an accident and certainly a coup. When the ALGOL 60 Report was nearing completion and circulated for final comments, it was discovered that recursion was nowhere explicitly excluded, and, just to be sure that it would be in, one innocent sentence was added at the end of the Section 5.4.4., viz. “Any other occurrence of the procedure identifier within the procedure body denotes activation of the procedure.”. Some committee members only noticed this sentence when it was too late to oppose, got very cross and refused to implement it. In more than one sense they were the losers. (End of aside)

To give you some idea of the significance of this sentence, it was crucial in enabling Tony Hoare to complete the design of one of computing’s most famous algorithms, viz. Quicksort. Prior to knowing ALGOL 60, he had the idea, but it remained an elusive vision, a dream that defied formulation, but as soon as he saw ALGOL 60 offering him just what he needed, Quicksort materialized in all its glory.

But it was not only the invention of individual algorithms that benefited, also program composition as a whole became much cleaner. For instance, once the implementation can cope with nested activations of the same procedure, the function supplied as parameter to an integration routine may itself be defined in terms of a definite integral, and by abolishing the combinatorial constraints that otherwise would be imposed, ALGOL 60 introduced a new standard of cleanliness. In passing it clarified the structure of compilers, for, the syntax being defined recursively, a bunch of mutually recursive procedures provides the simplest structure for a parser (so much so that “syntax-directed compiling” became a recognized technique). For the subsequent multiprogramming systems, in which nested activation was generalized to interleaved execution of different activations of possibly the same procedure, implementing recursion has been a valuable stepping stone.

The next milestone of ALGOL 60 that I must mention is ALGOL 60’s introduction of “boolean” as a full-blown type, i.e. not only with boolean expressions but also with boolean constants, variables, arrays, procedures and parameters. From a programming point of view it was not so shocking: besides “integers” whose values can be represented by some finite number of bits, one can introduce a type for which a single bit suffices, but in a wider culture it is making a major difference.

Remark Even for programmers, who saw that there was no implementation problem at all, the introduction of the boolean variable was --and probably still is-- a big leap, as is convincingly illustrated by the fact that for years one would still find even in published programs clauses like:

if c = true then ....

when of course

if c then .....

would suffice (End of Remark).

Evolutions do take time. Mathematicians have used boolean expressions at least since 1557, when Robert Recorde introduced the equality symbol “=” as infix operator, but a formula like “n=5” was not recognized as an expression, not syntactically and not semantically, because for lack of the type boolean, “n=5” was not something that could have a value.

This changed in 1854 when George Boole introduced the type we now name after him, an invention, however, that the mathematical community had not yet absorbed a century later: for the average mathematician, and even for the not so average one, in 1954, a boolean expression was not something with a value, but as in 0 <= n <= 10, a condition or a statement of fact, and, say, 2+3=7 was not a complicated way of writing the constant false, it was just wrong, an attitude that precludes the manipulation of uninterpreted formulae containing boolean subexpressions. I now see more and more people doing calculational mathematics such as formulating a theorem as a boolean expression and calculating that its value is true.

This new style of doing mathematics embodies a major simplification of the mathematical argument. Computing Science developed it because it needed and had the potential to do so; ALGOL 60’s promotion of the type boolean has played a historically significant role in that development.

Finally, I must mention ALGOL 60’s contribution to program structuring, On the statement scale it introduced conditional and repetitive clauses, to which I shall return later. On a more macroscopic scale of structuring it introduced procedures as program modules, but in this respect its greatest contribution was undoubtedly the block structure, an invention of the last weeks of 1959.

Mid 1959 I attended a preliminary meeting at which the notion of “scope” was still very tentative. Computing Science was really still in its infancy, for there was a constant confusion between the timeless concept of the program text and the temporal concept of the computation, a confusion that provoked someone to ask “Do I understand that we are considering scopes extending from here till then?” I remember, when I received the final document, the awe with which I observed how in the block structure the textual concept of scope had been related to the nested life times of incarnations. It was a beautiful synthesis, relating computation structure to program structure; as such it represented a quantum leap in our coming to grips with the programming task. I was deeply impressed by the block structure, but have never been able to find out who in particular has been responsible for its invention.

After 1960, academic computing science began to flourish, it did so with many different flowers, so many in fact, that here we can touch on only a very small fraction of them. The now obvious significance of formal grammars raised interest in parsing, recognition, finite automata, Turing machines and, particularly in the United States, in logic, decidability and complexity theory. Not surprisingly, those early flowers could bloom because they could be fertilized by mathematical theories that did already exist. Furthermore it should be noted that --surprisingly or not, probably not-- most of the early theoretical work was closely tied to the notion of a discrete machine and its sequential operation.

But at the same time people began to realize that, for making assertions about computations as they could evolve in time, it was desirable to learn how to reason effectively about the timeless concept of a program. In the 60s one could observe a shift in emphasis: as I have characterized it before, first it was the task of the programs to instruct our machines, a decade later it was the task of the machines to execute our programs.

Peter Naur from Copenhagen was around 1965 the first to contribute to the art of reasoning about programs in the little article in which he launched his “general snapshots” (which later would be called ”assertions”). Due to the limited circulation of the Journal BIT in which it was published it did not get the attention it deserved. He was followed by Robert W. Floyd from Stanford with the paper on assigning meanings to programs. This was a fundamental paper in that it tackled both correctness and termination: the fact that he phrased the problem for programs as unstructured as an arbitrary flow chart made his paper at the same time general and unattractive. Half-way the decade, the goto-statement had been identified as a complexity generator and by ignoring it Tony Hoare, at the end of the decade, nicely tied the proof obligations to successions, conditionals, and repetitions, three concepts that are explicitly reflected in the syntactic structure of the program. It was at the time, however, unclear whether Tony Hoare’s axiomatic basis for computer programming was based on a programming language semantics defined --presumably operationally-- somewhere else, or whether all by itself and on its own, it could be taken as the definition of the language semantics. A further departure from operational considerations took place in the 70s with the introduction of predicate transformers. They allowed the definition of programming language semantics without any reference to computers, their components or, most importantly, their activity, and thus it became possible to reason about programs while ignoring that the program text admits the interpretation of executable code as well. Programming was becoming of age.

Of course it is not enough to know how, in principle, one can reason about a program, for in practice the amount of reasoning required must be doable. The period I described reduced the amount of reasoning required by two devices, viz. structuring and abstraction. The latter abstracted away from the combinatorial explosion inherent in considering individual computations, i.e. sequences of individual states, while structuring contributed to the disentanglement of arguments.

Life continued and program structure become more widely exploited. Dana S. Scott showed the relevance of lattice theory to the programming world, which, attracted by its simplicity, then used it for its own purposes: in the refinement calculi it found ways of using structure to exploit the kind of monotonicity arguments lattice theory supports.

In some ways programs are among the most complicated artefacts mankind ever tried to design, and personally I find it fascinating to see that reasoning about them is so much aided by simple, elegant devices such as predicate calculus and lattice theory. After more than 45 years in the field, I am still convinced that in computing, elegance is not a dispensable luxury but a quality that decides between success and failure; in this connection I gratefully quote from The Concise Oxford Dictionary a definition of ”elegant”, viz. ”ingeniously simple and effective”. Amen. (For those who have wondered: I don’t think object-oriented programming is a structuring paradigm that meets my standards of elegance.)

On the whole, the period after 1970 showed a lot of progress. Pascal, designed by Niklaus Wirth from Zürich, had a wholesome influence worldwide on the teaching of programming, we got typed functional programming languages, logic programming entered the scene and disciplines for parallel programming emerged and were taught.

In retrospect it looks like a kaleidoscopic activity! It was. The turning point had been the NATO conference on Software Engineering at Garmisch-Partenkirchen in 1968, a conference that had been organized by Friedrich L. Bauer from Munich. It was there and then that the so-called ”Software Crisis” was admitted and the condition was created under which programming as such could become a topic of academic interest.

The latter, not surprisingly, turned programming from an intuitive activity into a formal one in which the program is derived by symbolic manipulation from its functional specification and the chosen form of correctness proof. In this connection the names of Ralph-Johan Back from Turku, Richard S. Bird and Carroll Morgan from Oxford and Wim Feijen from Eindhoven must be mentioned (with my apologies to all others whose names have been left out). David Gries published his ”The Science of Programming”, journals like ”The Science of Computer Programming” began to appear, and in the mean time the world has seen 4 conferences devoted to ”The Mathematics of Program Construction”, held in the Netherlands, England, Germany and Sweden respectively.

As you may have noticed, with the exception of Ithaca, the home town of David Gries, that I left out, all affiliations are European. We must come to the conclusion that, like Love, the mathematization of computer programming is a bad sailor. At the American side the whole idea of correctness by construction, of developing the program and its correctness proof hand in hand has been rejected, and we have to understand why, for if we are planning our future, we had better establish whether the idea has been rejected here because the idea is no good or whether this society has rejected because it is not ready for it. I’m afraid that all symptoms point into the direction of the latter.

• The ongoing process of becoming more and more an amathematical society is more an American specialty than anything else. (It is also a tragic accident of history.)

• The idea of a formal design discipline is often rejected on account of vague cultural/philosophical condemnations such as ”stifling creativity”; this is more pronounced in the Anglo-Saxon world where a romantic vision of ”the humanities” in fact idealizes technical incompetence. Another aspect of that same trait is the cult of iterative design.

• Industry suffers from the managerial dogma that for the sake of stability and continuity, the company should be independent of the competence of individual employees. Hence industry rejects any methodological proposal that can be viewed as making intellectual demands on its work force. Since in the US the influence of industry is more pervasive than elsewhere, the above dogma hurts American computing science most. The moral of this sad part of the story is that as long as computing science is not allowed to save the computer industry, we had better see to it that the computer industry does not kill computing science.

But let me end on a more joyful note. One remark is that we should not let ourselves be discouraged by the huge amount of hacking that is going on as if computing science has been completely silent on how to realize a clean design. Many people have learned what precautions to take, what ugliness to avoid and how to disentangle a design, and all sound structure systems “out there” sometimes display is owed to computing science. The spread of computing science’s insights has grown most impressively, but we sometimes fail to see this because the number of people in computing has grown even faster. (It has been said that Physics alone has produced computing ignoramuses faster than we could educate them!)

The other remark is that we have still a lot to learn before we can teach it. For instance, we know that for the sake of reliability and intellectual control we have to keep the design simple and disentangled, and in individual cases we have been remarkably successful, but we do not know how to reach simplicity in a systematic manner.

Another class of unsolved problems has to do with increased system vulnerability. System get bigger and faster and as aresult there comes much more room for something to go wrong. One would like to contain mishaps, which is not a trivial task since by their very structure these systems can propagate any bit of confusion with the speed of light. In the early days, John von Neumann has looked at the problem of constructing a reliable computer out of unreliable components but the study stopped as von Neumann died and transistors replaced the unreliable valves. We are now faced with this problem on a global scale and it is not a management problem but a scientific challenge.

If I were younger I would try to find a mathematically meaningful definition for the complexity of interfaces between the components of proofs and other sophisticated discrete systems, and I would look for lower bounds, but I leave this in confidence to the next generation: either they come with a more beautiful theory than I would ever have concocted, or they come with something of more significance.

I thank you for your attention.

[Keynote address to be given on 1 March 1999 at the ACM Symposium on Applied Computing at San Antonio, TX]

prof. dr. Edsger W. Dijkstra
Department of Computer Science
The University of Texas at Austin
Austin, TX 78712-1188 USA

Transcription by Jorge Andrés Pérez.
Last revised on Fri, 4 Apr 2008.

EWD1285

To Cambridge by mistake (12–18 April 1999)

Of course it did not help that, when I left on Tuesday afternoon, I was upset and rather depressed. In the morning I had listened to a faculty candidate and that had been a pretty awful experience. You see, a few years ago graduate students believed that the use of LATEX was enough to write a scientific article; these days faculty candidates seem to think that they can give a scientific lecture provided they have played enough with Powerpoint. That morning the visual noise had been exceptionally confusing; the majority, however, did not seem to mind or to notice, and that had been distressing. Until Chicago I have been pondering about this society's systematic refusal to analyse the adequacy of its chosen means of expression, and these were sad thoughts.

The occasion was "EDSAC 99", a celebration of the fact that 50 years ago —well: 6th May 1949— the EDSAC (= Electronic Delay Storage Automatic Computer) executed its first programme. Since the EDSAC was the first stored-programme computer to do so, this was something to commemorate. [This first programme printed a table of squares. The next day, 7th May 1949, this program still works, but the effort to print a table of primes fails: "programme incorrect" mentions the log book.] I was invited in my capacity of alumnus of the programming course that Wilkes, Wheeler and Gill gave in September 1951, and since those few weeks changed my life, I decided to attend.

My reasons for taking that decision were not very strong. It was some sort of symbolic act of gratitude, of the trio Wilkes - Wheeler - Gill, the last one had died a long time ago but I felt that this might be the last occasion to meet the other two together, and, finally, it could have been a consideration that with my retirement approaching, this could be about my last opportunity "to walk around", something I have hardly done during the 15 years my endowment enabled me to do so. With nice weather Cambridge is, of course, quite a pleasant place to visit, but apart from that I was not particularly looking forward to my visit: I expected very few friends to show up and with blank paper and things to be studied I prepared myself for a relatively lonely visit. It turned out to be a good thing that I had done so.

I travelled with American Airlines via Chicago. The flight to Chicago was 25 minutes late and both dishes they served I had to reject because they contained cheese. Despite the late arrival I caught my Chicago connection. On the second flight I got dehydrated as immediately after the meal I fell asleep, and slept almost until arrival at Heathrow.

On British soil the misery started. It was a pure accident that I found the coach to Cambridge, the address of the Holiday Inn was a well-guarded secret so that I could not find the hotel on the little map the Computing Lab had sent me. The official address of the Lab is New Museums Site (the map only mentioned "Museums") at Pembroke Street (not mentioned on the map) but the Lab should be entered by Corn Exchange Street (not mentioned on the map either). Having found the complex, I needed another 45 minutes to locate Beth Want, the secretary responsible for the organisation of the event. The only information she could give me was a list of participants (no more than title, first name and last name, and that often incomplete). Not being given any clue where to find the other participants —she could not tell me if others shared my hotel— I returned to my room, had a modest meal and went to bed.

The festivities started next morning at 11:00 in the foyer of the Charles Babbage Theatre. Because it was bitterly cold, everybody came with a coat, but there were hardly hooks to hang them on. (Later I heard that they could have rented hall-stands, but that the insurance would have been too expensive.) They had no name tags! Later glue-on labels were provided, but most participants did not use them. Consequently I hardly succeeded in meeting people whose names I knew —say Larry Paulson— but whom I had never met. I said "Hello" to David Wheeler and to Maurice Wilkes not even that: when I approached him, somebody else drew his attention and he turned away. Not wanting to risk creating an embarrassment, I did not repeat the effort. (In the mean time I had learned from Peter Wegner that he had attended the previous evening a dinner party at Wilkes's home, a reunion I had evidently not been invited to.)

In the afternoon we were addressed. After an impeccable introduction by Robin Milner (the current Director), there was a very nice talk by Maurice on the earliest year, giving credit where credit was due and delivered with great charm. Then David Wheeler on EDSAC 2, and you could not think of a greater contrast: David seemed completely uninterested. I always thought that a major advantage of microprogramming was that a larger fraction of the design could be justified by discrete reasoning, but David only mentioned the simplification of the production process. After a break of 30 minutes a video of interviews with Computer Laboratory engineers, a talk on Titan by Roger Needham, whose diction still causes me problems, and David Hartley, who had to read his text a fraction too fast for comfort. (All the speakers displayed an admirable timing discipline!) After a reception in the University Combination Room we had a dinner in St. John's College Hall that was not worth the $56 I had paid for it, but this is no reason for regret for I had it in the pleasant company of A.S.Douglas and his wife.

The next morning we had talks from 9:00 to 12:30. Dr. Frank King was, I think, the most sparkling speaker, Ian Leslie, clear, compact, and to the point, was also a pleasure to listen to. Michael Gordon made his points and was okay, the other speakers —some horrendous— will remain anonymous.

The whole affair was a bit self-congratulatory and nostalgic, but it was okay. I was, however, a bit disturbed by an undertone of complaint about a lack of recognition for all the Great Things the Cambridge Computing Laboratory had done since EDSAC 1. Everybody knows that it is not simple to live with a spectacular success in your past, and if the completion of EDSAC 1 represented the Laboratory's finest moment, that was nothing to be ashamed of. (We had come to celebrate that completion, hadn't we?) They confronted us, however, with what struck me as an exaggeration of the significance of later achievements. (They were even praised for how well they had copied MIT!) I also sensed traces of envy. I hope it is better now under its new director Robin Milner, for the laboratory does not seem to have always been a happy place.

Early Friday afternoon we were finished. I would have preferred to fly back on Saturday but that would have made my airline ticket so ridiculously expensive that I have "earned" money for the University by staying a day longer in England. I went to Dillons where I bought two autobiographies, one by Sir Georg Solti and one by Katharine Graham (both printed and bound in Great Britain). By the time I got home I had almost finished Solti.

Friday night I stayed in Cambridge, Saturday I went to Heathrow where I stayed in the International Hilton Hotel, a very modern, beautiful building in which you don't hear the planes. At 5 o'clock in the morning I did hear someone else's alarm clock; I did not sleep anymore, and that was a good thing. In the evening I had not succeeded in setting via the telephone my wake-up call (though I had faithfully followed the instructions), so I went to the reception where a lady said "We can do it for you", disappeared for 30 seconds and returned saying "Done!". But the next morning I did not get my wake-up call! They do not have their act together.

Austin, 30 April 1999

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Tristram Brelstaff
revised Sun, 9 Dec 2007

EWD1287

Dear Tony, dearest Jill, and other people, dear or not,

I would like all of you to realize that this is almost certainly Tony's last retirement because, now he is back in the folds of industry, he is all but certain to stay there until his dying breath. But when we address him then for the last time, at the side of his grave, when he can no longer hear what we say about him, tradition requires —"De mortuis nil nisi bene" and all that— that we say nice things only. This creates obligations for now, as it means that this is our last opportunity to be nasty. But have no fear: to help me, Tony once wrote me a list of techniques by which I could make my pronouncements less offensive. It is up to you to judge how successful a teacher he has been.

If I may, I would like to compare the two of us for a moment, because our two professional lives have been somewhat intertwined. The first time we met was in 1961 and neither of us remembers it. It was a lecture series on ALGOL 60 at Brighton. I can be forgiven that I don't remember Tony for I was one of the few speakers and he was only a participant in the audience. His amnesia is harder to forgive, but he has explained it to me by the presence of Peter Naur, the other bearded speaker with a continental accent, claiming that in his memory Peter and I merged into one person. Clearly he was not impressed. My personal explanation is that Tony's attention was distracted by the presence in the audience of a charming lady by the name of Jill Pym, whom I don't remember either.

The overwhelming similarity between the two of us is the absolutely flimsy ground on which people have been willing to grant us our fame, viz. a juvenile programming exercise and a bon mot. In my case they were a graph algorithm and a disparaging remark about program testing, in Tony's case they were Quicksort and the remark that "there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies". (End of comparison.)

A major question to be answered is how Tony could become such a successful professor of computing while his formal education —the usual Oxford stuff of those days— was so defective: economics, some applied probability theory and an unhealthy dose of philosophy, the unscientific non-discipline par excellence. There are four answers to this question.

The first answer, of course is that as an academic he did not succeed at all, he just posed as a scholar, while deep in his heart he was no more than an industrialist, a politician and a manager. Indeed, in the form of Elliott Brothers and Microsoft, industry has formed the alpha and omega of his professional life. This would have been forgivable if, in between, he would have been a faultless member of the academic community, but during his Belfast and Oxford years, besides being a director of the laboratory, he has also been heavily involved in IBM's PL/I, in the DoD's Ada and with Inmos in Occam, that it is a safe assumption that he could not combine this with his true professional duties.

The second answer is that his seemingly impressive scientific output was not his own but was written by his friends. He has always been a great master in sending out highly original but also totally immature drafts for debugging to a bunch of his cronies, who would then rewrite one out of every five sentences. He is also —as a true Anglo-Saxon— an extremely iterative text composer, who would often circulate five successive versions before official publication of the final text; you may draw your conclusions. As you may have noticed, I essentially stopped correcting his writings in the mid-eighties.

The third answer is that, years before his Belfast appointment, he had already earned his educational laurels by the design of ALGOL W, which for a decade has been the preferred language for introductory programming courses at the most enlightened American universities. ALGOL W's distinguishing feature was the incorporation of the "record", a data-structuring device Tony had invented. When he sent me his proposal in 1965, I tested it with a new coding of the shortest-path algorithm, and the new text was a great improvement over its predecessors, an improvement which was enhanced by the absence of goto statements. We agreed with each other's simplification efforts. I think that correspondence marks the moment after which we viewed each other as colleagues.

The fourth answer is that his defective Oxford education forced him to be an autodidact for the rest of his life. That has required much intellectual effort and a lot of hard work, but has had one valuable consequence: he grew up without a scientific model to emulate and thus became as [a] scientist absolutely unique.

This is not the place to give a complete enumeration of all the work he claims to have done, but we can give some idea of the influence he has had, i.e., of how he has impacted the world (as we Americans say), and also of how he has totally failed to have any noticeable influence.

Let us focus on some noticeable influence first, and let me state right at the beginning that it is widely regarded to have been, if not downright disastrous, at least very detrimental to the health of mathematics. I am referring to a development for which Tony may not be solely responsible but certainly can be considered the main culprit, and which, for lack of a better name, I shall refer to as "calculational mathematics". It started with his 1969 paper on the axiomatic basis for computer programming, which presented programming as a mathematical task in which the predicate calculus played an essential, central role. The mathematicians at the time knew no more about the predicate calculus than that it was something logicians talked about and were in general horrified by the suggestion that it [could], or even should become an indispensable tool for daily reasoning. A confession of mine may underscore how revolutionary these thoughts were at the time. For one or two years, the paper on the axiomatic basis failed to excite me and when I then saw Tony's correctness proof of the program FIND, my reaction was this ballet of symbols was not my cup of tea! Obviously, tea is a acquired taste, and some mathematicians never get it. Tony, however, liked tea years before the others.

But Tony knew full well what he was doing and can pride himself on having been rejected by the establishment. One of his letters contains a long and infamous quotation from Paul Halmos, arguing the foolishness of this type of calculational mathematics, but unrepenting he introduced the relational calculus into computing science, and next designed a more calculational approach to category theory, thereby again horrifying a section of the mathematical world. But all this was done without ill feelings: after a bitter complaint of mine about the obscurity of mathematical writings, reprimands me on 29 Dec 1983 with "You should have more sympathy with mathematicians — they find their subject as hard to understand as you do.".

So much for influence he did have; let me now give you an example of a lot of hard work done by Tony that had no effect at all: that was whenever he tried to get others to keep their language designs clean and simple. The first example dates from the 60s: he has been unable to prevent ALGOL 68 from being inflicted upon Mankind. (Fortunately, Mankind turned out to be rather resistant.) Then, for about 10 years, I think, he has been involved in trying to get PL/I clean enough for standardization, but to no effect, for the irrevocable harm had already been done. (In this connection, I am happy to report that PL/I has died: we now get graduate students who have never heard of PL/I. There seems to be some progress.) And finally, out of a sense of public duty, he has spent years trying to protect the DoD from making its overambitious mistakes. Again to no effect, and he suffered from that, as is shown in his letter of 25 March 1978, pointing out why IRONMAN, the next version of the requirement specifications for Ada, was so "misguided and dangerous":

"You cannot improve a compromise by asking it to meet more exactly the irreconcilable objectives which it was trying to compromise between. And especially not if you add a few more irreconcilable objectives! Oh dear, how can we ever make them see sense?".

Well, we couldn't. The quoted cri de coeur was at the bottom of p. 6; on p.3 he had explained why philosophy had been his favourite subject at Oxford.

This was in the part of the letter that was concerned with the work of George Spencer Brown. As by now you may be suspecting, the range of topics covered and moods reflected is quite wide. For instance, on 16 July 1977 he writes:

"I hope you had a pleasant holiday and that you are continuing to make a good recovery from it.".

while 3 years later he writes —on p. 8, after 7 pages of technical material—

"Last week I got a nice telephone call from the chairman of the Turing Award Committee, and I accepted.".

I must confess that I am not quite sure about my rights to quote from his letters to me: the law seems to be that, while the letters are mine, the copyright is his. So, for safety's sake I take my final, somewhat longer quotation from one of Tony's public manuscripts. I shall first read from the quotation and then tell you when it was written.

"So it is among the prophets of doom that I wish to enrol myself. I believe that the current situation in software design is bad, and that it is getting worse. I do not expect that this will be recognised by the designers, manufacturers, sellers, or even the users of software, who will regard the increase in complexity as a sign of progress, or at least an inevitable concomitant thereof; and may even welcome it as a tribute to their intelligence, or at least a challenge. The larger manufacturers are not only set in their ways, but they have actually profited from the increase in complexity of their software, and the resulting decrease in the efficiency and effectiveness of their customers' use of hardware. And everything is now so complicated, that any particular attack on the problem of low quality software design can always be evaded by appeals to tradition, to standards, to customer prejudice, to compensating advantages, and even to promises to mend the fault in future issues.

So it will be a long time before there is even any recognition of the problem which faces our profession. But even if the problem were widely recognized and deplored, its solution is going to present extremely difficult technical problems. The pursuit of complexity is easy, and the implementation of complexity can safely be delegated to competent managers. But the pursuit of simplicity is one of the most difficult and challenging activities of the human mind. Progress is likely to be extremely slow, where each complexity eliminated must be hailed as a breakthrough. we need not only brilliance of intellect but breadth of experience, nicety of judgement, excellence of taste, and even more than our fair share of good luck. And finally we need a puritanical rejection of the temptations of features and facilities, and a passionate devotion to the principles of purity, simplicity and elegance."

Tony wrote the above in 1974, and it reveals that already 25 years ago, he had a clear vision of the shape and of the science that Academia would have to create, notwithstanding the somewhat discouraging circumstance that would consider that creation a superfluous and futile exercise.

But we can also read these paragraphs differently. We can read them as a very personal statement of what he intended to do with the rest of his professional life, and then we can only admire his courage and dedication, and marvel at the accuracy of his prediction: he has indeed displayed "a passionate devotion to the principles of purity, simplicity, and elegance". Tony earns our deeply felt admiration and gets it, however not without the simultaneously expressed, equally deeply felt gratitude to Jill, who has made all this possible by sharing with him the joys (and sorrows) of Life.

prof. dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Tristram Brelstaff
revised Wed, 5 Dec 2007

EWD 1288

Ulrich Berger’s argument rephrased

We introduce a special type of line integral, the “contour integral”, in which the differential dc is an infinitesimal vector along the tangent. [With s the length along the contour, we have

dc = (cos.φ ds, sin.φ ds).]

We only consider clockwise integrals along closed contours; hence the law ∮dc = (0,0).

We now consider for a vector field f and some contour the contour integral ∮f.(x,y)•dc, where • denotes the scalar product. We don’t need to consider “bagels” with a hole in them

for the above two figures have equal contour integrals because the two contributions along the cut cancel.

Similarly, when we consider —like a jigsaw puzzle— a figure partitioned into a finite number of pieces, then the contour integral of the whole equals the sum of the contour integrals of the pieces. (We refer to this as “the Law”.)

Note   For   f.(x,y) = (y,0)   or   f.(x,y) = (0,–x), the contour integral equals the area enclosed by the contour, and indeed: the area of the whole jigsaw puzzle equals the sum of the areas of the pieces. (End of Note.)

*         *         *

We only consider rectangles with horizontal and vertical sides. A rectangle is called nice when in at least one direction it has sides of integer length. The theorem to be proved is that in the case of a large rectangle R partitioned in a finite number of little rectangles r, rectangle R is nice if all rectangles r are nice.

We demonstrate that, with all rectangles r nice, R has an integer width w when its height h is noninteger. We do this by introducing an f such that

(i) | the contour integral of R equals w
(ii)   | the contour integral of each r is integer.

The Law then allows us to conclude that w, a sum of integers, is integer.

When we place R with its bottom at y=0 (and, hence, its top at y=h), some reflection shows that this is, for instance, realized by

f.(x,y) = (if y is integer → 0 ▯ y is not integer → 1 fi, 0)

ad (i).   Only the top side, of length w, contributes to the contour integral of R, 0 being integer and h not.

ad (ii).   For a rectangle whose vertical sides are of integer length, the contributions along its horizontal sides (zero or not) cancel, and for a rectangle r whose horizontal sides are of integer length, the contributions along its horizontal sides (zero or not) are integer; in either case, nice rectangle r has a contour integral of integer value.

Nuenen, 8 September 1999

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Corrado Cantelmi
revised 18-Mar-2012

EWD1290

Eliminating cascading carries

In this note we describe an adder for numbers in the following decimal representation

(0)     n = 〈 Σ i : 0≤i : di∙10i 〉

(1)     −5 ≤ di ≤ 6 for all i    .

All integers can be represented this way, but note that the representation is not necessarily unique: for instance, 26 can be represented in two decimals by (2,6) as well as by (3,−4).

In our "adder", which can calculate ±a±b, the sum of two digits ranges from −12 through +12; its addition table represents these values as c∙10 + s —from "carry" and "sum digit"—, with c, s satisfying

(2)    −1 ≤ c ≤ +1 and −4 ≤ 5 ≤ +5     ,

i.e., | from | −12  | through |  −5, | c = | −1 |      , |
| from | −4  | through |  +5, | c = | 0 |      , |      and
| from | +6  | through |  +12, | c = | +1 |  |   .

Because (2) excludes for s the extreme digit values −5 and +6 and |c| ≤ 1, each sum digit can absorb a carry from the right without generating a new one. In long parallel adders the problem of carry propagation has thus been eliminated; alternatively we can add from left to right with a "look-ahead" of only 1 position.

Remark If we so desire, we may replace (1) by the weaker, symmetric −6 ≤ di ≤ +6. with (2) weakened accordingly, some freedom in the addition table is introduced. (End of Remark)

Please note that (i) the representation of zero is unique, and (ii) the sign of a non-zero value is determined by the sign of its most-significant non-zero digit.

The above, which was designed decades ago, was inspired by the implementation of the end-around carry in the serial adder of the ARMAC. Since the advent of systolic arrays it must look like something familiar.

Austin, 23 September 1999

Prof.dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Hai Zhou
revised Wed, 28 Nov 2007

EWD1292

When a symmetric operator distributes over ↑ and ↓

To begin with we postulate (0) and (1):

(0)    relation ⊑ is reflexive and antisymmetric,

i.e., for all x, y

x=y ≡ x⊑y ∧ y⊑x

(1)    for any x,y there exists a (unique) value, which we denote by x↑y, that satisfies for all z

x↑y ⊑ z ≡ x⊑z ∧ y⊑z .

Remark Since the uniqueness can be proved, it need not be postulated; hence the parentheses. (End of Remark.)

It then follows that (for all x,y)

(2)    ↑ is idempotent, symmetric, and associative

(3)    x ⊑ x↑y

(4)    x = x↑y ≡ y⊑x

(5)    ⊑ is transitive (hence —see (0)— ⊑ is what is known as “a partial order”)

(6)    ↑ is monotonic

We'll just prove (6).

Proof We calculate for any triple x,y,z :

x↑z ⊑ y↑z

≡ {(4)}

y↑z = (y↑z)↑(x↑z)

≡ {(2)}

y↑z = (y↑x)↑z

⇐ {Leibniz’s Principle}

y = y↑x

≡ {(4)}

x ⊑ y

To the above we add “the dual” (0′) through (6′) obtained from (0) through (6) by

(α) interchanging the arguments of ⊑ , and

(β) replacing ↑ by ↓ and vice versa.

Remark The reader may note that, thanks to the symmetry of ∧ , (0′) is equivalent to (0). The “and vice versa” has been added so as to make (β) —like (α)— its own inverse. (End of Remark.)

And this concludes our summary of Lattice Theory.

*               *
*

Now we are ready to formulate and prove the following simple theorem.

Theorem Let the symmetric infix operator ● distribute over ↑ and ↓ Then

(7)    (x↑y)●(x↓y) = x●y

Proof To begin with we observe for any x,y

(x↑y)●(x↓y)

= {● distributes over ↑}

(x●(x↓y))↑(y●(x↓y))

= {● distributes over ↓, twice}

(x●x ↓ x●y)↑(y●x ↓ y●y)

⊑ {(3') and (6), twice}

x●y ↑ y●x

= {symmetry of ● , idempotence of ↑}

x●y ,

i.e.,

(8)    (x↑y)●(x↓y) ⊑ x●y . .

By dualization we conclude from (8):

(8′)    x●y ⊑ (x↓y)●((x↑y) ,

and thanks to the symmetry of ● and (0), the conjunction of (8) and (8′) yields (7). (End of Proof).

*               *
*

The above theorem and proof emerged yesterday afternoon when K. Rustan M. Leino joined the session of the ATAC and wanted to show us some aspects of his proof of the fact that the product of two natural numbers equals that of their GCD and their LCM (what he did). The decision to go from there to lattices in general was a minor step. Acknowledgements are further due to Dr Rajeev Joshi, who contributed to what we presented here.

Austin, 6 October 1999

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Hasnain Mujtaba
revised 08-Jan-2015

EWD1297

Triggered by a high-school exercise

In this note, “fractions” are restricted to quotients of positive integers. If a/b and c/d are two such fractions of different values, one is asked to construct a third fraction that lies between them.

The book in which we met this problem —a textbook of Anuj Misra’s— started by giving the fractions equal denominators, so 2/3 and 3/4 would become 8/12 and 9/12, but then the problem is that there is no integer between 8 and 9; this is overcome by introducing an extra factor of 2, so that the fractions become 16/24 and 18/24 and the answer 17/24. When, later, I started to discuss this problem with an American colleague, he came up with the same solution, which made me wonder whether I had met a cultural difference between two continents because, spontaneously and indepedently, Ria and I had reacted with “What about (a+c)/(b+d)?” The reasons for writing this little note, however, are my experiences in proving the correctness of the this hunch.

I first came up with a visual proof, and later with a calculational one. In both proofs we restrict ourselves to

(0)          a /b < c /d

The visual proof

Connect the points (b, a) and (d, c) to the origin and complete the parallelogram

Because of the monotonicity of the tangent in the 1st quadrant and the fact the diagonal of a parallelogram lies inside that parallelogram, i.e., between the two sides, we conclude

(1)          a /b < (a+c)/(b+d) < c/d

The calculational proof

For the left inequality of (1) we observe

a /b < (a+c )/(b+d )

≡          { b · (b+d ) > 0 }

a · (b+d ) < (a+c ) · b

≡          { algebra }

a · d < c · b

≡          { b · d > 0 }

a /b < c /d

A similar proof shows that also the right inequality of (1) is equivalent to (0), to which we could restrict ourselves “without loss of generality”.

*            *
*

It was a few days after the problem had been shown to us when I realized that I had not taken the trouble to prove the correctness of our hunch; after a while, the visual proof came to the mind, and I must confess that it convinced me.

It was another few days later when my mind returned to the visual “proof” and I realized how shaky it was and how much it had left unsaid. It draws “conclusions” from the loosely stated fact that the diagonals lie “inside” the parallelogram, but how to prove that? In all probability by proving (1)! By not being explicit about the rules of the game and appealing to “the visual intuition” instead, one introduces a lot of ambiguity about the whole enterprise of proving. No wonder that the kids at school get confused!

After all the above I began to wonder what went into the construction of the hunch: certainly neither of the two arguments shown above. I was at least familiar with the following ingredients:

(i) fractions are monotonic functions of their numerators and antimonotonic functions of their denominators,

(ii) the whole problem is in a sense insensitive to a systematic replacement of a /b by b/a, etc.,

(iii) the problem is symmetric in the two given fractions —the word “between” makes it that—,

(iv) the sum is the first symmetric, monotonic function of integers that comes to my mind.

That probably suffices.

Austin, 16 March 2000

prof.dr. Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Bart Vreugdenhil
revised 30-Dec-2011

EWD1298

Under the spell of Leibniz's Dream

Recently, when it dawned upon an undergraduate student that I had been introduced to automatic computing in 1951, he reacted with "Wow! Then even my parents were not born yet.", thus driving home the message that, indeed, the outstanding feature of my professional career could very well be its length. It has been a long time indeed, and if I had to characterize those almost 50 years, the first characterization that came to my mind was "Half a century of change.". My personal experience of change has, of course, been intensified by my switch from one continent to another, from one civilization to a very different one, thus almost doubling the set of experiences I had to integrate

You should realize that I grew up in a very simple world. During the German occupation, the manifest lawlessness made that the distinction between the Good Guys and the Bad Guys was no problem at all. Life remained simple for about two decades after the Liberation by the Allied Forces (to whom I shall remain grateful for the rest of my life and beyond), because WWII had left my country in such a complete shambles that everyone agreed that restoration of our infrastructure was the first thing to be done. Before that task had been completed, a devastating flood showed the need for what became known as "the Delta Works". The urgency and scope of these undertakings gave to many endeavours a unique sense of purpose which in retrospect should be viewed as a luxury: we never needed to wonder what to do next. On the contrary, for each of the new machines that were built at the Mathematical Centre in Amsterdam, urgent work was waiting before the machines were operational. For the first X1 I changed one of the first programs because one of the ferrite cores in memory was broken and could store only one value, but the show had to go on!

An important side-effect of the hard times was the creation of a spiritual climate in which the distinction between pure and applied science had vanished: of all the things you could do, you just did the most urgent one, and the development of some urgently needed theory was often the most practical thing to do. It was my privilege to grow up in that spiritual climate, and the conviction that what is theoretically beautiful tends to be eminently useful has been an article of my faith ever since: in the design of sophisticated digital systems, elegance is not a dispensable luxury but a matter of life and death, being a major factor that decides between success and failure.

In 1969, at the NATO Conference on Software Engineering Techniques in Rome, I called the distinction between practical and theoretical people "obsolete, worn out, inadequate and fruitless", angrily adding that I absolutely refused to consider myself as either impractical or not theoretical. But times have changed. These days there is so much obsession with application that, if the University is not careful, external forces, which do make the distinction, will drive a wedge between "theory" and "practice" and may try to banish the "theorists" to a ghetto of separate departments and separate buildings. A simple extrapolation will tell us that in due time the isolated practitioners will have little to apply; this is well-known, but has never prevented the financial mind from killing the goose that lays the golden eggs. The worst thing with institutes explicitly devoted to applied science is that they tend to become institutes of second-rate theory.

But I am rushing ahead. During WWII, the Universities had been closed; when I enrolled in 1948, there was still a lot of catching up to be done, and I remember that Leyden University was a very crowded place. The ideal to extend higher education to a larger fraction of the graduating high school population existed, but for a decade or so it did not really materialize, just for lack of space and lack of facilities. It was only after my graduation that the Universities stopped being the elite institutions that they used to be.

The envisaged growth of the university system was viewed with grave suspicion. I remember how, in 1955, one of my great-aunts felt that starting a new technological university in Eindhoven was a stupid idea, for she did not see how they were ever going the find faculty for it that was sufficiently bright and decent. A decade later, I was on the faculty of that university myself, and I must admit that, indeed, the old lady's misgivings had not been misplaced.

In the 50s, the university population really began to grow, the faculty, the student body and the goals of the university, they all became more diversified and it was not a happy mix. I was regularly reminded of a remark by Antoine de Saint-Exupéry that it is Man's predicament to have to plan for tomorrow in yesterday's language: the outstanding feature of faculty meetings was the general dishonesty, because linguistically we were still pretending to strive for perfection and to conduct a first-rate enterprise while we all knew that mediocrity was taking over.

The students were not happy either. While faculty complained that they could not maintain standards, students were frustrated by demands they were not used to, such as clarity of diction and correctness of spelling and grammar. They also felt cheated: going to University had been presented to them as the privilege of being admitted to an exclusive group, but as a result of their sheer numbers, the group was no longer exclusive.

Around 1968, the time bomb exploded and worldwide the student revolutions broke loose, buildings were occupied and on campus, mob rule reigned. The revolution was successful in the sense that, when the dust had settled, the old university was no more. Under slogans like "Education for the People by the People", maintaining intellectual standards was presented as something immoral and striving for perfection —traditionally the raison d'être of the academic enterprise— was discarded as "elitist" and hence "undemocratic". For a lecture course on a formal topic like program correctness, the climate had become less than ideal, for the whole preposterous idea that programs should meet formal specifications was clearly only pushed by an older generation that wanted to stay in power and to that end tried to prolong the circumstances in which their better education gave them the upper hand. Political sloganeering knew no limits; half a decade later, an Australian columnist would relate mathematical discipline to fascism and would explain that from Wirth and Dijkstra, coming from Germanic countries, you could expect no better than sympathy for such stifling rigour, but that he totally failed to understand how the freedom-loving Anglo-Saxon Hoare could join that crowd.

But I digress. Within two student generations, i.e., about 10 years, the revolutionary zeal had petered out, and it looked as if on campus life was back to normal, but that appearance was very misleading. The whole turmoil had caused major shifts in the power structure, in the role of money, and in the intellectual quality of the whole academic enterprise.

I grew up with an advice of my grandfather's: "Devote yourself to your most genuine interests, for then you will become a capable man and a place will be found for you.". We were free not to try to become rich (which for mathematicians was impossible anyhow). When Ria and I had to decide whether we should try to start a family, we felt that we had to choose between children and a car; Ria had a Raleigh, I had a Humber, we decided that they were still excellent bicycles and chose the children. Today's young academics, whose study is viewed as an investment, should envy us for not having grown up with their financial distractions. The other day I saw a telling symptom of how the business world is encroaching on our peace of mind. For a number of years I now give each semester one lecture to a class of software engineering students, who then write down their comments on my performance, and these are revealing; for instance, they used to refer to my contributions to computer science, but the last time they just referred to my contributions to "the industry". This was a telling but innocent symptom, but there are much more serious ones, such as the retention problem. For some undergraduates the major computer science problem seems to be in which month to drop out so that they can become a billionaire, and in the more pragmatic graduate schools it becomes very difficult to attract Ph.D. students because their target audience is just as happy to go to industry directly. About 10 years ago I tried to make up my mind on the question whether Computing Science could save the computer industry, and my conclusion was negative; since then I felt it my duty to try to prevent the computer industry from killing Computing Science, but I doubt that I have been successful....

But, worried as I am by the monetary distortion of our academic value system, I am even more worried by another development over the last fifty years, and that is the general loss of respect for each other, and if that is the price to be paid for the growth of the academic enterprise, we may ask indeed whether that price was not too high. Observing in Leyden our fellow students, we quickly saw that some shouldn't have enrolled; the others soon coalesced into a support group for which mutual trust and respect provided the glue, and it is quite possible that I have learned more from my fellow students than from my professors. Observing our professors, we soon decided that a few appointments had been mistakes; for the others we had the greatest admiration, and I remember that we felt proud to be their students. Conversely, our professors treated us with respect: we were treated as the next generation that had to provide their successors.

But things have changed. These days it is quite common that students don't even know the name of the person who is lecturing to them, let alone that they feel proud to be his student! And it is equally common that faculty talk about students, in particular undergraduates, as if they were animals from another planet. Students are no longer seen as part of the solution, but as part of the problem, and textbooks and lecturing techniques have become so condescending that, if I were a student, I would take offence. I don't think that I could stand a lecturer that assumes that my attention span is no more than 7 minutes or who feels obliged to feed me a cartoon every 5 foils, and subjects me to multiple-choice tests because I am supposed to be functionally illiterate. I invite you to read carefully the catalogues of publishers of mathematical textbooks: obviously, colour math is better than B&W math, most books are recommended for being intuitive instead of formal, for being chatty instead of crisp, for being vague and sloppy instead of rigorous. It is clearly an article of the New Faith that teaching the real thing would be counter-productive: just as our students are supposed to live on junk food, they are supposed to thrive on junk science.

The loss of mutual respect has affected more than just the educational process, it has corroded publication as well. In 1975 I received a letter that objected to the style in which I had written an article for the Communications of the ACM (= Association for Computing Machinery). The complaint was that, by separating my concerns more strictly than usual, I had addressed my intended audience in a style they were not used to. The writer continued with the well-known quotation from P.T.Barnum that "No one ever got broke by underestimating the intelligence of the American people." and urged me to bear that in mind whenever I wrote for the programming community. So, 25 years ago, the rot had already set in; at the end of the century it would lead to an endless series of fat, yellow books titled "Such and such for dummies". Allow me to quote in contrast from "The elements of Style" by Strunk and White, because it reflects a much more inspiring spirit; "No one can write decently who is distrustful of the reader's intelligence, or whose attitude is patronizing.".

This disrespectful, almost contemptuous attitude has not only affected teaching and publishing, it has affected the academic research agenda as well, but in spite of all that, Computing Science was conceived, was born, and started to grow up quite successfully.

It definitely was not born yet when, in the early 50s,I got involved in automatic computing. At the time I was being groomed to become a very good theoretical physicist, but in 1955 that training was aborted when I decided to become a programmer instead. Not suffering from excessive modesty, I had what I considered a very good reason: I had concluded that programming presented a greater challenge than theoretical physics. I traded theoretical physics, a discipline highly respected because it had been good for a number of Dutch Nobel prizes, for what at the time was hardly a profession and certainly was without academic respectability. It was a difficult decision, which I would never have taken without the support of my parents and the encouragement of A.van Wijngaarden, my then boss at the Mathematical Centre in Amsterdam. I am grateful to all three.

Things changed in 1960, when a transatlantic cooperation created the programming language ALGOL 60, an event that my colleague F.E.J.Kruseman Aretz for good reasons has chosen to mark the birth of Computing Science. The reasons were good because ALGOL 60 introduced a handful of deep novelties, all of which have withstood the test of time. Let me review them briefly.

Firstly there is the introduction and use of Backus-Naur-Form (or BNF for short), a formal grammar to define the syntax of the programming language. More than anything else, ALGOL 60's formal definition has made language implementation a topic worthy of academic attention, and this was a crucial factor in turning automatic computing into a viable scientific discipline.

Secondly there was the block structure and the concept of the local variable, with the beautiful synthesis of lexicographic scope with dynamically nested lifetimes. The lexicographic scope led to a unified notation for mathematical quantification, while the nested lifetimes opened the door to the next novelty.

This was recursion. Logicians knew it, LISP had incorporated it, but ALGOL 60 gave it a firm place in imperative programming. These days, that place is quite natural, but at the time it was a shocking novelty because FORTRAN, which did not accommodate recursive definitions, had created the widely held opinion that recursion was too fancy and hence misplaced in a "real" programming language. In defence of the status quo, ALGOL 60 has been blamed for one of its major virtues. A few years later a five-year old son would show me how smoothly the idea of recursion comes to the unspoilt mind. Walking with me in the middle of town he suddenly remarked to me, "Daddy, not every boat has a lifeboat, has it?" I said "How come?" "Well, the lifeboat could have a smaller lifeboat, but then that would be without one."

In the fourth place I would like to mention the introduction of the type boolean as a first class citizen. It emerges when we view statements such as "2 + 2 = 4" or "It's Friday" as expressions that have a value, the two possible values being denoted by "true" and "false". These so-called "truth values" were introduced in 1854 by George Boole, but they hardly got citizenship in the world of mathematics. From the fact that, thanks to ALGOL 60, now each programmer is familiar with them, I expect a profound and radical influence on mathematics as a whole, an influence which is only beginning to be felt. This expectation is not based on gazing in a crystal ball but on my mother's inability to really accept the concept. She was a brilliant mathematician, but by definition a generation older, and she could not really accept 3 + 4 = 9 as an expression: for us it is a complicated way of writing "false", for her, 3 + 4 = 9 was just wrong. For her, boolean expressions were statements of fact: she had to interpret them.

Let me try to give you a simple example of what interpretation can lead to. Consider 10 pigeonholes with pigeons in them, and look now at the following two statements.
First statement: When the number of pigeons exceeds 10, at least 1 hole contains at least 2 pigeons.
Second statement: If each hole contains at most 1 pigeon, there are at most 10 pigeons.
The first statement evokes in the usual interpretation a picture of housing shortage, of holes with too many pigeons crammed into them. The second statement evokes a picture of housing luxury, with each pigeon having his own hole, and perhaps even some free holes! Yet in Boolean logic, the two statements are equivalent, they mean the same thing in exactly the same way as "Jack loves Jill" and "Jill is loved by Jack" mean the same thing. In other words, the pictorial interpretations blur the issue by introducing spurious distinctions.

ALGOL 60's fifth novelty was its machine independence. FORTRAN's purpose had been to ease programming for the IBM 709, while now it became the computer's task to execute ALGOL programs, and this was a major paradigm shift. We saw in the difficulty of implementing ALGOL 60 on IBM machines a confirming symptom of their poor design; Alan Perlis, however, judged ALGOL 60 "an inefficient language".

In the decade that followed, I passed a few personal milestones. My programming experience culminated in the ALGOL implementation with J.A.Zonneveld at the Mathematical Centre in Amsterdam and the THE Multiprogramming System with a handful of people at the Technical University Eindhoven. Both projects were at the time very ambitious. We successfully completed them by keeping them as clean as possible; by today's standards both were a mess, and both times we knew we were making history. Each evening, for instance, Jaap Zonneveld and I would take our own copy of the documentation home so that the compiler could not get lost in a fire at the Mathematical Centre.

The ALGOL implementation was one of my proudest achievements. Its major significance was that it was done in 8 months at the investment of less than 3 man-years. The rumour was that IBM's FORTRAN implementation had taken 300 man-years and thus had been a project in size way beyond what a university could ever hope to undertake. By requiring only 1 % of that labour, our compiler returned language implementation to the academic world, and that was its political significance. The THE Multiprogramming System was technically significant: it has introduced concepts that pervade computing science to this very day.

The advent of more powerful and —what people sometimes forget— much more reliable computers invited many ambitious projects at all sorts of places. Some were successful, some were overambitious, all of them drove home the message that such systems could easily get so complicated as to become intellectually unmanageable and, hence, no longer trustworthy. These were serious concerns, which led to a number of observations and conclusions. I mention a few.

(i)   When exhaustive testing is impossible —i.e., almost always— our trust can only be based on proof (be it mechanized or not).

(ii)   A program for which it is not clear why we should trust it, is of dubious value.

(iii)   A program should be structured in such a way that the argument for its correctness is feasible and not unnecessarily laborious.

(iv)   Given the proof, deriving a program justified by it, is much easier than, given the program, constructing a proof justifying it.

Considerations like the above gave rise to my "Notes on Structured Programming (from 1969) and C.A.R.Hoare's "Notes on Data Structuring" (from 1970). It is hard to quantify influence, but I think they have been seminal papers. People don't refer to them anymore, many haven't even read them, but the message has not been forgotten, it has been absorbed. [For your information, the book containing both texts is still in print; for 1999, our worldwide sales were 4 copies.]

Before going on I would like to point out that the recognition of programming as an intellectual challenge was at the time highly controversial.

Firstly, there was the matter of accuracy. A program would consist of, say, a few thousand instructions of half a dozen characters each, and thus would be a text of ten thousand characters, in which not a single typing error was permitted. The competent programmers unavoidably learned the clerical skills needed for the flawless manipulation of such long character strings: they became routine , like the surgeon's precautions in the operating room. The misunderstanding this created in the minds of others was that programming was merely a matter of accuracy, and that therefore it should be done by clerically trained personnel, and, if more persons were involved, under proper management. In short, programming was viewed as a perhaps painful but simple, low-level task. Needless to say, this confusion between the score and the composition led to an underestimation of the intellectual challenges programming presents.

Secondly, there was the widely spread belief that, once we had the right, sufficiently powerful programming language, programming would be so easy that everybody could do it. The older ones among us still remember the famous ad in a Datamation issue of 1968, showing in full colour a beaming Susie Mayer, telling the reader that she had solved all her programming problems by switching to PL/I. IBM never published her picture 4 years later.

The forces to play down the difficulty of programming were just too strong. I mentioned the sense of "popular justice" of the democratization movement that felt that everybody should be able to program. Then there was the religion at Xerox PARC that it should all be so natural that toddlers would love to do it. Then there was COBOL's creed that if your programming language was similar enough to English, even officers would be able to program. A major force was IBM, which wanted to sell hardware and hence was eager to present its machines as solutions rather than as the source of new problems. Finally, the prejudices of management did not allow industrial programming to be viewed as difficult: in the first half of the century, it had become a management goal to organize for the sake of stability the industrial enterprise in such a fashion that it would be as independent as possible of the competence of individual employees, with the result that in the second half of the century the mere suggestion that even industrial programming could require brains was blasphemy. For a while, the "deskilling of the programmer" was a hot topic.

The prevailing attitude was reflected in the creation of two literary figures —admittedly of rather poor literature,but nevertheless of great paralyzing power—, viz. "the average programmer" and "the casual user". Up to these days, academic research in programming methodology has been supposed to respect the severe intellectual limitations of these fictitious morons; consequently any proposal that required any further education of the programming person was out. Academia has suffered, for programming methodology could not flourish as a research topic in a world in which it was considered irrelevant. For many a university, this has been a great loss; here and there the situation might be improving, but it is a slow process.

By the end of the 60s, The University of Oxford had its PRG, i.e., its Programming Research Group, and IFIP, the International Federation for Information Processing, had its Working Group 2.3 on "Programming Methdology'. Both flourished and, as time went on, they were joined by the newly founded NATO Summer School in Marktoberdorf, as that became more focussed on the methodological aspects of design and got more and more prestigious in the process. So the word spread, and that was fine, but how slowly it did so is clearly illustrated by the date of the 1st Conference on the Mathematics of Program Construction —or MPC for short—: this was organized in the Netherlands by Roland C.Backhouse and Jan L.A. van de Snepscheut in 1989, essentially 20 years after the scientific merit and potential of the topic had been recognized. The next 3 MCP Conferences took place in the 90s, in the United Kingdom, in Germany, and in Sweden, respectively, and if I were an American, I would consider the fact that the first four of these conferences all took place in Europe a very alarming symptom indeed.

On the other hand, we should be glad that the gospel of design by derivation, rather than by trial and error, is still preached. For me personally it is very gratiftying to see that the area of application has been extended by people whom I consider in moments of greater vanity as my pupils: I have in mind A.J.Martin in connection with chip design, and W.H.J.Feijen and A.J.M. van Gasteren, who forged the Gries-Owicki theory into a methodology for deriving multi-programs. They all have done me proud.

Back to personal history. After 10 years at the Mathematical Centre in Amsterdam, I went to the Department of Mathematics at the Eindhoven University of Technology, where I stayed from 1962 until 1973. During that decade, Computing Science, or "Informatics", as the topic became known on the continent, became a much more substantial discipline than my mathematical colleagues had envisaged or intended and, perhaps not totally without justification, part of the blame for this undesired development was heaped upon me. Life in Eindhoven became a little difficult, but fortunately, Burroughs Corporation offered to rescue me.

I stayed with Burroughs Corporation for 11 wonderful and very productive years, my primary charter being to do my own thing. I had one major disappointment: I had hoped to lead the life of a scientific "man of letters", but the frequency with which my letters were answered was, on the average, too low to maintain a lively interchange, and so I ended up travelling more than I had intended and was comfortable with. But apart from that, they were, as said, wonderful years. It was too good to last, and it did not. After the company had changed its CEO, it rapidly lost interest in science and technology, and the groups with which I had built up my relations disbanded the one after the other. But it was not only Burroughs that changed during that decade, for I changed as well; my mathematical interests widened and eventually I was ready to return to the University Campus, and was fortunate that UT Austin offered me the opportunity to do so.

During my Burroughs years I changed very much as a mathematician. By the end of the 60s, R.W.Floyd and C.A.R.Hoare had shown us how to reason in principle about programs, but it took a few years before their findings penetrated through my skull. In the early 70s we studied Tony Hoare's correctness proof of the routine "FIND" and my friends still remember that at the end of that study I declared in disgust that "that meaningless ballet of symbols was not my cup of tea"; only gradually, my resistance to that kind of formula manipulation faded, until eventually, I began to love it.

Circumstances forced me to become a very different mathematician. I had invented predicate transformers as a formal tool for programming semantics and they served my purpose, but I lacked at the time the mathematical background needed to understand what I was doing, so much so that I published a paper with a major blunder. I was helped by C.S.Scholten, with whom I had worked since the 50s, and together we provided the mathematical background that had been lacking. In doing so we developed a much more calculational style of doing mathematics than we had ever practised before. I stayed away from where I had blundered, but that hurdle the younger and mathematically better equipped R.M.Dijkstra took in his stride after he had extended our apparatus from predicates to relations.

Let me try to sketch my mathematical change. For centuries, mathematics has been what it says in the dictionary: the abstract science of space, number and quantity. In this conception, mathematics is very much about things, such as triangles, prime numbers, areas, derivatives and 1-1 correspondences. Accordingly, such mathemetics is done in a language in which nouns prevail and which each time is tied rather closely to the subject matter at hand. In its orientation towards things, it invited pictures and visual representations. This has gone so far that the Greeks introduced, for instance, the hardly needed notion of the "triangular numbers" 1, 3, 6, 10, etc., purely because such numbers of dots admitted triangular arrangements:

     .      .        .       .
           . .      . .     . .
                   . . .   . . .         etc.
                          . . . .
     1      3        6       10

But at least since the 18th Century —personally I am aware of Augustus de Morgan and George Boole from Great Britain— there has emerged another view, representing a shift from the "quod" to the "quo modo", from the "what" to the "how": it views mathematics primarily as the art and science of effective reasoning.

This was refreshing because the methodological flavour gave it a much wider applicability. Take a sophisticated piece of basic software such as a programming language implementation or an operating system; we cannot see them as products engendered by the abstract science of space, number and quantity, but as artefacts they are logically so subtle that the art & science of effective reasoning has certainly something to do with their creation: in this more flexible conception of what mathematics is about, programming is of necessity a mathematical activity. History has shown that the mathematical community needs a constant reminder of this more methodological conception of its trade, as many mathematicians invest so much of their time and energy in the study of a specific area that they tend to identify mathematics with its [always specific] subject matter.

As far as I know, Gottfried Wilhelm Leibniz, who lived from 1646 to 1716, has been the first to tackle effective reasoning as a technical problem. As a youngster of 20 years of age he conceived, possibly inspired by the work of Descartes, a vision of reasoning as applying a calculus. Like modern computing scientists, he invented impressive names for what had still to be invented, and, for good reasons not overly modest, he called his system no more and no less than "Characteristica Universalis". And again like modern computing scientists, he grossly underestimated the time the project would take: he confidently prophesied that a few well-chosen men could do the job in five years, but the whole undertaking was at the time of such a radical novelty that even the genius of Leibniz did not suffice for its realization, and it was only after another two centuries that George Boole began to realize something similar to the subsystem that Leibniz had called the "calculus raticinator".

Let me quote from E.T.Bell young Leibniz's description of what he was aiming at:

"a general method in which all truths of the reason would be reduced to a kind of calculation. At the same time this would be a sort of universal language or script, but infinitely different from all those projected hitherto; for the symbols and even the words in it would direct reason; and errors, except those of fact, would be mere mistakes in calculation."

I think it absolutely astounding that he foresaw how "the symbols would direct the reasoning", for how strongly they would do so was one of the most delightful discoveries of my professional life.

Around 1900, the Dream of Leibniz came closer to realization as the necessary formalisms became available and the great German mathematician David Hilbert promoted the project. Hilbert made clear that the total calculation had to be achieved with the aid of manipulations from a well-defined repertoire. One could argue with the repertoire, and the Dutchman L.E.J.Brouwer vigorously argued against Hilbert's choice, but instead of arguing what is the "right" repertoire, one can turn the concept of proof from an absolute concept to one relative to the repertoire of admitted manipulations. In passing we note that, having abolished the notion of "the true repertoire", we still are free to have our preferences. Hilbert's revolution was in any case to redefine "proof" to become a completely rigorous notion, totally different from the psycho/sociological "A proof is something that convinces other mathematicians.". A major shortcoming of the latter view is that it gives no technical guidance for proof design and makes it very difficult to teach that kind of mathematics. Yet, or perhaps for this reason, many of the more conservative mathematicians still cling to this form of consensus mathematics; they will even vigorously defend their informality.

Here I must admit that I am a poor historian or a poor psychologist, for I see two things that I cannot reconcile with each other. On the one hand Hilbert, generally recognized as the greatest mathematician of his generation, has stated very explicitly that rigour in proof is not the enemy of simplicity, and, also, that the effort for rigour leads us to the discovery of simpler and more general methods of proof. He confirms the prediction Leibniz made, that "the symbols would direct reason". On the other hand the world of mathematics seems to continue as if these things had never been said. They don't even take the trouble of explaining why Hilbert was wrong or misguided, it looks more as if he is just ignored. [As soon as I wrote this down, I took a test and checked the index of Descartes' Dream: The World According to Mathematics by the mathematical philosophers Philip J.Davis and Reuben Hersch: after "Heinlein" comes "Hofstadter". Hilbert is not mentioned. I should add that the blurb characterizes the book as "A passionate plea against the use of formal mathematical reasoning as a method for solving mankind's problems...."]

Sure, mathematicians manipulated formulae prior to Hilbert, but with the exception of the most familiar cases —such as doing arithmetic—, people manipulated interpreted formulae, i.e., they justified their manipulations via the perceived properties of the things denoted by their symbols. Hilbert the formalist showed that such interpretation was superfluous because which manipulations were permissible could be defined in terms of the symbols themselves. By leaving the formulae uninterpreted, their manipulations becomes much simpler and safer. As my initial protest against the "meaningless ballet of symbols" illustrates, the preferences of the formalists are an acquired taste, but since Hilbert we know that the taste is worth acquiring.

During Hilbert's life, Leibniz's Dream, by and large, just stayed a dream. People viewed formal proofs as an interesting theoretical possibility or an unrealistic idealization, and they would regard their own proof as a usually sufficient sketch of a formal argument. They would even assure you that, if you insisted, they could formalize their informal argument, but how often that claim was valid is anybody's guess.

In the 2nd half of the 20th Century, things shifted with the advent of computers, as more and more people began to adopt formal techniques. Parts of Leibniz's Dream became reality, and it is quite understandable that this happened mostly in Departments of Computing Science, rather than in Departments of Mathemetics. Firstly, the computing scientists were in more urgent need of such calculational techniques because, by virtue of its mechanical interpretability, each programming language is eo ipso a formal system to start with. Secondly, for the manipulation of uninterpreted formulae, the world of computing provided a most sympathetic environment because we are so used to it: it is what compilers and theorem provers do all the time! And, finally, when the symbol manipulation would become too labour-intensitive, computing science could provide the tools for mechanical assistance. In short, the world of computing became Leibniz's home; that it was my home as well was my luck.

Most circumstances conspired to make me very fortunate. In 1981, while I was still with Burroughs Corporation, the BP Venture Research Unit, under the enlightened guidance of D.W.Braben, gave a grant titled "The Taming of Complexity", from which Netty van Gasteren's work could be supported; a subsequent grant for "The Streamlining of the Mathematical Argument" would enable the young British logician L.A.Wallen to visit us in Austin as a "post doc". All this assistance is gratefully acknowledged. In those years we learned that the most effective way of avoiding unmastered complexity is not to introduce that complexity in the first place. And when we focussed on that laudable goal we learned to exploit and appreciate the power of well-designed calculi.

A second reason for considering myself fortunate was my transfer to UT Austin, where the Department of Computer Sciences was most accommodating. As specific examples I mention The Year of Programming, initiated by K.M.Chandy and J.Misra, but mostly organized by H.Richards, and the sabbatical years that W.H.J.Feijen, W.H.Hesselink, C.A.R.Hoare and D.Gries spent at the Department, visits that greatly enriched both our lives in all sorts of ways. Add to that helpful staff, whose continued assistance I greatly appreciated, brilliant students who made it a challenge and a privilege to lecture for them, and the clear, blue sky of Texas, for which I had been waiting for more than 50 Years!

I thank everybody in general for everything, and you in particular for your attention.

Austin, 22 April 2000

Prof.dr Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin

Transcription by Adobe Capture™
Copy editing by Ham Richards
revised Mon, 8 Feb 2010

13xx

1300: The notational conventions I adopted, and why

1301: The river, the isles and the bridges

1302: Once more bichrome triangles in complete graphs

1303: My recollections of operating system design

1304: The end of computing science?

1305: Answers to questions from students of Software Engineering

1306: The chessboard covered with dominoes

1306a: The chessboard covered with dominoes

1307: An unavoidable case analysis

1308: What led to “Notes on Structured Programming”

1309a: Zuckerman’s problem and the ETAC

1310: Three trip reports rolled into one: 2001.04.16 – 2001.07.06

1311: Another look at a problem from Hugo Steinhaus

1312: On disjoint binary numbers

1313: The GCD and the minimum

1315: Indirect equality enriched (and a proof by Netty)

1316: Philips and I: a few snapshots

1317: From van IJzeren’s correspondence to my aunt & uncle

1318: Coxeter’s rabbit

EWD 1300

The notational conventions I adopted, and why

At a given moment, the concept of polite mathematics emerged, the underlying idea of which is that, even if you have only 60 readers, it pays to spend an hour if by doing so you can save your average reader a minute. By inventing an idealized “average reader”, we could translate most of the lofty, human goal of politeness into more or less formal criteria we could apply to our texts. This note is devoted to the resulting notational and stylistic conventions that were adopted as the years went by.

We don’t want to baffle or puzzle our readers, in particular it should be clear what has to be done to check our argument and it should be possible to do so without pencil and paper. This dictates small, explicit steps. On the other hand it is well known that brevity is the leading characteristic of mathematical elegance, and some fear that this ideal excludes the small, explicit steps, but one of the joys of my professional life has been the discovery that this fear is unfounded, for brevity can be achieved without committing the sin of omission.

I should point out that my ideal of crisp clarity is not universally shared. Some consider the puzzles that are created by their omissions as spicy challenges, without which their texts would be boring; others shun clarity lest their work is considered trivial.

*                *
*

As time went by, we accepted as challenges to avoid pulling rabbits out of the magician’s hat. There is a mathematical style in which proofs are presented as strings of unmotivated tricks that miraculously do the job, but we found greater intellectual satisfaction in showing how each next step in the argument, if not actually forced, is at least something sweetly reasonable to try. Another reason for avoiding rabbits as much as possible was that we did not want to teach proofs, we wanted to teach proof design. Eventually, expelling rabbits became another joy of my professional life.

I should point out that also my ideal of proofs without rabbits is not universally shared. Some authors believed that, in order to keep the reader awake, one has to tickle him with surprises. Others believe that simulated sparks of divine inspiration are essential for earning the respect of their readership.

*                *
*

As a final influence I must mention our desire to let the symbols do the work —more precisely: as much of the work as profitably possible—. The intuitive mathematician feels that he understands what he is talking about and uses formulae primarily to summarize situations and relations in to him familiar universes. When he seems to derive one formula from another, the transformations he allows are those that seem to be true in the universe he has in mind. The formalist, however, prefers to manipulate his formulae, temporarily ignoring all interpretations they might admit, the rules for the permissible symbol manipulations being formulated in terms of those symbols: the formalist calculates with uninterpreted formulae. While the average intuitive mathematician is perfectly happy with semantically ambiguous formulae “because he knows what is meant”, the formalist obviously insists on an unambiguous formalism.

Saying that the preferences of the formalist are not universally shared, would be the understatement of the year: intuitive mathematicians can hate more formally inclined colleagues with the same visceral hatred as Republicans can hate Democratic presidents with.

*                *
*

Infix notation and expressions

Without much hesitation I have decided to stick to the usual infix operators. They have the disadvantage of requiring parentheses to distinguish (p+q)/r from p+(q/r) which prefix notation would have rendered as /+pqr and +p/qr respectively.

Remark  One of the names of prefix or Polish notation is “parenthesis-free” notation, but that is a little bit misleading, for though no longer needed, the parentheses are still permissible: we could have written /(+pq)r and +p(/qr) respectively. (End of Remark).

A little hesitance was induced when my late colleague Wouter Peremans remarked in passing that infix notation was of course “a notational relic”. It made me realize why I like it so much for associative operators: it allows us to write p+q+r  without being forced to choose between (p+q)+r and p+(q+r); in prefix notation, the choice between ++pqr and +p+qr would have been unavoidable.

The main reason to stick to the infix notation for the usual operators was, of course, that we are so terribly used to it, but the associativity does play an honest role: I did introduce —with great satisfaction!— infix operators for what I used to denote by max(x, y) and gcd(x, y) , and find that I don’t introduce anymore infix operators that are not associative.

Priority rules, i.e., rules of relative binding power, are the standard way of reducing the number of parenthesis pairs that would otherwise be needed, but we should remember that we are not obliged to reduce them to the absolute minimum. We learned to appreciate the following customs.

•      Only use priority rules that are frequently appealed to, and hence are familiar. I would not hesitate to write p+q∙r, but would avoid p/q∙r and p ⇒ q ⇒ r .

•     Do not introduce priority rules that destroy symmetry. I remember how much more pleasant the predicate calculus became to work with after we had decided to give con- and disjunction the same binding power and thus to consider p ∧ q ∨ r an ill-formed formula.

•      When introducing new infix operators, parenthesize so as to postpone decisions about binding powers until experience justifies a preference.

•      When you have the freedom, choose the larger symbol for the operator with the lower binding power.

•      Surround the operators with the lower binding power with more space than those with a higher binding power. E.g.,

p ∧ q   ⇒   r      ≡     p  ⇒  (q  ⇒  r )

is safely readable without knowing that ∧ ⇒ ≡  is the order of decreasing binding power. This spacing is a vital visual aid to parsing and the fact that nowadays it is violated in many publications means that these publications do a disservice to the propagation of formal techniques. (The visual aid is vital because the mathematician does not do string manipulation but manipulation of parsed formulae: when substituting equals for equals, identifying subexpressions is essential.)

•      For unary operators, give them the highest binding power and stick to prefix operators.

•      For the relation/predicate calculus we settled on the following order of decreasing binding power

¬ |   ~ |  | (negation, relational converse)
; |  |  | (relational composition)
∧ | ∨ |  | (conjunction, disjunction)
⇒ | ⇐ |  | (implication, consequence
≡ |  |  | (equivalence)

As time went on, I learned to appreciate expressions built with operators as a way of avoiding functional notation. We can write the difference  a−b  as  dif.(a, b) or exc.(b, a), where min and exc are functions of an ordered pair. (I believe that the notion of “function of 2 arguments” is now obsolete.) But we can also write the “curried” versions (min. a). b and (sub. b). a in which, for instance, sub is a higher-order function such that sub. b decreases its argument by b (so that sub.(−1) would be the successor function). Functions dif, exc, min and sub are different functions and as soon as the operation of functional composition enters the game, the distinctions are essential. But as long as we don’t do functional composition, the choice between the four options is irrelevant and writing the expression a−b is a lovely way of avoiding being overspecific. (Not making superfluous distinctions should always be encouraged; it is bad enough that we don’t have a canonical representation for the unordered pair.)

*                *
*

Invisible operators

A.N. Whitehead made many wise remarks it is a pleasure to agree with, but I cannot share his judgement when he applauds the introduction of the invisible multiplication sign. The multiplication being so common, he praises the mathematical community for the efficiency of its convention, but he ignores the price.

The one price is confusion: look at the different semantics of juxtapositions in

3½           3y           32            .

Is it a wonder that little children (many of whom have a most systematic mind) get confused by the mathematics they are taught? One would like the little kids to spend their time on learning the techniques of effective thought, but regrettably they spend a lot of it on familiarizing themselves with odd, irregular notational conventions whose wide adoption is their only virtue.

The much heavier price is that the invisible multiplication all but rules out the introduction of multiple-letter identifiers, thus creating the need of symbols of other alphabets (which —and Whitehead should have known that!— significantly contributed to the pain of typing mathematics). And when the multiple-letter identifiers could no longer be avoided, they were admitted at the price of ambiguity, as

sin (s + i + n)

illustrates.

Remark  I also think that Whitehead made another error of judgement. Brevity is much more effectively obtained by macroscopic measures such as avoiding duplication, case analysis and superfluous nomenclature, than by such microscopic measures as making the multiplication invisible. (End of Remark.)

I now avoid invisible infix operators almost entirely. I do remember a few texts dealing with theorems about strings in which concatenation was denoted by juxtaposition. I could afford that because at the beginning I had declared the types of my one-letter variables: x, y, z  were of type character,  X, Y, Z were of type  (possibly empty) character string: in xX, x would stand for the leading character of the string xX.

The most far-reaching consequence is the introduction of a visible infix operator for function application. I have given it the highest binding power and therefore I have chosen the smallest symbol I could think of: the infix dot “.” . So, instead of the traditional f (x)  I now write f. x .  I have started doing this very tentatively in 1984; I have stuck to the convention and I see more and more people adopting it. One of its attractions is the way in which it caters for λ-abstraction: in 1973 I wrote “wp(S, R)” for the weakest precondition such that statement S establishes postcondition R, but wp. S. R is much more attractive, wp. S now being the predicate transformer associated with statement S. Note that we have chosen the function application dot to be left associative:  wp. S. R is short for (wp. S ). R .

Remark The convention that function application is left-associative has been adopted almost universally. Note that the parentheses then necessary in

 f.(g. x)

can be eliminated by writing the above as

 f ◦g . x

and postulating that functional composition has a greater binding power than functional application. Please note that

 f ◦g ◦h . x

is semantically unambiguous, functional composition being associative. (End of Remark.)

*                *
*

Quantification

I had three major desires with respect to quantification, (i) unambiguous identification of the dummy, (ii) clear delineation of the scope, and (iii) range as a uniform ingredient.

ad(i)  The need for unambiguous dummy identification becomes clear when we consider the list of sets, which starts with the set of the first 10 squares:

 { i ² | i <10 },     { i ³ | i <10 },     { i n | i < 10 },    { i n | i < n }

where {i i+1, i i+2, i i+3, .... } would be a possible interpretation of the last set.

ad(ii)  It is already an ambiguity with the traditional summation; compare

3 |  |  |  |  | 3 |  |  |  | 3 |  |  |  | 3 |
∑ | n² |   , |  | 1 + | ∑ | n² |   , |  | ∑ | n² + 1 |   , |  | ∑ | 1 +n²
n=1 |  |  |  |  | n=1 |  |  |  | n=1 |  |  |  | n=1 |

possible interpretations being, in order,   14,   15,   15 or 17,   17 or 3+n² .  But even logicians write

∀x P(x) ∧ Q

without making clear whether they mean

(∀x P(x)) ∧ Q    or    (∀x P(x) ∧ Q)

which differ if the range for x is empty.

ad(iii)   Although the properties of the underlying (symmetric and associative) operators may differ  —addition and multiplication are not idempotent and maximum and minimum may lack a neutral element— we would like a uniform format. There is, for instance, no reason why summation should have a dummy ranging over consecutive integers.

The format is based on our format for set notation. The set that we formerly described as

{ i ² | i < 10 }

is denoted by

〈 i : i < 10 : i 2 〉

where “i ” is the dummy —if there are more dummies, we separate them by commas—, “i < 10” is the range and “i 2 ” is the term. The semicolons around the range are only separators, the “angle brackets” delineate the scope of the dummies. The explicit enumeration of the dummies between 〈 and the first : acts like ALGOL 60’s declaration of the local variables of an inner block. The convention enables us to distinguish between

〈 i : i < n : i n 〉 ,    〈 n : i < n : i n 〉  and    〈 i, n : i < n : i n 〉 ;

The last one is the set of all powers for which the exponent exceeds the base, the first two are subsets thereof.

In ALGOL 60, the declaration of a local variable includes the type of that variable, and I see no logical objection against adopting that convention: we could have written

〈 i ∈ ℕ : i < 10 : i 2 〉           ,

but we have never done so: I have always found it preferable to supply such information in the surrounding text.

Remark  It took many years before I introduced the angle brackets 〈 〉 ; all that time I used the standard parentheses ( ) . The transition to angle brackets for scope delineation was a great improvement. (End of Remark).

When a quantified operator is applied to the set

〈 i : r. i : t. i 〉   ,

we write it just after the opening angle bracket:

〈∑ i : r. i : t. i 〉  ,   〈∏ i : r. i : t. i 〉  ,   〈∀ i : r. i : t. i 〉  ,   〈∃ i : r. i : t. i 〉 ,

〈↑ i : r. i : t. i 〉   and   〈↓ i : r. i : t. i 〉  .

For the first two, the type of the term t. i must admit addition and multiplication, for the next two, universal and existential quantification respectively, the type of the term t. i had better be Boolean, while for the supremum and the infimum the surrounding text had better specify the partial order with respect to which these extremes have been defined.

From a logical point of view, universal and existential quantification don’t need a variable range parameter since it can be absorbed in the term:

〈∀ i : r. i : t. i 〉    ≡    〈∀ i : true :  r. i  ⇒  t. i 〉 

〈∃ i : r . i : t. i 〉    ≡    〈∃ i : true :  r. i  ∧  t. i 〉

But the range parameter allows more elegant formulae, such as the defining property of the supremum

〈↑ i : r. i : k. i 〉 ⊑ z   ≡   〈∀ i : r. i : k. i  ⊑ z 〉

The explicit range parameter is also welcome from a practical point of view. During many manipulations, the range can remain constant, as is for instance illustrated by de Morgan’s Law

¬〈∀ i : r. i : t. i 〉     ≡    〈∃ i : r. i : ¬t. i 〉

and we shall show below the notational exploitation of such range constancy.

*                *
* 

The proof format

When, for transitive  → , we conclude A → C from A → B and B → C  , we wish for brevity’s sake to write down the intermediate result B only once. We therefore present the calculation  in the following format

| A |
→ |  | {hint why A → B}
| B |
→ |  | {hint why B → C}
| C |

We shall return to the role of the hints later; we now only report that it is absolutely essential that at least one line is available for each hint, so as to discourage economizing on them.

    Another, purely editorial way of reducing duplication is declaring something, once and for all, to hold for all intermediate results of a calculation rather then repeating it each time. We do this for the type specification of variables and the range of dummies. This is a special case of “embedding the calculation in a context”. To illustrate some of these matters, let me show a few ways of proving the following the following simple

Theorem 0.   For associative  •  , we have for all  x, y, z

x • y = y  ∧  y • z = z   ⇒    x • z = z

Proof 0.    This proof uses Leibniz’s Principle in the form

p = q   ∧   f. p    ⇒    f. q

and has the structure of a weakening chain of boolean expressions.

    We prove Theorem 0 by observing for any x, y, z and associative  •

| x • y  =  y   ∧   y • z  =  z
≡    |      { predicate calculus }
|  y • z  =  z   ∧   x • y  =  y   ∧   y • z   =   z
⇒ |      { Leibniz }
| y • z  =  z   ∧   (x • y) • z   =   z
≡ |      { • associative }
| y • z  =  z   ∧   x • ( y • z)   =   z
⇒ |      { Leibniz }
| x • z  =  z

(End of Proof 0).

Here the calculation is embedded in the context of • being associative, a proof shape that is suggested by the formulation of theorem 0.

Proof 1   This proof uses Leibniz’s principle in the form

p = q   ⇒   f. p = f. q

We prove Theorem 0  by observing for associative • and x, y, z satisfying the antecedent

| x • z
=    |     { y • z  =  z   from antecedent }
| x • ( y • z)
= |     { • associative}
| (x • y) • z)
= |     { x • y = y  from antecedent }
| y • z
= |     { y • z = z  from antecedent }
| z

(End of Proof 1)

In proof 1, we have been very —one could argue: too !— explicit in our hints: we could have started with

     x • z
=        { antecedent }
     x • ( y • z )

because the observed equality is obviously justified by   y • z = z   ,    which fortunately is one of the conjuncts of the antecedent. But personally I am in favour of making the hints as clear and helpful as possible. And in the style of   Proof 1 we can afford it, for we have embedded our calculation in a more elaborate context —viz. that of the antecedent— from which the hint selects a conjunct only when it is needed. This is more concise  than the style of proof 0, in which conjuncts —e.g.  y • z = z— are dragged along as long as they are needed. In the next example we’ll show another way of how “context” can be used to avoid repetition of the same subexpression.

We recall the defining property of the supremum  ↑  with respect to the complete partial order ⊑:

〈↑ i : r. i : k. i 〉⊑ z   ≡   〈∀i : r. i : k. i  ⊑ z 〉    for all z

Part of the Theorem of Knaster-Tarski states that with  h  defined by

h = 〈↑ y :  y ⊑ f. y : y 〉

we have

h ⊑ f. h

if f is monotonic with respect to ⊑ ,  i.e.,

p ⊑ q   ⇒   f. p ⊑ f. q    for all p, q .

(In another language: “f-application is ⊑- preserving”.)

Proof   In this proof   y ⊑ f.y   is understood to be the range of the dummy y.

To begin with we conclude from the definitions of ↑ and h that h’s defining property is that

(0)         h ⊑ z    ≡  〈∀y :: y ⊑ z 〉   for all z .

And now we observe

|  h ⊑ f. h
≡    |      { (0) with z := f. h }
| 〈∀y :: y ⊑ f. h 〉
⇐ |      { ⊑ transitive ; ∀ monotonic }
| 〈∀y :: y ⊑ f.y  ∧ f.y  ⊑ f. h 〉
≡ |      {∀ distributes over ∧}
| 〈∀y :: y ⊑ f. y 〉   ∧   〈∀y :: f. y  ⊑ f. h 〉
≡ |      { range is y ⊑ f.y, predicate calculus }
| 〈∀y :: f. y ⊑ f. h 〉
⇐ |      { f monotonic; ∀ monotonic }
| 〈∀y :: y ⊑ h 〉
≡ |      { (0) with z := h }
|  h ⊑ h
≡ |      { ⊑ reflexive }
|  true

( End of Proof)

Remark As an aside I would like to point out that the second step, which strengthens

y ⊑ f. h

to

y  ⊑ f. y  ∧  f. y  ⊑ f. h

is absolutely standard. In the original relation the operands differ in two respects: y versus h and the number of f-applications, in the strengthened version each of the differences has been localized in one of the conjuncts, so that they can be dealt with separately. We could have tried the separation the other way round

y  ⊑ h  ∧  h  ⊑ f. h

but as that choice reintroduces the original poof obligation it is not helpful.
(End of Remark)

*                *
*

The role of the hints

With suitable formalization, the hints would fully define the manipulations, and we could omit all the intermediate results, as they would follow. Clearly we have not done so; we consider the intermediate results an essential ingredient of the proof since it is the “intermediate” result that indicates whether we are done or, if not, suggests what to do next.

Our hints were intended to be helpful, and as time went by, we made up our mind how we wanted to help the reader. The most important property of the hint became that it restrict and delineate the search space where the justification should be found. So, if the hint is

{predicate calculus}        ,

then this means that the rules of the predicate calculus suffice. When anything beyond that is needed, it is something, a rule or a property , from the context in which the calculation is embedded; in that case the hint should identify that context element uniquely. For this purpose we commonly number formulae (like “(0)” in the last example).

Remark  For the formula number’s place the left margin is to be preferred over the right margin, because then it is easier to maintain a small distance between the number and the formula it numbers. (A similar remark applies to page numbers in tables of contents.)
(End of Remark.)

In the hints, in our last example, that referred to (0), we gave the instantiations —“z := f. h” and “z := h” respectively— though in a simple example like this it is perhaps a little bit overdone. As soon as the pattern matching might become a problem, however, the instantiation is really helpful and we therefore don’t omit it: our texts should not pose puzzles to the reader.

To save space we sometimes combine two manipulations within a single step. We do not hesitate to do so in the case of independent commuting operations on disjoint subexpressions of the intermediate result. We never combine nested substitutions, for that would be asking for trouble. For such microscopic space savings, the general advice is “In dubio abstine.”; the space savings that can be obtained by proper proof structure —such as effective disentanglement and avoided case analyses— are greater and intellectually more satisfying.

*                *
*

Overloading and an unsolved dilemma

Derivation distributes over addition, i.e.,

d |  (x+y)  =   | dx |   +   | dy |         .
dt | dt | dt

Usually we don’t consider this an example of overloading, but if x+y  stands for a speed and t is time, than the  +  at the right-hand side adds accelerations.   Yet we don’t feel obliged to introduce two different + signs and to write something like

d |  (x +s y)  =   | dx |   +a   | dy |         ,
dt | dt | dt

primarily because the absence of a notational distinction between the two additions did not introduce any ambiguity.

Let now x and y be two functions which, when applied to t yield two addable values. Then it is customary to define the function that is denoted by x+y by

(x+y). t  =  x. t + y. t            for all t,

Note that, formally, “. t ” now distributes (to the left) over +  .  (In our former example the distribution of d/dt  was “to the right”, so we are still on reasonably familiar ground.)

But now the question arises what meaning to ascribe to x = y  . The traditional interpretation is that x = y is a boolean  expression stating that x and y are the same function, i.e.,

x = y   ≡   〈 ∀t :: x. t = y. t 〉

(Here we have used ≡ for equality between boolean operands.) But in analogy to our previous example x = y could also be interpreted as a boolean function given by

(1)       (x = y). t   ≡   x. t  =  y. t    for all t  ,

i.e.,  the boolean function that yields true wherever x and y coincide, and false everywhere else.

   In many of my writings I have chosen interpretation (1). In addition I have chosen to use a pair of square brackets to denote for a boolean function universal quantification over its domain:

(2)        [b]    ≡    〈 ∀t  :: b. t 〉

The great advantage of the square brackets is that one does not need to introduce a dummy argument. And now one proceeds

| ( x and y are the same function )
≡ |      { definition of the functional equality }
| 〈 ∀t  :: x. t = y. t 〉
≡ |      { (1) }
| 〈 ∀t  :: (x = y). t 〉
≡ |      { (2)  with  b :=  x = y }
| [x = y ]                                      ;

the annoying moral of the story is that to express what we know and appreciate as plain and honest-to-God equality may require an extra pair of square brackets. All this is not very satisfactory, but I don’t know enough of type theory to try to improve the scene.

Nuenen,  25 July 2000

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Mario Béland and Hamilton Richards
edited by Corrado Cantelmi
revised 23-Mar-2018

EWD1301

The river, the isles and the bridges

In a river lie 6 isles, connected by 13 bridges to each other and the shores as follows:

When in a storm each bridge has a probability 1/2 of being swept away. What is the probability that the shores remain connected?

*           *
*

We propose to associate the 13 bridges with the 13 squares in the following array

fig.0

such that the original bridges correspond to the diagonals between the marked corners of the squares.

In each square we connect with probability 1/2 either

(i) | the marked corners by a solid diagonal: | [picture]
| or |
(ii) | the unmarked corners by a dotted diagonal | [picture]

In the new terminology, we are now asking for the probability that there exists a solid path between the As and the Bs.

Paths being continuous we conclude

(As and Bs are connected by a solid path)
≢    (Cs and Ds are connected by a dotted path)

and hence

(0)   the probability that As and Bs are connected
  =   the probability that Cs and Ds are not connected.

From the symmetry of fig. 0 and the equal probabilities of (i) and (ii) we conclude

(1)   the probability that Cs and Ds are not connected
  =  the probability that As and Bs are not connected.

Combining (0) and (1) we conclude that the As and Bs are as likely to be connected as to be disconnected. The answer we were looking for is therefore ½ .

Remark The answer is not surprising since ½ is also the answer in the situations

and

(End of Remark)

*                          *
*

I learned this problem early June from Dr. Georg Zimmermann at a workshop "Sprache und Mathematik" that the Fachschaft Mathematik of the Bischöfliche Studienförderung "Cusanuswerk" had organized in Uder. We solved the problem at the next session of the ETAC ( = Eindhoven Tuesday Afternoon Club); in particular the contribution of Frans van der Sommen is acknowledged.

And then it took me almost a month to find the time and muster the energy to record the solution. Besides the usual excuses of having other things to do, there was the fact that I still had to invent fig. 0, an invention that helped me —I think!— in my exposition, but also annoyed me because I needed pencil and paper for it.

Eventually I concluded that I did not like the problem too much: its solution remained an isolated ingenuity.

Nuenen, 10 July 2000

prof.dr Edsger W.Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Carl Ludwigson
revised Sat, 24 Nov 2007

EWD1302

Once more bichrome triangles in complete graphs

We consider the bichrome triangles in a complete n-graph of which each of its edges is either red or blue. Each bichrome triangle has 2 "mixed Vs," where a mixed V is a pair of edges with different colours and a shared end point, while a monochrome triangle has no mixed Vs. Thus we can find an upper bound for nbt, i.e. the number of bichrome triangles, by halving an upper bound for the number of mixed Vs. We distinguish even and odd n.

n = 2k  .   The n−1 edges that share an end point form at most k∙(k−1) mixed Vs. Hence there are at most n∙k∙(k−1) mixed Vs, and

(0) | nbt ≤ k²∙(k−1)     .

n = 2k + 1  .  The n−1 edges that share an end point form at most k² mixed Vs. Hence there are at most k²∙n mixed Vs and

(1) | nbt ≤ k²∙(2k+1)/2     .

(Note that the right-hand side need not be integer.)

The rest of this note is devoted to the question whether these upper bounds are as low as possible. The answer will turn out to be affirmative. This will be demonstrated by constructing for arbitrary n a graph such that for each node red and blue degree are as equal as possible, i.e. the situation from which the upper bounds (0) and (1) are derived [the red/blue degree of a node is the number of red/blue edges sharing that node as an endpoint.] We deal with even and odd n separately.

n = 2k   Partition the n nodes into k A-nodes and k B-nodes, colour the AA- and the BB-edges red and the AB-edges blue. Then each node has a red degree equal to k−1 and a blue degree equal to k, which, n−1 being odd, is as equal as you can get them.

n = 2k + 1  This case is slightly more complicated because the situation that in each node the degrees are both equal to k can only be obtained for even k; for uneven k we must admit 1 node with degrees (k−1, k+1); this corresponds to the situations in which the right-hand side of (1) is not an integer.

As before we partition the n nodes, but this time into n+1 A-nodes and n B-nodes. Were we to colour them as before, each A-node would have degrees (k,k) as desired, but each B-node would have degrees (k−1,k+1). To remedy the situation, consider the following transformation:

A — A A — A || → || B B B B

While it leaves the degrees of all A-nodes unchanged, it can be used to change at 2 B-nodes degrees (k−1, k+1) into (k,k), as desired. With k = 2∙h or k = 2∙h+1, we can apply this transformation on h disjoint pairs of B-nodes (and h distinct, and hence initially red, AA-edges).

Note For odd k, a node with degrees differing from (k,k) is unavoidable because the sum of the red/blue degrees is even.
(End of Note.)

Austin, 29 October 2000

Prof. Dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by Jordan Olsommer.
Last revised Sat, 24 Nov 2007.

EWD1303

My recollections of operating system design

From, say, 1956 to 1966, I was involved in aspects of what would now be called the design of "operating systems." At the time, those years were exciting, in retrospect they were interesting. They were exciting because we were faced with all sorts of challenges of which we did not know whether they could be met at all: sometimes we succeeded, sometimes we failed. And it is now interesting to see how long it took for some key concepts to emerge and how separable (and eventually separated) problems remained for many years intertwined, solely because they had presented themselves together. (For many years, for instance, nondeterminacy and concurrency were always closely linked: the one was never considered without the other.)

In what follows, I shall try to provide my recollections with all the background information needed to understand the story.

The source of the problems

In Amsterdam, at the Mathematical Centre, I started programming for binary machines for which an electric typewriter with electromagnets under the keys was the primary output device. The first machine could operate 16 keys of the typewriter: the 10 decimal digits, plus, minus, period, space, tabulate and NLCR (= New Line Carriage Return), the second one had access to the entire keyboard. The type instruction pulled the key identified by the 4 (6) least significant digits of the A-register (= main Accumulator); these bits were chosen because that was the place where the conversion process from binary to decimal representation would produce each time the binary representation of the next digit to be typed.

Between the 4 flip-flops of the A-register and the typewriter was a "decoder", i.e., a device with 4 input wires and 16 output wires: the combination of the signals on the 4 input wires would determine which one of the 16 output wires could activate its electromagnet.

In the above arrangement, the A-register is either available for calculation or has to control the decoder, and thus the machine as a whole is a strictly sequential device in which calculating and typing alternate.

Mechanical devices as typewriters being as slow as they are, the decoder needs for each character typed its input for 100 ms, which by electronic standards is a long period of time: it is a pity to force for that whole period the calculator to idleness. This can be remedied for the price of introducing a 4-bit "output register"

At the beginning of the execution of the type instruction, the least-significant bits of A are copied into the output register at electronic speed, and then, during the next 100 ms, two independent processes take place concurrently: having the A-register at its full disposal, the unhampered calculator continues to calculate at electronic speed, while under control of the output register the mechanical typewriter types the character. (The maximum gain in speed —rarely achieved in practice— is a factor of 2, but the price of an extra output register is not negligible when each flip-flop requires two radio valves. I don't remember whether my first machine had such an output register, but the second machine had one of six bits. Sheer luxury!)

In the above description, I skipped a minor problem: I said that during those 100 ms "having the A-register at its full disposal, the unhampered calculator continues to calculate" but what if, during those 100 ms it tries to execute another type instruction? This would change the contents of the output register and hence interfere with the process of printing the current character. Perhaps even typewriter arms could get entangled!

What to do? We can leave the calculator unhampered but burden the programmer with the obligation not to write —not even accidentally!— programs that might entangle the typewriter arms, but this option is generally considered to be unacceptable. The arrangement would violate the reasonable requirement that no (cheap) program should be able to damage your (expensive) machine. It would have a further disadvantage of a type that was recognized only later: suppose that a technical improvement would speed up the calculator by a factor of 2, then, as a result, a formerly acceptable program could now damage the typewriter by executing a next type instruction too soon (This is called "a real-time consideration"; we'll return to this issue later.)

The next alternative is a little hardware extension that conditionally hampers the calculator indeed: during the 100m ms, the calculator can work at full speed unless it tries to execute a type instruction, for in that case it is instantly frozen and only allowed to proceed after the 100 ms has expired. (Depending on the mechanical properties of the typewriter, it could be that a period of 100 ms is not homogeneously appropriate: because of movement of the carriage, TAB and NLCR might need more time. If so, the period's dependence on the "character" typed should be incorporated in the hardware extension if we want to keep the programming of the calculator free of real-time considerations.)

I would like to stress that with this conditional freezing of the calculator, we have achieved CCC (= Completely Concealed Concurrency) in the sense that our two machines (i.e., with and without the output register) are now functionally equivalent in the sense that, fed with the same program, they will produce exactly the same output. As long as speed of execution is unobservable, it is impossible to determine which of the two machines did execute your program. (Hence the name CCC.)

Thus CCC improved the efficiency by allowing the simultaneous activity of temporarily independent system components without any of the potential complications of concurrency, and that was its great virtue, but the comfortable invisibility of concurrency had a high price.

The first machine in which I saw that price paid in full was the Telefunken TR4. It incorporated CCC on a scale much more grandiose than the 4- or 6-bit output register I just described. The store of the TR4 was partitioned into 8 or 16 banks —I don't remember the exact number— and the central processor could initiate a communication action —say reading or punching a punched card— involving information between the communication device and a specified storage bank. During the information transport the CPU could continue calculating as long as it did not address that specified bank; when it did, it would be held up until the communication action had been completed. Several communication actions could be active simultaneously provided they each had their own bank. It was CCC in its full glory.

Consider now a program that has to process many punched cards, while the order in which this happens is irrelevant —say we are adding voting counts—. Suppose furthermore that the machine is fast enough to engage all its card readers in this process; in that case we would like to do that, with each card reader running at its maximum speed most of the time. Note (i) that the card readers, being independent pieces of equipment, cannot be expected to have the same speeds, and (ii) that a card reader's speed need not be constant, as it is zero when the input tray is empty.

To maximize throughput, we would like each reader to read at its maximum speed most of the time, which means that the calculator should issue for each reader the next communication command as soon as possible after the completion of its preceding communication action. In particular, with the calculator idling for lack of input, one would like it to continue as soon as one of the readers has completed its input action, but with CCC, the calculator has no means of identifying the input stream: the invisibility of concurrency has made the notion of "first-come-first-served" inapplicable. The moral of the story was that, essentially for the sake of efficiency, concurrency should become somewhat visible. It became so, and then, all hell broke loose.

Pandora's box

Enabling the central processor to react to the relative timing of progress of the various communication devices created a host of new problems, so new that we didn't really know how to think and talk about them and what metaphors to use. To mention one example, people were used to view the control of the whole installation as localized in the central processor: wasn't that the component that issued its commands to the communication devices, wasn't that what the popular literature called "the electronic brain"? Now, suddenly it looked as if the central processor might have to serve a peripheral device at its bidding! Weren't we trying to switch from one master with many slaves to one slave having to serve many masters (who might give incompatible orders)? People felt like facing a revolution they did not understand. Needless to say, the widespread use of anthropomorphic terminology only aggravated the situation. [Here I must confess to having prolonged the confusion somewhat by later introducing "directors" and "secretaries"; fortunately this was in a paper that has largely been ignored.]

In retrospect, the problems were in roughly three areas:

(i) The basic mechanics of switching the central processor from one task to another,

(ii) The strategy for scheduling the central processor and the scope of its commitment,

(iii) The logical problems that emerge when a number of resources are shared by a number of competitors,

and all that without theories or agreed criteria that could assist you in your choice between the options. Those years taught me that the ability to detect timely that some theory is needed is crucial for successful software design.

The simplest idea, which was often suggested for process control, was to have one "physical machine" simulate a small number of "logical machines", each coupled to its own device, such that the state of the device would determine whether the corresponding logical machine could proceed. Each logical machine was given its own priority and at each moment the physical machined would simulate of the logical machines that could proceed the one with the highest priority. The priorities and the way they controlled the allocation of the single processor were built-in hardware features of the physical machine.

The idea was that the logical machine of the highest priority would be coupled to the device with short, urgent, frequent messages, while those of lower priority would be coupled to device that could be served more leisurely. If so desired, the one of the lowest priority could be devoted to an interesting "background" computation, say the generation of prime numbers, because it would be a pity to leave that expensive processor idling.

The above arrangement was usually all right as long as the logical machines were coupled to independent experiments, but as soon as logical machines had to communicate with each other, for instance because they dealt with different aspects of the same experiment, things became very difficult. In principle, logical machines could communicate with each other by writing and reading it [sic] the common store, but as a rule safe communication was very tricky if not impossible. It was quite common to take the risk that things would go wrong, as they would when the central processor was reallocated exactly at an inopportune moment, and in many an installation the risk had been taken unconsciously. (The frequency with which today your desktop system crashes in an irreproducible manner suggests that such bugs are still quite common).

Furthermore the above arrangement turned out to be too rigid for general-purpose computing: it is quite easy to think of a process in which the actions of very different urgency alternate. (What about a child who throws a ball into the air when it feels like it and then has to catch the ball?)

More flexibility was achieved by the introduction of "probe instructions" that enabled the central processor to test whether a concurrent activity it had started earlier had, in the mean time, been completed. Such probes are tricky: while the answer "Yes" is reliable, the answer "No" can become obsolete as soon as it has been given. (The designers of the IBM 360 of 1964 had still fallen into this trap, with the result that users of "command chaining" had to accept the risk that a communication command got lost!)

But the inclusion of probe instructions created all sorts of dilemmas. Since the execution of the probe instruction takes time, probing with high frequency could noticeably slow down the computation, while probing with low frequency could increase the computer's reaction time too much. But even if we can agree on a frequency that may not be the end of our problems. Say that you would like to probe every 100 instructions, do you insert a probe instruction into a loop body of 10 instructions? If you do, you might probe with unnecessarily high frequency, if you don't, you might probe with undesirably low frequency. Your subroutine library presents another problem; you might find yourself tempted to introduce each subroutine in two versions, one with probe instructions and one without.

The third arrangement, known as "the interrupt", circumvents all these dilemmas. While the computer calculates at full speed, a piece of dedicated hardware monitors the outside world for completion signals from communication devices. When a completion is detected, the program under execution is interrupted after the current instruction and in such a fashion that it can be resumed at a later moment as if nothing had happened, thus instantaneously freeing the central processor for a suddenly more urgent task. After the interrupt the processor would execute a standard program establishing the source of the interruption and taking appropriate action.

It was a great invention, but also a Box of Pandora. Because the exact moments of the interrupts were unpredictable and outside our control, the interrupt mechanism turned the computer into a nondeterministic machine with a nonreproducible behavior, and could we control such a beast?

Below I shall address the major issues as I now remember encountering them; unavoidably this is very much a description "in retrospect": a lot of the terminology I use now did not exist at the time, nor were different issues as clearly separated as they are now. (The now common expression "separation of concerns" hadn't been coined yet.)

I had designed the basic software for the ARRA, the FERTA and the ARMAC, and was going to do the same for the X1, the next machine my hardware friends Bram J. Loopstra and Carel S. Scholten were designing. At the time I was quite used to programming (in machine code) for machines that didn't exist yet; at the time the hardware got operational, I would have all the communication programs ready. The machines could execute programs one instruction at a time so that one could inspect intermediate states when something went wrong.

Halfway the functional design of the X1, I guess early 1957, Bram and Carel confronted me with the idea of the interrupt, and I remember that I panicked, being used to machines with reproducible behaviour. How was I going to identify a bug if I had introduced one? After I had delayed the decision to include the interrupt for 3 months, Bram and Carel flattered me out of my resistance, it was decided that an interrupt would be included and I began to study the problem. To start with I tried to convince myself that it was possible to save and restore enough of the machine state so that, after the servicing of the interrupt, under all circumstances the interrupted computation could be resumed correctly.

This turned out to be a very rewarding exercise, for not only was I unable to prove the possibility, I could demonstrate the impossibility as well. Bram and Carel changed their design accordingly, after which I designed a protocol for saving and restoring that could be shown always to work properly. For all three of us it had been a very instructive experience. It was clearly an experience that others had missed because for years I would find flaws in designs of interrupt hardware.

I designed the interrupt handler and the asynchronous conversion routines —"the input/output programs"— for the basic peripherals each copy of the machine would be equipped with. It was the code that each copy of the machine would have wired in. It comprised slightly over 900 instructions, it was the work with which I earned my Ph.D. and no one would call it an operating system: the machine was envisaged as a uniprogramming system with concurrent activity of the peripherals, which can request the attention of the central processor.

An interlude

After the completion of these communication programs I was for a couple of years otherwise engaged, first with writing other programs for the X1 —that was the name of the machine for which I designed the interrupt handler— and then thinking about compilers and ALGOL 60, which we implemented at the Mathematical Centre, essentially during the first half year of 1960.

As a consultant to Electrologica —the manufacturer of the X1— I participated in discussions on how to attach punched-card equipment, and in the process I became very wary of what later would become known as "real-time problems". We called them "situations of urgency", i.e. the situations in which the computer had to react or to produce a result "in time". I remember, for instance, a device in which a punched card would pass, in order, a reading station, a punching station, and a final reading station. The role of the final reading station was simply to check that the card leaving the device had the proper holes, and that was no serious problem. The difficulty came from the combination of two circumstances, viz.

(i) in most applications, the additional information to be punched into a card would depend on what had already been punched into it, i.e., the computer would have to perform a problem-specific computation between the reading and the punching of the same card, and

(ii) once a card had been fed into the first reader, it could no longer be stopped and would inexorably pass the other stations so many milliseconds later.

We learned to distinguish between "essential urgency", where failure to be in time would derail the computation, and "moral urgency", where the failure would only hurt the efficiency (say in the form of a missed drum revolution). This was an important lesson for it taught us that in resource allocation —a problem we would tackle a few years later in its full glory— one could (and therefore should) separate the concerns of necessity and of desirability.

Connecting the machine to one card punch of the type I described was bad, connecting it to two of them was terrible. I found the combination of resource sharing and real-time constraints totally untractable and, slowly, the avoidance of urgency situations became a conscious goal. Choosing peripherals that could be stopped and introducing enough dedicated buffers often did the job.

But, as said, until mid 1960 I was otherwise engaged. In the summer of 1959, I was one of the many programmers who invented a stack to implement recursion. (This was EWD6, written during a holiday in "Het Familiehotel" in Paterswolde, in the northern part of the Netherlands. The manuscript no longer exists.) That fall, I embarked on parsing problems, and then we implemented ALGOL 60 on the X1. At the time the ALGOL implementation was by far the most ambitious undertaking I had ever embarked on, and I knew that I would never get the thing working unless the structure of the compiler and of the object programs were as clear, simple and systematic as I could get them. It was my first effort at implementation and the result was not clean at all by later standards when bootstrapping had become a well-mastered technique, but as far as I was concerned that did not matter. I had learned that a programmer should never make something more complicated than he can control. (Of course, the fact that the X1 I was implementing ALGOL 60 for had only 4K words of storage helped to keep things simple.)

Multiprogramming

For IBM machines, the purpose of "operating systems" —and hence their name— was to assist the operators in juggling tape reels and decks of cards, a purpose that never appealed to me since I have always been a paper-tape person.

Other cultures were driven by the perception that, at least for the next decade, processors would be too expensive to let them lie idle half the time and stores fast enough to match the processor's speed would be relatively small, so that a multi-level store was something we should have to live with. Examples reflecting this vision were the Burroughs B 5000 and its successors (USA), the Ferranti/Manchester ATLAS (UK) and the Electrologica/Eindhoven X8 (NL), machines that in contrast to IBM's products, were loved by their user communities. Besides the decade of syntax, the 60s also became the decade of demand paging and replacement algorithms, but in the summer of 1960, all that was still future for me.

I resumed my ponderings about the synchronization between independently clocked entities, and to begin with I did so, true to my past experience, in the context of a central processor coupled to all sorts of peripheral gear, and I still remember my excitement about an in retrospect totally trivial discovery.

I recall the coupling between the computer and its output typewriter with the output register between the computer's A-register and the typewriter decoder, where the computer would be temporarily frozen if it tried to execute the next type instruction before the execution of the previous type instruction had been completed. The exciting discovery was one of symmetry: just as the computer could be temporarily frozen because the typewriter wasn't ready for the next type action, so could the typewriter be temporarily frozen because the computer was not ready yet for the next type action; just as the computer could have to wait until the output buffer was empty, the typewriter could have to wait until the output buffer was filled.

To see the precious milliseconds being lost because the expensive computer was being delayed by a cheap, slow peripheral was most regrettable, but when that same cheap, slow typewriter was idle because there was nothing to be typed, we could not care less. The excitement came from the recognition that the difference in emotional appreciation was irrelevant and had better be forgotten, and that it was much more significant that from a logical point of view they were two instances of the same phenomenon. In retrospect, this insight should perhaps be considered more radical than it seemed at the time, for decades later I still met system designers who felt that the maximization of the duty cycle of the most expensive system components was an important insight.

With the symmetry between CPU and peripheral clearly understood, symmetric synchronizing primitives could not fail to be conceived and I introduced the operations P and V on semaphores. Initially my semaphores were binary, reflecting that the output register I described earlier could be empty or filled. When I showed this to Bram and Carel, Carel immediately suggested to generalize the binary semaphore to a natural semaphore, a generalization that would greatly enhance the usefulness of the semaphore concept: it enabled us to generalize the one-character output register to an output buffer of any size. How valuable this generalization was we would soon discover.

The component taking care of the information transport between store and peripheral was called "a channel"; our channels could be active concurrently with the CPU and as a rule their activity was synchronized with the peripheral they served.

Then simplest channels would accept one "command" at a time; this would be, say, the reading of a card, the writing of a block on magnetic tape or the reading of half a track of information from the drum. For an act of communication the CPU would specify its parameters at a dedicated location and then would send a start signal to the channel. After an act of communication, the raising of an interrupt flag would signal the completion to the CPU, which was then free to present the next communication command to the channel.

Many peripherals could be designed in such a way that they did not confront the CPU with real-time obligations, with situations of "essential urgency", for instance, the magnetic tape unit would stop automatically if the next command to write a block of information would not come soon enough, other devices like card readers or drums would just miss a cycle or a revolution. So far, so good, but the problem was, that these same devices would often now confront the CPU with situations of "moral urgency": it was such a pity that it really hurt if the channel did not get its next command in time.

The solution was to allow the CPU to build up a queue of commands and to enable the channel to switch without CPU intervention to the next command in the queue. Synchronization was controlled by two counting semaphores in what we now know as the producer/consumer arrangement: the one semaphore, indicating the length of the queue, was incremented (in a V) by the CPU and decremented (in a P) by the channel, the other one, counting the number of unacknowledged completions, was incremented by the channel and decremented by the CPU. [The second semaphore being positive would raise the corresponding interrupt flag.]

In the IBM/360, which appeared a year later, such queueing was done by "command chaining": in the chain of queued commands, the last one carried an end marker, and attaching a new command was done by overwriting that end marker by a pointer to the command to be attached. But the design contained two serious flaws.

If at the moment of attachment the channel was still active, the new command would be executed in due time, otherwise the channel had to be reactivated. To establish whether this obligation was present, the instruction code contained test instructions testing whether channels were active or not, but the trouble with such a test instruction is that when a channel is reported to be still active, that information can be obsolete a microsecond later. In the IBM/360 the result was that, when a new command had been attached while before the attachment the channel was observed to be active and after the attachment it was passive, this information was insufficient to determine whether the channel had deactivated itself before or after the attachment, i.e. whether the last command had been executed or not.

Reporting completions was similarly defective. Command chaining had introduced channels that in due time would report a sequence of completions, but instead of a counter there was only the binary interrupt flipflop to record a next completion. If an interrupt signal came before the previous one for that channel had been honored, it would just get lost! They had traded the minor evil of moral urgency for the major one of essential urgency.

At the time I was shocked by the fact that the major product of the world's largest and most powerful computer manufacturer could contain such a serious blunder. Later I realized that to a certain extent I myself was to be blamed, for when I invented the semaphores and the synchronizing primitives, I did not publish my invention. We did not keep it secret, we lectured freely about the topic, but did not publish it until the end of the decade. This was a self-imposed censorship. I knew that it would determine the channel organization of the EL X8, the next machine of the NV Electrologica, of which I was a consultant. Trusting that the lovely channel organization of the EL X8 would be a major selling point of the machine, I did not broadcast my invention among the competition. At that time I clearly still believed in a positive correlation between a product's technical quality and its commercial success. In retrospect I am sorry that I postponed widespread publication until 1967 and think that I would have served mankind better if I had enabled The Evil One to improve its product.

For economic reasons one wants to avoid in a multiprogramming system the so-called "busy form of waiting", in which the central processor is unproductively engaged in the waiting cycle of a temporarily stopped program, for it is better to grant the processor to a program that may actually proceed. This economic consideration was in 1961/62 a strong incentive for the introduction of the P/V-synchronization mechanism, which made it explicit to the scheduler when a program was no candidate for processor time. An in retrospect more profound incentive, however, came from an experience I had in 1959 at the Computation Department of the Mathematical Center in Amsterdam.

I had invented what, in that environment at least, was a new type of problem. Consider two cyclic processes, each consisting of an alternation of "a critical section" and "a noncritical section". Was it possible to synchronize these two processes such that at any moment at most 1 of these processes would be engaged in its critical section? The way in which the processes could communicate was by atomic reads and writes in a common store. After having convinced myself that —at least according to the State of the Art of those days— the answer was not obvious, I broadcast the problem to the members of the Computation Department for their general amusement and distraction. It was given that each execution of a critical section would only take a finite amount of time and it was required that a process ready to execute would in due time get the opportunity to do so.

Many purported solutions were handed in, but on closer inspection they were all defective, and my friends realized that the problem was harder than they had suspected and that their simple "solutions" wouldn't do. Fortunately my friends didn't give up and they handed in "improved" versions of their earlier efforts. But as their designs became more and more complicated, it became harder and harder to construct a counterexample. I couldn't keep up with them and had to change the rules of this programming contest: besides a program I required a proof that the program had all the desired properties.

And then something profound and lovely happened. By analyzing by what structure of argument the proof obligations could be met, the numerical mathematician Th.J. Dekker designed within a few hours the above solution together with its correctness argument, and this settled the contest. In the above solution, the pair "c1,c2" implements the mutual exclusion, while "turn" has been introduced to resolve the tie when the two processes simultaneously try to enter their critical sections.

To capture the spirit of the time, I have presented Dekker's solution as a flow chart of the type we then used to design and document our programs. It looks very simple, there are only 3 commonly accessible bits, two, "c1 & c2", written by one process and inspected by the other, and a third one, "turn", which is written and read by both. But how great an invention it was is shown by the fact that the generalized problem for N processes, instead of for two, was only solved in 1965; the latter solution was also considered a tour de force.

The profound significance of Dekker's solution of 1959, however, was that it showed the role that mathematical proof could play in the process of program design. Now, more than 40 years later, this role is still hardly recognized in the world of discrete designs. If mathematics is allowed to play a role at all, it is in the form of a posteriori verification, i.e. by showing by usually mechanized mathematics that the design meets its specifications; the strong guidance that correctness concerns can provide to the design process is rarely exploited. On the whole it is still "Code first, debug later" instead of "Think first, code later", which is a pity, but Computing Science cannot complain: we are free to speak, we don't have a right to be heard. And in later years Computing Science has spoken: in connection with the calculational derivation of programs —and then of mathematical proofs in general— the names of R.W. Floyd, C.A.R. Hoare, D. Gries, C.C. Morgan, A.J.M. van Gasteren and W.H.J. Feijen are the first to come to my mind.

At the time, the most tangible and most influential abstraction was the notion of loosely coupled sequential processes, their most essential property being their undefined speeds. You could not even assume individual speeds to be constant. This notion eliminated in one fell swoop all analogue arguments about time, all synchronization needed for logical reasons had to be coded explicitly, and consequently only discrete reasoning was needed to establish the system's correctness. Compared with all alternatives, this was a tremendous simplification. This is now so obvious that it is hard to recognize today that at the time an invention was involved, but there was. It was before the term "layers of abstraction" had been coined, and I remember being blamed for ignoring speed ratios also when they were perfectly known: I as accused of throwing away possibly valuable information and had to defend my decision by pointing out that I was heading for a superior product in the sense that no reprogramming would be required when, say, the line printer would be replaced by a faster model.

For me the main virtue as that the logical correctness now no longer depended on real-time considerations: the term "tremendous simplification", which I used above, was no exaggeration. It made it possible for us to know so well what we were doing that there was no need "to debug our design into correctness". I have two pregnant memories of how differently others tried to work.

When the design of the THE Multiprogramming System neared its completion the University's EL X8 was getting installed, but it had not been paid yet, and we hardly had access to it because the manufacturer had to put it to the disposal of an American software house that was supposed to write a COBOL implementation for the EL X8. They were program testing all the time, and we let it be known that if occasionally we could have the virgin machine for a few minutes, we would appreciate it. They were nice guys, and a few times per week we would get an opportunity for our next test run. We would enter the machine room with a small roll of punched paper tape, and a few minutes later we would leave the machine room with the output we wanted. I remember it vividly because when they realized what we were achieving, our minimal usage of the machine became more and more frustrating for them. I don't think their COBOL implementation was ever completed.

The other vivid memory is of what I heard about IBM's mechanical debugging aid. In order to make errors reproducible they equipped the IBM/360 with a special hardware monitor; in the recording mode it would capture precisely where in the computation each interrupt took place, in the controlling mode it would force the computer to replay exactly the recorded computation, thus making intermediate results available for inspection. It struck me as a crude and silly way of proceeding, and I remember being grateful that lack of money had protected me from making that methodological mistake. I felt grateful and superior, and when a few years later it became clear that IBM couldn't get its OS/360 right, I was not amazed.

*               *
*

The period I more or less covered started while I was a staff member at the Computation Department of the Mathematical Centre in Amsterdam, it ended while I was professor of mathematics at the Eindhoven University of Technology. The graduates of our department got the official academic title of "Mathematical Engineer".

In the beginning I knew that programming posed a much greater intellectual challenge that generally understood of acknowledged, but my vision of the more detailed structure of that vision was still vague. Halfway the multiprogramming project in Eindhoven I realized that we would have been in grave difficulties had we not seen in time the possibility of definitely unintended deadlocks. From that experience we concluded that a successful systems designer should recognize as early as possible situations in which some theory was needed. In our case we needed enough theory about deadlocks and their prevention to develop what became known as "the banker's algorithm", without which the multiprogramming system would only have been possible in a very crude form. By the end of the period I knew that the design of sophisticated digital systems was the perfect field of activity for the Mathematical Engineer.

Austin, October 2000 / April 2001

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Ham Richards; corrections by Martijn van der Veen.
Last revised Thu, 12 Aug 2010.

EWD1304

The end of Computing Science?

"The price of reliability is the pursuit of the utmost simplicity. It is a price which the very rich find most hard to pay."

Sir Antony Hoare, 1980

In academia, in industry, and in the commercial world, there is a widespread belief that computing science as such has been all but completed and that, consequently, computing has "matured" from a theoretical topic for the scientists to a practical issue for the engineers, the managers and the entrepreneurs, i.e. mostly people —and there are many of those!— who can accept the application of science for the obvious benefits, but feel rather uncomfortable with its creation because they don't understand what the doing of research, with its intangible goals and its uncertain rewards, entails. This widespread belief, however, is only correct if we identify the goals of computing science with what has been accomplished and forget those goals that we have failed to reach, even if they are too important to be ignored.

I would therefore like to posit that computing's central challenge, viz. "How not to make a mess of it", has not been met. On the contrary, most of our systems are much more complicated than can be considered healthy, and are too messy and chaotic to be used in comfort and confidence. The average customer of the computing industry has been served so poorly that he expects his system to crash all the time, and we witness a massive worldwide distribution of bug-ridden software for which we should be deeply ashamed.

For us scientists it is very tempting to blame the lack of education of the average engineer, the short-sightedness of the managers and the malice of the entrepreneurs for this sorry state of affairs, but that won't do. You see, while we all know that unmastered complexity is at the root of the misery, we do not know what degree of simplicity can be obtained, nor to what extent the intrinsic complexity of the whole design has to show up in the interfaces. We simply do not know yet the limits of disentanglement. We do not know yet whether intrinsic intricacy can be distinguished from accidental intricacy. We do not know yet whether trade-offs will be possible. We do not know yet whether we can invent for intricacy a meaningful concept about which we can prove theorems that help. To put it bluntly, we simply do not know yet what we should be talking about, but that should not worry us, for it just illustrates what was meant by "intangible goals and uncertain rewards".

And this was only an example. The moral is that whether Computing Science is finished will primarily depend on our courage and our imagination.

Austin, 19 November 2000

[Written for the Communications of the ACM]

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcription by James Lu.
Last revision: Sat, 24 Nov 2007.

EWD 1305

Answers to questions from students of Software Engineering

[The approximate reconstruction of the questions is left as an exercise to the reader.]

Gadgets are not necessarily an improvement, vide the succession

Blackboard -> Overhead Projector -> Power Point

And I don't need to waste my time with a computer just because I am a computer scientist.

[Medical researchers are not required to suffer from the diseases they investigate.]

It is not the business of computing science to promote "computerization", say by developing demanding applications so as to create a market for the next generation of hardware.

[Medical researchers are not required to develop new diseases so as to create a market for more pharmaceutical products.]

It is not the task of the University to offer what society asks for, but to give what society needs.

[The things society asks for are generally understood, and you don't need a University for that; the university has to offer what no one else can provide.]

We are all shaped by the tools we use, in particular: the formalisms we use shape our thinking habits, for better or for worse, and that means that we have to be very careful in the choice of what we learn and teach, for unlearning is not really possible.

[Many years ago, if I could use a new assistant, one prerequisite would be "No prior exposure to FORTRAN", and at high schools in Siberia, the teaching of BASIC was not allowed.]

A programmer has to be able to demonstrate that his program has the required properties. If this comes as an afterthought, it is all but certain that he won't be able to meet this obligation: only if he allows this obligation to influence his design, there is hope he can meet it. Pure a posteriori verification denies you that whole-some influence and is therefore putting the cart before the horse, but that is exactly what happens in the software houses where "programming" and "quality assurance" are done by different groups. [Needless to say, those houses deliver without warranty.]

The required techniques of effective reasoning are pretty formal, but as long as programming is done by people that don't master them, the software crisis will remain with us and will be considered an incurable disease. And you know what incurable diseases do: they invite the quacks and charlatans in, who in this case take the form of Software Engineering gurus.

Some of you doubt that aforementioned "techniques of effective reasoning", nice as they are for small programs, will scale up, I quote "given the daunting size and sheer complexity of most programs". Well, they will be powerless if you try to use them to disentangle the horrendous mess produced by a group of incompetent, unorganized programmers. Their power manifests itself in the construction phase where (i) they tend to lead to much shorter texts than would be produced otherwise and (ii) lengths of program derivations tend to grow not much more than linearly with the lengths of the programs derived. Finally the programs thus produced are infinitely better than the usual junk.

We should never forget that programmers live in a world of artefacts, a fact that distinguishes them from most other scientists. The programmer should not ask how applicable the techniques of sound programming are, he should create a world in which they are applicable; it is his only way of delivering a high-quality design. To which I should add a quotation from EWD898 (1984)

"Machine capacities now give us room galore for making a mess of it. Opportunities unlimited for fouling things up! Developing the austere intellectual discipline of keeping things sufficiently simple is in this environment a formidable challenge, both technically and educationally."

In reply to questions why we teach useless things that industry ignores, I refer you to EWD920 (1985). Let me quote here one paragraph

"Back to our original question: can computing science save the computer industry? My answer is "If the computer industry can be saved, only computing science can do it.". But it may take a long time before the computer industry —in particular the well-established companies— will share this view. It will almost certainly take longer than the limited period over which they plan their futures. In the mean time, the academic world —which traditionally plans much further ahead— has no choice. It has to refine and to teach to the best of its abilities how computing should be done; would it ever yield to the pressure to propagate the malpractice of today, it had better fold up.".

But to stress how much patience we need, let me give you another old quotation (from 1988)

"Too few people recognize that the high technology so celebrated today is essentially a mathematical technology."

(from the 2nd David-report, so named after the committee's chairman Dr. E. E. David Jr.)

No, I'm afraid that computer science has suffered from the popularity of the Internet. It has attracted an increasing —not to say: overwhelming!— number of students with very little scientific inclination and in research it has only strengthened the prevailing (and somewhat vulgar) obsession with speed and capacity.

Yes, I share your concern: how to program well —though a teachable topic— is hardly taught. The situation is similar to that in mathematics, where the explicit curriculum is confined to mathematical results; how to do mathematics is something the student must absorb by osmosis, so to speak. One reason for preferring symbol-manipulating, calculating arguments is that their design is much better teachable than the design of verbal/pictorial arguments. Large-scale introduction of courses on such calculational methodology, however, would encounter unsurmountable political problems.

In the software business there are many enterprises for which it is not clear that science can help them; that science should try is not clear either.

Austin, 28 November 2000

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcription by James Lu.
Last revision: Sat, 24 Nov 2007.

EWD 1306

The chessboard covered with dominoes

We consider a partitioning of the squares of the 8×8 chessboard into 32 pairs of adjacent squares and call a pair of squares in the same row (column) “a horizontal (vertical) domino”. Then the number of horizontal dominoes with a black left square equals that of those with a white left square. [Corollary: the number of horizontal dominoes is even.]

Proof   Consider for a given partitioning one of the seven lines that separate two adjacent columns; it divides the board into a left and a right part. We observe that (i) because the column length is even, each column, and hence the left part consists of equal numbers of black and white squares, and (ii) because domino consists of a black and a white square, the dominoes entirely to the left of the line comprise equal numbers of black and of white squares. Combining the two observations, we conclude about the horizontal dominoes crossed by the line —i.e., the dominoes with 1 square at either side of the line— that there are as many with a black left square as with a white one. Since each horizontal domino is crossed by exactly one of the seven lines, we now can conclude by summation that the total number of horizontal dominoes with a black left square equals the total number of those with a white left square.

(End of Proof)

Note that of the chessboard dimensions, we only used that the height is even.

Acknowledgement   I owe thanks to Jayadev Misra who inspired me to write this down and to Jan L.A. van de Snepscheut, who contributed part of the argument.

Austin, 5 February 2001

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

Transcription by Xiaozhou (Steve) Li.
Last revision: Wed, 4 May 2016.

EWD 1306a

The chessboard covered with dominoes

Claim We consider a partitioning of the squares of a chessboard into 32 pairs of adjacent squares, and call each pair a domino. A domino whose squares are in the same row we call a horizontal domino. We claim that the number of horizontal dominoes with a black left square and the number of horizontal dominoes with a white left square are equal. [Corollary: the number of horizontal dominoes is even.]

Proof For a given partitioning, consider one of the seven lines that separate two adjacent columns; it divides the board into a left and a right part. We observe that

because the column length is even, each column, and hence the left part, contains equal numbers of black and white squares, and

because a domino consists of a black and a white square, the dominoes entirely to the left of the line comprise equal numbers of black and white squares.

Combining the two observations, we conclude that, among the horizontal dominoes crossed by the line, there are as many with a black left square as with a white one. Since each horizontal domino is crossed by exactly one of the seven lines, we conclude by summation that the number of horizontal dominoes with a black left square and the number of horizontal dominoes with a white left square are equal.

(End of Proof)

Note that of the chessboard dimensions, we only used that the height is even.

Acknowledgement I owe thanks to Jayadev Misra, who inspired me to write this down, to Jan L.A. van de Snepsheut, who provided a major part of the argument, and to Ham Richards, who contributed stylistic improvements.

Austin, 11 February 2001

prof. dr. Edsger W. Dijkstra
Department of computer Sciences
The University of Texas at Austin
Austin, TX 78712 - 1188
USA

Transcription by James Lu.
Last revision: Sat, 24 Nov 2007.

EWD1307

An unavoidable case analysis

Archiving old manuscripts, I found at the end of EWD766 "An educational stupidity" of more than 20 years ago the following exercise:

"Prove that none of the decimal numbers 1001, 1001001, 1001001001, 1001001001001, ... is prime." [It is not clear why I underlined "none". EWD]

Here is a proof. Denoting by k*<string>* the concatenation of k copies of the digit string enclosed, we deal with the decimal numbers

k*001*       for k ≥ 2

If k mod 3 = 0, the number is, according to the traditional 3-test, divisible by 3 because the sum of its decimal digits, which equals k, is divisible by 3.

If k mod 3 ≠ 0, we see by generalising the traditional 9-test to the k*9*-test, that the number reduced modulo k*9* equals k*1*. Hence the number is divisible by k*1* (because k*9* is). (Note that this observation does not exclude primality for k=1.)

In argument (i), the crux is the validity of the 3-test, which is valid whenever base mod 3 = 1, a condition that base 10 (= ten) satisfies. The conclusion has nothing to do with the accident that the length of the repeated string happens to be 3: for k mod 3 = 0, also k*00001*  is divisible by 3.

In argument (ii) we generalized the 9-test because the problem was about decimal numbers, but for any base B (B ≥ 2) there is a (B−1)-test, and k*1* divides k*(B−1)*. The conclusion that the number reduced modulo k*(B−1)* yields k*1*, however, depends on the fact that k has no factor in common with the length of the iterated string. Argument (ii) is base independent: interpreting *k001* and *k1* in binary, we find for instance that for k=4 and k=5, 585 is divisible by 15 and 4681 by 31.

Argument (i) relies on a relation between k and the base of the number system, (ii) on a relation between k and the length of the iterated string.

Austin, 18 March 2001

prof.dr. Edsger W. Dijkstra
Department of Computer Science
The University of Texas at Austin
Austin, TX 78712-1188, USA

Transcriber: Kevin Hely.
Last revised on Sat, 24 Nov 2007.

EWD1308

What led to "Notes on Structured Programming"

The purpose of this historical note is to describe the experiences which in hindsight seem to have influenced me when I wrote EWD249 "Notes on Structured Programming" in 1969. The note is based on what I remember; I am sure my memory has been selective and hence don't claim the objectivity of the professional historian.

I was introduced to programming at the 1951 Summer School, given in Cambridge by Wilkes. Wheeler and Gill, and became in 1952 on a part-time basis ℄initially 2 days per week℄ the programmer of the Mathematical Centre in Amsterdam; the rest of the week I studied Theoretical Physics in Leyden.

My only model was the program organization for the EDSAC in Cambridge; I followed it closely when designing program notation, input, output and library organisation for the ARRA in Amsterdam. For the next machines, the FERTA, the ARMAC and the X1, program notation and input would very much follow the same pattern: I clearly was a conservative programmer. Add to this that the ARMAC's instruction buffer with a capacity of one track of the drum, destroyed the store's homogeneity, and you will understand that I did not embark on adventures like "autocoders".

In 1955 I took the decision not to become a theoretical physicist, but to become a programmer instead. I took that decision because I had concluded that of theoretical physics and programming, programming embodied the greater intellectual challenge. You see, in those days I did not suffer from intellectual modesty. It was a difficult decision, for I had been groomed as first-class scientist and becoming a programmer looked like a farewell from science. When I explained to A. van Wijngaarden, my then boss, my dilemma, he told me that computers were here to stay and that in the world of programming I could be very well be the one called to create the science that was still lacking. Getting my physics degree in Leyden became a formality to be done with as quickly as possible. (As a matter of fact I no longer felt welcome in Leyden: the physicists considered me as a deserter and the mathematicians, one of whom openly prided himself on "of course knowing nothing about computers", were just contemptuous.)

In the mean time a pattern emerged for the cooperation between me and my hardware colleagues Bram J. Loopstra and Carel S Scholten. After the functional specification of the next machine had been written down (usually by me), that document served as a kind of contract between us: it told them what machine to design and construct, while I knew what I could count upon while writing all the basic software for the machine. The target of this division of labour was that my programs would be ready by the time the construction of the machine had been completed.

Looking back I now observe that the above arrangement has had a profound influence on how I grew up as programmer: I found it perfectly normal to program for not yet existing machines. As a byproduct it became firmly ingrained in my mind that I programmed for the abstract machine as specified in the original document, and not for the actual piece of hardware: the original document was not a description but a prescription, and in the case of a discrepancy not the text but the actual hardware would be at fault.

At the time I regarded this division of labour and the resulting practice of programming for non-existing machines as perfectly normal. Later I read an American article on why software was always late; I remember being very amazed when I read that limited availability of the hardware was the main cause, and I concluded that the circumstances under which I had learned programming had been less common than I had assumed.

Of course I could not exclude from my designs typographical errors and similar blemishes, but such shortcomings did not matter as long as the machine was not ready yet, and after the completion of the machine they could be readily identified as soon as they manifested themselves, but this last comforting thought was denied to me in 1957 with the introduction of the real-time interrupt. When Loopstra and Scholten suggested this feature for the X1, our next machine, I got visions of my program causing irreproducible errors and I panicked.

Eventually, Loopstra and Scholten flattered me out of my resistance and I studied their proposal. The first thing I investigated was whether I could demonstrate that the machine state could be saved and restored in such a way that interrupted programs could be continued as if nothing had happened. I demonstrated instead that it could not be done and my friends had to change their proposal. Admittedly the scenarios under which the original proposal would fail were very unlikely, but this can have only strengthened my conviction that I had to rely on arguments rather than on experiments. At the time that conviction was apparently not so widespread, for up to seven years later I would find flaws in the interrupt hardware of new commercial machines.

I had a very illuminating experience in 1959, when I had posed my colleagues at the Mathematical Centre the following problem. Consider two programs that communicate via atomic reads and writes in a shared store; can they be programmed in such a way that the execution of their critical sections exclude each other in time? Solutions came pouring in, but all wrong, so people tried more and more to elaborate counterexamples for their refutation, I had to change the rules: besides the programs they had to hand in an argument why the solution was correct.

Within a few hours, Th. J. Dekker handed in a true solution with its correctness argument. Dekker had first analysed the proof obligations, then chosen the shape of an argument that would meet them, and then constructed the program to which this argument was applicable. It was a very clear example of how much one loses when the role of mathematics is confined to a posteriori verification; in 1968 I would publish a paper titled "A constructive approach to the problem of program correctness".

And then there was ALGOL 60. We saw it coming in 1959 and implemented it in the first half of 1960. I was terribly afraid, for this implementation was then by far my most ambitious project: ALGOL 60 was so far ahead of its time that even its designers did not know how to implement it, I had never written a compiler and had to achieve my goal with a machine that had only 4096 word of storage. (The latter constraint was of course a blessing in disguise, but I don't remember seeing that when we started.)

By today's standards we did not know what we were doing; we did not dream of giving any guarantee that our implementation would be correct because we knew full well that we lacked the theoretical knowledge that would be needed for that. We did the only thing we could do under the circumstances, viz. to keep our design as simple and systematic as we could and to check that we had avoided all the mistakes we could think of. Eventually we learned that we had made mistakes we had not thought of, and after all the repairs the compiler was no longer as clean as we had originally hoped. (F. E. J. Kruseman Aretz still found and repaired a number of errors after I had left the Mathematical Centre in 1962.)

Right from the start we expected two very different types of errors, writing errors, whose repair is trivial, and thinking errors that would send us back to the drawing board, and the distinction has helped us because one combats them by different techniques. J.A. Zonneveld and I combatted the writing errors by coding together, each with his own text in front of him; when we were done, both our texts were punched independently, the two tapes were compared mechanically, and about two dozen discrepancies ℄if I remember correctly℄ showed up. The thinking errors we had tried to prevent by convincing each other why the proposed section would work. In this reasoning we could mainly discuss the workings of the compiler while the program compiled was treated as data, and this experience has been helpful for later, as it made us accustomed to non-operational considerations of program texts.

The whole experience has made me sensitive to what later would be called modularization or divide-and-rule or abstraction, to the care with which interfaces have been chosen and to the potential scope of the programming challenge in general. It has heavily contributed to my subsequent opinion that creating confidence in the correctness of his design was the most important but hardest aspect of the programmer' s task. In a world obsessed with speed, this was not a universally popular notion.

I remember from those days two design principles that have served me well ever since, viz.

(i) before really embarking on a sizable project, in particular before starting the large investment of coding, try to kill the project first, and

(ii) start with the most difficult, most risky parts first.

My first test program was almost the empty block, say

begin real x end  ,

not the most difficult example, but my 4th test was a double summation in which the nested calls of the summation routine were introduced via the parameter mechanism, while the summation routine itself had been defined recursively. In passing we had demonstrated the validity of what became known as Jensen' s Device.

After this implementation interlude I returned in fairly general terms to the still open problem of the proper coordination of in principle asynchronous components. Without being directly involved I had witnessed a few years earlier the efforts of coupling all sorts of punched card equipment to the X1 and had been horrified by the degree of complication introduced by the inclusion of real-time commitments. For simplicity' s sake I therefore insisted on "timeless" designs, the correctness of which could be established by discrete reasoning only.

Almost unavoidably the model of Cooperating Sequential Processes emerged: sequential processes with (by definition!) undefined relative speeds and hence, for the sake of their cooperation, equipped with some primitives for synchronization.

Another opportunity for simplification was presented by the recognition that timing aspects between a piece of communication equipment and the program that used it were completely symmetrical between the two and independent of whether we had an input or output device. Needless to say, this unification helped a lot.

When we got involved in the design of the THE Multiprogramming System, scaling up slowly became a more and more explicit concern. It had to. Within IBM, and possibly elsewhere as well, circulated as a supposed law of nature that "system complexity" in some informal sense would grow as the square of the number of components; the reasoning behind it was simple ℄each component could interfere with each other component, etc.℄ but if it were true it would de facto rule out systems beyond a certain size. This evoked my interest in systems structured in such a way that "system complexity" in the same informal sense would not grow more than linearly with the size. In 1967, the expression "layers of abstraction" entered the computer lingo.

Let me close the discussion of this episode by quoting the last two sentences of EWD123 "Cooperating Sequential Processing" (September 1965):

"If this monograph gives any reader a clearer indication of what kind of hierarchical ordering can be expected to be relevant, I have reached one of my dearest goals. And may we not hope, that a confrontation with the intricacies of Multiprogramming gives us a clearer understanding of what Uniprogramming is all about?"

In 1968 I suffered from a deep depression, partly caused by the Department, which did not accept Informatics as a relevant to its calling and disbanded the group I had built up, and partly caused by my own hesitation what to do next. I knew that in retrospect, the ALGOL implementation and the THE Multiprogramming System had only been agility exercises and that now I had to tackle the real problem of How to Do Difficult Things. In my depressed state it took me months to gather the courage to write (for therapeutic reasons) EWD249 "Notes on Structured Programming" (August 1969); it marked the beginning of my recovery.

It tries to synthesize the above mentioned ingredients of the preceding decade. It mentions on an early page "the program structure in connection with a convincing demonstration of the correctness of the program", mentions as our mental aids "1) Enumeration, 2) Mathematical Induction, 3) Abstraction", and about the first and the last I quote (from EWD249-14)

"Enumerative reasoning is all right as far as it goes, but as we are rather slow-witted it does not go very far. Enumerative reasoning is only an adequate mental tool under the severe boundary condition that we only use it very moderately. We should appreciate abstraction as our main mental technique to reduce the demands made upon enumerative reasoning."

I had had two external stimuli: the 1968 NATO Conference on "Software Engineering" in Garmisch-Partenkirchen and the founding of the IFIP Working Group on "Programming Methodology". Thanks to the ubiquitous Xerox machine, my typewritten text could spread like wildfire, and it did so, probably because people found it refreshing in the prevailing culture characterized by the 1968 IBM advertisement in Datamation, that presented in full colour a beaming Susie Mayer who had solved all her programming problems by switching to PL/I. Apparently, IBM did not like the popularity of my text; it stole the term "Structured Programming" and under its auspices Harlan D. Mills trivialized the original concept to the abolishment of the goto statement.

Looking back I cannot fail to observe my fear of formal mathematics at the time. In 1970 I had spent more than a decade hoping and then arguing that programming would and should become a mathematical activity; I had (re)arranged the programming task so as to make it better amenable to mathematical treatment, but carefully avoided creating the required mathematics myself. I had to wait for Bob Floyd, who laid the foundation, for Jim King, who showed me the first example that convinced me, and for Tony Hoare, who showed how semantics could be defined in terms of the axioms needed for the proofs of properties of programs, and even then I did not see the significance of their work immediately. I was really slow.

Finally a short story for the record. In 1968, the Communications of the ACM published a text of mine under the title "The goto statement considered harmful", which in later years would be most frequently referenced, regrettably, however, often by authors who had seen no more of it than its title, which became a cornerstone of my fame by becoming a template: we would see all sorts of articles under the title "X considered harmful" for almost any X, including one titled "Dijkstra considered harmful". But what had happened? I had submitted a paper under the title "A case against the goto statement", which, in order to speed up its publication, the editor had changed into a "letter to the Editor", and in the process he had given it a new title of his own invention! The editor was Niklaus Wirth.

Nuenen, 10 June 2001

prof.dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcription by Wolfgang Houben.
Last revised on Mon, 21 Apr 2008.

EWD1309a

Zuckerman's problem and the ETAC

Thanks to David Zuckerman, the following problem circulated, before I left for Europe, at the Department in Austin.

At a University with N professors, committees have to be formed under the following constraints.

C0: each committee consist of an odd number of professors

C1: any two distinct committees share an even number of professors.

What is the maximum number of committees that can be formed?

*                 *
*

Before leaving the USA I had thought about the problem but had not solved it. The N distinct committees each consisting of a single professor meet both constraints, so the answer is ≥ N. Exploring the possibilities for a few small values of N gave me the "moral certainty" that the answer was also ≤ N.

I quickly decided not to use set notation, which I don't like (never found it helpful) but to characterize instead each committee by a vector of N bits. It took me more time to decide how to interpret these bits: were they Booleans representing true/false, or were they integers representing 0/1.

Initially I was attracted by the Boolean interpretation because the continued equivalence expresses so nicely the evenness of the number of its false arguments and C0 requires us to pay attention to such odd/evenness. In C1, however, the notion of sharing requires us to pay attention to the identity of the professors as well, but this identity is not really reflected in the continued equivalence which is defined on unordered bags of arguments. Thus I found that in the context of this problem I could not manipulate the continued equivalence in a meaningful manner.

Turning my attention to the integer interpretation I realized that both constraints could be expressed without explicit mention of the individual professors in terms of the scalar product.

Note The scalar product • is defined on pairs of integer sequences of equal length by

[]•[] = 0

[x:xs]•[y:ys] = x∙y + [xs]•[ys]

(End of Note)

Here is the problem as I posed it to the ETAC on Tuesday 12 June 2001.

Consider a set V of 0/1 vectors of N components such that

C0:    〈∀i: vi ∈ V : odd.(vi•vi)〉

C1:    〈∀i,j: vi,vj ∈ V ∧ i ≠j: even.(vi•vj)〉

Show that V contains at most N vectors.

Remark The two constraints can elegantly be combined into

〈∀i,j: vi,vj ∈ V: i = j  ≡  odd.(vi•vj)〉

and this is very encouraging. (End of Remark)

Because in N-dimensional space there are no sets of more than N linearly independent vectors, the ETAC set out to solve the problem by showing that the vectors in V are linearly independent. Let ON denote the zero-vector of length N and let α be a sequence of as many coefficients as there are vectors in V. Linear independence of the vectors vi in V then means that for any α

(0)           〈∑i:: αi•vi 〉 = ON  ⇒  〈∀i:: αi=0 〉

In my experience with linear algebra, the components of the vectors and the coefficients αi of the linear composition used to range over the real numbers, but fortunately some of the ETAC members knew the whole theory is also applicable in the field of rational numbers. The vector components being integer, and hence rational, it suffices to prove (0) for rational α. But since left- and right-hand side of (0) are invariant for multiplication of α by a constant that differs from zero, we can confine our attention to integer α. (Because the number of vi is at most 2N, i.e. finite, we can multiply α by a common multiple of the denominators of the αi to get all coefficients integer.) From now on, α stands for a sequence of integer coefficients. We observe for any j in range

〈∑i :: αi ∙ vi 〉 = ON

⇒         { ON • vj = 0}

〈∑i :: αi∙ vi 〉• vj = 0

≡         { • distributes over ∑ }

〈∑i :: (αi∙vi ) • vj 〉 = 0

≡         { ∙ and • mutually associative }

〈∑i :: αi∙(vi • vj )〉 = 0

≡         { split range; 1-point rule }

〈∑i : i≠j : αi∙(vi • vj )〉 + αj∙(vj • vj ) = 0

⇒         { αi integer; C1, i.e. even.(vi • vj ) }

even.(αj∙(vj • vj ))

⇒         { C0, i.e. odd.(vj • vj )}}

even.αj

The above calculation implies with the aid of some elementary algebra that

(1)       int.α ∧ 〈∑i:: αi∙vi 〉 = ON

is invariant under α := α/2, which allows us to conclude that under the truth of (1), each αj is divisible by arbitrary high powers of 2 and hence = 0. And thus, (0) has been established.

Nuenen, 25 June 2001

prof. dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA.

transcribed by Wolfgang Houben
revised Wed, 14 Nov 2007

EWD1310

Three trip reports rolled into one: 2001.04.16-2001.07.06

I started the year with an esophagus that had been reattached to my stomach, but whose exit had a tendency to close up. It needed to be dilated twice in January and once in February, and I wondered whether organising such a long trip was not an act of irresponsibility: could I trust that the last dilatation would be good for at least 20 weeks? The surgeon Tim L. Faulkenberry made no objections and the gastroenterologist Tom S. McHorse practically ordered me to buy our tickets. In their judgements that it would be for me safe to go, they have been right.

It was a long trip but that was almost dictated by how my appointments were spread out in time: 24 April (Oxford), 23 May (Athens) and 28/29 June (Bonn). There was just no point in going back in between. I also had an invitation for later in April, say the 27th, in Lausanne, but I was afraid that accepting it would be too much for my still anaemic body and declined it; I did so with regret but when the time was there I was glad that I had done so.

Ria decided that we would fly to the Netherlands first so that the worst of the jet lag would be over when I had to perform in Oxford. I decided that, because its personnel threatened to strike, we would avoid Northwest Airlines, and this ruled out our usual route via Memphis. We flew from Austin to Eindhoven (and back), changing planes in Houston and in Amsterdam.

We left Austin on April 16th at 12:35 and arrived in Eindhoven the next morning at 11:25. It had been an almost pleasant flight because all planes had arrived on time, we did not lose any luggage and I —on doctor's orders!— was not allowed to lift anything heavy, but the food that KLM served on the transatlantic flight had reached a new level of inedibility. In Eindhoven, Netty van Gasteren and Wim Feijen were at the airport to collect us; they took us and our luggage in Netty's big car to Nuenen where Wim's Golf was waiting for us on the driveway. Inside the house the first thing we did was turning up the thermostat of the central heating.

A few things I remember of those first days. At the Eindhoven Customs I had to open my briefcase to show all my pills (which had shown up in the x-ray scan, and there were many of them!) were legal medicines. When we said hello to our neighbours, they showed us the tv-program that the VPRO had devoted to me and that had been aired a week earlier. Many people would later comment on it; the VPRO had done a very good job.

On Saturday morning we went by train to Amsterdam, first to celebrate the 40th anniversary of our daughter Femke, to say hello to her husband and to renew the acquaintance with their two little sons. After that family reunion we went to our son Marcus, who lives in Amsterdam as well. After a nice evening in his company, we stayed there for the night; on Saturday morning, after breakfast, he gave us a ride to Schiphol, from where we flew to London–Stansted.

In the air I already realized that those few days in my fatherland had been enough to mix my feelings. The immediate cause was the deterioration of the railway system, which was threatened by strikes by way of protest against a change in the timetable. I remember a famous railway strike during WWII, but that was an act of sabotage directed against the German occupation. In the decade after the war, when the railway system , which had largely been destroyed, was reconstructed, it became an object of national pride and a railway worker who would have suggested a strike would have run , I think, the risk of being lynched. Times have changed and, as usual, it was not an improvement. Later I would learn a bit more about what went wrong.

Since flights can be delayed or cancelled, I think invited speakers should not plan a late arrival —though planning a quick departure is okay—. So we flew on Sunday because the lecture in Oxford was on Tuesday. In Stansted we were met by a nice taxi-driver who took us to Blewbury, where we would be the guests of Richard & Norma Bird.

They live there in a lovely cottage, which is about 5 centuries old. Apart from the fact that its doors are so low that it is very easy to hurt one's head (what I did), it was a nice visit. The next morning, Richard had to be at the University very early and had left in his two-seater by the time we woke up. Before taking us to Oxford, Norma showed us thew center of the village —church, cemetery, pub and little streams with clear water, it was all there— ; we arrived in Oxford around noon.

That Monday afternoon and the next morning I talked with all sorts of people while Ria amused herself in town. Oege de Moor was very helpful in taking us to the Randolph —where we would stay one night for an appalling £170— and at lunch to a deli; it was nice to meet him again. Monday evening —our wedding anniversary, but no one knew that— we were taken for dinner; besides Richard and Oege and his wife, I remember Joe Stoy and his wife and Jeff Sanders and his companion —we had met Jeff in Australia, I guess in Perisher Valley— . I don't remember the food, so that must have been okay, but conversation was all but impossible: firstly we were sitting at a narrow, long table, secondly the acoustics of the room were atrocious.

The Christopher Strachey Lecture was on Tuesday afternoon from 4 till 5; the laboratory having a bedroom (!), I had been able to sleep earlier in the afternoon. The idea of giving the Strachey Lecture attracted me very much for we knew, liked and expected each other. [I consider my Distinguished Fellowship of the BCS one of my highest distinctions because I was allowed to share the honour with Christopher when the BCS created the distinction.] My lecture, I am sorry to say, was not very good. I had to address an audience of 180 people in a lecture hall with 120 seats, no microphone and no blackboard (!). but I think the main reason that my talk did not go too well was that I was still too weak. At 6 o'clock we were whisked away and taken by taxi to Cambridge, where we arrived 2 hours later at the new home of Sir Antony & Lady Hoare.

I left Oxford with mixed feelings. The Colleges, and even some female students, were beautiful, but my overwhelming memory is of a number of decrepit, obviously very miserable beggars, huddled up in porches, trying to stay out of the rain. And also the University mixed my feelings. In private conversations I still met scientists, but when I met them collectively, they struck me primarily as members of a teaching body. And the whole place gave me the impression that the authorities have honed the harassment of intellectuals into a devious craft.

Our visit to Tony and Jill was very nice; it is always a pleasure to meet them, this time it was an extra pleasure because Jill took very good care of the recovering patient. One day they took us to Ely and I was very proud that I managed to climb the central tower —called " The Lantern"— of Ely Cathedral. The other day they took us to the heart of Cambridge; I had been there before, but for Ria this was the first visit to Cambridge, so there was a lot to see. Tony showed us Microsoft Research where I met Roger Needham —none of the other employees I knew— and good old David Wheeler, who happened to be visiting that day. It was a pleasant surprise to meet him again; he seemed in excellent shape.

On Friday, Tony and Jill took us to Stansted Airport. The plane to Schiphol left on time and four hours after take-off I opened the front door of our house in Nuenen. It had been a most enjoyable visit, but I was glad to be home.

And then we stayed for more than three weeks in the Netherlands. On the 4th of May we observed the two minutes of silence in memory of the victims of WWII as part of a little open-air ceremony in Amsterdam, at which our daughter Femke sang in the choir; I had not heard her for a long time, and it was a pleasure to do so again.

On the 11th of May we celebrated my birthday, and we were lucky that the weather cooperated and we could sit with our guests in the garden. Femke and Marcus came on the day itself, Rutger (our other son) came the next day, my sister Anneke came, my brother Albert was in Southern France (and stayed there).

On the 15th/16th, we had a reunion in Slenaken —at about the most Southern point of the country— of friends of my student days. We were 12 1/2 couples and it was a pleasure to see that all present were in good shape (admittedly in some cases thanks to medical technology, but what do you expect? We are all in our early seventies.). In the mean time, the nice weather was gone again: already before dinner we had a thunderstorm.

On Monday the 21st of May we flew to Athens, where we were joined by Femke, who wanted to witness her father receive an Honorary Doctorate. The ceremony was Wednesday, and we returned the next day, making our visit as short as possible. The point was that when we bought our ticket in March, the latest (and third) dilation of the passage from oesophagus to stomach was only five weeks ago, nobody could guarantee that it would stay open, I knew from sad experience that blocking would require immediate hospitalization and I wanted to avoid Greek hospitals. (Just in case, I had a large amount in traveller's cheques —in Euros!— with me.)

The Greek hospitality was absolutely amazing. To give a few examples, when they heard that Femke would come as well, they immediately reserved a room for her as well, and they picked up that hotel bill too, and was quite thrilled to see that the Homeric tradition of the ξεινήιον —the gift that the host gave to his guests— was still alive: after the ceremony, Ria and Femke were called to the office of prof. Theodoros Apostolopoulos —the Vice-Rector of the Athens University of Economics and Business— and were each given a golden bracelet and some jewelry to hang around their necks. But I was most impressed by the subtle tact with which they took almost permanent care of us without ever imposing themselves on us. That was something very special.

We arrived at 19:00 at Athens new airport, where Ria saw Femke and I identified Yannis Diamantis, who would collect us. We were joined by the driver of the car of the vice-rector of the University. (The reason we were collected by two people was that the driver did not speak a single word of English; he was, however a very competent driver.) At the Park Hotel, Yannis Diamantis handed us over to our official host, Prof. Emmanuel J. Yannakoudakis, Head of the Department of Computer Sciences and the man who would officially grant me the honorary doctorate. Yannakoudakis took us for a while to his home, where we were introduced to his family; then his wife joined us for the dinner, which started after 10 o'clock. It was in the elite restaurant of an equally elite hotel, it was clearly THE place to have dinner. (It reminded me of Hotel "Beau Rivage" in Lausanne.) The food, by the way, was excellent. We had moved a time zone and so it it did not bother us to come back in the hotel after local midnight.

On Tuesday morning Mr. Diamantis kindly showed us the Parthenon —that he must have seen before— and the museum next to it. I had not regained all my strength yet for I remember being impressed by my climbing of the Acropolis. After we had seen enough boys with leprous noses and broken penes, we descended to "Plaka" where (after a considerable effort!) our guardian angel found a restaurant that served soup. After lunch, we returned to our hotel, where we had a nice nap, gathering strength for that evening's "Working Dinner".

That happening took place in some sort of cafeteria on the top floor of a university building. (The University was truly within walking distance of our hotel; that was very practical.) Well, we did not work and I hardly dined, for almost each dish —even the tossed salad— contained cheese. (But there was beer and all sorts of things to nibble on). Upon arrival I had been introduced to each member of the faculty, but for the rest of the evening I only spoke to the people I shared the table with, so it was nice when afterwards, in the bar of the Park Hotel we were joined by a few faculty members. (Greek beer does, of course, not enjoy Budweiser's world-famous drinkability, but it can be drunk. Femke had it as well.)

Wednesday was the great day. Fortunately I had discovered in time that I had left my prepared foils in Nuenen and the University had provided me with blank ones and pens. I used Wednesday's free moments to make new ones.

At 10 o'clock Maria Valiantza, Yannakoudakis's charming secretary, came to take us to the Museum. Afterwards we had a drink on a shaded terrace, where I took 3 very nice pictures (in order: Miss Valiantza, Femke and Ria), and then we had lunch on another shaded terrace, and there she did what Mr. Diamantis had done the day before: she did not only order what we had asked for, but a whole bunch of additional dishes we should try as well. Another aspect of Greek hospitality?

In the afternoon we rested for a while, and I made a few last foils. At five o'clock we were collected and walked to the University where two competing TV crews were waiting to interview me. When that was over, we went to the hall for the ceremony, which was nice; it was all done in Greek, so I shall never know what they told about me, but that did not prevent us from noticing that the atmosphere was both solemn and festive. And then I gave my speech.

For its preparation I had asked about the nature and estimated size of the audience, and whether there would be a blackboard and whether the audience would understand English. No, there would be no blackboard, but my audience would consist of all of Greek Computing Science, so English would be no problem at all. People from all over Greece would come, and accordingly, I prepared a technical/historical talk. But that turned out to be a mistake. The audience consisted for a sizable fraction of 27 Bachelors about to graduate + their siblings, parents and grand-parents, I dropped a joke and from the tepid reaction I deduced that my English was Greek to them. So I moved as quickly as possible to my more pictorial foils, and finished within 25 minutes, with the uncomfortable feeling of having short-changed the colleagues that had come all from Salonika. Then came the graduation of the 27 Bachelors; had I known this and that they would be congratulated individually, then I would have asked to join the line and shake their hands as well. After a "Gala Dinner" —well, not so very Gala— with the 27 Bachelors and their families, we were taken to (I think) St. Georges Lycabetus: first a church on a very windy hill, and then to a restaurant where they served us incredibly expensive ice cream. After Ria and Femke had been kissed by almost everybody in the company, we were seen to our hotel.

The next day, Femke left early in the morning, we early in the afternoon; the vice-rector's car drove twice to the Airport.

We have been in Greece too short to be able to interpret what we saw. On the streets of Athens we felt safe and the other people seemed to do so too, we did not see a single rifle and the police was fully occupied by the traffic, which was allowed to clog up the city to such an extent that we could not escape the impression that the current Greek government feels itself to be a well-established democracy. It was also clear that their dictatorship occurred in a not too distant past: at the academic ceremony, half the front row was occupied by top brass, all except one in full uniform, and it was revealing to see how much attention the TV crews paid to them. I don't think they were dangerous. [Once or twice during the ceremony I wondered whether, in reality, we were only playing our part in a Gilbert & Sullivan opera, and almost expected the singing to start.]

My economic impressions were contradictory. On the one hand it was obviously not a rich country, on the other hand the expensive shops and the Mercedes density gave the impression of a very rich upper class, or an upper class with lots of money to spend. I would not be amazed if expense accounts and budgets for representation were by our standards out of proportion. Perhaps this is only to be expected in a country that was recently controlled by dictators and tycoons.

Then, more than a month later, on 28/29 June, we had in Bonn the sd&m Conference "Software Pioneers". The acronym sd&m stands for "software, design & management" and is the name of a Munich software house with (I was given to understand) about 900 employees. I quote from the brochure:

"Today's young computer scientists and software developers don't know much about the roots of their field. [...] This holds as well for some of the young sd&m software engineers.

The sd&m Conference 2001 aims at filling this lack of historical awareness by presenting ground-breaking contributions to the development of software as a field of its own, authentically presented by the pioneers themselves."

(Had the composer commissioned to write something for the occasion been Modest Moussorgsky, he would have composed "Speakers at an Exhibition".)

The second reason for the sd&m extravanganza turned out to be that it marked the retirement of Prof. Fr. Ernst Denert, CEO and founding father of sd&m AG. He and Manfred Broy (from the Technical University Munich) had organized the conference, and they had done so very well.

The conference (for 1200 people) was in the old building for the Bundestag in Bonn, the speakers were housed in Gästerhaus "Petersberg" in nearby Königswinter. For us this was very convenient , we could make the trip between Nuenen and Königswinter in slightly over 2 hours. Not knowing how easy the place would be to find, we left in time and arrived on Wednesday afternoon.

Gästerhaus "Petersberg" was a 5-star Hotel that used to specialize in foreign heads of state. (It was the "Reagan-slept-here" type of hotel.) On the day of arrival I got stuck in the elevator, Ria got stuck the next morning and, later that day, Tony and Jill Hoare would do so together. We had there dinner twice, and breakfast three times, and the food was excellent.

For the record I reproduce the speakers, their topic and the size of their time slot. Broy, who acted as master of ceremonies, had the program under perfect control: everything happened on time. Here is the schedule for the first day.

(15 min) Ernst Denert & Manfred Broy: Welcome and Opening

(45 min) Ernst Denert: The pioneers' influence on sd&m

(35 min) Friedrich L. Bauer: From the stack principle to Algol

(35 min) Ole-Johan Dahl: Simula

(35 min) Niklaus Wirth: Pascal

(35 min) Fred Brooks: OS/360

(75 min) Alan Kay: Graphical User Interfaces

(45 min) Rudolf Bayer: B-Trees and Codd's Relational Data Model

(35 Min) Peter Chen: Entity / Relationship Modelling

All this was followed in the evening by a reception, a gala dinner, a (very nice) performance of classical music and a very elegant procedure in which the parting CEO handed the baton to his successor. [Sorry, the passing of the baton was on the next day.] Ria and I were highly impressed by the tastefulness with which these festivities had been organised. When for the benefit of the younger generation loud music was introduced so as to make all conversation impossible, we could fortunately return to our hotel.

The schedule the next day was as follows:

(35 min) Edsger W. Dijkstra: Structured Programming

(35 min) C.A.R. Hoare: Assertions & Program Verification

(35 min) David L. Parnas: Modularization by Information Hiding

(35 min) John Guttag: Abstract Data Types

(35 min) Michael Jackson: Jackson Structured Programming

(35 min) Tom DeMarco: Structured Analysis

(35 min) Michael Fagan: Inspections

(35 min) Barry Boehm: Software Economics

(35 min) Erich Gamma: Design Patterns

(25 min) Manfred Broy & Ernst Denert: Closing and Farewell

I did not make notes and after more than two months, most of what has been said I have forgotten, but I vividly remember Alan Kay's performance because it was so abysmal. He kept us 75 minutes waiting for his lecture to start; instead he showed us one long "demo" out of his "laptop", most of it so insipid that I blamed him for insult of audience. My impression is that, except for his own performance, he did not attend the conference.

Rudolf Bayer's talk was a little bit larger than the others, but that was probably because he also wanted to do justice to the contributions by Codd, whom reasons of health had prevented from participating. He was one of the few who seems to be able to give a technical talk without suffering from "PowerPoint".

Unkel Fritz, who was in great shape, described the German compiler efforts of the late 50s, a topic perhaps too big for 35 minutes. Ole-Johan, Niklaus and Brooks spoke about topics they have been identified with for a very long time; each of them coped with this problem in his own way. Ole-Johan and Niklaus aimed at a more technical audience than Brooks, but that was to be expected. I did not understand what Peter Chen was telling, but that was to be expected too, for I never understood "modelling".

Friday morning I filled the first slot (known in Marktoberdorf as "The Victory of Mind over Matter"); my message was that "Structured Programming" had been more about reasoning than about eliminating goto's, easily fitted in 35 minutes. I was followed by Tony Hoare, who gave an absolutely beautiful talk. One of my American colleagues remarked afterwards to me that Tony's (legendary) mastery of English made him "green with envy". I wish the younger generation understood the trouble Masters take to give their best: while sitting in the audience the previous day, Tony had been editing his text very carefully! I missed the talk by Dave Parnas because I had accepted to be interviewed; later I heard that this had been unfortunate as Dave had prepared to expose me to his disagreements with me. Thus an opportunity for fireworks was missed.

 To John Guttag and Michael Jackson I listened with pleasure, and to Boehm, whom I don't know that well, with interest. DeMarco was a slick salesman, but his saving grace was that he told his audience so himself (and warned that slick salesmen were dangerous). I was surprised by the final attention he paid to "Extreme Programming". Fagan was a salesman too, but a less charming one and Gamma was the last speaker.

 That evening (or was it the next morning?) the Munich employees returned with the specially rented train with which they had come. The speakers and their wives returned to the hotel, where we had the privilege of enjoying good food in good company. The next morning we found each other again at a leisurely breakfast, for which the tables had been set outside on a terrace overlooking the Rhine: a perfect closing for a lovely party.

 For the sake of completeness, I mention another way of looking at the whole happening, viz. regarding it as a 16-fold confirmation of the ruinous influence of PowerPoint, for the less of it you use, the better your lecture. [For the record: all our lectures were in blue.] Unwittingly, Manfred demonstrated that influence in his closing words by not referring to our lectures but to our "presentations". [In Austin I cannot avoid the depressing observation that all faculty candidates lack the courage not to use what in MicroSoft's own terminology is "its presentation software".] The bloody electronics only encourage the next steps of the replacement of content by form, and as such contribute to the Great Educational Fraud ( = GEF).

On the 6th of July, we flew back to Austin, another week later dr. T.L. Faulkenberry repaired my abdominal hernia: it was clear we were home.

PS. I did not mention it, but in Athens I was struck by the ubiquitous presence —with the exception of the University Campus— of priests of the Greek Orthodox Church. The other day I read that in Greece they don't have the separation of church and state. That was new for me.

Austin, 10 September 2001

prof. dr. Edsger W. Dijkstra

Department of Computer Sciences

The University of Texas at Austin

Austin, TX 78712–1188

USA

Transcribed by Mario Béland
Last modified Wed, 14 Nov 2007.

EWD 1311

Another look at a problem from Hugo Steinhaus

    Let a,b,c,d be, in order, the 4 sides of a convex polygon; let a and b meet at an end point of diagonal x, and let y be the other diagonal. If among the 3 edges meeting at a vertex, 1 is shorter than the other 2, that shortest one is marked. We have to show that at least one of the diagonals remains unmarked, i.e. we have to show

(0) | [(a ≤ x ∨ b ≤ x) ∧ (c ≤ x ∨ d ≤ x)]   ∨ [(b ≤ y ∨ c ≤ y) ∧ (d ≤ y ∨ a ≤ y)]

The first line expresses that x is unmarked; it is a conjuction of 2 conditions, 1 for each of its end points. The second line similarly covers y. Please note that in demonstrandum (0), each diagonal is compared with each side of our polygon.

To connect lengths of sides and diagonals with the convexity, we appeal to the

Theorem 0  In a convex quadrilateral, the sum of the lengths of the diagonals is at least the sum of the lengths of two opposite sides.

(This theorem can be proved by appealing twice to the triangular inequality and using that convexity means that the diagonals intersect each other between their end points.) We propose to show that (0) follows from

(1) | a + c ≤ x + y   ∧  b + d ≤ x + y.

As you see, we have not chosen a pair of opposite sides, we have taken them both, mainly because the 4 sides all occur in (0), but also because, in this early stage, I did not want to destroy the symmetry. Finally there is a fair chance that we need both conjucts of (1) since a + c ≤ x + y by itself does not imply that x and y are the diagonals of a convex quadrilateral.

    Before continuing with (1), we rewrite (0): by distributing the outer ∨ over the ∧, we can express (0) as a conjuction of four terms, and it is always nice to have your demonstrandum as a conjuction because one can deal with conjucts separately. By distribution of the outer ∨ we rewrite our demonstrandum (0) as

(2)
( a ≤ x ∨ b ≤ x ∨ b ≤ y ∨ c ≤ y ) ∧
( c ≤ x ∨ d ≤ x ∨ d ≤ y ∨ a ≤ y ) ∧
( a ≤ x ∨ b ≤ x ∨ d ≤ y ∨ a ≤ y ) ∧
( c ≤ x ∨ d ≤ x ∨ b ≤ y ∨ c ≤ y )

We now have to show (1) ⇒ (2). We do so by eliminating to begin with the + sign, using

Theorem 1       p + q  ≤  r + s   ⇒   p ≤ r  ∨  q ≤ s.

(By taking the contrapositive, one recognizes a monoticity property of addition.)

    (1)

⇒    {Theorem 1, 4 times}

    ( a ≤ x ∨ c ≤ y ) ∧
    ( c ≤ x ∨ a ≤ y ) ∧
    ( b ≤ x ∨ d ≤ y ) ∧
    ( d ≤ x ∨ b ≤ y )

⇒    {termwise implication; ∧ monotonic}

    (2)

QED.

*                       *
*

    I recorded the above proof so that we can compare it with the argument by Hugo Steinhaus. [Note: Steinhaus draws only the line segments that we called "marked" and he assumes all distances to be different .] I quote:

    "Let us suppose that the newly formed figure includes two intersecting segments AB and CD.

    Let us suppose that the points A and B have been connected by a segment because B lies nearest to A; and let us suppose similarly that the point D lies nearest to point C. Then AB < AD, CD < CB, whence AB + CD < AB + CB, which contradicts the proposition that in a convex quadrangle the sum of the diagonals is greater than the sum of two opposite sides.

    In this we have proved [...] the theorem."

    My proof seems to repeat the same argument about four times, each time with a different permutation of the letters; I have not been able to avoid that repetition by exploiting the symmetries. By phrasing the argument as a reductio ad absurdum, Steinhaus could postpone the introduction of nomenclature and thus reduce the repetition somewhat.

    For a completely different proof by Lyn Pierce, see EWD 1251.

                              Austin, 16 October 2001

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712–1188
USA

transcribed by Adam Dariusz Szkoda
revised Wed, 14 Nov 2007

  EWD 1312

On disjoint binary numbers

For a pair of natural binary numbers we define a "double" as a position in which both have a 1 , nd.(h,k) denotes the the number of doubles in the pair (h,k)   and   (h,k) is "double-free" means nd.(h,k)=0 . [In the title, the concept "double-free" is hinted at by the adjective "disjoint".]

Another way of stating that the pair (h,k) is double-free is s.(h+k) = s.h+s.k , where s.n equals the number of 1's in the binary representation of n. [We could define s by s.n = nd.(n,n).]

The rest of this note is inspired by a theorem of Jay Misra's about the odd/evenness of binomial coefficients. The link with the concept "double-free" is given by

(

n

k

) is odd ≡ (k,n-k) is double-free ,

a lemma we won't prove here.

Misra's theorem about binomial coefficients was (practically) equivalent to the following theorem about double-free pairs:

Theorem Consider for positive integers h and k the three pairs (h,k), (h−1,k) and (h,k−1) ; an even number of them is double-free.

*             *
*

Proof In the following it helps to remember that in binary, a decrease by 1 boils down to an inversion of the right-most 1 and all zeroes to its right; to the left of the inverted 1 , nothing is changed.

Because h and k are positive, each contains at least one 1, hence a right-most 1. Let h end with a 1 followed by x zeroes, and let k end with a 1 followed by y zeroes. Our theorem being symmetric in h and k , we can confine our attention to the situation x≤y . We now consider two main cases, viz. x=y and x<y .

x=y.    The pair (h,k) has at least x as a double, so nd.(h,k)>0 . Since both nd.(h−1,k) and nd.(h,k−1) both equal nd.(h,k)−1 —the double at x is destroyed and no new doubles are created— nd.(h−1,k)=nd.(h,k−1) . Hence zero or two pairs are double-free.

x<y    Since in the transition from (h,k) to (h−1,k) all the changes in h occur in positions where k has zeroes, we conclude nd.(h,k)=nd.(h−1,k). Since (h,k−1) has at least x as a double, nd.(h,k−1)>0 ; again zero or two pairs are double-free.

And this completes the proof.

*             *
*

If you want to prove this essentially combinatorial theorem from first principles, case analysis is all but unavoidable. In this problem, the challenge is to keep the number of cases small. Before the above, I had designed two proofs which each distinguished five different cases, in one of them the main distinction being 0, 1 or more doubles in (h,k). Thanks to the introduction of the function nd , the specific value of nd.(h,k) need not be mentioned.

          Austin, 11 November 2001

prof. dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by Daniel Kolditz Rubin
revised Wed, 14 Nov 2007

EWD1313

The GCD and the minimum

It all began with a friend who was preparing his undergraduate lectures asking me whether I had a nice calculational proof of

(0) | x↓y = 1   ⇒   x↓(y *z)  =  x↓z |

(All variables are of type natural and ↓ stands for the greatest common divisor.) I did not have a nice proof of (0), so I started to think about it, and then the fun started. Hence this little note.

*               *
*

Having learned to like Lattice Theory and the Galois Connection, I immediately decided to regard ↓ as the infimum with respect to the partial order ⊑, read as "divides". The greatest common divisor ↓ is then defined by

(1) | u ⊑ x↓y   ≡   u ⊑ x  ∧  u ⊑ y | for all x,y,u.

From the above definition, many nice properties of ↓ elegantly follow, such as

(2) | ↓ is associative, symmetric and idempotent

(3) | x↓y ⊑ x   and   x = x↓y  ≡  x ⊑ y

As the above are general results from elementary lattice theory and have nothing to do with integer arithmetic, I decided to use them freely as the need would arise. [It turned out that, to begin with, that need would only arise for (2).]

Besides ↓, (0) contains the special constants 1 and *, and the next question was how to capture their relevant properties. For 1 I could come up with two relations, connecting 1 to * and to ↓ respectively,

(4) | 1*u = u | for all u, and

(5) | 1↓u = 1 | for all u,

and I postponed the choice.

Note At the time I did not realize that (4) is the more promising candidate. By presenting 1 as a unit element (of *), it offers a way of eliminating 1, while (5), which presents 1 as a zero element (of ↓), does not offer that service. (End of Note.)

(4) connects * with 1 but I assumed that this was not enough to capture the "relevant properties" of *. To connect * with ↓, I came up with

(6) | x↓(y *z)  =  x↓(x↓y * x↓z) | .

Now the proof of (0) was straightforward: we observe for any x,y,z (satisfying (6) and (0)'s antecedent)

| x↓(y *z) |
= |  | { (6) } |
| x↓(x↓y * x↓z) |
= |  | { antecedent of (0) } |
| x↓(1 * x↓z) |
= |  | { (4) with u := x↓z } |
| x↓(x↓z) |
= |  | { ↓ associative and idempotent } |
| x↓z   , |

which completes the proof of (0).

*               *
*

The above proof is nice, but one can object that it does not prove very much, as (6), which we use, is hardly simpler than the demonstrandum (0). [It is, for (6) does not contain 1.] So I started to think about proving (6), but in order to simplify matters, I switched to the additive version

(7) | x↓(y +z)  =  x↓(x↓y + x↓z) | ,

where x,y,z are of type real and ↓ denotes the minimum. For this proof I used — besides (1) with ⊑ specialized as≤ —

(8) | x↓y ≤ u   ≡   x≤u  ∨  y≤u | for all x,y,u

which holds because ≤ is a total order — i.e. x≤y  ∨  y≤x — and

(9) | u + x↓y  =  (u+x)↓(u+y) | for all x,y,u

— i.e. + distributes over ↓ —, which follows from (1).

In order to prove (7) we observe

| x↓(y+z)  =  x↓(x↓y + x↓z) |
≡ |  | { + over ↓, i.e. (9) thrice } |
| x↓(y+z)  =  x↓(y+z)↓(x+x)↓(x+y)↓(x+z) |
≡ |  | { (3) } |
| x↓(y+z)  ≤  (x+x)↓(x+y)↓(x+z) | (*)
≡ |  | { (8) } |
| x  ≤  (x+x)↓(x+y)↓(x+z)  ∨ |
| (y+z)  ≤  (x+x)↓(x+y)↓(x+z) |
≡ |  | { (1), 2 times twice } |
| ( x ≤ x+x  ∧  x ≤ x+y  ∧  x ≤ x+z )   ∨ |
| ( y+z ≤ x+x  ∧  y+z ≤ x+y  ∧  y+z ≤ x+z ) |
≡ |  | { simplifications } |
| ( 0 ≤ x  ∧  0 ≤ y  ∧  0 ≤ z )   ∨ |
| ( z ≤ x  ∧  y ≤ x ) |

We failed to prove (7) because it is not a theorem: it only holds for nonnegative x,y,z or when x is the largest of the three.

*               *
*

From (*) we first eliminated ↓ at the left-hand side, using (8), and then we used (1) to eliminate the ↓s at the right. We could have done it in the other order. We illustrate the consequences with a simpler example. Consider the calculations

| x↓y  ≤  a↓b |
≡ |  | { (8) } |
| x  ≤  a↓b   ∨   y  ≤  a↓b |
≡ |  | { (1) } |
| (x ≤ a  ∧  x ≤ b)   ∨   (y ≤ a  ∧  y ≤ b) |

and

| x↓y  ≤  a↓b |
≡ |  | { (1) } |
| x↓y  ≤  a   ∧   x↓y  ≤  b |
≡ |  | { (8) } |
| (x ≤ a  ∨  y ≤ a)   ∧   (x ≤ b  ∨  y ≤ b) | ,

from which we conclude

| (x ≤ a  ∧  x ≤ b)   ∨   (y ≤ a  ∧  y ≤ b)   ≡ |
| (x ≤ a  ∨  y ≤ a)   ∧   (x ≤ b  ∨  y ≤ b) |

a beautiful formula that I did not know, but don't try to prove it by predicate calculus alone, for you need that ≤ is a total order.

Because, in contrast to ≤, ⊑ in the meaning of "divides" is not a total order we can expect (6) to be essentially harder to prove than its additive version (7). I would not be amazed if the uniqueness of the prime factorization were needed.

Acknowledgement I thank Hamilton Richards for starting me on these investigations and Jayadev Misra for his interest shown.

                            Austin, 27 November 2001

Prof. Dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

Transcribed by John S. Adair
Copy Editor: Ham Richards

Last revised on Wed, 14 Nov 2007.

EWD1315

Indirect equality enriched (and a proof by Netty)

Proofs known as "proofs by indirect equality" traditionally exploit

(0)      x = y     ≡   〈∀u : true : u⊑x ≡ u⊑y 〉

for some reflexive, antisymmetric ⊑ : they establish equality by establishing the right-hand side of (0). The following lemma shows that we may be able to get away with a proof obligation that is formally weaker.

Lemma For reflexive, antisymmetric ⊑ and predicate P such that P.x ∧ P.y , we have

(1)      x = y     ≡   〈∀u : P.u : u⊑x  ≡  u⊑y 〉

Proof

LHS ⇒ RHS   This follows from Leibniz's Principle.

RHS ⇐ LHS   We observe for any x,y, P such that P.x ∧ P.y

〈∀u : P.u : u⊑x ≡ u⊑y 〉

⇒       { instantiate u:= x and u:= y }

(P.x ⇒ (x⊑x ≡ x⊑y )) ∧ (P.y ⇒ (y⊑x ≡ y⊑y ))

≡       { P.x ∧ P.y }

(x⊑x ≡ x⊑y ) ∧ (y⊑x ≡ y⊑y )

≡       { ⊑ is reflexive }

x⊑y ∧ y⊑x

⇒       { ⊑ is antisymmetric }

x = y                                           (End of Proof)

*           *
*

An application

Let the above ⊑ be the partial order of a lattice for which the infimum ↓ is defined by the usual

(2)     u ⊑ x↓y    ≡    u⊑x  ∧  u⊑y

Fairly directly follow the general lattice properties

(3)     ↓ is idempotent, symmetric, associative

(4)     x↓y ⊑ x and x↓y ⊑ y

(5)     x⊑y   ≡   x = x↓y

We now specialize by making the variables x, y, u etc. of type natural and identifying ⊑ with "divides" —or "is a divisor of"—, which is a partial order on the naturals for which the infimum exists: x ↓ y is in fact the Greatest Common Divisor of x and y .

The formal link between our lattice and arithmetic on the naturals —multiplication in particular— is given by providing 〈∃q :: q*x = y 〉 as a third expression for "x divides y ", i.e. we add to our laws

(6)     〈∃q :: q*x = y 〉   ≡   x⊑y

from which the mutually equivalent

(7)     m ⊑ m*x       and       m  =  m ↓ m*x

immediately follow. (Please note that we have given * a stronger binding power than ↓.)

We are now ready to prove that the GCD of two m-tiples‡ is an m-tiple‡, in formula

(8)     m  ⊑  m*x ↓ m*y

Proof    We observe

m   ⊑   m*x ↓ m*y

≡        { (5) and associativity of ↓ (3) }

m   =   m ↓ m*x ↓ m*y

≡        { (7) }

m  =  m ↓ m*y

≡        { (7) with x:= y }

true

(End of Proof)

‡ An "m-tiple" is a multiple of m.

And now we are ready for an application of the Lemma with which this note started: we shall show that multiplication distributes over the GCD, in formula

(9)     m * (x↓y )   =   m*x ↓ m*y

Proof

On account of (7), the LHS of (9) is an m-tiple, on account of (8), the RHS is an m-tiple. Lemma (1) can thus be applied with m ⊑ u for P.u . Accordingly we observe for 1 ≤ m —the case of m = 0 is obvious—

(9)

≡        { (1) }

〈∀u : m⊑u :  u ⊑ m*(x↓y )  ≡  u ⊑ m*x ↓ m*y 〉

≡        { transforming the dummy: u = m*w }

〈∀w :: m*w  ⊑  m*(x↓y )   ≡   m*w  ⊑  m*x ↓ m*y 〉

≡        { (2) }

〈∀w :: m*w ⊑ m*(x↓y )   ≡   m*w ⊑ m*x  ∧  m*w ⊑ m*y 〉

≡        { r ⊑s   ≡   m*r  ⊑  m*s for 1≤m }

〈∀w :: w ⊑ x↓y   ≡   w⊑x ∧ w⊑y 〉

≡        { (2) }

true

(End of Proof)

Addendum

For those who are not comfortable with the dummy transformation, here is its pattern in a bit more detail

〈∀u : m⊑u : Q.u 〉

≡        { for non-empty range 〈∀w :: C 〉≡ C }

〈∀u : m⊑u : 〈∀w : u = m*w : Q.u 〉〉

≡        { interchange of quantifications }

〈∀w :: 〈∀u : u = m*w  ∧  m⊑u : Q.u 〉〉

≡        { u = m*w  ⇒  m⊑u }

〈∀w :: 〈∀u : u = m*w : Q.u 〉〉

≡        { one-point rule }

〈∀w :: Q.(m*w ) 〉

(End of Addendum)   

*           *
*

All of the above was triggered by Netty van Gasteren's use of (9) in her ingenious proof of

(10)     x↓y = 1  ⇒  x ↓ y*z = x↓z    :

x↓z

=        { antecedent of (10) }

x ↓ (x↓y )*z

=        { (9) and associativity of ↓ }

x ↓ x*z ↓ y*z

=        { (7) with m,x := x,z }

x ↓ y*z

Nuenen, 14 December 2001             

prof. dr Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by David Naumann and Carl Ludwigson
revised Mon, 3 Dec 2007

EWD1316

Philips and I: a few snapshots

I was working at the Mathematical Centre in Amsterdam when I was introduced to the people who built computers at Philips Research Laboratories in Eindhoven. It was a type of people I did not know, I found them very strange and they did not inspire confidence at all. Later I learned that I had been introduced to electronic engineers.

In Eindhoven they built the "Peter" and the "Pascal", and then Philips started its computer industry in Apeldoorn, where —if I remember the numbers correctly— the P1000 and the P1400 were developed in the 60s. I went to the festive inauguration of one of those machines; their demonstration was the algorithm for the shortest path, which I had used about a decade earlier for the inauguration of the ARMAC. I remember finding those guys a little lacking in originality; I was not given any credit.

At the Technological University Eindhoven, where I had gone in 1962, I had to build up a group in Computing Science. By the end of the decade we had the world's leading centre in operating system design, but Philips Apeldoorn hired none of my pupils, and a few years later Philips had to fold up its mainframe business. I remember the shock of seeing my potential domestic market being wiped out and the (difficult) conclusion that as a professor I would work for export only.

While I combined the functions of Burroughs Research Fellow and of Professor Extraordinarius at the T.U. Eindhoven, I had the misfortune of inventing a possibly patentable solution under circumstances that made it totally unclear whether the patent would belong to Burroughs or to Philips. In an effort to sort out that mess, I drove with Ir. P.J.P.G. Simons to Köln where we would meet a few relevant Burroughs officials; Ir. Simons was Adjunct Director of "Octrooien & Merken" (= Patents & Trademarks) at Philips. He was a nice, interesting and knowledgeable man, we had never met before but turned out to have a number of common acquaintenances, and an animated conversation evolved effortlessly. At a given moment he asked in a tone of some disbelief "Did I understand correctly that you never lived in the United States?". I confirmed that impression, upon which he asked in utter amazement

"But how could you then become an expert in your area?" ["Maar hoe hebt U dan een expert op Uw gebied kunnen worden?"] When I told this story to Ria, she immediately guessed my answer, viz. "By creating the area myself.".

Please remind yourself of Simons's question, each time you hear people complaining about "the cultural imperialism" of the USA: if there is such a thing, the USA seems to be the last country to blame for it.

                           Nuenen, 21 December 2001

Prof. Dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712-1188
USA

transcribed by John Adair
last revision Wed, 14 Nov 2007

EWD1317

From van IJzeren's correspondence to my aunt and uncle

Browsing through letters sent to my late aunt dr H.A. van Herk-Kluyver, I found the following theorem and proof in a letter from my late brother-in-law mr dr J.van IJzeren. The theorem is surprising but not interesting; this note is devoted to its proof because it is an elementary and very convincing illustration of the use of the device of the General Solution (which I promoted in EWD1155).

The proof uses two theorems.

(0) A Pythagorean triple that is relatively prime, can be written as p² – q², 2pq, p² + q² (See EWD1172.)

(1) For prime p, np – n is a multiple of p. (Known as "Fermat's Little Theorem", see EWD740.)

The theorem to be proved here —as said: surprising but not interesting— is

(2) For any Pythagorean triple, i.e. with a² + b² = c², there is a multiple of 7 among (a), (b), (a−b), (a+b).

* |  | *
| * |

Proof Because of a² + b² = c², any factor shared by 2 of the numbers is shared by the 3rd, and hence we can restrict ourselves to a, b, c that are relatively prime. We shall do so in what follows.

With ⊑ denoting "divides" and p,q providing (see (0)) the parameters for the General Solution of a² + b² = c², we observe

  7 ⊑ a ∨ 7 ⊑ b ∨ 7 ⊑ a-b ∨ 7 ⊑ a+b
≡   { algebra, prime.7 }
  7 ⊑ ab(a² – b²)
≡   { a := p² – q², b := 2pq }
  7 ⊑ 2(p² – q²)pq(p⁴ - 2p²q² + q⁴ – 4p²q²)
≡   { ¬ 7 ⊑ 2, prime.7, algebra }
  7 ⊑ pq(p² – q²) (p⁴ - 6p²q² + q⁴)
≡   { modulo calculus }
  7 ⊑ pq(p² – q²) (p⁴ + p²q² + q⁴)
≡   { algebra }
  7 ⊑ pq(p⁶ – q⁶)
≡   { algebra }
  7 ⊑ p⁷q – pq⁷
≡   { Fermat's Little Theorem, modulo calculus, prime.7 }
  7 ⊑ pq – pq
≡   { 7 ⊑ 0 }
  true.

I don't think I could have proved this theorem without the introduction of p and q.

Austin, 11 January 2002

prof.dr. Edsger W. Dijkstra
Department of Computer Sciences
The University of Texas at Austin
Austin, TX 78712 – 1188 USA

Transcribed by Guy Haworth.
Last revised Wed, 14 Nov 2007.

EWD1318

Coxeter's rabbit

On p.13 of his Introduction to Geometry, H.S.M. Coxeter invites the reader to see (and to use spontaneously) that with s = (a+b+c)/2 , abc equals

(0)   s(s–b)(s–c) + s(s–c)(s–a) + s(s–a)(s–b) – (s–a)(s–b)(s–c)

Proof     s(s–b)(s–c) + s(s–c)(s–a)

          =    { algebra }

             s(s–c)(2s–a–b)

          =    { definition of s }

(1)        s(s–c)c

            s(s–a)(s–b) – (s–a)(s–b)(s–c)

          =    {algebra}

(2)        (s–a)(s–b)c

Because both expressions (1) and (2) contain a factor c , so does (0); for reasons of symmetry, (0) also contains factors a and b , i.e. is a multiple of abc. The coëfficient equals 1 —as is trivially established with, say, a,b,c := 2,2,2 — and thus abc = (0) has been proved.

(End of Proof)

Nuenen, 14 April 2002

prof.dr.Edsger W.Dijkstra
Plataanstraat 5
5671 AL Nuenen
The Netherlands

transcribed by Diethard Michaelis
revised Wed, 14 Nov 2007

Table of Contents

The Manuscripts of Edsger W. Dijkstra

00xx

28: Substitution processes

32: Some meditations on Advanced Programming

35: Over de sequentialiteit van procesbeschrijvingen

37: A review of the IBM 1620 Data Processing System

41: Het vectorgeheugen

51: Multiprogrammering en de X8

54: Multiprogrammering en de X8 (Vervolg van EWD51)

57: Multiprogrammering en de X8 (Vervolg van EWD54)

62: Notitie over de aansluiting en de programmering van de teleprinter

65: Over Jansen

68: Some comments on the aims of MIRFAC

69: Over stapeladministratie

70: Over stapeladministratie. II

71: Over pagina-administratie

72: Over trommelpaginatransporten

74: Over seinpalen

75: Over standaardroutines

77: Het controlerende communicatieapparaat

82: Een ponsbandorganisatie voor de X8

84: Over paginaadministratie

86: Bezettingsadministratie der trommelpagina’s

89: Over formal locations

91: Samenvatting van oordeel over het “Voorstel tot aanschaffing van een digitale informatieverwerkende machine voor de afdeling der elektrotechniek”

96: Embedding complex arithmetic

01xx

101: Description of the object program

102: Description of the object program, II

105: Description of the object program (a sequel to EWD102)

108: Een algorithme ter voorkoming van de dodelijke omarming

111: Error checking

112: Ruwe schets vertaalproces

113: Segment control

116: De bankiersalgorithme en verfijningen daarvan

117: Programming considered as a human activity

118: Communicatiebuffering voor de EL-X8 - T.H.E.

123: Cooperating sequential processes

126: The multiprogramming system for the EL X8 THE

130: A sequel to EWD126

131: Verslag van bezoek aan de Arbeitstagung fuer Automatentheorie te Hanover.

132: An Experiment with the “record class” as suggested by C.A.R.Hoare

137: Heel kort verslag bezoek aan het symposium over Multi Access Computers, 2–4 november 1965 in het NPL

139: Appreciatie van ponskaarten

140: Documentatie over de communicatie apparatuur aan de EL X8

145: Globale beschrijving van de drijvende arithmetiek van de EL X8

147: Proposal for the input and the notation of the system

149: Documentatie over de communicatieapparatuur aan de EL X8 (vervanging van EWD140)

150: Tentamenopgave “Cooperating Sequential Processes”

155: Context dependent names

157: Over de sequentiele interpretatie van een ponsband

158: Tentamenopgave “Cooperating Sequential Processes” (april 1966)

161: Sequentiele interpretatie van ponsband

163: Eerste verkenning over de dood van programa’s

164: Keuze tussen symcharf en symchart

167: Aan de leden van de onderafdelingsvergadering

184: Ir.Medema, Ir.Hendriks, weledelgestrenge heren!

188: Over een academische opleiding tot “Computer Scientist”

190: Tentamen “Co-operating Sequential Processes”

191: Aan de Commissie Wetenschapsbeleid ter zake van Automatiseringswiskunde aan de THE

194: Het einde van een ambacht

196: The structure of the “THE”-multiprogramming system

198: An effort towards structuring of programmed processes

02xx

200: The variable size machine

201: A sequel to EWD200

206: A sequel to EWD201

209: A constructive approach to the problem of program correctness

209A: A constructive approach to the problem of program correctness

214: ACM Symposium in Gatlinburg “Operating System Principles”

215: A case against the GO TO statement

221: [Raw code for computing De Bruijn-sequences]

222: Verslag van het bezoek aan Grenoble en Parijs (6–11 december 1967)

224: HEEL VERTROUWELIJK

227: Stepwise program construction

229: Aan de leden van de Commissie Wetenschapsbeleid

230: To the EDITOR ALGOL 68

231: De Rekenautomaat als Gebruiksvoorwerp

232: Pretentie en doelstelling van het THE multiprogrammeringsproject

235: Contractie en expansie

236: Complexity controlled by hierarchical ordering of function and variability

237: A preliminary investigation into Computer Assisted Programming

238: Computation versus program

239: On trading storage against computation time

240: The moral of EWD237 – EWD239

241: Towards correct programs

243: Bijdrage voor de subcommissie Aanschaffingsbeleid Rekenautomaten

244: Een educatief dilemma

245: On useful structuring

246: Verslag van het bezoek aan de NATO Conference on Software Engineering

247: [“Journal for half-baked Ideas”]

247a: [Beantwoording ener enquete]

251: Requirements of programming tools

252: Mijn laatste verslag van een bijeenkomst van W.G.2.1.

252a: Ontwerp voorwoord [afstudeerrichting Fundamentele Programmering]

253: Tentamen Co-operating Sequential Processes (jan. 1969)

253a: Ontwerp Collegebeschrijving “Inleiding tot de kunst van het programmere

254: Computer Science of enkel Software Engineering?

254a: Hoger orde adressering

255: Over de IBM360

257: Verslag bezoek aan MIT

259: Toekomstverwachting Fundamentele Programmering

260: Plotting a curve with a printer

261: Hoe wiskundig programmeren is

264: On understanding programs

267: Over de toekomst van Computer Science

268: Structured programming

270: Aan de keuzecommissie rekenmachine

272: Verslag van de tweede “Conference on Software Engineering”, georganiseerd door de NATO Science Committee te Rome, 27–31 oktober 1969

273: The programming task considered as an intellectual challenge

275: Structure of an extendable operating system

278: Organisatie van onderzoek en onderwijs van Fundamentele Programmering

279: The programming laboratory project

281: Aan de Commissie Wetenschapsbeleid

282: A tree-structured system

286: Verslag van mijn reis naar California

287: Sans titre (but most definitely a predecessor to EWD316, “A short introduction into the art of programming”)

288: Concern for correctness as a guiding principle for program construction

288a: Recensie voor het tijdschrift “Informatie”

292: Letter to professor C.A.R. Hoare (31 August 1970)

295: Reisverslag van bezoek aan het Seminar on the Teaching of Programming at University Level

298: Informatica als wiskundige discipline

03xx

300: Exit “The Programming Laboratory”

301: Over de bewijsbaartheid van programmacorrectheid

302: Design considerations in more detail

303: On the reliability of programs

306: Over het gewicht van een informatica-opleiding

307: (over een voorgestelde configuratie van een P1400 en vier P880’s)

308: Reisverslag bezoek van E.W.Dijkstra aan IFIP W.G.2.3 te Warwick, Engeland

309: (over een voorgestelde configuratie van een P1400 en vier P880’s)

310: Hierarchical ordering of sequential processes

311: [Review of] Bauer, Goos: “Informatik, Erster Teil” Heidelberger Taschenbuecher, Band 80 Springer Verlag, 1971

312: Verslag van reis van E.W.Dijkstra naar Noord Amerika

316: A short introduction to the art of programming

316A: Reisverslag van Edsger W.Dijkstra aan Summer School Marktoberdorf, juli 1971

317: On a methodology of design

319: A class of allocation strategies inducing bounded delays only

325: Poging tot plaatsbepaling van de Informatica

330: [Book review of: Bauer-Goos, Informatik, Zweiter Teil]

338: Parallelism in multi-record transactions (with C.S.Scholten)

340: The humble programmer

341: [Toespraak over de noodzaak van programmeermethodologie]

343: Reisverslag betreffende het bezoek aan de USA van 14 tot 30 mei 1972 door E.W.Dijkstra

345: Ter zake van wiskundige modelvorming

348: Verslag van de reis van E.W.Dijkstra naar Boston, 12–18 augustus 1972

349: Ontwikkelingsplan Informatica

351: Verslag bezoek Engeland 30 augustus – 9 september 1972

353: Elementen ener afstudeerrichting in de informatica

356: Advanced Course on Computer Systems Architecture (Grenoble, December 1972)

361: Programming as a discipline of mathematical nature

362: Bezoek van E.W.Dijkstra aan l’Alpe d’Huez, 8–15 december 1972

363: Reisverslag E.W.Dijkstra: Open house on semantics, Aarhus, 7–18 jan. 1973

364: Weledelgestrenge Heer, Ingenieur Swinkels

365: A parabel

366: Waarom ik niet gewoon hoogleraar wil blijven

368: Verslag van bezoek aan Washington, maart 1973

374: The analysis of multiprogrammed systems of unspecified degree of parallellism

375: A non algebraic example of a constructive correctness proof

376: Finding the maximum strong components in a directed graph

379: On a connection pattern between 2**N elements

384: Betrouwbaarheid van programma's

385: Trip report E.W.Dijkstra Summer School Munich, July 25 to August 4, 1973

386: The solution to a cyclic relaxation problem

387: Trip report IBM Seminar “Communication and Computers”, Newcastle, Sept. 1973

389: Trip report I.U.C.C. Colloquium, Canterbury, 18th–21st Sept. 1973

391: Self-stabilization in spite of distributed control

392: Self-stabilization with four-state machines

393: On representational abstraction

395: Trip report E.W.Dijkstra IFIP Working Group W.G.2.3 “On Programming Methodology”, 21st–26th October 1973, Blanchland, England

396: Self-stabilization with three-state machines

397: Self-stabilizing systems with distributed control

398: Sequencing primitives revisited

399: An immediate sequel to EWD398: “Sequencing primitives revisited”

04xx

401: The characterization of semantics

404: A trip to France: 13th–20th December 1973

406: A trip to the U.S.A., 5th–25th January 1974

407: Acceptance speech for the AFIPS Harry Goode Memorial Award 1974

408: A time-wise hierarchy imposed upon the use of a two-level store

413: The formal treatment of some small examples.

415: A beautiful proof of a probably useless theorem (with W.H.J.Feijen)

416: On avoiding the infinite

417: On the abolishment of the subscripted variable

418: Guarded commands, non-determinacy and a calculus for the derivation of programs

420: Tripreport E.W.Dijkstra, Luxembourg, 7–12 April 1974

423: Trip report E.W.Dijkstra, W.G.2.3 Meeting “Boldern” 28th April–3rd May 1974

425: Trip report E.W.Dijkstra, USA and Canada, 5th–25th May 1974

426: Self-stabilizing systems in spite of distributed control

427: Speech at the occasion of an anniversary

428: Array variables.

429: A generalization of the Sheffer Stroke for n-valued logic (by C.S.Scholten)

432: [A letter to C.A.R. Hoare, 13 July 1974]

435: Associons: an effort towards accomodating potentially ultra-high concurrency (with W.H.J.Feijen and M.Rem)

439: Associons continued (with W.H.J.Feijen and M.Rem)

440: The problem of the most isolated villages.

442: Inside “Mathematics Inc”

443: A multidisciplinary approach to mathematics

447: On the role of scientific thought

448: Trip report E.W.Dijkstra, Edinburgh and Newcastle, 1–6 September 1974

449: Het curriculum informatica aan de THE

450: Correctness concerns and, among other things, why they are resented

451: Heer, verlos ons van de charlatans!

452: About robustness and the like

453: Finding the maximal strong components in a directed graph.

454: [Letter to Dr. H.Bekic, 8 October 1974]

456: Determinism and recursion versus non-determinism and the transitive closure

458: On non-determinacy being bounded.

459: The pattern matching problem.

462: A time-wise hierarchy imposed upon the use of a two-level store

463: Some questions

464: A new elephant built from mosquitos humming in harmony

465: Monotonic replacement algorithms and their implementation

466: Trip report E.W.Dijkstra, Meeting IFIP W.G.2.3., Munich, 8–14 December 1974

469: Programming methodologies, their objectives and their nature

470: Letter to the referees of EWD418

471: Bij de aanvang van het semester

472: Guarded commands, non-determinacy and formal derivation of programs

473: On the teaching of programming, i.e. on the teaching of thinking

474: Trip report visit ETH Zurich, 3–4 February 1975 by E.W.Dijkstra

475: A letter to my old friend Jonathan

476: Concurrent programming: a preliminary investigation

477: Tweede toespraak tot mijn studenten

478: On one-sided smoothing of event sequences

479: Commentaar op “Structuurplan Informatica (W.O.)” van de ARSI

480: “Craftsman or scientist?”

481: Derde toespraak tot mijn studenten

482: Exercises in making programs robust

483: Vierde toespraak tot mijn studenten

484: Tripreport E.W.Dijkstra, London, 9–10 March 1975

485: Marketing questionnaire “A Discipline of Programming”

486: Vijfde toespraak tot mijn studenten

487: Letter to the Burroughs recipients of the EWD-series

489: Zesde toespraak tot mijn studenten

492: On-the-fly garbage collection: an exercise in multiprocessing

493: [Toespraak tot een afstudeerder]

494: Trip report E.W.Dijkstra 16th April/7th May, U.S.A. and Canada

494a: Zevende toespraak tot mijn studenten

495: Achtste toespraak tot mijn studenten

496A: On-the-fly garbage collection: an exercise in cooperation (preliminary version) (with Leslie Lamport, A.J.Martin, C.S.Scholten, and E.F.M.Steffens)

496B: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, and E.F.M.Steffens)

497: A challenge to memory designers?

498: How do we tell truths that might hurt?

499: [toespraak tot een student bij uitreiking ir-diploma]

05xx

500: After many a sobering experience

501: Variations on a theme: an open letter to C.A.R. Hoare

502: On a gauntlet thrown by David Gries

503: A post-scriptum to EWD501

504: Erratum and embellishments of EWD503

506: Tripreport E.W.Dijkstra: NATO Summer School Marktoberdorf 1975

507: On a gauntlet thrown by David Gries

508: A synthesis emerging?

509: Eerste toespraak, najaar 1975

511: Tripreport E.W.Dijkstra W.G.2.3, Baden, 1–5 September 1975

512: Comments at a symposium

513: Tripreport E.W.Dijkstra Newcastle, 8–12 September 1975

514: On a language proposal for the Department of Defense

515: Tweede toespraak, najaar 1975

516: Derde toespraak, najaar 1975

518: Vierde toespraak, najaar 1975

520: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, E.F.M.Steffens)

521: Vijfde toespraak, najaar 1975

522: Zesde toespraak, najaar 1975

523: Zevende toespraak, najaar 1975

524: Review of “On the Feasibility of Software Certification”

525: On a warning from E.A.Hauck

526: Comments on “Woodenman” HOL Requirements for the DoD

527: On units of consistency

528: More on Hauck's warning

529: Achtste toespraak, najaar 1975

530: Negende toespraak, najaar 1975

531: Tiende toespraak, najaar 1975

532: An open letter to L.Bass

533: HOMO COGITANS

534: Elfde toespraak, najaar 1975

535: An answer to Jack Mazola

536: A sequel to EWD535

537: Twaalfde toespraak, najaar 1975

538: A collection of beautiful proofs

539: Mathematics Inc., a private letter from its chairman

540: Two views of programming

541: Dertiende en laatste toespraak, najaar 1975

542: [Toespraak tot twee afstudeerders]

543: Eerste toespraak tot mijn studenten, voorjaar 1976

544: An open letter to Ross Honsberger

547: Tripreport E.W.Dijkstra, England and USA, 3-26 January 1976

548: Tweede toespraak tot mijn studenten, voorjaar 1976

549: Derde toespraak tot mijn studenten, voorjaar 1976

550: A more formal treatment of a less simple example

551: Vierde toespraak tot mijn studenten, voorjaar 1976

552: Vijfde toespraak tot mijn studenten, voorjaar 1976

553: On a gauntlet thrown by David Gries

554: A personal summary of the Gries-Owicki theory

555: Aan de Raad van Advies

556: Zesde toespraak tot mijn studenten, voorjaar 1976

557: Zevende toespraak tot mijn studenten, voorjaar 1976

558: Achtste toespraak tot mijn studenten, voorjaar 1976

559: Negende toespraak tot mijn studenten, voorjaar 1976

560: Tiende toespraak tot mijn studenten, voorjaar 1976

561: A “non trip report” from E.W.Dijkstra

562: The effective arrangement of logical systems

563: Formal techniques and sizeable programs

564: A superficial book

564a: Aan de Raad van Advies, in tweede ronde.

565: Elfde toespraak tot mijn studenten, voorjaar 1976

566: Programming: from craft to scientific discipline

567: Twaalfde toespraak tot mijn studenten, voorjaar 1976

568: A programmer’s early memories

569: Dertiende en laatste toespraak tot mijn studenten, voorjaar 1976

570: An exercise for Dr.R.M.Burstall

571: A simple consideration with far-reaching consequences (DRAFT)

572: Tripreport E.W.Dijkstra, U.S.A. and U.K., 8 June - 10 July 1976

573: A great improvement

574: A letter to Professor Zohar Manna, 26 July 1976

575: To H.D.Mills, Chairman Software Methodology Panel

576: On subgoal induction

577: Tripreport E.W.Dijkstra, ECI-conference 9–12 August 1976, Amsterdam

578: More about the function “fusc” (A sequel to EWD570)

580: Waarom de onderafdeling der wiskunde zich met de informatica moet bezighouden

581: A somewhat open letter to Professor John McCarthy

582: A proof of a theorem communicated to us by S.Ghosh (with C.S.Scholten)

583: Eerste toespraak tot mijn studenten, najaar 1976

584: Tripreport E.W.Dijkstra, Poland and USSR, 4-25 September 1976

585: Tripreport E.W.Dijkstra, Tokyo, 28 Sep.—3 Oct. 1976

586: Tweede toespraak tot mijn studenten, najaar 1976

587: Derde toespraak tot mijn studenten, najaar 1976

588: Vierde toespraak tot mijn studenten, najaar 1976

589: Vijfde toespraak tot mijn studenten, najaar 1976

590: A first investigation of the crossflow computer

591: The problem of the maximum length of an ascending subsequence

592: A small note on the additive composition of variant functions

593: Zesde toespraak tot mijn studenten, najaar 1976

594: A parable

595: On-the-fly garbage collection: an exercise in cooperation (with Leslie Lamport, A.J.Martin, C.S.Scholten, E.F.M.Steffens)

596a: Tripreport E.W.Dijkstra, Copenhagen 10–12 Nov. 1976

597: Yet another note about termination

07xx

709: My hopes of computing science

710: When messages may crawl, II (A sequel to EWD708)

711: Trip report E.W.Dijkstra, Ithaca, Albany, Austin (Texas), 26/5 – 10/6 1979

712: Trip report E.W.Dijkstra, Antwerp, 24–29 June 1979

713: On a problem posed by W.H.J.Feijen

714: Trip report E.W.Dijkstra, Mission Viejo, Santa Cruz, Austin, 29 July – 8 September 1979

715: Trip report E.W.Dijkstra, Munich – London, 16–29 September 1979

716: A short talk to my students about money

717: An exercise in exposition

718: Assembly conventions for the EDSAC

719: On not duplicating volatile information

720: Why correctness must be a mathematical concern

721: The design of a state space with a useful structure (I)

722: A book review for the IBM Systems Journal

723: On W.H.J.Feijen’s solution for the lexicographic minimum of a circular list

724: Een gotspe

724E: A chutspa

725: Trip report E.W.Dijkstra, Liege, Nov.–Dec.1979

726: How Dutch Informatics fell between two chairs

727: Trip report E.W.Dijkstra, U.S.A. 12 Jan. – 2 Feb. 1980

728: A problem solved by Netty van Gasteren and me

729: On well-shaped mathematical arguments

730: On two types of infinite sets of infinite sequences (by the Tuesday Afternoon Club)

731: An experiment in mathematical exposition

732: The teachability of mathematical thinking (Draft contribution to “Mathematics Tomorrow”)

733: Naar aanleiding van Experimentele post-propadeuse opleiding voor informatica-ingenieur aan de THE” (Eindhoven februari 1980 SOO/jc/sdb)

734: The superfluity of the general semaphore

735: A mild variant of Combinatory Logic

736: Recording the structure of trees in their leaves

737: A notational alternative for quantification

738: More mathematical folklore

739: A somewhat open letter to the Editor-in-Chief of Acta Informatica

740: A short proof of one of Fermat’s theorems

741: Partitioning the edges of the complete graphs into trees or cycles (by the Tuesday Afternoon Club)

742: A sequel to EWD740

743: A new policy for Mathematics Inc.?

744: A short note on symmetric distributed arbitration

745: Trip report E.W.Dijkstra, Los Angeles, Austin (Texas), and Portland, 6–28 August 1980

746: Trip report E.W.Dijkstra, Newcastle-upon-Tyne, 1–5 Sep. 1980

747: Comments on MIL–STD–1862, 28 May 1980

748: A somewhat open letter to Wladislaw M.Turski

749: On the productivity of recursive definitions

750: American programming’s plight

751: Mainly on the omission of parentheses

752: Distributed Arbitration (DRAFT, with C.S.Scholten)

753: On a theorem by Lambek and Moser

754: An error in EWD744

755: Very elementary number theory redone

756: A postscript to EWD755

757: A misguided educational effort

758: An intriguing example

759: A somewhat open letter to D.A.Turner

760: A somewhat open letter to F.Kroeger

761: Een kanttekening

762: We mathematicians are losing the race

763: A proof by Rutger M.Dijkstra and me

764: Repaying our debts

765: A Hungarian problem

766: An educational stupidity

767: A.J.Martin’s solution of the Hungarian problem

768: Largely on nomenclature

770: D.A.Turner’s reply

771: About 2-coloured 6-graphs

772: A methodological sequel to EWD771

773: Trip report E.W.Dijkstra, Han-sur-Lesse, 7–12 Jan. 1981

774: Trip report E.W.Dijkstra, California, 17–31 January 1981

775: On Kleinrock’s Theorem

776: Lambek and Moser revisited

777: A word of welcome (Draft)

778: A somewhat open letter to Nils J.Nilsson

782: A stupid notation

783: The administration as social disease

786: Trip report E.W.Dijkstra, England, 23 April 1981

786a: Sets are Unibags

787: A (new?) proof of a theorem of Euler’s on partitions

788: What we seem to have learned (with A.J.M. van Gasteren)

790: Trip report E.W.Dijkstra, München, 19 May 1981

791: The psychology of the user

793: The analysis of a two-person game

796a: Smoothsort, an alternative for sorting in situ

797: Fibonacci numbers and Leonardo numbers

798: Trip report E.W.Dijkstra, Newcastle, 19–25 July 1981

799: Trip report E.W.Dijkstra, Marktoberdorf, 26/7–10/8/81

08xx

800: A bagatelle for the left hand

801: Distances from the root in skew trees (with C.S.Scholten)

802: Trip report E.W.Dijkstra, Scotland, Newcastle 31 Aug.–15 Sep. 1981

804: On equality of propositions

805: Trip report E.W.Dijkstra, Amsterdam, 26–29 Oct. 1981

806: Trip report E.W.Dijkstra, USA, 1–27 Nov. 1981

808: Canonical string reduction

810a: Fast image construction in computerized axial tomography (CAT) (with A.J.M. van Gasteren)

811: An alternative ending for AvG16/ EWD809

814: A review of a book on PEARL

818: A nice theorem on monotonic predicate sequences

819: Mathematical induction and computing science

821: From predicate transformers to predicates (Dedicated by the Tuesday Afternoon Club to C.A.R. Hoare at the occasion of his being elected Fellow of the Royal Society.)

824: Linearization of a two-dimensional search

826: Trip report E.W.Dijkstra, USA, 20 May 1982 – 14 June 1982

827: A very simple exercise in SASL

829: De software crisis, ontstaan en hardnekkigheid

831: Why numbering should start at zero

832: A theorem about infinite sequences of numbers

833: An In-Depth Seminar on Proven Tools & Techniques of Structured Methodology for Effective Software Configuration Management

837: Trip report E.W.Dijkstra, Newcastle-upon Tyne, 6–10 Sep. 1982

838: Trip report E.W.Dijkstra, Copenhagen, 10–16 Sep. 1982

839: Trip report E.W.Dijkstra, Utrecht 30 Sep.–1 Oct. 1982

841: “There is no ‘royal road’ to geometry”

845: McCarthy’s 91–function: an unfortunate paradigm

847: Trip report E.W.Dijkstra, Australia, 19 Jan.1983 – 12 Feb.1983

850: Trip report E.W.Dijkstra, Helsinki, 1–4 March 1983

852: Judging “HOS” from a distance

853a: Ingenieur Ebergen, Weledelgetrenge Heer

854: The fruits of misunderstanding

855: Trip report E.W.Dijkstra, Barcelona 5–7 June 1983

856: On maximizing a product

857: Generalizing an old formula

858: Trip report E.W.Dijkstra, USA, 10 June–3 July 1983

861: Research proposal: Our plans for the years to come (with A.J.M. van Gasteren)

862: A sequence with |x[n]| = x[n–1] + x[n+1] has period 9

864: The distributed snapshot of Chandy/Lamport/Misra

864a: The Distributed Snapshot of K.M.Chandy and L. Lamport

865: Trip report E.W.Dijkstra, Brasil & USA, 17 Oct.– 6 Nov. 1983

866: An analytical proof of the Butterfly Theorem

868: Computers and General Education: a position paper

869: Ter afsluiting van de “Inleiding tot de Kunst van het Programmeren”

870: My mother’s proof of the Butterfly Theorem (see EWD866)

872: The little essay I could not write

873: Trip report E.W.Dijkstra, London and Colchester, 16–20 Jan. 1984

876: De microprocessor als lollie

877: Some useful formulae (with A.J.M. van Gasteren)

878: A monotonicity argument (with A.J.M. van Gasteren)

879: Trip report E.W.Dijkstra, London, 14–17 February 1984

881: A review of “The Evolution of Programs”

885: Trip report E.W.Dijkstra, Muenchen, 12–14 April 1984

887: Trip report E.W.Dijkstra, USA, 23 April –10 May 1984

888: Trip report E.W.Dijkstra, Zürich, 22–24 May 1984

889: User-friendly Mathematics

892: Trip report E.W.Dijkstra, London, 12–14 June 1984

893: Trip report E.W.Dijkstra, USA, 17–26 June 1984

895: Trip report E.W.Dijkstra, Marktoberdorf, 30 July – 12 Aug. 1984

896: On the nature of computing science

898: The threats to computing science

09xx

903: A short sequel to EWD863

904: A problem solved by my nephew Sybrand L. Dijkstra

906: Trip report E.W.Dijkstra, Nuenen & London, 10 Dec.’84 – 10 Jan.’85

907: Trip report E.W.Dijkstra, Netherlands, Austria, 23–31 Jan. 1985

909: Trip report E.W.Dijkstra, Westboro-Boston, 14–17 Feb. 1985

911: Trip report E.W.Dijkstra, Tulsa, 1–6 March 1985

913: On a cultural gap (Draft)

917: Another misguided effort

918: A summary of a year’s impressions

920: Can computing science save the computer industry?

921: A correction of EWD914–15

923: Trip report E.W.Dijkstra, Ithaca, Newport, 30 May – 13 June 1985

923a: Where is Russell’s “Paradox”?

924: On a cultural gap

925: Trip report E.W.Dijkstra, London, 25–27 June 1985

926: A computer to think about

927: The ATAC ( = Austin Tuesday Afternoon Club)

930: For the record: the Linear Search

932c: The streamlining of the mathematical argument

936: On anthropomorphism in science

947: A letter to a typewriter manufacturer

951: Trip report E.W.Dijkstra, Europe, 13.12.1985 – 10.1.1986

952: Science fiction and science reality in computing

956: Address to my students

958: On naming (with A.J.M. van Gasteren)

960: On a proof I learned from prof. dr. J. Haantjes

962: Introducing a course on mathematical methodology

963: Visuals for BP’s Venture Research Conference

966: Management and Mathematics

968: Trip report E.W.Dijkstra, Marktoberdorf, 29 July – 10 Aug l986

973: The cosine rule

974: The longer side is opposite to the greater angle

975: On the theorem of Pythagoras

976: Who is your “target audience”?

977: An address to my students (16.9.1986)

978: A sequel to EWD977 (18.9.1986)

979: A solution designed by A. Blokhuis

980: The strange case of The Pigeon-hole Principle

981: Address to my students (23.9.1986)

983: How do we contribute? (30.9.1986)

987: On a class of graphs with modest diameter

987a: On a class of graphs with modest diameter

988: On the phenomenon of scientific disciplines

988a: How experimental is computing science?

989: Proving Gupta’s Theorem

991: Why Johnny can’t understand

992: Difficult is easy

993: The nature of my research and why I do it

996: Courtesy A.J.M. van Gasteren, C.S.Scholten and J.G.Wiltink

997: Computing Science in the United Kingdom

10xx

1000: Twenty-eight years

1003: Graphs of modest diameter and degrees

1006: Trip report E.W.Dijkstra, Stanford/Palo Alto, 26–29 March l987

1008: What computing science is about

1009: On a somewhat disappointing correspondence

1011: Introducing my fall 1987 course on Mathematical Methodology

1012: “Real mathematicians don’t prove”

1013: Position paper on “fairness”

1014: A monotonicity argument revisited

1016: A computing scientist’s approach to a once-deep theorem of Sylvester’s

1018: To the members of the Budget Council

1019: Another filler of the YoP Institute

1024: A new science, from birth to maturity

1026: Trip report E.W.Dijkstra, Marktoberdorf 1988

1027: My methodological blunder with grid polygons

1028: Euclid, Netty, and the prime numbers

1033: Trip report E.W.Dijkstra, Zürich, 15–20 Oct. 1988

1035: On long-range planning for the CS department

1036: On the cruelty of really teaching computing science

1039: Seemingly on a problem transmitted by Bengt Jonsson

1041: By way of introduction

1041a: Factorizing the factorial

1043: A few comments on “Computing as a discipline”

1044: To hell with “meaningful identifiers”!

1046: A tale of two winters

1049: A somewhat open letter to Uri Leron

1050: On the design of a simple proof for Morley’s Theorem

1051: The next forty years

1053: Monochrome pairs in the three-coloured plane

1054: On hygiene, intellectual and otherwise

1055: On the problem of the calissons

1055A: untitled (advice to a young scientist)

1055c: On covering a figure with diamonds

1056: Hoe onbelangrijk het is of duikboten kunnen zwemmen

1057: Andrei P. Ershov in Nuenen

1058: In reply to comments

1059: 0 Preface (Mathematical Methodology)

1060: “Predicate Calculus and Program Semantics”, fall 1989

1066: Hungry? Have a byte ....

1067: A very first introductory example (Mathematical Methodology)

1068: On the quality criteria for mathematical writing (Mathematical Methodology)

1069: Fair gambling with a biased coin

1070: For brevity’s sake (Mathematical Methodology)

1071: Making a fair roulette from a possibly biased coin

1071a: Making a fair roulette from a possibly biased coin

1072: On covering a figure with diamonds

1073: How Computing Science created a new mathematical style

1076: From “Discrete Mathematics with Applications” by Susanna S. Epp

1083: The balance and the coins

1085: Proving the theorem of Menelaos

1092: Two ways of determining an expectation value

1094: The undeserved status of the pigeon-hole principle (Mathematical Methodology)

1095: Are “systems people” really necessary?

1096: Potter’s proof of disjunction’s symmetry

11xx

1100: The computing habit

1101: Triangles in graphs: a sharp bound

1103: For the record: ETAC and the couples

1104: So much for scientific visualization

1105: For Bill Walker a sequel to EWD1099

1108: Too much PSST in Texas

1109: Simplifying a proof in our book

1110: To the members of the budget council (Confidential)

1112: Why “up to equivalence”

1113: A somewhat open letter to Ben Kuipers

1117: Monotonic demonstranda and dummy introduction

1121: Covering rectangles with bars of length 3

1126: Who failed?

1129: Why “heavy-weight” bits are unavoidable

1131: Bulterman’s theorem on shortest tree

1132: Introducing a course on the design and use of calculi

1134: The checkers problem told to me by M.O. Rabin

1135: The knight’s tour

1137: Computing the future?

1140: The arithmetic mean and the geometric mean

1142: It is all distributivity

1145: A somewhat open letter to Cathleen Synge Morawetz

1151: A terrible Thursday

1152: Het intellectuele gehalte van informatica

1155: A prime is in at most 1 way the sum of 2 squares

1155a: A prime is in at most 1 way the sum of 2 squares

1156: Voorwoord (voor jaarboek studievereniging UT)

1157: Introducing a course on program design and presentation

1161: How promiscuous are the French ?

1165: There is still a war going on

1166: “From my Life”

1170: Equilateral triangles and rectangular grids

1171: The argument about the arithmetic mean and the geometric mean, heuristics included

1175: The strengths of the academic enterprise

1177: In Memoriam Jan L.A. van de Snepscheut

1179: A sorry parade

1180: Heuristics for a very simple Euclidean proof

1181: Don’t mix unary pre- and postfix operators

1188: A problem from Zhendong Patrick Su (including an alternative solution by R.Boute

1190: Problem 10406 from The American Mathematical Monthly, Volume 101, Number 8 / October 1994

1193: On arcs and angles

1194: Z.P. Su’s second problem

1198: Jan van de Snepscheut’s tiling problem

1199: A supplement to EWD1140 and EWD1171

12xx

1200: Only a matter of style?

1202: The complete (n + 1)-graph in n-dimensional space

1203: Primes once more (re Kac & Ulam)

1204: Complete DAGs

1205: A trip to Harvard Law School, 10–11 April 1995

1206: An unfortunate use of symbols

1207: A theorem about “factors” perhaps worth recording

1209: Why American Computing Science seems incurable

1210: The non-unique node multiplicity

1211a: On some very binary patterns (dedicated to F.E.J. Kruseman Aretz)

1212: For the record: painting the squared plane

1213: Introducing a course on calculi

1214: The marriage agency

1215: Courtesy Dr. Birgit Schieder

1216: The equation x: [x]

1217: Comments on a Review of the Department

1219: “I have a proof that ....”

1220: Honors course “Mathematical Methodology”, Spring 1996

1224: Hm++, a new Professional Standard (From the desk of the chairman of the Board of Mathematics Inc.)

1226: A simple geometrical theorem I did not know

1227: A somewhat open letter to David Gries

1228: Sylvester’s theorem used (see EWD1016)

1229: Nondeterministic construction of an arbitrary witness

1231: The arithmetic and geometric means once more

1232: My simplest theorem

1235: Een scheve schaats

1237: Elegance and effective reasoning (Fall 1996)

1238: Foreword

1239: A first exploration of effective reasoning

1243: The next fifty years

1243a: The next fifty years

1245: A kind of converse of Leibniz’s Principle

1248: Homework #1 (See EWD996)

1250: The couples, the river, and the little boat

1251: Two problems derived from Hugo Steinhaus

1252: Convocation speech, December 8, 1996

1253: Mathematical induction’s fixpoint

1255: Pruning the search tree

1256: Mathematical Methodology, Spring 1997

1258a: The ladder theorem

1260: The marked coins and the scale

1261: The angle bisectors of a triangle

1268: The Mathematical Divide

1273: On Dijkstra’s Lemma and Kruskal’s Algorithm

1277: Society’s role in mathematics

1282: On graphs whose nodes are Black or White

1283: How “they” try to corrupt “us”

1284: Computing Science: Achievements and Challenges

1285: To Cambridge by mistake (13–18 April 1999)

1287: Dear Tony, dearest Jill, and other people, dear or not

1288: Ulrich Berger’s argument rephrased

1290: Eliminating cascading carries

1292: When a symmetric operator distributes over (up) and (down)

1297: Triggered by a high-school exercise

1298: Under the spell of Leibniz’s Dream

13xx

1300: The notational conventions I adopted, and why

1301: The river, the isles and the bridges

1302: Once more bichrome triangles in complete graphs

1303: My recollections of operating system design

1304: The end of computing science?

1305: Answers to questions from students of Software Engineering

1306: The chessboard covered with dominoes

1306a: The chessboard covered with dominoes

1307: An unavoidable case analysis

1308: What led to “Notes on Structured Programming”

1309a: Zuckerman’s problem and the ETAC

1310: Three trip reports rolled into one: 2001.04.16 – 2001.07.06

1311: Another look at a problem from Hugo Steinhaus

1312: On disjoint binary numbers

1313: The GCD and the minimum

1315: Indirect equality enriched (and a proof by Netty)

1316: Philips and I: a few snapshots

1317: From van IJzeren’s correspondence to my aunt & uncle

1318: Coxeter’s rabbit