Case Studies in Systematic Software Development
Case Studies in Systematic Software Development
Case Studies in Systematic Software Development
Edited by CLIFF B JONES Department of Computer Science, Manchester University and ROGER C F SHAW Praxis Systems plc.
c Prentice/Hall International
Contents
vi
Contents
Foreword
VDM is currently the most widely spread method for the systematic, via rigorous, to formal development of software, from programs to programming systems.
Background
VDM, as rst conceived, around 19731975, at the IBM Vienna Laboratory, derived its foundational and methodological constituents from many academic sources: notably from the works of, and inspired by such researchers as, Jaco de Bakker, Rod Burstall, Tony Hoare, Peter Landin, John McCarthy, Robin Milner, John Reynolds, Dana Scott, Christopher Strachey, and many others. The inspirational background offered here was cast into a whole to form classical VDM by the Viennese industrial researchers (the late) Hans Beki , and Wolfgang Henhapl, Peter Lucas, Cliff Jones and myself. c
viii
Foreword
of Computing, Vol. 1, No. 1, 1989. Phase 2 can be characterized as composed of a Danish (LNCS98) and an English (SDRA and SSD/VDM) school. The difference in emphasis between the two schools is really supercial: styles of notation differ, modes of dening functions and operations either mostly directly, and mostly applicatively (the Danish school), or (the English school) by means of pre-/post-conditions, and, for operations, on a slightly different imperial state notion.
a unication
The British Standards Institutes current VDM standardization effort is successfully amalgamating these two schools. The present book follows this consolidation. Whereas phase 3 work may be called post-VDM, and whereas it is too early to speak of this works wide acceptance, the present book offers material that can be readily adapted in any mature industrial environment.
Foreword
ix
to pursue software development in the only exciting and professionally responsible way it should be developed namely formally. Young, upstart, companies which offer this opportunity to the recent academically trained software engineers and programmers will attract the coming (large) generations. An old generation clings to such dogmatisms as: (1) formal definitions are unreadable, (2) it is hard to prove programs correct, (3) the technology is not available. This book proves otherwise: (1) the denitions are easy to read and one should only entrust serious software development to professionals anyway; (2) it is not that hard to reason about correctness and who would want incorrect software if it could be correct?; and (3) the technology, VDM, has been here for quite a while it is industrys task to develop industry-scale tools. Industry no longer has any excuse not to put the results of academic research into daily practice. This volume certainly proves that academic research is industrially useful. To specify formally, and to formally develop software, is to create insight into, and theories about, otherwise complex systems. This book, with its balanced examples proves that point: it is refreshingly relaxing to develop beautiful software embodying elegant theories formally and VDM is presently the strongest contender! Dines Bjrner Holte, 25 September 1989
Foreword
Preface
Although young by the standards of most engineering disciplines, software development tackles tasks of enormous complexity. In seeking a systematic approach to control this complexity, the software industry is recognizing the need for a variety of new practices. High on their list is an acceptance that formal methods are necessary if large systems are to be developed to higher standards than currently prevail. Formal methods is a term which is used to cover both the use of mathematical notation in the functional specications of systems and the use of justications which relate designs to their specications. One of the most widely known and used formal methods is called the Vienna Development Method (more often referred to as VDM). VDM was developed in an industrial environment but has also evoked considerable academic research. VDM provides both a specication notation and proof obligations which enable a designer to establish the correctness of steps of design. It is a development method in the sense that it offers notation and framework for recording and justifying specications and design steps. VDM does not, however, claim to be a normative method in the sense that it results in the choice of a standard or best design: the designer provides the insight. Chapter 1 discusses how VDM concepts t into the broader subject of software engineering. VDM grew out of earlier research but became a coherent whole in the mid 1970s. Since then it has been developed and discussed in a literally hundreds of publications. A clear sign of its maturity for industrial use is the availability of a variety of textbooks which set out to teach the use of both the specication and design justication parts of the method. Furthermore, courses are available from commercial organizations and two international conferences (organized by the European Community, VDM-Europe group) have been dedicated to VDM. It is the experience of the authors and editors of the current volume (amongst many other people) that methods like VDM enable them to describe major computer systems. Such experience is difcult to convey in a book and a textbook on a method such as [Jon90] is certainly an inadequate medium. Although the examples in this volume are not large by industrial standards, they should provide a much clearer indication of how to tackle major systems than is possible in any book whose main task is teaching xi
xii
Preface
the method from scratch. It has long been obvious that there is a signicant need for such material: both of the editors have taught courses where the step from the textbook examples to an industry-sized specication has to be bridged by some sort of case study. Much case study material has in fact been available in the literature. Unfortunately, the papers are not always easily located and the notation (often because of such mundane issues as printing devices) varies from one publication to the next. Experience of teaching VDM to industrial audiences constantly reminds one of the importance of a uniform style of presentation, at least during the early stages of the learning process. While researchers often show a cavalier disdain for issues of syntax, more practically oriented people tend to get confused when presented with a variety of notation. In fact, some industrial organizations cite the absence of a stable language (along with the paucity of tools) as a major reason for their reluctance to embrace formal methods. The work of the British Standards Institution (BSI) group BSI IST/5/50 has progressed to the point that an outline standard is now available for comment. This presents a timely opportunity to publish a collection of VDM material in a coherent notation which should achieve wide acceptance. There is also evidence that this stability is stimulating tool builders. A second edition of Systematic Software Development using VDM [Jon90] has been prepared using the draft BSI standard notation and the current volume adopts the same language. The case studies illustrate all facets of VDM. Some conne themselves to specications often providing insight as to why the particular specication was developed. 1 Other examples cover design by data reication or operation decomposition. In many chapters proofs are only sketched but some very detailed proofs are also presented. Ten authors have contributed a total of twelve case studies (Chapters 213). The authors come from backgrounds as varied as their material and beyond conformity to the specication notation itself the editors have not tried to force the material into a particular mould. In fact the editors could echo George Bernard Shaws comment in the preface to Essays on Socialism that there has been no sacrice of individuality. There are several positive reasons for this. Before tackling larger specications the reader must become aware that there is often no right specication. Furthermore, seeing a range of styles will help the readers focus on what they wish to develop as their own approach. The size of the chosen case studies is such that they illustrate many of the points made in [Jon90] better than was possible there. This is particularly the case with the exhortation to use more formal approaches in the early stages of design. Another major point which should become clear is the importance of providing a design record. Most readers will probably begin their study of the material with application areas with which
1 The term reication is preferred to the more widely-used word renement. Michael Jackson pointed out to the author that the latter term is hardly appropriate for the step from a clean mathematical abstraction to a messy representation dictated by a particular machine architecture. The Concise Oxford Dictionary denes the verb reify as convert (person, abstract concept) into thing, materialize.
Preface
xiii
they are familiar. This should enable them to perceive the use of formal models in experimenting with alternative architectures. Apart from the case studies themselves, an appendix covers the notation used. In part, this is just a summary of the language; but it also discusses those aspects which are needed in some case studies but are not covered in [Jon90] (e.g. Lambda expressions). A reader who encounters anything unfamiliar should consult Appendix A. There is also a list of references to the literature (a wider list of references is to be included in the Teachers Notes associated with [Jon90]; since the material covered here represents only a very small percentage of that published about VDM; the reader is encouraged to follow such references as might be relevant to their own application area). It was decided to conne the material is this book to the major uses of VDM and only Chapter 12 explores extensions to VDM in the area of user interface design. In particular, no attempt has been made to exemplify material which extends VDM to handle concurrency. Work in this area is at the research stage and the interested reader must follow the references to the relevant publications. Different users of this book will obviously employ it in different ways. It is likely to be background reading for undergraduate courses which use one or the other textbook to teach VDM; while an MSc or industrial course might make detailed analysis of the case studies. A particularly valuable way of doing this is to organize some sort of walkthrough of chosen examples. By their very nature, few of the examples are closed and there is excellent scope for extending a case study as a major project. The editors are grateful to the long-suffering authors who have provided the bulk of this book, to Prentice Hall and Ruth Freestone for their help and encouragement in its formation and to Peter Luckham for his efforts in obtaining the Linotron output. Cliff Jones wishes to express his thanks for nancial support to his research from the Wolfson Foundation and SERC; the latter both from research grants and his Senior Fellowship. He also gratefully acknowledges the stimulus provided by meetings of IFIP WG2.3. Roger Shaw expresses his thanks to Praxis Systems plc for support of his part in editing this book.
xiv
Preface
Contributors
John S. Fitzgerald Department of Computer Science The University Manchester United Kingdon M13 9PL Chris W. George STC Technology Ltd London Road Harlow Essex United Kingdon CM17 9NA Kevin D. Jones Digital Equipment Corp. Systems Research Center 130, Lytton Avenue Palo Alto Ca 94301, USA Cliff B. Jones Department of Computer Science The University Manchester United Kingdon M13 9PL Lynn S. Marshall Computing Research Laboratory Bell-Northern Research Ltd. P.O. Box 3511, Station C Ottawa Ontario Canada K17 4H7 Richard C. Moore Department of Computer Science The University Manchester United Kingdon M13 9PL Roger C. Shaw Praxis Systems plc 20, Manvers Street Bath United Kingdon BA1 1PX Sunil Vadera Deptartment of Mathematics and Computer Science University of Salford Salford United Kingdon M5 4WT Anne Walshe 18, Brighouse Close Ormskirk Lancashire United Kingdon L39 3NB Mario I. Wolczko Department of Computer Science The University Manchester United Kingdon M13 9PL
xv
xvi
Preface
In the course of presenting industrial training on formal methods a number of questions relating to the application and relevance of such methods to software engineering have cropped up repeatedly. Some of these questions relate to the scope of such methods as VDM. Others reveal a concern over the use of the term method, and suggest that many software engineers have a different understanding of its meaning than do the proponents of formal methods. The intention of this chapter is to explain what is meant by the term formal method and to show how such methods t naturally into the software development process.
1.1 Introduction
Neither this collection of case studies nor the companion textbook [Jon90] is intended to teach the topic of software engineering: there are many good texts devoted to that subject [Pre87, Rat87, Sho83, Som88] and some of these present a fairly extensive discussion of the role of formal methods [Rat87, Som88] within the software development process. Nonetheless we need to briey review what is meant by software engineering. For the purposes of the following discussion software engineering may be viewed as those activities associated with the development of software for computer-based applications. The development activities considered should ensure that the software produced is t for the purpose, that the development employs the best available practices, and that the development is properly recorded and soundly organized, planned and managed. In other words software engineering encompasses those management, technical and quality related activities that are involved in the professional development of software.
Planning
Product development
Marketing
CP
PR
RD
Check
SM SSPR
PS PIR AD IT
STT
PAR
PSR
PDR
DD
UT
IR
DDR
IMP
CP RD PS AD DD IMP UT IT
PHASES Conceptual planning Requirements denition Product specication Architectural design Detailed design Implementation Unit testing Integration testing
KEY MILESTONE REVIEWS PIR PSR PDR DDR IR INR PSUDR PAR SSPR Product initiation review Product specication review Product design review Detailed design review Implementation review Integration review Product support and documentation review Product acceptance review Sales/Support periodic review
STT SM PR
Requirementsn
Specicationn
Requirementsn
(SP0 ) using a formal specication language. In the case of VDM the abstract specication takes the form of a model of the intended problem that characterizes what is required; it eschews, as far as possible, issues to do with how the requirements will be implemented. Then, through a series of reication (renement) steps, the specication is transformed into an implementation which satises the specication (SP1 to IMP4 ). The process of reication involves the controlled introduction of detail related to problem space partitioning, abstract algorithm selection, data representation, algorithm decomposition and implementation. Reication is depicted in Figure 1.3. Figure 1.3 depicts reication in a rather simplistic manner. Firstly, during this process, many considerations have to be analyzed and specication decisions made. Rework is not uncommon and thus the normal iterative and backtracking activities associated with investigating any design are encountered. Secondly, at each step in the development, decisions are taken relating to strategic design objectives. For instance, algorithm or data representation decisions may be made to achieve a minimum store or fastest execution objective. Renement choices are made de-
Specication (SP0 ) P r o o f O b l i g a t i o n s
Reication (SP1 )
Reication (SP2 )
Reication (SP3 )
pending on whether a prototype implementation or nal product implementation is required. These questions, or similar, will appear at each development step. Secondly, as indicated in Figure 1.4, a development step may result in a single reication or a decomposition into several components which, when composed, composes satisfy their specication. In this case the composition operator specications SP21 and SP22 while the operator composes specications SP31 and SP32 . Here we would need to show that SP31 SP32 satises SP21 and that SP21 SP22 satises SP1 . Various composition operators are possible and depend on the particular formal language being used. Conceptually, reication and decomposition allow us to develop detailed implementation level specications from our abstract specications. However, life is not quite so straightforward. While there is considerable agreement on how to specify sequential systems research activity is being expended on nding out how best to specify parallelism. In addition, there is no clear view on how best to specify and decompose problems involving both parallel and sequential components. Should we start with a specication that views parallelism as the natural order and
SP0
SP0
SP1
SP1
SP2
SP21
SP22
SP3
SP31
SP32
SP33
IMP4
IMP41
IMP42
IMP43
introduce sequentiality within the reication and decomposition process or vice versa? These remain interesting research questions to which answers are eagerly awaited. 3. Verication technique. In order to ensure that a series of reication steps preserves correctness, i.e. fulls the top level specication, there is an obligation to prove that each reication correctly models the previous specication. This is termed a proof obligation. Further, it shows that the implementation satises the specication, that is, IMP4 satises SP3 which in turn satises SP2 , which satises SP1 and that, nally, SP1 satises SP0 . In VDM this involves the gen2 eration of what are called adequacy and operation modelling proof obligations.
debate has focused on what is meant by the terms renement and reication. Various applications need different formulations of what is called the renement proof obligation. Chapter 8 of Jones [Jon90] advocates a specic relationship which is a special case of the more general relations
2 Considerable
2. The notion of abstraction is essential to the application of a formal method. The rst step is to produce an abstract specication characterizing the essential properties of the problem and stating what is required rather than how it is to be achieved. In VDM implicit specication is the main vehicle for abstraction. 3. The reication process advocates progressive development towards implementation with design and implementation specic details being introduced systematically and progressively. 4. Proof obligations provide the substance for verication and validation activities. Discharged rigorously, or formally, they focus attention on critical questions concerning the consistency and correctness of specication and reication steps. 5. Decomposition encourages breaking larger specications into components which can be reied independently and then, through composition combinators, shown to satisfy the larger specication. 6. Guidelines are provided for assessing specications the complexity of data type invariants and proof obligations, the idea of implementation bias [Jon90]. From this discussion it is clear that formal methods have little to say about review procedures, management practices, costing, performance modelling, sizing, reliability modelling, testing 3 and the host of other activities undertaken within the development process. But then most other development methods do not address all of these topics. Procedures, methods and tools appropriate to these activities must be sought elsewhere. In fact, as suggested below, formal methods can quite easily be added to development methods that lack a formal specication language and formal development framework. The method side of formal methods may be viewed as the use of formal systems, the use of abstraction and reication and the generation and discharging of specic proof obligations. In these terms we have a method, not an all-embracing development method, but nonetheless a method. Formal methods do not proscribe the use of ideas and heuristics drawn from other methods. In fact, formal methods complement existing development approaches such as SSADM by allowing practitioners to formally capture specication and development detail that is only informally captured in these other methods. Returning to the discussion of the process and contractual models; formal methods provide a framework for recording our specication and designs. The concept of reication provides a formal framework for the phase development steps outlined in the model. Proof obligations formalize the substance of the verication and validation activities and thus underpin reviews. In these terms the formal framework of software development
3 See [Hay85] for an interesting discussion on how formal specications can assist in the generation of test cases.
10
may be viewed as an abstract representation of some of the tasks undertaken within the software development process model.
2 NDB: The Formal Specication and Rigorous Design of a Single-user Database System
Ann Walshe
This specication of a general-purpose database system provides a good illustration of the usefulness of model-oriented specication techniques for systems. The chosen system (NDB) also has intrinsic interest. This chapter explains the derivation of the appropriate state; after this is found, writing preand post-conditions for the operations is relatively straightforward. The starting point for this specication exercise was an informal description which made heavy use of pictures. It was also couched too much in terms of the implementation to be abstract enough for a concise formal specication. As well as the specication itself, this chapter provides a good example of the development method (particularly data reication).
11
12
2 NDB
2.1 Introduction
This chapter illustrates the use of VDM [Jon80, Jon90] in the formal specication and development of a program to implement simple update operations on a binary relational database called NDB [WS79]. It is shown how an initial specication can be formed and then manipulated in a rigorous way through the careful introduction of design detail in the form of data structures and operations until an implementation is reached. The work is described more fully in [Wel82]. The paper has the following structure. Firstly the rigorous method is briey reviewed. Then NDB, the database to be implemented, is explained before the specication, development and implementation steps are presented.
13
The program development described here uses data reication; four separate states are dened in moving from the most abstract specication to the implementation. Operation decomposition is not used.
14
2 NDB
Currency pound yuan dollar Country Scotland Scotland China China Australia
Price per meter 4.50 6.00 8.00 9.50 Material tweed wool satin silk wool
Export no. E1 E2 E3 E4 E5
Export no. E1 E2 E3 E4 E5
identier value
identier of connections
15
Figure 2.4 A one-many connection called an R-list. Figure 2.5 represents the relations Scotland has currency pound and Scotland exports tweed and wool. Many-one and many-many relations can also be represented by using this structure; Figure 2.6 represents a many-many relation.
16
2 NDB
pound
wool
exports Australia
wool
17
Relationship types have attributes fromset, name, toset and maptype dened as follows: fromset This is the type of objects which the relationship may be from. name This is the name of the relation. toset This is the type of object which the relation may be to. maptype This indicates whether the relation may be single- or multi-valued. These are system-dened relationship types and require system-dened entity sets, such as the set to which every status belongs. So, although the end user of the database system may see none of the metadata structure, the application programmer will see a set of all sets, containing the systemdened sets, and a set of all relationship types, containing system-dened relations, all accessed via system-given names and enabling him to create further sets and relations.
18
2 NDB
-exports
Figure 2.7 An inverse connection 4. The relation from a V-element to a list of V-elements will be known to be a relation from a particular type of object to another particular type of object. Therefore, all V-elements in a C-list are assumed to be of the same entity type, namely the target object type of the relation in which the C-list is involved.
19
To add an entity set, a new V-element must be created, and the parameters of the operation are the set name, its status, picture and width. Recall their denition in Section 2.3. To delete a connection, the parameters given need to identify the connection to be deleted. At each stage of development a preliminary check needs to be made to ensure that the operations can be dened on the proposed state, but they are not fully specied at that stage until the nal state has been formed. Some proofs are given as examples of the method; in reality all the required proofs should be sketched in enough detail to show that they could be constructed formally if necessary. Section 2.10 contains a table of abbreviations used in the specication. Additionally it should be noted that not all the auxiliary functions used within the specications are dened here, as their meaning should be clear enough for the purposes of this paper.
20
2 NDB
Entity set country currency material price per meter amount in meters export number
Members (identier / value pairs) (1, Scotland), (2, China), (3, Australia) (4, pound), (5, yuan), (6, dollar) (7, tweed), (8, wool), (9, satin), (10, silk) (11, 4.50), (12, 6.00), (13, 8.00), (14, 9.50) (15, 200), (16, 300), (17, 400), (18, 700) (19, E1), (20, E2), (21, E3), (22, E4), (23, E5) Connections
Relationship type Fromset Name Toset country currency material cost price per meter export number country export number export number
(1,4), (2,5), (3,6) (7, 11), (8, 12), (10, 13), (9, 14) (19, 1), (20, 1), (21, 2) (22, 2), (23, 3) material (19, 7), (20, 8), (21, 9) (22, 10), (23, 8) amount in meters (19, 17), (20, 16), (21, 15) (22, 18), (23, 15)
Figure 2.8 Example of a database State-a1 :: esets : Esetnm rels : Reltype Esetinf :: membs : Eid Reltype :: fs : Esetnm nm : Relnm ts : Esetnm Relinf :: conns : Pair-set Pair :: fv : Eid tv : Eid
m m m m m
Esetinf Relinf
Value
Value Value
The structure of Esetnm, Relnm, Eid and Value are irrelevant to the specication and so they are not dened further. If required, a structure could be given to them later in the development. The NDB NULL value is represented in the abstract state by nil. Note, the chosen mapping structure ensures that no two entity sets have the same
21
name and no two relationship types have the same fromset, name and toset, fullling two of the conditions to be observed when implementing NDB (i.e. entity sets are distinguishable and relationship types are distinguishable). Note also that since entity identiers are unique, entity-identier value pairs are represented as mappings from entity identiers to values, although in the fv or tv component of a pair the mapping will contain only a single maplet. However, in the relation information, a mapping from an entity identier to a value can be replaced by the entity identier only, since the value can be retrieved by looking in the relevant entity set information. The abstract state becomes: State-a2 :: esets : Esetnm rels : Reltype Esetinf :: membs : Eid Reltype :: fs : Esetnm nm : Relnm ts : Esetnm Relinf :: conns : Pair-set Pair :: fv : Eid tv : Eid State-a2 already represents the fact that all relationship types have a fromset, name and toset. The special attribute maptype can be expressed by adding an extra component to the relation information a maptype. Similarly, the special attributes of entity sets, namely status, picture and width, can be added to the information associated with each entity set. The special attributes are system-dened relationship types and require system-dened entity sets, such as the set to which every status belongs. The state now becomes: State-a3 :: esets : Esetnm rels : Reltype Esetinf :: status picture width membs : : : :
m m m m m
Esetinf Relinf
Value
Esetinf Relinf
22 Reltype :: fs : Esetnm nm : Relnm ts : Esetnm Relinf :: map : Maptype conns : Pair-set Maptype 1: 1 1: M M: 1 M: M
2 NDB
Pair :: fv : Eid tv : Eid Since entities can belong to more than one set, information may be duplicated, i.e. the value associated with an Eid is given in every set in which the Eid appears. If the m Value is extracted, this information will appear only once; thus mapping Eid inconsistencies will not arise or need to be disallowed by an invariant. The nal version of the abstract state becomes: Esetinf State-a :: esets : Esetnm m rels : Reltype Relinf m ents : Eid Value Esetinf :: status picture width membs : : : : Status Picture Width Eid-set
m
Reltype :: fs : Esetnm nm : Relnm ts : Esetnm Relinf :: map : Maptype conns : Pair-set Maptype 1: 1 1: M M: 1 M: M
Pair :: fv : Eid tv : Eid Status Picture Width Eid Esetnm Relnm Value
NOT YET DEFINED
23
esetnms
inv-pairs : Esetnm Esetinf Reltype Relinf inv-pairs esm rm reltype dom rm let mk-Reltype fs nm ts reltype in let prset conns rm reltype in are-membs froms prset esm fs are-membs tos prset esm ts
24 The function inv-pairs uses the following auxiliary functions: are-membs : Eid-set Esetinf are-membs eset esetinf eset froms : Pair-set froms prset tos : Pair-set tos prset Eid-set fv pr pr Eid-set tv pr pr membs esetinf
2 NDB
prset
prset
inv-ents : Esetinf -set Eid-set inv-ents esetinfs eids let ents membs esetinf ents eids
esetinf
esetinfs
in
There is also an invariant on the type Relinf , which must be satised by any object of that type created in the specication. This is dened as follows: inv-map : Relinf inv-map mk-Relinf map prset cases map of M: M true pr1 pr2 prset pr1 pr2 fv pr1 fv pr2 M: 1 1: M pr1 pr2 prset pr1 pr2 tv pr1 tv pr2 1: 1 pr1 pr2 prset pr1 pr2 fv pr1 fv pr2 tv pr1 tv pr2 end
m
25
The parameters to the operation are the new entity set name, and the values which are to be its status, picture and width. The pre-condition states that an entity set of that name must not exist already. The post-condition states that the state after the operation has been performed (the nal state) is the state before the operation is performed (the initial state) with the new entity set added to the esets mapping. Note that the specication does not indicate how this changed state is to be obtained. It merely species a relationship between the initial and nal states.
2 NDB
Note that the conns component is a set of triples rather than a mapping, Rid Pair-set
as would be expected. The decision to represent this component in a different way was made because it contains the actual data rather than the metadata of the database.
27
inv-domains : State-r inv-domains sr let statusr dom status sr in let fsr dom fs sr in statusr dom picture sr statusr dom width sr dom membs sr statusr dom nm sr fsr dom ts sr fsr dom map sr fsr inv-rids : Triple-set Rid-set inv-rids conns nms t conns rnm t nms inv-rels : Rid Esetnm Rid Relnm Rid inv-rels fs nm ts rid1 rid2 dom fs rid1 rid2 fs rid1 fs rid2 nm rid1 nm rid2 ts rid1 ts rid2
m m m
Esetnm
A problem may arise in evaluating invr State-r in that the rst term, inva retra sr may be undened if any of the subsequent terms is false, as a valid State-a cannot be retrieved from an invalid State-r. This situation is cleanly catered for within LPF (Logic for Partial Functions) see Section 3.3 of [Jon90] where the conjunction of an undened value and false is dened to be false.
28
2 NDB
designated by the rnm component of the triple. Rids are discarded, as this means of binding relationship type attributes is not required in the abstract state. The denition of retra is: retra : State-r State-a retra sr let esets esetnm esetinfo esetnm sr esetnm dom status sr reltype rid sr relinfo rid sr rid dom fs sr in let rels let ents valof sr in mk-State-a esets rels ents esetinfo : Esetnm State-r Esetinf esetinfo esetnm sr let a status status sr esetnm in let a picture picture sr esetnm in let a width width sr esetnm in let a membs membs sr esetnm in mk-Esetinf a status a picture a width a membs reltype : Rid State-r Reltype reltype rid sr let a fs fs sr rid in let a nm nm sr rid in let a ts ts sr rid in mk-Reltype a fs a nm a ts relinfo : Rid State-r Relinf relinfo rid sr let a map map sr rid in mk-Pair fv t tv t let a conns mk-Relinf a map a conns
in
conns sr
rnm t
rid
in
Now, using this retrieve function, the following adequacy proof obligation must be discharged: a State-a r State-r retra r a
29
from r State-r eset Esetnm s Status p Picture w Width 1 from eset dom esets retra r 1.1 dom esets retra r dom status r infer eset dom status r 2 ! eset dom esets retra r eset dom status r 3 eset dom esets retra r pre-ADDR eset s p w r infer pre-ADDA eset s p w retra r Figure 2.9 A proof of the domain rule for the ADDR operation
The parameters are the entity set name, the status, picture and width as before. The pre-condition again states that an entity set of the given name must not exist already; this time the check is made by looking in the status mapping although the picture, width or membs mapping could equally well have been used. The post-condition states that the entity set name has been added to the domains of the rst four mappings of the state and mapped to the appropriate values. In order that ADDR models ADDA, two conditions must be satised. They are as follows: 1. Domain Rule. If a set of parameters satises the pre-condition of ADDA (the abstract specication of the ADD operation) then it must satisfy the pre-condition of the reied specication of the ADD operation, ADDR. This proof amounts to showing that the pre-condition of the ADDR operation is not too restrictive. The
30 domain rule proof obligation is formalized as follows: r State-r pre-ADDA retr r pre-ADDR r
2 NDB
2. Result Rule. Here we are concerned with showing that initial/nal state pairs that satisfy the post-condition of ADDR must also satisfy the post-condition of ADDA when they are viewed through the retrieve function. The proof obligation is stated as follows: r r State-r pre-ADDA retr r post-ADDR r r post-ADDA retr r
retr r
The antecedent of the implication has two conjuncts. The rst states that we are only concerned with pre-conditions that satisfy the post-condition of the abstract state (that is, the reied operation may have a wider pre-condition) and the second conjunct restricts consideration to those states that satisfy the post-condition of the reied operation. Generally, it is not necessary to fully construct a formal proof that these rules are satised. The nature of the retrieve function, which directly relates states and state changes on different levels, usually eliminates the need. However, it is important to establish that formal proofs can be constructed if required. Figure 2.9 shows a proof of the domain rule and Figure 2.10 a proof of the range rule. The operation to delete a connection is dened on State-r as follows: DELCONNR eid1: Eid rid: Rid eid2: Eid ext wr conns : Triple-set conns pre mk-Triple eid1 rid eid2 mk-Triple eid1 rid eid2 post conns conns The parameters are the identiers of the two connected entities (eid1 and eid2) and the identier of the relationship connecting them (rid). The pre-condition states that the connection must exist for it to be deleted. The post-condition shows that the triple representing the given connection has been removed from the conns component of the state. Note that this operation was not dened on State-a. This is because the concept of a Rid was not introduced into the specication until State-r. An equivalent operation could have been dened, but with different parameters, namely a Reltype rather than a Rid to dene the connection to be deleted.
31
from r r State-r eset Esetnm s Status p Picture w Width 1 from pre-ADDA eset s p w retra r post-ADDR eset s p w r r 1.1 eset dom esets retra r -E(h1),pre-ADDA 1.2 status r status r eset s -E(h1),post-ADDR picture r picture r eset p width r width r eset w membs r membs r eset 1.3 eset dom status r retra,1.1,1.2 1.4 dom status r dom status r eset -E(1.2) 1.5 esets retra r esetnm mk-Esetinf status r esetnm picture r esetnm width r esetnm membs r esetnm esetnm dom status r retra 1.6 status r eset s picture r eset p width r eset w membs r eset -E(1.2) 1.7 esets retra r esetnm mk-Esetinf status r esetnm picture r esetnm width r esetnm membs r esetnm esetnm dom status r eset mk-Esetinf status r eset picture r eset width r eset membs r eset 1.4,1.5,1.6 1.8 esets retra r esets retra r eset mk-Esetinf s p w retra,1.7 infer post-ADDA eset s p w retra r retra r 2 ! pre-ADDA eset s p w retra r post-ADDR eset s p w r r h infer pre-ADDA eset s p w retra r post-ADDR eset s p w r r -I(1,2) post-ADDA eset s p w retra r retra r Figure 2.10 A proof of the range rule for the ADDR operation
32
2 NDB
Relationship type Fromset Name Toset country currency This is represented in State-r by:
mk-State-r country s1 currency s2 country p1 currency p2 country w1 currency w2 country 1 2 3 currency 456 r1 country r1 nil r1 currency r1 M: 1 1 Scotland 2 China 3 Australia 4 pound 5 yuan 6 mk-Triple 1 r1 4 mk-Triple 2 r1 5 mk-Triple 3 r1 6
dollar
where arbitrary identiers have been introduced. To see how this is represented in State-i, consider rst the conns component. In State-r it is dened as a set of triples of the form: Triple :: fv : Eid rnm : Rid tv : Eid From this set, a map can be formed as follows. Each entity identier, eid1, which is the rst component of a triple in the set is mapped to a list of all pairs rid eid2 for which the triple eid1 rid eid2 is in the set, thus: 1 r1 4 2 r1 5 3 r1 6
33
Each sequence in the range of this map can also be transformed into a map as follows. For each sequence, each relation identier, rid, which is the rst component of a pair in the sequence is mapped to a list of all the elements eid2 for which the pair rid eid2 is in the sequence, thus: 1 r1 4 2 r1 5 3 r1 6
Now, the values of the entity identiers in the domain of this map can be incorporated into the range of the map by introducing a composite object as follows: 1 2 3 mk-Vel r1 mk-Vel r1 mk-Vel r1 4 5 6 Scotland China Australia
The reason for calling this object a Vel will become apparent below. State-i contains a map of this form and is written: State-i1 :: vm : Eid
m m
Vel
Eid Vel :: rl : Rid val : Value Note that Eids occurring in the domain of valof State-r may not appear as the rst component of a triple in conns State-r . In such cases, the Eid must map to a Vel which has as its rl component an empty mapping. Since they can be restated in triple form, all the other components of State-r can be incorporated into the above State-i structure. The triples will be formed by the following transformation: 1. Let the component in State-r be C and have the following form: A
m
B.
2. For every element a in A, the domain of C, create for each element b to which it maps, a triple (a m b) where m is a special relationship type identier (metarid) for component C as given in Figure 2.11. So in the above example, since the metarid for STATUS State-r is DBSTATUS, triples of the form (Esetnm, Status) will result, thus, (country, DBSTATUS, s1),(currency,DBSTATUS,s2) This is not sufcient, since State-i requires identier triples and the triples formed here contain a mixture of identiers and values. The values must be replaced by identiers. When the corresponding map is formed, for each value, a new identier is created and mapped to a Vel. This Vel has the value as its val component and the relationships in which the value is involved as its rl component. For example, the resulting map for the status component is:
34
2 NDB
Special identier in State-i DBSTATUS DBPICTURE DBWIDTH SMEMBS DBFSET DBREL DBTSET DBMAP
Figure 2.11 NDB special relationship type identiers countryid mk-Vel DBSTATUS s1id mk-Vel s1 currencyid mk-Vel DBSTATUS s2id mk-Vel s2 s1id s2id country currency
Thus all components of State-r can be tted into the State-i structure. vm State-i will consist not only of mappings from Eids but from other identiers too, including Rids. All these identiers (ids) are given the collective name Vid (Vel identier). State-i becomes: State-i :: vm : Vid
m m
Vel
Vel :: rl : Vid Vid val : Value Now some way of indicating which Vids are relationship type ids, entity ids, status ids, etc. is needed. This is done by linking each Vid to a Vel which describes its type, i.e. which names the set of which the Vel to which Vid maps is a member, by means of another metarid, the is-member relationship. Another level of special ids (metasets) identifying the sets is created. These identiers are tabulated in Figure 2.12. All the metasets in Figure 2.12 except DBSUSE and DBRUSE are entity set identiers (Esetids) so these in turn are mapped via the is-member relationship to DBSUSE. All the metarids in Figure 2.11 are relationship type identiers (Rids) so they are mapped to DBRUSE. Therefore, the whole database is linked and can be accessed from DBSUSE and DBRUSE. The metasets and metarids must also have the attributes that ordinary entity sets and relationship types have, namely status etc. These metadata are introduced into the invariant. This is done by including statements that the special identiers exist, with their own attributes.
35
Type of element in State-r Status Picture Width Relnm Maptype Esetnm Rid
Id of set to which it belongs in State-i DBSTATUSSET DBPICTURESET DBWIDTHSET RELATIONS DBRELMAP DBSUSE DBRUSE
Figure 2.12 NDB special entity set identiers The invariant on State-i Having described the structure of State-i we can now formally write down the invariant. inv-i : State-i inv-i si invr retrr si let vm vm si in is-submap initmap vm vid dom vm vid DBSUSE vid DBRUSE vid getesetids vm vid getreltypeids vm vid geteids vm esetid getesids vm inv-entset vm esetid reltypeid getreltypeids vm inv-reltype vm reltypeid inv-conns vm inv-order vm inv-esetnames vm The following auxiliary functions are used: getesetids : Vid Vel Esetid-set getesetids vm let vel vm DBSUSE in rng rl vel SSMEMBS getreltypeids : Vid Vel Rid-set getreltypeids vm let vel vm DBRUSE in rng rl vel RMEMBS
m m
2 NDB
Vel Eid-set members esetid vm
m
esetid
getesetids vm
members : Esetid Vid Vel members esetid vm let rel rl vm esetid in if SMEMBS dom rel then rng rel SMEMBS else
Eid-set
ID RELATIONS DBSTATUSSET DBPICTURESET DBWIDTHSET DBRELMAP ID DBTSET DBFSET DBREL DBMAP DBSTATUS DBPICTURE DBWIDTH SSMEMBS RMEMBS SMEMBS
DBWIDTH ... ... ... ... ... DBMAP M:1 M:1 M:1 M:1 M:1 M:1 M:1 1:M 1:M M:M
DBFSET DBRUSE DBRUSE DBRUSE DBRUSE DBSUSE DBSUSE DBSUSE DBSUSE DBRUSE DBSUSE
DBTSET DBSUSE DBSUSE RELATION DBRELMAP DBSTATUSSET DBPICTURESET DBWIDTHSET DBSUSE DBRUSE DBSUSE
DBREL TO FROM NAME MAP STATUS PICTURE WIDTH MEMBS MEMBS MEMBS
Figure 2.13 Metamappings Apart from the prerequisite that a State-r retrieved from a State-i must satisfy the
37
1. The mapping of system-dened entity sets and relationship types to their respective attributes must be part of any database. This is expressed in invi State-i by is-submap. 2. The map dened by the table describing initmap must be a submap of any valid State-i, i.e. all relations in the table must appear in State-i. The rst part of initmap says that the mapping DBSUSE mk-Vel SSMEMBS metaid-list nil
where metaid-list is a list of the metasets, and the mapping DBRUSE mk-Vel RMEMBS metarid-list nil
where metarid-list is a list of all the metarids, must appear in State-i. The second part of the table gives the status, picture and width of each metaset. So State-i must include a mapping RELATIONS mk-Vel DBSTATUS sid DBPICTURE pid DBWIDTH
wid
nil
where sid (pid, wid) maps to a Vel which has as its value the status (picture, width) of the entity set mapped to by the identier RELATIONS. The omitted values in the table (indicated by ellipses) are implementation-dependent and therefore cannot be specied here; the table merely indicates that such values must exist. The third part of the table gives the fromset, toset, relation name and mapping attribute of each metarelation. The fromset and the toset are the identiers of the relevant entity sets; the relation name and the mapping are values of entities in the sets identied by RELATIONS and DBRELMAP respectively. So the mapping DBTSET mk-Vel DBFSET DBRUSE DBTSET DBSUSE DBREL nameid DBMAP mapid nil where the value component of the V-elements identied by nameid and mapid are to and M:1 respectively, must be part of State-i. 3. The database must be connected, so that every V-element can be accessed from DBRUSE or DBSUSE via the metadata. This is ensured by the membership
38
2 NDB
relations all relationship types belong to DBRUSE, all entity sets belong to DBSUSE and every entity belongs to at least one entity set. Every V-element except DBRUSE and DBSUSE denotes either an entity set or a relationship type or an entity. This coincides with the nal version of State-a, which also reects the notion of three types of object, namely entity set, relationship type and entity. 4. All members of DBSUSE are entity sets and therefore have the attributes status, picture and width (expressed by inv-entset); all members of DBRUSE are relationship types and therefore have the attributes fromset, name, toset and map (expressed by inv-reltype). 5. All connections have an inverse (expressed by inv-conns). For each mapping eid1 mk-Vel rid eid2 v1
representing the triple eid1 rid eid2 , the mapping eid2 mk-Vel rid eid1 v2
where v1 and v2 are the values of eid1 and eid2 respectively, must be included in State-i. This allows efcient access of relations in both directions. The inverse of a connection has in the rst component of the R-element the rst component of the R-element of the forward connection preceded by a minus sign. 6. C-lists are ordered by the values of the V-elements to which they point (expressed by inv-order), hence the use of a Vid-list rather than a Vid-set. 7. Entity set names are unique (expressed by inv-esetnames). This is an implementation decision, as entity set V-elements are distinguished by their values rather than by their identiers. This condition is included, because normally, two V-elements can have the same value, e.g. two people can have the same name.
The retrieve function, retrr In retrieving State-r from State-i, only forward connections are retained. For every entity set which is not a metaset, an entry is made in status State-r , picture State-r , width State-r and membs State-r (if a set has no smembs relationship then it maps to the empty set in membs State-r ), and similarly for every relationship type which is not a metarelation its attributes are placed in the appropriate elds of State-r. Finally, the triples which comprise the actual data connections are retrieved and placed in conns State-r .
39
A number of auxiliary functions are used within retrr. Several of these are specied below and in Section 2.7. The specication of the remainder is left as an exercise for the reader. All are specied in [Wel82]. Vel Esetnm fromset : Vel Vid fromset vel vm let esetid fsetid vel in val vm esetid pre -SSMEMBS DBSTATUS DBPICTURE DBWIDTH fsetid : Vel Esetid fsetid vel let esetid rl vel DBFSET in esetid pre -RMEMBS DBFSET DBTSET DBREL DBMAP
m
dom rl vel
dom rl vel
40 The operations on State-i The operation to add an entity set is dened as follows: ADDI eset: Esetnm s: Status p: Picture w: Width esetid: Esetid m ext wr vm : Vid Vel pre vid getesetids vm val vm vid eset post esetid dom vm dom vm esetid dom vm esetid getesetids vm val vm esetid eset let vel vm esetid in picture vel vm p status vel vm width vel vm w members vel vm
2 NDB
The parameters have changed slightly in that a result parameter giving the identier of the new V-element created is returned. There was no concept of an entity set identier in the previous two states. The operation to delete a connection is dened as: DELCONNI eid1: Eid rid: Rid eid2: Eid m ext wr vm : Vid Vel geteids vm pre eid1 eid2 let vel vm eid1 in rid dom rl vel eid2 post let vel1 vm eid1 in let rl1 rl vel1 in elems rl1 rid elems rl1 rid let vel2 vm eid2 in let rl2 elems rl2 minus rid eid2 rl vel2 in eid1
Note the informal use of all other things remain the same. If complete formality were required, this should be expanded. Again, although not presented here, proofs should be constructed that ADDI and DELCONNI respectively model ADDR and DELCONNR.
41
Edinburgh
in Figure 2.14 is sufcient to represent the connection between Scotland and its (only) capital Edinburgh. So the second component of an R-list is either a C-list identier or a V-element identier. Each V-element has the structure: Velp :: rl : Vid val : Value
m
Cnlid Vid
Note that Cnlid Vid allows a nil value as the second R-element component; this occurs when deleting connections it effectively indicates that there is no connection. There must also be some mapping from connection list identiers to connection lists. Connection lists are stored in blocks with pointers between blocks, i.e. a connection list is a list of Vids followed by a next pointer to a continuation connection list. The resulting state which expresses this is: State-p :: vm : Vid cm : Cnlid Velp :: rl : Vid val : Value Cnl :: cl : Vid np : Cnlid The invariant on State-p The new conditions on State-p are: 1. R-lists and the cl component of Cnls have a xed maximum length. 2. If a relationship type is many-one or one-one then a Vid, otherwise a Cnlid, must appear in rl rid , where rl is the rl component of a V-element and contains rid in its domain, and all Cnlids are in dom cm(State-p).
m m m
Velp Cnl
Cnlid Vid
2 NDB
inv-length sp
inv-optconn sp
inv-clists sp
The retrieve function, retri State-p is similar to State-i, so State-i can be easily retrieved. The retrieve function shows that State-p models State-i. retri : State-p State-i retri mk-State-p vm cm mk-State-i vid newvel vm vid cm
vid
dom vm
To retrieve State-i from State-p, take vm State-p and for each V-element replace the identiers in the range of rl by the lists to which they point. A V-element identier, vid, is replaced by the list [vid]; a C-list identier cnlid is replaced by the list in the Cnl to which it maps in cm (concatenated to the continuation list(s) if the np component of the Cnl is not nil). Note that State-i and State-p are so similar that they could have been merged into a single renement step. However, State-i resembles NDB more closely than would a state which included the design decisions of State-p. Also, one level only would require too great a jump from State-r. For these reasons, two separate states are maintained. The operations on State-p The two operations are dened as follows: ADDP eset: Esetnm s: Status p: Picture w: Width esetid: Esetid m ext wr vm : Vid Velp m rd cm : Cnlid Cnl eset pre vid getesetidsp vm cm val vm vid post esetid dom vm dom vm esetid dom vm esetid getesetidsp vm cm let velp vm esetid in val velp eset statusp velp vm s picturep velp vm p widthp velp vm w membersp esetid vm cm
43
44
2 NDB
NP nil nil
45
46
2 NDB
This chapter discusses the specication of a special-purpose database system. The material therefore complements Chapter 2. The system described is an early version of ISTs integrated project support environment known as ISTAR. A link is established in this chapter between the task of requirements analysis and the design of the state of a VDM state. The specication goes further into VDM notation by using both the module and exception specication notations.
47
48
3.1 Introduction
This chapter presents the design specication of the original ISTAR database management system [Ste86]. Current versions of ISTAR no longer use the binary relationship model described here, rather, a full entity relationship model is now supported. Section 3.2 describes the informal design requirements that were produced prior to the development of the database system. These requirements have been extracted from the original technical design documents [IST85]. Section 3.3 presents an analysis of the requirements using entity relationship modelling and the various database operations are also identied. From this an outline specication structure is derived in Section 3.4 and presented in Sections 3.5, 3.6 and 3.7. The problem analysis is rudimentary to the extent that none of the customer/analyst interactions are represented and many of the important steps that would be undertaken when performing the rst stages of a data analysis are only hinted at. Nonetheless the material presented here should provide a good indication of how formal specication techniques and traditional data analysis methods blend well together.
49
This single fact can be entered into the database using either of these two forms and can subsequently be returned in either form. The content of a database consists of a collection of dened verb/verb inverse pairs and a collection of triples of the form described above. For example, the following shows a possible database state in the sense that the indicated verb/verb inverse pair has been entered along with the specic relationships: Verb and verb inverses Studies Is Studied by Relationships entered [ Jennifer , Studies , Computer Science ] [ Jennifer , Studies , Mathematics ] [ Ben , Studies , Mathematics ] [ Mathematics , Is Studied by , Ruth ] [ Louise , Studies , Physics ]
Query of a database
The database is queried by retrieving all those triples in the database that match a given template. A template has three elds corresponding to the subject verb object structure of a triple but, as we will see, can also contain some special matching symbols. In the following discussion we will assume a database set up as shown above. Three forms of query may be identied as follows. Checking if a specic triple is in the database. A template of the form [ Jennifer , Studies , Computer Science ] would match a triple in our database and thus the query would return true. A template of the form [ Mathematics, Is Studied by, Jennifer ] would likewise return true because, for any triple entered into the database, the inverse relation is also considered to be present. The following query, not being in our database, would return false: [ Jennifer , Studies , Physics ]
50
The match anything symbol. The wild card symbol ? can be used in a template to indicate that any eld may be considered as a match for this entry. Thus, in our example database, the query template: [ Jennifer , Studies , ? ] would yield: [ Jennifer , Studies , Computer Science ] [ Jennifer , Studies , Mathematics ] The template: [ ? , Studies Mathematics ] would yield: [ Jennifer , Studies , Mathematics ] [ Ben , Studies , Mathematics ] [ Ruth , Studies , Mathematics ] The template: [Physics, ?, ?] would retrieve the triple: [Physics, Is Studied by, Louise] The template: [ ? , ? , ? ] would yield the entire database, thus: [ Jennifer , Studies , Computer Science ] [ Jennifer , Studies , Mathematics ] [ Ben , Studies , Mathematics ] [ Ruth , Studies , Mathematics ] [ Louise , Studies , Physics ] [Computer Science, Is Studied by, Jennifer ] [Mathematics, Is Studied by, Jennifer ] [Mathematics, Is Studied by, Ben ] [Mathematics, Is Studied by, Ruth ] [Physics, Is Studied by, Louise ]
51
The dont care symbol. For some queries the value of one or more eld is of no interest; in such cases the * symbol is used as a dont care indicator. The query template: [ *, Studies, ?] would retrieve the following triples: [ *, Studies, Computer Science] [ *, Studies, Mathematics] [ *, Studies, Physics] Note that only one triple of the form: [ *, Studies, Mathematics] is returned even though there are three entries in the database that would be returned by the query: [ ?, Studies, Mathematics]. The query: [ ?, *, *] would yield each subject and object token used in the database (remember that both the forward and inverse relation is held in the database).
then Louise will be related to both Physics and Music through the verb Studies. If a course transfer was being registered then we would have to make a deletion removing the triple relating Louise to Physics and then insert the new relationship.
Database partitions
So far, in discussing the ISTAR database, the impression has been given that we have a single database comprising a collection of triples and a collection of verb/verb-inverse pairs. This is an oversimplication of matters. What we have is zero or more databases, each of which comprises a set of partitions. Each of these partitions is a logically distinct object having a unique identier within the system and with a set of declared verbs and a set of triples. Every database consists of one or more partitions. Thus each partition of a database has all the properties outlined above. A database is a collection of partitions each of which may have verbs declared, triples added to and deleted from it and queries undertaken on its contents. To a considerable degree, then, each partition is a separate logical unit. However, there are logical groupings of partitions, and such a grouping is termed a database. Partitions are important because they can be updated and queried in the manner discussed above. Complete databases are important because of the ideas of a database owner, a database identier and a database session, as discussed below.
53
Access control
Every individual database has an owner. Each partition within a database may have a number of users who are authorized readers and writers. Writers are permitted to both read from and write to the partition while readers may only read from the partition. The owner of the database may write to or read from any partition. At the time that a database is rst created the creator is established as the owner of the database. The owner may subsequently create and delete partitions within the database and may modify the authorized readers and writers of any partition as required. Each partition has its own name which is unique within the context of that database.
Database sessions
Databases are accessed during well-dened sessions, where a session can be a read, a write or an owner session. Operations are provided for session initiation and session termination. The owner of a database may initiate any kind of session. A user who is not the owner may initiate a write session only if that user is authorized to write to some partition of the database, or a read session only if authorized to read from some partition. For an individual database there may be many read sessions active at one time; however, there may only be one owner or writer session active at one time although read sessions may be run concurrently.
Partition access
The partitions of a database may be accessed only during a session on that database. Write access to a partition is permitted only during a writer or owner session, and only if the user is the database owner or an authorized writer of the partition. Read access to a partition is permitted during any session by any user who is authorized to access the partition. Subject to the read/write restrictions mentioned above there are no limits to the number of partition sessions that may be initiated on a particular partition.
54
in Section 3.2. Such queries result in zero or more triples being detected that satisfy the template. The set of triples that satisfy the query is tagged with a unique reference number, or key, which is then returned to the user. Subsequently the user may wish to extract triples from the query set. This is done by using an extraction operation which, given an appropriate reference number, will yield a triple from the set of triples associated with that particular reference number.
55
useful insight in the development of the VDM state model. A thorough discussion of data analysis techniques may be found in [How83]. We start by undertaking a simple entity/relationship analysis of the requirements. An entity is a concept or object which has independent existence, which can be uniquely identied and about which there is a need to record information. A relationship is an association between two or more entities that is signicant within the problem space that is being modelled. The analysis will be undertaken as follows: 1. Identify the important entities arising from the problem description. 2. Identify the list of operations that must be supported. 3. Draw a simple ERA diagram showing how entities are related to one another. 4. For each entity, identify potential attributes and identify any complex relationships that have attributes. If required redraw the ERA diagram. 5. Check that the ERA diagram will support the identied operations.
Entity identication
Based on our reading of the previous section we may identify the following entities. Database User Database Partition Triple Verb Retrieved Triple After some consideration a Database Session and a Partition Session are both considered to be relations that hold between a Database User and a Database, and a Database and a Partition respectively.
Operation list
The next step in our analysis is to examine the various operations that must be supported. These are shown in Figure 3.1.1 Not all of these operations were explicitly included in the informal requirements. What we have done here is go through
1 Abbreviations have been attached to the name of each operation and these will be used in various places within the remaining parts of the chapter. In this case the need for such shortforms arises from page layout problems associated with the use of the longer names.
56
Partition
Verb
Triple
Retrieved Triple
Operation REGISTER USER (RU), DELETE USER (DU) CREATE DB (CDB), DELETE DB (DDB), START SESSION (SS), COMMIT (COM), ANNUL (AN), END SESSION (ES), ANNUL SESSION (ANS) CREATE PARTITION (CP), DELETE PARTITION (DP), RENAME (RE), COPY PARTITION (CPYP), OPEN PARTITION (OPP), CLOSE PARTITION (CLP), GRANT ACCESS (GA) DECLARE VERB (DV), UNDECLARE VERB (UV), VERB INVERSE (VI), TEST VERB (TV) BUILD TRIPLES (BT), COUNT (CT), SHORT COUNT (SCT), DELETE (DLT), INSERT (INS) GET TRIPLE (GT)
Figure 3.1 Operation/entity associations the requirements and extract obvious operations such as INSERT, BUILD TRIPLES, GET TRIPLE, COMMIT, CREATE DB, etc. and introduce others which seem to be useful such as VERB INVERSE, RENAME, COUNT, etc. All these operations will have to be specied and then discussed with the customer.
ERA diagram
We now produce an ERA diagram. An entity relationship diagram shows the relationships that hold between entities. Looking at Figure 3.2, consider the entities Partition and Verb. An instance of the entity set Verb is associated with a single Partition instance; this is shown by the single-headed vector running from Verb to Partition. A Partition instance has, optionally, many Verb instances associated with it. The one many relationship is shown by the double-headed arrow and the optional nature of the relationship is shown by the O on the relationship line nearest to the entity which is optional in the relationship. The solid boxes represent the entities indicated above while the dotted boxes represent two relationships that have attributes in their own right. These
57
two relationships have been introduced to remove the many many relationships that exist between Database User and Database on the one hand and Database and Partition on the other. Howe provides a detailed discussion of this problem [How83]. The relations between the entities should be fairly clear from the discussions in the previous section. Relationships should all be explicitly named; however, for brevity this has not been done.
58
Verb O
Triple O O
Retrieved Triple
Partition O
Partition Session O
Database
Database Session O
Database User
59
Partition. Partitions are associated with an instance of a named database. A partition therefore has a name and a reference to the database instance to which it is associated. In addition, partitions have associated authorized readers and writers. We may be tempted to include authorized readers and writers as attributes of a partition. However, note that authorized readers and writers are optionally associated with a partition, that is, a partition may have no such users or a number of them. For this reason we will include them as derived entities. Lastly, for each partition, there is the possibility that several instances may exist associated with different read and write sessions. For example, a write session on a partion creates a new instance of that partition. When the partition is closed it may be reopened by a subsequent read session. That partition instance will remain until the database is closed or the partition is closed. Each write access partition that is closed may be picked up by a read session and thus several instances may coexist: Partition(p name, db instance key) P instance(p instance key, p name) Readers(user name, p instance key) Writers(user name, p instance key) Verb. A verb is identied by its verbname but is also associated with its inverse. This gives the following structure: Verb(verb name, p instance key, verb name) Triple. A triple comprises a subject and object together with a link to the associated verb that makes up the relationship: Triple(subject, object, p instance key, verb name) Retrieved Triple. A retrieved triple associates a key with one or more triples resulting from a template query. The associated triples are extracted from the entity set triple but they may be changed to the extent that any of the elds may contain the * symbol. We will therefore identify an attribute called r triple to model this situation: Retrieved Triple(key, p instance key, r triple) Two relationships are identied on the ERA diagram which have attributes. These are Database Session and Partition Session. These relationships were put in to resolve the two potential many to many relationships that appear between Database Users and Databases and between Databases and Partitions. These two relationships are modelled as follows.
60
In the light of this analysis we can redraw the entity relation diagram showing the newly identied entities and relationships this is shown in Figure 3.3. In addition we need to reassign operations to entities as shown in Figure 3.4
61
Verb O
Triple O O
Retrieved Triple
Writers O Readers
Partition Instance
Partition O
Partition Session O
Database O
Database Instance
Database Session O
Database User
62
Triple
Retrieved Triple
Operation REGISTER USER (RU), DELETE USER (DU) COMMIT (COM), ANNUL (AN), END SESSION (ES),START SESSION (SS), ANNUL SESSION (AS) CREATE DB (CDB), DELETE DB (DDB), OPEN PARTITION (OPP), CLOSE PARTITION (CLP) CREATE PARTITION (CP), DELETE PARTITION (DP), RENAME (RE), COPY PARTITION (CPYP) GRANT ACCESS (GA) DECLARE VERB (DV), UNDECLARE VERB (UV), VERB INVERSE (VI), TEST VERB (TV) BUILD TRIPLES (BT), COUNT (CT), SHORT COUNT (SCT), DELETE (DLT), INSERT (INS) GET TRIPLE (GT)
Figure 3.4 Revised operation/entity association a list of operations. We now wish to use that analysis as a guide in producing a formal specication of the database problem. Essentially we will examine the set of entities and identify several abstract data types each of which will have a state and associated operations. The states models will be derived from the entity relationship analysis already undertaken and operations will be associated with an appropriate data type. The operations will then be specied using the data type state model. As we will end up with a hierarchy of data types we will have to deal with the problem of migrating the operations associated with basic data types through the specication hierarchy. If we look at Figure 3.3 we see the need to model the entity sets Database User, Database and the relationship Database Session. This latter relationship captures the concept of a database session where a specic instance of a named database is linked to a session key and mode. A database may be associated with many read mode sessions but only one write or owner session. Thus, a particular named database may have several instances associated with different session keys. Remember a write session may result in several COMMIT operations leading to instances of the database which could be picked up by newly initiated read sessions. With this in mind we will produce a specication
63
Entity Database User Database Database Instance Database Session Partition Partition Instance Partition Session
Attribute CDB user nm r can own r db name r,s owner s db instance key s db name s committed s db session key db instance key db mode p name db instance key p instance key p name p session key p instance key p mode Key d r s u DDB r r r,d r,d d d d r r r d d d d
Operations SS COM AN r r r
ES
AS
s s s
d d d d d r u r d d d d d d d
d d d
64
of a data type called Dbms which will capture the User and Database Instance entity sets as well as the Database Session relationship. The second data type that will be modelled will be called Database and will capture the entity set Partition Instance as well as the relationship Partition Session. Lastly, the data type Partition will capture the entity sets Triple, Verb and Retrieved Triple. These entities and their associated relationships will be modelled using the basic VDM data types of sets, functions and cross-products or records. We need to consider operations for a moment. As mentioned above we will introduce three data type specications Partition, Database and Dbms. The operations associated with these three data types follow more or less from Figure 3.4. However, there are some minor differences. The operations CREATE PARTITION, DELETE PARTITION, CREATE DATABASE and DELETE DATABASE all have the effect of creating or destroying an instance of, respectively, type Partition and Database. Instances of type Partition will be held in a Database state and, similarly, instances if type Database will be held in the Dbms state. Thus, CREATE PARTITION will alter a Database state. Considering CREATE PARTITION, we see there are two effects. Firstly an instance of type Partition is generated and secondly the instance is associated with a Database state. Data type instances are dealt with by an initialization operation or assertion on the initial state of the data type for this we will use an INIT operation. The creation and deletion operations will therefore be associated with the data type whose state is changed as a result of generating an instance of a data type object. To this end CREATE PARTITION will be associated with the data type Database and similarly with the remaining operations. The operations RENAME and COPY PARTITION offer similar difculties. RENAME requires that the new name is not associated with any partition in a database. Only the Database data type has access to partition names within it thus this operation must be a Database operation. However, we will require a CHANGE NAME operation on the Partition data type. Similarly, COPY PARTITION requires a new instance of type Partition to be created and once again has name restrictions associated with it. This operation will also be associated with the Database data type. With these observations in mind we now embark on the specication of the Partition, Database and Dbms data types.
65
For each verb entry we record a maplet between the verb and its inverse and the inverse and its verb. data. Here we model triples within a partition as a set of type Triple where a triple is modelled as a cross-product of type (subject, verb, object). retrieved triples. The BUILD TRIPLE operation yields a set of triples that match a given template. For each query the resulting set of triples is indexed by a unique query key. The GET TRIPLE operation will access this state component when extracting the results for a particular query key. readers. Authorized users who may read from the partition. writers. Authorized users who may write to the partition. Something should be said about the attribute p instance key which is clearly not explicitly modelled. The key was used to identify specic partition instances and an ordering was required on that key to determine the latest instance of a partition. Each instance of a Partition will be managed in the Database specication and as will be seen there is no need to include such a key either to distinguish the latest partition instance or to distinguish one partition from another. For this reason the key is not modelled. Briey, some of the type denitions are: Template. A Template has the same form as a triple but allows any of the elds to contain symbols of type Match symbol. D template. A template used by the DELETE operation. The type only allows the ? special symbol and precludes *. R triple. Partition enquiries can result in triples being returned with the special symbol * appearing in some elds. This type allows for results of this form. Get triple result. Used to return information from the GET TRIPLE operation. Query key. The BUILD TRIPLE operation constructs query sets which are indexed by instances if this type. Pr types. A union type which brings together the types of the results produced by partition operations. Match symbol. This type models the special symbols * and ? which are, in turn, represented by members of type Star and Question mark respectively.
: P name Partition :: p name verbs and inverses : Verbmap data : Tripleset m retrieved triples : Query key R triple-set readers : User-set writers : User-set inv mk-Partition nm v-and-i d rt r w tr d let mk-Triple subject verb object tr in d mk-Triple object v and i verb subject verb dom v and i Having dened the state careful consideration should be given to identifying any data type invariants applicable to the state as a whole or to any of the types used within the state denition. The invariant on the state asserts that for any (subject, verb, object) relationship within a partition the inverse verb relationship should also be in the partition. The following invariant might be considered to hold: rng rt d
However, on reection it seems unreasonable that triples can not be deleted from the database if they exist explicitly in a query set. Verbname Verbmap Verbname vn dom vm vn vm vm vn inv vm vn vm vn dom vm rng vm The type Verbmap requires an invariant restricting the map to be well formed with respect to verbs and their inverses, that is, the inverse of each verb is the verb itself and the name of the inverse verb should not be the same as the verb itself. The remaining type denitions are given below. Tripleset Triple-set
m
Triple :: subject : Text verb : Verbname object : Text Template :: subject : Text Match symbol verb : Verbname Match symbol object : Text Match symbol
67
Verbname Star
D template Template inv mk-D template s v o so Text Question mark Match symbol
Question mark is not yet dened Star is not yet dened P access R EAD W RITE
Get triple result :: tr : R-triple more : Yes no Verbname Pr types O K FAILED Text Yes no Get triple result Query key Verbname
Query key P name is not yet dened We now turn to the specication of some auxiliary functions that are used in the specication of other data types. As presented here it appears that these functions are divined before the operations are specied or the other specications are developed. However, it should be clear that these functions were extracted as the specication was 2 developed and are presented here, together, for convenience. triplematch : Template Tripleset Verbmap triplematch tem data v and i res
2 The
R triple-set
denitions given below deliberately employ several different styles, even though this is not really warranted for the present specication, purely for the purposes of illustration.
68 post let mk-Template s v o tem in v dom v and i v Match symbol res v res s dom v and i v Match symbol mk-R triple sr vr or mk-Triple su vb ob Question mark sr su s
data
Question mark vr
vb
Question mark or
ob
o o
The triplematch function takes a template, a set of triples and the verb inverse map and returns the set of all triples that match the template. This formulation of triplematch looks overly complicated and a simplication may be achieved as follows: simple match : Template Tripleset Tripleset let mk-Template s v o tem in simple match tem data mk-Triple su vb ob mk-Triple su vb ob data su s s Match symbol vb v v Match symbol ob o o Match symbol star match : Template Tripleset R triple-set let mk-Template s v o tem in star match tem data mk-R triple su vb ob mk-Triple subject verb object su Star s Star su subject s Star vb Star v Star vb verb v Star ob Star o Star ob object o Star
data
With these two subsidiary functions we can now respecify triplematch as follows: triplematch : Template Tripleset Verbmap triplematch tem data v and i res R triple-set
69
The p name is function is used to return the name of the partition. User P access p authorized : Partition p authorized state "user access access R EAD user readers state access W RITE user writers state Depending on the setting of the access parameter the p authorized function returns true if the indicated user is in the set of authorized readers or writers. P name Partition p change name : Partition p change name state name state p name name
There is a need to change the name of a partition. This function accepts an argument of 3 type Partition and a name and returns the partition state with the name changed. We can now address the specication of the operations identied earlier in Section 3.3. For this specication exception conditions have been stated in the post condition of each operation. No use has been made of the special syntax available for specifying exceptions. This notation will be employed when we consider the specication of the data type Database in Section 3.6. A brief commentry on each operation follows the specication. BT tem: Template result: Query key m ext wr retrieved triples : Query key R triple-set rd data : Tripleset rd verbs and inverses : Verbmap post let queryset triplematch tem data verbs and inverses in result dom retrieved triples retrieved triples retrieved triples
3 The functions p
result
queryset
name is and p authorized have been specied using lambda notation; p change name uses currying. Both of these forms are described in Appendix A.
70
The BUILD TRIPLE operation takes a template and constructs the set of triples that satisfy the query template. The set of retrieved triples is inserted into the retrieved triples map using a unique key, that is one that has not already been allocated, and the key is returned as an output from the operation. CT tem: Template result: ext rd data : Tripleset rd verbs and inverses : Verbmap post result card triplematch tem data verbs and inverses This simple operation takes a template as argument and returns a count of the number or triples within the partition that match the template as discussed in Section 3.2. DV fv: Verbname iv: Verbname result: Yes no ext wr verbs and inverses : Verbmap post fv fv dom verbs and inverses iv iv verbs and inverses OK iv domverbs and inverses domverbs and inverses fv result fv iv iv fv verbs and inverses
Verbs and their inverses must be entered into a partition. The DECLARE VERB operation performs that task. Clearly the forward verb and the inverse verb should not have already been dened and they should not be identical to one another. Given this condition the verb/inverse pair will be entered into verbs and inverses and a satisfactory response returned. If this is not the case then a failed response is returned. DLT tem: D template result: Yes no ext rd verbs and inverses : Verbmap wr data : Tripleset
71
Question mark in
let fs triplematch tem data verbs and inverses in let r tem mk-Template s v o in let is data triplematch r tem data verbs and inverses in data fs is result OK
match all let fs triplematch tem data verbs and inverses in let r tem mk-Template o verbs and inverses v s in let is data others data end triplematch r tem data verbs and inverses in data fs is result FAILED OK data result
How do we remove triples from a partition? The DELETE operation is provided to perform this task. Given a template (not containing the star symbol), all those triples which match the template (forward and inverse relations included) are taken out of the partition. An exception is raised when the verb provided within the template is neither of type Question mark nor a verb within verbs and inverses. GT key: Query key result: Get triple result m ext wr retrieved triples : Query key R triple-set
72 post key dom retrieved triples let triple retrieved triples key in
retrieved triples key let newset retrieved triples key -triple in newset in let more retrieved triples retrieved triples key result mk-Get triple result triple more retrieved triples key retrieved triples key retrieved triples result mk-Get triple result N IL FALSE key dom retrieved triples newset
retrieved triples retrieved triples result mk-Get triple result N IL FALSE Recall the partition query mechanism described in Section 3.2. BUILD TRIPLE is used to create an indexed set of triples satisfying a query template. Extracting elements from this query set is accomplished by the GET TRIPLE operation. Given an argument of type Query key the operation returns a record containing an arbitrary element from the query set and a boolean indicator stating whether there are further triples to be retrieved. A nal call of the operation when the query set is empty causes the query set to be removed entirely. GA u: User access: P access ext wr readers : User-set wr writers : User-set post access R EAD readers access writers readers W RITE writers u readers readers u writers writers
This operation GRANT ACCESS alters the read or write access authority as indicated. INIT nm: P name
73
R triple-set
The initialization of a data type is an important specication consideration. When a data type is instantiated, i.e. when a new instance of the type is rst created, the initialization operation must be employed. The initialization operation establishes the data type invariant on the initial state of the data type. INS tr: Triple result: Yes no ext rd verbs and inverses : Verbmap wr data : Tripleset tr in post let mk-Triple s v o v dom verbs and inverses data data result O K v tr mk-Triple o verbs and inverses v s
We have already seen the DELETE operation that removes triples from a partition. The INSERT operation inserts triples into a partition. A triple is provided as input to the operation. If the verb is valid then the triple and its inverse are placed in data. Note, if the triple is already present in the database then no indication to this effect is given. If the verb is invalid, that is not in verbs and inverses, then a failure is signalled. PCL ext wr retrieved triples : Query key post retrieved triples
m
R triple-set
The PARTITION CLEAR operation produces a partition without any outstanding triple queries. SCT tem: Template result: ext rd verbs and inverses : Verbmap rd data : Tripleset
74
SHORT COUNT returns zero or one if there are zero or one template matches. If there is more than one match then an arbitrary natural number, but not zero or one, is returned. Note that the result type constrains the response to being of type natural number; apart from zero or one the specic value is not determined. TV fv: Verbname iv: Verbname result: ext rd verbs and inverses : Verbmap fv dom verbs and inverses post result verbs and inverses fv iv Given two verbs the TEST VERB operation returns true if the verbs have been declared and are the inverse of one another. UV fv: Verbname iv: Verbname result: Yes no ext wr verbs and inverses : Verbmap rd data : Tripleset post let wf -verb fv dom verbs and inverses verbs and inverses fv let not-in-db trip data verb trip fv verb trip iv in let undeclare wf -verb not-in-db in undeclare verbs and inverses result O K undeclare verbs and inverses verbs and inverses result FAILED The UNDECLARE VERB operation removes a verb and its inverse from the partition. Two conditions must be fullled. Firstly, the verb and verb inverse must be well-formed and, secondly, neither the verb nor its inverse should appear in a triple within the partition. VI v: Verbname result: Verbname Yes no ext rd verbs and inverses : Verbmap post v dom verbs and inverses result v dom verbs and inverses result fv iv verbs and inverses iv in
75
The bulk of the specication for this data type is now complete. However, there are two further issues that require addressing. The rst relates to the use of Partition operations on instances of this type and the second concerns the visibility of names outside of the specication. Recall for a moment how partitions are used. Firstly a user will create a database and then initiate a database session. Subsequently a partition will be created and opened resulting in a partition session. Operations such as INSERT and DECLARE VERB will then be available for use within the context of a particular database and partition session. Clearly, we do not want to explicitly specify analogs of these operations in both the Database and Dbms specications. Rather we seek to provide an abstract syntax description of these operations which can then be used within these other specications appropriately linked to partition and session keys. How do we provide such an abstract syntax? Consider the DECLARE VERB operation. This has two arguments representing the forward and inverse verbs. The operation signature can be described as a record type with two elds, thus: Dv :: forward verb : Verbname inverse verb : Verbname The SCT operation signature may be described as follows: Sct :: template : Template How these abstract syntax representations will be used is described in Section 3.6. Accepting this mode of description we need to add the following denitions to our collection of types: Partition ops Bt Ct Dv Dlt Gt Ga Ins Sct Tv Uv Vi
Abstract syntax representations for all these operations may easily be generated as indicated above. The nal issue remaining is that of name space management. Name visibility is controlled through the use of an interface specication which states what names are to be exported (made visible) outside of the specication and what names are to be imported into the specication i.e. made visible for use within the specication. Import and export clauses are provided within the interface specication to capture this information. Figure 3.6 shows the interface specication for the Partition data type.
76
module Partition exports operations o BT: Template Query key o CT: Template o DV: Verbname Verbname Yes no o DLT: D template Yes no o GT: Query key Get triple result o GA: User P access o INIT: P name o INS: Triple Yes no o PCL: o SCT: Template o TV: Verbname Verbname o UV: Verbname Verbname Yes no o VI: Verbname Verbname Yes no functions p name is: Partition P name p authorized: Partition User P access p change name: Partition P name Partition types Pr types Yes no Get triple result Query key Verbname P access P name Template D template Triple R triple Partition ops Bt Ct Dv Dlt Gt Ga Ins Sct Tv Uv Vi imports from Dbms types User end Figure 3.6 Interface specication for the Partition data type
77
partitions. This state element models the set of created partitions. The names of the created partitions should be unique and the set will always contain the most recently commited partition instance. p sessions. This map models partition sessions. Associated with each partition is a partition key. The range of this map will feature partitions drawn from partitions when the session was initiated by an OPEN PARTITION operation. p modes. Once again, associated with each partition session, is a mode indicator which will be either READ or WRITE. Database :: name : Db name owner : User partitions : Partition-set m Partition p sessions : P key m p modes : P key P mode inv mk-Database n o p ps pm let write sessions k k dom pm pm pk W RITE in i j write sessions i j p name is ps i p name is ps j let part names p name is entry entry p in p name is entry entry rng ps in let session p names session p names part names i j p p name is i p name is j i j dom ps dom pm The data type invariant states that: 1. No partition is associated with more than one WRITE session. 2. The names of partitions associated with sessions are a subset of the names of currently created partitions. 3. The names of created partitions are unique. 4. p sessions and p modes have the same domain set of keys. The remaining type denitions are: P mode R EAD W RITE
Db name P key is not yet dened close partitions : P key-set P key Partition m P key P mode Partition-set Partition-set close partitions pks p ses p mod pre part post part let updated partitions pt pt Partition p pks p mod p W RITE post-PCL p ses p pt let old partitions pt pt pre part p pks p mod p W RITE p name is pt p name is p ses p pre part old partitions updated partitions post part
m
in
in
The function close partition asserts that all write sessions in the paramaterized set of session keys are properly closed and that partitions will be updated to contain these latest instances. User db owner : Database db owner state "user owner state user
This function returns true if the user is the owner of the database. User P mode db authorized : Database db authorized state "user mode let mk-Database - - partitions - state in entry partitions p authorized entry user mode db authorized returns true if the database allows the user access of the indicated mode. Note the use of VDMs dont care entries in the let construct where the record of type Database is constructed. The - entries indicate that we are not interested in these elds and are therefore willing to accept any value constrained only by type and invariant. db name is : Database Db name name state db name is state We now turn to the specication of the operations. As a contrast to the specication of Partition, exceptions will be specied using the notational extensions described in Chapter 9 of [Jon90]. Where exceptions are specied it is assumed that the state is not changed and assertions are made only to specify the result conditions. Additionally, exceptions have been specied to return FAILED in all cases; this is clearly unreasonable but sufces for the purpose of this exercise.
79
CLP pk: P key result: Yes no ext wr partitions : Partition-set m Partition wr p sessions : P key m wr p modes : P key P mode pre pk dom p sessions post close partitions pk p sessions p modes partitions partitions p sessions pk p sessions p modes result O K errs INVALID SESSION: pk dom p sessions pk result p modes FAILED
The requirements for the CLOSE ALL PARTITIONS operation arose during the specication of Dbms. When a database is committed, for instance, it is required that all partitions be properly closed. The second operation is similar but is specic to a single partition. The rst operation is not provided to users of the database system while the second is. CPYP from: P name to: P name result: Yes no ext wr partitions : Partition-set m rd p sessions : P key Partition from pre entry from partitions p name is entry from entry to partitions p name is entry to to entry rng p sessions p name is entry from post entry partitions p name is entry from p change name entry to
80
This operation duplicates a partition and renames it. The operation requires that the from partition exists, that there is no extant session on this partition and that no database exists with the same name as to. CP nm: P name result: Yes no ext wr partitions : Partition-set nm pre p partitions p name is p post p Partition Partition post-INIT nm - p partitions partitions p result O K errs EXISTS: p partitions p name is p nm result FAILED DP nm: P name result: Yes no ext wr partitions : Partition-set m rd p sessions : P key Partition pre entry partitions p name is entry nm entry rng p sessions p name is entry nm post entry partitions p name is entry nm
partitions partitions entry result O K errs NOT EXIST: entry partitions p name is entry nm result FAILED SESSION: entry rng p sessions p name is entry nm result FAILED These two operations create and delete partitions. The specications should be fairly self-evident. Note the need to distinguish that the INIT operation is that operation associated with the type Partition. INIT u: User nm: Db name
81
INIT establishes the data type invariant for initial instances of the data type. OPP u: User nm: P name mode: P mode result: P key Yes no ext rd owner : User rd partitions : Partition-set m Partition wr p sessions : P key m wr p modes : P key P mode pre entry partitions p name is entry nm let authorized reader p authorized entry u R EAD in let authorized writer p authorized entry u W RITE in u owner in let valid owner let no write sessions pk dom p sessions p name is p sessions pk nm p modes pk W RITE in mode W RITE valid owner authorized writer no write sessions mode post entry let key p modes R EAD valid owner authorized reader partitions p name is entry nm p sessions key p modes key entry result OK
authorized writer
p sessions
82
Partition sessions are established by the OPEN PARTITION operation. A session may only be established for a partition if the named partition exists and is owned by the nominated user or the user has access of the appropriate mode. Further, for write sessions, there should be no other write session associated with that partition. RE present name: P name new name: P name result: Yes no ext wr partitions : Partition-set m rd p sessions : P key Partition present name pre entry partitions p name is entry entry rng p sessions p name is entry present name entry partitions p name is entry new name post entry partitions p name is entry present name partitions partitions entry p change name entry new name result OK errs NO DB: entry partitions p name is entry present name result FAILED SESSION: entry rng p sessions p name is entry present name result FAILED NAME EXISTS: entry partitions p name is entry new name result FAILED The RENAME operation renames an existing partition. The partition must not be involved in a session and the new name must be unique. POPS pk: P key op: Partition ops result: Pr types
83
Dlt
op
post let pre-st p sessions pk in post-st Partition cases op of p sessions p sessions pk post-st post-BT t pre-st post-st result mk-Bt t mk-Ct t post-CT t pre-st post-st result mk-Dv fv iv post-DV fv iv pre-st post-st result mk-Dlt dt post-DLT dt pre-st post-st result mk-Gt qk post-GT qk pre-st post-st result mk-Ga u a post-GA u a pre-st post-st result mk-Ins t post-INS t pre-st post-st result mk-Sct t post-SCT t pre-st post-st result mk-Tv fv iv post-TV fv iv pre-st post-st result mk-Uv fv iv post-UV fv iv pre-st post-st result mk-Vi v post-VI v pre-st post-st result end errs INVALID KEY: pk dom p sessions result FAILED NOT WRITE: op Dv op Dlt op Ins op Uv p modes pk W RITE result
FAILED
PARTITION OPERATIONS species how partition operations are to be handled by the Database data type. Remember that partition operations only have meaning in the presence of a database instance. This operation reveals that all partition operations require a partition key which associates the partition operations with a particular partition instance. In addition, some of the operations can only be used within a write session. When we specied Partition, abstract syntax representations for the various user operations were produced and exported through the interface specication. Those abstract syntax representations are used here. PARTITION OPERATIONS accepts an argument of type Partition ops and one of type P key. All operations of type Partition ops are specic to a particular partition and thus require a partition key as argument. In the post condition the individual operations are identied through their abstract syntax representation and each, individually, results in a specic Partition operation being quoted. Quotation is fully described in [Jon90]. Lastly, before dening the interface specication, we need to generate the abstract syntax for the Database operations. The types we require are dened as follows: Database ops Clp Cpyp Cp Dp Opp Re
module Database exports operations o CLAP: o CLP: P key Yes no o CPYP: P name P name Yes no o CP: P name Yes no o DP: P name Yes no o INIT: User Db name o OPP: User P name P-mode P key Yes no o RE: P name P name Yes no o POPS: P key Partition ops Pr types functions db name is: Database Db name db authorized: Database User P mode db owner: Database User types Database ops Clp Cpyp Cp Dp Re Opp Dbr types Db name P mode P key Partition ops Bt Ct Dv Dlv Gt Ga Ins Sct Tv Uv Vi Pr types Yes no Get triple result Query key Verbname R triple P name P access D template Template Triple imports from Partition all imports from Dbms types User end Figure 3.7 Interface specication for the Database data type
85
each user with a boolean value indicating whether he or she is allowed (true) or is not allowed (false) to own a database. This is an important distinction. Only owners of databases may create them or write to them. databases. The set of most recently created and committed databases. db sessions. A map from database session key to an associated database instance. db modes. Each session key is mapped to the session mode (read, write or owner). The state outlined above follows almost directly from the entity/relationship analysis carried out in Section 3.3. : User Dbms :: db users databases : Database-set m db sessions : Sk Database m db modes : Sk Db mode inv mk-Dbms du db dbs dbm let write sessions k k dom dbm dbm k W RITE dbm k OWNER i j write sessions i j db name is dbs i db name is dbs j let db names db name is entry entry db in db name is entry entry rng dbs in let session db names session db names db names i j db db name is i db name is j i j dom dbs dom dbm i db j dom du db owner i j du j
m
in
The data type invariant follows that developed for the data type Database with the addition of the nal condition which states that all databases must have an owner who is a legitimate database owner, that is, no database can be owned by an unregistered user. Associated types are now dened. Db mode R EAD W RITE OWNER
User Sk is not yet dened In the operation specications that follow no exception conditions are specied. Pre conditions record the assumptions made by each of the operations.
86 commit db : Sk Database-set Database-set commit db sk old dbs new dbs db sessions let dbname db name is db sessions sk clean db Database post-CLAP db sessions sk clean-db entry old dbs db name is entry dbname new dbs old dbs entry Sk in
m
clean db
The commit db function commits the database referenced by the session key. All partitions are closed and the database instance noted as the most recently committed by placing it in databases. AN sk: Sk ext rd databases : Database-set m wr db sessions : Sk Database m rd db modes : Sk Db mode pre sk dom db sessions db modes sk W RITE db modes sk post let dbname db name is db sessions sk entry databases db name is entry dbname db sessions db sessions sk
OWNER in
entry
The ANNUL operation causes a database session to be annulled. The session key must be valid and the session must be a write or owner session. Note that the existing session key is unchanged but becomes associated with the most recently committed database. As the database has a current write or owner session associated with it we can safely pick up the last committed version because no other write or owner session will have been allowed. ANS sk: Sk m ext wr db sessions : Sk Database m wr db modes : Sk Db mode pre sk dom db sessions db modes sk W RITE db modes sk post db sessions db modes sk sk db sessions db modes
OWNER
This operation, ANNUL SESSION, annuls a session removing both the session key and the associated database instance.
87
OWNER
post commit db sk databases databases db sessions The COMMIT operation causes the current read or owner session database to be committed. A copy of a tidy version of the database is made and is stored as the most recently committed instance of the database. The session then continues. CDB u: User nm: Db name m ext rd db users : User wr databases : Database-set pre u dom db users db users u entry databases db name is entry post entry Database Database post-INIT u nm - entry
DDB u: User nm: Db name m ext rd db users : User wr databases : Database-set m rd db sessions : Sk Database pre u dom db users db users u entry databases db name is entry nm db owner entry u entry rng db sessions db name is entry nm post entry databases db name is entry databases- entry nm databases
The two operations specied above create and delete databases. In the rst instance no database must exist with the indicated name and in the second case a named instance of the database must exist and no sessions should be associated with an instance of that database. A database may only be created by a user who is authorized to own databases, while a database may only be deleted by its owner. ES sk: Sk
88 ext wr databases : Database-set m wr db sessions : Sk Database m wr db modes : Sk Db mode pre sk dom db sessions post db modes sk W RITE db modes sk
OWNER
commit db sk databases databases db sessions db modes sk db sessions R EAD databases sk databases sk db modes
db sessions db modes
The END SESSION operation terminates a read, write or owner session. In the case of owner or write databases the associated database instance is tidied and made the most recently committed version of that database by replacing the previous version. SS u: User nm: Db name mode: Db mode key: Sk m ext rd db users : user rd databases : Database-set m wr db sessions : Sk Database m wr db modes : Sk Db mode pre entry databases db name is entry nm let authorized reader db authorized entry u R EAD in let authorized writer db authorized entry u W RITE in let valid owner db owner entry u in sk sk dom db sessions let s keys db name is db sessions sk nm in let no write owner session k s keys db modes k W RITE db modes k OWNER in mode OWNER valid owner no write owner session mode W RITE authorized writer
valid owner
mode
authorized writer
valid owner
89
Sessions may be started when the following conditions, asserted in the pre condition, hold: 1. The named database exists. 2. If the session mode indicates an owner session then the database must be owned by the indicated user and there must not be an existing owner or write session on that database. 3. If the session mode is write then the user must be authorized to write to a partition in the database or the user must be the owner and must still be allowed to own a database. Further, no write or owner sessions should be associated with that database. 4. If the session is a read session then the user must be allowed read access to at least one partition in the database or the user must be the owner of the database and still be registered as a database owner. DBOPS sk: Sk pk: P key op: Partition ops Database ops res: Dbr types Pr types m ext rd db users : User m wr db sessions : Sk Database m rd db modes : Sk Db mode pre sk dom db sessions op Cpyp op Cp op Dp op Re op Ga db modes sk OWNER op Partition ops pk N IL op Ga let mk-Ga u op in u dom db users
90
module Dbms exports operations o AN: Sk o ANS: Sk o COM: Sk o CDB: User Db name o DDB: User Db name o ES: Sk o SS: User Db name Db mode Sk DBOPS: Sk P-key Partition ops Database ops
Dbr types Pr types types Sk User Db mode Database ops Clp Cpp Cp Dp Op Re Dbr types Db name P mode P key Partition ops Bt Ct Dv Dlt Gt Ga Ins Sct Tv Uv Vi Pr types Yes no Get triple result Query key Verbname R triple P name P access D template Template Triple imports from Database all end Figure 3.8 Interface specication for the Dbms data type
As has already been seen, the use of formal methods introduces the idea of proof obligations, that is, theorems which record desirable properties of our specications or development steps. How do we go about discharging these proof obligations? What automated support can be provided to help with this task? Richard Moores chapter discusses these issues. Restricting itself to the propositional calculus, the paper rst considers proof style and the various strategies that might be adopted when proving a simple theorem. Having identied how proofs may be performed, the chapter then presents a specication of a proof editor which will support the strategies identied in the earlier discussion. Although only the specication is given here, a development using Smalltalk 80 has been undertaken. Subsequent work by the same group has built a system which handles more general logics.
91
92
4.1 Introduction
The prime objective of the formal reasoning work in the Alvey/SERC supported IPSE 2.5 project [JL88, War89] is to design and build a theorem proving assistant which will provide sufcient support for the task that a user will be encouraged to use it to actually discover formal proofs rather than just to check the details of proofs already sketched out on paper. The general consensus amongst the researchers at Manchester University and Rutherford Appleton Laboratory who are engaged in this part of the project is that two things in particular could go a long way towards helping achieve this aim. First, the system should be sufciently exible to allow the user to work as naturally as possible; specically, it should impose no xed order of working on the user, and it should allow the user access to all of its functionality. Second, it should have sufcient knowledge of the mathematics that it is supporting to allow it both to help the user to decide what to do next by offering a selection of possible actions consistent with the underlying mathematics and to advise on the existence of any inconsistencies. The emphasis is, therefore, on a user-driven, machine-supported theorem prover rather than vice versa. Very early in the project, an investigation of existing theorem proving systems was undertaken [Lin88]. Not one of the systems surveyed satised all our requirements as set out above, and it was therefore decided that some experimentation of our own with user interface issues was required. The resulting system, known as Mufn for reasons which are likely to remain totally obscure here, is the subject of this paper. Mufns emphasis as an experiment in the design of a user interface to a theorem proving assistant meant that it could be restricted to dealing with a single, simple selfcontained branch of mathematics, in fact the propositional calculus. In addition, initial ideas on the exact form of the surface user interface (i.e. the appearance of the screen) were somewhat nebulous. The rst stage of the development of Mufn therefore consisted of designing and specifying a theorem store for the propositional calculus. This abstract theorem store could then be viewed in a range of different ways by simply coding different projection functions on top of it, thus allowing experimentation with the surface user interface. Having xed on the surface functionality, the specication was then extended to cover the whole system.1 It is interesting to note that this additional specication exercise led to the discovery of a couple of bugs in the code.
93
2. The only things that can y are birds, planes and survivors of the wholesale destruction of the planet Krypton. From these, together with the two obvious statements 3. An elephant is not a bird. 4. An elephant is not a plane. most readers should have little difculty in deducing that 5. All pink elephants are survivors of the wholesale destruction of the planet Krypton. Let us rst rewrite these ve statements in terms of six propositions: (A) X is an elephant. (B) X is pink. (C) X can y. (D) X is a bird. (E) X is a plane. (F) X is a survivor of the wholesale destruction of the planet Krypton. They turn into: 1 . If X is an elephant and X is pink Then X can y. 2 . If X can y Then X is a bird or X is a plane or X is a survivor of the wholesale destruction of the planet Krypton. 3 . If X is an elephant Then X is not a bird. 4 . If X is an elephant Then X is not a plane. 5 . If X is an elephant and X is pink Then X is a survivor of the wholesale destruction of the planet Krypton. Symbolically, 1 . A B 2 . C D C E F
94 3 . A 4 . A 5 . A B D E F
The sequents express the fact that the proposition on the right of the turnstile ( ) can be deduced from the proposition(s) on the left, and , and represent and, or and not respectively. To establish the validity of statement 5, we rst assume that both proposition A (X is an elephant) and proposition B (X is pink) are true. Statement 1 then tells us that proposition C is true (X can y), whence, with the help of statement 2, it follows that either proposition D is true (X is a bird) or proposition E is true (X is a plane) or proposition F is true (X is a survivor of the wholesale destruction of the planet Krypton). Since we know that proposition A is true (X is an elephant), however, statements 4 and 5 allow us to deduce that both proposition D and proposition E are false (X is not a bird; X is not a plane). The only remaining alternative is therefore that proposition F is true (X is a survivor of the wholesale destruction of the planet Krypton). Thus the sequent 5 A B F
is established as a valid inference. The sorts of argument leading to the result above are exactly the same sorts of argument used in proofs in the propositional calculus, the only difference being that the above example employed reasoning about specic propositions whereas the propositional calculus deals with reasoning about propositions in the abstract. Thus, expressions in the (impropositional calculus are built up from the operators (not), (and), (or), 2 together with letters to represent the propositions. The (equivalence), plies) and fact that one expression follows from another is still represented as a sequent. Note that a sequent with nothing to the left of its turnstile means that whatever is to the right of the turnstile follows from no assumptions: that is, it is itself true. This is exactly what is meant when we write an expression alone, so that a sequent with an empty set of assumptions is equivalent to an expression. Valid deductions in the propositional calculus are represented by inference rules. These have one or more hypotheses and a conclusion, and are often written with the hypotheses and conclusion respectively above and below a horizontal line. An example of such an inference rule is the -Er (and-elimination-right) rule: -Er
2 The
E1 E2 E1
95
Note, however, that this represents a valid deduction for any propositions E , E2 . It can 1 therefore be used to justify results such as: p q p r p q
or:
If E2 Then ( If E1 Then E1 and E2 )
-I
E1
There is thus some duplication inherent in the above description, which is generally removed by insisting that the conclusion of an inference rule should not be a sequent. A more complicated inference rule, which has sequents among its hypotheses, is the -E (or-elimination) rule: -E E1 E2 ; E1 E E; E2 E
This states that if E1 E2 is known and if some conclusion E has been shown to follow from each of the disjuncts E1 and E2 , then E can be deduced, or, alternatively:
If all E1
96
This rule thus provides a way of reasoning by cases and can be used to justify, for instance, the deduction of p q r from the three knowns p q, p p q r and q p q r. Although the individual rules, such as -Er , might not in themselves appear to be particularly useful, combinations of these rules can be used to build larger proofs and thus establish nontrivial results. One way of presenting such proofs is shown in Figure 4.1.
p r from p q 1 p q 2 from p infer p q r 3 from q 3.1 p r 3.2 from r 3.2.1 q r infer p q r infer p q r infer p q r
Figure 4.1 A partial proof Here, the body of line 1 (i.e. p q) has been deduced by applying the rule -E to the r p r , referred to in line 1 as h, and the overall conclusion overall hypothesis p q p q r has been justied by appeal to the instance of the -E rule above, applied to line 1 and boxes 2 and 3. Notice how sequent hypotheses in the -E rule are justied by appeal to boxes: the hypotheses of the sequent appear on the from line of the box, the conclusion of the sequent on the infer line. Of course, the fact that the conclusion of the proof is justied does not mean that the proof as a whole is complete not all of the things used to justify the conclusion are themselves justied. In fact, this example nicely illustrates two aspects of the kind of freedom of action Mufn aims to support. First, there is the ability to reason both forwards and backwards. Forward inferencing corresponds to the creation of lines like line 1 in Figure 4.1 which can be deduced, either directly or indirectly, from the overall hypotheses of the proof. The set of such valid deductions, together with the proofs hypotheses, are called the knowns of the proof. In the example of Figure
97
p r and p q. Backwards 4.1 the knowns are thus the two expressions p q inferencing, on the other hand, effectively amounts to lling in the proof from the bottom (the overall conclusion) upwards. Thus, in Figure 4.1 the overall conclusion is justied by appeal to an application of the -E rule to the (justied) line 1 and the (unjustied) boxes 2 and 3. The goal of proving p q r has therefore been reduced to three subgoals, namely to proving p q, which has indeed already been established, and the two sequents p p q r and q p q r. Some progress towards establishing the validity of the second of this pair of sequents has indeed already been made. Thus, line 3.1 follows from the overall hypothesis analogously to line 1, this time via the -El (and-elimination-left) rule: -El E1 E2 E2
and the conclusion of box 3 has again been justied by appeal to the -E rule, here applied to the (justied) line 3.1 and the (unjustied) boxes 2 and 3.2. One forward step has also been created in box 3.2, where line 3.2.1 has been deduced by applying the -I rule to the hypothesis of box 3 and that of box 3.2. In order to complete the proof of Figure 4.1, the conclusions of both box 2 and box 3.2 need to be correctly justied. It is worth looking at these steps in some detail. The conclusion of box 2 could in principle be correctly justied by appeal to any of the following: p the local hypothesis of box 2. p p q p r the overall hypothesis.
In other words, the knowns of box 2 plus the knowns of all its containing boxes (in this case only the box corresponding to the proof as a whole). Thus, in trying to justify the conclusion of box 2 we are effectively trying to validate the sequent: p q p r ;p q; p p q r
which justies: p p q r
98
Suppose, however, that the -Ir rule had not been shown to be valid. In such a case, a user of Mufn could abandon the proof of Figure 4.1 in the state shown, prove the -I r rule, then return to the current proof some time later and complete the proof of box 2 by appeal to the new -Ir rule. This illustrates the second aspect of freedom of action alluded to above that Mufn supports. Turning attention to box 3.2, its conclusion can similarly be correctly justied by appeal to any of its knowns (in this case both r and q r) or to any of the knowns of its containing boxes. Note that, since box 2 is now completely justied, the sequent p p q r which it represents has become a known of the overall proof. Lines and indeed boxes (were there any) inside box 2 are, however, not knowns available within box 3 as they depend on assumptions (namely p) which do not hold there. The proof of box 3.2 is completed by appeal to the rule -I (or-introduction-left), l analogous to -Ir used to justify the conclusion of box 2: -Il E2 E1 E2
p r from p q 1 p q 2 from p infer p q r 3 from q 3.1 p r 3.2 from r 3.2.1 q r infer p q r infer p q r infer p q r
-Er (h) -Ir (h2) -El (h) -I(h3,h3.2) -Il (3.2.1) -E(2,3.1,3.2) -E(1,2,3)
distributes over
One nal point, which is important for the understanding of Mufn, is that this complete proof justies a new derived inference rule, namely: E1 E2 E1 E1 E3 E2 E3
99
This rule is then available for use in future proofs in just the same way as the rules mentioned so far.
In such a description, a tree-form unary expression like Tnot has a single operand, which is either an Atom or some composite tree-form expression, and a tree-form binary
particular set of operators has, in fact, been chosen and is built into Mufn. This is, however, largely for convenience and is by no means crucial. The (fairly simple) modications that have to be made to the specication developed here in order to accommodate a user-dened set of operators can be found in [Moo87].
3A
100
expression like Tand has both a left and a right operand, each of which is either an Atom or a composite tree-form expression. Thus, the expression p q r would actually correspond to: mk-Tor ap mk-Tand aq ar where ap , aq and ar are Atoms representing p, q and r respectively. In these terms, a tree-form sequent (rather inexplicably called Tsubseq here) would have a set of tree-form expressions to the left of its turnstile and a single tree-form expression to the right. A Tsubseq could then be described in terms of a left-hand side and a right-hand side as: Tsubseq :: tlhs : Texp-set trhs : Texp l inv mk-Tsubseq l r The invariant removes the duplication between expressions and sequents with empty left-hand sides.4 Turning attention next to inference rules and proofs, it is clear that some sort of interdependency is needed which is more general than the tree representation described above: a derived inference rule is to have some associated proof(s), the lines of which are justied by appeal to inference rules. The set of inference rules and their proofs thus has a graph-like rather than a tree-like structure, which is normally modelled in formal specications by associating each object with some sort of structureless reference object. In fact, it is also possible to treat expressions as graph-like objects, with expressions being associated with some references to expressions (Exprefs) via some expression store (Expstore): Expstore where Exp Atom Not And Expref
m
Exp
In such a scheme, expressions have references to expressions rather than expressions themselves as their operands, so that, for example, Not and And are described by: Not :: not : Expref And :: andl : Expref andr : Expref
4 The alternative approach, namely that more complex objects do not contain expressions at all but rather have them represented as sequents with empty left-hand sides, would also have been perfectly feasible.
101
In order to ensure that this description makes sense, some consistency conditions have to be imposed on the Expstore. First, any reference appearing as an operand in some expression in the range of the Expstore should be in its domain. This condition ensures that all expressions are completely dened and is itself expressed by the function is-closed: is-closed : Expref is-closed m
m
dom m
This closure condition on the Expstore is equivalent to saying that all sub-expressions (args) of any expression in the Expstore are dened in the Expstore. The other consistency condition states that no expression should be a sub-expression of itself: is-nite : Expref is-nite m
m
Exp dom m
rng trace y m y
args x
The function trace effectively nds the sub-map of m having as its domain some set of expressions, in this case the unit set containing y, and all their sub-expressions. Full details of the auxiliary functions args and trace, and indeed the full Mufn specication, can be found in [JM88]. The full invariant on the Expstore is therefore: inv-Expstore : Expstore inv-Expstore es is-closed es is-nite es
In this scheme, a Subseq has a set of references to expressions as its left-hand side and a single reference to an expression as its right-hand side. The invariant that the left-hand side should not be empty remains: Subseq :: lhs : Expref -set rhs : Expref l inv mk-Subseq l r References are associated with Subseqs via the Subseqstore: Subseqstore Subseqref
m
Subseq
For consistency, any Expref occurring in the exps (that is, the left-hand side plus the right-hand side) of a Subseq in the Subseqstore should be in the Expstore: is-valid-subseqstore : Subseqstore Expstore is-valid-subseqstore ss es q rng ss exps q dom es
For convenience, expressions and sequents are collectively referred to as Nodes: Tnode Texp Tsubseq
These form the building blocks for more complex objects in Mufn. Before proceeding, it is worth reviewing the processes to be supported in Mufn. To begin with, a user will want to dene a set of axioms for the propositional calculus. These will have the same form as inference rules but will not have associated proofs. The user should then be able to create other objects of the same syntactic form as inference rules (we shall call them problems) and try to prove them. Two main classes of problem can therefore be distinguished. On the one hand there are unsolved problems, problems 5 which are neither axioms nor have some associated complete proof. On the other hand there are solved problems, of which three sub-classes can conveniently be distinguished. First, axioms, which are problems having the special status of being proved but which have no associated proofs.6 Second, there are derived inference rules, solved problems with at least one associated complete proof and third, there are all the rest of the solved 7 problems, those which are neither axioms nor derived inference rules. All these classes of problem can be described in terms of a single abstract object, called Problem. It has a set of Nodes ((references to) expressions and/or sequents) as its 8 hypotheses, and a single (reference to an) expression as its conclusion (cf the -E rule). Problem :: hyp : Node-set con : Expref Again, Problems are associated with references to Problems (Problemrefs), this time via the Problemstore: Problemstore Problemref
m
Problem
The Problemstore should be consistent with the Subseqstore and the Expstore in that the nodes (that is, the hypotheses plus the conclusion) of any Problem in the Problemstore should be in either the Subseqstore or the Expstore, whichever is appropriate: is-valid-problemstore : Problemstore is-valid-problemstore ps ss es Subseqstore Expstore o rng ps nodes o dom ss dom es
Proofs
The last primitive object we need to be able to describe is a proof. Let us rst consider only complete proofs, in particular the one shown in Figure 4.2. A cursory perusal of this
may, of course, have a whole cart-load of incomplete proofs. right, neither complete nor incomplete. 7 Mufns inference rules are its axioms plus its derived inference rules, just as you would expect. 8 Recall the equivalence explained above which allowed the restriction that no sequent should appear as the conclusion of an inference rule.
6 Thats 5 They
103
proof reveals a marked similarity between the proof as a whole and any of its boxes (e.g. box 3) each has a set of hypotheses (the from line) and a conclusion (the infer line) and contains some list of lines and boxes. In fact the only difference between a proof and a box is that the hypotheses of a proof can contain sequent hypotheses whereas those of a box cannot. (Recall that a box is used to justify a sequent hypothesis in some rule, with the hypotheses of the box consisting of the left-hand side of the sequent to be so justied and the conclusion of the box the right-hand side of that sequent. Since the left-hand side of a sequent is a set of expressions, the hypotheses of a box will also be a set of expressions.) This suggests a picture in which a box and a proof are described by the same abstract object. We have already seen how validating a box corresponds to proving a problem whose conclusion is the expression on the infer line of the box and whose hypotheses are the knowns available inside the box. This is, however, not a good picture to adopt overall as adding lines to containing boxes can change the knowns available inside the box and hence the effective hypotheses of its corresponding problem. The picture can, however, be made unambiguous by noting that it is sufcient to take the effective hypotheses of the problem representing a box to be the hypotheses of the box itself plus the hypotheses of all its containing boxes any nonhypothesis knowns omitted under this scheme can be regenerated inside the box in question via the same set of steps as was used to generate them in their actual positions in the proof, as all the hypotheses on which they depend will be available there. Redrawing the proof of Figure 4.2 in this scheme leads to the alternative projection shown in Figure 4.3. Notice how all the boxes are now disjoint, i.e. all justications of lines inside a box only refer to things also inside the box. The last step of the abstraction comes about by rewriting the lines with justications as sequents. A line like line 1 is effectively recording the fact that its body p q can p r , or be deduced by applying the -Er rule to the overall hypothesis p q p r p q is a valid instance of the -E rule. This equivalently that p q r results in the alternative projection of Figure 4.3 shown in Figure 4.4. Here, each line of a proof consists of a problem together with some proof of that problem. That proof can be simply a reference to some inference rule (when the problem is simply an instance of that inference rule) or it can itself be a list of lines. In abstract terms, a proof can therefore be either an instantiation, an inference rule together with a mapping recording how atoms in the rules statement are to be replaced by expressions in order to build the required instance of the rule, or a composite proof, a sequence of solved problems. Proofs are also assigned references, this time via the Proofstore. Instantiation :: of : Problemref m Expref by : Atom inv mk-Instantiation o m m
104
from p q p r 1 p q 2 from p; p q infer p q r 3 from q; p q 3.1 p r 3.2 from p; q; infer p q 3.3 from r; q; 3.3.1 q r infer p q infer p q r infer p q r
-Er (h) p p r -Ir (h21 ) r -El (h32 ) p q r p q r p p r -Ir (h3.21 ) r -I(h3.31 , h3.32 ) -Il (3.3.1) -E(3.1, 3.2, 3.3) -E(1, 2, 3)
Proofstore
Proof
Note that the invariant on Instantiation says that the mapping dening the substitution should not be empty: that is, some substitution should actually be performed. This is to remove the redundancy corresponding to a problem being considered as an instance of itself. For ease of testing equality, the Expstore, Subseqstore and Problemstore have all been described by 1-1 mappings. Such a restriction turns out to be impractical for proofs, however, because new complete proofs are going to be built by editing (i.e. adding and/or removing steps to/from) incomplete proofs and sometimes different references to essentially the same proof might be needed. (For example, the user might get part way through some proof and then not be able to see exactly how to proceed. Allowing duplication of the current state of the proof at this point would permit the exploration of different possibilities.) Since there is no concept of editing an Instantiation, however, it is possible to restrict the Proofstore in such a way that it assigns a unique reference to each Instantiation. The following invariant is therefore imposed on the Proofstore:
105
from infer
p q p p q r
by
1 2
p
from infer
p r p p; p q p q r
by
q p
-Er r
from infer
2.1 p q; p q p q r
by
p p
q r r
-Ir
3.1 3.2
p
from infer
p r p r p; q; p q p q r
by
-El p r
3.3
from infer
3.2.1 p p q r r; q; p q p r p q r
by
-Ir
3.4 4 p r; p p
p q r; q
r; p p
3.3.1 3.3.2 p q p q q r
q; r q r q r p q r r; r p q r r p q r
-I -Il -E -E
Figure 4.4 The proof of Figure 4.2 in Mufn style inv-Proofstore : Proofstore inv-Proofstore fs p q dom fs fs p fs q
is-instantiation fs p
The exactly opposite position is in fact taken for composite proofs indeed, parts of the consistency conditions on the Proofmap and the Incomplete-proofmap (see below) will insist that any Proofref referencing a composite proof should not belong to more than one problem. This is actually rather stronger than is absolutely necessary, however, and it would be possible to weaken it such that sharing of complete composite proofs was allowed but sharing of incomplete ones was not. In addition, the Proofstore has to satisfy the usual consistency condition, namely that all components of each proof in it are in the Expstore, the Subseqstore or the
106
Problemstore as appropriate. For an instantiation this amounts to the conditions that the problem being instantiated (its of eld) should be in the Problemstore, that the domain of the substitution mapping (its by eld) should be a subset of the Atoms appearing in that problem, that the expressions in the range of the substitution mapping should all be in the Expstore, and that the substitution should not replace some Atom with (a reference to) itself. For a composite proof the condition states simply that all elements of the proof should be in the Problemstore. The full consistency condition is therefore: is-valid-proofstore fs: Proofstore ps: Problemstore ss: Subseqstore es: Expstore r: pre is-valid-subseqstore ss es is-valid-problemstore ps ss es post r v rng fs is-instantiation v is-valid-instantiation v ps ss es is-composite-proof v is-valid-composite v ps An instantiation is a complete proof of some problem if that problem is obtained as a result of performing the substitution of expressions for atoms dened in its by eld on the problem representing the inference rule dened in its of eld. A composite proof is a complete proof of some problem if the knowns of the problem with respect to the proof include the conclusion of the problem. The knowns of a problem p with respect to some composite proof c are obtained as follows: If c has no elements, the knowns are just the hypotheses of the problem p. If c is not empty, the ith element v of c contributes a new known to the set of knowns k collected from the rst i 1 elements of c according to the following rules: 1. If the hypotheses of v are all in k, the new known is the conclusion of v. 2. If not, but if there is some sequent s in the Subseqstore such that the righthand side of s is the conclusion of v and the left-hand side of s added to the hypotheses of p gives the hypotheses of v, then the new known is s. 3. If neither of the above, v contributes no new known to k: new-known p: Problemref k: Node-set v: Problemref ps: Problemstore ss: Subseqstore r: Node-set dom ps pre p v
107
hyp ps p
hyp ps v
rhs ss s
con ps v
Notice how this works in Figure 4.4. Line 1 contributes p q to the knowns, line 2 contributes the sequent p p q r, line 3 the sequent q p q r, and line 4 the desired conclusion p q r. Similarly, in box 2, line 2.1 adds its conclusion directly, whilst in box 3 line 3.1 adds p r to its knowns, box 3.2 adds p p q r, box 3.3 adds r p q r, and line 3.4 adds its conclusion p q r. Finally, in box 3.2 the conclusion is added directly by line 3.2.1, and in box 3.3 line 3.3.1 adds q r and its conclusion is added by line 3.3.2. So far only complete proofs like that in Figure 4.2 have been considered. Does this picture work for incomplete proofs like the one in Figure 4.1 too? Let us begin by rewriting that proof in the style of Figure 4.4. The result is shown in Figure 4.5. At the top level, boxes 2 and 3 remain incomplete, although completing the proofs of boxes 3.2 and 3.3 would be sufcient to complete box 3. The top level proof at this point therefore can contain only lines 1 and 4 it can not contain boxes 2 and 3 as only solved problems can occur in a proof. The proof at box 2 is empty. Similarly, the proof at box 3 contains just lines 3.1 and 3.4 and that at box 3.2 is empty. Finally, the proof at box 3.3 contains the single line 3.3.1. As explained earlier, this proof uses examples of both forward and backward inferencing. Thus at the top level line 1 is an example of a forward inferencing step whilst line 4 is an example of backward inferencing the former adds to the knowns (in this case p q) and the latter reduces a goal to subgoals (here, p q r has been reduced to p q, p p q r and q p q r). To progress in the proof, the user can add either forward steps, thereby increasing the knowns, or add backward steps and reduce some goal to subgoals. This amounts to adding new elements to the middle of the list constituting an incomplete composite proof. In order to describe incomplete proofs in the above picture we therefore need to know the position in the sequence of elements of an incomplete composite proof marking the division between the forward and the backward steps. This is done by recording the position of the last element of the forward proof in the Indexmap: Indexmap Proofref
m
Next, some record of which proofs, complete and incomplete, are associated with which problems is needed. The Proofmap and the Incomplete-proofmap store this information Proofmap Problemref
m
Proofref -set
108
from infer
p q p p q r
by
1 2
p
from infer
p r p p; p q p q r
by
q p
-Er r
from infer
?? q; p q p q r
by
3.1 3.2
p
from infer
p r p r p; q; p q p q r
by
-El p r
3.3
from infer
?? r; q; p p q r
by
3.4 4 p r; p p
p q r; q
r; p p
3.3.1 ?? p q p q q r
q; r
q r q r
-I
r; r p r p q r
-E -E
Figure 4.5 The incomplete proof of Figure 4.1 in Mufn style Incomplete-proofmap Problemref
m
Proofref -set
Note that each maps a Problemref to a set of Proofref a problem may have many proofs, both complete and incomplete. There are essentially two different but equivalent ways in which a problem could have no incomplete proofs in this scheme. Either it could map to the empty set under the Incomplete-proofmap or it could simply not appear in the domain thereof. In Mufn, the (arbitrary) choice that the latter is the case is made, thus allowing the restriction that the empty set should not occur in the range of the Incomplete-proofmap. The restriction that no two problems should have composite proofs in common leads to the second clause of the invariant on the Incomplete-proofmap:
109
The solved problems are those appearing in the domain of the Proofmap. All other problems, that is those in the domain of the Problemstore but not in that of the Proofmap, are unsolved. The axioms of Mufn are made to conform to this denition by mapping them to the empty set under the Proofmap. Some subset of the solved problems is designated as the rules of inference of Mufn. These problems, which should include all the axioms, are distinguished by giving them names via the Rulemap. Again, no two rules may have the same name and the empty string is not a valid name. Rulemap inv rm String Problemref dom rm
m
The consistency condition on the Rulemap states that all rules should be solved problems, that all axioms should be rules, and that all instantiations should be instances of rules: is-valid-rulemap : Rulemap Proofmap Proofstore is-valid-rulemap rm jm fs axioms jm rules rm rules rm solved-problems jm p complete-proofs jm p dom fs is-instantiation fs p of fs p
rules rm
The consistency condition on the Proofmap is somewhat more complicated. The easy bits state that all solved problems (i.e. everything in the domain of the Proofmap) should be in the Problemstore, that no two problems share a complete composite proof, and that all proofs attached to a problem via the Proofmap are in the Proofstore, contain only solved problems in their components, and are actually complete proofs of that problem. The hard bit says that the set of solved problems and their proofs should be logically sound. This bit is further complicated by the fact that a solved problem can in principle have more than one complete proof. This means that circularities can exist in the problem-proof graph a user might prove a rule A directly from the axioms of the system, then construct a proof of a rule B in which some line is justied by appeal to the derived rule A, and nally construct a second proof of the rule A in which some line is justied by appeal to the derived rule B, all without destroying the logical soundness of the system (because there is a proof of A which does not depend on the rule B). The statement of logical soundness for Mufn is therefore that each solved problem should be derivable, at least in principle, directly from the axioms of the system (is-self -consistent):
110
The full consistency condition on the Proofmap then reads: is-valid-proofmap jm: Proofmap fs: Proofstore ps: Problemstore ss: Subseqstore es: Expstore r: pre is-valid-subseqstore ss es is-valid-problemstore ps ss es is-valid-proofstore fs ps ss es post r solved-problems jm dom ps complete-proofs jm dom fs is-self -consistent jm fs u solved-problems jm v jm u problems fs v dom jm is-complete-proof fs v u ps ss es k m dom jm v jm k jm m is-composite-proof fs v k m The validity condition on the Incomplete-proofmap is built up similarly. First, any problem in its domain must be in the Problemstore and any incomplete proof attached to that problem in the Proofstore. In fact, this condition is extended to state that the Proofstore contains only those proofs which are attached to some problem via either the Proofmap or the Incomplete-proofmap. Here, however, the proof must not be a complete proof of the problem, though it must still consist only of solved problems. In addition, no proof should be both an incomplete proof of some problem and a complete proof of some other. Finally, Mufn views the building of an Instantiation as an essentially single-step process and provides no operations for editing existing ones. This effectively means that only complete Instantiations are considered, thus allowing the restriction that no Instantiation should occur in any element in the range of the Incomplete-proofmap. is-valid-incomplete-proofmap im: Incomplete-proofmap jm: Proofmap fs: Proofstore ps: Problemstore ss: Subseqstore es: Expstore r: pre is-valid-subseqstore ss es is-valid-problemstore ps ss es is-valid-proofstore fs ps ss es is-valid-proofmap jm fs ps ss es post r dom im dom ps axioms jm dom im complete-proofs jm incomplete-proofs im dom fs complete-proofs jm incomplete-proofs im u dom im v im u problems fs v solved-problems jm is-composite-proof fs v is-complete-proof fs v u ps ss es As we have already seen, incomplete proofs consist effectively of two parts, the forward
111
proof and the backward proof, with the proof as a whole being the concatenation of the backward proof onto the forward proof. When attempting to convert an incomplete proof of some problem into a complete proof thereof, new elements can be added either to the tail of the forward proof or to the head of the backward proof, corresponding respectively to forward inferencing and backward inferencing. The index of the last element of the forward proof is stored in the Indexmap. The elements of the forward proof give rise to all the knowns, with part of the validity condition on the Indexmap being that each element of the forward proof should actually contribute to the knowns. The elements of the backward proof, on the other hand, provide a proof of the conclusion of the relevant problem from some set of subgoals. Proving all these subgoals would be sufcient to complete the proof. In this case, a new element can be added to the head of the backward proof if the conclusion of that element is amongst the current subgoals. This condition also forms part of the validity constraint. Another part of the validity condition on the Indexmap states that the backward proof should contain no element all of whose hypotheses are among the current knowns such an element would correctly contribute its conclusion to the knowns and should therefore be positioned at the tail of the forward proof. Finally, the Indexmap should record an index for each incomplete proof but for no complete proof, with the value of that index lying somewhere between zero and the number of elements in the proof. is-valid-indexmap xm: Indexmap im: Incomplete-proofmap jm: Proofmap fs: Proofstore ps: Problemstore ss: Subseqstore es: Expstore r: pre is-valid-subseqstore ss es is-valid-problemstore ps ss es is-valid-proofstore fs ps ss es is-valid-proofmap jm fs ps ss es is-valid-incomplete-proofmap im jm fs ps ss es post dom xm incomplete-proofs im u dom im v im u let fp forward-proof v fs xm bp backward-proof v fs xm gp reverse bp in len fs v 0 xm v z rng bp hyp ps z knowns u hyp ps u fp ps ss g dom gp con ps gp g goals con ps u g len gp gp ps b dom fp adds-known u knowns u hyp ps u b len fp fp ps ss fp b ps ss Finally, each of the primitive objects introduced above can be given a name in Mufn so that a user can more easily identify those objects of particular interest. The names are
112
stored in a name store, mapping strings to the appropriate class of reference object, for each of the basic types of object. There is a restriction that no two objects of the same type can have the same name, and another that the empty string is not a valid name. The ProofNames map is typical of the class: ProofNames String dom fn inv fn String Character
m
Proofref
The consistency condition for each name store ensures that only objects in the relevant object store are assigned names, for example: is-valid-proofnames : ProofNames Proofstore is-valid-proofnames fn fs rng fn dom fs Putting all this together leads to the following description of the full Mufn state: Mufn :: es : Expstore ss : Subseqstore ps : Problemstore fs : Proofstore en : ExpNames sn : SubseqNames pn : ProblemNames fn : ProofNames jm : Proofmap rm : Rulemap im : Incomplete-proofmap xm : Indexmap inv mk-Mufn es ss ps fs en sn pn fn jm rm im xm is-valid-subseqstore ss es is-valid-problemstore ps ss es is-valid-proofstore fs ps ss es is-valid-expnames en es is-valid-subseqnames sn ss is-valid-problemnames pn ps is-valid-proofnames fn fs is-valid-proofmap jm fs ps ss es is-valid-rulemap rm jm fs is-valid-incomplete-proofmap im jm fs ps ss es is-valid-indexmap xm im jm fs ps ss es
113
es y x es es es es y x
and you can add a new sequent to the Subseqstore if all the expressions you want it to consist of are already in the Expstore: add-subseq z: Expref -set y: Expref g: Subseqref ext rd es : Expstore wr ss : Subseqstore dom es z pre z y post let t mk-Subseq z y in t ss ss t rng ss g dom ss ss g t rng ss g dom ss ss ss g t Finally, you can add a new problem to the Problemstore if all the sequents and expres9 sions you want to make it out of are in the Subseqstore and the Expstore respectively. add-problem n: Node-set y: Expref u: Problemref ext rd es : Expstore rd ss : Subseqstore wr ps : Problemstore pre y dom es n dom es dom ss post let t mk-Problem n y in t rng ps u dom ps ps u t ps ps t rng ps u dom ps ps ps u t
functions add-subseq and add-problem, although depressingly similar to add-exp, are included here because their pre-conditions are incorrect in [JM88].
9 The
114
Alternatively, you can add new expressions to the Expstore by building instances of old ones. The function is-substitution appearing in the pre-condition essentially ensures that Atoms are only replaced with existing expressions. The invariant on the Expstore is maintained by adding not only the new instantiated expression but also any subexpressions (descendents) which are not already in the Expstore. Expref r: Expref instantiate-exp y: Expref m: Atom ext wr es : Expstore es pre y dom es is-substitution y m post es es r dom es is-exp-match y r m es dom es dom es
m
descendents r es
New sequents and problems can also be added by this method, but the operations for doing this are even more unspeakable than the above. They are all in the full specication, of course. Flushed with success at having created a new problem, you will no doubt be eager to call it fred, in which case the operation name-problem is just the thing you will need. Its pre-condition means, however, that you can only name some problem fred if the problem exists and if no other problem is called fred, though it rather magnanimously allows you to call a problem fred if it is already called fred. Not only that, but if the problem is actually called gladys it gets renamed fred. And thats not all. Naming something with the empty string actually unnames it. name-problem n: String p: Problemref ext wr pn : ProblemNames rd ps : Problemstore pn n pre p dom ps n dom pn post n dom pn pn pn n pn n dom pn n pn pn p
p pn n
p p
The operations for naming expressions, sequents and proofs are entirely analogous. So you have a new problem called fred. What can you do with it? One thing you might want to do is throw it away. There is a catch here, though. You can only throw away unsolved problems (on the grounds that throwing away a solved problem is dangerous it might have been used to justify some step in a proof of some other problem10 ). Not only that, but it is not just a case of removing it from the Problemstore and the ProblemNames either it might have a whole slew of incomplete proofs. In
10 Of course, it would be possible to get around this and write an operation for throwing away solved problems. The only snag would be that proofs using it would become invalid, so that some problems would have to revert from being solved problems to being unsolved problems, then any proofs using those would become invalid, so more problems would go back to being unsolved, etc. Such an operation is, thankfully, outside Mufns scope.
115
that case, it also has to be removed from the domain of the Incomplete-proofmap and any proofs which were attached to it there have to be removed from the Proofstore, their names from the ProofNames, and their indices from the Indexmap: remove-problem p: Problemref ext wr ps : Problemstore wr fs : Proofstore wr im : Incomplete-proofmap wr xm : Indexmap wr pn : ProblemNames wr fn : ProofNames rd jm : Proofmap pre p dom ps p dom jm p ps pn pn p post ps p p dom im im p im im fs fs fs im p xm dom im im xm fs im p xm fn xm fn fn fn im p
Another thing you might want to do to your wonderful new problem is make it an axiom of your system. To do this you have to give it a name (some non-empty string) in the Rulemap. If the problem in question is already an axiom, the effect of the operation make-axiom is simply to rename it, though unnaming it by renaming it with the empty string (which amounts to removing it from the set of axioms) is not allowed as this might destroy the logical soundness of the system. In addition, the pre-condition will not let you convert a derived rule to an axiom after all, if you have already proved something from your existing axioms, turning it into an axiom gains you nothing. Converting an unsolved problem to an axiom is thus the only case of any interest. Here, any incomplete proofs of the problem are removed from the Proofstore and their names and indices from the ProofNames and the Indexmap respectively. The problem itself is removed from the Incomplete-proofmap and an association mapping it to the empty set is added to the Proofmap. make-axiom ext wr im : wr jm : wr rm : wr xm : wr fs : wr fn : pre n p: Problemref n: String Incomplete-proofmap Proofmap Rulemap Indexmap Proofstore ProofNames p axioms jm n dom rm
rm n
dom jm
im p
fs
dom im xm xm fs xm jm jm rm rm
A third possibility is that the problem named fred is justiable by some Instantiation, in which case the operation add-instantiation should prove useful. In order that the invariants on Instantiation and Proofmap be respected, the problem p being instantiated should be a rule and the instantiation mapping m should not be empty, should have a domain which is a subset of the Atoms occurring in p and should have a range containing only expressions existing in the Expstore. Building the instance of the problem p with the instantiation mapping m should result in the problem q (i.e. the problem called fred). The whole process is, however, forbidden if the problem named fred is an axiom adding proofs to an axiom would convert it to a derived rule, possibly destroying the logical soundness of the system into the bargain. If the Instantiation i (i.e. mk-Instantiation p m ) is in the range of the Proofstore, the Proofref f referencing it is added as a new complete proof of the problem q by adding f to the set to which q is mapped under the Proofmap. Otherwise, some new association i is added to the Proofstore rst, where f is now some new Proofref not previously f existing in the domain of the Proofstore, then the Proofmap is updated as above. These contortions ensure that the invariant on the Proofstore, in particular the part insisting that Instantiations are assigned unique references therein, is maintained. Expref q: Problemref add-instantiation p: Problemref m: Atom ext wr fs : Proofstore wr jm : Proofmap rd rm : Rulemap rd ps : Problemstore rd ss : Subseqstore rd es : Expstore dom m vars nodes ps p ss es pre p rng rm m is-substitution nodes ps p m ss es is-problem-match p q m ps ss es q axioms jm post let i mk-Instantiation p m in i rng fs f dom fs i q dom jm s jm q jm jm q s fs f i fs fs fs f i rng fs f dom fs fs f q dom jm s f
m
117
If the conclusion of some problem is amongst its hypotheses, it already automatically satises the condition by which a composite proof of it is complete (the conclusion of the problem is in its knowns with respect to the proof). It can therefore be proved by an empty composite proof (not an empty set of proofs as this would mean it was an axiom). The operation add-assumption thus adds an empty composite proof to the set of complete proofs of such a problem. Of course, the problem should not be an axiom for exactly the same reasons as given above. add-assumption p: Problemref ext wr fs : Proofstore wr jm : Proofmap rd ps : Problemstore pre p dom ps p axioms jm post f p dom fs dom jm fs jm fs f jm p p f dom jm jm jm p f jm p
con ps p
hyp ps p
If none of the above appeals, you might like to try to construct a non-trivial composite proof of your new problem. The rst step in this process is to add a new empty composite proof to the incomplete proofs of the problem. Again, the problem should not be an axiom. It should, however, be an existing problem (in the Problemstore). In addition, its hypotheses should not include its conclusion if they did the empty composite proof would actually be a complete proof of the problem, in which case it should not be attached to it via the Incomplete-proofmap. The operation add-empty-proof therefore adds a new empty composite proof to the Proofstore, assigns it the index 0 in the Indexmap (corresponding to it having no forward proof), and adds this new proof to the set of incomplete proofs of the problem as recorded in the Incomplete-proofmap. add-empty-proof p: Problemref ext wr im : Incomplete-proofmap wr xm : Indexmap wr fs : Proofstore rd jm : Proofmap rd ps : Problemstore pre p axioms jm p dom ps con ps p post f p dom fs dom im fs im fs f xm im p p xm f dom im im im p f im p
hyp ps p f 0
There are operations for naming and removing proofs similar to those given above for
118
doing likewise to problems. The restriction here is that only incomplete proofs can be thrown away throwing away a complete proof might cause the problem of which it was a proof to revert to being unsolved, thus leading to the selfsame set of undesirable consequences as arise when throwing away a solved problem. See the complete specication for the full details of these operations. Having created a new empty composite proof, you will want to add steps to it, either forward (via add-fwd-step) or backward (via add-bwd-step). You can add a new Problemref s to the tail of the forward proof of some incomplete proof if s is a solved problem and if it satises the condition for adding some new known to the proof. The new step is inserted immediately after the element whose position is dened by the index of the proof. As a result of the insertion, however, that part of the invariant saying that the backward proof contains no element whose hypotheses are amongst the current knowns might have been violated addition of the new forward step will have increased the knowns. Thus, any step in the backward proof whose hypotheses are indeed amongst the new knowns must be transferred to the tail of the forward proof, this process being repeated until the backward proof contains no more such elements. In turn, shifting elements out of the backward proof may have destroyed the part of the invariant that insists that the steps of the backward proof taken in reverse order progressively reduce goals to subgoals. Those elements remaining in the backward proof after the transference of elements to the forward proof which do not satisfy this condition should therefore be discarded. If the new forward proof is a complete proof of the problem in question, the whole of the backward proof is discarded and the new forward proof is added as a complete proof of the problem, reference to the proof being removed from the Incomplete-proofmap and the Indexmap into the bargain. Otherwise, the proof as a whole (still incomplete) becomes the new forward proof concatenated with the new backward proof, with its new index being the number of elements in the new forward proof. add-fwd-step p: Problemref f : Proofref s: Problemref ext wr fs : Proofstore wr im : Incomplete-proofmap wr xm : Indexmap wr jm : Proofmap rd ps : Problemstore rd ss : Subseqstore rd es : Expstore pre let k knowns p hyp ps p forward-proof f fs xm ps ss in p dom im f im p s dom jm adds-known p k s ps ss
119
z backward-proof f fs xm k knowns p hyp ps p y ps ss l new-fwd-steps k z ps bwd new-bwd-steps con ps p fwd y l new-proof fwd bwd in
reverse z rng l ps
Adding a backward step is somewhat easier as no reorganization of the proof is required the pre-condition ensures that the new step being added to the head of the backward proof is not a valid forward step and none of the existing backward steps can be because they would have been transferred previously if they were. The rest of the pre-condition just checks that the new step is a solved problem and that its conclusion is one of the current goals. The proof becomes the old forward proof, the new element and the old backward proof in that order. Its index does not change as its forward proof has not altered. add-bwd-step p: Problemref f : Proofref s: Problemref ext wr fs : Proofstore rd im : Incomplete-proofmap rd xm : Indexmap rd jm : Proofmap rd ps : Problemstore rd ss : Subseqstore pre let k knowns p hyp ps p forward-proof f fs xm ps ss g goals con ps p reverse backward-proof f fs xm ps in hyp ps s k con ps s p dom im f im p s dom jm post let new-proof fs fs f forward-proof f fs xm s new-proof backward-proof f fs xm in
g k
If you have completely messed things up as a result of the above, you can always remedy the situation with the help of the undo functions undo-fwd-step and undo-bwd-step.
120
The former removes the tail of the forward proof (provided there is a forward proof), the latter the head of the backward proof under a similar condition. There is a surprise in store here for the unwary, though undo-fwd-step is not necessarily the inverse of add-fwd-step as some steps might have been transferred from the backward proof to the forward proof as part of the add-fwd-step action. The corresponding operations on the backward proof are mutually inverse, however, as no reorganization of the proof occurs. Both operations are fairly predictable, simply removing the relevant element from the proof. In addition, undo-fwd-proof decrements the proofs index by one. You can only apply them to incomplete proofs, of course. undo-fwd-step p: Problemref f : Proofref ext wr fs : Proofstore wr xm : Indexmap rd im : Incomplete-proofmap 0 pre p dom im f im p xm f post xm xm f xm f 1 fs fs f xm f fs f
undo-bwd-step p: Problemref f : Proofref ext wr fs : Proofstore wr xm : Indexmap rd im : Incomplete-proofmap len fs f pre p dom im f im p xm f post xm xm fs fs f xm f 1 fs f
If you get stuck in some proof and want to try out different strategies from that point you can copy the current state of your proof with the spawn-proof operation. Your problem then acquires a new incomplete proof which looks just like the one you got stuck in. The new proof is added to the Proofstore and its index to the Indexmap as part of the process. spawn-proof p: Problemref f : Proofref ext wr im : Incomplete-proofmap wr xm : Indexmap wr fs : Proofstore pre p dom im f im p post g dom fs fs fs g fs f xm xm im g xm f im p g im p
Finally, when you have completed your proof you can make the problem it was a proof of into a derived rule with the help of the operation name-rule. This just associates a name (non-empty string) with the problem via the Rulemap. Note that the operation can also be used for renaming existing rules.
4.5 Mufn
name-rule ext wr rm rd jm pre n post rm n: String p: Problemref : Rulemap : Proofmap p dom jm n dom rm rm p n p
121
rm n
4.5 Mufn
This nal section gives some details of the actual implementation of Mufn in Smalltalk 11 80 which was based on the specication described in the two preceding sections. The various components of the system can conveniently be divided into three categories, the browser, the builder and the prover. Mufns browser essentially allows the user to inspect the current state of Mufn. The user can select the type of object of interest from the list axioms, proofs, rules, problems, subsequents (i.e. sequents) and expressions. The browser will then show all objects of the selected type. Where the particular type selected has multiple subtypes, e.g. complete and incomplete for proofs, and, or, etc. for expressions, the user can additionally select one of these subtypes and the browser will then show only those objects of the selected subtype. Objects can be accessed via their names or some textual representation of the objects themselves. When the object selected is a problem, the browser shows additionally either the status of any existing proofs of that problem or that the selected problem is an axiom. In the latter case, the axiom name is also shown. Figure 4.6 shows the browser where the selection is the unsolved problem named or-and-dist and its incomplete proof of the same name, the completed version of which is shown in Figure 4.2. In addition, the browser allows a few simple changes to be made to the state of Mufn, such as naming and renaming of objects, conversion of an unsolved problem to an axiom, conversion of a solved problem to a (derived) rule, and addition of a new empty composite proof to the set of incomplete proofs of some problem. Finally, the browser acts as a controller for the other components of Mufn. Thus, for instance, it allows the user to start up either a builder or a prover, to inspect the current status of some existing proof, to remove incomplete proofs and unsolved problems from Mufns store, and to restart some abandoned proof at the point at which it was abandoned. The builder, of which there are several different forms, allows the user to create new expressions, (sub)sequents and problems and add them to the relevant object stores.
system is an Alvey deliverable and copies of the code are available via M.K.Tordoff, STL NW, Copthall House, Nelson Place, Newcastle-under-Lyme, Staffs ST5 1EZ.
11 The
122
4.5 Mufn
123
Lastly, the prover allows the user to edit an incomplete proof with a view to converting it into a complete proof. It uses a display based on the ideas of the knowns and the goals of the problem in question with respect to the proof. Figure 4.7 shows a prover at that point during the construction of the proof of Figure 4.2 at which the proof is complete apart from the subproof at box 3. The top pane of the prover shows the problem which is to be solved, the middle pane the knowns of the problem with respect to the proof, and the bottom pane the current subgoals. Subproofs of the proof, for example the one at box 3 in Figure 4.2, each appear in a separate prover, where the problem to be solved has as its conclusion the conclusion of the relevant box and as its hypotheses the hypotheses of the box itself plus all the hypotheses of each of its containing boxes. If the amount of information becomes too great, the user can chose to reduce it by making use of the facility of elision of knowns. Thus, for instance, if a user decides that some particular known is not going to be useful in the remainder of the proof it can be designated as hidden and it is then removed from the display. When a prover has hidden knowns, Mufn reminds the user of this by displaying ellipsis points at the foot of the list of displayed knowns. Any hidden known remains a known of the proof, of course, and the reverse operation of redisplaying hidden knowns is available at any time. Mufn offers some assistance with the process of proof creation, largely through its matching facilities. Thus, the user can select an expression from either the knowns or the goals and ask Mufn for a list of all rules matching that expression, that is any rules which might be applicable. In the case where the selection is a known, Mufn provides a list of all the rules so far proved which contain some expression amongst their hypotheses which could be instantiated to the selected expression. When the selection is a goal, the list provided is of those rules whose conclusion can be instantiated to the selected expression. Selecting a rule from the list returned then causes Mufn to try to build the appropriate instance of the selected rule and add this as a new step to the proof. The variable substitution deduced from the matching process is not always complete, however. For instance, more than one element of the hypotheses of the selected rule might match the selected expression, or the rule might contain more Atoms than the expression which was used in the matching procedure. In such circumstances, Mufn prompts the user to complete the parts of the instantiation mapping it was unable to deduce for itself. When this has been completed satisfactorily, it adds the new step to the proof. The other way in which Mufn offers assistance with the proof is in the case where one of the subgoals is a sequent (as in Figure 4.7). We have already seen that, in order to make a sequent a known of a proof it is necessary to add to the tail of the forward proof a (solved) problem, the conclusion of which is the right-hand side of the sequent and the hypotheses of which are the hypotheses of the sequent plus those of its containing problem (the containing problem is the problem appearing in the top pane of the prover).
124
4.5 Mufn
125
The user can therefore select a sequent in the goals pane of the prover and ask Mufn to search through all its solved problems to see whether the appropriate problem is amongst them. If it is, Mufn adds it to the tail of the forward proof, and the sequent becomes a known of the proof. Otherwise, Mufn offers the user the opportunity to open a new prover in order to attempt to solve that problem. The user may have as many provers, browsers and builders as desired active and displayed on the screen at once and can switch the focus of attention between them at will. In particular, there may be provers in which different problems are being proved as well as provers showing different attempted proofs of the same problem. Thus, for example, if, while working on some proof, the user decides that the proof would be more straightforward if some new derived rule were proved rst, the current proof can be abandoned and the problem stating that derived rule can be built in a builder, proved in some other prover, then designated as a derived rule, maybe in a browser. On returning to the original proof, the new rule will now be available and it can be used there as desired. The surface user interface as described here thus offers the user several different views of the underlying Mufn state, together with ways of altering that state. Each component of the user interface thus essentially lters out that part of the total information held in the Mufn state as a whole which is relevant to the particular task in hand and presents it to the user, hopefully in a way which makes assimilation of that information straightforward and which allows the user to carry out the desired actions as naturally (whatever that might mean) as possible. Of course, the abstract state dened above places only a single restriction on the surface user interface, namely that only information actually stored in the state can be projected. Thus, a user interface of radically different appearance to the one described here would be an equally valid way of interacting with the Mufn state as specied. Indeed, the experimentation with user interface issues carried out in the Mufn project indicates that different users will prefer different interaction styles (in tests, some expressed a preference for the knowns-goals style described above, others would prefer to interact with a display based on the layout of a proof shown in Figure 4.1.). The conclusion is therefore that a whole range of (preferably user-tailorable) user interface components offering a variety of ways of performing essentially the same set of tasks should be provided in order to really support the process of interactive theorem proving.
126
This and the next chapter apply VDM to a problem of considerable practical importance in computing. Proofs in propositional calculus, discussed in Chapter 3, require simple pattern matching to determine how inference rules can be used. For the full predicate calculus, unication is required. The realization that unication is a fundamental process in many applications has led to much study aimed at producing algorithms of satisfactory time/space complexity. This chapter sets the scene by showing how certain obvious algorithms do not work and uses these to construct a simple unication algorithm informally. By constrast, a formal specication is constructed and one particular algorithm developed from it. This illustrates the use of operation decomposition rules and proofs in guiding the development of code.
127
128
5.1 Introduction
This case study concerns the specication of a practically important problem and the rigorous development of an algorithm from the specication. The idea of unication of rst order terms in an empty equational theory is introduced; its importance as the basis of many practical applications and the wide range of extant algorithms are noted. It is argued that a formal specication of unication is required as a basis for the rigorous development of such algorithms. An algorithm is developed entirely informally. A formal specication of rst order unication is developed and the necessary supporting proofs are outlined. The obligation to prove implementability of the specication is discharged by means of a constructive proof using operation decomposition rules to guide design of an algorithm similar to the one developed informally, but this time with some assurance of correctness because of the rigor of the development. Some comments on the specication and development processes conclude the case study.
5.1 Introduction
129
yields the same result, namely f g y y . # is said to unify t and t2 and is called a unier 1 of those terms. This study is restricted to uniers which make terms exactly equal, not merely equal modulo properties of the functions denoted by the function names (such as associativity or commutativity). x g y is also a unier of t1 and t2 . # is said to be more general Notice that # than #, because # can be derived from # (by adding the maplet z y to it). Not all sets of rst order terms have uniers, but those which do always have a most general unier, i.e. a unier from which all the other uniers of the terms can be derived. These ideas will be expressed more rigorously in Section 5.2. This study concerns procedures for nding the most general unier of sets of rst order terms in the absence of equational properties of the functionals. Such procedures are called unication algorithms.
u:
while t1
130
The means of recording pairs in substitutions will be more fully discussed in Section 5.2. Applying Algorithm 1 to the above example yields: 1. 2. 3. 4. . Initialize u: u Generate disagreement pair x a . x a . Reconcile disagreement: u Apply u to t1 and t2 : t1 t2 f aha f ay ha .
5. Generate disagreement pair h a y . x ay 6. Reconcile disagreement: u 7. Apply u to t1 and t2 : t1 t2 8. t1 t2 Stop. f aha f aha
So the algorithm works for some pairs of terms but not for all. For example, in trying to unify: f gx t1 t2 f hx the rst disagreement pair is g x h x . This disagreement cannot be reconciled since no substitution will make the functionals g and h the same. Clearly 1 and t2 are not t uniable. The algorithm should test for this kind of failure (called a clash because it is due to clashing function symbols). A clash occurs when there is no variable in the disagreement pair, so a check for the variables presence should be incorporated into the algorithm. This yields Algorithm 2:
Algorithm 2 Input: t1 ,t2 Output: substitution u, failure ag
u:
while t1
5.1 Introduction
if neither d1 nor d2 a variable then FAIL Clash else let d1 be the variable in the pair in begin
131
t1 t2
f x f hx
The rst disagreement pair is x h x . According to Algorithm 2: u but applying u to t1 and t2 yields t1 t2 f hx f hhx x hx
The algorithm goes on generating the same disagreement and never making the terms equal. It will not terminate because the substitutions generated do not eliminate x. The substitution is called cyclic and t1 and t2 are not nitely uniable. This study and the majority of practical applications deal only in nitely uniable terms, so a check (the Occurs check) is included to look for a variable in the disagreement occurring in another term of the disagreement. Termination can then be forced when such a disagreement is detected. This gives Algorithm 3:
Algorithm 3 Input: t1 ,t2 Output: substitution u, failure ag
u:
while t1
; t2 and not failed Generate disagreement pair d1 d2 ; if neither d1 nor d2 a variable then FAIL Clash else let d1 be the variable in the pair in if d1 occurs in d2 then FAIL Cycle
else begin
132
end endwhile End Algorithm 3
related to the algorithm developed rigorously in Section 5.4. Exponential time complexity is the main vice of Robinsons algorithm, countering its virtue of intuitive simplicity. This exponentiality, according to Corbin and Bidoit [CB83], derives from the choice of data structure used to represent terms. The next example illustrates this. Consider terms represented as ordered trees (we assume ordering of arguments left to right in the diagrams below). Consider unifying: t1 : x x f g y y t2 : g z h u The unier is x ghu hu y hu z h u . The resultant unied term has ve copies of the subterm h u if represented as a tree: f g h u h u h u g h u g h u g y f g h u
The h u subterm is copied eight times during the execution of Algorithm 3 on this problem. The unication computation done in this way on tree structures can lead to exponential growth. To take an extreme example, consider unifying the following terms by Robinsons algorithm (or Algorithm 3):
5.1 Introduction
133
t1 :
t2 :
x1
x2
.....
xm x0
g x0 x1
g x1
..... xm
g xm
The rst disagreement pair is x1 g x0 x0 . Applying the resultant substitution to t1 and t2 yields:
t1 :
t2 :
g x0 x0
x2
.....
xm x0
g x0 x0 g
..... g xm x0
g xm
x0 x0
In general the k th disagreement results in adding a component of the form x a term of 2k 1 nodes to the substitution. This is the source of the exponential complexity in Robinsons algorithm. Corbin and Bidoit [CB83] proposed the use of directed acyclic graphs to represent terms to allow sharing of subterms and thus minimize copying. Thus the term f g h u h u h u g h u subterm: g h u
134
f g h u The use of this term representation is claimed to bring about a dramatic improvement in the algorithms performance. The process of deriving a unication algorithm appears to be nontrivial. Apart from the need to handle all kinds of disagreement, the algorithms efciency is greatly inuenced by such issues as the choice of data structure. Is it worth the effort? How useful is unication? g
5.1 Introduction
135
Type checking. Type checking in an environment with polymorphic functions involves substitution of type expressions for type variables. In checking the compatibility of two type expressions, they must be unied [ASU86]. Other applications. Examples include string handling, information retrieval, computer vision (unication of graphs) and knowledge representation in expert systems.
136
The development of a correct and efcient unication algorithm is, then, an activity of considerable practical value. In this section a simple (and probably highly inefcient) unication algorithm has been developed in an ad hoc way. The design methodology was crude: think of a possible algorithm and nd bugs; correct the bugs and check the algorithm again; repeat the process until convinced of the algorithms correctness. The reader with any practical experience in algorithm design will wonder if the development has gone far enough at Algorithm 3. Does it really nd a unier for all uniable input terms and stop with failure on all nonuniable inputs ... and is that unier the most general? This question of gaining conviction of correctness is at the center of this case study, where a rigorous approach to the specication of unication gives a basis for judging the correctness of proposed algorithms. It also provides a starting point for the analysis of the variety of algorithms described above in a controlled and rigorous manner. Different algorithms can be viewed as alternative developments of the same specication. The rest of this case study illustrates part of this approach. First, unication is dened by means of a formal specication. Then the rigorous development of an algorithm similar to Algorithm 3 is considered. The methods used should ensure the correctness of the result.
Terms
Functional terms consist of a function name and a list of arguments which are themselves terms. The name has an associated arity a natural number giving the correct number of arguments in any well-formed term containing the function name. Let FT be the type of functional terms and GT the type of general terms (dened below). Functional terms may then be specied thus:
137
The arity is taken to be part of the function name fn. Informally, the arity will be shown as a superscript in the function name. Thus f2 x y and f 3 x y z are valid terms with different function names. Note that FTs with no arguments are individual constants. Let the type of variables be V-Id. A term is either a variable or a functional term, so the type GT of terms is dened as the union of V-Id and FT: GT V-Id FT
Note that V-Id and F-Id are considered atomic types. It is assumed that equality on them is dened. Equality is also assumed to be dened on FT and GT in the obvious structural way. This specication does not admit innite terms involving cycles, like: f2 a0 x a0 The reason is that, in VDM, recursively-dened objects are required to be nite. This is essential for the well-foundedness of structural induction rules. Such a rule can be written for GT. It allows the proof of assertions about all t in GT. The rule is called GT-Ind: t
GT-Ind
g2 g2
F-Id l
GT
V-Id p t ; a rng l p a t GT p t
p mk-FT f l
Informally, this rule says that if p v can be shown to hold for any variable v and p mk-FT f l can be shown to hold if p a holds on each argument a in l, then p t holds whenever t is a GT. Now that variables and terms are dealt with, the occurs check mentioned above can be specied. Occurs is a function which takes a variable and a term and returns the boolean value true if and only if the variable occurs somewhere in the term. A variable occurs inside itself. Thus: Occurs x x true
Occurs is specied as follows: Occurs : V-Id Occurs v t GT if t V-Id then v t else a rng args t Occurs v a
If the term t is a variable, the check reduces to v t. Otherwise t must be a functional term and for the variable to occur in t it must occur in some argument of t. Since Occurs is a dened function, we can derive inference rules describing its behavior:
Occurs -Def
Occurs -Def
Such rules can be derived for all the dened functions in the specication, and this is left as an exercise for the reader. It is now possible to write a function which returns the disagreement set of a set of terms. This will be used in the algorithm developed in Section 5.4 below. Dis : GT-set GT-set if card s 1 Dis s then else if V-Id s t1 t2 s fn t1 then s else SeqDis args t where SeqDis : GT -set GT-set if q SeqDis q then else if Dis hd l l q then SeqDis tl l l q else Dis hd l l q
fn t2 t s
len args t1
len args t2
139
if the supplied set is empty or singleton. If the set contains a variable, Dis returns then all the other terms must disagree with that variable, so Dis returns the whole set. If the set contains a clash, then all the terms are in disagreement, so again Dis returns the whole set. Otherwise, SeqDis works through the arguments of the terms from left to right and returns the leftmost set of disagreeing subterms. Of course, a different function could be chosen which works right to left or even in no particular order at all. Indeed, an implicit specication of SeqDis would not suggest an order. However, this function is really for use in the development of an algorithm later on, so the deterministic denition above will sufce.
Substitutions
A substitution may be viewed as a mapping from V-Id to GT: Subst V-Id
m
GT
When a substitution is applied to a term, all occurrences of variables which appear in both the term and the domain of the substitution are replaced by their images un1 der the substitution. For example, under the substitution x g z y a0 , the term 3 x g1 y z becomes f 3 g1 z g1 a0 z . As in this example, the mapping can be parf tial (i.e. need not apply to all variables in V-Id). It has been shown how cyclic substitutions might arise in the unication process. Such substitutions can be characterized and excluded from the type Subst by means of an invariant, the derivation of which follows. Consider the directed graph of a substitution. Variables and functionals are represented by nodes. Variable nodes each occur only once in the graph. When a variable is in the domain of a substitution it has one outgoing arc pointing to its image. If a variable is in the range of the substitution, it will have at least one incoming arc. Functional terms are represented in the usual way, with a functional node and arcs pointing to arguments. Thus the substitution x g2 a0 y z u has graph: a0 x g2 y This graph is acyclic, and so is the substitution. f 2 x y is cyclic (x on both sides of the same component) The substitution x and so is its graph: f2 y x z u
140
This kind of substitution in which a domain variable occurs in its own image is called directly or immediately cyclic. A more pernicious kind of substitution is the indirectly cyclic type. Here the cycle may not be clear until one examines the graph: x f1 y y x g2 v z f1 u g2 u z u f1 y g2 f1 z z g2 v x
An invariant on Subst is used to characterize and eliminate cyclic substitutions. This is done in the spirit of Jones [Jon90] so that subsequent searches for representation data types can capitalize on this invariant property, though it is quite possible to develop algorithms which do not rely on acyclicity as an invariant on substitutions, and this is just what is done in the development below. A cyclicity testing function could be derived which would search the substitution graph to see if any variable can be reached from itself ([Vad86, Nil84]). The denition of such a function is avoided by using a property of substitutions pointed out by Manna and Waldinger [MW81] and Eder [Ede85]. If a substitution is cyclic then there is a variable in its graph which can be reached from itself. The variables node must have both an incoming and an outgoing arc (the incoming arc shows that the variable is in some term of the substitutions range, while the outgoing arc shows that the variable occurs in the domain of the substitution). If the domain and set of variables in the range are disjoint then there will be no variable nodes with both incoming and outgoing arcs. Hence the substitution represented by the graph will be acyclic. A substitution with this disjointness property will be called var-disjoint. Var-disjoint substitutions are always acyclic, but not all acyclic substitutions are vardisjoint. This is why Vadera [Vad86] argues that his specication of substitutions is more general than that presented here. This is indeed so, but for the purposes of this application, we do not lose out by insisting on var-disjoint substitutions. This point is considered with substitution reduction below. Now for a function describing var-disjointedness: VarDisj : V-Id VarDisj #
m
GT xy
dom #
Occurs x # y
VarDisj # is true if and only if no variable in the domain of # occurs in a term in the range of #. One rule derived from this function denition is used in the proof in Figure 5.1 below.
141
VarDisj -Def
xy
There are some acyclic substitutions which are not var-disjoint. These substitutions have graphs containing paths through one or more domain variables. For example: # y y g1 x x g1 x z a0 z a0 a0 a0
Here the variable x occurs in the domain of # and in a term of the range, yet the substitution is acyclic. Is inv-Subst too strong in excluding this type of substitution? In fact, non-var-disjoint acyclic substitutions can be reduced to var-disjoint ones. For example, # can be reduced to # : # y y g1 a0 x g1 x z a0 z a0 a0 a0 a0
A reduction function which, given a non-var-disjoint acyclic substitution, returns its var-disjoint equivalent can be dened. (Two substitutions are equivalent if, when applied to any term, they yield the same resultant term.) Thus it is possible to show that any non-var-disjoint acyclic substitution has a var-disjoint equivalent. For this reason, the VarDisj invariant on Subst will be used. This may appear to give a simpler specication for substitutions, but there is no such thing as a free lunch. In fact, the gain in the simplicity of substitution application (all of the substitution can be applied at once) may be countered by the complexity of substitution composition, which must preserve var-disjointedness. At this stage in the specication, one can see that var-disjointedness may bring gains in the speed of substitution application, but at the price of maintaining the invariant. This will be a favourable trade-off in applications where substitution application is more important than fast substitution construction or modication. Application of a substitution to a term is simply specied. If the term is a variable in the domain of the substitution then the variable is replaced by its image under the substitution. Var-disjointedness of substitutions ensures that this does not have to be done recursively. If the term is a variable not in the domain of the substitution, then it is unaffected by application of the substitution. If the term is functional, then the function name
142
is unaffected by the substitution, and the arguments all have the substitution applied to t them. Hence we specify the application operator ( ) thus:
t t
: Subst #t
# args t i
t
i
t
dom args t
Inx notation will be used for this function, so for # t , # t is preferred. Application has been explicitly dened, so the denition can be followed through on an example. x mk-FT g1 z . Then: Let t mk-FT f 3 x y z and # #
t
x2
# yz yz
y3
#x yz mk-FT g1 z
1
extends
: Subst #s
GT-set GT-set t # t t s
s
This will also be used in inx form: # s. In the informal development of a simple unication algorithm, it was necessary to combine substitutions in some way. Indeed, this is the case for all unication algorithms which accumulate a unier component by component. An inx composition operator, , can be specied so that for substitutions # #2 , 1 #1 #2 is a substitution which has the same effect on any term as applying # to the 1 term and then applying #2 to the result. So, the composition #1 #2 is a (var-disjoint) t t t #1 t . This gives an obsubstitution r such that for any term t in GT, r t #2 vious post-condition for an implicit specication of . The pre-condition is rather more complex. First, the full function specication is given, and then the derivation of the pre-condition is considered: #1 #2 : Subst r: Subst pre x y dom #1 dom #2 t Occurs x #2 #1
#2
#1
143
#2
#1
The pre-condition on an operation or function specication delimits the domain of states and input values over which the operation or function must be dened. When specifying , it must be ensured that there are no input values for which it is impossible to give an output satisfying the post-condition. This is the essence of the implementability proof obligation in Jones [Jon90]. The pre-condition in the specication of above is there to exclude pairs of substitutions which have no var-disjoint composed form. For example: #1 #2 x u uy wz z f1 x
A composed substitution should map x to w and y to f1 x , but such a substitution would not be var-disjoint. pre- excludes cases like this by requiring that no variables in the input substitutions can participate in a cycle in the result (unless the cycle is a trivial one like x x in which case the component can be eliminated). Var-disjoint substitutions have an interesting property, namely idempotence under substitution composition. In general, x is idempotent under a binary operation if and only if x x x. Var-disjoint substitutions are idempotent under substitution composition (dened below).The reader is invited to formulate and prove this property. It is claimed that pre- is sufciently weak, i.e. no #1 #2 excluded by pre- could have a var-disjoint composed form. See Section 5.6 for a consideration of the proof of this assertion. The claim that all #1 #2 permitted by pre- have var-disjoint composed forms satisfying post- is the implementability proof obligation (see Section 5.3).
Unication
It is now possible to specify unication of a set of terms. A substitution unies a set of terms if and only if applying it to all terms in the set yields the same result. The function unies denes just this: unies : Subst unies # s GT-set t1 t2 s #
t
t1
t2
Again, inx form will be preferred: # unies s. Following this denition, any substitution unies the empty set of terms. The most general unier for a set of terms is that unier from which any other unier of the set may be constructed by composing it with a suitable substitution. The function MGen , given a set of terms and a substitution, checks that the substitution is indeed the most general unier of the set.
Subst $ unies s
"
Subst $
# "
A set of terms is uniable if and only if it has a unier: Uniable : GT-set Uniable s # Subst # unies s
The operation MGU operates over a set of terms, a unier and a boolean ag. If a set of terms s is not uniable, MGU must leave the ag b false. In that case the value of the unifying substitution u is irrelevant and may be arbitrary. If s is uniable, MGU must leave b true and u set to the most general unier of the set. MGU ext rd s : GT-set wr b : wr u : Subst post b MGen u s b Uniable s It is not necessary to write to s to nd a unier and so the operation has read access only (this might be different if the unied term had to be returned). Since a unier is to be constructed in u and the ag b must be set, read and write access is given to them.
145
where % is the state space (including the operation parameters). The extension of this rule to operations with input and result parameters is obvious. When the implementability obligation is discharged, one must show that a result of the appropriate type exists for a given input. This existential proof is often constructive and is thus not very different from the process of building an implementation at the same level of abstraction as the specication. In such situations, the implementation often proceeds given the (strong) feeling that the obligation can be discharged.
i.e. that for any pair of substitutions satisfying pre- it is possible to construct a substitution & which is their composition and so satises post- . The proof is constructive, i.e. for any #1 #2 , a suitable & is constructed. To do this, a function R is dened. It is to be proved that R #1 #2 is a substitution satisfying inv-Subst and, furthermore, post- #1 #2 R #1 #2 holds. First, however, the denition of R: Subst R : Subst Subst R #1 #2 t t v #2 #1 v v
dom #1 dom #2 v
#2
#1
t t
v
t
R #1 #2 maps each variable v in the domains of #1 and #2 to #2 #1 v , unless this would introduce an identity cycle such as x x , in which case the guilty variable is ignored. Consider an example: #1 #2 R #1 #2 x u x f2 u v w a y
2 0 0
y a0
f a v u
The main proof (Figure 5.3) has two parts. Firstly, the invariant preservation proof, that for any #1 #2 Subst, R #1 #2 is still a well-formed substitution:
InvPres-R
This is dealt with separately in Figure 5.1 and is used at line 1.1 in the main proof. Secondly, the proof that R #1 #2 satises post- : post- is a predicate quantied over all t GT, so the structural induction rule GT-Ind introduced above is used. The base case:
146
from #1 #2 Subst pre- #1 #2 t t t 1 v dom #1 dom #2 #2 #1 v GT h, , Subst m 2 R #1 #2 V-Id GT 1, h 3 from x y dom R #1 #2 3.1 x y dom #1 dom #2 h3, R t t 3.2 x #2 #1 x h3, R t t 3.3 R #1 #2 x #2 #1 x h3, R t t 3.4 R #1 #2 y #2 #1 y h3, R t t t t 3.5 Occurs x #2 #1 y x #2 #1 x pre- , -E(h,3.1) x R #1 #2 x 3.6 Occurs x R #1 #2 y =-subs (3.3, =-subs (3.4, 3.5)) =-subs (3.3, 3.2) 3.7 x R #1 #2 x vac -E (3.6, 3.7) infer Occurs x R #1 #2 y x y dom R #1 #2 Occurs x R #1 #2 y -I (3) 4 VarDisj -Def (2, 4) 5 VarDisj R #1 #2 inv-Subst, 2, 5 infer inv-Subst R #1 #2
Base
is shown in Figure 5.2 which contributes line 1.2 to the main proof. The induction step itself is shown in the main proof at 1.4.
Implementability of MGU
At this point it is worth considering the implementability proof for MGU . As MGU is an operation capable of modifying the state on which it operates, the obligation amounts to showing that: # % true # % post-OP # #
A brief examination of this obligation (as expanded by substituting the full postcondition) and an outline of its proof (left as an exercise for the reader) shows that discharging the obligation depends on the proposition that for any uniable set of terms there is a most general unier. The truth of this proposition can be proved by designing
147
from #1 #2 Subst pre- #1 #2 1 R #1 #2 Subst 2 from t V-Id 2.1 from t dom R #1 #2 t 2.1.1 R #1 #2 t R #1 #2 t t t t infer R #1 #2 t #2 #1 t 2.2 from t dom R #1 #2 2.2.1 t dom #1 t dom #2 t #2 2.2.2 from t dom #1 t dom #2 t 2.2.2.1 #1 t t t t t 2.2.2.2 #2 #1 t #2 t t 2.2.2.3 #2 t t t t infer t #2 #1 t t t 2.2.3 t #2 #1 t t 2.2.4 R #1 #2 t t t t t infer R #1 #2 t #2 #1 t t dom R #1 #2 2.3 t dom R #1 #2 t t t infer R #1 #2 t #2 #1 t t t t infer t V-Id R #1 #2 t #2 #1 t
Lemma 1
#1
h2.2, R, h2, -E (h2.2.2), t 2.2.2.1, t h2, -E (h2.2.2), -trans (2.2.2.2, 2.2.2.3) 2.2.1, 2.2.2 t h2.2, 2.2.3, 2.2.4 h2, 1, -E(2.3, 2.1, 2.2) -I(2)
t
Figure5 2 Base base case property for main implementability proof a correct algorithm which generates such a most general unier for any uniable set of terms. This is the subject of Section 5.4.
148
from #1 #2 Subst 1 from pre- #1 #2 1.1 inv-Subst R #1 #2 t t t 1.2 t V-Id R #1 #2 t #2 #1 t 1.3 from t V-Id t t t infer R #1 #2 t #2 #1 t 1.4 from f F-Id l GT inv-FT mk-FT f l t t t a rng l R #1 #2 a #2 #1 a t 1.4.1 R #1 #2 mk-FT f l t mk-FT f i R #1 #2 l i i dom l 1.4.2 from i dom l rng l 1.4.2.1 li t t t infer R #1 #2 li #2 #1 l i t t t 1.4.3 i dom l R #1 #2 li #2 #1 l i t 1.4.4 R #1 #2 mk-FT f l t t mk-FT f i #2 #1 l i i dom l t 1.4.5 #1 mk-FT f l t mk-FT f i #1 l i i dom l t t 1.4.6 #2 #1 mk-FT f l t t mk-FT f i #2 #1 l i i dom i #1 1.4.7
t t
, h1.4
#2 #1 mk-FT f l t t t mk-FT f i #2 #1 l i i dom l 1.4.6, , t t t mk-FT f l #2 #1 mk-FT f l 1.4.7, 1.4.4 infer R #1 #2 t t t 1.5 t GT R #1 #2 t #2 #1 t -I (GT-Ind (1.3, 1.4)) 1.5, 1.6 post- #1 #2 R #1 #2 1.7 R #1 #2 Subst 1.1 -I (1.7, 1.6) infer & Subst post- #1 #2 & t 2 ! pre- #1 #2 , infer pre- #1 #2 & Subst post- #1 #2 & -I (1,2) Figure5 3 Main proof of implementability of substitution composition
149
The algorithm
In Section 5.1 a simple unication algorithm (Algorithm 3) was developed in an ad hoc manner. Now a development can be presented more rigorously, working on the the data types introduced in the specication via the operators also introduced there. As in Algorithm 3, the procedure will be iterative, generating and resolving disagreement sets until either the set of terms reduces to a singleton under application of the constructed substitution or a clash or cycle is found and the set is deemed nonuniable.
Algorithm development
Technique Now that a specication of unication has been given, we can consider the design of an algorithm which meets the specication. In Section 5.1, Algorithm 3 was developed informally, but here the design will proceed in a controlled manner, starting from the specication. We begin with the specication of the operation we wish to implement (in this case MGU) and break it down into structured code in some suitable implementation language. The development proceeds in stages. For example, if we are developing an algorithm similar to Algorithm 3 above, we can break MGU into two operations which are sequentially composed: ;
Initialization will itself be broken down into sequentially composed assignments while MainPhase employs a while-loop whose body breaks down into nested conditionals and
so on. This process of breaking an operation down into component operations linked by combinators is called operation decomposition. The combinators are usually based on constructs of an implementation language, but need not be so concrete. Successive decompositions can be used to eliminate the more abstract combinators so that the fully decomposed operation specication is a program in the implementation language. At each step in a decomposition, the code designer chooses to introduce a new construct from a range of alternatives. The step involves a design decision and in a rigorous development such design decisions must be shown to preserve the properties of the specication which forms the input to the decomposition step. Thus each step generates a proof obligation. The behaviour of each construct in the combinator/implementation language is described by rules which are used to justify the decomposition step. What do the operation decomposition rules look like? It is possible to comment a program with assertions over the state variables. Operation decomposition rules allow the manipulation of these assertions. The set of rules used in a development clearly depend on the particular implementation language chosen. For the purposes of this case study, the rules needed are as follows.
150 Assignment.
-I
WD e
E x:
e x
E x x
where E x x is E with all free xs replaced by x . Thus if E is asserted before an assignment, it can, properly qualied, be asserted afterwards. WD e indicates that e should denote a proper value (i.e. it should not be undened). Strictly, there is a class of such assignment rules, one for each possible type. Thus if T is the class of all types, then for each T: T .
: -I
E x:
e x
E x x
Conditional.
if-I
pre test TH post ; pre test EL post pre if test then TH else EL post
In order to introduce a conditional given pre, show that the post-assertion holds in both limbs separately. inv test S inv rel inv while test do S end inv rel
Iteration.
while-I
test
inv is an invariant predicate which is true before and after each iteration of the loop. The predicate rel denotes a well-founded and transitive relation on states before and after execution on the loop body. rel is its reexive closure. pre1 S1 post1 pre2 ; pre2 S2 post2 pre1 S1 ; S2 post1 post2
;-I
#i
% post1 # #i
post2 #i #
The hypotheses ensure that the two operations S and S2 can be connected sequentially, 1 i.e. that S1 sets up a state in which S2 is dened. The conclusion states that there is then an intermediate state linking the state before S ; S2 to that after. Note that if post1 1 and post2 are single-state predicates, so that they refer only to # and not to # , this rule simplies to
;-I
pres
If S satises a specication then it satises a weaker specication. s ; pre v s S post pre let v s in S post
Nondeterministic choice.
let-I
This rule does not appear in [Jon90]. It allows the introduction of a nondeterministic choice construct provided the set over which selection is made is nonempty. pre S post pre S pre post
Inheritance.
pre
This allows the strengthening of a post-assertion by addition of the pre-assertion with all the free variables hooked. Note that for any variable v to which the S operation has only v. We will tend to use this fact implicitly below. rd or no access, v The development As has been indicated above, the development process involves the manipulation of assertions about the state and program variables. We kick this process off by using the pre- and post-conditions of the operation we wish to implement. MGUAlg will be correct with respect to the specication of MGU if, for all starting states satisfying pre-MGU , the algorithm terminates and does so with a state satisfying post-MGU . Note that post-MGU is a single-state predicate so we may write post-MGU s b u instead of post-MGU s b u s b u . Note that since s is a can use the fact that s s when appropriate. Thus the following should hold: true -only component of the state, we
post-MGU s b u
We must construct a proof which concludes this from denitions. The rst development step breaks MGUAlg into an initialization phase and a main processing phase (the loop which will construct the unier). Then: true ; post-MGU s b u
This decomposition has to be justied by the ;-I rule. Our proof is then of the form shown in Figure 5.4. The lemmas1 used in Figure 5.4 are:
152
; post-MGU s b u
infer true
post-MGU s b u
from Denitions 1 WD 2 WD true WD true 3 true 4 u true WD true u 5 WD true u: u true true u: WD true u 6 WD true u b: true b true u 7 ; b: true u b true infer true u:
post-MGU s b u
Lemma 5.1s proof justies the development of Initialization and Lemma 5.2s that of MainPhase. First consider Initialization. It can be decomposed into: true u: ; b: true u b
The proof of Lemma 5.1 in Figure 5.5 is one possible justication for this decomposition. In the rest of this study, arguments relating to the denedness of assigned expressions will be suppressed to avoid obscuring the substance of the development. Now for the (more complex) decomposition of MainPhase. It is intended that, as in Algorithm 3, MainPhase be a loop which generates disagreements and tries to resolve
1 In
153
inv
Figure5 6 Justifying the while loop introduction them, adding a new component to u each time (unless a clash or cycle is detected). So one possible decomposition of MainPhase is as follows: u b card u
s
1 b
post-MGU s b u We would like to use while-I to justify this decomposition via a proof of Lemma 5.2 of s the form shown in Figure 5.6 (where test stands for card u s 1 b) and the lemmas used are: inv test inv rel (5.3) u inv test rel b inv post-MGU s b u (5.4) (5.5)
Now inv and rel must be chosen so that Lemmas 5.4 and 5.5 are satised and Body must be developed so that Lemma 5.3 holds. The relation rel should be well-founded, relating states at the beginning of each execution of the loop body to the corresponding states at the end of the loop body. It describes the possible state transitions caused by the loop body. It should refer to a decreasing quantity in the system and should not have an innitely descending chain of values of that quantity, so that termination of the loop can be proved. In the case of Body, two possible kinds of state transitions have to be described: either the terms are found to be nonuniable (clash or cycle discovered) and b is set false to force termination or s a disagreement is resolved and the number of variables in u s is reduced (since the new substitution component replaces the variable in the disagreement with a term which s introduces no new variables). The number of variables in u s has to be at least zero, 2 so the following well-founded transitive rel is suggested:
2 The
interested reader may care to prove the well-foundedness and transitivity of this relation.
154 rel b b b b NV u
s
NV u
What factors need to be invariant over all iterations of MainPhase? These form inv. As the loop executes, disagreements are resolved and each resolution brings u closer to being a most general unier for s and if b is ever set false then s is not uniable. inv $ b Subst $ unies s Uniable s " Subst $ u "
Does this choice of inv and rel satisfy the criteria imposed by Lemmas 5.4 and 5.5? then $ itself is a suitable " in inv since $ Lemma 5.4 holds because if u The second conjunct of inv is vacuously true because b is true. Lemma 5.5 holds because if inv Case: if b then card u Case: if
s
".
card u
1 b
rel then:
These two cases construct post-MGU s b u . So now we have an inv and rel which can serve for the development of the loop body. s Body is to be lled out so that the following holds where test card u s 1 b: inv test inv rel
The body must check the disagreement set for clashes of function symbols and cycles. If none are found, a new component must be added to u. Let the cycle and clash checks be done by nested if-statements. Firstly the clash check: inv test if V-Id Dis u inv rel This decomposition can be proved valid (using if-I) if Lemmas 5.6 and 5.7 hold: inv test V-Id Dis u
s s
b:
false
s
s
b: s
(5.6)
(5.7)
155
from Denitions WD 1 WD false WD false Uniable s b: false Uniable s b : -I 2 Uniable s WD false Uniable s 1, , 3 4 Uniable s b: false Uniable s b weaken(3,2) s 5 inv test V-Id Dis u s b: false Uniable s b weaken (Lemma 5.8, 4) s 6 inv test V-Id Dis u s b: false inv test V-Id Dis u s s infer inv test V-Id Dis u s
s
Figure 5.7 Proving the rst conditional limb One proof of Lemma 5.6 using : -I, weaken and pre is shown in Figure 5.7. Note that the lemmas required by this proof are really facts about the data types and operations in the specication. They can be proved separately, independent of the algorithm development and operation decomposition rules. Since at this point we can stop using the operation decomposition rules and appeal to the theory associated with the original specication, we call these terminal lemmas. They are: inv test V-Id Dis u inv test V-Id Dis u
s s
s Uniable s
(5.8) (5.9)
s
The proof of Lemma 5.8 depends on the fact that if there are no variables in Dis u s then s is not uniable because a clash has been detected. For Lemma 5.9, since s is not uniable, inv holds. rel holds after the assignment because b has been changed from true to false. Proving Lemma 5.7 guides the development of CycleCheck. The idea is to select a variable from the disagreement set (using nondeterministic choice) and then check for a term containing it in the disagreement set. The presence of such a term means the
156
original set of terms was un-uniable. First, the introduction of the let statement: inv test V-Id Dis u s v V-Id Dis u s inv rel For this to be a correct decomposition (by let-I) we require that: inv test V-Id Dis u inv rel Now let be a conditional which looks for a potential cycle. If none is found, resolve a disagreement. So we will have: inv test V-Id Dis u s v s if t Dis u s v Occurs v t inv rel If this is to be a valid decomposition (by if-I), the following two lemmas must hold: inv test V-Id Dis u s v s t Dis u s v Occurs v t b: false inv rel inv test V-Id Dis u s v s t Dis u s v Occurs v t inv rel Discharging 5.10 proceeds in a similar way to 5.6, and the terminal lemmas are: inv test V-Id Dis u s v s t Dis u s v Occurs v t Uniable s inv test V-Id Dis u s v s t Dis u s v Occurs v t Uniable s b inv rel
s s s s s s s s
V-Id Dis u
V-Id Dis u
s (5.10)
V-Id Dis u
s (5.11)
V-Id Dis u
s (5.12)
V-Id Dis u
s (5.13)
157
v The proof of Lemma 5.12 depends on the fact that if there is a term t in Dis u s 3 containing v then the original set s is not uniable. Given this we can show Lemma 5.13. inv holds because s has no uniers and rel holds because b has been set to false. The proof of Lemma 5.11 governs the decomposition of Resolve. Resolve will (nons v and compose v t into u. deterministically) select a term t from Dis u s Lemma 5.11 would then be: inv test V-Id Dis u s v V-Id Dis u s t Dis u s v Occurs v t s t t Dis u s v Occurs v t u: R u v t inv rel
s s
For this to be a valid decomposition (by let-I) the following must hold: inv test V-Id Dis u s v V-Id Dis u s t Dis u s v Occurs v t s t t Dis u s v Occurs v t u: R u v t inv rel
s s
s (5.14)
Let the pre-assignment assertion be called X for brevity. To show the validity of this decomposition, use : -I, weaken and pre in the usual way, the terminal lemmas being: X X u u u WD R u R u v v t t inv rel (5.15) (5.16)
Discharging Lemma 5.15 involves showing that u and v t are indeed well-formed substitutions. Discharging Lemma 5.16 amounts to showing that, for any substitution $ unifying s which could be constructed from u, $ can still be constructed from u. This construction is, in fact, unchanged. It is also necessary (for rel) to show a reduction in s s s, v occurs the number of variables in u s. Since v and t are drawn from terms in u s s s. v does not occur in t so replacing all occurrences of v in u s in a term in u s s which were not there already and will by t will not introduce any variables into u s s s NV u s . eliminate v altogether. Hence NV u We have now shown inv test inv rel and so by while-I: inv
3 Again,
inv
test rel
158
as required, and the development is completed as per the proof outlined at the beginning of the decomposition. The nal algorithm is:
Algorithm MGUAlg ext rd s: GT-set wr b: wr u: Subst
; true; s while card u s 1 b s if V-Id Dis u s then b: false s else let v V-Id Dis u s in s if t Dis u s Occurs v t then b: false s else let t t Dis u s Occurs v t in u: R u v t u: b:
endwhile End MGUAlg
It is worth standing back from the minutiae of the development illustrated above to look at the process of development itself. Each program construct introduced represented a design decision. Each design decision generated a proof obligation to justify the introduction by the operation decomposition rules. The chain of design decisions involved in the development of the algorithm terminated when the obligation could be proved by appealing to properties of the data types and operations on which the algorithm was based. These properties are then proved separately (perhaps using a natural deduction format). Examples of such terminal obligations are 5.8, 5.12 and 5.15. The use of the operation decomposition rules restricts the freedom of the algorithm designer at the point of each design decision to only those possible design options which preserve the truth of the required assertions. This chains back all the way through the development, so that the only justiable designs are those which respect the original assertions imposed at the start of the development, namely the pre- and post-conditions on the specication of the implemented operation.
5.5 Conclusions
About specication
It is worth considering the process by which the specication was derived, as it illustrates a few interesting points. The brevity of the specication itself is in stark contrast to the amount of time taken over its construction. A rst attempt at the specication yielded a simple, but faulty, product. Subsequently it grew more complex, including features
5.5 Conclusions
159
like a cyclicity testing function for substitutions. After a certain level of complexity had been reached, it became more apparent that a simpler specication (which still dealt with acyclic substitutions) would result from using ideas like the idempotence property. Introducing the idempotence invariant on substitutions did have a complicating effect on the specications explanation, necessitating the introduction of ideas such as vardisjointedness and substitution reduction. It is often the case that devoting a little extra time to the specication phase in a rigorous development produces a more considered, and possibly much simplied, result for delivery to the developer. It is noted (Section 5.2) that the idempotence (var-disjointedness) requirement on substitutions is a restriction on this theory of unication. Idempotence is documented as an invariant primarily for the benet of further development. The algorithm developed does not use the property, but other algorithms might use results from a theory of unication which does exploit idempotence. However, the aim of this case study is not to develop such a theory, but rather to develop a specication for practical use. inv-Subst may reduce the generality of substitutions permitted, but the excluded substitutions can be reduced to an acceptable form. Only some simple proofs of properties about the specication have been shown, and those not in great depth. It is worth noting that the level of detail required in proofs should be decided with an awareness of the consequences of opting for low-level detailed proofs in terms of the effort required. These proofs are often long and routine, requiring relatively little mathematical insight, a characteristic which makes their development susceptible to automated assistance [JL88]. Implementability proofs play an important role in this study. In the case of substitution composition, an implementation (the function R) is developed in the proof. This method is related to the constructive mathematics approach illustrated in [MW80, MW81, C 86]. Development can be viewed as the constructive discharging of the implementability proof, but there are major pragmatic differences discharge the implementability obligation at an abstratct level and actually going about the development of executable code. For example, R may not be directly executable in the language or on the machine of our choice. It merely shows the existence of an implementation dened on the data types of the specication. The algorithm MGUAlg, based round more classical imperative programming constructs, may be nearer executable code for a particular application. Operation decomposition would not be an appropriate technique for constructing the abstract proof of MGU implementability. Certainly the development of an implementation does discharge the implementability obligation, but failure to attempt the implementability proof at the abstract level of a specication can result in a huge amount of wasted development time if it transpires that no implementation exists.
160
About development
This intimate connection between development and proof has other consequences. The author freely confesses great difculty experienced in choosing how to present the development of Section 5.4. Should one begin with the terminal lemmas and provide a bottom-up construction, building the necessary program constructs? No, for who would begin a development by producing Lemma 5.15 out of thin air? The development process itself is not purely bottom-up. Nor is it purely top-down: the designer does not groundlessly choose to introduce a conditional construct here and a while-loop there. In this study an attempt has been made to steer a middle course. The overall development is top-down in that it decomposes the specication of MGU , but individual steps have been bottom-up, introducing constructs derived from the informally developed algorithm of Section 5.1. It is important to note, however, that a formal development is more than just a pretty way of documenting the design. It is suggested in Section 5.1 that the hack it until you think its right approach to algorithm design may benet from some formalism. Controlled development from a formal specication allows real conviction of the algorithms correctness to be gained. But how does one gain conviction of the specications correctness? Has the hack it approach only been shifted out of the implementation phase and put into the specication phase of development? The interface between intuitive ideas and formalism must come somewhere. The advantage of the approach described here is that there are obligations to be met by the specication. The proofs of obligations provide an environment in which the details of the specication can be opened to systematic scrutiny in a way in which raw code cannot. Faults discovered at this stage can be corrected before they reach code. This method results in a top-down approach to proving lemmas about the data objects and operations in the specication. Only those properties required for the main obligation-discharging proof are proved.
161
acyclic graph structure for terms discussed in Section 5.1. There are several other areas into which the approach described here on modeloriented specications of unication might extend. For example: The extension of the specication to allow equational theories on rst order terms: particular properties (such as associativity) can be built into a unication algorithm [Bun83]. A universal unication algorithm is one which, given a set of terms and a theory, returns a complete set of uniers for the terms within the theory [Sie84]. One approach to specifying this might be the representation of equational axioms as sets of rewrite rules. The semidecidable problem of unication of second order terms: Bundy [Bun83] presents an algorithm due to Huet which incorporates the '-,(- and )- rules of "-calculus. The specication of this sort of problem might require not only the specication of a data type for second order terms, but the incorporation of equational axioms as well.
#1 #2 . Then:
t
#1
#2
#1
Occurs x #2
#1
#2
#1
and consider any substitution r: Case x dom r and y dom r. 1.1 r Subst, so Var-Disj r 1.2 So x y dom r Occurs x r y 1.3 In particular Occurs x r y
162
t t
1.4 and Occurs x r y since r y r y by denition of . t t t t t So r y #2 #1 y because otherwise (by assumption) Occurs x #2 #1 y ; t hence Occurs x r y , which would contradict line 1.4 above. Case x dom r and y dom r. t t 2.1 r y y by denition of 2.2 x y, by the case assumption Occurs x y by denition of Occurs 2.3 t 2.4 Occurs x r y by line 2.1 above t t t t t So r y #2 #1 y because otherwise (by assumption) Occurs x #2 #1 y ; t hence Occurs x r y , which would contradict line 2.4 above. Case x dom r t t 3.1 r x x by denition of t t t 3.2 So r x #2 #1 x by assumptions. Thus, in this case, x is a term for which r does not generate the same result as applying #1 and then #2 . So when x dom r, post- does not hold. This exhausts the possible cases. Thus under the current assumption, there is a term (x or y) for which r does not generate the same result as applying #1 and then #2 . By case distinction, for any r, post- does not hold. It is, therefore, not possible to generate a suitable r when the assumption pre- # #2 holds. Hence 1 #1 #2 Subst pre#1 #2 r Subst post#1 #2 r
Acknowledgements
The work described here was begun as an undergraduate project in the Computing & Information Systems degree course at Manchester University. The author owes a debt of gratitude to Ursula Martin and Cliff Jones for their careful supervision. Thanks are also due to Tim Clement, Peter Lindsay, Steve Palmer and Ralf Kneuper for their helpful comments. This work has been nanced by the Department of Education for Northern Ireland.
The same application is addressed here as in the previous chapter. The emphasis in Sunil Vaderas work is on building a theory of the basic concepts which are discussed in the specication and development. Sunil Vaderas work was done independntly of John Fitzgeralds and a comparison of the two chapters well illustrates the point that there is no single right approach to a specication. The chapters can be read independntly but a careful comparison pinpoints interesting differences like the precise invariant on substitution mappings. The algorithm developed in this chapter is quite space efcient.
163
164
6.1 Introduction
Unication is an important concept. It is used in Prolog, resolution, term rewriting, and natural language understanding. As the use of formal methods increase, unication will be part of formally developed systems. Hence a theory of unication is desirable. We use VDM to formalize unication. We dene substitution application recursively, develop a theory of noncircular substitutions, and write an implicit specication of unication. Some example proofs are presented in the theory. The correctness of a particular unication algorithm is proved with respect to the specication. The algorithm proved is more space efcient than the one proved by Manna and Waldinger. We also compare the theory developed with that of Manna and Waldinger and present some advantages of using VDM. The unication algorithm is used in many systems. It is used in resolution [Rob65] and term rewriting [HO80] approaches to theorem proving. It is a key feature of the programming language Prolog [CM84]. It is used in natural language understanding [SA77]. Siekmann [Sie84] describes the uses of unication, and Fitzgerald (see Chapter 5 of this book) lists the applications. The systems that use unication obviously rely on its correctness, and on specic properties of unication. Further, as the use of formal methods of software development increase, unication will be part of systems which are developed formally (e.g. [Nil84]). Hence, we develop a theory of unication. Section 6.1 summarizes some conventions, and the induction rule that we use. It also introduces the main ideas of unication. These ideas are then formalized in sections 6.2 to 6.6. Section 6.7 uses this formalization to prove a particular unication algorithm correct. Section 6.8 compares the theory developed with that of Manna and Waldinger [MW81]. In formalizing our notion of unication, we also present the proofs of some lemmas. For conciseness, we omit a number of proofs. These can be found in Vadera [Vad86].
Some conventions
Proof obligation To show that a function, f with domain Tp and range Tr satises a specication, we have to prove: p Tp pre-f p post-f p f p f p Tr
When the pre-condition is true, and the result is clearly of the right type, we will write this in the more compact form: post-f p f p .
6.1 Introduction
Induction
165
Mathematical induction is a technique of proving that a property P holds for the set of , we rst show that P 0 is true. natural numbers. To show that P n is true for all n Then, we show that P j is true under the assumption that P k is true for all k j, where j 0. To use induction on a set other than , say D, we dene a total function which maps the elements of D onto . We also use induction on 1 , and on 1. Proof presentation We present proofs as in [Jon86a]. However, when referencing a line in a justication we adopt the convention that n refers to a line m n where m refers to the enclosing from/infer box. This helps to reduce references like 2.2.3.2.3.2 in a deep proof.
Introduction to unication
A number of problem solving tasks can be posed as nding a proof for a theorem in predicate calculus. When proving theorems, it is often necessary to unify certain expressions. For example, given good-student jim and good-student X pass X
we want to show that pass jim is true. We rst have to unify good-student X with good-student jim . We can do this by jim . We setting the variable X to jim. We can record this fact in a substitution: X call such a substitution a unier of the two terms. We can now apply the substitution to pass X , and eliminate the implication to prove pass jim . good-student X In general, both the terms to be unied may contain variables. For example, the 1 . terms line X 1 and line 2 Y have a unier X 2 Y Of course, it is not always possible to unify two terms. Thus line X X and line 1 2 cannot be unied. Further, the unication process must nd the most general unier. For example, although the terms line X and line Y can be unied by an innite set of uniers: X 1Y 1 X 2Y 2
166
Most General Uniers Uniers Substitutions Terms sec 6.2 sec 6.3 sec 6.4 sec 6.5
Figure6 1 Layer by layer formalization When formalizing unication, we must also decide whether our theory will cater for circular substitutions like X f X . We formalize these ideas in a layer by layer manner as shown in Figure 6.1. We begin by developing a theory of terms. The theory of substitutions formalizes the notions of substitution application, circular substitutions, substitution equality, substitution composition, and idempotent substitutions. The concepts of a substitution being a unier and a most general unier are then formalized.
6.2 Terms
Abstract syntax
Terms are the basic objects that are unied. A term may be a compound term, or a variable. A compound term is one which has a function name followed by a sequence of terms. We specify terms by: Term Cmpterm Var
6.2 Terms
Var Fid Ident
167
tn , and lists of terms by tl tl1 tl2 tln . Variables We denote terms by t1 t2 vn , or by capital letters. For readability, we prefer to write a are denoted by v v1 well-formed term: mk-Cmpterm person mk-Cmpterm age X in the concrete syntax: person age X
Properties of terms
There are a number of properties of terms that we may believe to be true. Thus, the property the variables in the head of a list of terms is a subset of the variables in the list of terms is intuitively true. To formalize such properties, we dene the functions: vars-Term : Term Var-set vars-Term t cases t of vars-Terms tl mk-Cmpterm d tl v v end vars-Terms : Terms vars-Terms tl Var-set vars-Term tl i
inds tl
vars-Term and vars-Terms are abbreviated to vars when it is obvious which is meant. Thus, vars X f Y g Z X Y Z
We can now write the above property as: len tl 0 vars hd tl vars tl
Notice that we make use of the logic of partial functions. Since, when tl is the empty . Which, by the logic of partial list, hd tl is undened and we have a situation false functions, is true. To carry out the proofs by induction, we will need to order the terms. This is achieved by mapping the terms to natural numbers by the functions:
168 tm 1 len tl tm 2 len tl tm 3 len tl tm 4 len tl 0 0 0 0 vars hd tl vars tl tl vars tl vars tl no-Terms tl no-Terms tl
no-Term hd tl no-Terms tl tl
Figure6 2 Lemmas about terms no-Term : Terms 1 no-Term t cases t of mk-Cmpterm d tl v end no-Terms : Terms no-Terms tl if tl then 0 else no-Terms tl tl
no-Terms tl 1
no-Term hd tl
Thus, no-Term f Y g Z 4. Lemmas about terms are straightforward and are listed in Figure 6.2.
6.3 Substitutions
Abstract syntax
A substitution records the bindings of a variable to a term. Hence, a natural VDM specication for substitutions uses maps: Subst Var
m
Term
VDMs dom operator can be used to obtain the variables in the domain of the substitution. The variables in the range of a substitution can be obtained by applying the
6.3 Substitutions
function: range : Subst range s Thus range s s X Var-set vars s v v dom s
169
For the union of two maps to be dened, their domains must be disjoint. Hence we dene: dom-disjoint : Subst dom-disjoint s1 s2 Subst dom s1 dom s2
We will also encounter situations where we discuss a substitution whose domain is disjoint from the range of another. Hence we dene: dom-range-disjoint : Subst dom-range-disjoint s1 s2 Subst dom s1 range s2 Q f X , then dom-disjoint s1 s2
Substitution application
Applying the substitution: s= X f Y Z g
to a term has the effect of replacing any Xs by f Y , and any Zs by g. Thus applying s to t X f Z g results in the term t f Y f g g . However, what is the result of applying X f Z Z g to t X f Z g
If we simply replace the variables with their associated term in the range, we obtain t f Z f g g . Do we now replace the Z in this term by g? Some authors [Ede85, MW81] dene substitution application so that this further replacement is not done. As we shall see, this constrains their specication to the extent that the unication algorithm we prove does not satisfy their specication. Hence, we dene substitution application recursively:
ap 5 vars ts ap 6 vars ts
vars t
range s
Figure6 3 Lemmas about substitution application apply-sub : Term Subst apply-sub t s cases t of mk-Cmpterm d tl1 Term
v end
let tl2 apply-sub tl i s i inds tl in mk-Cmpterm d tl2 if v dom s then apply-sub s v v s else t
Thus, t X f Z g X f Z Z g t f g f gg . Lemmas about substitutions are listed in Figure 6.3. For example, Lemma ap4 states that substitution application does not remove those variables which are not in the domain of the substitution. A proof of ap4 is given in Figure 6.4. The proof proceeds by induction on no-Term t . The base case is proved by line 1, and the induction step is proved by line 2. The base case distinguishes between two cases. First, when t is a variable, line 1.2.2 proves the consequence of ap4 from the antecedent of ap4. It achieves this by the fact that t must be v, and that applying s does not remove v. Line 1.2 then introduces the implication to obtain ap4 from line 1.2.2. Second, when t is a compound term, line 1.3 proves ap4 by showing that the antecedent of ap4 is false since there are no variables in t. The induction step is carried out by rst showing that the induction hypothesis can be applied to all subterms of t (line 2.3) and then proving the consequence of ap4 from
6.3 Substitutions
171
from true 1 1 from no-Term t (h1,no-Term) 1.1 t Var t Cmpterm 1.2 from t Var 1.2.1 vars t t (vars, h1.2) 1.2.2 from v dom s v vars t 1.2.2.1 t v (1.2.1, h1.2.2, ) (1.2.1, .1, h1.2.2, ) 1.2.2.2 dom s vars t (.2, ap3, -E, .1) 1.2.2.3 ts v (vars, .3, ) infer v vars ts infer ap4 ( -I, ! h1 2 2 ,1.2.2) 1.3 from t Cmpterm (h1.3, h1, no-Term) 1.3.1 t Cmpterm d (1.3.1, vars) 1.3.2 vars t infer ap4 (vars, vac-I) infer ap4 (1.1,1.2,1.3, -E) n n 1 no-Term t n 2 from ap4 true for all no-Term t 1 (h2) 2.1 no-Term t (2.1, no-Term) 2.2 let t mk-Cmpterm d tl in i inds tl no-Term tl i n 2.3 (2.2,tm5,tm3,tm4, no-Terms, h2) vars tl (2.2, tm6) 2.4 vars t 2.5 from v vars t v dom s (h2.5, 2.4) 2.5.1 v vars tl i inds tl v vars tl i (2.5.1, tm7) 2.5.2 i inds tl v vars tl i s (h2.5,2.3,2.5.2,h2) 2.5.3 (2.5.3,tm7) 2.5.4 v vars tls (2.2,2.5.4,tm6) infer v vars ts n (2.5, -I) infer ap4 for no-Term t infer ap4 (1,2, induction)
Figure6 4 Proof of ap4 the antecedent of ap4 (line 2.5). This is done by applying the induction hypothesis to a subterm of t to obtain the consequence for the subterm (line 2.5.3). Lemmas tm7 and tm6 are then used to convert this into the consequence of ap4 for t.
172
Circularity
Notice that the above denition of apply-sub removes the possibility of nontermination in cases like: s X f Y Y gX and Xs produces f g X
Substitutions like s are known as circular since their graph is circular. Circular substitutions can arise when we attempt to unify terms. For example, consider an attempt to unify the terms: t1 t X Y t2 t f Y gX
The rst components of t can be unied by X f Y . Now the second components g X . However, when these two substitutions are comof t could be unied by Y bined by taking their union, we obtain a circular substitution X f Y Y g X . To formalize our notions of circularity we introduce a function: reach : Var Var Subst reach v1 v2 s if v1 dom s then false else let vset vars s v1 in if v2 vset then true else v3 vset reach v3 v2 v1
Figure 6.5 lists some properties of reach. We examine the rst lemma below, but leave the others as exercises for the reader (see [Vad86] if your theorem prover fails). Lemma re1 relates the ideas of reachability and substitution application. It states that the variables left after applying a substitution to v are reachable from v1 provided that 1 f Y Y g X ), v1 is in the domain of the substitution. Thus, since X vars X X g X ). we may conclude that reach X X X f Y Y We present a proof of Lemma re1 in Figure 6.6. The proof proceeds by induction on card s. The base case is straightforward since an empty substitution means that the antecedent of re1 is false. The inductive step is carried out by proving the consequent of re1 from its antecedent (line 2.1). To use the induction hypothesis we must reduce the size of the substitution. We do this by unfolding apply-sub to obtain line 2.1.1. However, this is still not in the form required by the second conjunct of the induction hypothesis since s v may be a 1 term. Fortunately, by Lemma ap5, there must be a variable in s v such that applying 1 s to it results in a term which contains v2 . We consider two cases the substitution v1 for such a variable. First, when it is v2 , line 2.1.3.2 obtains reach v1 v2 s by folding
6.3 Substitutions
re 1 v1 dom s v2 vars v1 s reach v2 v3 s reach v1 v2 s1 reach v1 v2 s reach v1 v3 s reach v1 v2 s1 s2
173
re 2 reach v1 v2 s
re 3 dom-disjoint s1 s2 re 4 v1
dom s1 v2 dom s2 dom-disjoint s1 s2 v3 dom s2 reach v1 v3 s1 s2 reach v3 v2 s1 s2 reach v1 v2 s1 s2 reach v1 v2 s1 v1 dom s1 v2 dom s1 reach v1 v2 s1 v3 vars v1 s1 reach v3 v2 s1 s2 s2 s2
the denition of reach. Second, when it is not v2 , lines 2.1.3.3.1 and 2.1.3.3.2 show that this variable must be in the domain of v1 s. Line 2.1.3.3.3 can then use the induction hypothesis and the -E rule to deduce that v2 is reachable from this variable in v1 s. We then use the denition of reach to obtain reach v v2 s . 1 We now return to use reach to dene circularity: circular : Subst circular s v dom s reach v v s
For conciseness, we will denote noncircular substitutions by $, $ , . . . $n. We are 1 now in a position to examine some properties of noncircular substitutions. Given a noncircular substitution, we can partition the substitution into two noncircular substitutions using the lemma: cr 1 dom-disjoint s1 s2 circular s1 s2 circular s1 circular s2
As the example at the start of this section illustrated, the union of two noncircular substitutions is not necessarily noncircular. However, if their domains are disjoint, and the domain of one of the substitutions is disjoint from the range of the other substitution, then their union will also be noncircular: cr 2 dom-disjoint $1 $2 dom-range-disjoint $1 $2 circular $1 $2
174
from true 1 from card s 0 infer re1 2 from re1 is true for all card s n n 0 card s n 2.1 from v1 dom s v2 vars v1 s 2.1.1 v2 vars s v1 v1 s vars v3 v1 s v3 vars s v1 2.1.2 v2 s v3 vars s v1 2.1.3 from v2 vars v3 v1 2.1.3.1 v3 v2 v3 v2 2.1.3.2 from v3 v2 2.1.3.2.1 v2 vars s v1 infer reach v1 v2 s 2.1.3.3 from v3 v2 2.1.3.3.1 from v3 dom v1 s 2.1.3.3.1.1 v3 v1 s v3 s infer v2 vars v3 v1 s 2.1.3.3.2 v3 dom v1 s 2.1.3.3.3 reach v3 v2 v1 infer reach v1 v2 s infer reach v1 v2 s infer reach v1 v2 s infer re1 true for card s n infer re1
(h2.1.3.2,h2.1.3) (2.1.3.2.1,reach)
(h2.1.3.3.1, ap3) (.1, vars, h2.1.3.3) (.1, h2.1.3,contra) (.2,h2.1.3, h2) (h2.1.3, .3, reach) (.1, .2, .3, -E) (2.1.2, 2.1.3) (2.1,!(h2.1) -I) (induction, 1, 2)
are noncircular substitutions, whose domains are disjoint, and the variables in the second substitutions range do not occur in the domain of the rst substitution, we can conclude that their union: X f Y Y gZ W Y Z gV
is noncircular. Lemmas cr1 and cr2 do not allow us to conclude that the union of the substitutions
6.3 Substitutions
X f Y and Y Z P can reach this conclusion by: cr 3 dom-disjoint $1 $2 where reduce : Subst reduce s1 s2 Subst v Subst s1 v s2 v dom s1
We restrict ourselves to noncircular substitutions although algorithms for producing circular substitutions do exist (see [Fil84]). An elegant property, which is true for noncircular substitutions, but does not hold for circular substitutions is: ap8 v dom $ v vars t$
Thus, this does not hold for the circular substitution X since X f X vars X X f X .
Equality
We dene two substitutions to be equivalent if substitution application has the same effect on any term: equal-sub : Subst equal-sub s1 s1 Subst t ts1 ts2 s2 . Thus, for example,
Instead of using the denition to show that two substitutions are equal, we can use the result: eq 1 s1 s2 v Var vs1 vs2
Composition
Consider how we could proceed to unify the terms: t f X g X and t2 f a Y . 1 a . In the context of this substitution, we We can unify the rst components by X can unify the second components by Y g a . Now applying these two substitutions a Y ga t2 X a Y ga in sequence unies the two terms: t1 X f aga . Now since we seek one substitution to unify t1 and t2 , we would like a substitution which has the same effect as applying the two substitutions in sequence. In our example, the obvious choice is X aY g a . However, X aY g X also has the same effect. Hence, we say that a substitution s3 is a composition of two substitutions s1 and s2 , written s1 s2 , if: t ts1 s2 Y ts3
In the above example, we obtained the composition of the substitutions X a and f a by simply taking their union. However, if we do this for the substitutions: X f Y and Z X
we obtain X f Y Z X
We therefore develop the lemmas given in Figure 6.7 to guide us when composing substitutions. In particular, Lemma cp4 allows us to deduce that: X a Y f a X aY f X
6.4 Uniers
cp 1 $ $ $ reduce reduce $1 $2 $3 t$ treduce $ v x
177
cp 2 reduce $1 $2 $3 cp 3 v dom $ v
vars t$
id 2 dom-range-disjoint s s id 3 $2 reduce $1 $1
Idempotence
Idempotence does not play a signicant role in our theory. However, we include it to relate to the work of Manna and Waldinger [MW81]. s. Manna and Waldinger We dene a substitution s to be idempotent if reduce s s dene a substitution, s to be idempotent if s s s. With our recursive denition of apply-sub, all noncircular substitutions would be idempotent if we adopted their denition (by Lemma cp1), and idempotent substitutions in our theory would not be idempotent in Manna and Waldingers theory. Lemmas about idempotence are given in Figure 6.8.
6.4 Uniers
A substitution $, is a unier of two terms, t1 and t2 if: unier : Term Term Subst unier t1 t2 $ t1 $ t2 $
vars t
are both uniers of the terms: g, and X. Two useful lemmas about uniers are given in Figure 6.9. As mentioned in the introduction, a unication algorithm must produce a most general unier (when one exists). We therefore need to formalize the notions of generality. We say that a substitution $1 is more general than another substitution $ if: 2 more-general : Subst more-general $1 $2 We write $1 X since X f Y X X f Y f (by Lemma cp4) f $2 , or $2 X f Y Subst $ $2 $1 $ $1 for more-general $1 $2 . For example: X
Given a unier, $1 , of two terms t1 , and t2 , any substitution which is less general than $1 is also a unier of t1 and t2 . More formally: gn 2 $2 $1 unier t1 t2 $1 unier t1 t2 $2 f Y X is also a unier of X
f is a unier of X and f , X
179
performed in the context of an existing substitution ([Nil84, SA77] for example). Hence, we also include a context substitution in our specication. A substitution $2 is a most general unier of two terms t1 and t2 in the context of an existing substitution $1 if: mgu : Term Term Subst Subst mgu t1 t2 $1 $2 $2 $1 unier t1 t2 $2 $ $ $1 unier t1 t2 $
$2
When mgu has list arguments, the above denition is applied to the corresponding elements of the two lists. The arguments will make it obvious which denition is meant. To construct a most general unier of two terms t1 and t2 in the context of a substitution $1 consider two situations. First when one of the terms is a variable and the other is a compound term, and second when both terms are compound. When t1 is a variable but t2 is a compound term in the context of $1 , the following lemma can be used to construct a most general unier. mg 1 t1 $1 Var t1 $1 vars t2 $1 mgu t1 t2 $1 $1 t1 $1 t2
The conjunct t1 $1 Var t1 $1 vars t2 $1 in Lemma mg1 ensures that the constructed substitution is not circular. If the constructed substitution is circular, then the following lemma tells us that there is no most general unier: mg 2 t2 $1 Cmpterm t1 $1 vars t2 $1 $2 mgu t1 t2 $1 $2
Now consider how we could proceed to unify the compound terms: t1 t X f bY t2 t Y f X a in the context
Suppose we choose X Y to proceed to unify the second components. However, in the context of this substitution, the second components: f b Y and f Y a , cannot be unied. At this stage, should we backtrack to the rst components and choose the X before again attempting to unify the second alternative most general unier Y components? Fortunately, the following lemma allows us to conclude that there is no unier without the need to backtrack:
$4 mgu t1
tl1 t2
tl2 $1 $4
Of course, if the rst components can not be unied, then we can conclude that there is no most general unier without attempting to unify the remaining components: mg 4 $2 mgu t1 t2 $1 $2 $3 mgu t1 tl1 t2 tl2 $1 $3
If a most general unier does exist, we can nd it in a sequential manner: mg 5 mgu t1 t2 $1 $2 mgu tl1 tl2 $2 $3 mgu t1 tl1 t2 tl2 $1 $3
Thus, given that V g X X is a most general unier of g X X and V in the context , and V g X X W g Y Y X Y is a most general unier of W W and g Y Y V in the context V g X X , we may use Lemma mg5 to conclude that V gX X W gY Y X Y is a most general unier of g X X W W and V g Y Y V in the context . Note that if $2 is a most general unier of the terms t1 and t2 in the context $1 , then $2 must not have any variables which are not in t1 $1 and t2 $1 . We state this as a proposition rather than complicate the denition: mg 6 mgu t1 t2 $1 $2 $3 $2 $1 $3 dom $3 vars-term t1 $1 vars-term t2 $1 range $3 vars-term t1 $1 vars-term t2 $1 The proof of the mg lemmas can be based on the earlier lemmas and do not require induction. As an example, Figure 6.10 presents the proof of Lemma mg2. The proof proceeds by establishing each requirement for the substitution to be a most general unier.
181
from t1 $1 Vars t1 $ vars t2 $1 1 let v t1 $1 in 2 v dom $1 3 vars t2 $1 dom $1 4 circular v t2 $1 circular $1 v t2 $1 5 circular $1 v t2 6 $1 v t2 $1 7 $1 v t2 t2 $1 8 t1 $1 v t2 $1 t2 $1 9 t2 $1 v t2 $1 10 unier t1 t2 $1 v t2 $1 11 $1 v t2 12 from $ $1 t1$ t2 $ $3 $ $1 $3 t1$1 $3 12.1 $3 $ $1 $3 $3 v 12.2 $3 $ $1 v t2 $1 12.3 $3 $ $1 v t2 12.4 $1 v t2 infer $ $ $ $1 unier t1 t2 $ 13 infer mgu t1 t2 $1 $1 t1 $1 t2
(h) (1, ap8) (ap8) (h, 1, reach, circular) (2, 3, 4, cr2) (2, 5, cr3) (2, 6, cp4) (1, , apply-sub) (h, ap3) (6, 7, 8, 9, unier, ) (7, ) t2 $1 $3 t2 $1 $3 $3 $ $1 (h12, , ) (1, 12.1, h, un1) (12.2, ) (7, 12.3, , ) (12.4, ) t (12, unier, -I, -I) (6, 10, 11, 13, mgu)
$3
182
t if v
$ else t
and unifylist takes the form: Subst unifylist : Terms Terms Subst unifylist tl1 tl2 $1 if tl1 or tl2 then tl1 tl2 $1 else let succ $4 unify hd tl1 hd tl2 $1 in if succ then unifylist tl tl1 tl tl2 $4 else false $1 The use of coerce avoids the need to apply the context substitution to the terms, and therefore reduces the overheads. Thus to unify Y and g X X in the context: X gZ Z Z gV V
183
ggV V gV V
The following two lemmas relate coerce to substitution application: co 1 coerce t $ $ co 2 coerce t1 $1 For example, with $ we have: coerce X $ $ X$ g W , and coerce V $ V$ W X Y Y Z Z gV V U U W t$ v t1 $1 v
We can show an analogous result to Lemma mg1: co 3 v2 vars t1 $1 t1 coerce term1 $1 v2 coerce term2 $1 mgu t1 v2 $1 $1 v2 term1
Further, the most general unier of coerced terms is the same as the most general unier of the terms (under the context): co 4 t1 coerce term1 $1 t2 mgu t1 t2 $1 $2 coerce term2 $1 mgu term1 term2 $1 $2
In examining the above algorithm, we notice that the length of the terms (no-Term) may increase on a subsequent recursive call to unify. Hence, we can not prove the algorithm by simply using induction on the length of the terms. However, we can use the fact that the number of variables decreases (after application of the context) when the length of the terms does not decrease. We therefore use the following ordering: * : Terms Terms Subst * tl1 tl2 $ card vars tl1 $ vars tl2 $
no-Terms tl1 $
no-Terms tl2 $
A similar denition holds for term arguments. We will need the following properties of this ordering when proving the above algorithm correct. or 1 len tl1 0 len tl2 0 * hd tl1 hd tl2 $ * tl1 tl2 $
or 2 * tl1 tl2 $
As an example of Lemma or3 in operation, consider the following situation: $1 $2 tl1 X gZ Z Z gV V X gZ Z Z gV V Y Y P tl2 gX X Z gX X
where $2 is a most general unier of hd tl1 and hd tl2 in the context of $1 , tl1 $1 tl2 $1 tl1 $2 tl2 $2 Y P $1 Y P g X X Z $1 gggV V gV V ggV V gV V gV V Y P $2 gggV V gV V ggV V gV V P g X X Z $2 ggV V gV V ggV V gV V gV V
Thus, although the total number of terms after application of $ is larger than the 2 total number of terms after application of $1 , the number of variables in the terms after application of $2 is less than the number of variables after application of $ . The number 1 of variables reduces because the domain of $ has an additional variable Y, which is 2 removed from the terms by the application of $2 (Lemma ap8) without introducing any new variables. A proof of Lemma or3 is presented in Figure 6.11. It has two cases. When $ is 3 empty, the result clearly holds (line 2.3). When $3 is not empty, line 2.4 obtains or3 by showing that the number of variables in t1 $2 t2 $2 reduces . We approach the proof that unify is correct in two stages. We rst prove that unifylist is relatively correct. That is, we prove: rc * t1 t2 $1 * tl1 tl2 $2 nk nk post-unify t1 t2 $1 unify t1 t2 $1 post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2
Before we present the proof of this lemma it is worth outlining the key ideas upon which the proof is based. Each recursive call to unifylist reduces the length of tl . Hence 1 the proof is by induction on the length of tl . The proof relies on the fact that if the 1 n k then any subsequent call to unifylist, say initial arguments satisfy * tl1 tl2 $2 n k . This with arguments tl4 , tl5 , $5 , will also maintain the relationship * tl4 tl5 $5 is shown with the aid of Lemmas or1 and or3. When unifylist produces a most general unier, Lemma mg5 informs us that it satises our specication. When unifylist fails to nd a unier, Lemmas mg3 and mg4 inform us that there is no most general unier.
185
from len tl1 0 len tl2 0 mgu hd tl1 hd tl2 $1 $2 1 $3 $2 $1 $3 dom $3 vars tl1 $1 vars tl2 $1 range $3 vars tl1 $1 vars tl2 $1 2 from $2 $1 $3 dom $3 vars tl1 $1 vars tl2 $1 range $3 vars tl1 $1 vars tl2 $1 2.1 $2 $1 $3 $3 2.2 $3 2.3 from $3 2.3.1 $1 $2 * tl1 tl2 $1 infer * tl1 tl2 $2 2.4 from $3 2.4.1 vars tl1 $1 $3 vars tl1 $1 range $3 vars tl2 $1 range $3 2.4.2 vars tl2 $1 $3 2.4.3 vars tl1 $2 vars tl2 $2 vars tl1 $1 vars tl2 $1 range $3 2.4.4 vars tl1 $2 vars tl2 $2 vars tl1 $1
(h2, -E)
(2.4.1, 2.4.2, , 2.1, ) vars tl2 $1 (2.4.3, h2, ) (h2, -E) 2.4.5 dom $3 vars tl1 $1 vars tl2 $1 v vars tl1 $1 vars tl2 $1 v vars tl1 $2 vars tl2 $2 2.4.6 (h2.4, 2.4.5, 2.1 ap8) vars tl1 $1 vars tl2 $1 2.4.7 vars tl1 $2 vars tl2 $2 (2.4.4, 2.4.6) * tl1 tl2 $1 (2.4.7, *) infer * tl1 tl2 $2 * tl1 tl2 $1 (2.2, 2.3, 2.4, -E) infer * tl1 tl2 $2 * tl1 tl2 $1 (1,2, -E) infer * tl1 tl2 $2
186
from true (unifylist, post-unifylist, vac-I) 1 rc is true for len tl1 0 2 from rc is true for all len tl1 m m 0 len tl1 m nk 2.1 from * t1 t2 $1 post-unify t1 t2 $1 unify t1 t2 $1 2.1.1 from * tl1 tl2 $2 nk 2.1.1.1 tl2 tl2 2.1.1.2 from tl2 infer post-unifylist tl1 tl2 $1 unifylist tl1 tl2 $1 (see Figure 6.13 ) 2.1.1.3 from tl2 infer post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2 (see Figure 6.14) infer post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2 (2.1.1.1, 2.1.1.2, 2.1.1.3, -E) nk post-unifylist tl1 tl2 $2 infer * tl1 tl2 $2 unifylist tl1 tl2 $2 (2.1.1, !(h2.1.1), -I)) (2.1, ,!(h2.1), -I) infer rc is true for len tl1 m infer rc (1, 2, induction)
from tl2 tl1 (h2) $ tl1 $ tl2 $ (.1, apply-sub, =) infer post-unifylist tl1 tl2 $1 unifylist tl1 tl2 $1 (.2, post-unifylist, h2.1.1.2, unifylist)
Figure6 13 Proof when tl is empty Figure 6.12 presents the top level of the proof. Figure 6.13 presents the the proof when tl is empty, whilst Figure 6.14 presents the proof when tl is not empty. To show that unify satises our specication, we prove:
187
2.1.1.3 from tl2 2.1.1.3.1 * hd tl1 hd tl2 $2 nk (h2.1.1, h2.1.1.3, h2, or1) unify hd tl1 hd tl2 $2 in 2.1.1.3.2 let succ $3 (.1, .2, h2.1) 2.1.1.3.3 post-unify hd tl1 hd tl2 $2 succ $3 2.1.1.3.4 succ succ 2.1.1.3.5 from succ 2.1.1.3.5.1 mgu hd tl1 hd tl2 $2 $3 (h2.1.1.3.5, 2.1.1.3.3, post-unify) nk (h2.1.1.3, h2, .1, or3, h2.1.1) 2.1.1.3.5.2 * tl1 tl2 $3 nk (.2, h2.1.1.3, h2, tl , *) 2.1.1.3.5.3 * tl tl1 tl tl2 $3 (h2, tl , len ) 2.1.1.3.5.4 len tl tl1 m unifylist tl tl1 tl tl2 $3 in 2.1.1.3.5.5 let b $4 (h2.1, .3, .4, .5, h2) 2.1.1.3.5.6 post-unifylist tl tl1 tl tl2 $3 b $4 b 2.1.1.3.5.7 b 2.1.1.3.5.8 from b (See Figure 6.15) infer post-unifylist tl1 tl2 $2 b $4 2.1.1.3.5.9 from b (See Figure 6.15) infer post-unifylist tl1 tl2 $2 b $4 2.1.1.3.5.10 post-unifylist tl1 tl2 $2 unifylist tl tl1 tl tl2 $3 (.7, .8, .9, -E, .5) infer post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2 (.10, h2.1.1.3.5, 2.1.1.3.2, h2.1.1.3, h2, unifylist) 2.1.1.3.6 from succ $3 mgu hd tl1 hd tl2 $2 $3 2.1.1.3.6.1 (h2.1.1.3.6, 2.1.1.3.3, post-unify) 2.1.1.3.6.2 post-unifylist tl1 tl2 $2 succ $2 (.1, h2.1.1.3.6, mg4, post-unifylist) infer post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2 (.2, h2.1.1.3.6, 2.1.1.3.2, h2.1.1.3, h2, unifylist) infer post-unifylist tl1 tl2 $2 unifylist tl1 tl2 $2 (.4, .5, .6, -E)
188
from b mgu tl tl1 tl tl2 $3 $4 (2.1.1.3.5.6,post-unifylist, h2.1.1.3.5.8) mgu hd tl1 hd tl1 $2 $3 mgu tl1 tl2 $2 $4 infer post-unifylist tl1 tl2 $2 b $4 (2.1.1.3.3, h2.1.1.3.5, post-unify) (.1,.2, mg5) (.3, h2.1.1.3.5.8, post-unifylist)
b $4 mgu tl tl1 tl tl2 $3 $4 (2.1.1.3.5.6, post-unifylist, h2.1.1.3.5.9) mgu hd tl1 hd tl2 $2 $3 (2.1.1.3.3, h2.1.1.3.5, post-unify) $4 mgu tl1 tl2 $2 $4 (.1,.2, mg3) infer post-unifylist tl1 tl2 $2 b $4 (.3, h2.1.1.3.5.9, post-unifylist)
from
Figure6 15 Proof cases of b post-unify term1 term2 $1 unify term1 term2 $1 As mentioned above, the proof is by induction on * term term2 $1 . Letting t1 1 coerce term1 $1 , and t2 coerce term2 $1 , there are four cases that may occur. In each case we rst deduce: cl post-unify t1 t2 $1 unify term1 term2 $1 Then we use Lemma co4 to obtain post-unify term1 term2 $1 unify term1 term2 $1 The rst case, when both t1 and t2 are compound terms, leads to Lemma c1 with the aid of Lemma rc and Lemma or2. The second and third cases, when one of t and t2 is 1 a variable but the other is a compound term, leads to Lemma c1 by Lemma co3 (when there is a unier), and Lemma mg2 (when there is no unier). In the fourth case, when both t1 and t2 are variables, Lemma c1 is proved with the aid of Lemmas co2 and co3. We present the detailed proof in two stages. Figure 6.16 shows how the four cases are combined, whilst Figures 6.17 to 6.19 prove each case. The third case is anologous
189
from term1 term2 Term $1 Subst 02 1 from * term1 term2 $1 infer post-unify term1 term2 $1 unify term1 term2 $1 2 (*, post-unify, unify) from post-unify term1 term2 $1 unify term1 term2 $1 is true nk nk 02 for * term1 term2 $1 * term1 term2 $1 nk 2.2 let t1 coerce term1 $1 t2 coerce term2 $1 in 2.3 rst case see Figure 6.17 2.4 second and third cases see Figure 6.18 2.5 fourth case see Figure 6.19 t1 t2 mk-Cmpterm id1 tl1 mk-Cmpterm id2 tl2 2.6 t1 t2 mk-Cmpterm id1 tl1 v2 t1 t2 v1 mk-Cmpterm id2 tl2 t1 t2 v1 v2 (Term) 2.7 post-unify t1 t2 $1 cases t1 t2 of mk-Cmpterm id1 tl1 mk-Cmpterm id2 tl2 mk-Cmpterm id1 tl1 v2 v1 mk-Cmpterm id2 tl2 v1 v2 end (2.3, 2.4, 2.5, 2.6, Cases-I) (2.2, 2.7, unify) 2.8 post-unify t1 t2 $1 unify term1 term2 $1 infer post-unify term1 term2 $1 unify term1 term2 $1 (2.8, 2.2, co4, post-unify) infer post-unify term1 term2 $1 unify term1 term2 $1 (1,2, induction)
190
2.3 from t1 t2 mk-Cmpterm id1 tl1 mk-Cmpterm id2 tl2 2.3.1 id1 id2 id1 id2 2.3.2 from id1 id2 2.3.2.1 * t1 t2 $1 * term1 term2 $1 (2.2, co1, *) 2.3.2.2 * tl1 tl2 $1 * t1 t2 $1 (h2.3, or2) nk (.1, .2, h2) 2.3.2.3 * tl1 tl2 $1 unifylist tl1 tl2 $1 in 2.3.2.4 let b $ (h2, .3, .4, rc) 2.3.2.5 post-unifylist tl1 tl2 $1 b $ 2.3.2.6 post-unify t1 t2 $1 b $ (.5, h2.3, h2.3.2, =, post-unifylist, post-unify) infer post-unify t1 t2 $1 if id1 id2 then unifylist tl1 tl2 $1 else false (.6, .4, h2.3.2, ifth-subs) 2.3.3 from id1 id2 2.3.3.1 $ mgu t1 t2 $1 $ (h2.3.3, h2.3, =, mgu) infer post-unify t1 t2 $1 if id1 id2 then unifylist tl1 tl2 $1 else false (.1,post-unify, h2.3.3, ifel-subs) infer post-unify t1 t2 $1 if id1 id2 then unifylist tl1 tl2 $1 else false (2.3.1, 2.3.2, 2.3.3, -E)
6.8 Discussion
In this section we compare the above theory with those of Manna and Waldinger [MW81], and Paulson [Pau85]. First, we must bear in mind that our objectives are different. Manna and Waldinger use unication as a nontrivial example of the constructive proof approach to derive programs. Paulson automates the proof in LCF to increase our understanding of the automatic proof and development of programs. In pursuing these objectives, they restrict their attention to a theory of idempotent substitutions. Our aim has been to develop a more general theory and to use it to prove a more space efcient algorithm. Manna and Waldinger use an algebraic approach to specication. As a result they need to develop a theory of maps. Paulson also needs to do this because maps are not in-built in LCF.
6.8 Discussion
191
mk-Cmpterm id1 tl1 v2 2.4 from t1 t2 2.4.1 v2 vars t1 $1 v2 vars t1 $1 2.4.2 from v2 vars t1 $1 2.4.2.1 mgu t1 t2 $1 $1 v2 term1 (h2.4.2, 2.2, h2.4, =, co3) infer post-unify t1 t2 $1 if v2 vars t1 $1 then true $1 v2 term1 else false (2.4.2.1, post-unify, h2.4.2, ifth-subs) 2.4.3 from v2 vars t1 $1 2.4.3.1 t2 $1 v2 (2.2, h2.4, co2) $ mgu t1 t2 $1 $ (.1, h2.4.3, h2.4, mg2, mgu) 2.4.3.2 infer post-unify t1 t2 $1 if v2 vars t1 $1 then true $1 v2 term1 else false (.2, post-unify, h2.4.3, ifel-subs) infer post-unify t1 t2 $1 if v2 vars t1 $1 then true $1 v2 term1 else false (2.4.1, 2.4.2, 2.4.3, -E)
Figure6 18 Proof of second case VDM includes maps as a data type; thus we have avoided dening maps. We have used the logic of partial functions [BCJ83]. Hence, we did not require our denitions to be total. The logic of partial functions has been particularly useful in expressing lemmas of the form: dom-disjoint $1 $2 P $1 $2
A theory of noncircular substitutions is developed. To do this, we have had to formalize the notion of circularity. Since idempotent substitutions are noncircular, this theory is more general. Substitution application is dened recursively, whereas Manna and Waldinger dene it as parallel application. For example, if in parallel substitution application: $ X$ X Y Y Y Z
192
v2
infer post-unify t1 t2 $1 if v1 v2 then true $1 else true $1 v2 term1 (.1, post-unify, h2.5.2, ifel-subs) 2.5.3 from v1 v2 infer post-unify t1 t2 $1 if v1 v2 then true $1 else true $1 v2 term1 (h2.5.3, h2.5, post-unify, ifth-subs) infer post-unify t1 t2 $1 if v1 v2 then true $1 else true $1 v2 term1 (2.5.1, 2.5.2, 2.5.3, -E)
Figure6 19 Proof of fourth case The specication of a most general unier differs from Manna and Waldingers in two respects. First, we allow the unication of terms in an existing context substitution. We can, of course, remove this context substitution by setting it to the empty map. As a result of a theory of noncircular substitutions, substitutions which may be most general uniers in our work, may not be most general uniers in Manna and Waldingers denition. For example, with $ although: f X X $ f Y Z $ f Z Z X Y Y Z
in our denition; in Manna and Waldingers theory this substitution is not a unier: f X X $ f Y Y but f Y Z $ f Z Z
The algorithm we have proved is more space efcient than the one proved by Manna and Waldinger provided that the check for circularity (the occurs check) is ignored (or implemented using the denition of reach). For example, to unify the terms (from [CB83, p. 910]):
6.9 Conclusion
t1 t2 f X1 X2 Xm , and f g X0 X0 g X1 X1
193
g Xm-1 Xm-1
The algorithm in Manna and Waldinger gives: X1 g X0 X0 X2 g g X0 X0 g X0 X0 X3 g g g X0 X0 g X0 X0 g g X0 X0 g X0 X0 . . . Xm Thus the space complexity of the algorithm they prove is exponential with respect to the length of the terms to be unied. The algorithm we prove gives: X1 g X0 X0 X2 g X1 X1 Xm g Xm-1 Xm-1
In general, the use of coerce in the above algorithm ensures that any pair v t that is accumulated in the substitution is such that the length of t is less than or equal to the larger of the terms to be unied (assuming that the initial context is empty). Thus the space complexity is of order m n where m is the length of the larger of the terms to be unied, and n is the number of variables occurring in the terms. However, the above algorithm does not improve upon the exponential time complexity of the algorithm proved by Manna and Waldinger. The major benet of our more general theory has been that we have captured the behavior of a wider class of unication algorithms. The example above illustrates the fact that the algorithm we prove does not satisfy Manna and Waldingers denition of the most general unier, that is, the algorithm we prove does not satisfy their specication of unication.
6.9 Conclusion
We have developed a theory of noncircular substitutions. Since idempotent substitutions are a proper subset of noncircular substitutions, and when restricted to idempotent substitutions, our denition of substitution application is equivalent to Manna and Waldingers, a theory of noncircular substitutions is more general than a theory of idempotent substitutions. We have presented a proof of an algorithm which does not satisfy Manna and Waldingers specication and is more space efcient than the one they prove. More efcient unication algorithms than the one we prove do exist [CB83]). These tend to represent substituitions as graphs [CB83, PW78]). To prove these in VDM, we would have to use the ideas of reication [Jon86a]. There are also a number of extensions to unication that
194
we have not discussed [Hue75, SR88]. Specifying and proving these algorithms correct would require further research. For example, we would have to tackle the problem of variable capture if we attempt to extend our work to cater for quantied terms [SR88].
Acknowledgements
I am grateful to Professor Cliff Jones for his help throughout this work. Professor Howard Barringer provided the reference to Corbin and Bidoits paper [CB83] and enlightenment about the use of unication in rewrite rules.
7 Heap Storage
Chris W. George
The specication describes the NEW and DISPOSE operations of the heap storage in Pascal. It contains several levels of specication, each intended to implement the previous one. It shows how an efcient implementation may be gradually created from an abstract specication by successive commitments to data structures and algorithms: VDM is used to capture design decisions one at a time. The example was originally created as an exercise for a VDM course. It has the advantage of being a problem many programmers are aware of while not being trivial.
195
196
7 Heap Storage
Loc-set Bool has seq : Loc is sequential s has seq s n free elems s free len s n is sequential : is sequential s Bool ij
197
Note that the normal renement rules, as for example in [Jon90], will not work for NEW1 and DISPOSE1 since their signatures have changed. (A careful examination will also show that in level 1 we have also added the restriction that the argument to DISPOSE must be a single piece, i.e. a sequential set of locations. This was not true at level 0.) Free1 Piece-set p1 p2 inv ps p1 p2 LOC p1 ps locs of p1 locs of p2 SIZE p1 LOC p2
/* pieces must be disjoint and nonabutting */ Piece :: LOC : Loc SIZE : Loc NEW1 req: res: Piece ext wr FREE : Free1 req pre p free SIZE p post locs free locs free locs of res locs of res locs free SIZE res req DISPOSE1 ret: Piece ext wr FREE : Free1 pre locs of ret locs free post locs free locs : Free1 locs ps locs of : Piece locs of p locs free Loc-set locs of p Loc-set LOC p locs of ret
ps
LOC p
SIZE p
198
7 Heap Storage
since the post-conditions of NEW2 and DISPOSE2 use locs2. Note that it would be more convenient to represent the level 2 state by: Free2 Piece
when the type Fp and the function is reachable are no longer necessary the quantication in the pre-condition of NEW2 can be done over the elems of the state. This example was written without using the list data type of VDM, but effectively modelling it, to show how recursive structures may be dened, and to show the use of predicates like is reachable with such structures. Free2 inv x Fp is ok2 x
199
FPLOC FPNEXT fp
/* Note that the pieces are in ascending order. Note also that the use of rather than forces the pieces not to abut. */ NEW2 req: res: Piece ext wr FREE : Free2 pre fp Fp FPSIZE fp req is reachable fp free post locs2 free locs2 free locs of res locs of res locs2 free SIZE res req DISPOSE2 ret: Piece ext wr FREE : Free2 pre locs of ret locs2 free post locs2 free locs2 free locs of ret
locs2 : Free2 Loc-set locs2 fp if fp nil then else FPLOC fp FPLOC fp locs2 FPNEXT fp
FPSIZE fp
200 is reachable : Fp Free2 Bool is reachable fp start if start nil then false else if fp start then true else is reachable fp FPNEXT start
7 Heap Storage
Adequacy
The retrieve function from level 2 to level 1 is: retr2 1 : Free2 Free1 retr2 1 free mk-Piece FPLOC fp FPSIZE fp fp Fp is reachable fp free This is clearly a total function, being given a well dened explicit denition. The next thing we have to do is to prove adequacy, i.e. that: ps Free1 fp Free2 retr2 1 fp ps
Frequently, the easiest way to prove such an adequacy requirement is to invent a function that is an inverse of the retrieve function. The existence of an appropriate fp is then shown by applying this inverse function to the ps value. In this case the algorithm for the inverse function is clear. If ps is empty the result is nil. Otherwise, since by its invariant all the pieces in ps are disjoint we can select the rst as the one with the lowest initial location and construct a record of type Fp. The FPNEXT eld will be the result of applying the same function to the rest of ps. More formally, we dene a function split that splits a (nonempty) set of pieces into the rst piece and the rest, and the inverse retrieve in terms of split. split ps: Free1 r: Piece pre ps Free1
201
LOC q Free2 if ps then nil split ps in else let p s mk-Fp LOC p SIZE p inv retr2 1 s
It is worth noting that the result of inv retr2 1 is in the type Free2, not just Fp , and so the invariant on Free2 is claimed to hold for it. This is easily proved from the invariant on Free1 that holds on its input. If we now assume that split is a well dened function with a unique result (which could also be proved formally) we can give the following proof that inv retr2 1 is a right inverse of retr2 1 and hence of the required adequacy result:
from ps Free1 1 from ps 1.1 inv retr2 1 ps nil 1.2 retr2 1 inv retr2 1 ps ps infer retr2 1 inv retr2 1 ps 2 from p Piece s Piece-set ps split ps retr2 1 inv retr2 1 s 2.1 inv retr2 1 ps mk-Fp LOC p SIZE p inv retr2 1 s 2.2 retr2 1 inv retr2 1 ps p retr2 1 inv retr2 1 s p s 2.3 retr2 1 inv retr2 1 ps ps infer retr2 1 inv retr2 1 ps ps 3 retr2 1 inv retr2 1 ps ps infer fp Free2 retr2 1 fp
Rened operations
We now have to prove the domain and result proof obligations for the renement. For DISPOSE the domain rule is:
7 Heap Storage
locs of ret
locs2 fp
which suggests that we might start by proving the lemma: fp Free2 locs retr2 1 fp locs2 fp
The proof of the lemma is as follows, using structural induction on the type Free2:
from fp Free2 1 from fp nil 1.1 retr2 1 fp 1.2 locs retr2 1 fp 1.3 locs2 fp locs2 fp infer locs retr2 1 fp f Free2 2 from l Loc n fp mk-Fp l n f locs retr2 1 f locs2 f 2.1 retr2 1 fp mk-Piece l n retr2 1 f 2.2 locs retr2 1 fp l l n 1 locs retr2 1 f 2.3 locs retr2 1 fp l l n 1 locs2 f l l n 1 locs2 f 2.4 locs2 fp locs2 fp infer locs retr2 1 fp locs2 fp infer locs retr2 1 fp
The domain rule for DISPOSE is now proved immediately from the lemma. The result rule, which also follows immediately from the lemma, is: fp fp Free2 ret Piece locs of ret locs retr2 1 fp locs of ret
pre-DISPOSE ret fp locs2 fp locs2 fp locs retr2 1 fp For NEW the domain rule is: fp Free2 req p retr2 1 fp SIZE p f Fp FPSIZE f req req is reachable f fp
203
from fp 1 f
Free2 req Fp is reachable f fp FPSIZE f req p retr2 1 fp SIZE p req p retr2 1 fp SIZE p req 2 f Fp is reachable f fp FPSIZE f req req infer p retr2 1 fp SIZE p f Fp FPSIZE f req is reachable f fp
The result rule for NEW is: fp fp Free2 req Nat res Piece locs of res
pre-NEW req retr2 1 fp locs retr2 1 fp locs retr2 1 fp locs of res locs retr2 1 fp SIZE res req locs2 fp locs2 fp locs of res locs of res locs2 fp SIZE res req which follows immediately from the lemma proved earlier. Since there are no initial states specied we have completed the data reication proof for the development step from level 1 to level 2.
204 retr3 2 : Free3 Free2 retr3 2 start store if start nil then nil else mk-Fp start store start retr3 2 store start pre is ok3 start store but as with level 2 it might be easier to use: retr3 0 locs3
7 Heap Storage
1 store
Neither of these retrieve functions will be adequate, of course, because of the ban on pieces of length 1. It should also be noted that this is the rst level at which a location is anything other than a natural number. In order to allow the heap to hold information about its structure we have introduced the notion of storage. Now its presence in the state would allow NEW and DISPOSE to change it arbitrarily, so we have added to the post-conditions of NEW3 and DISPOSE3 extra conjuncts to prevent them altering nonfree locations, i.e. locations in use by some program. The conjunct for NEW3 says that any location that was in use before NEW3 was invoked must remain in use with the same contents; the conjunct for DISPOSE3 says that any location that was in before DISPOSE3 was invoked, and has not just been disposed, must remain in use with the same contents. These constraints might well be regarded as part of the requirements of the specication, but can only be expressed once we have actually modelled storage. Such an inability to capture all requirements at the most abstract level of specication is quite common. Loc Store Free3 inv start store is ok3 start store Store Loc
m
205
is ok3 store a
1 store
/* Note the new restriction, carried into NEW3 and DISPOSE3, that the size of a piece must be at least 2 */ NEW3 req: res: Piece ext wr FREE : Free3 pre req 1 let start store free in a dom store store a nil store a req store a req is reachable3 a start store post locs3 free locs3 free locs of res locs3 free SIZE res req let start store free in loc dom store locs3 start store loc dom store store loc store loc
locs of res
DISPOSE3 ret: Piece ext wr FREE : Free3 1 pre SIZE ret locs of ret locs3 free post locs3 free locs3 free locs of ret let start store free in loc dom store locs3 start store loc dom store store loc store loc
206 is reachable3 : Loc Loc Store Bool is reachable3 a start store if start nil then false else if a start then true else is reachable3 a store start 1 store pre is ok3 start store locs3 : Loc Store Loc-set locs3 start store if start nil then else start start store start locs3 store start 1 store pre is ok3 start store
7 Heap Storage
207
remove4 : Loc Loc Store Store Piece 1 remove4 prev current store n if store current n store current n 1 then remove4 current store current 1 store n else let store1 if store current n then if prev nil then store else store prev 1 store current else store current store current n in store1 mk-Piece current store current -n n pre n 1 a dom store store a nil store a n store a n 1 is reachable3 a current store prev nil current is ok3 prev store is ok3 current store nil prev current
DISPOSE4 ret: Piece ext wr FREE : Free3 1 pre SIZE ret locs of ret locs3 free post let mk-Piece a s ret in free in let start store start if start nil then a else min start a store insert nil start store a s
208 insert : Loc Loc Store Loc Store 1 insert prev current store a s if current nil a current then insert current store current 1 store a s else let store1 store a s a 1 current in let store2 if prev nil then store1 else store1 prev 1 a in let store3 if current nil a s current then store2 else current current 1 store2 a s store2 current a 1 store2 current 1 in a let store4 if prev nil prev store prev then store3 else a a 1 store3 prev store3 prev store3 a prev 1 store3 a 1 in store4 pre s 1 prev nil current nil prev current is ok3 prev store is ok3 current store In this specication: store1 has new piece hooked up to next. store2 has new piece hooked up to previous one. store3 has new piece merged with next if possible. store4 has new piece merged with previous if possible. DISPOSE4 is an implementation of DISPOSE3.
7 Heap Storage
209
domain of the the map is irrelevant. The pre-conditions for DISPOSE4 and NEW4 should be replaced by exception conditions, and the exceptions raised at appropriate points in the algorithms. Note that this is more than encapsulation in some operation whose body (for NEW, say) is effectively: if pre-NEW req then NEW req else RAISE exception since an implementation of this implies in general two searches for a suitable piece. The type Loc should then be replaced by some range of values representing possible heap locations. (This introduction of bounds is, of course, an inadequate renement.) An extra exception for exhaustion of heap space should also be added. The operations could then be implemented in some suitable programming language, though of course we would only be modelling heap space by some (presumably large) array. A development along these lines into Pascal has in fact been completed and is documented in [Eva86].
7.9 Acknowledgements
This study was originally intended to provide an example of development for use in courses on VDM, and has beneted from the comments of course participants. A version of this paper was published in [BJMN87]. Several colleagues have also provided suggestions and pointed out errors, particularly J. Bicarregui, A. J. Evans, P. Goldsack and C. B. Jones. This work was partially funded by the Commission of the European Communities (CEC) under the ESPRIT program in the eld of software technology, project number
7 Heap Storage
8 Garbage Collection
Mario I. Wolczko
Like the preceding chapter, this specication is concerned with storage management. In this case, the topic of garbage collection algorithms is discussed. Standard algorithms such as reference counting and mark-sweep are related to an abstract VDM specication. These specications show how to record a body of knowledge about algorithms: VDM can be used to describe algorithms at a level of abstraction which makes their reimplementation in various languages straightforward.
211
212
8 Garbage Collection
8.1 Introduction
A milestone was achieved in the history of the development of programming languages with the introduction of automatic storage reclamation. In contrast to many lower-level 1 languages such as C and Pascal, languages like L ISP and Smalltalk-80 relieve the programmer from the burden of storage management. In these languages the programmer is free to create data structures at will, and the resources used by these data structures will be reclaimed automatically by the run-time system when it can prove that they are no longer required. Unusable data structures are known as garbage, and the task of 2 reclaiming garbage is more commonly known as garbage collection. It is of paramount concern that any implementation of a garbage collector be correct. An incorrect garbage collector can ll memory with unreclaimable garbage, or, more seriously, can reclaim data structures that are still in use. Clearly, the implications for a system using such a collector are severe: data will be modied in ways which seem to bear no relation to the program activity at the time. Indeed, a malfunctioning garbage collector can render a system as unusable as malfunctioning hardware. In principle, the task of a garbage collector is simple: it must detect garbage, and reclaim the resources it uses it for future use. In practice, however, this is a nontrivial task, especially when one considers efciency. The aim of this chapter is to introduce a VDM specication for the abstract problem of garbage collection, divorced from any implementation details, and then present several different reications which lead to garbage collection algorithms with different properties. By concentrating on the essence of each algorithm using a formal notation, the reader can gain insight into the operation of the algorithm, and its potential gains and drawbacks.
213
lection these items are of no consequence. To model object references we introduce the data type Oop (ordinary object pointer). Every object has its own unique Oop, and can contain within itself other Oops referring to other objects. The particular set of Oops is of no consequence at this stage in the specication; for the moment we will simply assume that the set contains enough distinct values to assign one to each object in the largest memory structure that we might be interested in. At the implementation level it may be a subrange of the integers representing the available address space of a machine. In addition to being identied by an Oop, the data within an object will most likely be ordered, so that each datum can be accessed by position. However, the ordering of references is of no consequence to the garbage collector; it is only concerned with what is referenced. Hence, our initial model of an object might be a set of references to other objects: Object Oop-set
However, this model is in some sense too abstract. When one considers the operations that take place on objects in a real system, one nds that it is important to know how many times one object refers to another. In other words, the graph of objects should be allowed to contain multiple arcs from one object to another. We shall say more about this later. Hence, our abstract model for an object is as a bag of references to other objects: Object Bag Oop
There is no ordering dened on the references, but if a reference is added to a bag more than once, it can be removed more than once. For a more complete exposition of bags, see [Jon90]. We shall use several operations involving bags: add to add an element to a bag, remove to remove an element from a bag, count to count the number of occurrences of an element in a bag, to add bags together, and set to obtain the set of elements in a bag. These are dened in the appendix. At this stage we shall also dene a number of auxiliary functions that operate on objects. As the denition of an object is reied, the denitions of these functions will be altered, but the interface will remain the same. Hence the set of functions can be thought of as a small object language. The rst function simply tests whether one object refers to another: refers to : Oop Object refers to p obj count p obj 0
The next two add and remove a reference to an object, respectively: add to obj : Oop Object Object add p obj add to obj p obj
214 remove from obj : Oop Object Object remove p obj remove from obj p obj
8 Garbage Collection
Finally, we shall need to know which objects an object refers to: all refs : Object all refs obj Oop-set set obj
In addition to the object manipulation functions, we shall also dene what the initial state of a newly created object is: init object init-Bag
The memory system will contain a collection of these objects, and distinguish some of them as roots: Object StateA :: mem : Oop roots : Oop-set (The subscript A indicates that this is our abstract state. As it is reied in later sections, the subscript will be altered.) For example, given a state s StateA , and an Oop p, we can discover which objects p references by looking up p in the memory of s: all refs mem s p (p must be in the domain of mem s , of course).
m
215
It should be obvious that garbage can only come into being as the result of a remove ref operation. Hence, we could state in the post-condition for remove ref that all garbage be removed immediately. However, by placing in the invariant the restriction that no garbage is ever in the state, we will make later development steps easier. Here are the operations: create from: Oop to: Oop m ext wr mem : Oop Object pre from dom mem post to dom mem mem mem from add to obj to mem from
to
init object
The post-condition of create chooses to from the set of Oops that are not in use; this allows an implementor as much freedom as possible in Oop allocation. add ref from to: Oop m ext wr mem : Oop Object dom mem pre from to post mem mem from add to obj to mem from In the post-condition of remove ref we need only state that all objects remaining in the state (except the one being altered) are unchanged; the invariant will take care of garbage for us: remove ref from to: Oop m ext wr mem : Oop Object dom mem refers to to mem from pre from to post mem from remove from obj to mem from p dom mem p from mem p mem p The invariant is now dened to ensure that no garbage appears in the state. inv-StateA mk-StateA mem roots roots dom mem no garbage roots mem The test for absence of garbage states that the set of objects in the memory is precisely the set that is reachable from the roots: no garbage roots mem reachable from roots mem dom mem
Reachability is determined by following all references from the roots recursively until no new objects are encountered. The set of objects encountered and recorded as reachable is known as the visited set; those objects referenced from the visited objects but not in the visited set are known as unvisited objects, and are visited in the next step
216
8 Garbage Collection
of the recursion. When the unvisited set becomes empty, all accessible objects have been traced, and are in the visited set. Object Oop-set reachable from : Oop-set Oop reachable from roots mem visit roots mem visit : Oop-set Oop-set Oop Object Oop-set visit visited unvisited mem if unvisited then visited else let visited visited unvisited in all refs mem p p unvisited visit visited
m m
visited mem
The state, invariant and operations describe an ideal system in which garbage is reclaimed immediately it is created. This is an example of a specication for which there is no known efcient implementation. All known garbage collection algorithms either do not guarantee that all garbage is reclaimed or take time proportional to the number of objects in the system to reclaim garbage. Clearly, having such behavior for each remove ref operation will be unacceptable. We need therefore to relax our constraint that no garbage ever appears in the state. A safe garbage collector is one that never reclaims active objects, and we can specify safety properties by relaxing the invariant: inv-State mk-State mem roots roots dom mem no dangling refs mem In our new, less abstract state (the A subscript has disappeared), any number of garbage objects may appear, but there must be no references to nonexistent objects. no dangling refs : Oop no dangling refs mem
m
dom mem
We can relate this new state to the abstract one by means of a retrieve function that discards all garbage: retr : State StateA retr mk-State mem roots mk-StateA reachable from roots mem it. GC ext wr mem : Oop
m
mem roots
Now that garbage may appear in the state, we need a separate operation to reclaim
Object
217
This specication states that the garbage collector may not introduce new objects, and that all objects present after garbage collection must be unchanged. The postcondition, taken in conjunction with the invariant, ensures that only garbage has been removed from the state. Note that the garbage collector can be very simple: it need not collect any garbage at all! We have to be this lax because some garbage collectors do not guarantee that all garbage is reclaimed. The create, add ref and remove ref operations require stricter pre-conditions stating that their arguments must not refer to garbage objects; these modications are left as an exercise for the reader.
remove from obj : Oop Object Object obj body remove from obj p obj all refs : Object all refs obj init object Oop-set set body obj
218
8 Garbage Collection
Given these denitions, the create and add ref specications for the previous state, State, can be used unchanged. The remove ref operation is dened so that it does not attempt to reclaim any garbage: remove ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set reachable from roots mem refers to to mem from pre from to post mem mem from remove from obj to mem from The mark and sweep operations are combined into a single GC operation by quoting their individual post-conditions and using an intermediate state: GC m Object ext wr mem : Oop rd roots : Oop-set pre p dom mem marked mem p m post mem Oop Object post-mark mem roots mem
As is usual in mark-sweep garbage collectors, we have stated that the mark phase must start with all objects unmarked, and the sweep phase must unmark all of the nongarbage objects. mark m Object ext wr mem : Oop rd roots : Oop-set pre p dom mem marked mem p post mem mem p mem p marked p
sweep m ext wr mem : Oop Object rd roots : Oop-set marked mem p pre p dom mem p reachable from roots mem post let remaining p dommem marked mem p in mem p mem p marked false p remaining
219
dec rc : Object Object obj RC RC obj 1 dec rc obj pre RC obj 1 When created, an object has a reference count of one: init object mk-Object 1
The denition of a retrieve function from a reference-counted State to the earlier RC State is straightforward and left as an exercise for the reader. The invariant is somewhat less obvious. In addition to stating that there are no dangling references, we must also
220 state that the reference counts are accurate: inv-StateRC mk-StateRC mem roots roots dom mem no dangling refs mem ref counts accurate roots mem
8 Garbage Collection
For each object this is determined by summing the number of occurrences of an Oop in all the object bodies in the memory and checking that the sum is equal to the objects reference count. Note that an extra reference is added for root objects. ref counts accurate roots mem p dom mem RC mem p if p roots then 1 else 0 + count p body mem q
q dom mem
To maintain the reference counts, add ref is modied to perform the appropriate increment operation: add ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set reachable from roots mem pre from to post let mem mem from add to obj to mem from mem mem to inc rc mem to
in
Note that the update to the memory must be done in two stages because of the possibility that from to. Similarly, remove ref performs a decrement operation. However, if the count falls to zero, then the object is freed, and the counts of all the objects referenced from the freed object are decremented. This in turn may cause further freeing and decrementing. The recursive decrement and freeing operation is captured by the dec function. remove ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set reachable from roots mem refers to to mem from pre from to post mem dec add to init-Bag mem from remove from obj to mem from
221
left
in
The dec function requires some explanation. At each step it is passed a bag, ptrs, containing the Oops to have their counts decreased the number of occurrences of an Oop in the bag is the amount by which its count is to be decreased and a memory, mem. If the bag is empty, then mem is returned unchanged. Otherwise garbage is calculated to be the set of Oops in mem whose reference count will fall to zero and hence become garbage; left is the set of nongarbage pointers in ptrs. The garbage is excluded from the memory (yielding mem ), and the reference counts of the Oops in left are adjusted. Finally, dec is called recursively with the sums of the bags of Oops in the garbage objects (we use a distributed form of between bags to perform this summation).
222
8 Garbage Collection
The create operation checks the free stack for any eligible objects (note that we ignore problems of size): create from: Oop to: Oop m ext wr mem : Oop Object rd roots : Oop-set pre from reachable from roots mem post let mem mem from add to obj to mem from to init object if p dom mem RC mem p 0 then to dom mem RC mem to 0 mem mem p dec rc mem p p all refs mem to else to dom mem mem mem
in
The remove ref operation now simply decrements a single reference count (addition to the free stack being implicit if the count falls to zero): remove ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set reachable from roots mem refers to to mem from pre from to post let mem mem from remove from obj to mem from in mem mem to dec rc mem to
223
Unvisited objects are referenced from visited objects, but have not themselves been traced. They are also known not to be garbage. Untraced objects have not been encountered by the garbage collector at all, and may or may not be garbage. Bakers algorithm traces all accessible objects, relocating each as it goes. When the unvisited set becomes empty, then all live objects are in the visited set, and all objects in the untraced set are garbage. Because the scheme is incremental, an object may become garbage and remain in the visited set for some time, but will be reclaimed at the next collection. A formal description begins by adding to each object a component that describes to which set it belongs: Object :: body : Bag Oop space : UNTRACED UNVISITED VISITED The object manipulation functions are redened to operate on the body part; suitable denitions can be found in Section 8.3. When an object is created it contains no references to other objects and is known not to be garbage, and therefore is marked as visited. init object mk-Object
VISITED
Other than this change, the create operation is as it was in the abstract specication. Similarly, the specication of remove ref from the mark-sweep collector applies to the incremental scheme. The major change occurs in add ref . If a reference is added from a visited object, f , to an untraced object, t, then t must be recorded as unvisited. Otherwise, at the end of the marking phase the sole reference to t may occur in f , which was scanned before t was added to it. add ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set reachable from roots mem pre from to post mem mem from add to obj to mem from if space mem from VISITED space mem to then to mem to space UNVISITED else
UNTRACED
A garbage collection step chooses an unvisited object, p (it does not matter which), marks it as visited, and marks all untraced objects referenced from p as unvisited. If
224
8 Garbage Collection
there are no unvisited objects left, then the untraced ones are reclaimed and the visited ones marked as untraced for the the next cycle of marking; root objects are marked as unvisited. GCstep m Object ext wr mem : Oop rd roots : Oop-set p dommem space mem p UNVISITED in post let unvisited if unvisited then u unvisited let untraced p all refs mem u space mem p UNTRACED in mem mem u mem u space VISITED p mem p space UNVISITED p untraced else mem p mem p space if p roots then UNVISITED else UNTRACED p dom mem space mem p VISITED In Bakers version of this algorithm, when an object changed from untraced to visited or unvisited it was copied into a different area of memory; the transition from unvisited to visited did not require copying. However, every complete garbage collection cycle required all accessible objects to be copied from one semispace to another (a benecial side-effect of this was the compaction of storage, an issue ignored in this chapter).
225
As all garbage collection activity is concentrated on the new set, the invariant insists that no new objects are roots. Otherwise, it is a straightforward extension of the earlier invariant: inv-StateGS mk-StateGS mem roots new remembered roots new remembered dom mem no dangling refs mem is-disjoint roots new is-disjoint new remembered The mutator operations must record the Oops of any old objects that may contain references to new ones. This involves a test in the create and add ref operations, but the remove ref operation does not perform any checks, as this would be expensive in an implementation. Instead, the remembered set that is part of the state is a superset of the true remembered set, which is recomputed when a garbage collection is performed: create from: Oop to: Oop m ext wr mem : Oop Object rd roots : Oop-set wr new : Oop-set wr remembered : Oop-set pre from reachable from roots mem post to dom mem mem mem from add to obj to mem from new new to if from new then remembered else remembered remembered remembered from
to
init object
add ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd new : Oop-set wr remembered : Oop-set reachable from roots mem pre from to
226 post mem mem from add to obj to mem from if from new to new then remembered else remembered remembered remembered from
8 Garbage Collection
The garbage collection operation nds all new objects reachable from the roots and the remembered set, and discards the rest. In addition, any objects in the remembered set which no longer refer to a new object are removed from the remembered set. GC ext wr mem rd roots wr new wr remembered post new remembered mem new : : : : Oop Object Oop-set Oop-set Oop-set p remembered new mem is-disjoint new all refs mem p
m
Because of the presence of the remembered set, the test for reachability does not require a sweep of all accessible objects the sweep area can be conned to the new objects. This is more apparent if the rst line of the post-condition is recast in the following, equivalent form: new reachable fromGS roots remembered new mem
The reachable fromGS function need only take the part of the memory containing the new objects as its argument: reachable fromGS : Oop-set reachable fromGS r m
m
Oop visitGS
Object mr
Oop-set
visitGS : Oop-set Oop Object Oop-set Oop-set visitGS visited mem unvisited if unvisited then visited else let visited visited unvisited in visitGS visited mem all refs mem p dom mem p unvisited
visited
Of course, the scheme just presented suffers from the problem that the new set will increase as new, long-lived objects survive collections. Hence, the aim of generation
227
scavenging, that is to make the collection time imperceptible, will be lost. To keep the size of the new set down, any new objects which survive a predetermined number of collections are tenured: they move out of the new set and are no longer eligible for reclamation. In this scheme, each new object has a record of its age: StateGS :: mem roots new remembered : : : : Oop Object Oop-set m Oop Oop-set
m
When created, an object has age zero: create from: Oop to: Oop m ext wr mem : Oop Object rd roots : Oop-set m wr new : Oop wr remembered : Oop-set pre from reachable from roots mem post to dom mem mem mem from add to obj to mem from new new to 0 if from dom new then remembered else remembered remembered remembered from
to
init object
The add ref operation requires a small change to account for the modied denition of new; this is left as an exercise. The GC operation increases the age of new objects that survive collection, and tenures objects with age threshold. GC ext wr mem rd roots wr new wr remembered : : : : Object Oop Oop-set m Oop Oop-set new in
m
post let new reachable from roots remembered mem new tenure new remembered mem p
dom new
remembered is-disjoint dom new all refs mem p dom new mem
8 Garbage Collection
Oop new p
m
1 p
threshold
The invariant for this state adds the property that all Oops in the ZCT have reference counts of zero:
3 In a typical L ISP system the stack does not consist of objects, but activation records, which cannot be referenced in the usual way by pointers. However, for the purposes of this specication we shall assume that the stack is just a distinguished set of objects (as it is in a Smalltalk-80 system, for example).
229
Note that it is not necessarily the case that all objects with a reference count of zero are in the ZCT: an object that is part of the stack, but not referenced from a nonstack object, will have a count of zero, but will not be in the ZCT. Entry into the ZCT occurs primarily when the last reference to an object from a nonstack object disappears. The accuracy of reference counts is determined by examining nonstack objects only (cf. the denition of ref counts accurate in Section 8.4). ref counts accurateDRC roots mem stack p dom mem RC mem p if p roots then 1 else 0 + count p body mem q
q
dom mem
stack
The create operation distinguishes between references from stack and nonstack objects, and installs the newly allocated Oop in the ZCT if appropriate: create from: Oop to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd stack : Oop-set wr zct : Oop-set pre from reachable from roots mem post let rc if from stack then 0 else 1 in mem mem from add to obj to mem from to dom mem zct if from stack then zct to else zct
to
mk-Object
rc
The create operation creates a new object not on the stack. In systems where it is possible to create an object on the stack a dual of this operation is required, or possibly operations to move an object to and from the stack. These are left as exercises for the reader. The mutator operations are now dened. We have split them into two pairs, depending on whether the object being mutated is on the stack or not. We could have as easily made the test in the post-condition, but in practice the different cases can be distinguished statically and the overhead implied by the post-condition test can be avoided.
230
8 Garbage Collection
Hence, add ref mutates a nonstack object, add ref s mutates an object on the stack, and similarly for remove ref and remove ref s. The post-conditions of the on-stack operations are the same as the abstract operations dened in Section 8.2. This emphasizes that there is no additional overhead on these operations imposed by deferred reference counting. add ref s from to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd stack : Oop-set reachable from roots mem from stack pre from to post mem mem from add to obj to mem from remove ref s from to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd stack : Oop-set reachable from roots mem pre from to refers to to mem from from stack post mem mem from remove from obj to mem from The off-stack operations modify the ZCT appropriately. add ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd stack : Oop-set wr zct : Oop-set reachable from roots mem from stack pre from to post let mem mem from add to obj to mem from in mem mem to inc rc mem to zct zct to remove ref from to: Oop m ext wr mem : Oop Object rd roots : Oop-set rd stack : Oop-set wr zct : Oop-set reachable from roots mem pre from to refers to mem from to from stack
231
Finally, we come to the collection operation itself. This is similar to the recursive freeing operation in Section 8.4, but has the added complexity of maintaining the ZCT and searching the stack. The rst stage of the operation is to identify garbage by nding all entries in the ZCT that do not occur on the stack. The auxiliary function on stack identies whether a particular Oop occurs on the stack. GC ext wr mem rd roots wr stack wr zct : : : : Object Oop Oop-set Oop-set Oop-set in
m
p zct on stack p stack mem post let zct let garbage zct zct in zct stack mem
on stack : Oop Oop-set Oop Object on stack p stack mem q stack p all refs mem q pre stack dom mem The free operation takes a set of Oops representing the garbage objects, computes a bag of Oops, dec, representing the changes in counts of those objects referenced from the garbage, and alters the reference counts accordingly. Any objects whose counts become zero and are not on the stack are reclaimed in the next stage of the recursion. Meanwhile, garbage objects are removed from the stack and ZCT, and the ZCT is recomputed.
8 Garbage Collection
Oop
Object
free freed zct stack mem if freed then zct stack mem else let dec + body mem p
p freed
stack freed freed mem p mem p RC RC mem p count p dec p set dec freed p set dec RC mem p 0 on stack p stack mem zct zct freed p set dec RC mem p 0 on stack p stack mem in free freed stack zct mem
stack mem
8.8 Summary
This chapter has presented a collection of specications that describe different types of garbage collection schemes. While by no means exhaustive, a wide variety of schemes has been covered. Each specication can serve to help explain the scheme (although it should be emphasized that many implementation issues have been glossed over) and can also serve as the rst step in a series of reications towards an implementation. The author thanks Cliff Jones and Ifor Williams for many illuminating and thoughtprovoking discussions on the topic of garbage collection.
233
remove : X Bag X Bag X remove el b if count el b 1 then el b else b el count el b pre count el b 1 X-set set : Bag X dom b set b : Bag X Bag X b p count p a Bag X count p b
dom a dom b
234
8 Garbage Collection
The main stimulus for the inception of VDM was the description of programming languages. It is therefore appropriate that this book of case studies should demonstrate the use of the BSI syntax for language description. A limited amount of notation has to be introduced which has not been used in other case studies but the main emphasis is on precisely the sort of modelling which is familiar in other applications of VDM. This and the next chapter present language descriptions. Here the task is a small procedural language which could be thought of as a micro Pascal. This is the conventional area of denotational semantic denitions whereas the next chapter (and to a certain extent Chapter 11) are more novel applications of denotational semantics.
235
236
9.1 Introduction
The preface of [BJMN87] explains the role played by formal descriptions of programming languages in the development of VDM. Although not covered in [Jon90], the subjects of programming language semantics, and implementations based thereon, remain of crucial importance because of the danger that errors could be introduced into correct programs by erroneous compilers. Furthermore, formal descriptions present the opportunity to dene meaningful and useful reference points for programming language standards. Not only can the formality provide a precise statement, but a suitably written formal specication can also provide a useful starting point for systematic designs of implementations. This chapter presents a description of a small, hypothetical, procedural programming language. The language is kept simple so that the main points can be illustrated in a reasonable space. The reader is referred to [BJ82] for more realistic denitions including A LGOL 60 and Pascal or to the references in the Teachers Notes associated with [Jon90] for, inter alia, work on PL/I and Ada. There are three more-or-less distinct approaches to xing the semantics of a programming language. The oldest approach is to write an abstract interpreter which gives an operational semantics. An axiomatic semantics is a series of proof rules which permit all possible facts to be deduced about valid observations on a programs behavior. Except for the fact that there has been no discussion of completeness, the inference rules presented in [Jon90] are in this mould. For studying language concepts and relating implementations to specications, it is now widely accepted that a denotational semantics is most useful. (A fuller discussion of these alternatives can be found in most books on semantics see, for example, Lucass chapter in [BJ82].) It is obviously not appropriate to explain the method of denotational semantics in any depth here. The basic idea is very simple: given a language L whose semantics is to be dened, one has to provide a way of mapping any construct of L into a language whose semantics are already understood and which, hopefully, is easy to manipulate algebraically. For standard procedural languages, the denotations are likely to be functions in the simplest case functions from states to states. A full language description would contain: A concrete syntax. An abstract syntax. Context conditions (restricting the class of abstract texts). A set of understood semantic objects.
237
A mapping from objects of the abstract syntax (which also satisfy the context conditions) to semantic objects. The issue of concrete syntax descriptions and the design of reasonable concrete syntax is clearly very important but is not considered further here since it is a separate concern. There is a restriction on the semantic mapping known as the denotational rule. This requires that the mapping respects the structure of the abstract syntax: denotations of composite objects are built (only) from the denotations of their components, i.e. the mapping is homomorphic. A fuller description of the denotational method the reader is referred to [Sch86, Sto77] or, for VDM, to [BJ82]. There are several different orders in which a full language description can be presented: here some repetition is employed which should aid the reader but would be avoided in a reference document.
Block :: typem : Id Sctype m procm : Id Proc body : Stmt If :: test : Expr th : Stmt el : Stmt
238 While :: test : Expr body : Stmt Call :: pr : Id al : Varref Assign :: lhs : Varref rhs : Expr
The N ULL statements have no contents; in fact they are only there to cover situations like empty else-clauses in conditionals. Procedures can be dened within blocks: Proc :: fpl : Id m typem : Id Sctype body : Stmt Sctype I NT B OOL
Notice that parameters can only be scalars; this language does not allow procedures to be passed as parameters. Most of the interesting points about expressions can be made with only three simple alternative forms: Expr Inx Rhsref Const
Varref :: Id The set of scalar values (Scval) is dened in Section 9.4. This syntax has not, of course, settled semantic questions like the parameter passing mechanism: these topics are discussed in Section 9.5.
239
Attr
Sctype Procattr
A Procattr contains a list of the types of the parameters: Procattr :: Sctype Sctype see abstract syntax
The type of the context conditions is, in nearly all cases: WF: Text Senv
240
in different scopes; on the other hand, the same variable can be denoted by different identiers (in the same scope) because the parameter passing is by variable. The standard way of tackling this problem is to introduce as an abstraction of machine locations a surrogate for each variable. These surrogates are normally known as locations and here the set is called Scloc (since nonscalar locations are needed in the extensions discussed in Section 9.6). The simple idea of mapping names to values can then be broken into two maps: one from names to locations and the other from locations to values. This is the most basic modelling decision in this denition. It remains to decide where the two maps are to be held. Because it can be changed by any assignment statement, it is natural to place the mapping from locations to values in the store. But the association from names to locations only changes between scopes and this can be clearly reected by placing it in an environment parameter. Most meaning functions then become functions from environments to functions from stores to stores. This sort of higher-order function is very common in denotational semantic denitions. Thus, the denotations of statements etc. are determined with respect to an environment (Env) which contains the denotations of all of the identiers occurring in the text. These denotations are either scalar locations (Scloc) or procedure denotations (Procden). The parameter passing method in this section is by variable so the domain of the functional procedure denotations is a sequence of scalar locations; the range is a store-tostore transformation (Tr) which is dened below. Env Scloc Procden Id
m
Scloc Procden
As for most imperative languages, the denotations of the statement constructs are transformations (Tr) which are functions over Stores. Tr Store Store
Notice that when the signature of Procden is expanded, it is seen to be a function which yields functions as results. The main semantic functions have the type: M: Text Env
m
Tr
A Store maps scalar locations to their values: Store Scval Scloc Scval
9.5 Mapping
241
A number of useful auxiliary functions can be dened for a Store. (The parameter # is used consistently for Store.) Access to, and change of, values are dened by: contents : Scloc Store contents l "# # l Scval
Here, the functional result of contents is dened by the use of a lambda expression. assign : Scloc assign l v Scval Tr "# # l v
Remember that Tr is a functional type which is why a lambda denition is required. New locations are allocated and initialized by a function called newlocs. This function takes a mapping from names to types as an argument and yields a function which is like a transformation except that the function yields an additional result which is an association from the required identiers to their allocated locations. The type information is required since the locations are also initialized. It is desirable not to tie newlocs too tightly.1 Here, it is dened implicitly so as to under-determine which locations are actually allocated. Rather than discuss post-conditions of higher-order functions, the required properties are presented as an implication. newlocs: Id newlocs m # dom , # #
m
Sctype Store Store Id Scloc # , dom m is-disj rng , dom # is-oneone , , id 0 m id I NT , id false m id
B OOL
Locations are removed from store by: epilogue : Scloc-set Tr "# ls # epilogue ls
9.5 Mapping
The mapping from the abstract syntax to the semantic objects is the main part of the denition. Experience with writing larger denitions has resulted in the move to an order in which rather than follow a strict separation of the parts of the denition the abstract syntax, context conditions, and semantic mapping are presented together. This makes it possible to collect all of the relevant information about one language construct
reason for leaving the freedom is so that it becomes easier to prove correct various compiling strategies. It is, however, a moot point whether newlocs is a function at all: this point is not pursued here see [HJ89] for further details.
1 The
242
together in one place. This plan is followed here even though it results in repeating the abstract syntax given in Section 9.2. With such a recursive abstract syntax it is difcult to present the language in an order such that the whole denition can be grasped in one pass. In a reference document, a top-down order is likely to yield a more convenient presentation. Here a bottom-up order is taken: the reader will nd the abstract syntax of Section 9.2 useful to establish the context of the low-level details until the higher-level semantic functions are encountered.
Variable references
The statement which sets the tone of procedural languages is the assignment (cf. Assign in Section 9.2). In a simple case like x : y, the variable on the left-hand side of the assignment must be evaluated to a location and that on the right to a value (A LGOL 68 dereferencing). In this core language, which only has scalar variables, a variable reference is just an identier: Varref :: Id The context condition requires that the identier is known (the reference is in an appropriate scope) and that it refers to a scalar variable (not a procedure). This is done by checking the information stored in the static environment (in all of the context conditions the parameter , is used for Senv): Senv WFVarref : Varref WFVarref mk-Varref id , id dom , , id Sctype
) follows a convention in semantic deniThe use of so-called Strachey brackets ( tions: they set off arguments of the abstract syntax. It is also common practice to omit parentheses around short arguments: thus WFVarref mk-Varref id , is the way that the more familiar expression WFVarref mk-Varref id , is written in a denotational semantic text. In other context conditions, it will be necessary to determine the types of variable references. This information is also obtained from the static environment: Senv Sctype TPVarref : Varref , id TPVarref mk-Varref id , As indicated above, the denotation of a variable reference is the scalar location which is stored in the environment (the meaning functions use Env here, , is used for parameters of type Env):
9.5 Mapping
Env Scloc MVarref : Varref , id MVarref mk-Varref id ,
243
Remember that this yields the location (not the value) corresponding to an identier.
Expressions
Checking the abstract syntax for Assign shows that a Varref , which is to occur in an expression, is embedded in an object which is a Rhsref (in the example above, x : y, the actual abstract object would be mk-Assign mk-Varref x mk-Rhsref mk-Varref y ). So, the abstract syntax of references to variables is given by: Rhsref :: Varref The context condition simply uses that for the embedded variable reference: Senv WFRhsref : Rhsref WFRhsref mk-Rhsref vr , WFVarref vr ,
The same indirection is present in the case of the TP function: Senv Sctype TPRhsref : Rhsref TPRhsref vr , TPRhsref mk-Rhsref vr , The meaning function obtains the contents of the location as computed by MVarref : Env Store Scval MRhsref : Rhsref contents MVarref vr , MRhsref mk-Rhsref vr , This is what distinguishes a right-hand reference whose denotation is a value from a left-hand reference whose denotation is a location. An even simpler form of expression is a constant: Const Any c Scval
WFConst : Const WFConst c , Its type is given by: TPConst : Const TPConst c ,
Senv if c
244
Its denotation (in any environment) is the value of the constant: MConst : Const MConst c , Env Store "# c Scval
Notice that MConst has to be made to depend in a trivial way on the state, so that its signature matches that of MExpr. The relevant points about inx expressions can be illustrated with: Inx :: l : Expr op : Operator r : Expr Operator P LUS O R L ESSTHAN
The well-formedness of inx expressions checks that the operator and operand types match: WFInx : Inx Senv WFInx mk-Inx l op r , WFExpr l , WFExpr r , TPExpr l , TPExpr r , I NT op TPExpr l , TPExpr r , B OOL op
P LUS L ESSTHAN OR
The type of an inx expression is governed by the operator: TPInx : Inx Senv Sctype TPInx mk-Inx l op r , if op L ESSTHAN O R then B OOL else I NT In order to determine the meaning of an inx expression, it is assumed that the meaning of the operators is given by: MOperator: Operator Then: MInx : Inx Env Store Scval MInx mk-Inx l op r , "# MOperator op MExpr l ,# MExpr r ,# Notice that both operands (l r) can be evaluated in the same store (#) because there is no feature in this language which can cause side-effects in expression evaluation. This has covered the only three forms of expression in the language: Expr Inx Rhsref Const Scval Scval Scval
9.5 Mapping
The overall context condition can be dened by cases: WFExpr : Expr WFExpr e , Senv cases e of mk-Inx l op r mk-Rhsref vr otherwise end
245
The signatures of the other relevant functions are: TPExpr: Expr MExpr: Expr Senv Sctype Env Store Scval
Their denitions follow exactly the same case statement form and are not written out here.
Statements
The preceding subsection has prepared everything needed for the assignment statement: Assign :: lhs : Varref rhs : Expr An assignment statement which consists of a lhs and a rhs is well-formed in a static environment , if, and only if: lhs is a well-formed Varref in ,; rhs is a well-formed Expr in ,; and the scalar types found by TP (also in ,) for lhs and rhs are the same: WFAssign : Assign Senv WFAssign mk-Assign lhs rhs , WFVarref lhs , WFExpr rhs , TPVarref lhs , Sctype TPVarref lhs ,
TPExpr rhs ,
The denotation of an assignment statement which consists of a lhs and a rhs in an enviTr) which is determined by the denoronment , is a transformation (assign loc val tations of its constituents in ,. Notice that the value of an expression does rely on the Store while the location denoted by a variable reference does not: MAssign : Assign Env Tr MAssign mk-Assign lhs rhs , "# assign MVarref lhs , MExpr rhs ,# # The simplest form of statement in the language is the null statement (there is exactly one such statement):
246 N ULL
Such an object is always (in any environment) well-formed: WFNull : N ULL Senv WFNull N ULL , true The meaning of a null statement is the identity transformation: MNull : N ULL Env Tr IStore MNull N ULL , Conditional statements contain other statements within them: If :: test : Expr th : Stmt el : Stmt The context condition validates the type of the test and checks the well-formedness of the constituent statements: Senv WFIf : If WFIf mk-If test th el , WFExpr test , TPExpr test ,
The obvious way to show that the evaluation of the test precedes the execution of one or other statement is to write: Env Tr MIf : If MIf mk-If test th el , "# let b MExpr test ,# in if b then MStmt th ,# else MStmt el ,# But this sort of ordering and passing of states occurs so often in denotational semantics that a special def combinator has been provided in VDM which makes it possible to present this as: MIf mk-If test th el , def b: MExpr test ,; if b then MStmt th , else MStmt el , The use of such combinators can signicantly increase the readability of large denitions; it can also make it easier to see that the denotational rule is being followed. The abstract syntax for the repetitive construct is:
9.5 Mapping
While :: test : Expr body : Stmt
247
Its well-formedness condition checks that the test expression has the appropriate type and that the body is well-formed: WFWhile : While Senv WFWhile mk-While test body , WFExpr test , TPExpr test ,
The meaning function again uses the def combinator but also needs to compute the leastxed point of the recursive denition of wh. MWhile : While Env Tr MWhile mk-While test body , let wh def b: MExpr test ,; if b then MStmt body ,; wh else IStore in wh The abstract syntax of call statements is: Call :: pr : Id al : Varref The corresponding context conditions check that pr actually refers to a procedure and that the types of al match the declared parameter types (which have been stored in Procden): WFCall : Call Senv WFCall mk-Call pr al , pr dom , , pr Procattr let mk-Procattr tl , pr in i inds tl TPVarref al i , len tl len al
tl i
The meaning function should be considered in relation to the type of Procden (cf. Section 9.4) which shows that applying a Procden to a list of locations yields a transformation; the fact that the al of a Call is a list of variable references determines that they are evaluated to locations: MCall : Call Env MCall mk-Call pr al let ll MVarref let prden , pr prden ll Tr , al i , i in
elems al in
248
Procedures
Before considering blocks, procedure declarations must be discussed. Their abstract syntax is: Proc :: fpl : Id m typem : Id Sctype body : Stmt The context condition requires that no identier is repeated in fpl and that each such parameter name is given a type in typem; the body must be well-formed in a static environment which is modied to include the parameters: WFProc : Proc Senv WFProc mk-Proc fpl tm s , is-uniques fpl elems fpl
dom tm WFStmt s , tm
(Auxiliary functions like is-uniques are dened at the end of this chapter.) The context conditions for Block need a procedure attribute for each procedure; this is computed by: TPProc : Proc Procattr TPProc mk-Proc fpl tm s mk-Procattr tm fpl
The meaning of a procedure declaration is a function (cf. Procden in Section 9.4) from a sequence of scalar locations to a transformation: MProc : Proc Env Procden MProc mk-Proc fpl tm s , "ll MStmt s , fpl i ll i
inds fpl
It is essential to the normal meaning of procedures that the environment (,) in which their denotations are determined is that of the declaring block. It is this which gives languages with A LGOL-like block structure their lexicographic naming idea. The parameter locations (ll) are derived in the calling environment.
Statement sequences
The body of a block is actually a sequence of statements so some extra functions are required: WFSeq : Stmt WFSeq sl , Senv s elems sl WFStmt s ,
9.5 Mapping
249
The meaning of a sequence of statements is a transformation formed by composing the meanings of the component statements: MSeq : Stmt MSeq sl , "# if sl Env Tr
Blocks
The construct for declaring variables and procedures is a Block, its abstract syntax is: Sctype Block :: typem : Id m procm : Id Proc body : Stmt For blocks the context condition is: WFBlock : Block Senv WFBlock mk-Block tm pm sl , is-disj dom tm dom pm pr rng pm WFProc pr dom pm , tm let prattrm pid TPProc pm pid pid dom pm in WFSeq sl , tm prattrm This requires that the same name is not used for both a scalar variable and a procedure in the same block; it also species that the components of a block must be well-formed with respect to appropriate environments. The local declarations of both variables and procedures are used to form a new static environment in which the well-formedness of the body of the block is checked. Notice that this formulation prohibits recursion direct or indirect because the well-formedness of each Proc is checked in a reduced static environment. The meaning function is: MBlock : Block Env Tr MBlock mk-Block tm pm sl , "# let # , newlocs tm # in pid MProc pm pid let , MSeq sl , , , # let # epilogue rng , #
m
,, in
pid
dom pm in
The locations for the local variables (formed by newlocs) are put into , and are thus available within procedures declared in the same block; local procedure denotations are not because there is no recursion. The denotation of a Proc, pm pid , is found
250
by MProc pm pid , , . The creation of # captures the initialization of the local variables and # is the state after the meaning of the block body has been elaborated this has to have the locations of the local variables removed before the meaning of the block ( Tr) is complete. The abstract syntax of Stmt shows that all of the cases have been dened: Stmt Block If While Call Assign N ULL
The meaning functions and context conditions: WFStmt: Stmt Senv MStmt: Stmt Env Tr can again be dened by cases in terms of the functions dened above.
Programs
The overall structure in the language is a Program: Program :: Stmt The context conditions are dened for all constructs by a function called WF. For a Program the denition is: WFProgram : Program WFProgram mk-Program s WFStmt s in I NTG out I NTG
This denition uses WFStmt which requires a static environment. The creation of the initial Senv reects the fact that the only identiers used within a Program which do not have to be declared in Blocks, or parameter lists, surrounding their use are in and out. Were the language to have a collection of predened functions and constants (e.g. maxint), they would also be stored in the initial Senv. By arranging for one input integer and one similar output value, the overall meaning of a Program turns out to be a function: MProgram : Program MProgram mk-Program s in0 let #0 ,0 newlocs in I NTG out I NTG in0 in let # MStmt s ,0 #0 ,0 in # ,0 out
in
This represents a rather primitive view of communication with the outside world but, clearly, more powerful input and output statements could be added to the language.
251
Parameter passing
It is easy to change the language so as to make all parameter passing work by value. The abstract syntax (cf. Section 9.2) need not be changed at all. (If as in Pascal the programmer is to be given the choice between by value and by variable parameter mechanisms, the abstract syntax of procedures must be extended to show which parameters are to be passed in which way.) The modied procedure denotations reect the type of the object to be passed at call time: Procden Scval Tr
Although one need not change call statements, it is now possible to generalize the arguments so that: Call :: pr : Id al : Expr The context condition for call statements (WFCall) need only be changed so that the expressions in al are handled. The changes necessary to the meaning function for Call show the store explicitly since it is needed for expression evaluation: MCall mk-Call pr al , # let vl MExpr al i ,# i let prden , pr in prden vl # inds al in
The nal change involves the semantics (Procden) of procedure declarations. Unlike the by-variable case, locations must now be found for the fpl when the procedure is invoked (and removed after execution of the body): MProc : Proc Env Procden MProc mk-Proc fpl tm s , vl # let # , newlocs tm # in # , fpl i vl i i let # MStmt s , , # in let # epilogue rng , #
inds fpl
in
Parameter passing by value/result is interesting because it provides a way for a procedure to change the values of its arguments without creating the aliasing which com-
252
plicates reasoning in the case of parameter passing by variable. The syntax of Call statements reverts (i.e. arguments can only be variable references) to that in Section 9.2. Procedure denotations also revert to: Procden Scloc Tr
The meaning of call statements is identical with that in Section 9.5. The whole effect is seen in the change to: MProc : Proc Env Procden MProc mk-Proc fpl tm s , ll # let # , newlocs tm # in let # # , fpl i # ll i i MStmt s , , # in let # rng , # ll i # , fpl i
inds fpl i
in
inds fpl
Here, the key point is the copy back of the results after execution of the procedure body.
Multiple assignment
Suppose the language were extended to include a multiple assignment statement: Stmt Massign
Massign :: lhs : Varref rhs : Bexpr This is a place where, if the wrong choices are made, the semantics (i.e. language) would become messy. Obviously the left-/right-hand sides want to be the same length. The case for avoiding repeated identiers (e.g. v1 v1 : true false) is strong. So a reasonable context condition is: WFMassign : Massign Senv WFMassign mk-Massign lhs rhs , len lhs len rhs is-uniques lhs i inds lhs WFVarref lhs i , WFExpr rhs i , TPVarref lhs i , TPExpr rhs i , But there is still the open issue of when expressions are evaluated in relation to the assignments. Does: v1 : true; v1 v2 : false v1
253
set v2 to true or to false? Here a semantics which evaluates all of the right-hand side in the same store and then makes all of the assignments is given (but the alternative is not wrong, it just represents a different language): MMassign : Massign Env Tr MMassign mk-Massign lhs rhs , # let locs MVarref lhs i , i inds lhs in MExpr rhs i ,# i inds rhs in let vals vals i i inds lhs # locs i
Composite types
Pascal-like records provide one example of composite types. It is easy to extend the syntax of Section 9.2 to cope with records whose elds are selected by identiers: Type Block :: typem : Id m procm : Id Proc body : Stmt Type Sctype Rectype Id
m m
Rectype
Type
Notice that, because Rectype recurses back to Type, records can be nested to arbitrary level. No context condition is given so that it is possible to use the same eld selector at a I NT ). different levels in the same record (e.g. a If records are only manipulable via their scalar components, it is easy to make the requisite changes to the abstract syntax and context conditions. The interesting decision relates to the handling of the record structure in Store Env. If scalar elements of records are to be passable as (by variable) parameters, it is much easier to construct a denition in which the structure of records is shown in the locations (rather than in the values). Thus the environment is changed so as to make it possible to nd scalar locations and Store is kept as a map whose domain is Scloc. Senv Attr Env Loc Id
m
Attr
Type Procattr Id
m
Loc Procden
Scloc Recloc
Scval
There is no need to change the context condition for Block (WFBlock) given in Section 9.5. The major changes come with variable references: Varref Scvarref Fldref
MScvarref : Scvarref Env Scloc , id MScvarref mk-Scvarref id , Fldref :: rec : Id ds : Id WFFldref : Fldref Senv WFFldref mk-Fldref rec ds , rec dom , , rec Rectype match ds , rec match : Id Type match ds rtp if ds then rtp Sctype else rtp Rectype hd ds
TPFldref : Fldref Senv Sctype TPFldref mk-Fldref rec ds , select : Id Type select ds rtp Type if ds
select ds , rec
selectd ds , rec
255
The function selectd is identical in denition to select: some ML-like polymorphism would allow one function to be used for both tasks. Notice that the meaning of a righthand-side reference is as before (M mk-Rhsref vr ,#). It is now possible to sketch a semantic model for one-dimensional Arrays. The rst part is easy: Varref Scvarref Arrayvarref
Varattr Procattr
Sctype Arrayattr
Arrayattr :: Sctype WFArrayvarref : Arrayvarref Senv WFArrayvarref mk-Arrayvarref arr ssc , , arr Arrayattr TPExpr ssc , I NT It is important that the component relation (of the arrays) is placed in the Env so that sublocations (or even A LGOL 68 style slices) can be passed as (by variable) arguments. Thus: Env Loc Id
m
Loc
Arrayloc
Notice that this model assumes that arrays are indexed from 1. Further generalizations are not difcult but one must think about the (normal) regularity constraints on the shape of Arrays.
256
9.7 Appendix
Auxiliary functions
In common with other uses of VDM, it has been convenient to extract some auxiliary functions whose denitions are given here. is-disj : X-set is-disj s1 s2 is-uniques : X is-uniques l X-set e s1 e s2
ij
inds l i
li
lj
9.7 Appendix
257
Abbreviations
Arrayloc Attr ATTR Const disj Env Expr Fldref Id Loc Massign Proc Procattr Procden Recloc Rectype Rhsref Scloc Scval Scvarref Sctype Senv Stmt Tr TP Varref WF array location attribute attribute (of a procedure) constant disjoint environment expression eld (of a record) reference identier location multiple assign procedure procedure attribute procedure denotation record location record type reference (to a variable) scalar location scalar value scalar variable reference scalar type static environment statement transformation type (function) variable reference well-formed (function)
258
10 Object-oriented Languages
Mario I. Wolczko
Continuing with the language specication theme introduced in the last chapter, Mario Wolczko examines what is meant by the term object oriented. Firstly he identies the essential features of these languages namely the ideas of object, message, method and class. Following this an abstract syntax for a hypothetical language is introduced and the semantics specied in the conventional denotational style. Lastly, the notion of inheritance is briey discussed and a specic model specied. The material in this chapter shows how formal specication techniques can be used, at an early stage in the language design process, to investigate the meaning of novel language features. Once the meaning of these features has been decided upon a fuller language definition exercise can be undertaken with some degree of condence that the essential structure of the language is well founded.
259
260
10 Object-oriented Languages
10.1 Introduction
One of the earliest applications of VDM was to the formalization of programming language semantics. The VDM approach to denotational semantics has been used to describe a wide variety of programming language features, and a substantial number of real languages. In [BJ82], for example, can be found complete denotational descriptions of Pascal and ALGOL-60. In this chapter, VDM is used to investigate the semantics of object-oriented languages. Although the object-oriented approach has been around for two decades, it is only recently that it has gained widespread attention and popularity. Moreover, there is much confusion as to what exactly characterizes an object-oriented language. The aim of this chapter is to present a semantic model of the core features of object-oriented languages, so that any comparison between object-oriented and conventional languages may be based on rmer foundations.
261
The behavior of an object is described by its response to a message. For each different sort of message, a method is dened this is the procedure that will be activated in response to that sort of message. A collection of methods can dene completely the behavior of an object. Usually such collections are named, and referred to as classes. All objects instantiated from a class, and therefore having behavior dened by the class, are known as instances of the class. These, therefore, are the core concepts we need to describe: objects (including primitive objects and those with instance variables), messages, methods and classes. We shall do this by inventing a small and simple object-oriented language, and specifying its semantics.
Modelling objects
The rst stage is to model objects. We shall divide objects into two categories, primitive and nonprimitive (or plain), and place them in an object store. Each object will be identied by a unique handle known as an Oop (short for object pointer). These are the keys to the object memory; indexing the store with an Oop will return the associated object: Object memory Oop
m
Object
Every object has two parts: a body for the data part, and a class identier for the behavior. We shall assume that classes are immutable, so that we need not represent them directly in the object memory: Object :: class : Class name body : Object body Class name :: Id Plain objects associate a value with each instance variable; this value can refer to any other object. Primitive objects stand for themselves. In our simple language, the only sort of primitive object is an integer. In real languages, other objects, such as characters and real numbers, might be primitives. Object body Plain object Plain object Primitive object Id
m
Oop
Primitive object The following auxiliary functions are used to access and modify a plain objects instance variables:
262 inst var : Id Oop inst var iv oop # Object memory body # oop Oop iv
10 Object-oriented Languages
update inst var : Id Oop Oop Object memory Object memory update inst var inst var oop value # # oop # oop body body # oop inst var value
The denotation of a class is a collection of method denotations, indexed by message name. The name of a message is usually termed a selector. Class den Selector
m
Method den
Computation proceeds by objects sending messages to each other. In response to a message, an object will invoke a method, which in turn can access the instance variables of that object, or send messages to other objects. Let us now examine the abstract syntax of our simple language.
Class body
However, most methods contain a body, which is a single expression, and a declaration of the parameters to the method: Method Method body
Method body :: Params : Ulist Id Expr : Expression The parameter list is a sequence of identiers, no identier appearing more than once in the sequence: Ulist X where inv-Ulist X l card inds l card elems l X
There are ve basic types of expression, in addition to expressions which are the sequential composition of subexpressions: Expression Expression list Assignment Object name Message New expr Literal object
Expression list :: Expression Note that this is an expression-oriented, rather than statement-oriented language. Every expression returns a value, but the value can be ignored. An assignment evaluates an expression and assigns the result to a variable. Assignment :: LHS : AVar id RHS : Expression There are three types of identier accessible within a method: Instance variables are used to access the mutable state of the object processing the current message (the receiver) Argument identiers refer to the Oops passed with the current message Temporary variables provide working store within a method. Only instance and temporary variables can be assigned to within a method. Arg id :: Id Temp id :: Id
10 Object-oriented Languages
In addition, the self keyword refers to the receiver. Object name Var id Var id S ELF
When sending a message, one expression is evaluated to determine which object will receive the message, and other expressions can be evaluated to pass arguments to the message. The message selector itself is determined from the program text. Message :: Rcvr : Expression Sel : Selector Args : Expression To create a new object, a new-expression is evaluated, naming the class of object to be created. The values of the instance variables of the new object will be undened initially. New expr :: Class : Class name Primitive objects cannot be created via a new-expression; they are created by being named by a literal. Literal object Int literal :: Int literal
10.4 Semantics
Having described the syntax of the language, we can proceed to specify its semantics. (For brevity, we shall omit a formal description of the context conditions, stating them informally where appropriate.) We require a collection of semantic functions that take the appropriate syntactic elements, together with any relevant context, and map them to their denotations. The denotation of the entire program will be the denotation of the initiating expression, in the context of the other classes. Supplying this expression with an initial, empty store will yield the result of the program, which we will choose to be the nal store, together with the result of the expression. Answer Oop Object memory
10.4 Semantics
MProgram : Program Answer MProgram mk-Program rootc init classes let ,0 c MClass body classes c ,0 c dom classes create mk-Object rootc let root oop #0 !0 mk-DEnv root oop result !r #r MExpression init ,0 !0 #0 in result #r SEnv Class name
m
265
in
Class den
The rst line establishes the relevant context for the initiating expression. This is a map containing the denotations of all the classes in the program, and is known as the static environment. The use of ,0 on the right-hand side indicates that we are taking the least xed point of this expression [BJ82]. The second line creates the root object and adds it to the empty store, and the last two lines evaluate the denotation of the initiating expression in the initial store and return the result (the meaning of the ! expression will 0 become clear below). The denotation of a class is the composition of the denotations of its individual methods: MClass body : Class body SEnv Class den MClass body meths , sel MMethod meths sel sel , sel dom meths The denotation of a primitive method is itself; MMethod body is used to describe the denotation of a nonprimitive method. Selector SEnv MMethod : Method Primitive method if m Primitive method MMethod m sel , then m else MMethod body m sel , Primitive method Method den Method den
Within the execution of a method we need to record the values of the variables local to that method (arguments and temporaries), as well as the receiver of the method. These are collected together into a dynamic environment, and this is passed from expression to expression within the method. DEnv :: Rcvr : Oop m Oop Params : Id m Temps : Id Oop
266
10 Object-oriented Languages
The following function can be used to set or update the value of a temporary: update temp : Id Oop DEnv DEnv ! Temps update temp id value ! Temps ! id value
The denotation of a nonprimitive method is a function that creates an initial dynamic environment (binding formal to actual parameters), and evaluates the body of the method in that environment. The environment is discarded when the method returns. SEnv Method den MMethod body : Method body Selector MMethod body mk-Method body formals expr sel , "rcvr actuals # let ! mk-DEnv rcvr bind args formals actuals result ! # MExpression expr , ! # in result # bind args : Ulist Id Oop bind args formals actuals Id Oop formals i
m
actuals i
inds formals
The denotations of the various types of expression are similar functions, but they also take an environment parameter, and return a (possibly modied) environment in addition to the result Oop and object memory. 2 The denotation of an Expression list is straightforward: Object memory Oop DEnv Object memory MExpression mk-Expression list exprs , ! # let oop ! # MExpression hd exprs , ! # in if len exprs 1 then oop ! # else MExpression mk-Expression list tl exprs , ! # An assignment expression updates either an instance variable of the receiver, or a temporary in the dynamic environment: MExpression mk-Assignment id rhs , ! # let result ! # MExpression rhs , ! # in cases id of result update temp t result ! # mk-Temp id t mk-Inst var id iv result ! update inst var iv Rcvr ! result # end
2 Most of these denitions could be shortened by the use of combinators [BJ82], but for simplicity the explicit forms have been used.
MExpression : Expression
SEnv
DEnv
10.4 Semantics
267
The various forms of object name extract values from the receiver or the dynamic environment: MExpression mk-Arg id id MExpression mk-Temp id id , ! # , ! # Params ! id ! # Temps ! id ! #
Note that the value of an uninitialized temporary is undened. The crucial part of the denition is the semantics of message-sending. First, the receiver and arguments must be determined: MExpression mk-Message rcvr sel arglist , ! # let rcvr oop ! # MExpression rcvr , ! # actuals ! # MExpression list arglist , ! # result # perform sel , rcvr oop actuals # in result ! # The following function evaluates a list of expressions, returning a list of results: MExpression list : Expression SEnv DEnv Object memory Oop DEnv Object memory
MExpression list el , ! # if el then !# else let val ! # MExpression hd el , ! # val list ! # MExpression list tl el , ! # val val list ! #
in
Next, the perform function is given the receiver and argument Oops, and evaluates the message by 1. determining the class of the receiver; 2. looking up the denotation of that class in the static environment; 3. applying the denotation of the class to a selector to yield the denotation of the appropriate method; 4. applying the denotation of the method to the relevant Oops and object memory.
10 Object-oriented Languages
Object memory Oop Object memory , class # rcvr sel rcvr args #
Creating a new object is straightforward. We use a nondeterministic specication for the create function, because it does not matter which particular Oop is allocated to the new object, only that it has not already been allocated. MExpression mk-New expr class , ! # let new oop # create mk-Object class new oop ! # create obj: Object new oop: Oop ext wr # : Object memory post new oop dom # # # # in
new oop
obj
The only unusual aspect of the semantics of literals is that the implementation can choose to make a new object for the literal, or nd an existing object with the same value. Because literals are immutable, these options are equivalent. MExpression mk-Int literal int , ! # let oop # nd or make immutable int Integer # in oop ! # nd or make immutable: Primitive object Class name
Object memory
Oop
Object memory
nd or make immutable value: Primitive object class: Class name obj: Oop ext wr # : Object memory post # obj mk-Object class value # # obj
Finally, we give an example of a primitive method: integer addition. This function simply nds or creates an integer object with the value that is the sum of its operands. plus primitive : Primitive method plus primitive "rcvr oop arg oop # nd or make immutable body # rcvr oop
10.5 Inheritance
269
10.5 Inheritance
Inheritance is an important feature in object-oriented languages. However, it not an essential feature, as some have argued [Str87]. For example, the simple language just described is most certainly object-oriented, but does not have any form of inheritance. There are many different inheritance schemes, but most seem to fall into one of two camps: class-based or object-based. In class-based inheritance, a class may have a number of parent classes from which it inherits method denitions and instance structure. An instance of such a class responds to the methods dened in that class, plus any inherited from parent classes (or, in turn, their parents, and so on). Similarly, such an instance will have the instance variables dened by the class in addition to any dened by ancestor classes. Interesting variations in design are used to resolve name clashes between instance variables and method names in different ancestor classes [Wol88]. In object-based inheritance, an object can inherit directly from other objects. In some languages, the pattern of inheritance can even be changed at run-time, whereas inheritance between classes is usually static. In most languages with object-based inheritance a special form of message-sending, known as delegation, is used. As Lieberman has shown [Lie86], delegation can be used to emulate class-based inheritance, but the converse is not true. To conclude this chapter, we will extend our tiny object-oriented language to include delegation. This will give us a simple yet exible form of inheritance.
Delegated method :: Id The denotation of a method will have to take an extra argument, representing the Oop of the client. This will also be stored in the dynamic environment, and will be
270
10 Object-oriented Languages
accessible via a keyword, client, analogous to the keyword self. Method den Oop : : : : Oop Oop Object memory Oop Object memory
Var id
MExpression C LIENT , ! #
A conventional message send sets self and client to be the same object; this requires a small modication to MExpression, and a further change to perform to pass the client Oop to the method denotation: MExpression mk-Message rcvr sel arglist , ! # let rcvr oop ! # MExpression rcvr , ! # actuals ! # MExpression list arglist , ! # result # perform sel , rcvr oop rcvr oop actuals # result ! # perform : Selector SEnv Oop Oop Oop
in
perform sel , rcvr client args # , class # rcvr sel rcvr client args # Additionally, MMethod body is altered to save the client Oop in the dynamic environment: SEnv Method den MMethod body : Method body Selector MMethod body mk-Method body formals expr sel , "rcvr client actuals # let ! mk-DEnv rcvr client bind args formals actuals result ! # MExpression expr , ! # in result # Finally, a meaning function for delegating methods is required. This simply evaluates the message for the object being delegated to, passing on the client Oop:
271
10.8 Summary
In this chapter we have illustrated how the basic mechanisms of object-oriented languages can be described using VDM: Objects require a particular memory structure, based on two-level map (from Oop to objects, and thence to Oops again). Message-sending requires that the binding of messages to method denotations take place on every message send. Classes can be described as functions that interpret messages. In addition we have shown how the simplest form of inheritance, namely delegation, can be added to the basic model.
272
10 Object-oriented Languages
This chapter introduces two interesting aspects of VDM specications. Ostensibly, the paper describes a machine architecture and, as such, is the rst excursion into hardware description presented in this book. In spite of the use of the word software in the title of this book, this chapter ts the overall style of contributions. In fact, it illustrates well the fact that a VDM specication written at the right level of abstraction could be reied to either hardware or software implementations. The particular machine discussed is the tagged dataow architecture developed at Manchester University. The machine exhibits a form of parallelism but this is reduced in the formal specication to nondeterminism. The description strongly resembles the denotational semantics descriptions in the two preceding chapters, but here the denotations have to be relations in order to encompass the nondeterminism.
273
274
11.1 Introduction
This chapter presents an outline of a semantic description of the Manchester Dataow Machine (MDFM) written in VDM with some extensions. The full description can be found in [Jon86b], which includes the design of a nondeterminate applicative programming language and the development of an associated compiler. This work can be taken as illustrative of the extension of traditional VDM methods to parallel or, more generally, nondeterminate environments. Dataow machines would seem to serve as a good example in this situation since they are inherently nondeterministic and seem likely to be of importance in the future due to commercial interest. The rest of Section 11.1 provides an introduction to the ideas behind dataow machines, in general, and the Manchester Dataow Machine in particular. Section 11.2 describes the development of a denotational semantics for this machine. The complete version is discussed in Section 11.3. Section 11.4 draws together some comments on this work.
Dataow machines
In order to understand the formal model that follows, this section gives some background to the concepts involved in dataow computing. For a more complete description, see the publications of the Dataow Group at Manchester University (e.g. [GW83]). All dataow machines are based on the theoretical concept of a dataow graph. Such a graph is a structure consisting of nodes and arcs. These represent operations and data paths, respectively. Graphs are represented pictorially as shown in Figure 11.1. When all the input tokens to some nodes are present, action can occur. This action, called ring, consists of the consumption of the input tokens, followed by the computation and production of the corresponding output tokens. In Figure 11.1 nodes 1 and 4 are in a position to re since their input tokens are present. More formally, dataow graphs are considered to be two-dimensional descriptions of a partial ordering on computational events. They are structured by data dependency. Nodes represent indivisible atomic actions. Arcs connect dependent nodes unidirectionally, showing the direction of dependency. They are connected to the input/output points of nodes. Tokens are items of data passed along arcs. A node may execute only if all of its inputs are available. This is referred to as the ring rule. It will, at some time in the future, consume the tokens on the input arcs. Later, a result token is produced on the output arc. This is the only constraint on execution, so it can be seen that all sequencing is implicit in the model. This means that a central controller, such as the program counter of the von Neumann model, is unnecessary. Variations on the model exist which affect the exact denition of the ring rule, but all follow the above description to some extent. The concept of a dataow machine arose from considering direct execution of these
11.1 Introduction
275
Figure 11.1 An example of a dataow graph graphs. Data are represented as tokens actually moving along arcs. An architecture that uses (a representation of) these graphs as its basic programs forms the basis of a dataow machine. The graph showing data dependencies does not enforce a linear ordering. It can be seen how this partial order leads naturally to a parallel architecture. At any point in time, more than one node may be in a position to re. Any (or all) ready nodes may be activated in parallel (since they are independent) provided there are sufcient processors available. The major difference between various implementations of the dataow model can be found in the way code reusability is dealt with. Reusable code causes a problem, since it is necessary to preserve the context of tokens in order to ensure correct tokens are matched together. One approach is to make all arcs rst in rst out (FIFO) queues. In the extreme case, these queues are limited to a maximum length of one. This gives the static approach to dataow (using the terminology of [GW83]). This is capable of handling re-usability in an iterative sense but does not naturally extend to recursion, since multiple re-entry would cause difculties. Recursion can be simulated by copying portions of the graph. Alternatives to the queuing strategy have been proposed, usually in an attempt to increase asyncronicity. In the Manchester Dataow Machine [GW80], code is made
276
truly re-entrant by forcing tokens to carry tagging information, to preserve matchings. From a pragmatic point of view, the dynamic tagged approach seems to give certain advantages in terms of available parallelism and quantity of code held. There is no proliferation of program code by copying, and reuse is limited only by the number of tags (sometimes called colors) available.
Token :: Data Label Destination The meaning of these elds is given below: data gives the value (and type) of the token, e.g. an integer, a character, etc. See [Kir81] for full list of types and values. label is the tag used to identify the token uniquely. This actually consists of three subelds which are used as:
1 See
11.1 Introduction
277
Host
Switch
Token queue
Matching store
Processing unit
P.E. 1 . . . P.E. n
Node store
Figure 11.2 The conguration of the Manchester DataFlow Machine 1. activation name separates instantiations of re-entrant code in the case of functions; 2. iteration level used for iterative code;2 3. index used for data structuring. destination is used to identify the node to which the token is being sent, i.e. it implicitly denes the data arcs. This eld also includes other information which is described below. The machine is physically based on a ring structure. This is composed of a number of independent units around which the data tokens (and composite structures) circulate. The ring has the conguration shown in Figure 11.2. Specic details such as number of bits in a token, catalog number of processing elements, length of wire between units and other information vital to engineers will not be given. Anyone interested to this level should consult [Gur82]. Next, each unit on the ring is looked at in more detail. 1. The switch This routes information to and from the host machine. It can be ignored if input
2 Fields
278
2. The token queue This unit is present for purely pragmatic reasons. It is used to buffer tokens. The actual representation strategy has no effect and both a FIFO queue and a stack are used interchangeably. This has no effect beyond some difference in processing speed for particular sorts of programs. 3 3. Matching store This is a unique feature of the MDFM and gives the architecture a exibility that would not be found in a pure dataow machine. Assuming all nodes are binary, a simplied description of the function of the matching store can be given as follows. When a token enters the matching store, a search is made within the store for the matching token. A token matches if it has the same destination (i.e. is going to the same node) and the labels are identical. If such a match is made, the pair are packaged together into a group package and passed along the ring to the node store. If no match is found then the incoming token is placed in the store to await the arrival of its matching token. More complex matching facilities are available and these are described later. 4. The node store This unit holds the representation of the dataow graph and can be taken to be equivalent to the program store of a conventional machine. Each node of the graph is stored, according to the representation described above, in a uniquely addressed location. This representation, actually consisting of an operator code and a node store address representing the arc to the next node, is loaded into the store from the host. This is similar to the loading of a program in a conventional machine. When a group package arrives from the token store, the relevant node is selected according to the destination eld of the incoming tokens. A copy of the operator and the result destination are added to the package. This is known as an executable package. It is then sent to the processing unit. 5. The processing unit This is the actual computing unit of the machine. It consists of a number (up to twenty in the current machine) of independent processing elements. Each is capable of accepting an executable package, performing the specied operation
3 That is not completely true. Changing the queue/stack switch could sometimes have an interesting effect, since some local wizards have been known to depend on properties of the queue to make unsafe programs execute.
11.1 Introduction
279
and producing the result token with the appropriate destination eld. This is then passed on round the ring. It is in this area of the machine that true parallel processing is found. Since the processing elements operate independently, they accept incoming packages on an availability basis, in parallel. In summary, the action of the MDFM (after initialization) is: A token enters the matching store. If the matching partner is not present within the store, the incoming token is placed in the store to wait. If the matching token is found, then all inputs to a particular node are present and that node is eligible to re. The tokens are grouped together and sent to the node store. The relevant operator and the result destination are picked up. This package goes to the processing unit where it is executed by one of the processing elements, producing a result. This is sent back around the ring to continue the process. The termination of a program, executed on this machine can occur in one of two ways. The rst way is clean termination. In this case, all tokens have left the ring (i.e. have been given destinations in the host and so are switched out). Termination occurs when there are no tokens left anywhere in the ring and the host machine has received all expected output. In the second case,4 output is handled as above but the difference is that tokens are still present in the ring. As will be seen below, use of special matching functions can cause tokens to be left in the matching store with no possibility of a matching token ever arriving. In this case, the program is said to terminate when all tokens left in the ring are stored in the matching store (i.e. there is no chance of a match, and so no possibility of any further action). It is intended that good examples of dataow programs leave the store empty. A dataow program which does so is said to be well-formed. As was mentioned earlier, one interesting feature of the MDFM is the fact that dataow arcs can be generated dynamically, i.e. during execution. The mechanism for handling this is the provision of primitive operations to extract and set the destination elds of tokens. In fact, destinations, colors, etc. can generally be handled as data values. (For precise details, see [Kir81].) The above description of the operation and structure of the MDFM is sufcient for a general understanding of the machine. However, it does contain one major simplication. In reality, the matching store may be used in a more complex manner.
4I
suppose this could be called unclean termination but usually it is politely ignored.
280 Matching
The matching process described above is the default action of the store. This is known as extract wait EW since its function is to extract a token if there is a match and to cause a token to wait otherwise. This is sufcient for almost all normal programming and represents pure dataow. However, there are cases, such as explicit nondeterminate programming, where other actions may be desirable. To facilitate this, the action of the matching store can be controlled explicitly by use of a matching function carried by the incoming token. This matching function species the action to be taken by the matching store, both in the case of a match and a failure to match. These are usually denoted by a two-letter code, the rst denoting the match action and the second denotes the fail action (as in EW above). This code is carried in the tokens destination eld, along with the (previously described) node address. Before going into the detail of matching, it is necessary to give a more complete description of a token. In fact, the destination eld contains a further subeld known as the input point. This species whether the token is the right or left operand of the node to which it is sent. This also explains the manyone matching situation mentioned in defer, below, in that two tokens with the same input point could arrive before the matching token with the opposite input point. The situation where two tokens with identical destination elds are both present in the store is forbidden in the MDFM (since a true matching token would have the opposite input point) and is known as a matching store clash. The matching function defer exists to avoid such a clash. In dataow terminology, a program is said to be unsafe if there is the possibility of store clashes and safe if there is no such possibility. In the current implementation, there are four possible match actions and four possible fail actions. These are listed below. Match action 1. Extract The matching token is removed from the store, combined with the incoming token to form a group package and passed on to the node store. 2. Preserve A copy of the matching token (present in the store) is taken to form the group package but the stored token is not removed from the store. 3. Increment As preserve, except the token in store has its value eld increased by one. 4. Decrement As increment, except the eld is decreased as opposed to being increased.
11.1 Introduction
Fail action
281
1. Wait The incoming token is placed in the store to wait for a match. This is the normal way of placing a token in the matching store. 2. Defer The incoming token is not stored but is passed back to the token queue (via the rest of the ring but in transparent fashion) to be resubmitted. This is used to avoid store clashes when many tokens could potentially match. 3. Abort The incoming token is not stored but it is grouped with a special EMPTY token and passed on. This is usually used to control explicit nondeterminacy. 4. Generate The action of generate is identical to abort except that a copy of the incoming token with its input point is stored. This means future tokens with identical destinations to the original incoming token will nd a match. This again nds its main usage in situations involving nondeterminacy. There is also a further matching function, bypass BY , which simply allows the token to pass through the store unaffected. This is used for input to unary nodes where no matching is required. Not all possible combinations of available matching functions are implemented. The currently available combinations are: 1. Extract wait EW 2. Bypass BY 3. Extract defer ED 4. Preserve defer PD 5. Increment defer ID 6. Decrement defer DD 7. Extract abort EA 8. Preserve generate PG
282
For a more complete description of the function and usage of matching functions on the MDFM, the reader is referred to [Bus83]. By the use of special matching functions, it is possible to deviate considerably from the model of pure dataow. As Section 11.3 illustrates, this causes increased complexity in the formal semantics of the architecture.
283
A Destination contains the Node address to which the value is to be sent plus an Input point. 8 Destination :: NA : Node address IP : Input point The meaning of an individual Node is dened (by the function M ) in terms of N the application of its operator to the values in a set of appropriate input Tokens and the creation of a new Token containing the result sent to the given Destination.
Node
A subsidiary function ips is used to identify the Tokens destined for a particular Node. ips : Node address Token-set t ts NA D t ips d ts Token-set d
The meaning of a program is dened as the xed point of a relation over token sets. The basis of this expression are those sets of Tokens in which no further computation is possible. 9 Any Node which has two input Tokens can be red, i.e. the M function N can apply. To allow for the parallelism in the machine (which is side-effect free), all such Nodes can re at once. This is modelled by use of a distributed union:
2 2
The above formulae can be interpreted as follows. A meaning function M is P given from a program to a relation on token sets. The meaning of a program is found by
8 At this level of simplicity, input points are not checked. However, if they were not included, two tokens with identical values input to a node would be coalesced by the set construction, preventing valid rings occurring. Since the set construction is required in later denitions, it does not seem appropriate to use (say) a pair construct here. 9 In this simple case, that means there are no Nodes which have two input Tokens.
284
ADD
ADD
MUL
Figure 11.3 A simple example building a xed point, backwards from terminated states. The basis for the construction is the set of states that do not change (i.e. have no nodes that could possibly re). States that can be arrived at by an eligible node ring are added at each step. This is done for all eligible nodes and the distributed union is taken. The ring of a node is represented by the removing of its input tokens from, and adding its result tokens to, the state. The result of a particular node ring is given by the meaning function MN on given node address. This is dened to be the construction of a result token which has the result destination and a value given by the node operator being applied to the input values. The input set ips of the node is generated, giving the candidates for ring. This gives the general idea of the way in which the semantics is developed. In order to gain a better grasp of the formalism, and the way it works on a dataow program, it is worth examining a small example. c d , as shown in Figure 11.3. If we look Consider the graph to calculate a b 10 at how this graph would be represented, we get to following node store: ns
10 For
3 2
3 3
out
285
where 1, 2 and 3 are destinations (representing the node store addresses). out is just meant to represent a destination that is not within the graph being considered. Assume the initial token set is: ts0 vala 1 valb 1 valc 2 vald 2
The construction of the relation is based on the nal states (i.e. those which will not transform further). It can be seen that the relation must allow the following actions. At the rst step, either node 1 or node 2 could re giving:
R
ts1
ts0 ts1
tso ts2
valc 2
vald 2
and ts2 results from node 2 ring, i.e.: ts2 vala 1 valb 1 valc
d
derived from the MN function on the + operator in each case. At the next step only 1 or 2, depending on which has not already red, is eligible to re, and so on. So, it can be seen why the meaning is given as a distributed union within a xedpoint construction. The xed point builds the sequences of token sets produced as each action takes place in time. Each future action is enabled by the tokens produced at the current step. The starting point for the construction is the set of tokens for which no action takes place. This undergoes the identity transformation. Each step in the construction represents a ring action taking place. The union operation allows for many nondeterministic choices of which of the eligible nodes actually res at any particular step. In other words, all possible computation paths are included in the expression. This should enable an intuitive grasp of the semantics. More complex examples are not presented in detail as they very quickly become tedious.
A Node is extended to contain information about the number of expected inputs and the output Destination is generalized to a set: Node :: O : Operator D : Destination-set Operators now contain details of their arity in addition to the Function. Operator :: F : Function NIP : Function: Token-set Destination-set Token-set Since the denitions are seen to be becoming longer, a slightly different style of denition is used for MP . The identity relation over the set s is written as Es , following [Jon81]. The relation is now dened in terms of relational composition (; ) over R . This combinator has the following type:
Token-set
Token-set -set
is normally used in an inx form and has the usual meaning for composition. Using the following operators:
the meaning of a single node ring is extended to the relational type to allow use of composition:
Token-set
Token-set -set
rdys d ts n
ts
Token-set
287
The function rdys extracts those sets of Tokens which constitute complete input sets to the given Node: rdys : Nodeaddress Token-set rdys d ts nip rts ts t1 t2 rts L t1 Token-set -set L t2 NA D t1 d card rts nip
Most of this denition should be easily understood since it does not differ very much from the earlier denition above. The noticeable additions are the checking for a given cardinality on a nodes input set as opposed to the default of two in a binary case and the multiple level of choice on the rdys function. This is due to the fact that it is necessary, in the rst instance, to select all possible ready sets to the given node and to take the distributed union of the result of any of these being used. This gives the desired result at the MN level. The use of MN and ; (relational composition) within the denition of M make it P easier to see how the composition is used to build xed point. This notation is maintained for the later denitions. Termination Before increasing the complexity of the machine any further, a signicant technical difculty needs to be considered. It is well known that problems are encountered when using relations as a denotation (see [Jon73] for example), particularly due to relational composition. This is most easily illustrated by the case of distinguishing between a b and ab a , when nontermination is a possible result. (The symbol for bottom is used in its traditional sense to represent nontermination, i.e. undened result.) To solve this problem, the approach of [Par80] is followed, where the denotation of a program is given as a pair of functions: 1. The meaning function as before. 2. A second function giving the set of inputs over which termination is guaranteed.
11 The termination function appropriate to the previous denition is:
ts
11 The following conventions simplify considerations of input/output: tokens which are addressed to a destination not within the node store (i.e. NA D t dom ns) are assumed to be output; it is assumed that any program which has a state composed entirely of output tokens has terminated.
288
The function termset generates sets of Tokens which are all terminated: termset : Node store ts termset ns Token-set -set t ts D t dom ns
The termination function TP is also dened in terms of a xed point. This is built over the possible token sets. An informal explanation of the derivation of this function can be given as follows. The starting point is given by the function termset (i.e. those states containing only tokens that can not be modied further since they have destinations that do not apply to any nodes in the node store). The xed point is then built by adding all states which must yield one of these states whichever node res, and so on. This denition is as far as it is reasonable to progress using an abstract machine. Further steps are necessary to consider the precise details found in the MDFM.
that the actual instruction set is microcodable, this is reasonable even from a practical viewpoint.
289
number of expected inputs as this is deducible from inspection of the matching function of the incoming token (unary if BY; binary otherwise (remembering Section 11.1)). A list of differences from the previous denition is given below along with an indication of the reason for the modication. 1. Type checking and error detail are added these use the extra information carried by tokens to perform some error checking. 2. Tokens carry type information this is necessary to reect the strong typing present in the machine. 3. Labels are expanded this is to allow labels to be used both to separate tokens in multiple instantiations of a piece of graph and to separate elements of a data structure. 13 4. Matching functions are included in destinations to enable matching actions to be considered. 5. Operators are made explicit this is done to allow a more precise characterization of the actual machine. Not all implemented operators are included. 6. Alternative result destinations are included this addition is necessary to deal with branching and switching nodes. In fact, the hardware only gives a restricted version of this facility but it can be achieved using DUP nodes. 7. Literals are added to nodes that is, constant values could be attached to one input of a binary node removing the need to pass in xed constants. 8. The identity relation used in previous denitions to represent no ring is replaced by an operator allowing for deferred failures this is forced by the fact that defer and wait have a slightly different action. The matching functions of waiting tokens are not considered again (they are within the store). On the other hand, a deferred token is represented as if the defer had not occurred. 9. The test of a nodes readiness to re is more complex. It is no longer enough to simply test if the cardinality of the ready set is equal to the number of expected inputs since action is also required in the case of some failures involving special matching functions. 10. The meaning function for nodes MN is rewritten this is again made necessary by the possibility of failure actions.
two elds are given since the third eld is used in practice to separate a special case of multiple instantiation.
13 Only
290
11. An additional meaning function is included M OP this is used in conjunction with the enumerated set to dene the available primitive operations. 12. Test and special action functions are added to deal with matching functions. 13. One further complexity is introduced by the use of the GCL node. This node returns a unique identier (color) each time it res. In the machine, this is possible by the use of a global variable containing a set of unused colors. Given the applicative style of the denition, this is difcult to reect here without the extra complexity of passing an extra parameter through all levels of the denition. In order to avoid this, the notation is abused and an external variable is used, following the operation denition style of VDM. As can be seen most of the above present no particular difculties. The exception is the treatment of matching functions, which is explained in detail below. It is not feasible to present the full denition here, it can be found in [Jon86b]. The following is a skeleton of the complete denition which serves to illustrate the structure.
Type = Machine types e.g. INT,COLOR Label :: C : Color I : Index Destination :: NA : Node address MF : Matching function IP : Input point Matching function = EW,. . . ,EA . . .
291
The meaning of a program is largely as before. The extension is to allow a more general test for an action occurring, to allow for special matching functions:
Token-set
Token-set -set
reaction na op nd l
failaction na op nd
The meaning of an Operator is given by MOP . This function also generates any extra tokens caused by special success matching:
Token-set
the result of performing the operation plus extra match tokens The rest of the denition consists of subsidiary functions handing the details of this scheme. As was mentioned above, most of the extra complexity in this denition is caused by the mechanisms added to handle matching functions. To facilitate the understanding of this, an informal explanation of the way in which matching is modelled is given below. In the previous denitions, matching was implicitly extract wait, i.e. pure dataow. This resulted in the simple mechanism of removing tokens from the state when nding matches, and performing an identity transformation in the case of waiting. In the complete denition, the matching functions are divided into three general cases: 1. Successful matching actions. 2. Normal failing actions, i.e. wait and defer.
The rst case, that of successful matching, is dealt with by an extra section to the M OP function. (In some sense, successful matching and ring could legitimately be regarded as closely linked since all tokens succeeding in matching immediately proceed to re.) Extra tokens are generated and added to the state to represent the effect of special matchings. In the case of extract, no extra tokens are generated. (Firing tokens are consumed in the reaction function.) Preserve causes a copy of the waiting token (identied by the NIL matching function) to be added to the state. Increment and decrement cause a token with the appropriately adjusted value to be generated. Normal failing, i.e. failures that do not change the state, is handled by the nfail operator. The reason for the quotes in the previous sentence is the fact that wait does require a slight modication to the state. It is necessary to identify the token as having undergone a failed matching, i.e. being resident in the store, for subsequent successful matchings. To enable this, the matching function of the waiting token is replaced with NIL. This is necessary to avoid the selection of the wrong tokens succeed function on subsequent matches. The defer action leaves the state completely unchanged. This would be expected since it is primarily an engineering solution to a problem and could be imagined to have the meaning forget that ever happened and try again later. The nal case, that the fail matching functions requiring special action, is a little more complex. This condition is detected by the test function failaction. This uses the function specialfail to examine the state for incomplete input sets containing a token which has a matching function that is a member of the Failmf set. The function failres uses the subsidiary function ft to generate the appropriate new token, i.e. an EMPTY token for abort and an inverted token for generate. This completes the record of the derivation of the formal semantics for the MDFM. The full denition contains some simplications of the actual machine but these were simply to reduce the length of the denitions to a manageable size. All of the important characteristics have been described and the complete detail could be included at the cost of increased bulk. It should be noted that the denition is, in some sense, parameterized on certain features to the level of the MOP function. To give a semantics for a different version of the same machine, e.g. with different matching functions, the same general denition could be used. To make this denition fully parameterized on these sets, it would be necessary to add another level of function below M to deal with matching OP separately.
11.4 Conclusions
This work shows a complete model for an existing piece of hardware. This is, of course, not the ideal way to proceed: it would have been better to have designed the implemen-
11.4 Conclusions
293
tation from the specication. However, working from a real example brings out some interesting points. As can be seen from [Jon86b], a model which deals with the intricacies of the real world is far from ideal from the point of view of reasoning about the system. It would have been convenient to have a more abstract model (of which the model in Section 11.3 was a veried renement) to reason about. As can be seen from the above, there is not a great deal of difference between the model of a parallel machine given here and the more common sequential machines seen previously. The major differences come at the level of the structure required to model the parallelism: relations in place of functions. The other modication made to the specication language in this work is to allow explicit use of the xed point operator x since this made to construction of the proofs (in [Jon86b]) easier. It should still be recognizable as VDM.
Acknowledgements
Thanks are due to: Cliff Jones, who supervised this work; the Dataow Group at Manchester for providing necessary information, and the SERC, for providing nancial support.
294
The specication and design of user interfaces is an extremely challenging subject area. Not only does it involve the difcult aesthetic and human factor issues associated with layout, use of color, information display, structure hierarchy, ease of use, learning efciency, etc. but it also requires the precise specication of the dialog structure between the user and the system. Dialog specication is important because it provides an abstract representation of the legal set of interactions between the user and the system allowing properties such as dialog consistency, safety, liveness and security to be analyzed. This chapter addresses the development of a formal system for the specication of user interfaces. Its rst part discusses the use of VDM and statecharts for this purpose. Interaction between a user and a system may be viewed as a ow of control between operations. Operations are specied in VDM and the ow of control is specied using statecharts. To prove properties about the dialog, the meaning of statecharts must be established and proof rules derived. These issues are tackled in the second half of the paper and a number of proofs demonstrated. The VDM used in this chapter does not conform strictly to the standard. The semantics of pre-conditions have been changed, statechart labels have been introduced and are used within the VDM operation specications. In addition a number of abbreviations have been introduced; for instance only abbreviated ext clauses are used. This study should be viewed as showing how a formal system may be extended rather than as an example of the use of standard VDM.
295
296
12.1 Introduction
Computer science is a relatively young eld. Just a few decades ago there were only a few computers in existence. They were very expensive, owned by large companies, and used only by specially trained personnel. Today, smaller computers are generally available and the use of computers of all sizes is widespread. As the number of applications for computers grows, the need for hardware and software to function correctly becomes critical. Formal methods have emerged to assist in this area. The term formal methods encompasses both formal description and veried design. Formal description involves the use of a mathematical notation to dene the function of a system, while veried designs use formal reication techniques for developing systems in a way which can be proved correct with respect to the formal description. Since computer systems are used by workers in all disciplines, the area of user interface design has become very important. Not only must computer users get the correct results, it should also be easy for them to obtain these results. The area of user interface design is in its infancy and few concrete guidelines exist. Perhaps the application of formal description methods to user interface design will provide new insights into both elds.
? U SER I NTERFACE
01101 A PPLICATION
The user interface controls who has the initiative at any stage in the dialog. It translates the users request into a form the application will accept and the applications reply into a form that the user can understand. The role of the interface is to allow the user to utilize software with a minimum of effort. The user interface is given many different names in the literature. These include user computer interface, human/computer interface (HCI), computer/human interface (CHI), human/computer dialog, human/machine interface, man/machine interface (MMI), and interactive dialog. The term user interface was chosen for brevity. It is understood that the user is interfacing with a computer. Also, this name does not unnecessarily restrict the users of the system to humans and/or males.
12.1 Introduction
297
By any name, a good interface is an essential part of any system. Even an excellent system will be useless without an adequate interface. The user interface should be easy to learn and easy to use. It should be simple and reliable, yet exible and transparent to the user. The interface should also be consistent and efcient, and as independent of the application as is feasible. Clear documentation and diagnostics are vital. However, these qualities are hard to dene and measure. Also, many design choices are unclear. The users reaction to various user interfaces is difcult to appraise. User interface design may need to take into account the different users of the system, the applications that the users need to access, and the input and output devices available. The fact that the user interface is dependent on so many system-specic details adds to the difculty in proposing design guidelines. Due to these problems, user interface design is not an exact science. There remains much disagreement and many unknown quantities. Currently, user interface design remains an iterative procedure utilizing social scientists and psychologists in an attempt to develop systems acceptable to the user community. See Section 12.2 for a further discussion of user interface design.
298
mal. Informal descriptions may be easier to write and understand, and can be useful in some instances, but, for a description notation to be used for analyzing properties of the proposed system, a formal mathematical basis is necessary. Many researchers feel that an executable description method is best as it allows rapid prototyping of the description and iterative system design. However, an executable description language leads to program-like thinking and discourages abstractness, the major aim of a formal description. Formal methods are currently employed mainly for describing and proving properties of noninteractive, or static, systems. Error handling is not as vital in a static system as in an interactive system. Due to this, the formal description usually deals only with valid input, leaving the interception of invalid input and production of error messages to the implementor. Even if an interactive system is considered, the formal description usually considers only the application, ignoring the user interface along with key issues like error handling, on-line help information, and interrupts.
299
should not be necessary to have much special training to follow the description. Also, the formal description must be abstract. While the ow of control is important for illustrating the overall effects of the user interface, the description should not impose order when it is unnecessary. Finally, a sound basis in mathematics is needed for the notation to be rigorous enough for claims concerning properties of the user interface to be formally veried. Introducing a formal notation will not suddenly cause all user interfaces which have been described using this technique to be ideal. However, a formal description technique which can easily express the user interface of an interactive system should reduce the need for iterative user interface design. If the use of formal methods can help in the construction of user interfaces or in the determination of what makes a good user interface, research in this area is worthwhile.
Synopsis
Section 12.2 describes the current research in user interface design and examines ways in which formal methods can be of use. Section 12.3 describes the adopted approach, while an example using the proposed approach is presented in Section 12.4. The semantics of the method and sample proofs are given in Sections 12.5 and 12.6. Section 12.7 gives the conclusions and suggestions for further work. Further details, additional examples and many more references are contained in [Mar86].
300
clear, and versatile. The term user-friendly is often mentioned though numerous researchers agree that its meaning is unclear. How friendly an interface is depends on the task and the user. The ease of use of a system depends on various factors. Also, there is a trade-off between ease of learning and ease of use. Recommendations for user interface design often conict thus making the user interface designers task a difcult one.
12.3 Approach
301
as possible of the input and output devices, language, machine, and interaction technique. [OD83] opts for application independence and device dependence. Some authors also recommend device dependence [Bae80, NS81], while another [HT85] suggests that the user interface should be user dependent. It is possible that these discrepancies can be explained by considering the amount of detail in each authors view of the user interface. However, a technique for describing the user interface alone could well prove inadequate to aid in user interface design.
12.3 Approach
The required properties of the formal description technique are the following: ow of control. The user interface governs the ow of control within an interactive system. The formal description should clearly illustrate this general, or top level, view of the interactive system. levels. To allow the system designer or user to look at the formal description in as much or as little detail as desired, the description should be split into levels ranging from the top level ow of control discussed above, to the details of each operation within the system. modular. All but the top level of the formal description should be modular. This will enable the design of each operation to be considered in isolation. concise. The notation should allow the necessary concepts to be expressed in a concise manner. A notation which is clumsy or verbose will unnecessarily lengthen the description. understandable. The formal description technique should be easy to understand. As well as satisfying the points above, the notation should be as clear and simple as possible. abstract. While a user interface may be partially dependent on the particular interactive system, the description should still remain abstract. The formal description should
302
sound. To allow formal proofs of correctness to be carried out, the description technique should have a sound mathematical basis. VDM [Jon90] uses pre- and post-conditions for the abstract description of operations. This method satises all of the requirements except that it is inadequate for illustrating the ow of control. The best formal description method for showing the top level ow of control are transition-state diagrams (TSDs). In fact, statecharts [Har84], a form of extended TSD, seem to be the best choice. The chosen approach is a combination of statecharts and VDM operations. A statechart describes the toplevel ow of control between the operations of the system, while each operation is described by a pre- and a post-condition. The details of the approach are described below. Note that a restricted form of statechart is used to enable the semantics of the method to be fully described.
Statecharts
A statechart shows the ow of control of a system. A statechart can be any one of the following. Operation. A simple operation is illustrated: OP Composition. A sequential composition of two statecharts, S S1 ; S2 , is illustrated:
S1
S2 S
12.3 Approach
Selection. The selection of at most one statechart from a list. cn then Sn : IF if c1 then S1 c2 then S2 C c2 ... S2
303
c1 S1
cn Sn IF
S1
C S2
LP Wait. Wait for a condition to become true. The wait construct assumes that there is something outside the system which can effect the state. This construction is normally used to wait for the user to enter input before attempting to read it in. The need for this construct is explained later in this section. wait c tiaw is illustrated: W c A statechart must not attempt to force an operation to occur when its pre-condition is not satised. Any labels on the statechart (e.g. c above) must be dened in terms of the data types in the state. It is often convenient to use these labels in the pre-condition of the corresponding operations.
Logon example
Basic logon This example involves a user attempting to logon to a computer system. The user can type ahead but the input queue is restricted and if he exceeds the queue length his input is discarded. If the entered user name is invalid a message is printed. The logon terminates when the user enters a valid name.
UP R
input UPW
UR D
UGET
valid input
M SG L OGON L OGON = loop UG ET if valid input exit M SG pool UG ET = UPW ; UR EAD UPW = UP RMT ; wait input tiaw User statechart
I NPT
C tr U SER
U SER = loop I NPT pool State State :: uprompt invmsg users qlen input curuser screen : : : : : : : String String Word-set
1
prompt for user name (cn) invalid message (cn) valid users (cn) maximum input queue length (cn) input queue current user name output to screen
12.3 Approach
305
len input
qlen
Statechart label denitions valid input curuser input input tr true Operations Set the initial values of the state. Note that the constant (cn) portion of the state is dependent on the system and the values given below illustrate one possible choice: I NIT ext cn uprompt invmsg users qlen wr input curuser screen Login: invmsg Invalid, login post uprompt users Tom, Dick, Harriet qlen 50 input curuser screen The prompt is displayed on the screen: UP RMT ext cn uprompt wr screen post screen addstr screen uprompt users
306
The user can enter a word at any time. The word is displayed and, provided the input queue is not full, added to the input queue: I NPT ext cn qlen wr input screen post w Word input if len input then input else input screen addstr screen w qlen w
If there is input it is moved to the current user eld: UR EAD ext wr input curuser pre input post curuser hd input input tlinput If the user name entered is invalid a message is printed: M SG ext cn invmsg users rd curuser wr screen pre valid input post screen addstr screen invmsg
Function Add a string to some text: addstr : Text addstr t s String Text t s
Quoting operation example If the screen in the preceding example may be optionally cleared whenever a new string is added, then the addstr function would no longer be adequate. Instead, a D ISP operation could be dened as follows.
12.3 Approach
Display information on the screen. The screen may be cleared rst: D ISP S: String ext wr screen post screen screen s s
307
The operations using addstr would be redened to quote D ISP. For example, the prompt is displayed on the screen: UP RMT ext cn uprompt wr screen post post-D ISP uprompt screen screen
PR
RD
P&R
However, for S TORE and D ISP a single operation is appropriate. Store and display the input: S TORE & D ISP ext rd input message wr save disp pre input nil post save input disp disp message Applying this type of reasoning allows each notation to be employed when it is most suitable.
308
Discussion of wait
The L OGON example shows the user and user interface as separate processes (each has its own statechart) while the application is tied in with the user interface. This representation is chosen since it is realistic. The user interface can control the application program but it is not always possible or desirable for the user interface to control the user. Neither is it plausible for the user to have complete control over the user interface. The wait construct described is a tie between the user and interface: W input It is employed when it is necessary for the user interface to wait for input. This construct was chosen as it indicates that there may be a time delay, and because it keeps the user and interface as independent as possible. Other representations exist. For example, since I NPT is the only operation which can make input true, another statechart is:
C
input
I NPT
WI
However, this statechart obscures any time delay that may occur, and there is no clear indication that the I NPT operation may also occur at any other time.
12.4 Example
The L OGON example of Section 12.3 can quite easily be extended.
Add password
The user must enter a password after entering his user name. The password is not displayed on the screen, and any input entered before the password prompt appears is discarded. The interface statechart is updated. The users statechart does not change. users becomes a map. pprompt, echo and curpswd are added to the state, and the denition of valid input changes. The operations I NIT and M SG are updated, and PP RMT and PR EAD are added.
12.4 Example
Statechart
309
UP R
input UPW
UR D C
UGET
valid input
M SG PP R
input PPW
PR D
PGET GET
L OGON
State State :: uprompt pprompt invmsg users qlen input echo curuser curpswd screen Invariant len input qlen : : : : : : : : : : String String String Word
1
Word
Statechart label valid input curuser dom users curpswd users curuser
310 Operations
Set the initial values of the state. Note that the constant (cn) portion of the state is dependent on the system and the values given below illustrate one possible choice: I NIT ext cn uprompt pprompt invmsg users qlen wr input echo curuser curpswd screen post uprompt Login: pprompt Password: invmsg Invalid, login., Try, again. users Tom se3cx Dick fred Harriet qlen 50 input echo curuser curpswd screen
hello
The password prompt is displayed on the screen, input is ushed, and echoing is turned off: PP RMT ext cn pprompt wr input echo screen post echo input screen addstr screen pprompt
If there is input it is moved to the current password eld and echoing is turned on: PR EAD ext wr input echo curpswd pre input post echo curpswd hdinput input tl input If the user name and/or password entered are invalid a message is printed: M SG ext cn invmsg users rd curuser curpswd wr screen pre valid input post screen addstr screen invmsg
Add limit
The user has only a certain number of tries to login. Once this limit is exceeded the keyboard is locked for a certain length of time. The interface statechart is updated. A clock which ticks continuously is introduced. This is another process illustrated by the
12.4 Example
311
C LOCK statechart. The users statechart does not change. trylimit, locktime, trynum, and time are added to the state. The denitions of limit and unlock are given. The operations I NIT and M SG change, while L OCK and T ICK are added. Interface statechart
UP R
input UPW
UR D C
UGET
M SG PP R
input PPW
PR D
PGET GET
T RY
C
limit
L CK
W
unlock LKW
L OGON
Clock statechart
T ICK
C tr
CLOCK
312
State State :: uprompt pprompt invmsg users echo trylimit locktime qlen input curuser curpswd screen trynum time Statechart labels limit trynum trylimit unlock time locktime Operations Set the initial values of the state. Again, the constant (cn) portion of the state is dependent on the system and the values given below are just an example: I NIT ext cn uprompt pprompt invmsg users trylimit locktime qlen wr input echo curuser curpswd screen trynum time Login: pprompt Password: post uprompt invmsg Invalid,login.,Try,again. users Tom se3cx Dick fred Harriet hello trylimit 5 locktime 1800 qlen 50 input echo curuser curpswd screen trynum 1 time : : : : : : : : : : : : : : String String String Word
1 1 1
Word maximum number of tries (cn) length of time of keyboard lock (cn)
12.4 Example
If the user name and/or password entered are invalid a message is printed: M SG ext cn invmsg users rd curuser curpswd wr screen trynum pre valid input limit trynum trynum 1 post screen addstr screen invmsg
313
Reset the time to indicate the beginning of keyboard lock, and reset the try number: L OCK ext cn trylimit wr trynum time pre limit post trynum 1 time Clock ticks continuously: T ICK ext wr time post time time 1
Add timeout
If the user pauses too long between typing his user name and password he must re-enter his user name. The interface statechart changes accordingly. It is illustrated in two parts to make it easier to read. The user and clock statecharts do not change. timelimit is added to the state. The denition of timeout is given. The operations I NIT and PP RMT change. Statecharts
(below)
G ET
C (valid
input limit)
C limit
M SG
TRY
L CK
W
unlock LKW
L OGON
314
UP R
input UPW
UR D
UGET
input
PP R
UPGET
PR D
GET
State State :: uprompt pprompt invmsg users echo trylimit timelimit locktime qlen input curuser curpswd screen trynum time Statechart label timeout time timelimit : : : : : : : : : : : : : : : String String String Word
1 1 1 1
Word
12.5 Semantics
Operations
315
Set the initial values of the state. Again, the constant (cn) portion of the state is dependent on the system and the values given below are just an example: I NIT ext cn uprompt pprompt invmsg users trylimit timelimit locktime qlen wr input echo curuser curpswd screen trynum time post uprompt Login: pprompt Password: invmsg Invalid,login.,Try,again. users Tom se3cx Dick fred Harriet hello trylimit 5 timelimit 30 locktime 1800 qlen 50 input echo curuser curpswd screen trynum 1 time 0 The password prompt is displayed on the screen, the time reset, input ushed, and echoing turned off: PP RMT ext cn pprompt wr input echo screen time post echo input screen addstr screen pprompt time 0
12.5 Semantics
Denitions
Let S be a set and R be a relation. Then: S R s s R s S R S s s R s S R2 R; R i R I R i 0R S R R S R s s R s S s s R s S Ri i 0 ss s %
316
Semantic model
The underlying semantic model of the formal description notation assumes a global state, %. The semantics of a description are given by a function dening the termination set:
: Desc
P %
giving all states in which the given description can be sensibly applied, and by a function describing the meaning relation:
: Desc
P % %
giving pairs of initial and nal states related to each other by the description. For a description to be implementable it is necessary that: (1) TS dom M S Note that T I % and M I I. The termination and meaning functions can also be applied to expressions:
: Expr
P %
%
: Expr
gives the value of the expression in the states for which it is dened. Again it is necessary that:
T e
C C C
For the operations described by pre- and post-conditions, any state allowed by the precondition should be described in the post-condition: op description # % pre-op # # % post-op # #
12.5 Semantics
317
To allow for systematic program development from the description a method of reifying the description is needed. A reication, S , of a description, S , is said to satisfy the description provided: (2) S sat S i.e. T S T S (S terminates whenever S does) M S M S and T S (over the termination set of S the meaning of S is contained in the meaning of S) So if we claim to have found the meaning relation and termination set for a statechart construct we need to show that: dom M cons (I) T cons (II) cons sat cons provided these two clauses are true for each statechart within the construct. The following sections present the termination sets and meaning relations for the statechart constructs. Concatenation
S1 Written: S1 ; S2 Claim:
S2 S
M S1 ; S2 T S1 ; S2
M S1 ; M S2 T S1 dom M S1
T S2
318 Have:
Here the substatecharts are S1 and S2 , so we assume that (1) and (2) are true for these two statecharts: A. T S1 B. T S2 dom M S1 and dom M S2 by (1)
S1 sat S1 by (2) i.e.: C. T S1 T S1 and M S1 M S1 D. T S1 S2 sat S2 by (2) i.e.: T S2 and E. T S2 M S2 M S2 F. T S2 Prove: Now we can prove (I) and (II) by proving 1., 2., and 3.: (I) T S1 ; S2 dom M S1 ; S2 or: dom M S1 T S2 dom M S1 ; M S2 1 T S1 (II) S1 ; S2 sat S1 ; S2 i.e.: T S1 ; S2 T S1 ; S2 and T S1 ; S2 M S1 ; S2 M S1 ; S2 or: dom M S1 T S2 T S1 dom M S1 T S2 and 2 T S1 dom M S1 T S2 M S1 ; M S2 M S1 ; M S2 3 T S1 Note 1: Proving this here will simplify proof 1.
T S1
dom M S1
T S2
dom T S1
M S1
T S2
Intuitively, the set of initial states for which S ; S2 always terminates is con1 tained in the set of initial states for which S1 ; S2 could terminate: Note 1 proof:
T S1 dom M S1 T S2 a T S1 dom T S1 M S1 T S2 by defn. b dom T S1 M S1 dom T S1 M S1 T S2 by A c dom T S1 M S1 T S1 M S1 T S2 by defn. dom d dom T S1 M S1 T S2 by defn.
12.5 Semantics
Proof 1:
319
T S1 T S1
a b c d Proof 2:
dom M S1
T S2
dom M S1 ; M S2
T S1 T S1 a T b T c T
Proof 3:
T S2 :
T S2 S1 T S2 by defn. S1 T S2 by defn. S1 T S2 by C T S2
and D and E
T S1
M S1 ; M S2
M S1 ; M S2 :
T S1 dom M S1 T S2 M S1 ; M S2 a T S1 dom M S1 T S2 T S1 M S1 ; M S2
b c d e f
T S1 T S1 T S1
T S2 T S2 T S2
M S1 ; M S2 by D M S1 T S2 ; M S2 M S1 ; T S2 M S1 ; M S2
by defn.
T S1 dom M S1 T S2 M S1 ; M S2 by defn.
by defn. M S2 by defn. by F
320 If C c2 ... S2
c1 S1 Written: IF IF Claim:
cn Sn IF
M IF T IF
Have:
T ci
dom M Si A T Si Si sat Si i.e.: T Si and B T Si M Si M Si C T Si Prove: (I) T IF Ci T 1 (II) IF sat T IF Ci T 2 3 Ci T Ci dom M IF or: Si T ci dom Ci M Si Ci I IF i.e.: T IF and T IF M IF M IF or: Si T ci Ci T Si T ci and Si T ci Ci M Si Ci I
M Si
Ci
12.5 Semantics
Note 2: Ci
321
T Si
T ci
Ci T Si
Ci
Intuitively, the set of states in which all the conditions can be evaluated and the branches corresponding to all true conditions terminate is contained in the set of states in which some true branch will terminate or no condition is true. Note 2 proof: Ci a b c d e f Proof 1: Ci Ci a b c d e Proof 2: Ci Ci
T Si
Ci % % % Ci Ci
T ci
T Si T Si
T ci T ci
dom
Ci
M Si
Ci
Ci T Si Ci by Note 2. Ci dom M Si Ci by A dom Ci M Si Ci by defn. dom dom Ci M Si dom Ci I by defn. dom dom Ci M Si Ci I by defn. dom
T Si T Si
Ci
T ci T Si T ci
Ci
T Si
T ci :
and B
T ci by defn.
322 Proof 3: Ci
T Si
Ci
T ci
Ci Ci
M Si
T ci
I :
Ci
M Si M Si
Ci
Ci
Ci a b c d While
T Si
Ci T Si Ci T Si Ci Ci
Ci Ci Ci
I I I
by defn. by Note 2. Ci
Ci Ci Ci Ci
M Si
M Si
Ci
M Si M Si
by C
I by defn.
M WH
T WH
x "r x "s
C C
M S ;r
dom M S s % C
C T S
Note that T WH is not --continuous. Also, C is total (i.e. C C). Have: A T S dom M S S sat S i.e.: T S and B T S M S M S C T S
12.5 Semantics
Prove: dom M WH (I) & 1 T WH (II) WH sat WH i.e.: T WH T WH or 2 x "s C C T S C dom M S s s and
323
x "s 3 T WH Proof 1:
C T S
dom M S
M WH
M WH
T WH
dom M WH : C dom C C
1
M S M S ;r
s C dom C
C
1
F Fn
C
M S
Fn
I G Gn
M S ;Gn
Claim: n 0 F n dom n 0 G n To prove this we will use induction: dom G n n 0 Show: F n By induction on n: dom G 0 Case n 0: F 0 Case n 1: F C dom C I dom G Assume true for n and prove for n 1: Fn dom G n and Prove: F n 1 dom G n 1 Fn 1 C dom C M S Fn n a C dom C M S dom G by induction hypothesis. C dom C M S ; G n by defn. dom b c dom C I C M S ;Gn by defn. dom d dom G n 1 So: F n dom G n n dom thus: n 0 F n
n
n 0G
C T S
dom M S
s s by Note 1. A
C dom
C T S s
M S
by defn.
dom M S
s s :
C T S
dom M S
x "s a b Proof 3:
C C C
C T S C T S C T S
dom M S
s s s by C by B
x "s x "s
dom M S dom M S
T WH
M WH
M WH :
C C T S dom M S s
Now: T WH
x "s
T WH And: T WH Thus: T WH
C I M WH M WH
M S ; r by C. T WH M WH by defn. x M M WH by A
C
12.5 Semantics
Loop
325
S1
C S2
LP Written: LP LP Dene: Here is the denition of LP in terms of concatenation and while: LP LP Have: The meaning relation and the termination set for loop are determined from those for concatenation and while. S1 ; while c do S2 ; S1 S1 ; while c do S2 ; S1 loop S1 if c exit S2 pool loop S1 if c exit S2 pool
M LP
M S1 ; x "r C I
M S2 ; M S1 ; r
M S1 ; x "r C I
M S2 ; M S1 ; r
by defn. M S1 ; S2
326
T LP
T S1
C T S2
dom M S1 dom M S2
x "s C
T S1
M S2 ; M S1
by defn. T S1 ; S2
by defn. T WH
T S1
C
dom M S1
T S2
dom M S2
T S1
dom M S2 ; M S1
by defn. T S1 ; S2 M S1 ; S2 e
T S1
dom M S1
x "s C
C T S2 by defn. f
dom M S2
T S1
dom M S2 ; M S1
T S1
dom M S1
x R"s C
C T S2 by defn. g
dom M S2
T S1
dom M S2 ; M S1
T S1
dom M S1
x "s C
C T S2 by defn. Now:
dom M S2 dom
T S1
M S2 ; M S1
Since we have already completed the necessary proofs: dom M LP and 1 T LP 2 LP sat LP follow from the proofs for concatenation and while.
12.5 Semantics
Wait W c Written: WT wait c tiaw
327
We assume that C is total and that there is a unique user action, U, which will make C become true. We also assume that the user eventually performs U. Dene: Based on the assumption we can dene WT in terms of if: WT WT Have: if c then U if c then U
M WT
M U
I :
328
Proof rules
P S R means: if # P and S is performed on # then S will terminate, and if the resulting state is # then # # R. Alternatively this can be read as: If the predicate P is true then S will terminate and when S terminates the predicate R will be true. i.e. S satises P R . This can also be written: S sat P R Note that, although the same notation is used to represent both the predicate and the set of values which satisfy the predicate, no confusion should arise. P S R can be taken to mean: P
T S
M S
R P there is then an
M S
P or: P
M S
M S
The following sections give the proof rules for the statechart constructs. Concatenation rule Claim: Here we claim that if the rst two clauses are true then the third is also true: P1 S1 R1 P2 ; P2 S2 R2 Have: Here the rst two clauses are expanded using the denitions above: P1 S1 R1 P2 a P1 T S1 b P1 M S1 c P1 M S1 P1 M S1 P2 P2 S2 R2 d P2 T S2 e P2 M S2 R2 R1 P1 S1 ; S2 R1 ; R2
12.5 Semantics
Show: The third clause is expanded showing the two parts we must prove: P1 S1 ; S2 R1 ; R2 P1 T S1 ; S2 P1 M S1 ; S2 1 P1 T S1 dom M S1 T S2 2 P1 M S1 ; M S2 R1 ; R2 Proofs: 1 P1 R1 ; R2
329
T S1
dom M S1
T S2 :
Now: M S1 T S2 a M S1 P2 by (d). P1 M S1 P2 by defn. b c P1 M S1 P2 P2 by (c). by defn. d So: T S1 T S1 dom M S1 T S2 Thus: P1 T S1 dom M S1 T S2 by (a). 2 P1 a b c If rule Claim: P Ci Si R ; P Have: P Ci Si R a P Ci P i Ci I R c P d P T ci Show: P if ci then Si R P T IF P M IF 1 P Ci T Si T ci 2 P Ci M Si Ci I R R i Ci I R ; P P1
M S1 ; M S2
R1 ; R2 :
T ci
P if ci then Si R
T Si
Ci
b P Ci M I R
M Si
330 Proofs: 1 P Ci
T Si
T ci :
M Si
Ci
R:
M Si Ci I Ci M Si P P Ci M Si P P Ci M Si P
I by (b).
R P Ci R R by (c). R by defn.
While rule Claim: P C S R P ; R transitive and well-founded P while c do S R P C Have: P C S R P a P C T S b P C M S R c P C M S P C M S P d R; R R R transitive R well-founded no innite chains. This allows a special type of induction (see (1). below). Show: P while c do S R P C 2 P M WH R 3 1 P P T WH M WH P M WH P C
12.5 Semantics
Proofs: 1 P
331
T WH
By induction on R (well-founded and transitive). Prove: A P dom R T WH B R R T WH P dom R C C T S dom M S A P dom R T WH : Note: P dom R C Proof: P dom R C P C dom R by defn. a b dom P C M S dom R by a c dom R dom R by b d by defn. So: P dom R C since C total. T WH by defn. T WH as desired. B Assume: R R
T WH
T WH T WH
Prove: P dom R C C T S dom M S Case B(i) Assume: C % C : P dom R P dom R C by assumption. a ` C defn. b c C C T S dom M S
T WH
by defn.
as desired.
332
M S ;r
R :
12.5 Semantics
C I C M S ;r R : B P C I C M S ;r P a P C I P C M S ; r by defn. b P C I P C M S ; r by defn. c P C I P C M S ; r by defn. d I P C M S ; r by defn. e I R P; r by (b). I R; P r by defn. ; f g I R; R by assumption. I R by defn. R h i R by defn. R as desired. 3 P
333
M WH
M WH
C :
334 B P P a b c d e f g C I C P C I C I C P C I P C I P C I P C I P C I P C I P C I
M S ;r C M S M S ;r P C M P C M P C M
;r
C :
P1 S1 R1 P2 ; P2 C S2 R2 P1 ; R2 ; R1 transitive and well founded P1 loop S1 if c exit S2 pool R1 ; R2 ; R1 Proof: P1 S1 R1 P2 ; P2 C S2 R2 P1 a P1 S1 R1 P2 ; P2 C S2; S1 R2 ; R1 P2 b c d Wait rule Claim: P C I R C ; P C U R C ;T c % P1 S1 R1 P2 ; P2 while c do S2 ; S1 P1 S1 ; while c do S2 ; S1 R1 ; R2 ; R1 P1 loop S1 if c exit S2 pool R1 ; R2 ; R1
P2 C
P wait c tiaw R C
12.6 Proofs
Proof: P C I R C ; P C U R C ;T c % P C I R C ; P C U R C ; P T c by defn. % a b P if c then U R C by if rule. P wait c tiaw R C by defn. wait. c
335
12.6 Proofs
A major advantage of the use of a formal technique for describing the user interface, as opposed to an informal design method, is that properties of the interface can be formally stated and proved. It is difcult to design and assess experiments to evaluate an interface, though some researchers suggest or attempt this [BK82, Pen82, Rei83, SR82]. Other researchers have attempted proofs using a formal description method [And85, Fol81, Jac84, Rei82], but little work has been done in this area, mainly due to the problems in formally representing general user interface properties. This chapter presents a few examples of proofs that can be carried out using the suggested formal description method.
A designer may want to ensure that the input queue will never overow the space allocated to it. Here is a proof that the input queue in the L OGON example of Section 12.3 never exceeds qlen. Show len inq qlen qlen Now: qlen 1 so 1 so len inq 0 1 qlen Initially inq Only the user can add things to the input queue; this is done using the operation I NPT. Now the pre-condition of I NPT requires that len inq qlen. The post-condition of I NPT contains: w Word inq inq w so len inq a b c d len inq len w len inq 1 qlen 1 qlen as required.
Termination
Logon termination In the verication of application programs many proofs are concerned with the successful termination of looping constructs. In a secure user interface, part of the interface may be concerned with preventing unauthorized users from completing the logon procedure. The L OGON example presented in Section 12.3 is an example of a case where a user may never successfully complete the logon task, and thus the logon loop will never terminate. However, it is interesting to note that under certain restrictions it is possible to prove that the user will eventually enter a valid user name. The conditions require that there is some measure of the user, such as his knowledge, which will increase each time an error message is presented. Provided that there is a limit to how knowledgeable the user can become, he must eventually enter a correct user name (otherwise he would become innitely knowledgeable). While this may not be a very realistic example, it illustrates a type of proof that may be carried out. Loop proof Section 12.4 contains an extension to the original L OGON example in which the user has only a given number of tries before the keyboard is locked for a period of time. In
12.6 Proofs
337
this case it is possible to prove that if a user attempts to logon either he will successfully logon or the keyboard will eventually be locked, i.e., the T RY statechart always terminates. From the VDM presented it is easy to see that: true UP RMT true and input UR EAD true From the denition of wait, and the existence of the I NPT operation: true wait input tiaw input Now: UPW UP RMT ; wait input tiaw So: true UPW input by the concatenation rule. Also: UG ET UPW ; UR EAD So: true UG ET true by the concatenation rule. Similarly: true PG ET true Now: G ET UG ET ; PG ET And: true G ET true by the concatenation rule. From the VDM: valid input limit M SG trynum and trynum trynum trynum trylimit trylimit is transitive and well-founded.
Applying the while rule to G ET and M SG gives: true loop G ET if valid input limit exit M SG pool trynum trynum trylimit
valid input
limit
Now: T RY loop G ET if valid input limit exit M SG pool And: limit trynum trylimit So: true T RY trynum trynum trylimit valid input trynum trylimit Or: true T RY trynum trylimit valid input trynum trylimit Thus T RY always terminates. From the proof it is easy to see that when T RY terminates, either the user has entered valid input before exceeding the permitted number of attempts, or he has exceeded the limit.
338
12.7 Conclusions
Formal description and user interface design are both new and rapidly changing elds in which there is much ongoing research. This study aims to show how formal description methods can be used to aid in user interface design. It is argued that it is not currently feasible to formally describe the set of properties that any user interface should have. User interface research has not yet reached a stage where this approach is fruitful. Also, it is not often possible to dene the user interface totally independently of the other components of the interactive system. Usually the user interface designer wants to take advantage of various characteristics peculiar to the particular interactive system for which the user interface is intended. Thus a formal technique has been developed for the description of interactive systems with emphasis on the user interface. The proposed method is a new hybrid formal notation which combines statecharts with pre- and post-conditions. A statechart outlines the ow of control between the operations within the system, and each operation is described using pre- and postconditions. This formal description technique meets the criteria outlined at the beginning of Section 12.3. It deals with those parts of a system which are crucial in an interactive environment: error handling, help information, and interrupts. It emphasizes the top level ow of control and describes the system in levels. (The method does not dictate a level of abstraction, and ground rules for suitable levels are a subject for research.) Each operation is described separately in a modular fashion. The notation used is concise and abstract, yet easy to understand. The technique is also mathematically sound, enabling it to be used to prove various properties of the interactive system. Since this method has only been applied to a few examples, exploration of further examples is needed. Perhaps timing considerations could be added to allow for the description of concepts such as response time. More research is also needed to perfect and possibly extend the suggested formal description technique to deal with all possible interfaces and interface styles.
This chapter contains an unusual specication. The task is to describe the output which is required on a raster graphics device when lines are to be projected. As the author relates, the starting point was an informal specication which represented nothing more precise than wishful thinking. An interesting aspect of the specication is the need to underspecify the result because of the range of devices which have to be covered. The chapter contains both the specication and a discussion of implementations. These latter are justied (with respect to the specication) at a level closer to normal mathematical reasoning (rather than the formal proofs of steps of reication).
339
340
13.1 Introduction
Formal description is a useful tool in many areas of computer science since it allows the aims of a computer system to be clearly and unambiguously expressed and statements concerning the system to be formally proven. The formal description of computer graphics systems is in its infancy. Research in this eld has been pioneered by Carson [Car74], Gnatz [Gna], and Mallgren [Mal83] and is of great potential help. Graphical data are usually in the form of images composed of various drawing primitives such as points, lines and text. Most graphical devices are unable to represent drawing primitives exactly and thus must produce an approximation to the ideal. This makes the use of conventional program verication tools, such as a test driver, very difcult. The Graphical Kernel System (GKS) is the new international standard for twodimensional interactive computer graphics (ISO 7942). Work in designing test suites for GKS implementations is certainly not straightforward, and work on a formal description of GKS is under way [DFM84, DFM88, Mar84b, Rug88]. A formal description of the approximation to an image that a given computer graphics device should display will be useful in proving that the various devices in a computer graphics system function correctly. The idea of specifying what comprises a valid approximation to some ideal picture on a given graphics device has been deliberately ignored in previous research in the formal description of graphics. Mallgren [Mal83] says, The display system is assumed to provide a recognizable approximation to this representative picture., while Carson [Car74] admits, Of course, someone must eventually describe how a line should look but we could treat this as a binding issue, not a specication issue. However, it seems meaningless to maintain that a graphics program is functioning correctly unless it produces recognizable output. Carson [Car74] notes the following: At one extreme, nothing at all is said about the actual effects on a display surface when an output primitive is drawn. This would enable any vendor to claim that almost any implementation conformed to the standard, since it would be impossible to test implementations. At the other extreme, the specication could completely describe the effects of output primitives in terms of parameters such as addressability, color, hardware, text fonts, etc. that apply to typical display devices. Unfortunately, any parameter set considered by the speciers places unfair restrictions on manufacturers of certain classes of display devices. Furthermore, xed parameters would inhibit the degree of technological exibility available to implementors. Thus, it is necessary to devise a formal description that will permit the display of any one of a range of approximation to a picture thus allowing any reasonable output, but only reasonable output.
341
Section 13.2 of this chapter discusses graphics devices and their capabilities, and Section 13.3 describes line and their attributes. In Section 13.4 a formal description of thin solid lines is given, while Section 13.5 describes various line drawing algorithms, and Section 13.6 is a proof that Bresenhams line drawing algorithm satises this description. Section 13.7 suggests some extensions and Section 13.8 gives an extended formal description for thick solid lines. A proof that a sample thick line drawing algorithm satises the formal description is presented in Section 13.9, and a discussion of ideas for further research and conclusions follow in Sections 13.10 and 13.11. The appendix, shows a sample line plotted by various line drawing algorithms. Further references can be found in [Mar84a, Mar85].
13.3 Lines
A straight line to be displayed on a graphical device usually has a number of associated parameters. It must have a startpoint, an endpoint, a width, a line-type, and a color. The line can be any length, have any slope, be thick or thin, solid or broken, and can be drawn in any available color. Since the pixels of the raster device lie in a grid formation, the device must produce an approximation to the line to be displayed. Thus, the representation of a line on a raster device is nontrivial. The initial description denes thin solid lines having integral endpoints.
342
13.4 Straight solid thin lines with integral endpoints on a twocolor raster device
What properties should the approximation to a line on a raster device have? As stated earlier, the properties given should be specic enough to allow only reasonable approximations but general enough to allow any reasonable approximation. Thus it is inappropriate to specify an exact algorithm since a range of approximations is permitted. Neither is it appropriate for the representation to be entirely implementation-dependent as the role of the formal description is to limit the implementor.
Properties
The following are some intuitive ideas concerning the approximation to a straight line on a raster device: 1. If a pixel is ON it must be close to the line (i.e. no pixel that is very far from the line should be ON). 2. If a pixel is very close to the line it must be ON (i.e. no pixel that is very close to the line should be OFF). 3. If two pixels are in the same row or column, on the same side of the line, and the further of the two from the line is ON then the closer of the two must also be ON. 4. The pixels which are ON form a connected region with no holes or bends.
Formal description
Data types A line on the screen with integral endpoints: Line :: P1 : Pixel P2 : Pixel inv mk-Line p1 p2 A pixel on the screen: Pixel :: X : Y :
x: x y
p1
p2
343
p1
p2
Point :: X : Y : where: : reals : reals 0 01 0 1 : reals : integers Cartesian plane 01 0 1 : reals : Booleans
2:
Note that Pixel is treated as a subset of Point. Thus any function accepting a Point as a parameter will also accept a Pixel (but not vice versa). Make functions Make functions are used to form instances of all multiple component data types, except the form x y is always assumed to be of type Point (or Pixel). Point functions The following are functions dened with points as one or more of the parameters. Addition:
p
p1
Y p2
Subtraction:
p
p1
Y p2
344 Multiplication:
p
pp p
Point Point c X p c Y p
p1
Y p2
Less than:
p
p1
: Point Point X p1 X p2 p p2
Y p1
Y p2
p1
n i 1 n i 1
: Point Point X p1 X p2 p p2
Y p1
Y p2
Summation:
+p
i:
Point
Point
Point
Point
+ ppi
p:
+n 1 X pi +n 1 Y pi i i
l1
: Realline Realline P1 l1 P1 l2 l l2 P1 l1 P2 l2
P2 l1 P2 l1
P2 l2 P1 l2
345
maxdist pix p
P1 line
p.
line
What is the difference between the endpoints of the line? . : Line . line Point P2 line
p P1
line
What is the maximum horizontal or vertical distance between the two points? maxdist : Point maxdist p1 p2 Point max X p1 X p2 Y p1 Y p2
What is the maximum of the set? max : -set max s /a s b s a pre s Is the pixel very close to the line? nearline : Pixel Line nearline pix line b
346 Is the pixel an endpoint of the line? endpt : Pixel Line endpt pix line pix P1 line
pix
P2 line
Does the line run right through the pixel? linethru : Pixel Line linethru pix line p1 p2 Point onlineseg p1 line onlineseg p2 line adjcorn p1 p2 pix onreallineseg p1 leftbord pix onreallineseg p2 rightbord pix onreallineseg p1 botbord pix onreallineseg p2 topbord pix Are the two points adjacent corners of the pixel? adjcorn : Point Point Pixel adjcorn p1 p2 pix let rline mk Realline p1 p2 in rline l rightbord pix rline l leftbord pix rline l botbord pix rline l topbord pix What is the left border of the pixel? leftbord : Pixel leftbord pix Realline mk Realline pix
p 1 2 1 2
pix
1 1 2 2
What is the right border of the pixel? rightbord : Pixel rightbord pix Realline mk Realline pix
1 p 2 1 2
pix
1 1 p 2 2
What is the bottom border of the pixel? botbord : Pixel botbord pix Realline mk Realline pix
p 1 2 1 2
pix
1 p 2
1 2
What is the top border of the pixel? topbord : Pixel topbord pix Realline mk Realline pix
p 1 1 2 2
pix
1 1 p 2 2
347
01
P1 rline
p .r
rline
348
What is the difference between the endpoints of the real line? .r : Realline .r rline Point P2 rline
p P1
rline
Are all pixels closer to the line that an ON pixel ON? closrptson : Pixel set Line closrptson pixset line pix1 pix2 Pixel samexory pix1 pix2 closrl pix1 pix2 line pix2 pixset Are the two pixels in the same row or column? samexory : Pixel Pixel samexory pix1 pix2 mindist pix1 pix2 0
What is the minimum horizontal or vertical distance between the two points? mindist : Point mindist p1 p2 Point min X p1 X p2 Y p1 Y p2
What is the minimum of the set? min : -set min s /a s b s a b pre s Are the pixels on opposite sides of the line? oppsides : Pixel Pixel Line oppsides pix1 pix2 line pix1 pix2 p Point inlineseg p mk Line pix1 pix2 Is the point a nonendpoint of the line segment? inlineseg : Point inlineseg p line Line !
01
online p line
P1 line
p.
line
Is the point on the line? online : Point online p line Line ! p P1 line
p
p.
line
349
Are the rows of the display valid? (i.e. do only rows in a continuous range contain ON pixels and is each of these rows valid?) validrows : Pixel set validrows pixset y y1 y y y1 y2 y1 y2 y2 y y1 y2 x pixset x x y validrow pixset y
Is this row of the display valid? (i.e. does this row have only one continuous range of pixels ON?) validrow : Pixel set validrow pixset y x x1 x x x1 x2
y
x1 x2 x2 x x1 x2 x y pixset xy pixset
Are the columns of the display valid? (i.e. do only columns in a continuous range contain ON pixels and is each of these columns valid?) validcols : Pixel set validcols pixset x x1 x x x1 x2 x1 x2 x2 x x1 x2 y xy pixset y validcol pixset x
Is this column of the display valid? (i.e. does this column have only one continuous range of pixels ON?) validcol : Pixel set validcol pixset x y y1 y y y1 y2
x
y1 y2 y2 y y1 y2 x y pixset xy pixset
350
Bresenhams simple digital differential analysis (DDA) and chain code algorithms
For any given line these three algorithms produce the same approximation by sampling the line once per row or column and turning on the closest pixel to the sampled point. Whether the line is sampled by row or by column is based on the slope of the line and selected so that the maximum number of points will be sampled. The simple DDA algorithm [NS81] is the most straightforward. Bresenhams algorithm [Bre65] is optimized to use only integer arithmetic, and the chain code algorithm [RW76] stores the resulting line as a series of integers modulo 7, representing the eight different directions to an adjacent pixel. The line is related to the pixel set by: let N maxdist P1 line P2 line in n 0 N pix P1 line pix pixset roundp : Point roundp p round : round r Pixel round X p
n p roundp N p.
line
round Y p
/i
1 2
1 2
These algorithms always turn on pixels which the line at least touches, and thus have a tolerance of 1 . 2
351
min .x .y
since .x2 .y2 is expensive to compute. Also, for efciency reasons, the number n of steps is chosen to be a power of two. Thus the number of sampled points is 2 1 , where n is the smallest n such that: 2n max .x .y
1 2
min .x .y
The Symmetric DDA algorithm gives a more equal density to approximations to lines of different slopes than the Simple DDA. The line is related to the pixel set by: let N minvalidn line in n 0 N pix pixset minvalidn : Line minvalidn line /n validn n line pix P1 line
n p roundp N p.
line
validn m line
1 2
The Symmetric DDA algorithm always turn on pixels touched by the line and thus has a tolerance of 1 . 2
352
recursive manner, giving successive approximations to the line until the best approximation is achieved. It is not possible to give a simple nonrecursive description of this algorithm! Brons chain code algorithm is often identical to the standard Chain Code algorithm. Hown , and .y 1 , it gives approximations with a tolerance ever, in cases with .x approaching 1.
10
n i 1
11
. line
d
i 1
+ p 2i
p ci
in
p signp
+ proundp
2n
1 i
p ci
validn : Line validn n line signp : Line signp line sign : sign a
2n
sign X . line
if a
a then 1 else
The BRM algorithm can be very inaccurate, especially for lines with .x equal to the reection of .y in binary notation. The tolerance for this algorithm is approximately 2. See the appendix to this chapter for a sample line and the approximations produced by these line drawing algorithms.
353
Part 1
pix pix Now, p P1
n p N p. n N
1 2
: P1
n p Rp N p.
pix
1 . And either Y p
.x N
or
.y N
is an integer, as
X p or R Y p
Part 2
pix Pixel nearline pix line pix pixset : linethru pix line 0 and n N ). If the
Now if the pixel is an endpoint of the line, it will be ON (cases n line runs right through the pixel, there are two cases:
354 Case 1 N .x :
The line runs through the pixel in a horizontal direction, and we have that the point: X pix Y pix ! for !
1 1 2 2
The line runs through the pixel in a vertical direction, and the point: X pix ! Y pix for !
1 1 2 2
is on the line. This row will be sampled, and since: R X pix ! X pix
Part 3
closrptson pixset line : closrptson pixset line samexory pix1 pix2 closrl pix1 pix2 line pix1 pix2 Pixel oppsides pix1 pix2 line pix2 pixset pix1 pixset
355
.x , only one pixel is turned ON in each column, so we can assume that pix Since N 1 and pix2 are in the same row. Without loss of generality, assume that .x is positive and that pix1 and pix2 are adjacent. Then since pix2 is ON: X pix2 And thus: X pix1 X1 n 1 and Y pix1 Y1 Rn
.y .x
X1
n and Y pix2
Y1
Rn
.y .x
Now pix1 and pix2 are on the same side of the line and pix1 is closer to the line than pix2 . So, the line must cross the line x X pix1 between: Y pix1 and Y pix1 So: R n 1
.y .x 1 2
1 2
Rn
and pix1 will be ON. Thus it is true that no such pix1 and pix2 exist, and the above is satised. Case 2 N .y , samexory pix1 pix2 :
Part 4
validpic pixset : validpic pixset validrows pixset validcols pixset
Bresenhams algorithm only turns on pixels in rows and columns between p and p2 , and 1 it turns on at least one pixel in each of these, due to the choice of N. Thus, it is necessary only to check that each of these rows and columns is valid.
356 Case 1 N .x :
Only one pixel will be turned on in each column, so the columns are valid. Assume we have an invalid row, i.e. two pixels in a row are ON, but one in between them is OFF. So: nm p1
.y .x
P1
p Rp
n .x
p .line
p2
P1
p Rp
n m .x
p .line
and thus: i 0 m R n i
.y .x
Rn
.y .x
So all pixels in the row between p1 and p2 will be ON, and the row must be valid. Case 2 N .y :
The argument is the same as in Case 1, with the roles of the rows and columns reversed. Thus Bresenhams algorithm satises this formal description of thin solid lines.
357
Thick lines
It is quite easy to extend the thin solid line description to one for solid lines of thickness t. One question that arises is how the endpoints of the thick line should be treated, as both round-end and square-end models for thick lines exist. Another requirement that should be added to the description is that any pixel entirely covered by the thick line should be ON. A formal description including these extensions is presented in the next section.
Formal description
New data types A thick line: Thkline :: LIN : Realline THK : R A circle: Circle :: CEN : Point RAD : R
Is the approximation to the given thick line valid and within a tolerance of !? validapprox : Pixel set Thkline validapprox pixset thkline ! pix pixset withintol pix thkline ! if a pixel in ON it is close to the line pix Pixel nearline pix thkline pix pixset if a pixel is very near the line it is ON closrptson pixset LIN thkline any pixel closer to the line than a pixel that is ON is ON validpic pixset the pixel formation is valid Is the pixel within the given tolerance of the line? withintol : Pixel Thkline withintol pix thkline ! p Point onthklineseg p thkline Is the point on the thick line segment? onthklineseg : Point Thkline onthklineseg p thkline Square Ends Model: line Realline parline line thkline onreallineseg p line Round Ends Model: inter mk circle p THK thkline LIN thkline 2 Is the real line a stroke of the thick line? parline : Realline Thkline parline line thkline eucldist P1 line P1 LIN thkline eucldist P2 line P2 LIN thkline THK thkline eucldist P1 line P1 LIN thkline 2 eucldist P1 line P2 line eucldist P1 LIN thkline P2 LIN thkline What is the Euclidean distance between the two points? eucldist : Point eucldist p1 p2 Point R X p1 X p2
2 2
maxdist pix p
Y p1
Y p2
359
Does the line run right through the pixel? linethru : Pixel Realline linethru pix line p1 p2 Point onreallineseg p1 line onreallineseg p2 line adjcorn p1 p2 pix onreallineseg p1 leftbord pix onreallineseg p2 rightbord pix onreallineseg p1 botbord pix onreallineseg p2 topbord pix Is the pixel covered by the thick line? thklinecov : Pixel Thkline thklinecov pix thkline What are the corners of the pixel? pixcorners : Pixel Point-set 1 1 pixcorners pix X pix X pix 2 Y pix 2 1 1 1 1 X pix Y pix X pix Y pix 2 2 2 2 Are the pixels on opposite sides of the line?
1 2
Y pix
1 2
360
onrealline p line
361
01
p .r
line
Is the point on the real line? onrealline : Point onrealline p line Realline ! p P1 line
p
p .r
line
Is the rst pixel closer to the real line than the second? closrl : Pixel Pixel Realline closrl pix1 pix2 line ! withintol pix1 line !
Algorithm tolerance
Since this algorithm turns on only pixels containing a point of the line, its tolerance, like that of many of the thin line drawing algorithms discussed, is 1 . 2
362
In fact, pix pixset withintol pix thkline 1 : 2 pix pixset p Point onthklineseg p thkline pix Rp p p Point onthklineseg p thkline X pix RX p p Point onthklineseg p thkline 1 1 X pix X p Y pix Y p 2 2 p Point onthklineseg p thkline 1 max X pix X p Y pix Y p 2 p Point onthklineseg p thkline maxdist pix p withintol pix thkline 1 2 Thus a pixel is ON iff it is within a tolerance of 1 as desired. 2 Part 2 pix Pixel nearline pix thkline pix pixset :
Y pix
RY p
1 2
endpt pix LIN thkline nearline pix thkline linethru pix LIN thkline thklinecov pix thkline If the pixel is the endpoint of the line, or if the line passes through or covers the pixel, then the pixel must contain a point of the line and is therefore ON as shown in part 1, above. Part 3 closrptson pixset thkline : No pixel closer to the line than an ON pixel can be OFF, since a pixel is ON iff it is no more than 1 away from the line. 2 Part 4 validpic pixset : Since all the pixels touched by the line are ON, these will form a totally connected pattern, and thus a valid picture (no holes).
363
Thus this simple thick line drawing algorithm satises the formal description for thick lines.
Alternative approaches
The work presented in this chapter is all based on the model introduced in Section 13.2. If a different model from that of the square pixel is used, new insight into the properties of output primitives on graphics devices might be obtained. One idea is to look at
364
different tessellations of the Cartesian plane. What would the description look like if hexagonal pixels, for example, were used? The concepts of rows, columns, and adjacent pixels would need to be examined. Another approach might involve the splitting of the description into two parts; the local and global properties of the line. Local and global properties are discussed by Guibas and Stol [GS82]. A local property is one that can be checked for each pixel or small piece of the approximation. Such as: If a pixel is ON it is close to the line. On the other hand, a global property is one requiring the entire approximation to be considered as a whole. For example: The line looks straight. Examining the formal description in this way may present new ideas. The choice of distance function can also inuence the description. Although the maximum horizontal or vertical distance between two points conforms to the square pixel model, the Euclidean distance function is introduced when thick lines are considered. A different choice of distance function may simplify the description or suggest a new model.
13.11 Conclusions
365
algorithm, the density of the line depends on its slope, and, unless the algorithm is adjusted slightly, lines drawn in opposite directions may differ. It may be desirable to try to incorporate relaxations of these conditions into the description. For example: A line produced has nearly constant density. All lines produced have approximately the same density. The line from p1 to p2 is close to the line from p2 to p1 .
13.11 Conclusions
When a new graphics device is produced, it is necessary to be certain that it functions correctly. Although the formal descriptions presented here are only the tip of the iceberg with regards to that of a complete graphics device, it is encouraging that such descriptions can be produced, and actually used, to prove that algorithms for drawing graphical primitives produce reasonable results.
366
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
Approximation produced by Bresenhams, the simple DDA, and chain code algorithms.
367
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
The symmetric DDA algorithm turns on all the pixels turned on by the simple DDA, and some additional ones.
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
The all pixels touched algorithm turns on all the pixels turned on by the symmetric DDA, and more.
368
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
Brons chain code algorithm is identical to the chain code algorithm except in column 20.
10 8 6 y 4 2 0 0 3 6 9 x 12 15 18 21
The BRM algorithm is quite inaccurate when approximating this line, since in binary .y . form .x
A Glossary of Notation
The following sections provide a brief summary of the VDM notation. A detailed text book description of the language may be found in [Jon90].
A.1
Lexical conventions
The specications collected together in this book have been written over the last six years and thus embody a variety of styles and conventions. While the editors have endeavored to impose a consistent lexical and notational style on the specications, considerable variations still remain as it has not been practicable for these to be completely removed. In order to provide some help to the reader various of these conventions are discussed below. 1. Operation names. Operation names are given as either upper case or lower case letters. The rst character should be a letter which may then be followed by one or more letters, digits, dashes or underscores. For example, the following are examples of operation names: NEW, create, GC, remove ref , ADD-VALUE. 2. Function names. Three broad conventions may be discerned: (a) The names of functions are usually given as sequences of lower case letters, digits, underscores or dashes; names should start with a lower case character. Subscripting may be employed at the end of a function name. The following examples illustrate this convention: inv-State , circular, get name, f2 , g. DRC (b) The second form of naming functions involves an inx or mixx notation. , divides , p . This form is described in Jones [Jon90]. For example (c) The nal naming form appears in those case studies involving the denotational denition of language constructs. Here functions are dened over the types of particular language constructs and the specication style requires the construction of functions which determine if a particular construct is Well Formed and, for well-formed constructs, yield its TyPe. In these, 369
370
Appendix A
and similar, cases we nd functions of the following form being dened: WFConst, TPConst, MProgram, etc.
3. Type names. Two conventions may be identied: (a) Standard built-in types are shown as expected, thus , , x
m
y, etc.
(b) User dened types start with an upper case letter which is followed by one or more lower case letters, digits, underscores, dashes, etc.; subscripts may be used at the end of a type name. The following are examples of type names: Student name, Tp1 . 4. Variable names. Variable names start with a lower case letter which may then be followed by zero or more lower case letters, digits, underscores, dashes, etc. Subscripts may once again be used at the end of a variable name. For example: x1 , y, partitions, student name. 5. Selector names. Selector names follow the same rules as for function names: remember they are sometimes refered to a selector functions or projection functions. However, they are sometimes expressed using sequences of upper case characters. For example: Object :: body : Bag Oop RC :
A.2 Functions
The Di and R are types ER R f : D1 D2 R f d1 d2 ER f d1 : D1 d2 : D2 r: R pre d1 d2 post d1 d2 r f d f1 f2 f n
Function denition signature Function denition Function specication Pre-condition Post-condition Application Function composition Function iteration
Glossary of Notation
371
A.3
Operation specication
State a specication state type % # # State inv-State # set of states # # % initial and nal state values The Ti are types. OP p1 : T1 p2 : T2 r: Tr Signature ext rd e1 : T1 Read/write state wr e2 : T2 Access declarations pre p1 p2 e1 e2 Pre-condition post p1 p2 e1 e2 e2 r Post-condition pre-OP p1 p2 # Operation Quotation post-OP p1 p2 # # r
A.4
Logic
E E1 E2 are truth valued expressions S is a set, T is a type x S true false E1 Negation E1 E2 Conjunction E1 E2 Disjunction E1 E2 Implication E1 E2 Equivalence E1 E2 Equals E1 E2 Not Equals x S E Universal quantication x: T E x S E Existential quantication x: T E ! x S E Unique existence ! x: T E
A.5
Trivial types
not yet dened Set of distinguished values Equals Not Equals
372
Appendix A
A.7 Numbers
n n1 n2 numeric expressions or terms 012 12 1 -1 0 1 Rational Numbers Real Numbers n Unary Plus n Unary Minus n1 n2 Binary Plus n1 n2 Binary Minus n1 n2 Multiplication n1 n2 Division n1 n2 Less Than n1 n2 Less Than or Equals n1 n2 Equals n1 n2 Not Equals n1 n2 Greater Than or Equals n1 n2 Greater Than n1 rem n2 Remainder n1 mod n2 Modulus abs n Absolute Value n1 n2 Exponentiation n1 divides n2 Integer Division
Glossary of Notation
373
A.8
Sets
The table below lists the operators appropriate to the set data type. Figure A.1 shows the signatures of the operatorss using what is called an ADJ diagram. In these diagrams the ovals denote data types, in most cases generic in some type, while the arcs associate operators with argument and result data types.
, ,
, (T-set)-set T-set
card
T , ,
374 T is the type over which the set is dened S S1 S2 are sets SS is a set of sets x S p x is a predicate involving x ij T-set Finite Power Set abc Set Enumeration x S px Set Comprehension i j Subset of Integers Empty set x S Element of x S Not an Element of S1 S2 Equals S1 S2 Not Equals S1 S2 Union S1 S2 Intersection SS Distributive Union SS Distributive Intersection S1 S2 Difference S1 S2 Strict Subset S1 S2 Subset card S Cardinality of a set /x S p x Iota function
Appendix A
A.9 Records
t x Types r r1 r2 R type s is a selector function R type: : s: Types mk-R type x y z sr r s t r1 r2 r1 r2
Composite Object Constructor Selector Function Modify a Composite Object Equals Not Equals
Glossary of Notation
375
A.10 Maps
The map operators are recorded in the following table and the ADJ diagram is shown in Figure A.2.
dom D-set
D D
m m
R R
rng R-set ,
D ()
376 D is the Domain type R is the Range type d d1 d2 R m d f d r1 r2 R M M1 M2 are maps Sd D Sr R n 1 m D R m D R d1 r1 d2 r2 d f d D R pd M1 M2 M1 M2 M d M -1 dom M rng M Sd M Sd M M Sr M Sr M1 M2 M1 M2 M1 M2 M n
Appendix A
Finite Maps Bi-directional Finite Maps Map Enumeration Map Comprehension Empty Map Equals Not Equals Map Application Map Inverse Domain, dom M D Range, rng M R Domain Restriction Domain Subtraction Range Restriction Range Subtraction Overwriting Union Composition Iteration
Glossary of Notation
377
A.11 Sequences
The table below shows the sequence operators and the ADJ diagram for these operators is given in Figure A.3. T T
dconc
len
tl
T T hd
inds , dom
elems , rng
-set
T-set
378 T is the type over which the sequence is dened L L1 L2 are sequences n dom L 1 n ij T Finite Sequence T Non-empty Finite Sequence a b c d Sequence Enumeration Empty Sequence L1 L2 Equals L1 L2 Not Equals Ln Sequence Application len L Length L1 L2 Concatentation dconc L2 Distributed Concatenation hd L Head tl L Tail dom L Domain rng L Range inds L Indices. Same as dom L elems L Elements. Same as rng L Li j Sub-sequence
Appendix A
Glossary of Notation
379
"-notation allows us to keep distinct the ideas of dening a function, as an object which can be manipulated directly, and the naming of the function. For instance we can dene an unnamed instance of the double function using "-notation as follows: "x 2 x
Given this denition we can then name the function as follows: let double "x 2 x in
Application involves applying a function to an argument. Using double again we can apply the function to the value 2 as follows double 2 which clearly yields 4. Similarly we can apply the "-expression as follows: "x 2 x2
which once again yields the value 4. The form of a "-expression is as follows: "variable list Expression where the variables declared in variable list should appear within Expression. Consider the simple function which takes two integer arguments and produces the sum as a result. This function may be specied as follows: "x y x y
As mentioned above "-notation allows us to introduce unnamed functions which can then be manipulated in their own right. Clearly we can dene functions which accept functions as arguments and can yield functions as results. For example, the function apply accepts a function as an argument and yields a function. This resultant function can, in turn, be applied to an appropriately typed value to yield a result. let apply "f "x f x in
Appendix A
double 4
Alternatively, the apply function may be dened in the following manner using the more conventional function denition style. As we are not using polymorphic types in the book the type of the function apply has to be declared fully so that apply double is correctly typed: apply : apply f "x f
An appropriate discussion of "-notation and the "-calculus may be found in Schmidt [Sch86].
% post-OP # #
The check that we need to make for each individual operation is that it can be implemented: Thus, there must exist a nal state (which satises the invariant) such that the post condition of the operation can be satised. This proof obligation, known as the implementability (or satisability) proof obligation, has to be discharged for each operation.
R ret r
The adequacy proof obligation asserts that every possible state value in our abstract model has at least one representation in our reied model. The function ret (retrieve function) is provided to transform representations of type R to representations of type A.
pre-OPR r
Glossary of Notation
381
The domain rule states that every reied state that satises the pre-condition of the abstract operation, when viewed through the retrieve function, should also satisfy the pre-condition of the reied operation, i.e. the reied operation must not be more restrictive, that is dened on fewer states, than the abstract operation.
382
Appendix A
Bibliography
[And85] [ASU86] [Bae80] S. O. Anderson. Proving properties about interactive systems. Technical report, Heriot-Watt University, Edinburgh, October 1985. A. Aho, R. Sethi, and J.D. Ullman. Compilers Principles, Techniques and Tools. Addison-Wesley, 1986. R. Baecker. Towards an effective characterization of graphical interaction. In R. A. Guedj, P. J. W. ten Hagen, F. R. A. Hopgood, H. A. Tucker, and D. A. Duce, editors, Methodology of Interaction. North-Holland, 1980. H. G. Baker. List processing in real time on a serial computer. Comm. ACM, 21(4):280294, 1978. H. Barringer, J. H. Cheng, and C. B. Jones. A logic covering undened in program proofs. Acta Informatica, 21:251269, 1983. D. Bjrner and C. B. Jones. Formal Specication and Software Development. Prentice Hall International, 1982. R. Bloomeld, R. B. Jones, and L. S. Marshall, editors. VDM 88: VDM The Way Ahead, volume 328 of Lecture Notes in Computer Science. Springer-Verlag, Berlin, 1988.
[BJMN87] D. Bjrner, C. B. Jones, M. Mac an Airchinnigh, and E. J. Neuhold, editors. VDM A Formal Denition at Work, volume 252 of Lecture Notes in Computer Science. Springer-Verlag, 1987. [BK82] L. Borman and R. Karr. Evaluating the friendliness of a timesharing system. ACM SIGSOC Bulletin, 13(23):3134, 1982.
[BLSS83] W. Buxton, M. R. Lamb, D. Sherman, and K. C. Smith. Towards a comprehensive user interface management system. ACM Computer Graphics, 17(3):3542, 1983. 383
384 [BM72]
Bibliography
R. S. Boyer and J. S. Moore. The sharing of structure in theorem-proving programs. In B. Meltzer and D. Michie, editors, Machine Intelligence, Vol. 7, pages 101116. Edinburgh University Press, 1972. J. E. Bresenham. Algorithm for computer control of a digital plotter. IBM Systems Journal, 4(1):2530, 1965. R. Brons. Linguistic methods for the description of a straight line on a grid. Computer Graphics and Image Processing, 3:4862, 1974. A. Bundy. The Computer Modelling of Mathematical Reasoning. Academic Press, 1983. V. J. Bush. A survey of the use of matching functions. Private Communication, 1983. R. L. Constable et al. Implementing Mathematics with the Nuprl Proof Development System. Prentice Hall, 1986. J. Cameron. An overview of JSD. IEEE Transactions on Software Engineering, SE-12(2):222242, 1986. G. S. Carson. The specication of computer graphics systems. IEEE Computer Graphics and Applications, 3(6):2741, 1974. J. Corbin and M. Bidoit. A rehabilitation of Robinsons unication algorithm. In R. E. A. Mason, editor, Information Processing 83, pages 909 914. Elsevier Science Publishers (North-Holland), 1983. W. F. Clocksin and C. S. Mellish. Programming in Prolog. Springer-Verlag, second edition, 1984. J. Cohen. Garbage collection of linked data structures. ACM Computing Surveys, 13(3):341367, 1981. B. Cohen. Justication of formal methods for system specication. Software Engineering Journal, 4(1):2635, 1989. G. E. Collins. A method for overlapping and erasure of lists. Comm. ACM, 3(12):655657, 1960. W. R. Cook. The semantics of inheritance. Private Communication, 1988. C. J. Date. An Introduction to Data Base Systems. Addison-Wesley, 1981.
Bibliography
[DB76] [DFM84]
385
L. P. Deutsch and D. G. Bobrow. An efcient, incremental, automatic garbage collector. Comm. ACM, 19(9):522526, 1976. D. A. Duce, E. V. C. Fielding, and L. S. Marshall. Formal specication and graphics software. Technical Report RAL-84-068, Rutherford Appleton Laboratory, August 1984. D. A. Duce, E. V. C. Fielding, and L. S. Marshall. Formal specication of a small example based on GKS. ACM Transactions on Graphics, 7(3):180 197, 1988.
[DFM88]
[DLM 78] E. W. Dijkstra, L. Lamport, A. J. Martin, C. S. Scholten, and E. F. M. Steffens. On-the-y garbage collection: An exercise in cooperation. Comm. ACM, 21(11):966975, 1978. [Ede85] [Eva86] [Fil84] E. Eder. Properties of substitutions and unications. Journal of Symbolic Computation, 1:3146, 1985. A. J. Evans. Heap storage specication and renement to a target language. Technical Report RAISE/STC/AJE/1, STC Technology, 1986. M. Filgueiras. A Prolog interpreter working with innite terms. In J. A. Campbell, editor, Implementations of Prolog, pages 250258. Ellis Horwood, 1984. J. D. Foley. Tools for the designers of user interfaces. Technical report, George Washington University, March 1981. H. Freeman. Boundary encoding and processing. In B. S. Lipkin and A. Rosenfeld, editors, Picture Processing and Psychopictorics, pages 241 266. Academic Press, 1970. S. Guest and E. Edmonds. Graphical support in a user interface management system. Technical report, HumanComputer Interface Research Unit, Leicester, Polytechnic, 1984. J. V. Guttag and J. J. Horning. A Larch shared language handbook. Science of Computer Programming, 6(2):135158, 1986.
[Fol81] [Fre70]
[GE84]
[GH86]
[GHW82] J. Guttag, J. Horning, and J. Wing. Some notes on putting formal specications to productive use. Technical report, DEC, Palo Alto, CA, June 1982. [Gna] R. Gnatz. Approaching a Formal Framework for Graphics Software Standards. Technical University of Munich.
Bibliography
L. J. Guibas and J. Stol. A language for bitmap manipulation. ACM Transactions on Graphics, 1(3):191214, 1982. J. R. Gurd. Manchester prototype dataow system description. Private Communication, 1982. J. R. Gurd and I. Watson. A data driven system for high speed parallel computing. Computer Design, 19(6/7), 1980. J. R. Gurd and I. Watson. Preliminary evaluation of a prototype dataow computer. In Proc. IFIP 83. North-Holland, 1983. D. Harel. Statecharts: A visual approach to complex systems. Technical report, Department of Applied Mathematics, The Weizmann Institute of Science, December 1984. I. Hayes. Specication directed module testing. Technical Report PRG-49, Programming Research Group, Oxford University Computing Laboratory, Oxford, England, 1985. J. Herbrand. Researches in the theory of demonstration. In J. van Heijenoort, editor, From Frege to G del: A Source Book in Mathematical Logic o 1879 1931. Harvard University Press, 1967. J. F. He, C. A. R. Hoare, and J. W. Sanders. Data renement rened. Technical report, Programming Research Group, Oxford University Computing Laboratory, 1987. I. J. Hayes and C.B. Jones. Specications are not (necessarily) executable. Software Engineering Journal, November 1989. G. Huet and D. Oppen. Equations and rewrite rules; a survey. In R.V. Book, editor, Formal Language Theory: Perspectives and Open Problems, pages 349405. Academic Press, 1980. D. R. Howe. Data Analysis for Data Base Design. Edward Arnold, 1983. M. D. Harrison and H. W. Thimbleby. Formalising guidelines for the design of interactive systems. In P. Johnson and S. Cook, editors, People and Computers: Designing the Interface, pages 161171. Cambridge University Press, 1985. G. Huet. A unication algorithm for typed "-calculus. Theoretical Computer Science, 1:2757, 1975.
[Hay85]
[Her67]
[HHS87]
[HJ89] [HO80]
[How83] [HT85]
[Hue75]
Bibliography
[IST85] [Jac84]
387
IST. Database System Interface - IST 1021/2, third edition, October 1985. R. J. K. Jacob. Designing a human computer interface with software specication techniques. Technical report, Naval Research Laboratory, Washington, DC, 1984. C.B. Jones and P.A. Lindsay. A support system for formal reasoning: Requirements and status. In [BJM88], pages 139152, 1988. C.B. Jones and R. Moore. Mufn: A user interface design experiment for a theorem proving assistant. In [BJM88], pages 337375, 1988. C. B. Jones. Formal development of programs. Technical Report TR12.117, IBM Hursley, 1973. C. B. Jones. Software Development: A Rigorous Approach. Prentice Hall International, 1980. C. B. Jones. Development Methods for Computer Programs including a Notion of Interference. PhD thesis, University of Oxford, 1981. C. B. Jones. Systematic Software Development using VDM. Prentice Hall International, 1986. K. D. Jones. The Application of a Formal Development Method to a Parallel Machine Environment. PhD thesis, The University of Manchester, 1986. C. B. Jones. Systematic Software Development using VDM. Prentice Hall International, second edition, 1990. S. Kamin. Inheritance in SMALLTALK-80: A denotational denition. In Proceedings of the Fifteenth ACM Symposium on the Principles of Programming Languages, pages 8087, San Diego, California, January 1988. C. C. Kirkham. The basic programmers manual. Private Communication, 1981. D. E. Knuth. Fundamental Algorithms, volume 1 of The Art of Computer Programming. Addison-Wesley, 1979. H. Lieberman and C. Hewitt. A real-time garbage collector based on the lifetimes of objects. Comm. ACM, 26(6):419429, 1981. H. Lieberman. Using prototypical objects to implement shared behavior in object oriented systems. ACM SIGPLAN Notices, 21(11):214223, November 1986.
Bibliography
P. A. Lindsay. A survey of mechanical support for formal reasoning. Software Engineering Journal, 3(1), 1988. W. R. Mallgren. Formal Specication of Interactive Graphics Programming Languages. ACM Distinguished Dissertations 1982. MIT Press, 1983. L. S. Marshall. A formal specication of line representations on graphics devices. Technical report, Department of Computer Science, University of Manchester, September 1984. L. S. Marshall. GKS Workstations: Formal Specication and Proofs of Correctness for Specic Devices. University of Manchester, England, September 1984. Transfer Report. L. S. Marshall. A formal specication of line representations on graphics devices. In Lecture Notes in Computer Science 186, pages 129147. Springer Verlag, 1985. L. S. Marshall. A Formal Description Method for User Interfaces. PhD thesis, University of Manchester, 1986. A. Martelli and U. Montanari. An efcient unication algorithm. ACM Transactions on Programming Languages and Systems, 4(2):258282, April 1982. R. Moore. Towards a Generic Mufn. Ipse document 060/00140/2.1, 1987. University of Manchester. C. Morgan, K. Robinson, and P. Gardiner. On the renement calculus. Technical Report PRG-70, Programming Research Group, Oxford University Computing Laboratory, 1988. Z. Manna and R. Waldinger. A deductive approach to program synthesis. ACM Transactions on Programming Languages and Systems, 2:90121, 1980. Z. Manna and R. Waldinger. Deductive synthesis of the unication algorithm. Science of Computer Programming, 1:548, 1981. NCC, National Computing Centre Limited. SSADM, 1986. J. F. Nilsson. Formal Vienna Denition Method models of Prolog. In J. A. Campbell, editor, Implementations of Prolog, pages 218308. Ellis Horwood, 1984.
[Mar84b]
[Mar85]
[Mar86] [MM82]
[Moo87] [MRG88]
[MW80]
Bibliography
[Nip86] [NS73] [NS81] [OD83] [Par80]
389
T. Nipkow. Non-deterministic data types. Acta Informatica, 22:629661, 1986. W. M. Newman and R. F. Sproull. Principles of Interactive Computer Graphics. McGraw-Hill/Kogakuska Limited, 1973. W. M. Newman and R. F. Sproull. Principles of Interactive Computer Graphics. McGraw Hill, second edition, 1981. D. R. Olsen Jr. and E. Dempsey. Syntax directed graphical interaction. ACM Sigplan Notices, 18(6):112119, 1983. D. M. R. Park. On the semantics of fair parallelism. In D. Bjrner, editor, Abstract Software Specications. Springer-Verlag, 1980. Lecture Notes in Computer Science, 98. L. Paulson. Verifying the unication algorithm in LCF. Science of Computer Programming, 5:143170, 1985. W. D. Penniman. The need for quantitative measurement of on-line user behavior. ACM SIGSOC Bulletin, 13(2/3):4245, 1982. G. D. Plotkin. A powerdomain construction. SIAM Journal of Computing, 5(3), 1976. R. Pressman. Software Engineering: A Practitioners Approach. McGrawHill, second edition, 1987. M. S. Paterson and M. N. Wegman. Linear unication. Journal of Computer and System Sciences, 16:158167, 1978. B. Ratcliff. Software Engineering: Principles and Methods. Blackwell, 1987. P. Reisner. Formal grammar as a tool for analyzing ease of use: Some fundamental concepts. Technical report, IBM Research Laboratory, San Jose, December 1982. P. Reisner. Analytic tools for human factors of software. Technical report, IBM Research Laboratory, San Jose, March 1983. J. A. Robinson. A machine-oriented logic based on the resolution principle. Journal of the ACM, 12(1):2341, 1965.
[Rei83] [Rob65]
390 [Rob71]
Bibliography
J. A. Robinson. Computational logic the unication computation. In B. Meltzer and D. Michie, editors, Machine Intelligence, Vol. 6. Edinburgh University Press, 1971. A. Rosenfeld. Digital straight line segments. IEEE Transactions on Computers, C-23(12):12641269, 1974. C. Ruggles. Towards a formal denition of GKS and other graphics standards. In [BJM88], pages 6473, 1988. J. Rothstein and C. Weiman. Parallel and sequential specication of a context sensitive language for straight lines on grids. Computer Graphics and Image Processing, 5:106124, 1976. R. C. Schank and R. D. Abelson. Scripts, Plans, and Understanding. Lawrence Erlbaum, 1977. D. A. Schmidt. Denotational Semantics: A Methodology for Language Development. Allyn and Bacon, Inc., Boston, 1986. M. L. Shooman. Software Engineering: Design, Reliability and Management. McGraw-Hill, New York, 1983. J. H. Siekmann. Universal unication. In Lecture Notes in Computer Science, volume 170, pages 142. Springer-Verlag, 1984. I. Sommerville. Software Engineering. Addison-Wesley, third edition, 1988. N. K. Sondheimer and N. Relles. Human factors and user assistance in interactive computing systems: an introduction. IEEE Transactions on Systems, Man, and Cybernetics, SMC-12(2):102107, 1982. J. Staples and P. J. Robinson. Efcient unication of quantied terms. Journal of Logic Programming, 5(2):133149, 1988. G. L. Steele Jr. Multiprocessing compactifying garbage collection. Comm. ACM, 18(9):495508, 1975. V. Stenning. An introduction to ISTAR. In I. Sommerville, editor, Software Engineering Environments. Peter Peregrinus, 1986. J. E. Stoy. Denotational Semantics: The Scott-Strachey Approach to Programming Language Theory. MIT Press, 1977.
Bibliography
[Str87]
391
B. Stroustrup. What is object-oriented programming? In J. B zivin, J.-M. e Hullot, P. Cointe, and H. Lieberman, editors, Proceedings of the 1987 European Conference on Object-Oriented Programming, pages 5170. SpringerVerlag, June 1987. Lecture Notes in Computer Science, 276. D. Ungar. Generation scavenging: A non-disruptive, high performance storage reclamation algorithm. In Proceedings of the Software Engineering Symposium on Practical Software Development Environments, pages 157 167, Pittsburgh, PA, 1984. ACM SIGSOFT/SIGPLAN. S. Vadera. A theory of unication. Masters thesis, University of Manchester, 1986. J. S. Vitter and R. A. Simons. New classes for parallel complexity: A study of unication and other complete problems for P . IEEE Transactions on Computers, 35(5), 1986. B. Warboys. The IPSE 2.5 project: Process modelling as the basis for a support environment. In Proceedings of the International Conference on System Development Environments and Factories Berlin, May 1989, 1989. J. Weizenbaum. Symmetric list processor. Comm. ACM, 6(9):524544, 1963. A. Welsh. The specication, design and implementation of NDB. Masters thesis, Manchester University, October 1982. M. I. Wolczko. Semantics of Object-Oriented Languages. PhD thesis, Department of Computer Science, University of Manchester, May 1988. Technical Report UMCS8861. N. Winterbottom and G. C. H. Sharman. NDB: Non-programmer data base facility. Technical Report TR.12.179, IBM Hursley, September 1979.
[Ung84]
[Vad86] [VS86]
[War89]
[WS79]