Computer Science and Technology and their Application [1st Edition] 9781483153285

Computer Science and Technology and their Application is an eight-chapter book that first presents a tutorial on databas

932 95 16MB

English Pages 316 [306] Year 1974

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Computer Science and Technology and their Application [1st Edition]
 9781483153285

Table of contents :
Content:
Front MatterPage iii
Copyright pagePage iv
A Tutorial on Data-Base OrganizationPages 1, 3-64ROBERT W. ENGLES
General Concepts of the Simula 67 Programming LanguagePages 65-93J.D. ICHBIAH, S.P. MORSE
Incremental Compilation and Conversational InterpretationPages 95-114M. GRIFFITHS, M. BERTHAUD
Dynamic Syntax: A Concept for the Definition of the Syntax of Programming LanguagesPages 115-142K.V. HANFORD, C.B. JONES
An Introduction to ALGOL 68Pages 143-169H. BEKIĆ
A General Purpose Conversational System for Graphical ProgrammingPages 171-197, 199O. LECARME
Automatic Theorem Proving Based on ResolutionPages 201-266ALAIN PIROTTE
A Survey of Extensible Programming LanguagesPages 267-307N. SOLNTSEFF, A. YEZERSKI
Contents of Previous VolumesPages 309-310

Citation preview

Computer Science and Technology and their Application ADMINISTRATIVE

EDITORS

MARK I. HALPERN WILLIAM C CONTRIBUTING

McGEE EDITORS

LOUIS BOLLIET ANDREI P. ERSHOV J. P. LASKI

P E R G A M O N PRESS OXFORD · NEW YORK · TORONTO · SYDNEY

Pergamon Press Ltd., Headington Hill Hall, Oxford Pergamon Press Inc., Maxwell House, Fairview Park, Elmsford, New York 10523 Pergamon of Canada Ltd., 207 Queen's Quay West, Toronto 1 Pergamon Press (Aust.) Pty. Ltd., 19a Boundary Street, Rushcutters Bay, N.S.W. 2011, Australia Copyright © 1974 Pergamon Press Inc. All Rights reproduced, form or by recording

Reserved. No part of this publication may be stored in a retrieval system, or transmitted, in any any means, electronic, mechanical, photocopying, or otherwise, without the prior permission of Pergamon Press Ltd.

First edition 1974 Library of Congress Catalog Card No. 60-12884

Printed in Great Britain by A. Wheaton & Co.,

ISBN 0 08 017806 5

Exeter

A Tutorial

on Data-Base

Organization

ROBERT W. ENGLES IBM Corporation, Poughkeepsie, New York Abstract The purpose of this report is to clarify certain issues of data-base support. The main issues are data independence, security, integrity, search, and the integrated data base. The first section of the report is an introduction, which includes datamanagement history, trends, and terminology. The second section presents a theory of operational data based on the notions of entity sets and data maps. The third section is an exposition of data-bank design, emphasizing structure, search, and maintenance. The fourth section shows why data independence is a necessary feature of a viable data base system. The report should not be construed as representing a commitment or intention of IBM. The opinions expressed are personal and do not represent a corporate position. The intent of the report is tutorial, and the viewpoint is that of a systems programmer. Data independence Data integrity Data management Data security

Integrated data base Search Systems programming 21 Programming

1 2—AP

·

Preface The heart of an information system is its files or data base. The purpose of this report is to clarify certain issues of data-base support. The main issues are data independence, security, integrity, search, and the integrated data base. The first section is an introduction which includes data-management history, trends, and terminology. The evolution of data-management software is viewed in terms of the growing distinction between file organization (logical structure) and data organization (physical structure). A system structure is described to provide a framework for the definition of data-base concepts and terminology. The second section presents a theory of operational data based on the notions of entity sets and data maps. Entities are the things about which we record facts. Facts are relationships, and data maps are a means of defining relationships. The section includes an analysis of data maps, data-set organizations, and retrieval requests. The third section is an exposition of data-bank design, emphasizing structure, search, and maintenance. Hierarchical, multi-list, variable and fixed symbol-list organizations are described and compared. The section includes an analysis of complex structure, indexing techniques, and update problems. The final section shows why data independence is a necessary feature of viable data base support. The presentation emphasizes the need for a logical data organization against which application programmers can define file organizations, and against which data-base administrators can define data organizations. The notion of the entity record set is suggested as the basis of such a logical data organization. This report should not be construed as representing a commitment or intention of I B M . The opinions expressed in this report are personal and do not represent a corporate position. The intent of the report is tutorial and the viewpoint is that of a systems programmer. This report contains references to a selected bibliography which appears after the last section. A more extensive bibliography of data-base organization will be in found in réf. [1]. 1. Introduction 1.1.

BACKGROUND

Traditionally, file organization is the process or result of relating the stored-data requirements of a particular application to the physical characteristics of a particular type of input/output device. A

i?. W. Engles

4

more current definition would allow for the possibility of multiple applications and a class of I/O devices. In discussing data independence, it is necessary to distinguish between the logical organization of data appropriate to an application and the physical organization of the data base. We will use the term "file organization" to refer to the structure seen by the application programmer and "data organization" to refer to the actual arrangement of the stored data. It is not possible to use terminology that is consistent with all references. In ref. [19], for example, the terms "data structure" and "storage structure" are used for file organization and data organization, respectively. Our basic concepts and terminology are illustrated in Fig. 1. Traditionally, a file is defined as a collection of related records, and a record is defined as a collection of related fields. These terms need not be redefined provided it is clear that they refer to application-oriented units of information, not systems-programmingoriented units of stored data. The distinction is fundamental. Indeed, the exact relationship between files and stored data is an essential specification of any data management system. This relationship is used in an inexact way in Fig. 2 to categorize levels of datamanagement software. The category labelled the "past" is the level of no data management. In this category, software is limited to device handling and file organization is not distinguished from data organization. (The only difference between the file and the data is that many generations of data may exist for the "same" file.) Typically, the data organization is suitable for one type of device and one application program.

INFORMATION

File Organization

DataOrganization

Information:

The meaning assigned to data by known conventions.

Data:

A n y representations to which meaning may be assigned.

Storage:

A d e v i c e into w h i c h data can be inserted, in w h i c h it can be r e t a i n e d , and from which it can be r e t r i e v e d .

Data O r g a n i z a t i o n :

The correspondence between the structure of data and the structure of storage.

File O r g a n i z a t i o n :

The correspondence between the information structure and the structure of the d a t a .

FIG. 1

STORAGE

5

A Tutorial on Data-Base Organization File

Data

File

Data

Past

F l el

Data nset

File

Data set

Present

Fi les

Data base

Future

FIG.

2

Furthermore, the programmer's intimate knowledge of the data organization is embedded in both the logic and the instructions of the application program. The result is that the program, the data and the type of storage device are tightly bound, a situation which makes it difficult to change anything or use the same data for other applications. Any change to the data organization requires rewriting, recompiling, and retesting the programs which use the data. Efficient access to the data is limited to a particular search algorithm; i.e., either sequential or direct on one key. While much of the data might be of interest to another application it will probably include fields

6

R. W. Engles

that are not of interest, exclude fields that are of interest, and not be organized in the sequence that represents the relationships of interest to the other application. Given the premise that each application should be optimized, the usual solution to these problems is not to use the same data across applications. The category labeled the "present" includes conventional input/ output control systems (IOCS) and software which provides limited data-base support. Even at the IOCS level a distinction exists between file organization and data organization. For example, the application programmer views a particular file as a contiguous collection of fixed-format card images; the data organization differs from the file organization in that the data consists of blocked records stored on multiple volumes. However trivial, this is a form of data independence since the software provided blocking or deblocking and end-of-volume processing can be transparent to the application program. Changes to the blocking factor or number of volumes will not require changes to the application program. Current IBM operating systems and program products provide various degrees of data independence. All are limited. With function as the criteria, we can classify the present support into three levels : 1. The level of input/output control as exemplified by DOS. 2. The level of data-set control as exemplified by OS/360. 3. The level of data-base control as exemplified by IMS/360. At the level of input/output control, software will control the use of the channels and devices, provide error-correction procedures, label processing, symbolic device addressing, end-of-volume processing, and various access methods. At the level of data-set control, software assumes responsibility for direct-access device storage management and maintaining a catalog of data sets. This level also includes a greater degree of data-set protection and device independence. At the level of data-base control, software provides mechanisms for eliminating redundancy and sharing data across applications. This level includes a greater separation of file organization and data organization in that the file may be a subset of a data base. In IMS, for example, a data base consists of one or more data sets and many different files can be defined against the same data base. The records of a file are defined in terms of segments—a unit of stored data consisting of contiguous fields. During execution, IMS selects those segments required by an application program. Programs are dependent on the composition of the segments they use and the hierarchical relationships among segments; otherwise, changes can be made to the data organization without requiring changes to the application programs [2].

A Tutorial on Data-Base Organization 1.2.

7

TRENDS

Viable data-base support must provide further separation of file organization and data organization. In the future it should be possible to define a file in terms of the information required by the application without regard to the organization of the data base. Defining a file in terms of the required information implies a frame of reference composed of objects and relationships in the real world, as opposed to arrangements of data objects in storage. Limited only by what information is available from the data base, it should be possible to specify a file in terms of a set of objects and what facts are desired about these objects. These facts include relationships to other objects, about which one may want certain facts, etc. It should also be possible to select a subset of objects by presenting facts which characterize these objects. Furthermore, it is necessary to specify the sequence and format in which the information is desired. These requirements have tremendous implications for search and data-base organization. First, it is necessary to distinguish data access from data organization. In the past, it has been customary to design a data organization specifically for a particular method of access. The various access methods of current operating systems, for example, can be used only with the appropriate data organizations. As Mealy [3] puts it: . . the correspondence between the structure of the data and the structure of storage, we call the data organization. While this enables data access, it is not access. Access is a feature of the processing of the data, not of the data itself or how it is represented; different procedures will, in general, want to access the same data in different ways and orders. The order in which data items are fetched and stored is (or should be) independent of the data organization." For direct access, it has been customary to identify a particular field as the key and arrange the date to facilitate search on values of that field. With the direct access method, for example, the arrangement of data is determined by the key transformation algorithm. With the indexed sequential access method, the data is arranged in accordance with the collating value of the key field. Either way, efficient access to the data is only possible through a single key field. There have always been requirements for access by more than one key. In the future, every field should be considered a potential key for searching. If a data base is to represent useful information about the real world, then it must reflect some of the complexity of that world. If we view a data base as a representation of information about sets of objects such as parts, products, warehouses, organizations, people, sales orders, purchase orders, manufacturing orders, etc., it is clear

8

R. W. Engles

that there are many complex relationships among these sets of objects. The data base must contain representations of the objects, simple facts about the objects, and structural facts; i.e., representations of the relationships among the objects. The structure is obviously a complicated graph. Indeed, the relationships among a single set of objects such as parts can be a complicated graph. With the notable exception of problems such as the bill of material explosion/implosion of a product structure parts file, conventional batch applications do not require a nonredundant representation of complex structure. Even when applications and their files are interrelated, the files required by a single application need only represent a subset of the total relationships and these relationships are typically no more complicated than a tree structure. With batch processing methods, the data for the files can always be prepared before the execution of each application program. Selecting, merging, and sorting data between runs removes the need for any one collection of data to have complex structure. In effect, the complex structure of the total relationships is represented by distinct collections of simple structures. Each application program has its own files in the form of separate collections of data. Of course, data then exists in a highly replicated form causing problems in data integrity or file maintenance. However, in a batch processing environment, this problem can be solved by the judicious scheduling of sequential runs. In an environment characterized by the random arrival of heterogeneous inputs, batch processing methods no longer apply. If inquiries and transactions are to be handled as they occur, files cannot be prepared before each run and the problem caused by the replication of data cannot be solved by sequential scheduling of runs. It becomes necessary to design data banks that represent a maximum of relationships with a minimum of redundancy. The design process may be viewed as combining the files of all applications and factoring out the common information. The result is called an integrated data base. The issues of data independence, search, and the integrated data base are highly interrelated. One of the purposes of data independence is to allow an installation to evolve to an integrated data base without becoming bogged down in program maintenance. Data independence implies that application programs reference data by name and search is a system function. In order for a system to perform this function and also to provide data integrity and security, the mapping between file organizations and data organization must be formalized. Knowledge about data, which today is embedded in the procedural steps of a program, must be made explicit at the system level. Data must be consistently defined and centrally con-

A Tutorial on Data-Base Organization

9

trolled. The relationships among data elements must be formally described. 1.3. TERMINOLOGY

The design of effective data-base support must be based on consistent, coherent, and adequate notions about operational data. Today, we do not seem to have any "theory of operational data". However, we believe that such a theory is evolving and this is the subject of the next section of this tutorial. Unfortunately, we must first face up to the problem that exists whenever there is no clear and commonly agreed upon theory: the terminology problem. It is doubtful that all readers of this paper will agree with our use of the few technical terms introduced so far, which is exactly why it is necessary to define more terminology before proceeding any further. The trouble with terminology—as with data—is that meaning is a function of context. To provide context for our definitions, it is necessary to present a system structure. This is not a design, but merely a conceptual framework within which we can talk about data. We assume a multitasking system with a mixture of batch, transaction, and interactive processing. Of course, the system is oriented to on-line use of a common data base. As with any computer-based system, the major components of the system are hardware, people, rules, programs, and data. The major classes of data and the relationship of programs and data is shown in Fig. 3. The terminal management function includes the care and feeding of the lines, message queueing and routing, and control of local and remote terminal devices. The processing programs are responsible for the interpretation of their input data, requesting file update or retrieval, and the composition of output data. The data-base management function includes the interpretation of data independent file requests, search, and control of the creation, maintenance and use of the data base. A data base is defined as the total collection of stored, operational data used in the application systems of a particular enterprise. Operational data represents certain information about entities of concern to the enterprise; at any one time this data is distinct from input data, output data, programs and other types of data. The information content of a data base includes data stored on volumes of secondary storage and data derivable from the stored data by functions from the program base. Output data includes answers and reports which are a function of the information content of the data base. Input data includes representations of questions, procedures, and transactions. Transaction records may become part of the data base or cause changes to

10

R. W. Engles Output data

Input data

£99

QQ9

Program base Other data

Terminal management

Conventional data management

Processing

Task

programs

management

Data-base management

D a t a base

FIG.

3

be made to data in the data base. "Other data" includes queues of input and output data, temporary files, private files, logs, etc. We assume that other data is best handled by conventional access methods and that the data-base handling mechanisms do not apply to the true input/output that characterizes terminal handling. Furthermore, we are only concerned with formatted data as opposed to natural language text on the grounds that text can be handled as a special case of formatted data. In short, we are concerned here with stored, formatted, shared operational data. In defining data-base terminology we must distinguish first between units of storage and units of data. In defining units of storage we note the conventional distinction between main storage and secondary storage, and assume that the 8-bit byte is the smallest addressable unit. The major unit of secondary storage is the volume. An example of a volume is a disk pack. The relationships of volumes to storage devices and the existence and size of units such as the cylinder and the track are dependent on the device type. The basic unit of secondary storage is the physical record. A physical record is a sector on disk or that which is recorded between gaps on tape or address markers on disk.

A Tutorial on Data-Base Organization

11

In defining units of data we must distinguish between systemoriented units and application-oriented units. In defining systemoriented units we are concerned with subdivisions of the physical data base. In order from largest to smallest, the units are data bank, data set, extent, block, stored record, and data element (see Fig. 4). The data bank is the major unit of related data. A data base may be composed of one or more data banks. Data within a data bank is interrelated, but not related to data in other data banks. A data bank is composed of data sets. The possibilities include a single data set, data sets that are related in the sense that some are indexes to others, and data sets in different computer installations. A data set is a named collection of data in one or more extents. A data set may be wholly contained within a volume or may span many volumes. Note that the data set is defined without reference to

• Volume Secondary storage units

Physical record

Data bank Data set

Extent

System data units Block Stored record Data element ( d a t a item)

File Application data units

ι Logical record ——

FIG.

4

Field (value)

12

R. W. Engles

its information content. We assume that operational data is stored as data sets, and the system includes data sets which are not operational data. An extent is a collection of blocks which are contiguous in secondary storage. The extent is the result of storage allocation; its size depends on the storage allocation method. Data sets might have only one extent; at the other extreme, a chained list method of storage management might use the block as the unit of allocation. The block is the unit of interchange between main storage and secondary storage; i.e., that which is read and written. A block is usually contained in one physical record. A block contains all or part of one or more stored records. (In current data management a stored record is called a logical record.) A stored record is an identifiable collection of related data items. Exactly how the data items are related depends on the data organization. (The data items might represent different types of facts about the same entity, the same type of fact about different entities, or some mixture of facts and entities.) The mapping of stored records into blocks depends on the length of the two units and the selected combination of fixed-length or variable-length blocks and fixedlength or variable-length stored records. If stored-record size is not a factor of block size, either blocks must be padded, or stored records allowed to span blocks. With spanning, a stored-record segment is that portion of a stored record within a block. The smallest unit of system-oriented data is the data element. A specific instance of a data element is a bunch of bits which we call a "data item". Data elements have attributes such as name, value type, representation, length, etc. These are data attributes as opposed to information attributes; i.e., a data attribute is a characteristic of data elements; an information attribute is a characteristic of entities such as employee name, department, salary, etc. The purpose of a data element is to provide the values of an information attribute. The application-oriented units of data are the file, logical record, and field. A file is a collection of related logical records. A logical record is a collection of related fields. A field is the smallest unit of interest to an application. Logical records of the same file have the same logical structure. Every logical record of a simple file has the same number of fields. This includes the possibility of logical records composed of a single field. Logical records of hierarchical files usually do not have the same number of fields. Consider, for example, a DEPARTMENT file in which each logical record contains information about a department to include a list of the employees in that department. Since each department does not have the same number of employees, the number of fields will vary across

A Tutorial on Data-Base Organization

13

logical records. The selection and arrangement of fields and logical records is the file organization; it should not be confused with the data organization which may be different.

2. Operational Data 2 . 1 . ENTITIES AND ATTRIBUTES

Operational data is a representation of discrete assertions about the entities of concern to an enterprise. We will call these discrete assertions "facts" with the understanding that inaccurate and false assertions can be recorded as easily as true facts. An example of a fact is: "The employee with man-number 5 2 8 6 7 1 has the job title advisory programmer." It is typical of operational data that such a fact would be represented in an encoded form, and not in the form of text as shown here. It is also typical of operational data that the same type of fact would be recorded for all entities of the same type; e.g., every employee will have his job title recorded. We use the term "entity" in order to talk about operational data in general. An entity is a person, place, or thing. The things may be real or abstract and this includes such things as events, classes, and relationships. As a matter of fact, anything can be an entity because an entity is simply that which we record facts about. What objects are defined as entities will depend on the purposes of the given data base. It can also depend on the development stage of the data base. For example, in an early development stage of a particular data base, employees are entities, but job titles are not; i.e., job titles are viewed only as properties of entities, and not also as entities themselves. In a later stage of this data base, job titles become entities in that it is decided to record facts about job titles such as the qualifications for each title, number authorized, salary range, etc. An entity set is a collection of similar entities; i.e., things that have the same kind of properties. Examples are the set of parts, the set of employees, the set of customers, the set of manufacturing orders, etc. The idea of entity sets is pertinent to the integrated data base. For example, we would not speak of a "payroll entity set"; rather, we would speak of a set of employees about which we record facts of interest to the payroll application. Some of these facts plus other facts about employees may also be of interest to an education or personnel application. If we do speak of a payroll entity set, it means we have recorded facts about a set of objects called payrolls. One of the confusion factors in speaking about data is that we have at least three realms of interest in data processing and we tend to jump from realm to realm without warning. The three realms are:

R. W. Engles

14

the real world, ideas about it existing in the minds of men, and symbols on paper or some other storage medium. In Mealy's theory of data, the latter realms are representations of the former and each is a system composed of entities, values, data maps, and procedures [3]. We agree with this view, but think it is useful to use different words for different realms. Let us call the three realms "reality", information", and "data". In referring to reality, we will use the terms "entity" and "property". In referring to information, we will use the terms "attribute" and "value". In referring to data itself, we will use the terms "data element" and "data item". By our definition, a property is something in the real world, namely, a characteristic of an entity. An attribute is an idea about the real world, namely, a property class. To say that an entity has a certain property means that some attribute of that entity has a certain value. For example, to say that a part is red, means that the value of its color attribute is red. To represent this information in the realm of data, there would be a data element that corresponds with the color attribute such that an interpretation of one of its data items would yield the value "red". In short, a data item represents a value and a value represents a property. However, in order for these representations to be properly interpreted, the data item must be associated with a data element, the value must be associated with an attribute, and the property must be associated with an entity (see Fig. 5). We will speak of entities in the realm of information with the understanding that what we really have are attribute values. That is, we will assume that associated with each entity set is an attribute whose values have a one-to-one relationship with the entities. We

Data

FIG.

5

A Tutorial on Data-Base Organization

15

will call this attribute the identity attribute, and we will call its values unique identifiers or entity identifiers. Examples are partnumbers, man-numbers, order-numbers, etc. 2.2. DATA MAPS

It is useful to think about operational data in terms of sets of objects and relationships between members of the sets. A fact is a relation—a correspondence between members of two sets. In the realm of information, the sets are attributes and the members of the sets are attribute values. For each pair of sets, one of the sets is an identity attribute. For example, consider the following fact: the quantity-on-hand of part# 3265 is 800. Quantity-on-hand and part# are attributes; 3265 and 800 are attribute values. One of the sets is an identity attribute, namely part#. The quantity-on-hand of part 3265 is one relation between the two sets. Obviously, other relations exist, namely the quantity-on-hand of all the other parts. To talk about the totality of relations between members of two sets, it is customary to use the term "map". Thus, we can talk about the map of the set of part-numbers into the set of on-hand-quantities. In talking about a map of the set A into the set B, we will write A->B. This represents a map which makes values in Β correspond to arguments in A. To each element of A, a map may assign none, one, or more elements of B. The sets A and Β may be the same set or different sets. One of the sets is an identity attribute. The other set is an attribute associated with the same entity set. We will call such maps "data maps". An example of a simple data map is shown in Fig. 6. We can classify data maps in regard to the type of sets that can be mapped and in regard to the complexity of the mapping. The resulting classification provides a definition of the types of relationships that must be represented by a data-base organization. A data map involves two sets of attribute values. Let V denote one set of any type. We have distinguished two types: sets of attribute values that represent entities, and sets of attribute values that do not represent entities. Let Ε denote a set of entity identifiers, and W denote a set of values that are not entity identifiers. For now we consider only maps of the form E - W (as opposed to maps of the form V->E). Figure 6 is an example of such a data map. More specifically, assuming that the values of CLASS are not entity identifiers, Fig. 6 is an example of a nonstructural data map; i.e., a map of the form E->W. Such a map is said to represent simple facts as opposed to structural facts. If the values of CLASS were entity identifiers, we would have a structural data map—a map of relationships between entities. There are two types of structural maps: data maps of the form E->E are maps of relationships between entities of

R. W. Engles

16

Attribute:

Thing #

Attribute:

Class

F I G . 6 . Simple, non-structural data map. the same set; data maps of the form E->E' are maps of relationships between entities of different sets. Assuming that the values ofPLACE# are entity identifiers, Fig. 7 is an example of a structural data map, specifically, a map of the form E->E'. An example of the form E->E is a map that specifies the hierarchical relationships among the people in an organization. We classify mappings as simple or complex. In a simple mapping each element of Ε is related to no more than one element of V. In a complex mapping, an element of Ε may be related to many elements of V. We further classify each type as follows: given a simple or complex map E->V, is its inverse, i.e., the map V-^E, simple or complex? This yields four types of mappings: The map The map The map The map

is simple; the inverse map is also simple. is simple; the inverse map is complex. is complex ; the inverse map is simple. is complex; the inverse map is also complex.

An example of a simple map whose inverse is also simple is a map of job codes to job titles (assuming the titles are unique). In maps of this type, the elements of the two sets have a 1-to-l relationship. However, this does not necessarily mean that every element of Ε is paired with every element of V and vice versa. Either set may have elements that are not assigned to elements of the other set. This applies to all four types of mappings.

A Tutorial on Data-Base Organization Attribute

Thing #

Values:

Attribute

17

Place #

Values :

FIG. 7. Complex, structural data map. Figure 6 is an example of a simple map whose inverse is complex. In maps of this type, the elements have a «-to-l relationship; i.e., many elements of Ε can be related to the same element of V. In a complex map whose inverse is simple, the elements have a l-to-n relationship; i.e., one element of Ε can be related to many elements of V. An example is a map of job codes to employees with those job codes. (Assuming an employee has a single job code.) Note that an n-to-l map is the inverse of a l-to-n map. In a complex map whose inverse is also complex, the elements of the sets have a n-to-n relationship; i.e., each element of Ε can be related to many elements of V and each element of V can be related to many elements of E. Figure 7 is an example of such a map. In regard to examples, it should be noted that the complexity of a relationship depends on one's ideas about the real world. The map of married males to married females could be any one of the four types depending on whether we assume monogamy, polygamy, polyandry, or both polygamy and polyandry. We have classified data maps in regard to the types of sets that can be mapped and in regard to the complexity of the mapping. By combining the classifications we define all the basic relationships that must be represented by a data-base organization. The twelve types of data maps are shown by the matrix of Fig. 8. Below the matrix is an example of each type of data map. Names of identity attributes 3—AP

*

*

18

R. W. Engles

E-+ V

Map is Map is Map is Map is simple ; simple ; complex; complex ; Inverse map Inverse map Inverse map Inverse map is simple is complex is simple is complex

E-^W

1

2

3

4

Ε->Ε'

5

6

7

8

Ε -> Ε

9

10

11

12

A. B. C. D. E. F. G. H. I. J. K. L.

Man# Man# Dept# Man# Dept# Man# Dept# Part# Man# Man# Dept# Part#

Date of Hire M a n # of Manager M a n # of Manager of Department Warehouse # of warehouses where stocked Dept# of subordinate departments Social Security Number Telephone Numbers M a n # of Spouse M a n # of Employees in Department Part# of component parts Degrees Held Dept# of Department FIG. 8

end with a number sign. Thus, in the first example, M a n # is an identity attribute and Social Security Number is not. 2.3. DATA STRUCTURE

Data-base organization may be viewed as the process of defining, representing, storing, and maintaining data maps. A multitude of methods are applicable to this process. Our purpose is not to cover them all, but rather, to uncover the essential problems and solutions. The first step in data-base organization is determining what data maps are required. The problem is that at any stage in the development of a data base, it is not possible to predict exactly what data maps will be required for all subsequent stages. Data maps will be added, deleted, and redefined. Furthermore, changes in requirements and resources will dictate changes to the implementation of data maps. "Data independence" allows these changes to be made with a minimum of disruption to existing applications. We will return to this aspect of data-base organization in the final section of this tutorial.

A Tutorial on Data-Base Organization

19

"Data maps" are a way of talking about relations. Another way of talking about the same subject is to use the term "function". "In classical applied mathematics most functions of interest can be approximated by some algorithm which becomes, for practical purposes, the definition of the function. In other areas, however, many functions of practical, if not general, interest (such as the correspondence between employee name and salary) can be specified only by an exhaustive listing of each argument value and its corresponding function value. Such a function will be called fortuitous. The basic algorithm applicable to the evaluation of a fortuitous function is a search of the list of arguments, i.e., a comparison of the given argument with the list of arguments to determine the correspondent to be selected..." [4]. In data-base organization most functions of interest are fortuitous. For now, we will ignore other possibilities, and think of data maps as lists of argument values and function values. Some of the possible ways of representing data maps become evident if we take the following point of view: Our purpose is to represent relations between values of two attributes; i.e., argument values and function values. We allow a function value of "null". If, for the moment, we ignore complex data maps, then we can say that a relation is completely specified by giving two attribute names and two attribute values. We could therefore represent a fact by a sequence of four data items; i.e., identity-attribute-name, entityidentifier, other-attribute-name, attribute-value. While this may not be a bad form in which to communicate information to processing programs, it is obviously an inefficient way to organize a data base. Therefore, we proceed as follows: First, we group the facts by entity set and remove the identity-attribute-name. We now have a sequence of three data items where the one attribute-name classifies the relation between the two attribute values; i.e., we have triplets of the form : entity-identifier, attribute-name, attribute-value. Information represented in this form has been called a "relational data file" [1]. Now, it is typical of operational data that many different facts will be recorded for most, if not all, of the entities. We therefore group the triplets by type of fact and remove the attribute-name. We are left with pairs of values; i.e., entity-identifier, attribute-value. By placing the sets of pairs in the same order by entity-identifier, we can factor out all replications of the entity identifiers. The result of this organization is illustrated in Fig. 9. Our immediate objective is to identify the major types of data organizations. The matrix of Fig. 9 is a schema of a data organization. The type of data organization illustrated by this matrix will be called a regular data organization. A more concrete illustration of the organization is given in Fig. 10. However, the matrix of Fig. 10

R. W. Engles

20

A t t r i butes Α ι , Α 2,

Ε,

V|,i

VI

|2

Ε2

V 2, i

V2

2|

V 2, m

Values

Entities

En

FIG. 9.

is still more logical than physical because it does not show how the structure is mapped into storage. We will refer to such a structure as an "entity record set". From the matrix, we can specify a specific data organization; i.e., we can specify the content and structure of one or more data sets. For example, consider that the values are represented by data items such that all the data items of one row of the matrix comprise a stored record, some fixed number of stored records comprise a block, and all the blocks are contained in one data set. We do not use the word matrix in the sense in which programming languages define a matrix because we do not assume that the data elements are homogeneous. However, we do assume for now that each column is homogeneous. In other words, we assume one fixed-length data element per attribute. This assumption combined with a fixed-number of attributes per entity gives us fixed-length records. This is a great simplification which facilitates the management of both storage and data. Later we will see if we can live with such assumptions. (Remember, for example, that we are currently ignoring complex data maps.) The matrix of Fig. 1 0 can be mapped into storage in other ways. We could partition the matrix horizontally, placing some of the stored records in one data set and the remainder of the records in

A Tutorial on Data-Base Organization

21

Attributes of THINGS: THING # NAME

11549 11648 11985 12003 12116 12237 12345 12563 12677

Joe Sam Bob Ray Jim Joe Max Jim Irv

CLASS

STATUS

COLOR

DATE

Beta Alpha Alpha Gamma Beta Delta Gamma Beta Delta

Out Out In Out In In In Out In

Red Blue White Red Green Black White Yellow Blue

122032 081352 101547 012853 042939 081148 122032 111140 033045

Part of a logical data set of simple data maps in a regular, fixedlength, and sequential organization representing facts about the set of entities called THINGS. FIG. 1 0

another data set. One reason why we might want to do this is to group the most frequently used stored records. Another way in which the matrix could be mapped into storage is to partition it vertically, placing some attribute values in one data set and the remaining attribute values in another data set. One reason why we might want to do this is to optimize a particular batch application that requires only some of the attribute values. These arrangements of our data do not change the data maps. Since our data is not self-describing, i.e., does not contain attribute names and data-type descriptors, it is necessary that the values of the different attributes are arranged in the same order in each stored record of the data set. This consideration does not apply to the order of the stored records because the connection between entities and stored records is represented in each stored record by an entity identifier. It follows that if the matrix is partitioned vertically into two or more data sets, then the entity identifier should appear in all data sets.

22

R. W. Engles

2.4. DATA-SET ORGANIZATIONS

How should the stored records of a data set be ordered? One of the problems of data organization is that many different sequences may be required at the same time, but only one physical sequence is possible; i.e., only one sequence which can be implicit in the contiguous placement of records in secondary storage. If the same stored records must be ordered in different ways, then all but one sequence must be logical. To simplify storage allocation, all sequences could be logical, but the efficiencies that accrue from taking advantage of contiguity cannot be ignored. Consider, for example, a series of references to stored records in the same block as opposed to stored records in different cylinders. While compromises will have to be made between physical sequencing and the requirements of storage allocation, even the smallest amounts of contiguous storage can be significant to performance. We assume the existence of a storage management facility that permits us to think of the data set as a contiguous unit even though it may have many extents, and we will examine the problem of record insertion later. The question now is: to what purpose do we put the one possible physical sequencing? There are many different criteria, both internal and external to the data, by which stored records can be physically sequenced. For example, the ordering could be used to represent data maps, to indicate a time sequence, or to facilitate random retrieval through key transformation techniques. The most common method of ordering stored records is to use the collating sequence of the values of one of the attributes, particularly the identity attribute. When stored records are positioned relative to each other according to some specified sort sequence, the data is said to be sequentially organized. A regular, sequential organization is the classical method for batch processing. This includes data sets composed of stored records of different types and lengths. The organization is particularly appropriate to the use of sequential-access devices. The traditional technique of passing such data against a batch of similarly ordered transaction records and producing a new data set provides for efficient search, a back-up copy for recovery, and retention of the physical sequential organization despite the insertion and deletion of stored records. The regular, sequential organization is also applicable to the use of direct-access devices, particularly when one of the applications using the data is best done in the batch mode. However, the data set need not be copied each time it is changed, and most online applications need something better than sequential search. One solution is to have a directory of the stored records. Such a

A Tutorial on Data-Base Organization

23

directory is usually called an "index". Later we will see that some indexes are data maps. The index we are discussing now is called a "primary index" and it is not a data map. It is a map which relates entity identifiers to the storage locations of their stored records. If the stored records are in sequence by the collating value of their entity identifiers, the primary index need not contain an entry for each stored record; it can have one entry for some group of stored records. The index is itself ordered by the entity identifiers. Therefore, given any entity identifier, we can use the index to determine the location of the group containing the stored record. The stored record can then be located by means of a short sequential scan. The problem we have now is that of searching the index. The solution is the same. We build an index to the index. For large data sets the process can be repeated until we have a level of index which is small enough to be efficiently scanned. This organization of data is called "indexed sequential". An illustration of the index structure is given in Fig. 1 1 . Index sequential is a general form of data set organization. Some of the various methods of implementation are described in ref. [5]. The main differences have to do with the way new stored records are inserted and the index is updated. As implemented in current IBM software, the lowest level of the index contains a pair of entries for each track. The first entry of the pair contains the key of the highest stored record or block on the track, and the second entry contains the highest key of any stored records that have overflowed the track as a result of additions to the data set. Overflow records from a track are chained together in collating sequence and insertions of stored data records are handled without causing insertions to the index. The structure of the index reflects the geometry of the direct access device and each part of the lowest level of the index is in the same cylinder as the tracks to which it points. Each cylinder has an overflow area or one area is allocated for the entire data set. The index sequential organization is efficient for either sequential or direct access on entity identifiers. In regard to direct access, retrieval is said to be accomplished by the "table method", as opposed to the "hashing method". The latter is associated with the so-called random organization. With this technique, stored records are physically sequenced on the basis of a predictable relationship between the key of a record and its location in secondary storage. Hashing refers to the key transformation algorithm that is used to derive this relationship. Many techniques are known. At the one extreme, the key is used directly as an address; at the other extreme, the key is subject to a complex series of operations in order to produce an appropriate address. A general technique is to divide the key by the number of available address in the data space and add the remainder to the base

24

R. W. Engles Level 1 ( 1 t a b l e , 10 e n t r i e s ) Master Index DASD

R e c o r d key

( cyl

Address group)

1

00124

0 0 - 1 9

2

00862

20

3

01739

4 0 - 5 9

4

04980

6 0 - 7 9

( 10 t a b l e s , 2 0 e n t r i e s e a c h )

- 3 9

1

1 C y l i n d e r in dtx R e c o r d key

DASD

Address

( cylinder)

5

12651

8 0 - 9 9

6

28116

100-119

12913

100

?

40575

120-139

13877

101

8

51347

140-159

15126

102

3

9

59493

160-179

16389

103

4

180-199

17640

104

5

18054

105

6

18216

106

7

18760

107

8

18933

108

9

199 2 7

109

10 1 1

10

64208 R e a d sixth table in l e v e l 2 (cylinders 100-119)

index

Level 3 ( 2 0 0 tables, 1 0 e n t r i e s each)

1 Track R e c o r d key

I

ndex D A S D Address (track)

1 2

20173

n o

21309

III

12

21984

112

13

22772

113

14

23559

114

15

16434

1

24396

115

16

2

16562

2

25743

116

17

3

16822

3

26329

117

18

4

16995

4

27945

118

19

5

17236

5

28116

119

20

6

17387

6

7

17444

7

8

17500

8

9

17621

9

10

17640

10

1

R e a d s e c o n d t r a c k of c y l i n d e r 1 0 4 and s e a r c h forrecord 16518 A s s u m e 10 t r a c k s p e r c y l i n d e r

j

Generalized index system for DASD

©

R e a d f i f t h t a b l e in level 3 i n d e x ( c y l i n d e r

104)

To locate a record (example, 16518) I. Scan through master index until the index record key is equal to or higher than the desired item 2 Scan through the cylinder index indicated from the selected master index entry until the index record key is equal to or higher than the desired item 3 Perform a similar scan through the track index indicated by the cylinder index 4. Read the indicated track, and search the track for the desired item

FIG. 11

address of the data space. By providing a mapping from relative block numbers to physical addresses, the Basic Direct Access Method of current IBM software allows the use of such techniques without making the data set dependent on specific physical locations. Unique key transformations are limited to special key sets. For typical key sets such as man-numbers, part-numbers, etc., there are usually many unevenly-distributed unused values within the total range of values. Therefore, transformations on such key sets will not always yield unique addresses. Stored records whose keys transform

A Tutorial on Data-Base Organization

25

to the same address are called synonyms. A random organization will either have much unused storage or many groups of synonyms. Synonyms within a group can be chained together in an overflow area and resolved by sequential search. Random organization is a general technique that can be implemented in many ways. The main differences have to do with the method of handling synonyms. It is a critical problem which is usually compounded by the addition of new stored records to the data set. A good discussion of key transformation techniques and methods of handling synonyms will be found in ref. [6]. In the context of a regular data organization, we have identified three data set organizations: sequential, index sequential, and random. A fourth form is possible and we will call it "index random". In an index random organization, the stored records are unordered with respect to the primary index. Higher levels of the index can be identical to index sequential. The lowest level must contain an entry for each stored record. At the cost of this additional storage, the organization offers more flexibility than index sequential. The entity record set can be partitioned in various ways and physical sequence used for some other purpose. Like index sequential, the various methods of implementation differ mainly in the way new stored records are handled and the index is updated. Unlike index sequential, the index itself is a data set since it may point to more than one data set. 2.5. DATA REQUESTS

Having identified the different types of data maps and the different types of data-set organizations, we can now examine the question of data-bank design for on-line inquiry and update. We will do this from the viewpoint of data-base management, not from the viewpoint of a user at a terminal. The distinction is important. A data structure suitable for display is not usually the same as a data structure suitable for storage. Any complex structure can be reduced to a simpler structure by a replication of its elements. This is a good principle to apply to the display of data and a bad principle to apply to the storage of data. As Raver [7] points out, in data-base systems, data occurs on three distinct levels: external, internal logical, and internal physical. We have called the internal logical level the file organization, and the internal physical level the data organization. The external level is not within the scope of this tutorial. Another reason for making the distinction between data-base management and terminal users is that what might appear to be simple inquiry to the user can be a complex request from the viewpoint of data-base management, and vice versa. For example, a complex

26

Κ W. Engles

inquiry such as "Count the Employees who are Exempt, but Not Managers" might translate into a simple request for data-base management because that particular total is maintained as stored data. Furthermore, we shall make distinctions that should only be of interest to data-base management. For example, we will define a type of inquiry called attribute request and insist that the attribute be single-valued (i.e., no complex data maps) and that the attribute values must be stored data; i.e., no implied functions. These restrictions are relevant to data-base management and (should be) irrelevant to a terminal user. Consider that we have a data set in one of the regular data organizations that allows efficient direct access to stored records. To be more specific, let's say that we have the matrix of Fig. 10 as an index sequential data set where each row of the matrix is a stored record occupying 100 bytes, and we have about 300,000 stored records. How suitable is this organization for on-line inquiry with human response-time requirements? The answer depends on the type of inquiry and many factors other than data organization. We ignore terminal management, task scheduling, and language interpretation, and assume the data is in a disk pack that is on-line to a large System/360. No inherent problem appears with inquiries such as: "In regard to THINGS, what is the COLOR of 12345?" In general, if the inquiry presents a legal entity-set-name, entity-identifier, and attribute-name, we should be able to return the requested attribute value within a second. Moreover, the inquiry could request many attributes of the same entity. However, the attributes must be single-valued (i.e., no complex data maps) and the attribute values must be stored data (i.e., no implied functions). This type of inquiry will be called an attribute request. It includes the possibility of requests for attributes of many entities provided all entity identifiers are given explicitly; e.g., "What is the NAME, CLASS, and STATUS of 11549, 12003, 12237, and 12677?" While this introduces more accesses, the output need not be held back until all searches are complete. Even with the resource-contention problems of a multiprogramming environment and the possibility of searching through chains of overflow records, we have a high degree of certainty that the response to an attribute request will be received within a few seconds. Now consider a request such as: "List the THINGS whose COLOR = Red." With our presumed organization, we have no choice but to examine every stored record of the data set. This will take at least a few minutes. Under certain conditions, it could take as long as an hour. The initial response-time and the delay between outputs will depend on the number and distribution of "Red thing"

A Tutorial on Data-Base Organization

27

records. If very few "Red things" exist, the inquiry is a reasonable on-line request, but the response-time will not be satisfactory. In general, the data organization is not suitable for this type of request. We will call this type of inquiry a classification request. It is characterized by the presentation of an entity-set-name, an attribute-name, a comparison operator, and a value. The response to the request is a list of the unique identifiers of those entities with the specified property. The number of identifiers in the list can range from none to the total number of entities in the set. For the purpose of establishing a taxonomy of requests, we restrict the classification request to comparison on a single attribute, but allow comparisons such as not equals, greater than, less than, and combinations thereof. In addition to being valid types of requests in their own right, attribute requests and classification requests are important as components of more complicated types of requests. For example, the inquiry: "What is the NAME and STATUS of THINGS whose CLASS is Alpha?" is a classification and attribute request. A compound classification request involves comparisons on two or more attributes. The conditions are usually combined through boolean operators such as AND and OR, for example: "List the THINGS whose COLOR is Blue AND CLASS is Alpha." A compound classification and attribute request is an inquiry for properties of entities with certain specified properties. For example: "What is the T H I N G # , NAME, and CLASS of THINGS whose STATUS is In AND COLOR is Green OR DATE IS GREATER THAN 123140?" Further types of requests are defined by allowing a function in combination with any of the above types of requests. Examples of functions are SORT, COUNT, SUM, AVERAGE, etc. An example of a classification and function request is "COUNT the THINGS whose STATUS is Out." An example of a compound classification, attribute, and function request is: "What is the NAME and DATE of THINGS whose CLASS is Beta AND STATUS is In; SORT ascending on NAME." Requests that include such a function are particularly troublesome in regard to response time because all the values must be collected before the function can be applied. It is therefore not possible to overlap output and search, and the need to allocate storage for work space can lead to additional I/O delays. Similar comments apply to compound classification requests. In general, the problem is not solved by data organization. From the above discussion of request types, it is evident that a basic aspect of response-time is the efficiency of handling a classification request. This is a problem that can be solved by data organization. The solution is the other major type of data organi-

28

R. W. Engles

zation, commonly called the "inverted file". An inverted organization is a collection of data maps in an inverted form. Such maps are usually complex; i.e., each attribute value will be associated with many entities. Complex data maps can be represented in many ways to facilitate either search or maintenance. One method is shown in Fig. 12 which is the entity record set of Fig. 10 in an inverted organization. Any data map can be derived from its inverse. Representing maps in the form V->E, rather than in the form E->V, facilitates the handling of classification requests, but does not change the information content. In terms of our original concept of data organization, an inverted organization may be viewed as the storing of data by columns rather than by rows. In a regular organization values of the identity attribute are not replicated; other attribute values are replicated. In an inverted organization values of the identity attribute are replicated and other attribute values are not replicated. All symbols in Fig. 12 are stored data and the arrows represent stored pointers such as relative addresses of the form block number-byte displacement. The semicolons are list delimiters. The lists of entity identifiers are separated from the lists of attribute values in order to facilitate search of the attribute value lists. Given a request such as "List the THINGS whose CLASS is Beta", we can find "CLASS" in the list of attribute names and use the pointer to get the list of its attribute values. Finding 'Beta' in the list of attribute values we can use the pointer to get its entity-identifier list which is then scanned to the delimiter yielding the THING identifiers 11549, 12116, and 12563. An inverted data organization is reminiscent of various manual retrieval systems such as the punched card "peekaboo" method. Manual systems severely limit the number of entities and limit attributes to boolean values; i.e., an entity either has an attribute or it doesn't. Nevertheless, the cards of such manual systems represent data maps of the form V->E, and one computer method of representing certain data maps and handling compound classification requests is conceptually equivalent to these manual methods. For attributes that are boolean, such as male or female, exempt or nonexempt, etc., the inverted data map is represented by an ordered bit string with one bit assigned to each entity so that, for example, if the bit is on, the corresponding entity is male, otherwise, female. Compound classification requests involving such data maps can then be handled by AND'ing or OR'ing the bit strings. Compound classification requests involving attributes that are not boolean must be handled by a procedure that compares lists of entity identifiers. Regardless of the particular method, the inverted data organization is clearly suitable for classification requests.

A Tutorial on Data-Base Organization Things

in an inverted data organization:

Class -

Alpha

Color •

Beta

Date

Gamma

-

Name Status

-

-11648

11985,



-11549

121 16

-12003

12345;

- 12237

12677;

Delta — ••Black Blue

-

Red

• I 1648

-

• 12116;



• 11549

12003;

-

- 11985

12345;

White

12677;

- 12563,

Yellow

- 11549 042939-

12345;

- 12116 ,

1140 -

- 12563,

033045 -

- 12677,

101547-

- I

081148-

- 12237-,

081352-

- I

012853-

- 12003,

- Bob

- I

1985; 1648; 1985;

Irv

- 12677,

Jιm

- 12116

12563;

Joe

- 11549

12237;

Max

- 12345,

Ray

- 12003;

Sam

- 11648

-In Out

12563;

- 12237;



Green

I I

29

•11985

12116

12237

12345 12677',

-11549

11648

12003

12563;

FIG. 12.

With our data in an inverted organization, we cannot expect good response time to attribute requests or any type of request that includes an attribute request. With current technology the only general solution to the problem of getting fast response to both attribute requests and classification requests is to have the data in both a regular organization and an inverted organization. Of course, this duplication of data will require at least twice as much storage and complicate the update problem. Very few systems maintain data in both a regular organization and an inverted organization. The usual compromise is to have inverted data maps only for selected attributes. Such maps are often called "secondary indexes". We will return to the subject of secondary indexes after we examine data organizations that include structural data maps. 3. Data Banks 3.1. COMPLEX AND STRUCTURAL DATA MAPS

Data banks must be designed to facilitate both retrieval and update. Trade-offs are necessary because these two design goals tend

30

R. W. Engles

to be conflicting. For example, pointers introduced to facilitate maintenance can have a deleterious effect on search and vice versa. One aspect of the update problem is the maintenance of complex data maps. Using THINGS as an example, consider the simple data maps of the regular organization as opposed to the complex maps of the inverted organization. A change, such as the Status of a THING changing from Out to In, can be handled by a simple replacement of a value. In the inverted organization, the same change requires the deletion of an entity identifier from one list and its addition in another list. Any type of update causes these lists to grow or shrink. Thus, in order to allow on-line update of the inverted data organization shown in Fig. 12, some form of chaining would have to be included in the entity-identifier lists. The problem is not peculiar to an inverted organization; it is a problem of complex data maps. Maps of the form E->V can be complex, and if their inverse is also complex, the problem can exist regardless of whether the organization is regular or inverted. Three methods of representing complex data maps are shown in Fig. 13. Many other representations are possible in which pointers are used to achieve some trade-off* between maintenance and search. What is the best representation? The question is meaningless unless the system context is specified; i.e., how is the data to be used, what type of storage devices and storage allocation methods are involved, how is the data map related to other data maps, what is the pattern and frequency of change, can update be restricted to the batch mode, etc.? Even when the system context is specified, evaluation is difficult because the efficiency of a representation is dependent on the particular data map. In a complex data map each argument value is associated with η function values. Using some trade-off between efficient use of storage and simplicity of storage mapping as a criterion, the best representation can depend on the range of «. If « is a constant, the data map is best represented as η simple maps. (This might also be the best approach if the range of η is known to be small. On the other hand, η can be the same for all argument values, but subject to change; e.g., it will increase by one every week.) If η is a variable, but the total number of function values in the data map is small, the connection matrix is an efficient representation. If the total number of function values is large, but the value of η is usually small, value pairs might be the best representation. For many data maps the variable list representation would seem to be the best choice because of the efficient use of storage. In considering the representation of complex data maps, it is necessary to distinguish the different types of maps. In the previous section of this tutorial, twelve types of data maps were defined, but

A Tutorial on Data-Base Organization Argument -

31

Function

The data map :

Connection matrix :

I A

I

I

Ο

Ο

Β

J

Ο

Ο

Ο

C

O

D

Value pairs:

V a r i a b l e lists:

Ο

A

I

A

2

Β

I

C

2

C

3

C

4

D

3

D

4

I

I Ο

I I

I

A 12 j Β I i C 2 3 4 ;

D 3 4 ;

FIG. 13. Three methods of representing a complex data map without pointers. data organization was viewed only in terms of nonstructural maps. In this section we consider the two types of structural maps. These data maps are often complex, but not necessarily of the type whose inverse is also complex. Regardless of their complexity, maps of the form E->E' lead us to the important notion of related data maps. Consider the map Α-κΒ, where A and Β are different entity sets. Since Β represents a set of entities, at least one map exists in which the entity identifiers of Β are argument values; e.g., we also have the map B->C. The maps Α-κΒ and B->C are related data maps and implicit in their relationship is the additional data map A->C. An important aspect of data-base management is the many ways in which data maps can be related. The values in one map can be a function of values in other maps, one map can be the inverse of another, different maps can have the same set of identifiers as argument values or the same set of identifiers as function values,

32

R. W. Engles

and maps can be indirectly related in a myriad of ways. Our immediate objective is to examine how different data organizations represent the relationships among different entity sets. For now we ignore those complex maps whose inverse is also complex and further restrict our attention to ordered structural relations; i.e., related maps such as A->B, B->C, C->D. In other words, we consider relationships that are not more complicated than a tree structure. 3.2. HIERARCHICAL ORGANIZATIONS

A popular method of representing tree structures is the contiguous hierarchical data organization. The organization is based on the fact that it is possible to represent a tree structure in a linear storage without the use of pointers. The relations among the different entity sets are represented by means of storage mapping and delimiters as illustrated in Fig. 14. The diagram shows the elements of data maps associated with one entity of A. Each node of the tree designates a collection of data items representing facts about one entity. The nodes are numbered to indicate the sequence in which the data is stored. Parentheses are used as delimiters in the example in order to further illustrate the principle. In practice, a two-part numeric code might be used to specify the type and

A ( B l ( C l , C 2 . C 3 ) B 2 ( C 4 , C 5 ) B3)

FIG. 14. Linear representation of a tree structure.

A Tutorial on Data-Base Organization

33

number of subordinate nodes. A type code, as opposed to a simple level indicator, is necessary to allow different kinds of nodes at each level; i.e., more than one complex data map per entity set. Implementations of the hierarchical organization often provide only some subset of its tree structuring capability. GIS [8], for example, offers three types of limited hierarchical organization: a single level of subordination; multiple levels of subordination, but only one entity type at each level; and multiple levels of subordination with different entity types at a level, but only at the lowest level. IMS, on the other hand, offers a full hierarchical structure; i.e., multiple levels with different entity types at the same level—at any level of subordination. The hierarchical data organization has venerable origins in card and tape-oriented applications design. The organization has often been extolled as a method of saving storage space, the assumption being that the alternative is to replicate all nodes in the path to the root of the tree for each occurrence of a terminal node. Thus, the alternative to the representation shown in Fig. 14 is as follows: Al Al Al Al Al Al

Bl Bl Bl B2 B2 B3

CI C2 C3 C4 C5 0

The above representation has in fact been used to give data the appearance of a simple file. Clearly, the method wastes storage and complicates update. By the same reasoning, the hierarchical organization is not suitable when the relations among entity sets are more complicated than a tree structure. Consider, for example, that in addition to the data map A->B, we also have the map D->B. With a hierarchical organization there would be a replication of the data pertaining to the entities of Β that are related to the entities of both A and D. The same comments apply to the representation of a single complex map of the type whose inverse is also complex. In the terminology associated with hierarchical organization, a . . data base record is a collection (a variable number) of hierarchically related, fixed-length data elements, called segments. A root segment is the highest hierarchical segment in the data base record. A dependent segment is a segment that relies on at least the root segment for its full hierarchical meaning. It is therefore always at a lower hierarchical level than the root segment" [2]. In our view, dependent segments are usually records associated with related entity sets. We cannot say that each different segment type is a different entity set because this is not true in two situations : 4—AP

*

*

34

R. W. Engles

1. When different segments are defined at the same level in order to group data maps associated with the same entity set (as may be done in IMS for the purposes of data independence, i.e., "segment independence"). 2. When a dependent segment is defined only to represent a complex data map (in which case the segment is a single "repeating data item"). However, hierarchical organizations are characterized by repeating groups of data items and it is these "repeating groups" that are other entity sets; i.e., when a dependent segment is a group of data items which has a variable number of occurrences for each occurrence of the parent segment, the two segments are collections of data associated with two different entity sets related by a complex data map. The reason for making this point is that when different entity sets are involved, it is possible that some application program will want to retrieve and update the segments independently of their hierarchical relationship. On-line update and access to segments other than through the root segment is facilitated by the noncontiguous hierarchical organization illustrated in Fig. 15. Let us say that in Fig. 15, A is departments, Β is employees, and C is children of employees; i.e., the rectangle labeled Al is a stored record containing information about department Al, the rectangle labeled B2 is a stored record containing information about an employee in department Al, the rectangle labeled C3 is a stored record containing information about a child of employee Bl, etc. With a noncontiguous hierarchical organization, simple facts about employees can be accessed without reading and scanning over the department and children information. More important, employee information can be accessed through employee man-number, rather than through department code. Of course, this means that entities must have unique identifiers, i.e., the scope of uniqueness is the entity set, not the hierarchical context. Also, since one of the facts we may want about employees is their department code, this would now have to be stored in each employee record. For efficient direct access or efficient sequential access in other than department sequence, the employee records would have to be indexed, and the index would have to be of the type that points to every record. Viewing the employee data independently of its hierarchical relationships with other data, it is an index random data set of fixed-length records. Obviously, the contiguous and noncontiguous hierarchical arrangements can be combined. For example, the department and employee data could be noncontiguous, while the employee and children data is contiguous. The resulting data set of information about employees

35

A Tutorial on Data-Base Organization Contiguous hierarchical data organization AI

Bl

CI

A2

B4

C6

C2 B5

C3 C7

B2 C8

C4

C5

B3

C9

FIG. 15.

and their children, like any contiguous hierarchical organization, would then have variable-length records. IMS provides a noncontiguous hierarchical data organization at one level of subordination, but access is logically through the root segment in that the key must include the root segment identifier to ensure uniqueness. 3 . 3 . DATA-BANK ORGANIZATIONS

A general-purpose data organization must be capable of representing a network of relationships; i.e., relationships that are more complex than a tree structure. In terms of our last example, consider that we also have a set of entities which are jobs, and that we are interested in the relationship between jobs and employees. We now have the complex data maps Department->Employees and Jobs^Employees, and therefore the total relationships are no longer as simple as a tree structure. With this example and the noncon-

36

i?. W. Engles

tiguous hierarchical organization as a starting point, we can quickly develop the concepts of a few of the many possible organizations which can represent networks. Notice that in the example of the noncontiguous hierarchical organization the physical ordering of employee records was usurped by the hierarchical organization; i.e., the employee records were in order by department code. With "multiple parent segments", this arrangement is no longer appropriate. It would probably be best to use the one possible physical ordering to facilitate independent access. Therefore, let us assume that the employee records are in order by man-number in an index sequential data set. Now, there are two general approaches to the problem of representing the relationships among entity sets. First, we could represent the relationships symbolically as in the three methods of representing a complex data map without pointers. In the second approach the problem is viewed as the logical ordering of the employee records by job and the logical ordering of the employee records by department. For now we follow the second approach which, of course, involves the use of pointers. Two data organizations capable of representing networks are shown in Fig. 16. In the chained list organization, the records of employees with job 1 are linked together, the records of employees with job 2 are linked together, the records of employees in department 1 are linked together, etc. The head of each chained list is the respective job or department record. Moreover, the employee records might be the head of chains of children records and the job or department records might also be members of various chains. In general, any set of records could be the head of many chains and the members of many chains. In principle, the technique can accommodate any degree of complexity. Since the physical ordering of each set of records is independent of the method of representing relationships among sets, the data set organization could be sequential or random and indexed or not. The chaining technique can also be used to sequence records, index data sets, and represent data maps of the form W->E. The particular chaining technique illustrated in Fig. 16 is called a simple list structure. There are other techniques such as bidirectional list structures and unidirectional or bidirectional ring structures. A chained list organization based on ring structures is recommended in the report of the COBOL Data Base Task Group [9]. The following description of ring structures is quoted from that report: "In a ring structure, lists are circular in that the tail of any list leads back to its head rather than containing an indicator to show that it is the last record in the list. "This proves to be very powerful as it provides a facility, where

A Tutorial on Data-Base Organization

37

Departments '

Employees :

Jobs : Variable pointer list organization

FIG. 16.

there are multiple record types which are logically related, to retrieve and process all of the records in any one ring while branching off at any or each of the records to retrieve and process other records which are logically related. Such records would also be stored in a ring structure and in turn permit the same facility; this nesting is carried through to any level required by the logical relationships in the data. "Thus, all information which is logically related regardless of its complexity or of the hierarchical or network nature of the data may be chained together to form a kind of route map which has many possible points of entry and through which many differing paths are available. At the same time this form of structure can equally well describe a simple file. Each ring or circular chain has a point of entry or header record and any number of detail records which may themselves be the heads of other rings and so on. Pointers are used for progression around rings and by the inclusion of more than one pointer forward or backward tracing, or direct return to the head of the list is possible."

38

R. W. Engles

The power and flexibility of a chained list organization is offset by certain disadvantages in recovery and search. The recovery problem is simply that a chain is as strong as its weakest link. If a pointer is lost, so is the rest of the chain. The search problem is simply that it can be a time-consuming operation to follow a chained list on a typical direct access storage device. These are the reasons for bidirectional chains and for storing the chain value or a pointer to the head of the chain in each record. Search time with a chained list organization can vary widely because of the general unpredictability of the physical placement of related records. At the one extreme, all the records in a particular chain may be stored in the same block. At the other extreme, each record of the chain is in a different block. (And the blocks are in different cylinders of a disk in the worst possible seek sequence.) With a chained list organization it is not possible to optimize the sequence of I/O operations because record η must be retrieved in order to determine the address of record η + 1. If the techniques to handle the problem are carried to their logical conclusion, the result is a different organization: the variable pointer list organization is shown in Fig. 16. One of the advantages of ring structures is that a ring represents a data map and its inverse with a minimum of storage and maintenance. From a department record we can follow the chain to find the employee records for that department, and from an employee record we can find the department record for that employee. With a variable pointer list organization the inverse relationship must be represented separately. However, this is a distinct advantage when the complex map is of the type whose inverse is also complex. Unfortunately, a rather basic problem is associated with a variable pointer list organization: maintenance is a nightmare. In order to update, pointer lists must be capable of expansion and contraction, but data set reorganization is practically precluded because of its effect on all the pointers to the data set. Rather than introduce more pointers to facilitate maintenance, let us investigate the symbolic approach to the representation of relationships among entity sets. Indeed, all we have to do to achieve a more reasonable trade-off between retrieval and update is to replace the pointers with symbols. Thus, each department record would include the man-numbers of its respective employees and each job record would include the mannumber of employees with that job. Starting from a department record, we can find information about the employees of that department by taking each man-number found in the department record and using it as a key to the index or whatever search mechanism exists for direct access to the employee records. This is the data organization proposed by Raver [7]. In the data organizations discussed above, simple and complex

A Tutorial on Data-Base Organization

Departments Dept*

Name

. . »

39

Jobs Job^ Name

FIG. 17. A regular organization with secondary indexes used to represent all complex data maps. maps have been combined in one physical structure. Another approach to data-bank design is based on the separation of simple and complex data maps. Complex maps are represented as separate secondary indexes to a regular data organization of fixed-length records. This type of organization is illustrated in Fig. 17. Since the use of pointers in the secondary indexes is subject to the same maintenance problems mentioned above, it would probably be better to use symbols instead. Therefore, consider that the arrows in Fig. 17 are replaced by the man-numbers to which they point. This is the organization proposed by my colleague, C. T. Davies, Jr. 3.4. PRINCIPLES OF ENTITY-SET ORGANIZATIONS

The organizations proposed by Raver, Davies, and others involve the same basic principles. The first principle is that a data bank represents a network of relationships among entity sets. The second

40

R. W. Engles

principle is that data banks change. New entity sets and/or additional relationships will have to be represented. The organization should facilitate these changes. Experience has shown that later stages of data banks are characterized by more complex relationships than earlier stages. This is why a data bank should always be considered a network, even though the relationships may, in fact, be simpler when the data is first generated or integrated. This type of generality requires that, in the beginning, the data associated with the different entity sets be clearly identified as distinct nodes of the network. The implications for the naming and storing of data are as follows: Entity identifiers should be unique within an entity set and entity-set names should be unique within a data bank. The data associated with different entity sets should be stored in separate data sets and relationships among entity sets represented by methods that facilitate change. One of the problems of "entity-set organizations" is that it is not always obvious what the entity sets are. For example, Davies suggests that whenever we have a complex data map of the type whose inverse is also complex, this type of relationship defines another entity set; i.e., the "objects" about which we may want to record facts are themselves relationships between other sets of objects. It follows that these other sets of objects could, in turn, be relationships, etc. Eventually, of course, each relationship can be traced to sets of "primitive objects"; i.e., objects that are not relationships. It is not necessary to get involved in such complexity in this tutorial. It is necessary to examine those complex maps whose inverse is also complex. Of particular interest are such maps of the form E->E. An example is a data map which specifies the relationships among the parts, assemblies, and subassemblies which make up a product. (Parts, assemblies, and subassemblies are viewed as the same kinds of objects.) In a paper entitled "The Organization of Structured Files" [12], Dzubak and Warburton present a variety of techniques for representing and tracing through such complex data maps. The following is quoted from that paper; the figures referenced in the quotation are shown in Fig. 18 of this report. ". . . Figure 1 represents the relationships between the assemblies, subassemblies and detail parts making up products A and C. A bill of material (B/M) describes the parts and the quantity of those parts comprising an assembly. The bill of material for part number D contains part numbers 1, Β, E, and their associated quantities 2, 3, and 1. The quantity '2' is just a condensed way of saying that there are two part number *1V necessary to build assembly D, or that there are two connections between assembly D and detail part 1. The term explosion refers to the process of tracing through a graph and producing a total B/M for a given part. For example, the

A Tutorial on Data-Base Organization

I

Fi le in Β / M order

2

41

Tree f o r m e d by explosion of part A

3 . File in W / U order

Graphs f r o m

[l2]

FIG. 18.

explosion of product A produces the list of parts shown in Fig. 2. In order to purchase the necessary parts, we would like to know how many of each part will be required to build product A. This process is termed total requirements generation. "The term level refers to some arbitrary grouping of parts. It usually is defined by some topological relationship between parts or by the data processing method. If we let part A of Fig. 2 be at level 0, then part D is at level 1. It is possible for the same part to appear on more than one level. The phrase level by level requirements refers to the component of total requirements necessary to build a particular level of a product. For example, two part B's and two part D's are necessary to build level 1 of product A. "The representation shown in Fig. 3 is said to be in where-used (W/U) order and shows every assembly on which a given part is

42

R. W. Engles

used. For example, subassembly Ε is used to build assembly D and product C. Implosion refers to the process of tracing through a W/U file producing a set of information as shown in Fig. 4." In Figs. 18-1 and 18-2, a complex data map of the form E->E is pictured by means of a structural diagram known in graph theory as a directed graph. Note that the W/U order is the inverse map of the B/M order. Figure 18-2 is the same information as a subset of Fig. 18-1, but the network has been reduced to a tree by replication of the common nodes. This "structure reduction/data explosion" is accomplished by a procedure which traces through the network. One of the requirements of a data organization is that it should facilitate such traces. Furthermore, if a data-management system claims to have "structural data independence" (i.e., complete separation of file organization and data organization) then these traces must be performed by the system. In regard to the product structure example, what are the entities? If we say that the entities are the parts and assemblies, then what do we do with the quantity attribute; i.e., the number of occurrences of a part in a particular assembly? Clearly, this quantity is not an attribute of a part, but rather an attribute of a relationship between a part and an assembly. Since we have defined an entity as that which we record facts about, it follows that the entities are these relationships. Using the word "part" to refer to any level of assembly, the entities are pairs of connected parts. This set of entities is distinct from the set of single parts. In other words, there are two entity sets, call them PARTS AND PAIRS. Associated with the set of PARTS are attributes such as Description, Quantity-on-hand, etc., and the entity identifiers are part-numbers. Associated with the set of PAIRS is the Quantity attribute. Unique identifiers could be assigned to each pair, but the same effect is achieved by using part-number pairs as entity identifiers. One method of representing the information about PAIRS is as follows: Quantity Pair # 2 A Β 2 A D Β 1 Β 2 C Ε C 4 2 D Β 3 D Ε Ί D 1 Ε 2 2 Ε 3

A Tutorial on Data-Base Organization

43

With the above representation, the information about PAIRS looks like any other information in a regular data organization with fixedlength records. The records of the data set are in B/M order. By treating the second part of each Pair# as a distinct attribute and building a secondary index on its values, a W/U ordering is represented. The representation shown above is suggested by Davies and the PAIRS entity set is an example of his contention that whenever there is a complex map whose inverse is also complex, the relationship defines another entity set. Another example is Part #->Warehoused An attribute of the relationship is Quantity-on-hand, i.e., the quantity-onhand of a part in a particular warehouse. Data organization based on this contention is characterized by many, simple data sets as opposed to fewer, more complex data sets. In the next section of this tutorial, the concept will also be applied to file organization. As a product structure is a network of relationships among parts, a data-bank structure is a network of relationships among entity sets. As product control requires B/M and W/U files, data-bank control requires similar information about data relationships. This is the key idea in Raver's "File Organization in Management Information and Control Systems" [7]. Using a "threading matrix" to represent the relations among entity sets, he has defined algorithms for finding all the related data maps in a given data bank. This capability is viewed as a system tool for determining optimum data organization and as a part of the mechanism for providing data independence to problem programs through the evolving stages of a data bank. 3.5. A N ILLUSTRATIVE SYSTEM

At the end of the previous section of this tutorial, we stated that both a regular organization and an inverted organization of the same data were required to ensure good response time for both attribute requests and classification requests. Implicit in the statement was the assumption that requests were unpredictable and therefore the data could not be organized for specific, anticipated uses. A system based on this assumption is the SDC Time-Shared Data Management System (TDMS). TDMS is an operational system which is unique in its ability to provide good response time to nontrivial requests from nonprogrammer users. By "good response time" we mean that ". . . even with 25 users in a time-shared environment, the answer to most queries will begin to appear within 5 seconds of the completion of the question" [14]. By "nontrivial requests" we mean that, in addition to the various types of requests described in the previous section of this tutorial, TDMS provides " . . . a hierarchical data handling capability" in which

44

R. W. Engles C

D

Ε

TDMS data o r g a n i z a t i o n

FIG. 19.

". . . the user can differentiate between levels and/or the scope of retrieval" [15]. A TDMS data bank is diagrammed in Fig. 19. It is a very complex organization. However, when all the pointers have been cleared away, we find a regular and an inverted hierarchical organization of the same data. The hierarchical aspect of the organization differs from the conventional representation of tree structure. It is designed to handle the "hierarchical retrieval problem"; i.e., requests such as: PRINT DEPARTMENT BUDGET WHERE EMPLOYEE HAS JOB TITLE EQ PROGRAMMER. The problem is that the attribute request and the classification request refer to different levels of the hierarchy; i.e., different entity sets or repeating groups. The TDMS data organization can be explained as follows: A data bank is a dual representation of one hierarchical file. Each logical record of a hierarchical file is a tree structure and each node of the tree is the contents of a field. Each node of each tree of the file is uniquely identified by a node number. In Fig. 19, the inverted part of the organization includes the tables labelled A, B, and C. A is called the dictionary, Β and C are called the concordance. For each attribute, the dictionary contains such information as the attribute name, an internal attribute number, a repeating group identifier, a data element descriptor, and a pointer to the attribute value list. Long attribute value lists are indexed; i.e., a block directory appears between the dictionary and any value list which occupies multiple blocks of secondary storage. An

A Tutorial on Data-Base Organization

45

attribute value list is an ordered set of values. Associated with each value is a pointer to a list of node numbers which specify the occurrences of that value in the hierarchical file. A node number list is an ordered list in which the first word specifies the number of entries. This count of occurrences is useful in minimizing the number of comparisons involved in compound classification requests. Node numbers are used as pointers to table D. If an attribute value occurs only once, the node number appears in the value list; i.e., the value list points directly to table D. Tables D, E, and F are the "regular" organization. Table Ε is the data except for values that cannot be represented with one word. For these values, which are usually character strings as opposed to numbers, table Ε contains a pointer to table F. Table F is a list of unique, variable-length character strings in the form and order in which they arrived in the data bank. The data in table Ε is self-defining. It contains an attribute number which is used as a pointer back to the dictionary. A group of entries in table Ε is a variable-length logical record of fixed-length data items. The logical records are in the order of arrival. Repeating groups within logical records are in order by hierarchical level and the end of each group is marked. All other structural information is in table D. Tables D and Ε are in parallel; a node number n, used to access the nth entry of table D, is also used to access the corresponding entry in table E. Table D contains repeating group identifiers and two sets of pointers which specify the structural relationships for every node of every logical record. The table is used to resolve the hierarchical retrieval problem and locate the requested data in table E. The TDMS data organization is . . an inverted tree structure with self-defining entries. This organization has made it possible for TDMS to meet its goal of providing rapid responses to unpredictable queries in a time-shared environment. . . . Naturally, to obtain the retrieval speed, one must be willing to pay some penalties. First, the concordance requires as much (if not more) storage as the data itself. . . . A second penalty is that this type of structure is difficult to maintain" [14]. 3.6. INDEXING TECHNIQUES

A TDMS data bank is viewed as an inverted organization plus a regular organization. The more conventional viewpoint of a data bank is that of a regular organization plus secondary indexes. The two approaches become conceptually equivalent if a secondary index exists for every attribute. As a practical matter, however, the two approaches can be significantly different depending on the system context and the characteristics of the secondary indexes. We will now consider data

46

R. W. Engles

organization from the viewpoint of the various types of secondary indexes. Search is the problem. Indexes are a technique for reducing search time, a substitute for sequential scan. It has often been observed that data processing would be a cinch if we could store all our data in associative memories. Lacking such devices, we use indexes or other search techniques. If the same data is to be searched on different attributes, then the only general substitute for secondary indexes is sequential scan because other search techniques such as binary search and hashing are dependent on physical ordering of the data. However, when we build an index, we then have the problem of searching the index. This is where other search techniques may come into play, as opposed to the technique of indexing the index, etc. Indeed, short scans are usually part of any search technique. Most key transformations, whether accomplished by hashing or by indexing, are a means of partitioning a data set into subsets small enough to be scanned efficiently. Furthermore, sequential or binary scans are needed to search an index block. Search techniques are analyzed by Salton [1], Iverson [4], Buchholz [6], and Meadows [16]. Secondary indexes include both structural and nonstructural data maps. Simple maps are possible, but as inverted lists, secondary indexes are usually complex maps. Regular organizations with secondary indexes may be classified into two groups depending on the method used to represent the secondary indexes. If a chained list representation is used such that pointers are embedded in the data, we have what is called a "multilist organization". If secondary indexes are represented such that these inverted data maps are separate from the primary data, we have a multiple-index organization. The difference is illustrated in Fig. 20. The multilist organization is a chained list data organization in which the same technique is used to create secondary indexes. Illustrated in Fig. 20 is a single index using a unidirectional ring structure : the entity identifiers are the numbers and the indexed attribute has the values 'A' through Έ \ For the purposes of illustration, the chains are very short; for many data maps, they would be very long. Note that if the index were a structural map, the heads of the chains would be in records associated with another entity set. The particular type of separate secondary index illustrated in Fig. 20 is designed to allow on-line update. It is shown as it might appear after a few changes have been made. For the purposes of illustration, we have only four entries per index block. A symbolic value pair representation is used and the blocks of the index are created and updated by a procedure which handles the complex data map maintenance problem. At the cost of more storage and more complex update, separate secondary indexes usually provide faster search than embedded

A Tutorial on Data-Base Organization

FIG.

47

20.

indexes. The storage costs become similar if compression techniques are applied to the separate index and attribute values are included in the primary data of the multilist organization. An important advantage of separate indexes is their independence. Without affecting the primary data or other indexes, they can be created, moved around, and destroyed as requirements change, and their search time is independent of the number of other indexes in the data bank. A multilist organization, on the other hand, is a physically interdependent arrangement that is not as easily modified and is subject to diminishing returns on search performance as the number of indexes

48

R. W. Engles

increases. (The search problem is that as the number of logical orderings increases, the chances of physical proximity of the related records decreases.) With a multiple-index type of organization, a multitude of choices exist in regard to the design of the separate indexes. The first choice is whether or not to have a secondary index for a given attribute. A basic premise is that secondary indexes should exist only for those attributes that are frequently referenced and require minimum search times. However, even if an attribute meets these criteria, it does not always pay to index its values. The efficiency of a search is measured by its selection ratio: the number of hits over the number of records examined. (More precisely, the number of bytes selected over the number of" bytes passed.) The major purpose of any secondary index is to reduce the number of records to be examined in the regular organization. The larger the selection ratio by sequential scan, the smaller the pay-off in having a secondary index. In general then, the decision to create a secondary index on an attribute should also consider the ratio of the number of different values of the attribute to the number of entities in the set. More specifically, the judgment should be based on the corresponding physical I/O considerations. Obviously, no indexes are necessary if the set is small enough, and a primary index always has a pay-off if the set is large enough. For a large set of personnel records, it will probably not pay to index an attribute such as Sex, while it would pay to index an attribute such as Employeename. Viewing a secondary index as a table of argument values and function values, some of the possibilities are as follows: The argument values could be all the possible values of an attribute, the values in use when the index is created, selected values of the attribute, selected ranges of values of the attribute, boolean combinations of two or more sets of attribute values, etc. The function values could be entity identifiers, absolute addresses, relative block numbers, relative record numbers, bit strings that map into relative record numbers, etc. No one choice or argument type and function type will be best for all possible indexes. The task of secondary index design is a great opportunity for local optimizers. An entity record set can be horizontally partitioned to optimize one secondary index, another secondary index can take advantage of the physical ordering of records in an index random data set, the lowest level of one index can be stored with the data to minimize seek time, and the levels of an index can be arranged around a direct access device to minimize rotational delay. All kinds of optimizations are possible by taking advantage of the anticipated uses and known properties of a given complex data map. Above, we said it would not pay to index an attribute such as Sex. On the other hand, knowing that the vast majority of employees were male, an index of females only could be

A Tutorial on Data-Base Organization

49

worthwhile. (This is not discrimination; it is merely an example of selected attribute values.) In regard to the method of representation used in a secondary index, we have already pointed out that the efficiency of a representation is a function of the particular complex data map. Finally, the search of a secondary index can often be optimized. Certain sets of attribute values, for example, will allow the search to be accomplished by unique key transformations such as simply using the given value as a displacement to a contiguous list of pointers to the function values. With today's hardware, optimization of secondary indexes can be too significant to be ignored. One approach to data-bank design is to formalize the optimizations so that an index generating program can produce various types of indexes which are tailored to the particular data maps. The other approach is to have a generalized index structure which includes data-map-independent optimizations. One generalized approach involves the techniques of multiple index levels and compression of the index entries. Both techniques apply to either primary or secondary indexes. Multi-level indexes (i.e., the technique of indexing the index, etc.) were discussed in the previous section of this tutorial. In the diagram of a multi-level index (Fig. 11), full keys were shown at all levels of the index. Since a key at any level defines a boundary between two keys from the data set, it is not usually necessary to carry all of the characters of either key. It is sufficient, in fact, to carry only characters of one of the keys up to the character position in which the keys differ. Thus, if the last entry of volume one of the encyclopedia is "bazooka", and the first entry of the next volume is "beachhead", the first volume would be marked "A through BA", and the next volume would be marked "BE through . . ." Either "BA" or "BE" is sufficient to denote the boundary, the choice depending on convention. Excluding of such characters from a key entry in an index is called rear compression. Let's say that we have a separate, secondary index on Employeename. In the regular organization the values are character strings which are left-justified and either truncated or padded on the right with blanks such that all the values of Employee-name occupy 20 bytes. In the index, we assume a value pair representation ordered on the employee names, and the use of sequential scan to search an index block. Now consider two adjacent names such as : ENGELHARD,HANSbbbbbb ENGELHARD,LUDWIGbbbb The first ten characters are common to both names, For any two adjacent entries, there are probably many characters which are common to both names. Indeed, with the value pair representation, the names can be exactly the same. Common characters can be factored out; i.e., the leading characters of an entry which are the same as the previous entry,

5—AP

*

*

50

R. W. Engles

can be replaced by a control byte which indicates how many characters have been omitted. Factoring of such characters from a key entry in an index is called front compression. By treating a value pair as a single character string, the factoring can also be applied to the function values. For the two names shown above, the last nine characters are not needed to distinguish between the two entries. For any two adjacent entries, rear compression can be used to eliminate the blanks and any other insignificant characters, i.e., all characters to the right of the character which serves to distinguish an entry from the previous entry. In general, both front and rear compression can be applied to entries at all levels of an index. In our example, the attribute value "ENGELHARD, LUDWIGbbbb" can be compressed to two bytes: a control byte and an "L". Clearly, compression techniques can result in substantial savings in both storage space and search time. 3.7. UPDATE PROBLEMS

We have examined data-bank design with an emphasis on structure and search. We conclude this section of the tutorial with a description of update problems. By update, we mean any additions, changes, or deletions to the information content of a data base. These operations have all the requirements of retrieval plus problems which are unique to the updating process. None of the problems are easily solved without imposing constraints on the use of the data base. Update has always been difficult. On-line update of shared data is very difficult. We have already mentioned the difficulties of maintaining complex data maps and inserting new stored records into data sets. The essential problem is that of storage allocation and addressing. Dynamic allocation of secondary storage space is required to handle on-line update. Dynamic allocation implies the use of pointers and pointers are addresses of objects, rather than names of objects. Whenever a data structure contains pointers, any physical rearrangement of that structure is not a trivial operation. Many techniques are known, all of which involve some penalty in performance and/or storage utilization. If dynamic device allocation is also involved, procedures are needed to avoid excessive fragmentation of the data base. It seems unreasonable to limit storage allocation to volume boundaries, but without some constraints, related data can eventually span so many volumes that all of it cannot be on-line at the same time. In general, unless all data banks are permanently on-line, some form of batch reorganization is inevitable. One of the purposes of data independence is to permit data base reorganization without impacting application programs. Any update operation is a potential hazard to the integrity of the data base. Obviously, the validity of new data should be checked. Not

A Tutorial on Data-Base Organization

51

so obvious is the possibility that incorrect values in the data base can result from concurrent update of the same block of data. Consider, for example, that task A and task B, by coincidence, both get a copy of the same stored record. Task A updates the record and causes it to be written onto secondary storage. Task Β then updates its copy and causes it to be written onto secondary storage. The result is that the change to the stored record made by task A is lost. With logical records the odds are better, but the problem still exists as long as concurrent updating tasks are given copies of the same data. One solution to the "double update problem" is to prohibit multiple copies of the same data in main storage by requiring application programs to request exclusive access to data which is to be updated. Data-base management must then recognize when different tasks are contending for the same data and provide interlocks so that data is handled as a serially-reusable resource. Furthermore, exclusive access to groups of records is required for reasons other than the double update problem. For example, a report-generating task, even though it only retrieves data, must have exclusive use of a file to ensure the consistency of its output. More precisely, the requirement is not necessarily for exclusive use of data, but rather to prevent its concurrent use for update by another task. Given the exclusive ownership of resources, the question then is what to do about deadlock. An example of deadlock is the situation where task A owns resource 1 and is requesting resource 2 while task Β owns resource 2 and is requesting resource 1. Such impasses can arise in many forms involving many tasks and no general technique is known for correcting the condition. The usual solution is to specify programming conventions by which deadlock can be avoided. For example, deadlock cannot occur if all tasks own only one resource at a time, if all tasks request resources in the same order, or if each task requests all its necessary resources as a group. Unfortunately, these conventions are rather severe programming constraints. One of the goals of data independence is to permit programs to share data without knowledge of, or provision for, each others existence. Another update problem is that of maintaining the consistency of related data maps. In transaction processing, one transaction usually triggers many changes. Thus, for a stock item received, changes should be made to purchase order, inventory, and accounting files. Furthermore, changes should be made to any associated indexes or summary data items. Ideally, all related data maps should be changed simultaneously because the information is inconsistent until all changes have been made. The danger is that other tasks will use the data or that a system failure will occur during the period of inconsistency. With data independence, certain related changes should be made automatically by data-base management. The related changes that are

52

R. W. Engles

candidates for automatic update are those that are common to many application programs and those that involve redundant data maps such as secondary indexes and summary attributes. Whether these types of data maps are represented as stored data or not is a question of performance that is subject to changing requirements. Therefore, redundant data maps should be transparent to application programs and updated automatically by data-base management. A fundamental question of data-base management is what to do with the information that has been changed. For reasons of recovery and "as of retrieval", operational data cannot just be destroyed. Copies must be kept for back-up and history—and yet data must also be purged before all the available storage volumes are used. When and what to copy and when and what to purge are difficult questions to answer in the context of an on-line system with many applications using the same data banks. With shared data, update and retrieval are further complicated by the possibility that different users, specifying the same point in time, will want to see different values. For example, the current parts structure file as seen by manufacturing may be "as of a few months ago" as seen by engineering. To solve this problem with data independence implies that data-base management has information about the users of the data base and performs its update and retrieval services accordingly. Given a request to delete information, for example, it may or may not be proper for the deletion to be effective for all users of the data base. 4. Data Independence 4 . 1 . WHEN, WHERE, AND WHY, W H O SHOULD SPECIFY WHAT

Data independence is the capability by which an application program is insulated from the various aspects of data bank design and implementation. A high degree of data independence implies the ability to make changes to a data bank, such as a change to the method of representing a complex data map, without requiring changes to source programs. The implications of data independence might best be appreciated by considering the degree to which most programs are data dependent. First of all, the logic of source programs usually depends on the type of data organization. Beyond this, the dependencies vary depending on the system (even for the same programming language). To write an application program in a conventional system, the programmer may have to know the answers to all the following questions: A. In regard to using a data set: 1. How is it accessed ? i.e., (a) how is it located ?

A Tutorial on Data-Base Organization

53

(b) what access method should be used? (c) is access constrained by device characteristics ? 2. Where is it? i.e., (a) what volume(s) is it on ? (b) what device is the volume on ? (c) what computer is the device on ? 3. What is it? i.e. (a) how is it related to the file ? (b) what is the data-set organization ? (c) what are the record storage parameters ? 4. How is the access method used? i.e., (a) (b) (c) (d)

buffer requirements ? blocking/spanning? interlock procedures ? control blocks and linkages?

B. In regard to using a single data item: 1. How is it accessed? i.e., (a) (b) (c) (d)

is it stored or computed as a function of other values ? what is the search algorithm ? is there an index ? what do I have to do and know to use the index ? (Most of these questions about data also apply to the index.)

2. Where is it? i.e., (a) where is the data item in the segment or record? (b) where is the segment or record in the data set ? (c) what is the name or extent of the data set ? 3. What is it? i.e., (a) (b) (c) (d)

how do I tell if it's null ? what is its length ? what is the unit of measure of the value ? what type of value? (i.e., number, string, boolean, pointer)

4. How is the value represented? (a) what is the code? (i.e., which character set or which internal arithmetic representation) (b) what is the format? (i.e., fixed-length or justification and padding) (c) what is the level of representation? (i.e., internal or external, structured or primitive, standard or other)

54

R. W. Engles

C. In regard to update: 1. What checks should be made pertaining to : (a) authorization for the change ? (b) validity of the new data ? (c) consistency of related data ? 2. What other data should be changed ? (a) other copies of the values ? (b) related data maps ? (c) indexes or inverted data maps ? 3. What are the procedures for: (a) (b) (c) (d)

interlock/deadlock? copies for recovery and history ? handling additions and deletions ? allocating and freeing storage ?

With data independence the above questions must still be answered, but not by the applications programmer; i.e., while the parameters must still be plugged in, it should not be done by means of source program specification. This does not necessarily mean that all of the above parameters can or should be removed from source programs, nor does it mean that all parameters should be bound at the same time. The issue is not simply late-binding versus early-binding or data independence versus data dependence. The issue is when, where, and why, who should specify what. A widely-accepted premise of data-base support is that much of the specification should be done by the data-base administrator: an individual or group reporting to installation management. The data-base administrator is responsible for the economics of the information system, the quality of service to its users, and the information content, organization, integrity, custody, and usage of the data base. The reasons for data independence are as follows : 1. To allow the data-base administrator to make changes in the content, location, representation and organization of a data bank without causing reprogramming of application programs which use the data bank. 2. To allow the supplier of data processing equipment and software to introduce new technologies without causing reprogramming of the customer's application. 3. To facilitate data sharing by allowing the same data to appear to be organized differently for different application programs. 4. To simplify application program development and, in particular,

A Tutorial on Data-Base Organization

55

to facilitate the development of programs for interactive data-base processing. 5. To provide the centralization of control needed by the database administrator to ensure the security and integrity of the data base. 4.2. CHANGE AND CONTROL

Data independence is not a programming technique; it is a programming discipline. Data independence is not a tool for programmers; it is a tool for management, a tool by which management can control the data base and minimize the impact of changing it. Data independence allows application programs to cope with variations in the representation and materialization of values and in the organization and location of stored data. According to Meitzer [18], the reasons for these variations are as follows: "A. More information is required in the enterprise 1. More entities are found to exist in the enterprise, or are introduced into a data bank. 2. An entity is found to have more attributes. 3. An attribute is found to be common to more entities. 4. Two enterprises have merged. Obviously the systems and storage policies will have been different. "B. Usage of the information changes 1. Two or more data banks are combined when an unsuspected relationship is found, or a known but undefined relationship must be defined. 2. A data bank is subdivided to more stringently isolate classes of applications. Obviously, the capability to verify consistency of data which may be stored redundantly in each bank has been traded off. 3. The range (representation, length of data element) of a data item must be extended. 4. Data elements are shared with different relationships in different applications. 5. Relationships between data elements or groups of data elements are altered. 6. The name of the data set or data element is changed. "C. Control and optimization of the system is enhanced 1. Data common to applications is factored to reduce redundancy and increase integrity. 2. Data is divided into homogeneous data sets.

R. W. Engles

56

3. Data is divided so that a portion of it may be more convenient for updating or changing. 4. Data is divided and staged according to frequency of access. Some of the data need not be kept on line. 5. Dependent or interrelated data is associated to augment control, security and integrity. 6. The location of data is changed to enhance security. 7. The location of data is changed to make better use of available space or unique characteristics of the storage devices. 8. The combinations and organizations of data are changed according to changing requirements and priorities of applications or changing quantities and distribution of data. 9. The materialization or representation of data are changed according to changing requirements and priorities of applications or the capabilities and technologies of the system. "D. The configuration of the system changes 1. Obsolescent and uneconomical components are removed. 2. New equipment, software components, and technologies are introduced. 3. A new international, national, industry, system, or installation standard is promulgated, or an existing standard is modified. "E. Requirements of an application changes 1. 2. 3. 4. 5.

An application requires more files. A file requires more fields. A field changes from single-valued to multi-valued. The meaning of a field changes. The interrelationships between fields, records, or files change."

We do not know how to insulate a program from changes to its information requirements. This is where data independence ends. However, changes in the information requirements of one program should not impact other programs. This is what data independence is really all about. Without shared data, the capability of data independence is of marginal value; with shared data, some degree of data independence is essential. Without data independence the process of coping with change can severely inhibit the growth of a system. At one large data processing installation, over half of the programming staff is working full-time on program maintenance and it is estimated that over half of this maintenance activity is the result of changes in the representation and structure of data. The annual cost of program maintenance has become greater than the annual rental of the hardware and with more and more of the limited supply of programmers performing

A Tutorial on Data-Base Organization

57

maintenance functions, new applications are continually being deferred. Furthermore, this installation has only been sharing data in the batch mode. With on-line systems, the maintenance problem becomes more difficult and more extensive. Clearly, a major motivation for data independence is the problem of change. The other major motivation is the problem of control: the control needed by the data base administrator to create and evolve a consistent and integrated data base, and the control needed to maintain its security and integrity. Looking briefly at the history of control over data, we note that in the first generation each programmer had complete control over his data. In succeeding generations installation management centralized the custody of data and established some control over its usage. But as the size and complexity of a company's data base and procedures increased, the ability to make a change decreased. Not only were more and more people needed to make the changes, but certain changes could cause the application systems to be down for intolerable periods of time. As a result, management was often forced into a position of deciding not to change, rather than deciding which change would be more beneficial, simply because the cost of change was greater than the cost of no change. In other words, management had lost control. By limiting the impact of change, data independence enables management to regain control of the information processing system. ". . . Just as a tape library is established to avoid loss of data, such as a programmer walking away with an installation's records, data independence is established to avoid loss of the capability to use the data, such as a programmer walking away with the knowledge of what the records look like or mean. It reserves to management the decisions and control over the trade-offs and optimizations of the system. It enables the trade-off between people time and machine time. It secures for an installation some more programmer independence" [18]. With centralized control of the data base, it becomes possible to eliminate unnecessary redundancy in the acquisition and storage of data, to enforce standards of data representation and validation, and to protect the data base from improper usage. Protecting the data base from those who are not authorized to use it is called security; protecting the data base from those who are authorized to use it is called integrity. Security and integrity mechanisms can never be completely foolproof. On the other hand, security and integrity can never be completely adequate without some degree of data independence. Adequate data-base security requires that data requests be monitored and that data-base management "know" who is requesting what. Adequate data-base integrity requires that update

58

R. W. Engles

requests be monitored to guard against the untoward interaction of tasks and improper update by a single task. The latter requires that data-base management know about the user, the permissible relationships among entities, and the permissible range and type of attributes values. Security and integrity mechanisms are a natural adjunct to the object-time mapping required to achieve data independence. 4.3. BINDING AND MAPPING

"Binding is the firm association of an attribute of data with the program. Once bound, this attribute can no longer vary, until it is unbound and rebound. Data attributes can be bound individually or in groups at different times in program production and execution. Data independence is defeated by binding. Obviously, data cannot be accessed unless it is bound. The later it is bound, however, the more variation that is acceptable and the more interpretation that is necessary. "A program can be bound to its data at the following points: 1. Writing of the source program, implying or specifying the data descriptors. 2. Compiling of the object program, implying or including the data descriptors. 3. Linking the object program with precompiled tables or routines containing the data descriptors. 4. Opening of the file, associating the file description with the data descriptors. 5. Accessing of a data item or a record of data items, dynamically utilizing the data descriptors. "Binding in the source program defeats the ability to cope with static variation. Binding in the compiler, in linking, and at open are logically equivalent and, in a system which maintains where-used data, can be altered automatically to cope with static variation. Binding earlier than at each access defeats the ability to cope with dynamic variation. In a system that supports a user seated at a keyboard and browsing among the data, very late binding must be supported" [18]. Very late binding implies multiple levels of indirection and interpretation at every access. Full interpretation means that all data parameters are used at every reference to every data item. The performance penalty of full interpretation by software is measured in orders of magnitude. Consequently, data independence requires hardware innovation and/or binding trade-offs. An example of a binding trade-off is compile-time binding of data element attributes such as scale, units, length and representation. This implies that these attributes are constant

A Tutorial on Data-Base Organization

59

for all instances of the data element and that the compiler obtains the descriptors from data-base management, not from the source program. Ideally, variable binding times should be allowed for many data parameters. In particular, data independence for batch processing programs should not require very late binding, but it should be possible for an interactive processing program to access the same data by means of very late binding. In designing a system with data independence, the critical interface is the one between application programs and data-base management. The trade-offs that might be made in order to avoid full interpretation should not compromise the separation of file organization and data organization. For example, a file definition should not be constrained to a subset of the data organization. Files must be defined against some structure, but if file organization and data organization are to be really separate, that structure cannot be the physical data organization. This implies some kind of logical data organization against which files can be defined by application programmers, and against which data banks can be defined by data-base administrators. This logical data organization would provide the conceptual framework that links file organization and data organization, enabling data-base management to map a given file definition to a given data-bank design. A logical data-base organization can be derived from the notions of entity sets and data maps. Consider, for example, that a logical data bank is viewed as a collection of related entity record sets in a regular organization. As previously suggested, whenever we have a complex map whose inverse is also complex, the relationship defines another entity set. The corresponding entity record set is viewed in terms of the value pair method of representing a complex map. All complex maps whose inverse is simple are viewed as being represented in their inverse form, i.e., as simple maps. These assumptions permit us to think of each entity record set as a matrix of attribute values, just as we pictured the set of THINGS earlier in this tutorial. A simple file can then be defined as some subset of an entity record set. A hierarchical file can be defined in terms of selected relationships between entity record sets, with one or more simple files at each level of the hierarchy. In general, a logical data bank is a network of relationships among entity record sets; any hierarchy is therefore only one of the many possible hierarchies that can be defined against the same data bank. When we defined the entity record set in a previous section of this tutorial, we assumed it was a direct representation of the simple data maps pertaining to an entity set. We said it was more logical than physical because the storage mapping was unspecified. We discussed the various ways in which the structure could be partitioned into data sets and the various ways the stored records could be ordered. We then

60

R, W. Engles

explored various methods of representing complex data maps, organizing data to represent structural relationships, and constructing indexes to facilitate search. Ideally, application programs should be independent of all these aspects of data organization. Furthermore, just as file organization should be distinguished from data organization, fields should be distinguished from data elements. The definition of a field does not imply the existence of stored data. The field required by one application may be a subset of the field required by another application program. Different application programs may require different representations of the same value. The data-base administrator may want to change the method of representing or materializing a value for reasons of optimization, security, integrity, standards, or response-time requirements. Most important, both information attributes and data attributes must change in order to reflect changes in the real world. Like the number of entities in a set, the number of attributes associated with a set is subject to change. Typically, the number of attributes will increase because of new applications or regulations. Furthermore, the format or size of existing data elements is subject to change. This problem is illustrated by the postal requirement that the ZIP code be added to mailing addresses. Other examples involve identifier and summary attributes, such as when the employee number series grows from thousands to ten thousands and year-to-date gross sales now requires values in the ten million of dollars rather than millions. 4.4. DATA-BASE MANAGEMENT

We now extend the notion of an entity record set by considering the representation and materialization of its attribute values. Representation, or data type, is the relationship between data items and values. A data item is a bunch of bits ; a value is an interpretation of one or more data items. The same data item can be interpreted as different values; different data items can be interpreted as the same value. Materialization is the method by which a value is stored or computed, independent of its data type. Thus far, we have only considered the direct materialization type, i.e., we have assumed that the values of an attribute are represented by data items in stored records of data sets directly associated with the entity record set. There are other possibilities, one of which we explicitly ignored earlier in this tutorial: function specification by means of an algorithm rather than a list of values. In conventional systems, when functions can be specified by other than an exhaustive listing of argument values and function values, the algorithm is usually associated with the processing program and not with data management. In data-base systems, certain functions should

A Tutorial on Data-Base Organization

61

be associated with data-base management in order to have data independence. The functions of concern pertain to attributes, such as summaries, which can be realized either through search of a stored representation of the data map or by other means. Most of these functions will involve the use of related data maps. For example, consider the data map: Department#->Number-of-Employees. If we have a stored representation of the map Employee#->Department#, the number of employees in a department does not have to be stored data; it can be derived from the inverse of the Employee#->Department# data map. This may be preferable to storing a representation of the Department#->Number-of-Employees data map, which has to be updated whenever a change is made to the Employee#->Department# data map. Another possibility is that the number of employees is kept as stored data in a secondary index. Because of changing resources or requirements, the method of implementing the function is subject to change, and it should be possible to make the change without recoding, recompiling, and retesting application programs. In order for an application program to be independent of the method used to materialize attribute values, all values must be referenced in the same manner. Thus, in the entity record set, we pretend that all attribute values are stored data. Data generated by an algorithm, rather than by a retrieval procedure, has been called "virtual data". The important point in regard to data independence is that the procedure must be transparent to the processing programs. (If something is virtual, you can see it, but it isn't there; if something is transparent, it is there, but you can't see it.) Another way in which data may be virtual is the factoring of values into descriptors. For an example of factored attribute values, assume that the employee records of two divisions of the same company are integrated as one entity record set. However, the stored records remain separate; i.e., the employee records for division A are in data group 1 and the employee records for division Β are in data group 2. The two values of the Division attribute can both be factored into the descriptors of their respective data groups. Furthermore, assume that there are attributes of employees in division A which are not applicable to employees in division B. These attributes could then have the direct materialization type in data group 1 and the factored materialization type with a value of null in data group 2. The same value can be represented in many forms. The form which is appropriate to application programs is not necessarily the best representation for storage in a data bank. Numbers to be displayed to users are not in the same form required for computation. The form required for computation by a particular CPU/programming language is not necessarily the best form for storage. The use of compaction

62

R. W. Engles

techniques can save considerable amounts of storage but require a transformation between the coded form and the usable form. For example, an application program stores or retrieves a field which contains the name of a state. The data item as manipulated by the application program is a character string such as "CALIFORNIA". In the data bank, however, the value is represented by a numeric code and there is a function which maps these state codes into state names and vice versa. Such mapping functions should be part of data-base management and their use should be transparent to application programs. One of the major implications of data independence is the need for a data description language. This is the language used by the data-base administrator to describe all the aspects of a data organization and its relationship to entity record sets. As an example of what is probably involved, consider that the data-base administrator has to specify the following information about each attribute of each entity record set: 1. What the attribute values designate; i.e., identity, structural, or simple facts; status, summary or historical facts. 2. The materialization type; i.e., direct, indirect, factored, computed, or coded, and, depending on the type, the data set(s) and byte offset, function names, etc. 3. The representation of the values; i.e., binary or decimal, integer or real, digit or character string, length, justification, padding, scale, units, etc. 4. The security and integrity procedures; i.e., authorization tables, edit masks, range limits, related attributes, update rules, function names, etc. 5. Search mechanisms; i.e., whether the attribute values can be used as keys, whether the attribute is to be indexed, the type of index, search technique, etc. The data-base administrator must also specify the names that are to be used to reference data. This is not a trivial matter. A system with data independence is critically dependent on names. The need to be systematic in assigning names precludes the possibility of having a single set of meaningful names. Therefore, it is necessary to distinguish internal names from external names. Furthermore, the notion of a nonprogrammer user working with a "natural" nomenclature implies many sets of external names for the same data. Qualification will be needed to resolve ambiguity and synonymity will be needed to establish equivalence. 4.5. CONCLUSION

The essential characteristic of a "data-base system" is the sharing of data by multiple applications. In this tutorial we have assumed that

A Tutorial on Data-Base Organization

63

at least some of the applications are on-line as opposed to batch, that the sharing of data is concurrent, and that the system has a generalized inquiry facility. This type of environment demands a clearly defined line between data-base management and the application programs. We have advanced the opinion that this interface should provide a significant degree of data independence. A basic premise is that the individual users of a data-base system are not capable of applying "information economics" to their needs for services. Installation management must provide the level of guidance required to balance the desires of the individual users against what is best for the enterprise. Management cannot do this without control of the data base and the ability to make changes without disrupting existing applications. Thus, we have viewed data independence as a management tool, rather than as a programming technique. However, we believe that the goals of management and of productive programmers can be achieved simultaneously, with the further benefit of disciplining each programmer's practices to better support the requirements of the entire enterprise. A significant degree of data independence means that access methods and data organizations are transparent to application programs. This implies a logical data structure against which application programmers can define their files and specify their data requests. This tutorial has proposed the notion of a collection of inter-related entity record sets as the logical structure of a data bank. We did not examine other possibilities. Furthermore, we did not mention the problem of ambiguity inherent in related, complex data maps, we did not introduce the dimension of time into our theory of data, and we did not mention hybrid data organizations such as a combination of chained list and contiguous hierarchical organizations. Indeed, many other aspects of data base organization have not been discussed. From what has been discussed, we hope the reader has a better understanding of data. References and Selected Bibliography 1. SALTON, G., Automatic Information Organization and Retrieval, McGraw-Hill, 1968. 2. Information Management System/360 for the IBM System/360 (System Description) Application Description Manual, H20-0524. 3. MEALY, G. H., Another Look at Data, Proc. AFIPS 1967 Fall Joint Computer Conference, Vol. 31. 4. IVERSON, K. E., A Programming Language, John Wiley & Sons, 1962. 5. Data File Handbook, IBM Data Processing Techniques, C20-1638. 6. BUCHHOLZ, W., File Organization and Addressing, IBM Systems Journal, Vol. 2, 1963.

64

R. W. Engles

7. RAVER, N., File Organization in Management Information and Control Systems, FILE 68 International Seminar on File Organization, Working Papers, November 1968. 8. System/360 Generalized Information System (Basic) Application Description Manual H20-0521. 9. Report to the CODASYL COBOL Committee, January 1968, COBOL Extensions to Handle Data Bases. 10. DODD, G., Elements of Data Management Systems, Computing Surveys, ACM, Vol. 1, No. 2, June 1969. 11. ENGLES, R. W., Concepts and Terminology for Programmers, TR 00.1663, IBM, October 1967. 12. DZUBAK B. J., and WARBURTON, C. R., The Organization of Structured Files, Comm. ACM Vol. 8, 7, July 1965. 13. DIXON, P. J., and SABLE, J., DM-1—A Generalized Data Management System, Proc. AFIPS 1967 Spring Joint Computer Conference Vol. 30, Thompson Book Co., Washington, D.C. 14. BLIER, R. E., and VORHAUS, A. H., File Organization in the SDC

15. 16. 17. 18. 19. 20. 21.

Time-Shared Data Management System (TDMS), SP-2907, SDC, August 1, 1968. BLIER, R. E., Treating Hierarchical Data Structures in the SDC Time-Shared Data Management System (TDMS), SP-2750, SDC, August 29, 1967. MEADOW, C. T., The Analysis of Information Systems, John Wiley & Sons, 1967. LIU, H., A File Management System for a Large Corporate Information System Data Bank, Proceedings of the 1968 Fall Joint Computer Conference, Vol. 33. MELTZER, H. S., Data Base Concepts and Architecture for Data Base Systems, IBM Report to SHARE Information Systems Research Project, August 20, 1969. A Survey of Generalized Data Base Management Systems, CODASYL Systems Committee Technical Report, May 1969. MCGEE, W. C , Generalized File Processing, Annual Review in Automatic Programming,, Vol. 5, Pergamon Press, 1969. CODD, E. F., A Relational Model of Data for Large Shared Data Banks, Comm. ACM Vol 13, 6, June 1970.

General

Concepts

of the Simula

Programming

67

Language

J. D. ICHBIAH and S. P. MORSEf Compagnie Internationale pour L'Informatique, Les Clayes Sous Bois, France Introduction Simulation languages, like many problem oriented languages, serve a two-fold purpose. They provide the user with a number of frequently used operations. In addition, they offer him an ease of expression that is usually not found in general purpose programming languages. A simulation program is indeed a program in the sense that it can be executed and will give results corresponding to the workings of the model it describes. It should not be overlooked that a simulation program is also a representation of a model and, as such, must be concise and readable. The design of a model is usually the result of successive redefinitions and modifications. This process will be easier if the representation of the model remains clear and understandable at each step. Simulations involve complex entities, called processes, which consist of data structures and of algorithms that operate on these structures. Such associations of data and algorithms have general implications. However, languages referred to as "general purpose programming languages", such as FORTRAN, ALGOL, and PL/I, do not provide adequate facilities for the definition and handling of such entities. These are some of the considerations which underlie the definition of the SIMULA 67 language. Dahl, Myhrhaug, and Nygaard [4] have, in effect, designed it as a general purpose language that is general enough to serve as the base of the definition of a simulation language. SIMULA 67 incorporates into ALGOL 60 the notions of classes and objects as well as facilities for the treatment of quasiparallel systems. Classes permit the definition of complex entities which later can be used as elementary entities. In other words, these t Present address : Department of Electrical Engineering and Computer Sciences, University o f California, Berkeley. 65 6—AP

·

·

66

J. D. Ichbiah and S. P. Morse

complex entities can be used globally without having to refer to their components. Because of this feature SIMULA 67 can be used to conveniently define problem oriented languages. For example, facilities for handling symmetrical lists have been defined in the class SIMSET. Similarly, the class SIMULATION has been defined which offers facilities for handling quasi-parallelism analogous to the facilities found in the earlier language SIMULA [1, 2]. The first part of this paper describes the notions of class, subclass, and object. The second part treats reference variables and the means to assure that they can be safely used. The last part treats quasiparallelism. The notion of virtual entity and an example on the use of SIMULA 67 are presented in the appendices. 1. Classes and Objects 1.1. ORIGIN OF THE NOTIONS OF CLASS AND OBJECT

The notions of class and object in SIMULA 67 [3, 4] can be traced back to the notions of block and block instance in ALGOL 60 [6] and also to the notions of record class and record introduced by Hoare and Wirth [5, 7]. An ALGOL block is a description of a composite data structure and associated algorithms. When a block is executed, a dynamic instance of that block is generated. The block instance is the composite data structure described by the block and contains the local variables of the block as well as information needed for the dynamic linkage to other blocks. It is possible to have interaction between instances of different blocks and even between instances of the same block in the case of recursive procedure calls. The notion of class is a generalization of the notion of block. As with instances of blocks, it is possible to generate multiple objects of the same class and each object thus generated is an instance of the class. However, control may pass from one object to another in more general ways than is possible for procedures. Thus an object may suspend its execution. It may also ask that the execution of a different object be initiated or resumed. When there are no algorithms associated with the data structure of a class, the class reduces to a record class with its objects being records. In general, objects are records to which algorithms are associated. Different objects can coexist in memory ; they may be of the same or of different classes. Objects of the same class can be at the same stage or at different stages of execution of their algorithm. The definition of classes and subclasses, their concatenation, and the generation of simple and compound objects are described in the following sections.

General Concepts of Simula 67

67

1.2. CLASSES AND SUBCLASSES

SIMULA 67 is an extension of ALGOL 60. With some minor exceptions the rules of ALGOL 60 have been preserved in SIMULA. The definitions of certain syntactic units, however, have been extended to account for the new concepts of SIMULA. For example, as in ALGOL, the head of a SIMULA block contains declarations. However, in SIMULA these can be the declarations of classes as indicated by the redefinition of the syntactic unit < declaration > . < declaration > : : = < ALGOL declaration > | < class declaration > 1.2.1. Class Declaration A class declaration can have the following form: class A (PA); SA; begin DA; IA ; inner; FA end The identifier A is the name of the class; PA is the parameter list of the class A; SA is the list of specifications of the parameters PA. The class body begins with a list of declarations DA. The symbols IA and FA represent lists of instructions respectively called initial operations and final operations of the class A. The symbol inner represents a dummy instruction acting as a separator between the initial and final operations. The quantities passed as parameters in PA or declared in DA are called the attributes of the class A and are hence also attributes of any object of that class. We will see later that attributes of an object may be accessed by other objects whereas an entity declared in a block which is a subblock of the class body may only be accessed in the block itself. Note that a class declaration can be one of the declarations in DA. This would then be a class attribute of the class A. 7.2.2. Object Generation The expression new A (. . .) where A is a class, is an object generator. When encountered it creates an object which is an instance of class A and starts execution of the initial operations of A. The execution continues until

/. D. Ichbiah and S. P. Morse

68

the end of the class body is encountered, at which time the execution is terminated. Execution will be suspended, however, if a call to the procedure "detach" is encountered. It is this suspension capability that makes it possible for many objects to exist simultaneously. When the execution of an object is terminated, the data structure of the object remains in memory as long as it is possible to access it. 1.23. Subclasses A class declaration may be preceded by a prefix which is the name of another class. The prefixed class is now called a subclass of the A

FIG. 1. Hierarchy of classes and subclasses. prefix. The following is a declaration for the subclass Β of the previously declared class A. A class B (PB); SB; begin DB; IB ; inner; FB end More generally a hierarchy of classes can be introduced by a succession of declarations of subclasses as follows (see Fig. 1 ) : class A . . . ; A class Β . . . ; Β class C . . . ; Β class D . . . ; A class Ε . . . ; A graph corresponding to this hierarchy is an oriented tree. The root of the tree is the class that has no prefix (in this case A). The

General Concepts of Simula 67

69

prefix sequence of a given class is the sequence of classes encountered on the path (unique) going from the given class to the root. In the above example the prefix sequence of class C consists of C, B, and A. A subclass is said to be inner to its prefixes. Thus C is inner to Β and A. Conversely Β and A are said to be outer to C. 1.2.4. Class Concatenation and Compound Objects A subclass is equivalent to the class obtained by the concatenation of those classes that are on its prefix sequence. Thus the subclass C is equivalent to the class obtained by the concatenation of A, B, and C. This section describes the data structure associated with the concatenated class; the next section defines its class body.

FIG. 2. Structure of compound objects in Fig. 1. An object of a class resulting from a concatenation is a compound object. The concatenation process can be interpreted in terms of the space occupied by the data structure of a compound object as follows. This space is the union of the spaces occupied by the data structures of the various classes in the prefix sequence. Fig. 2 shows the structure of the compound objects in the previous example (Fig. 1). The spaces a, b, c, d, e represent the spaces occupied by the data structures defined by A, B, C, D, E. 1.2.5. Class Body of a Concatenated Class Consider the class A and its subclass Β defined previously. The subclass Β is equivalent to the fictitious class Κ defined below. class Κ (PA, PB); SA; SB; begin DA; DB; IA; IB ; inner; FB; FA end The class Κ is obtained therefore by concatenating PA and PB, their specifications SA and SB, and the declarations DA and DB. The body

70

/. D. Ichbiah and S. P. Morse

of class Κ is obtained by replacing the symbol inner of A by the initial operations of Β followed by; inner; and the final operations of B. This illustrates the role played by the symbol inner. On the one hand it is a dummy instruction when executed, and on the other hand it specifies where code may be inserted for a compound object. The execution of an object generator such as new Β (. . .) is equivalent to that of an object generator of the fictitious class K, namely new Κ (. . .). 1.2.6. Example A simulation model involves the interaction of independent entities called processes. It is convenient to be able to distinguish between the generation of a process and its activation, and also to test if the execution of a process is terminated or not. The following example shows how the class "process" can be defined within SIMULA 67 so that these conditions are satisfied. (Dot sequences . . . represent elements that are not essential to the understanding of the example.) . . . class process ; begin . . . ; Boolean TERMINATED; detach ; inner; TERMINATED := true; end Consider now a simulation of the spread of an epidemic disease [2J. The processes interacting in this simulation are sick persons and treatments. The definition of a sick person is given in the declaration of the following subclass of the class process. process class sick person . . . ; The effect of the object generator "new sick person" is as follows. The first action performed by the resulting compound object is a call to the procedure "detach". The execution of the object is thereby suspended. It is only after a subsequent activation that the actions indicated in the class body of "sick person" will be carried out. After completion of these actions the final operations of the class "process" are begun and the value "true" is assigned to the variable TERMINATED. In the previous example two classes have been defined corresponding to the two successive levels of description. —the class "process" accounts for the actions that are necessary because objects considered are processes. —the class "sick person" states the actions resulting from the fact that the processes considered are also sick persons.

General Concepts of Simula 67

71

It is clear that the definition of the class "process" can be done without considering the subclasses of "process" which are defined afterwards. 1.2.7. Prefixed Blocks The mechanism of concatenation can be extended to the case of prefixed blocks. The execution of a block prefixed by a given class consists of successively executing the initial operations of the class, the operations of the block, and the final operations of the class. In addition, the attributes of the class are accessible to the statements inside the prefixed block. Prefixed blocks are used mainly for the latter feature; accessibility to large sets of attributes is provided concisely by specifying only the prefix. 1.3. RELATIONSHIP BETWEEN CLASS AND SUBCLASS

The relation between class and subclass may appear striking at first glance. In certain cases the relation appears similar to the relation between set and subset. If Β and C are subsets of the set A, then Β and C are included in A ; also every element of Β or C is an element of A. For example consider the sets R and Κ of real and complex numbers. Note that R is included in K. Similarly, REAL may be made a subclass of the class COMPLEX in a SIMULA program. class COMPLEX (real part, imaginary part) ; real real part, imaginary part; end COMPLEX; COMPLEX class REAL; begin imaginary part:= 0; end REAL; comment examples of generation of objects of these classes ; ref (REAL) X, Z; ref (COMPLEX) Y; X :- new REAL (8,0); Y :- new COMPLEX (3, 2 ) ; Ζ :-new REAL (3, 2 ) ; The trouble with such a definition is that the treatment of reals is unnecessarily awkward. A real appears to be effectively a particular complex. Being treated as complexes, all reals possess therefore two fields—a real part and an imaginary part. The latter field is always null but nevertheless occupies space in memory. This inconvenience

/. D. Ichbiah and S. P. Morse

72

can be avoided by realizing that a class definition specifies characteristics that are possessed by all objects of the class. The definition of the subclass in turn specifies additional characteristics possessed by objects that are members of the subclass. Note that whereas a subset implies a restriction, a subclass can be used to introduce additional attributes. In the definition which follows, the characteristic common to the objects of the class REAL is the possession of a real part. The objects which are members of the class COMPLEX possess a real part and, in addition, possess a complex part. COMPLEX should therefore be made a subclass of REAL. class REAL (real part) ; real real part ; end REAL; REAL class COMPLEX (imaginary part); real imaginary part; end COMPLEX; comment examples of generation of objects of these classes ; ref (REAL) X, Z; ref (COMPLEX) Y; X :- new REAL (8); Y :- new COMPLEX (3, 2) ; Ζ :-new REAL (3); Thus the notions of set and subset correspond to an analytic approach; sets are stratified into subsets. Classes and subclasses may be designed to correspond to such stratifications. However, it will often be preferable to use a synthetic approach for the design of classes. When designing a given class no a priori knowledge of its subclasses is necessary. More and more elaborate classes can thus easily be obtained by a step-by-step definition of subclasses which introduce additional characteristics. 1.4.

METHODOLOGICAL IMPLICATIONS OF THE C O N C E P T S OF CLASS A N D

CONCATENATION

The indication of a class name in a prefix makes the entities defined in that class accessible within the prefixed class. Thus a simple and powerful means is available for the global communication of these entities. Consider for example the classes SIMSET and SIMULATION. The class "linkage" and its two subclasses "link" and "head" are class attributes of SIMSET. The class SIMULATION is itself prefixed by SIMSET. The class attribute "link" is therefore accessible inside of SIMULATION and "link" can serve as a prefix to the classes "process" and "event notice". Similarly a class "TRAFFIC", prefixed by SIMULATION, can be defined. Class attributes of "TRAFFIC"

General Concepts of Simula 67

73

Class attributes of each class

Classes

Linkage

Simset

Head

Link

Simulation

Traffic

Process

Route

Event notice

Intersection

FIG. 3. Hierarchy of classes used for traffic simulation. are the subclasses "route" and "intersection" of "process". A user doing a traffic simulation will thus be able to use these concepts inside a block prefixed by TRAFFIC (see Fig. 3). class SIMSET; begin class linkage; begin . . . end; linkage class head; begin . . . end; linkage class link; begin . . . end; end SIMSET; SIMSET class SIMULATION; begin link class process; begin . . . end; link class event notice; begin . . . end; end SIMULATION; SIMULATION class TRAFFIC; begin process class route; begin . . . end; process class intersection; begin . . . end; end TRAFFIC; The different classes correspond to the different levels from which a given problem can be viewed. SIMSET provides for the treatment of

74

J. Ζλ Ichbiah and S. P. Morse

lists. SIMULATION introduces the notion of simulation. The entities used in traffic simulation are defined in TRAFFIC. It is only inside a block prefixed by TRAFFIC that a traffic simulation of a particular network will be performed. This has considerable implications for the design of large systems. In such design it is a common practice to introduce successive levels of definition and to use a coherent set of concepts within each level. In the traffic simulation problem, for example, the levels considered are the list processing level, the simulation level, and the traffic level. On the traffic level the concepts introduced are route and intersection. They form the coherent set of concepts normally used by traffic engineers. Similarly, link and head are coherent concepts in list processing. However, head and route, which appear on different levels, would normally not be used in the same context. The prefixed classes of SIMULA bring this leveling design practice into a programming language. Because of this feature SIMULA 67 can be used as a powerful kernel language for the design of problem oriented languages. 2. Reference Variables and Remote Identifiers 2.1. LOCAL ACCESS AND REMOTE ACCESS

Consider the execution of an object. Some of the actions performed involve attributes of the object itself. This is called local access of attributes and the usual rules of ALGOL apply. The term remote access is used for the accessing of attributes of other objects. In this case a given attribute is not uniquely specified by merely mentioning its attribute identifier. In fact, at any given time several instances of the same class, each having identical attribute identifiers, can coexist in memory. It is therefore necessary to specify the object to which the considered attribute belongs. A remote access is thus performed in two steps: —The first step is the selection of a particular object —The second step is the determination of the attribute of the selected object. A new type of variable, the reference variable, is used for referring to objects. A reference to a newly created object is obtained during the execution of an object generator. This reference is analogous to a pointer. The language permits the calculation and assignment of references. For example, an object generator may be assigned to a reference variable. In such a case, the reference variable refers to the newly created object.

General Concepts of Simula 67

75

2 . 2 . INHERENT DIFFICULTIES OF REMOTE ACCESS

Some precautions must be taken if remote access is to be carried out efficiently and without loss of security. Consider the access of attribute " b " of the object referred to by reference variable X. In an implementation of the language, the value stored in X may be the base address of the object's data or may serve to obtain that address. The displacement of a given attribute with respect to this base address is the same for all the objects of a class. The address of the attribute " b " can therefore be simply obtained by adding to the base address a value which is known at compile time. If the requirement of efficient access is thus satisfied, then the same cannot be said about the security of use. The following risk is encountered. The language allows for the calculation of references and for their assignment to reference variables. It then can happen by accident that X refers to an object which belongs to a class other than the one intended. Even though this object has no " b " attribute, a value for the fixed displacement of that attribute is obtained at compile time. No error indication will be given until possibly much later in the execution of the program and the search for the cause of the error at that time may be difficult. Hoare's solution, taken and expanded in SIMULA 67, is to have the syntax make this sort of error impossible. In the majority of cases these referencing errors can and will be detected at compile time. For the remaining cases a run-time check is necessary. However, these checks will not significantly degrade the run-time efficiency since they occur infrequently. The elements of this syntactic solution to the problem of security of use for references are as follows. (a) A qualification must be included in the declaration of each reference variable. This qualification indicates to which class an object referred to by the variable may belong. It also specifies the scope of the attributes which may be remotely accessed with the reference variable. Thus the legality of a remote access depends on static information only and can be determined at compile time. (b) Reference assignments are defined and performed in such a way as to ensure that a reference variable will always designate an object whose run-time qualification corresponds to the declared qualification of the reference. 2 . 3 . REFERENCE ASSIGNMENTS

The qualification of a reference variable is used to test for the validity of reference assignments to that variable as illustrated in the

76

/. D. Ichbiah and S. P. Morse

following example. The classes A , Β and Ε are those defined in Fig. 1 (section 1.2.3). ref ( A ) X; ref (Β) Y; Y :- new Β; X:-Y; The validity of the above assignments may be established at compile time. In the first assignment the object new Β and the reference variable Y are both qualified by B. Thus Y really refers to an object of a class that it was intended to refer to and there is no danger. In the second assignment, X is qualified by A and will serve for remote access to attributes of that class. Since each of these attributes will also be present in an object of any subclass of A , the object referred to by Y may be safely assigned to X. Now consider Y:-X; In this case it is necessary to check at run-time whether the object referred to by X is actually a member of Β or of a subclass of B. If so the assignment may be carried out. Otherwise a run-time error results. Finally consider ref ( E ) Z ; Z:-Y; This assignment will be recognized as invalid at compile time. Reference variable Y is qualified by B, and Ζ by E. However, Β and Ε are not in the same prefix sequence. 2 . 4 . THE T W O TYPES OF REMOTE ACCESS

To carry out a remote access without ambiguity, an object and an attribute identifier must be known. In addition, to satisfy the security requirement the qualification of the object must be known. These requirements are satisfied by a remote identifier or, simpler yet, by the connection. 2.4.1. Remote Identifiers A remote identifier is composed of a reference variable (or an expression delivering a reference value), a dot, and an attribute identifier. Consider the remote identifier Y.b for the previous example. When the reference variable Y was declared, its qualification was specified (in this case B). Hence it is possible to check at compile time whether it has meaning to look for a " b " attribute of such a class. Thus if " a " and " b " represent respectively an attribute of class A and an attribute of subclass Β prefixed by A the remote identifiers X.a,

General Concepts of Simula 67

77

Y.a, and Y.b are permitted. Indeed, X is qualified by A which has an " a " attribute. Similarly Y is qualified by Β which has an " a " attribute and a " b " attribute after concatenation. On the other hand, X.b is not permitted since " b " is not in the scope of A , the qualification of X. Note that X may nevertheless refer to an object of Β (after the legal assignment X :- new Β for example). However, it can be known only at run-time if the object referred to by X is an object of class A or of class B, or, even, of another subclass of A with or without a " b " attribute. Therefore this justifies rejection at compile time. A local qualification may be placed on a reference variable for accesses which would not otherwise be permitted. The remote identifier X qua B.b where X is given the local qualification Β is thus legal. However, a run-time check will be made to determine if X refers to an object either of class Β or of one of the subclasses of B. 2Â.2. Connection The connection is another mechanism for accomplishing remote access. The same principles that are valid for remote identifiers are also valid for the connection. The connection is a convenient type of access when several remote accesses to the attributes of a given object must be made. In such cases it is possible to factor, and therefore do only once, both the access to the object and the qualification check. Thereafter the attributes may be referred to by their identifiers alone. The format of a connection statement is the following: inspect < object expression > when < class identifier > do < connection block > when < class identifier > do < connection block > otherwise... ; The evaluation of the object expression results in a reference to the object considered. Once the object is known, its qualification is also known. The qualification is then compared to the classes mentioned in the successive "when" clauses of the connection statement until a class is found that belongs to the prefix sequence of the qualification. The associated connection block is then executed. Inside this block the attributes of the object are referred to, exactly as with local access, by merely mentioning their identifiers. 2.5. ANOTATED EXAMPLE—THE CLASS SIMSET The following is a simplified version of the class SIMSET used for list processing. Symmetric lists are considered. A list is made of a head

78

J. D. Ichbiah and S. P. Morse sue

sue

PRED

PRED

PRED Head

sue

sue Link 2

Linkl

* ' *

PRED Link Ν

(a) List structure

sue

none

PRED

(b) An empty list

FIG.

( C) A link not on a list

4. S I M S E T list structures.

(0) class S I M S E T ; (1) begin (2) class linkage ; (3) begin ref (linkage) S U Q P R E D ; (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) ( 18) (19) (20) (21) (22)

end linkage; linkage class link ; begin procedure out; if S U C =/= none then begin S U C . P R E D :- P R E D ; P R E D . S U C :- S U C ; S U C :- P R E D :- none end; procedure follow (X); ref (linkage) X ; . . . procedure precede (X); ref (linkage) X ; . . . procedure into ( S ) ; ref (head) S ; . . . end link; linkage class head ; begin procedure clear ; begin ref (linkage) X ; for X :- S U C while X =/= this head do X qua link.out end clear;

(23) (24)

end head;

(25)

S U C :- P R E D end S I M S E T ;

:- this head

General Concepts of Simula 67

79

and of links, possibly none if empty. A link does not necessarily belong to a list (see Fig. 4). The class SIMSET possesses three attributes, all of which are classes. These are the class "linkage" (2-4) and its subclasses "link" (5-15) and "head" (16-24). Only the attributes SUC and PRED of the objects of the class "linkage" (3) will be considered here. These attributes may refer to other objects of the class "linkage". It will be seen shortly how objects can be linked to form symmetric lists. Note that in SIMULA the reference variables are initialized to the null reference none. The subclass "link" of "linkage" corresponds to the current list elements with the exception of the head of the list. All the attributes of this class are procedures. These attributes are accessible by means of remote identifiers. Thus in (21) X qua link.out constitutes a call of the procedure attribute "out" corresponding to the object of class "link" which is referred to by X. In instructions (8) and (10) SUC and PRED represent the fields of this object. Instruction (9) is more complicated. In SUC.PRED :- PRED, the variable SUC and the second occurrence of the variable PRED do indeed represent fields of the object referred to by X. On the other hand, SUC.PRED is a remote identifier. Thus that occurrence of PRED represents a field of the object referred to by SUC. Each object of class "link" has procedure attributes namely "out", "follow", "precede", and "into". The procedure attribute "out" of an object of class "link" permits removing that object from the list to which it belongs. The procedures "follow (X)" and "precede (X)" provide for making the object a successor or a predecessor of the object referred to by X. Finally, if S denotes the head of a list, the object will be added to that list as a result of the execution of the procedure attribute "into (S)". The subclass "head" corresponds to the list heads. The procedure "clear" is used for emptying a list. At each iteration of the for loop (20-21) the "link" which is the successor of the "head" is removed from the list. The local qualification "link" is given to the "linkage" X since "out" is an attribute of "link". The loop terminates when the list is empty, i.e., when the successor of the "head" is the "head" itself. In (23) the fields of a list head are initialized. The value of the expression "this head" is a reference to the "head" object being executed. In conclusion note that subclasses of the classes "head" and "link" can be defined in any subclass of SIMSET. The procedure attributes of "head" and "link" can therefore be used on behalf of the compound objects of those subclasses. Such compound objects know, in effect, the fields SUC and PRED on which these procedures operate. Note also that in SIMSET the concepts of list processing were defined without having to take care of the contents of the elements of the lists but

80

/. D. Ichbiah and S. P. Morse

only taking into account the mechanism which permits them to be linked. It is in a subsequent stage, in the definition of subclasses of "head" and "link", that the contents of these elements are defined. 3. Quasi-parallel Systems Simulating a system entails representing the different processes which act in parallel in the system. Usually only a single processor is used to carry out this simulation. This leads to a quasi-parallel representation of a parallel system. The parallel activity phases of different processes are, in fact, treated sequentially but the advancement of system time is done in such a way as to create the illusion of parallelism. There are conceivably a large variety of mechanisms that permit the sequencing of parallel activity phases. The sequencing mechanism of the earlier language SIMULA used a list of event notices. An event notice contains a reference to a process and the "date" when that process must be activated. The event notices are ordered in the list by increasing dates. Hence the processes are treated in the order in which their event notices appear in the list. In the case of continuous simulations, simpler mechanisms can be used. For example, the parallel phases of different processes can be treated successively and in an invariable order. SIMULA 67 puts the sequencing mechanism of SIMULA into the class SIMULATION. It is also possible to define other sequencing mechanisms in SIMULA 67. For this purpose certain notions have been introduced into the language. These are the notions of quasiparallel system, attached and detached component, as well as the procedures "detach" and "resume" which provide for detaching a component and resuming the execution of another component. 3.1. DEFINITION OF QUASI-PARALLEL SYSTEM

The execution of a SIMULA 67 program involves the generation and execution of block instances, of prefixed blocks, and of objects. Consider the execution of a block. This is performed as in ALGOL. Instances of subblocks of a block are created and destroyed as these subblocks are entered and exited. This sequencing does not involve mechanisms other than the normal ALGOL stack mechanism. It is in this sense that these subblocks are said to be attached to the block and belong to the same component as the block. Similarly, an object remains attached to the block calling for its generation until the delimiter end is reached or until a call to the procedure "detach" is issued as part of the execution of the object. As long as the object remains attached, it belongs to the same component as the block. When the delimiter end is finally reached, the object is no

General Concepts of Simula 67

81

longer attached but may still be kept in memory. Such an object can thus have an independent existence as a data structure. It is said to be in the "terminated" state. Consider now the execution of an object which comprises calls to the procedure "detach". The first call to "detach" on behalf of a given object removes this object from the component to which it belongs and makes it an independent component. The object is said to be a detached object. This leads to a multi-component system. The main program and the detached objects are the components of this system. The multi-component system is called a quasi-parallel system. 3.2. SEQUENCING OF THE EXECUTION OF THE QUASI-PARALLEL SYSTEM COMPONENTS

At a given time only one component in a quasi-parallel system is being executed ; the other components are temporarily suspended. The following definitions will be used to specify the sequencing effects of the procedures "resume" and "detach". Definitions —The outer sequence control ( O S C ) of a quasi-parallel system is the point of the system which is being executed at a given time. —The local sequence control ( L S C ) of a component of a quasi-parallel system is : (a) the actual execution point if the component is currently being executed (active component). (b) the point at which execution will be resumed if the component is suspended. At any given time it is clear that the O S C of the quasi-parallel system coincides with the L S C of the active component (see Fig. 5).

OSC Q u a s i - p a r a l l e l system LSC

LSC

Suspended

Suspended

component

component

LSC

Active component

FIG. 5. Sequence controls of quasi-parallel system.

7—AP

·

·

LSC

Suspended component

82

J. D. Ichbiah and S. P. Morse

3.2.1. Effect of "Detach" 3.2.1.1. First call. Consider the first call to "detach" on behalf of a given object which is initially attached and is therefore a part of a component. After "detach" the object becomes an independent component. Its execution is suspended and its LSC is positioned after "detach". The OSC is positioned after the instruction that caused the generation of the object. This is illustrated in Fig. 6(a).

newA

Detach ;

LSC OSC new A ;

Detach;

LSC OSC

CL

S

(a) First call

3.2.1.2. Later calls. Consider an object that issues more than one call to the procedure "detach". The object will be detached after the first call and remain detached when later calls are issued because it is not possible to reattach a detached object. For these later calls, just as for the first call, the LSC of the object is positioned after the call to "detach". But the OSC, on the other hand, takes the value of the LSC of the main program which therefore becomes active. This is illustrated in Fig. 6(b).

Detach;

Main program

LSC

ose

Detach ;

4> LSC

Main program

LSC

LSC OSC

(b) Later calls

FIG. 6. Effect of a call to "detach". 3.2.2. Effect of "Resume" The call of the procedure "resume (Y)" causes the execution of the object referred to by the reference variable Y to be resumed. The LSC

General Concepts of Simula 67

83

of the component containing the call to "resume" is placed after this call. The OSC of the quasi-parallel system takes the value of the LSC of the component referred to by Y. Note that "resume (Y)" can be called by the main program as well as by another component (see Fig. 7). The parameter of the procedure "resume" must refer to a detached object. Specifically, Y cannot refer to a terminated object because such an object no longer has an LSC.

Resume(Y);

(LSC OSC

Resume(Y);

LSC

LSC

LSC

OSC

FIG. 7. Effect of a call to "resume".

3 . 3 . SCHEDULING MECHANISM IN THE CLASS SIMULATION

Simulations describe the behavior of entities called processes which interact during a period of time. The basic problem faced in simulations is that of scheduling the simulated processes. Conceivably this may be done by a scheduler using a tag (event notice) associated with each process. Each tag contains the name of the corresponding process and the time at which that process is scheduled for activity. The scheduler will arrange these tags in chronological order and then always look at the first tag in order to know which process to activate next. The class SIMULATION introduces into SIMULA 67 the notions of processes and event notices along with a scheduling mechanism (see Fig. 8). The class SIMULATION is prefixed by the class SIMSET. This allows the list processing facilities of SIMSET to be used for queuing event notices and for queuing processes. In addition, the scheduling mechanism of the class SIMULATION uses the primitive sequencing procedure "detach" and "resume" to achieve quasiparallelism. The class "event notice" defined in SIMULATION is a subclass of the class "link". Thus event notices have SUC and PRED attributes permitting them to be put on a list called the sequencing set. In

/. D. Ichbiah and S. P. Morse

84

Sequencing set SQS

SUC

Queue -

SUC

PRED

PRED

Head

Head

SUC

SUC

PRED

PRED

h-

SUC PRED

evtime proc Event notice I

Process I

SUC

SUC

PRED

PRED

evtime

event

Process Κ

proc E v e n t notice 2

Process 2

SUC

SUC

PRED

PRED

evtime proc Event notice Ν

Process Ν

FIG. 8. Scheduling mechanism of the class simulation.

addition, event notices have the attributes "evtime" and "proc". The "proc" attribute is a reference to the associated process; the "evtime" attribute is the time at which that process is scheduled for execution. The event notices in the sequencing set are ordered by increasing values of "evtime". Hence the sequencing set represents the simulation time axis. At any stage of the simulation, the value of the simulation time is the value of the "evtime" attribute of the first event notice of the sequencing set. The head of the sequencing set is referred to by the reference variable SQS. The class "process" is also a subclass of the class "link" and thus processes can be put on lists. In addition, a process has an "event" attribute which is a reference to its associated event notice. In most practical simulations the processes considered will actually be objects of subclasses of the class process rather than just objects of the class process itself.

General Concepts of Simula 67

85

SIMSET class SIMULATION; begin link class process; begin ref (event notice) event; detach; inner; passivate ; error end process ; link class event notice (evtime, proc) ; real evtime; ref (process) proc; begin end event notice ; ref (head) SQS; procedure hold . . . ; procedure passivate . . . ; procedure activate . . . ; process class main program; begin L: detach; go to L end main program; ref (main program) main ; SQS :- new head; main :- new main program; main.event :- new event notice (0, main); main.event.into (SQS) end SIMULATION 3.3.1. Sequencing Procedures A process is in one of four states with respect to scheduling. The process associated with the first event notice of the sequencing set is the process currently being executed and is said to be active. The processes which are associated with the other event notices of the sequencing set are scheduled for future execution and are said to be suspended. If a process is not associated with an event notice in the sequencing set it is said to be passive unless its execution has reached the end of the body of the class process in which case it is said to be terminated. An active process can change its own state or the state of another process with a call to one of the following sequencing procedures.

86

/. D. Ichbiah and S. P. Morse

(a) The procedure "hold" stops the execution of the active process and reschedules it for future execution. The next process scheduled for execution then becomes active. The procedure "hold" accomplishes these actions in two steps. First the "evtime" attribute of the first event notice is changed and the event notice is reinserted into the sequencing set so as to maintain the chronological order. Then the primitive sequencing procedure "resume" is called to update the OSC. (b) The procedure "passivate" stops the execution of the active process but does not reschedule it for future execution. The next process scheduled for execution then becomes active. This is achieved by a call to the procedure "resume". (c) The procedure "activate" schedules the execution of a process. It can either schedule the execution of a passive process, thereby making it either active or suspended, or reschedule the execution of an active or suspended process. In this paper the procedure call "activate (X)", with no other arguments, will be used for immediate activation of the process referred to by X. 3.5.2. Scheduling Active Phases of the Main Program To perform a simulation a user will write a main program which is a block prefixed by the class SIMULATION. In the main program will be included the declarations of the subclasses of the class "process" which are needed for the simulated model. Also the main program will generate processes and interact with them. To provide for this interaction it is necessary to be able to schedule the main program. The previous section described a mechanism for scheduling the active phases of processes. Although the main program is not a process, the same mechanism is also used to schedule its active phases. This is accomplished by associating a process "main program" with the main program. Whenever this process is activated, it issues a call to "detach" which has the effect of passing control to the main program. The interaction between the main program and the processes is next illustrated by an example. Consider the simulation of a facility functioning on a first-come-first-served basis. Users arrive at the facility randomly (negative exponential distribution), enter a queue and wait their turn to be served. The first user in the queue is the one being served. When that user is finished with the facility he leaves the queue and passes control of the facility to the user who is then first in the queue.

General Concepts of Simula 67

87

SIMULATION begin Boolean facility busy ; ref (head) queue ; real service time ; process class user; begin into (queue) ; if facility busy then passivate; facility busy := true: hold (service time) ; facility busy:= false; out; if queue.SUC =/= queue then activate (queue.SUC qua process) end user; queue :- new head; service time:= 10; cycle : activate (new user) ; hold(negexp(. . .)); go to cycle end The progression of the simulation is described below. During the initial operations of the class SIMULATION the sequencing set is created and it is initialized to contain the event notice for the process "main program". This is illustrated in Fig. 9(a). Thus when the main program is being executed, the process "main program" will indeed correspond to the first event notice in the sequencing set. Other processes will now be generated and scheduled by the main program. This is done in the "cycle" of the above simulation example; the generation is the result of the evaluation of "new user" and the scheduling is performed by the procedure "activate". Note that the first instruction in the class "process" is a call to detach so after the main program generates a process, control is immediately passed back to the main program. Fig. 9(b) shows the sequencing set at this time. The main program can relinquish control by calling either the procedures "hold" or "activate". In the above example "hold" is called. The primitive procedure "resume" called by "hold" (or "activate") passes control to the process next scheduled for execution and the simulation continues. The sequencing set after the call to "hold" is shown in Fig. 9(c). 3.4. GENERALIZATION: MULTI-LEVEL QUASI-PARALLEL SYSTEMS

Quasi-parallel systems with multiple levels may be introduced by means of prefixed blocks. An instance of a prefixed block is initially detached. The objects generated in the prefixed block and detached by the procedure "detach" form a quasi-parallel system which is at a

J. D. Ichbiah and S. P. Morse

88

sQs —-rf sue

(a) Sequencing set prior to execution of main program

PRED

SUC PRED evtime

^ \\f

SOS

—-^i

11 1 I

proc

Main program SQS -

sue

PRED

sue PRED

sue

none

sue

PRED

none

PRED

event

evtime

Main program

proc

evtime proc

I

1

sue

sue

PRED

PRED

evtime

Events scheduled

proc

during first

evtime proc

execution of

Main program

main program

sue

SUC

PRED

PRED

evtime

evtime

proc

proc

(b) Sequencing set during first

(c) Sequencing set after main program

execution of main program

relinquishes control by calling the procedure "hold"

FIG. 9. Evolution of the sequencing set. different level than the system to which the prefixed block belongs. The degrees of nesting of prefixed blocks correspond to the successive quasi-parallel system levels. For a quasi-parallel system at a given level, the prefixed block and the blocks and objects attached to it act as a main program. Using this definition, the procedures "detach" and "resume" can be generalized for a quasi-parallel system with an arbitrary number of levels.

General Concepts of Simula 67

89

Acknowledgements The authors are grateful to Christian Scherer, Bernard Lang, and Jean-Paul Rissen for their perceptive remarks and suggestions on an earlier version of this paper. This work was sponsored by the Délégation à l'Informatique under contract number 69-02-006-212-75-01. Bibliography 1. DAHL, Ο. J., and NYGAARD, K., SIMULA—A Language for

Programming and Description of Discrete Event Systems. Introduction and User's Manual. Norwegian Computing Center, Forskningsveien IB, Oslo 3, Norway (1966).

2. DAHL, Ο. J., and NYGAARD, K., SIMULA—An ALGOL-Based

Simulation Language. Comm. ACM. 9 (Sept. 66) pp. 671-678. 3. DAHL, Ο. J., and NYGAARD, K., Class and Subclass Declarations. In Simulation Programming Languages J. N. Buxton (Ed.), North Holland, Amsterdam (1968), pp. 158-174. 4. DAHL, Ο. J., MYHRHAUG, B., and NYGAARD, K., SIMULA 67—

Common Base Language. Norwegian Computing Center, Forskningsveien IB, Oslo 3, Norway (May 1968). 5. Ho ARE, C. A. R., Record Handling. In Symbol Manipulation Languages and Techniques J. G. Bobrow (Ed.), North Holland Amsterdam (1968), pp. 262-284. 6. NAUR, P. (Ed.) et al. Revised Report on the Algorithmic Language ALGOL 60. Comm. ACM 6, 1 (Jan. 1963), pp. 1-17. 7. WIRTH,

N., and Ho ARE, C. A. R., A Contribution

to

the

Development of ALGOL. Comm. ACM 9 , 6 (June 1966), pp. 413^32. Appendix A. Virtual Entities

A class defines a model for entities having common attributes. There are cases where an attribute of a given name is to take a different meaning for various subclasses of the class considered. This effect can be achieved in SIMULA by the inclusion of a virtual part in a class declaration. Such a declaration is of the following form: K c l a s s M ( P ) ; S ; V; begin D ; I ; inner; F end

90

D. Ichbiah and S. P. Morse

V designates the virtual part. It is composed of "virtual:" followed by a list of virtual items. These can be labels, switches, or procedures. The rules of concatenation are extended to virtual parts in an obvious way. The meaning of a virtual attribute is determined as follows. Given an object of class N. Suppose that an attribute X is specified virtual in the class M belonging to the prefix sequence of N. An occurrence of X is interpreted as virtual in M and in all classes inner to M. The matching definition for the virtual attribute X is the innermost definition of X. This is illustrated by the following example. The procedure "show" is specified virtual in the class REAL. It is defined in both REAL and in COMPLEX. When "show" is called for X, the definition in the class REAL is used. When "show" is called for Y, two definitions are to be considered. The innermost definition, i.e. that given in the class COMPLEX, is the definition effectively used. begin class REAL (real part); real real part; virtual : procedure show ; begin procedure show; begin outfix (real part, 2, 5) ; outimage end end; REAL class COMPLEX (imaginary part) ; real imaginary part ; begin procedure show ; begin outfix (real part, 2, 5) ; if sign (imaginary part) > 0 then outtext (' + i') else outtext C — i'); outfix (abs(imaginary part), 2, 5); outimage end end; ref (REAL) X; ref (COMPLEX) Y; X :- new REAL (3); Y :- new COMPLEX (2, 4); X.show; Y.show; comment X.show prints 3.00 Y.show prints 2.00 + i 4.00 end

General Concepts of Simula 67

91

Appendix Β. Symbolic Differentiation The concepts of class and prefixed block are illustrated in what follows by their application to symbolic differentiation of expressions. The SIMULA 67 version of this classical problem was inspired by the formulation given by Hoare [5]. DEFINITION OF CLASSES

The class SYMBOL serves as a framework for the definition of the concepts and entities used in symbolic differentiation. Expressions are objects of the class EXPR. This class, its subclasses CONSTANT, VARIABLE and PAIR, as well as the subclasses of the latter—namely SUM and DIFF—are the class attributes of SYMBOL. The reference variables "zero" and "one" which serve to designate the constants " 0 " and " 1 " are additional attributes of SYMBOL. The objects corresponding to these two constants are generated during the initial operations of SYMBOL. The reference variable "delta" is the unique attribute of the class EXPR. Whenever the derivative of an EXPR object is calculated, a reference to this derivative will be assigned to the "delta" field of the object. The procedure "deriv" is specified virtual in the class EXPR. Corresponding to the subclasses CONSTANT, VARIABLE and PAIR of the class EXPR are objects having attributes which are the value of a constant, the name of a variable, and the left and right parts of a PAIR respectively. In addition, the subclasses CONSTANT and VARIABLE of EXPR, as well as the subclasses SUM and DIFF of PAIR, have a procedure attribute called "deriv". Note that a different procedure is defined for each of these subclasses in order to illustrate the level by level elaboration of a SIMULA 67 program. The call to a procedure "deriv" on behalf of a given expression has the effect of calculating the derivative of the expression with respect to the variable passed as a parameter. Furthermore, a reference to this derivative is assigned to the variable "delta". Thus, after the execution of the instruction

92

/ . D. Ichbiah and S. P. Morse L :- M.deriv(N)

the reference variable L refers to the derivative of M with respect to N . Furthermore, the relation L = = M.delta has the logical value true. class SYMBOL; begin class EXPR; virtual: ref(EXPR) procedure deriv; begin ref (EXPR)delta; end EXPR; EXPR class CONSTANT(k) ; real k ; begin ref(EXPR)procedure deriv(X); ref(VARIABLE)X ; deriv :- delta :- zero ; end CONSTANT; EXPR class VARIABLE(id); value id; text id; begin ref (EXPR) procedure deriv(X); ref(VARIABLE)X ; if χ = = this VARIABLE then deriv :- delta :- one else deriv :- delta :- zero ; end VARIABLE; EXPR class PAIR (left, right); ref(EXPR) left, right;; PAIR class SUM; begin ref(EXPR)procedure deriv(X); ref(VARIABLE)X ; begin ref(EXPR) 1 prime, r prime; 1 prime :- left.deriv(X) ; r prime :- right.deriv(X) ; delta :- if 1 prime = = zero then r prime else if r prime = = zero then 1 prime else new SUM (1 prime, r prime); deriv :- delta; end deriv ; end SUM;

General Concepts of Simula 67

93

PAIR class D I F F ; begin ref (EXPR) procedure deriv (X); ref (VARIABLE)X; begin ref (EXPR) 1 prime, r prime; 1 prime :- left.deriv(X) ; r prime :- right.deriv(X) ; delta :- if rprime = = zero then 1 prime else new DIFF (1 prime, r prime); deriv :- delta; end deriv; end D I F F ; ref(CONSTANT) zero, one; comment the initial operations of the class SYMBOL are the following; zero :- new CONSTANT(O); one :- new CONSTANT(l); zero.delta :- one.delta :- zero; end SYMBOL; USING THE CLASS

SYMBOL

Now that the class SYMBOL has been defined, it is possible to utilize the entities defined in SYMBOL inside a block prefixed by SYMBOL. The short program which follows requires the generation of the expression e = (x + y) — (z — 4) using the auxiliary variables u = (x + y) and ν = (ζ — 4). This generation is followed by the calculation of the partial derivative f of the expression e with respect to the variable y. SYMBOL begin ref (VARIABLE) x, y , z ; ref(EXPR)u,v,e,f; χ :- new V A R I A B L E ^ ' ) ; y :- new VARIABLE('y'); u :- new SUM(x,y) ; ζ :- new VARIABLE('z') ; ν :- new DIFF(z,new CONSTANT(4)) ; e :- new DIFF(u,v) ; f :- e.deriv(x) end

Incremental Compilation and Conversational Interpretation M. BERTHAUD IBM France, Grenoble Scientific Centre and M. GRIFFITHS Université de Grenoble, France 1. Introduction In a previous paper [1], a bird's-eye view was given of certain of the ideas involved in the incremental compilation of ALGOL 60 [7] or PL/I [8]. The space allocated by I.F.I.P. did not allow sufficient development of these ideas, as was pointed out by the reviewer of the paper [2]. Apart from necessary expansions of ideas already put forward, further information is now available as a result of the implementation of both languages using the algorithms suggested. Rough measures of performance have been obtained from comparisons of the time taken to interpret particular programs under the incremental system with the time taken to execute the code produced by the standard OS/360 compiler. As expected, these results vary considerably with the type of statement examined. An overall measure of the gains and losses will take much more time, since this can only come from user experience of the system over a period of months, and this only after the users themselves have become proficient. For the ALGOL project, a community of students and research workers should be the first to reach this state. The main technical interest in the projects lies in the interpretation techniques, which are heavily affected by the definition of incrementalism. If a programmer wishes to change one or more increments of an existing segment, the compiler does not consider the contents of any other increments when recompiling the new ones. Since there are no restrictions on the increments which can be altered, this means that the compiler uses no cross-increment information. In particular, uses of identifiers cannot be associated with their declarations until the segment is executed. The increment used is at most one statement or declaration, and in certain cases the increment is less than a statement. In view of the technical emphasis on the interpretation stage, the external specifications and the generator are reviewed briefly in the following two chapters. The rest of the paper contains details of the methods used to store data and to evaluate program and data. The intermediate pseudo-code used for ALGOL 60 is given in an appendix. Although the implementations were carried out on S/360, the description of techniques makes no mention of the particular machine. Β

95

M. Berthaud and M. Griffiths

96

2. User's View of the System The executable unit is a segment, which is itself made up of increments. The concept of program is somewhat weakened, since segments can call each other freely without prior warning being given to the system. A segment is inserted into the system by : 1 2 3 10

segment segmentname

endsegment

The segment name is an identifier. The integers are assigned by the system to the increments of the segment. The contents of each line are treated as successive items ; if more than one increment occurs on a given line, the increment number is augmented accordingly. For example, in ALGOL 60: 1 3 6

segment algol 1 ; begin real x, y ; m:x: = l ; y : = x + l ;

begin, declaration, label and assignment are all increments. Each increment is analysed syntactically as soon as the line is received. If the increment is syntactically incorrect, a message is printed and the increment number repeated until a syntactically legal increment is inserted. At the end of the segment a global check is carried out on the structure of the segment, for example to confirm that begin-end matching is correct. This type of error is not definitive, since it depends on inter-increment effects, which can be changed dynamically. Any existing segment can be executed (interpreted) by execute segmentname. If the segment calls other segments, they will also be interpreted at the point at which they are called. Names are local to their segment, so that association of names across segments is done by the programmer using parameters. These parameters are by lexicographical replacement. For example: 1 5 10 11 1 3 10 20

segment seg 1 ; a := b+ c; nonlocal a; endsegment segment seg 2 ; begin real χ ; include seg 1 using x; endsegment

Incremental Compilation and Conversational Interpretation

97

The nonlocal at the end of seg 1 indicates that a is to be replaced by an object declared in the calling segment. The word include is a call of a segment from another. In the example, seg 2 calls seg 1 with χ as parameter. The replacement of a by χ is a strict name association, a taking the type of χ and referring to the same object. The interpretation of a segment may temporarily cease for one of the following reasons: The statement wait was encountered in the segment. The attention button is pressed at the user console. An error is found. In this state, the programmer may type language statements or editing statements for immediate execution. After each such statement the system returns to the wait state, unless a goto or continue are obeyed. The statement continue is used to leave the wait state in sequential operation. Integers are allowed following goto, but are interpreted as increment numbers in the same segment. The goto is legal if and only if it would be legal to jump to the nonexistent label at the destination. The editing facilities are available during the reception of a segment as well as during interpretation. They are limited to the addition, replacement and elimination of whole increments or sequences of increments and new increments are accepted in the same way as the increments of the original segment. This short overview of the external specifications, which will be completely described in the users' manual, should serve to set the scene for the technical details which follow.

3. Generation Given the original restriction that the compiler must be incremental, it is evident that the generative part of the system is very limited. The transformation of the original text is essentially little more than a recoding, together with syntax analysis on a strictly local scale. The degree of transformation can best be judged by studying the code output from the ALGOL 60 generator, which is given in the appendix. The process of transformation is very rapid. A top-down, deterministic syntax is used, which was produced using a grammar transforming program [3] which stems from work by Foster [4] and Knuth [5]. Semantic functions are called from the syntax to produce the required output. The axiom of the analyser is a single increment and thus the generator is a routine which is called whenever a new increment needs to be treated either when entering a segment at the console or as a result of an edition. The pseudo-code produced by the generator for successive increments is placed in a buffer, which is transferred to the disc when filled. Because of edition, the order of arrival of increments is not necessarily their true lexicographical order. The pseudo-code is nevertheless left in the order in which it arrives, possibly wasting space since some of it may no longer be accessible, and the chaining between increments is done by means of a control dictionary. This contains one entry per increment, and is a summary of the state of a segment. Entries are arranged by increment number, and contain the number of the lexicographically following increment, the type of the increment, and a pointer to its pseudo-code. If a segment is entered sequentially, the lexicographically following increment has the next number, but after editing this is not so.

98

M. Berthaud and M. Griffiths

For example: segment seg 1 ; 1 begin real χ ; 3 χ : =y 10 10 11 11

after 2 integer y; endedit

The user arrives at increment 10 before realising that he wished to declare y as well as x. He can in fact write this declaration anywhere in the block, but let us suppose that he wants it to be after real χ ;. after 2 is an editing command which inserts successive increments until another command is reached. As a result the increment number 10 is considered to follow the increment number 2. The control dictionary will be :

To pseudo-code

A further advantage of this control dictionary will be seen when we consider the interpretation of pseudo-code; it contains the structure of the segment, and it is possible to decide which statement to consider next during execution without consulting the psuedo-code. The form of the pseudo-code is important. It must be compact, interprétable and symmetric, that is that the original text can be deduced from the pseudo-code (perhaps losing layout features). It is normally in functional notation, apart from the expressions, which are in reverse Polish. A normal segment fits into a pseudo-code buffer of 1024 bytes. Segments are limited to 256 increments and 128 identifiers. These limitations allow generation always to take place in a standard data zone of 4096 bytes/terminal. The ALGOL 60 language as normally implemented (that is no integer labels, no dynamic own arrays, fully specified parameters) is accepted, with local style input/output. For PL/I, more restrictions have been made, since we have no ambitions in the field of producing subroutine libraries. Let us consider a particular segment and its corresponding pseudocode and dictionaries : 1 3 4 5

segment example of generation; begin real a, b; integer array i[l : 100, 1 : 2] ; integer ρ ; for ρ : = 1 step 1 until 100 do

Incremental Compilation and Conversational Interpretation

99

begin read (a, b) ; i[p, 2] : = a + b ; i[p, 2] : = a * b end

6 8 9 10 11 12

end endsegment

After reception of the segment, an identifier dictionary, a control dictionary and a buffer of pseudo-code have been produced : A Β I Ρ READ

1 2 3 4 5

IDENTIFIER DICTIONARY

The unfilled spaces contain the internal representation of blank. 1 2 3 4 5 6 7 8 9 10 11 12

begin real int arr int for begin procst ass ass end end endseg 1 byte

2 3 4 5 6 7 8 9 10 11 12 0

Pointers to pseudocode

1 byte

2 bytes

CONTROL DICTIONARY

100

M. Berthaud and M. Griffiths

The pseudo-code is given below, with comments in brackets and starting a new line for each increment : (none for begin) 2 (number of identifiers) 1 2 (their codes) 1 (number of groups with bounds) 1 (number of identifiers with same bounds) 3 (name of identifier) 2 (number of dimensions) 3 1 9 3 100 9 3 1 9 3 2 9 (four expressions). 1 4 1 (simple varï 4 3 (type of for-group) 3 1 9 3 1 9 3 100 9 (three expressions) (none for begin) 5 2 (number of parameters) 1 1 9 1 2 9 (two expressions) 1 (number of left-hand sides) 2 (subscripted variable) 3 (name) 2 (number of subscripts) 1 4 9 3 1 9 (two expressions) 1 1 1 2 17 (plus) (right-hand side in reverse polish) 9 1 2 3 2 1 4 9 3 2 9 1 1 1 2 19 (times) 9 (none for end end endseg) This example should give the flavour of the transformation made by the generator.

4. Interpretation The main elements used by the interpreter are the control dictionary and pseudo-code provided by the generator, a symbol table, and a stack. The symbol table has one entry for each name used in the segment being interpreted, and this entry points at (contains the displacement of) the most recent occurrence of a value of the corresponding name. Values are kept in the stack, along with a great deal of other necessary information, and hence pointers to values are displacements from the stack base. Obviously, the symbol table is used to perform the association of references to names with their declarations. One of the effects of incrementalism is to complicate this process, for which the algorithms will be given in later chapters. In particular, name association must be done by the interpreter during a second pass of the source text, the first being taken up by the dynamic exedution of the declarations. We will show that, for PL/I, the execution of the declarations is itself a multi-pass process. The existence of the control dictionary is particularly important in the control of the different passes. In fact, each pass is not a pass of the source text, but of the control dictionary, and is usually limited to one block. Since the control dictionary contains the type and the order of the increments, it contains implicitly the structure of the program. It is thus possible to select the next increment to be obeyed dynamically in function only of the control dictionary, thus avoiding unnecessary references to the pseudo-code. Since the pseudo-code is paged on the disk, this can lead to important savings of system time in some cases. The interpreters themselves are written in the OS/360 assembly language, which has been augmented by macro-definitions [6] to allow the use of recursive procedures, conditions, loops and expressions in a form which resembles ALGOL 60. It was originally thought that the recursive procedures would allow the interpreter to model directly the recursive structure of the languages.

Incremental Compilation and Conversational Interpretation

101

For example, we would like to treat a compound statement as : ROUTINE COMPOUNDST WHILE B, STATTYPE, NE, END CALL OBEYSTATEMENT CALL GETNEXTSTATEMENT END WHILE RETURN If one of the statements inside the compound statement is itself compound, this leads to a harmless recursive call of COMPOUNDST. Unfortunately this technique does not work, since if a goto is obeyed which leads to a non-local label the recursion must be broken. It is easy enough to change the level of the data stack, and this is done as it is necessary, but the stack of return points controlling the interpreter routines is a different matter. This problem is more fully treated in the next chapter. This difficulty is typical of the difference between compilation and interpretation, and it is due to the fact that the decision of what to do is not treated independently of the execution of the action. It has been suggested that interpretation is easier for the compiler-writer than is compilation. In our view this is only true for trivial languages, the opposite being true for heavily-structured languages.

5. Structure of the Stack We have already seen that the entry in the symbol table corresponding to a particular name points at the most recent occurence of that name in the stack. Occurrences are put on the stack by the execution of a declaration of the name. If the name already existed in another block or in a previous and still current activation of thé same block, this previous occurrence must not be lost. Thus each occurrence on the stack points to the preceding occurrence of the same name, if one exists. Since the type of objects is also considered during the interpretation, the stack entry for a simple variable is a triplet of the type, value and a pointer to the preceding entry for the same name. In the case of ALGOL 60 on the 360 computer, this entry takes two words :

Value

.Stack

Type

-Pointer

The type is 1 byte, the pointer 3 bytes and the value one word. The more varied and more complex data types of PL/I require more space. In particular, the type of ALGOL 60

M. Berthaud and M. Griffiths

102

becomes an attribute symmary in PL/I, and this takes up a full word. Thus the minimum entry for a PL/I variable is three words. In general the life of a name is the same as the life of the block in which it is declared. At the end of a block its local names are "dedeclared", that is to say that the corresponding symbol table entries are replaced by the values they had at the start of the block. These values are found in the pointer field of the stack entry, since the pointer is to the preceding stack entry for the name. The current block level in the stack is kept in a particular memory location, and each block entry points to the preceding block entry. Let us consider a simple example in ALGOL 60: 1 2 •··

begin real a, b; begin integer b,c; ... A end

end

At a point A in the internal block, the stack and the symbol table would be :

Direction of g r o w t h Value

int

0

Value

int

Block 2 . Current block level

S y m b o l table Value

real

Value

real

0

0

Block I Stack

This simple identifier and block chaining is the basis of all the storage allocation and variable retrieval used in the compilers, but needs some improvement to treat certain particular cases which arise in ALGOL 60 or in PL/I. In particular, the search for non-local variables in the stack requires a second pointer in the case of procedures. Consider the

Incremental Compilation and Conversational Interpretation

103

ALGOL 60 program : 1 2 3

begin real x; procedure f ; begin χ : = 1; end; begin integer χ ; f; end end

Procedure f is called from block 3, and at the moment that the assignment to χ in block 2 is executed, the stack and the symbol table will be :

Block 2 (proc f ) Integer χ Block 3

S y m b o l table

Real χ Block I Stack

The most recent declaration of χ is in block 3, but the χ required is the χ of block 1, since block 2 is lexicographically contained in block 1 and not in block 3. To avoid referencing the wrong x, a second pointer is needed in the case of procedures, which indicates the lexicographically containing block. We call this pointer the static pointer, the pointer to the calling block being the dynamic pointer. A static pointer is needed for procedures and in the case of the evaluation of an actual parameter corresponding to a formal parameter by name. The use of two pointers in this latter case is already known in ALGOL 60 compilers. The pointers described above are sufficient to find all variables in ALGOL 60 and most in PL/I. The algorithm for a reference is the following: 1. Consider the address given by the relevant entry of the symbol table. If this address is in the current block, the reference is to a local variable and is given directly; otherwise the reference is non-local. 2. Consider the non-local address to decide if it is in scope. To do this, follow the static chain up to its first value before the address considered. 3. Follow the dynamic chain to its last value before the value found on the static chain. 4. These two values now enclose a block. If the address considered lies between them, the reference is found. Otherwise consider the next address in the identifier chain. 5. If this address is still higher in the stack than the static pointer value considered, go back to 4; otherwise go back to 2.

M. Berthaud and M. Griffiths

104

This process will always find an ALGOL 60 reference, if one exists, but needs modification due to the attributes INTERNAL/EXTERNAL, AUTOMATIC/STATIC/CONTROLLED /BASED in PL/I. References to arrays are done by the normal extensions to simple references, but references to structures need thought. In PL/I structure references would normally be evaluated at compile time, but this cannot happen in incremental mode. The organization of the structure is modelled in the pseudocode, so that with each element is associated its level number and the names of any immediate successors. For example, in DCL

la, 2 b FIXED BIN, 2 c, 3 a CHAR (10), 3 d FIXED DEC;

The element a is of level 1 and is followed by the names b and c. The generator detects multiple declarations, like DCL 1 x, 2y, 2y; The interpretation can stack directly the information given in the pseudo code and also test the compatibility of the declaration with the others in the same block; thus the element at level 1 must not be declared at this level elsewhere in the block. However, a name declared at a level other than level 1 can occur in declarations in the same block. Reference can be made to particular elements or sets of elements either by simple or by qualified names. The rules which decide whether the reference is legal are complicated, depending in thefirstinstance on the distinction between complete and incomplete references. A complete reference is one in which each occurring name which is not of level 1 is preceded by the name of the immediately including name, the two names being separated by a decimal point. We note that a complete reference is always unique in any block, since no name can have more than one declaration at level 1 and no two immediate substructures of the same structure element can have the same name. Complete references take priority over incomplete references, but if a simple or qualified name is not a complete reference, it must correspond to only one incomplete reference. In the previous example declaring the structure a : a is a complete reference to the whole structure, taking priority over the possibility of its being an incomplete reference to the element at level 3. a.c.a is a complete reference to the level 3 element. a.a and c.a are (legal) incomplete references to this same element of level 3. In the declaration DCL 1 p, 2q;

Incremental Compilation and Conversational Interpretation

105

p.z is an ambiguous incomplete reference, since there are two possibilities. The diagram shows the stack and symbol table corresponding to the original example :

Thus the general algorithm treating simple or qualified references in PL/I is the following: 1. Apply the ALGOL 60 algorithm to the first name in the reference. If the reference is qualified, go to 4. 2. The reference is unqualified. If the level number of the element found is equal to one, the element is the one referred to. 3. The level number of the element found is greater than one. Find any other references to the same name in the same block. If there are no others, the element is found. If a reference to a level one object exists, this is the correct one. If more than one reference exists in the block, and none of them is of level one, the reference is ambiguous. 4. The name is qualified. Search for a complete reference in the block. If none is found, then search for all incomplete references. If there is more thah one incomplete reference, the reference is ambiguous. 5. Search for a complete reference. If the first name in the element found is of level 1 and is not a terminal element, go to 6, otherwise go to 7.

106

M. Berthaud and M. Griffiths

6. The structure is searched directly for a complete reference. If one is found, it is the reference sought, otherwise go to 8. 7. Search the other entries on the identifier chain for an element in the same block which is non-terminal and of level 1. If one is found, go to 6. 8. No complete reference exists in the block. Find all possible incomplete references in the block. If there are none, go down the identifier chain to an including block and go to 5. If there are more than one, there is an error. If there is exactly one, it is the reference sought. Finding incomplete references is a tree search in which nodes may be jumped, which is a long process. An initial check to see if all the names of the reference are included within the part of the stack to be searched usually saves time. Obviously, if the end of the identifier chain is reached at any stage, the reference does not exist. A further chain is established in the stack to cope with the problem of recursion introduced in the previous chapter. This chain, called the scope chain, indicates which statements are contained in other statements. For example, consider the following portion of an ALGOL 60 program : if χ > 0 then begin for i : = 1 step 1 until 10 do begin a [i] : = a [i] + χ ; χ : - χ+ 1 end end When the assignment is made to χ inside the loop, the scope chain in the stack will be:

Compound st.

For st.

Compound st.

Conditional st.

Space in the entry for the for statement will also be used to indicate the current state of the for list. The scope chain is used to check that the current increment is permissible in the context— for example, that an else is preceded by an if then pair. It is also used to control the sequencing of increments, as detailed in the next chapter, and in the execution of the goto statement.

Incremental Compilation and Conversational Interpretation

107

6. Evaluation of Declarations On entry into a block, the local identifiers must be declared before executing the instructions within the block. In ALGOL, the compiler accepts declarations anywhere in the block and not only at its head. So it is necessary to see all the increments of the block, in order to declare the identifier appearing in declarations or as labels. There are two problems : 1. Find the end cf the block. 2. Ignore declarations in nested blocks, but declare the labels in nested compound statements. The control dictionary is used to detect the structure of the segment. Declarations are immediately interpreted by up-dating the Symbol Table and allocating space in the stack for the type and the value of each identifier; the same process is applied to labels. When a procedure declaration is encountered, the procedure identifier is also declared and the body of the procedure is skipped. When a begin is found, the type of the following increments is checked; if a declaration appears, it is a block and the corresponding end is found; otherwise, it is a compound statement and, in a second pass, the labels are declared. At the end of the current block, control returns to the beginning and the executable statements are interpreted according to the order given by the Control Dictionary. It should be noted that, in ALGOL the declarations in a block are independent and the expressions appearing as bounds of an array must only invoke variables declared in an outer block. In PL/I it is more difficult to find the end of a block, since the same END can close several blocks or DO groups. For example : 1

ρ : PROC OPTIONS (MAIN);

5

lab(2) : loop : . . . ;

10 11

χ :PROC ; DCL ζ FLOAT ;

14

y : ENTRY ;

20

continue : DO . . .

28 29 30

END χ ; DCL i FIXED BIN, lab(10) LABEL; END ;

On entry to p, the variables i, lab, loop, χ and y become active, but the declarations of ζ and continue do not. The END χ in line 28 closes the procedure χ and all other blocks or DO-groups within x. Thus the DO of line 20 is also closed. Thus the structure of a PL/I program depends not only on the Control Dictionary, but also on the labels (simple labels only) which are attached to BEGIN, PROC or DO. This structure information is thus stacked, and the right number of closures done for a multiple END, testing first that the label exists. Line 14 of the example shows up another problem, which is that of the secondary entry

108

M. Berthaud and M. Griffiths

point, y exists at the same level as the primary entry point χ of the procedure, that is in the block containing the block in which it occurs. To avoid confusion, the PL/I interpreter does a preliminary pass of a segment to define its structure. The control dictionary is at this moment slightly changed to include the number of the increment containing the corresponding END in the case of BEGIN, PROC and DO statements. Since the segment can be changed by edition, this operation is performed each time the segment is edited. To an incremental compiler, the declarations are normally interpreted in the order given by the control dictionary. However, in PL/I, the declarations within a block can be interdependent in such a way that the order of'evaluation becomes important. For example: 1 example : PROC ; 2 DCLa(x); 3 DCL χ FIXED BINARY INITIAL (10); The declaration of x, together with its initialisation, must be performed before the declaration of a. In general, the operations performed at the head of a block constitute the prologue. The language [8] defines the list of items which are available at the start of the prologue (for example variables declared in enclosing blocks) and the list of items which become available as the prologue progresses (automatic variables declared in the block, etc.). The prologue may need to evaluate expressions, concerning only automatic and defined data, in lengths, bounds, area sizes, and in. the INITIAL attribute as iteration factors or as arguments in the CALL option. These references are dynamic in the sense that they make use of the value of the variable concerned. Inversely, the attribute LIKE considers only the description of the structure referred to and then creates new names without evaluating. In other cases, such as CONTROLLED and DEFINED, there exist expressions which refer to names, but these expressions are evaluated either when storage is allocated or when the variable is used. The different memory classes in PL/I require different treatment. AUTOMATIC variables go on the stack, as in ALGOL 60, but STATIC variables require the value to be kept alive between activations of the block in which they are declared. In a batch compiler the STATIC memory is allocated at compile time and is treated, like the ALGOL 60 own, as if it were declared in the outermost block. This method is not easily applicable in the incremental compiler since the concept of outermost block is weakened and also the attribute LIKE can be applied to a STATIC structure. This latter implies the recognition of the name following LIKE before the name has been declared. It will therefore be necessary to separate the notions of name and value of identifiers, since these do not always have the same scope, and divide the prologue in two. 1. Reserve all the names declared in the block being activated. 2. Allocate memory, initialising as required. We suppose that all identifiers are explicitly declared. This simplifies the compiler, since implicit and contextual declarations have the whole program as their scope, which at best implies a reorganisation of the stack and at worst a problem of transfer of names across segments. In an incremental compiler it would be preferable to declare the identifier locally and AUTOMATIC.

Incremental Compilation and Conversational Interpretation

109

The control dictionary indicates those statements which must be examined during the first phase of the prologue (DECLARE, label, etc.). The corresponding pseudo-code is examined and an entry is made in the symbol table to reserve each name. The symbol table entry points to a stack entry which contains the following information: previous stack entry of the same name; type (for example label, static, etc, but not a full description); where to find the attributes (increment and pseudo-code address), or the value in the case of label constants ; pointers to immediate sub-structures for structure variables; flag indicating that the memory space is not yet allocated, and thus that the variable cannot be used in an expression ; indications of particularities, for example that an expression is contained in the declaration or that the attribute LIKE is present, etc. During this pass, multiple declarations are detected, This is not always trivial, since the label attached to PROC, for example, can also be declared, but not be used as a label elsewhere in the same block. In a second scan, names affected by LIKE are evaluated, and any new names produced by this process are reserved. The storage allocation scan can now be carried out, except for the case of CONTROLLED and BASED variables, which are allocated by the programmer. The STATIC variables within the block are allocated a continuous zone in the stack, zones corresponding to the STATIC variables of different blocks being chained together. Allocation of STATIC space is only done the first time that the block is entered, since it is kept until the end of.the program. Thus, at the end of a block, the STATIC space is attached to the enclosing block, which sometimes leads to recopying of STATIC values to a lower level. The memory allocation consists of replacing the address of the pseudo-code by a pointer to an attribute list and space for a value. If the block has previously been active its STATIC zone is found on the STATIC chain and the pointers recalculated. If STATIC declarations are altered during the course of an interpretation, the interpretation should restart to take the changes fully into account. The example shows the stack and symbol table after execution of the prologue to block 5 :

Value = 5 attributes

Pointer to last static zone

Static chain Static Symbol table

Stack

M. Berthaud and M. Griffiths

110 Program : 1 BEGIN;

5 BEGIN; 6 DCLi STATIC INIT (5); 10 END; 11 END; For DEFINED variables, memory space cannot yet be allocated, although their complete attribute list must be obtained. This can require the evaluation of expressions. The value of such a variable is the pseudo-code address, so that the code is interpreted at each reference AUTOMATIC and DEFINED variables are artificially put into two categories. declarations in which the attributes contain expressions referring to names; declarations in which the attributes either contain no expressions or only constants. This second category can be treated immediately. At the same time the declarations of the former category are analysed and a list made of the names they reference. In a second pass, these declarations are examined cyclically. If a declaration refers only to names which have been treated, it also can be treated. If at any time no declaration can be treated, then there exists an interdependence, otherwise, at the end of the process and after a number of unlimited cycles, all the declarations have been treated. For completion, we note that EXTERNAL variables require that the name itself shall be known to the interpreter. Finally the prologue initalises arrays of AUTOMATIC LABEL variables. ALLOCATE and FREE are instructions which allow the user to allocate or liberate memory corresponding to previously declared variables. This requires interpretation of the corresponding declaration and the existence of a second zone of storage, since such quantities are not kept on the stack.

7. Evaluation of Particular Statements We discuss in this chapter certain problems arising from particular constructions in the languages. The scope chain was introduced in ALGOL to treat statement nesting. In general, at the end of each statement interpreted, the first element of the scope chain is examined. The following actions are taken, depending on the type of this element. if. The then part has been obeyed. If an else exists, the else clause is skipped. An else encountered elsewhere is illegal. The if is removed from the scope chain and the next element examined. for. The condition for continuation of the loop is found in the pseudo-code of the for statement. If the for is terminated, it is removed from the scope chain and the next element examined. procedure. The procedure is completed and the return point is found. The procedure is removed from the scope chain. If the procedure returns a value, control is passed to the

Incremental Compilation and Conversational Interpretation

111

expression containing the call, otherwise the next element on the scope chain is examined after the return, but before the following increment is obeyed. begin compound statement or block. The normal state and the one which allows continuation without looking at further elements of the scope chain, begin is obviously removed by the corresponding end. The scope chain also serves to confirm the legality of statements in their context, for example that else follows if then and that then if and then for are not encountered. In PL/I, since the program structure is treated at the start of interpretation, the different parts of the conditional statement are chained. The general form is: IF expression THEN instruction 1 ; [ELSE instruction 2;] instruction 3 The square brackets indicate that the ELSE part is optional. In the control dictionary, the IF increment points to the ELSE (if it exists) or to instruction 3. Thus, since DO groups are included in the block chain, PL/I does not use a scope chain. Since DO is also terminated by END this is more practical in the particular case of PL/I. In both languages, the interpretation of a GOTO uses the block chain and in ALGOL the scope chain. The value of a label is in two parts : the number of the increment; block level at its "declaration". The algorithm is the following. 1. If the block level of the label is higher than the current block level, there is an error. This can only happen in PL/I with a program like: 1 2

BEGIN; DCL 1(10) LABEL;

10 11 15

BEGIN; p: . . . id) = p;

20 21

END; GOTO 1(1);

30

END;

The label 1(1) referred to in 21 is declared, but its value is not. Since variables are "dedeclared" at the end of their block, a jump to a non-existent label is normally shown up by the absence of an entry in the symbol table. 2. If the label is declared in an enclosing block, the block chain is used to close the right number of blocks. 3. The label and the program are now at the same block level. There can be two further difficulties : the GOTO can leave an internal statement (DO group in PL/I or IF, FOR or compound statement in ALGOL). The scope and/or block chain can be affected; c

112

M. Berthaud and M. Griffiths

the GOTO causes a jump into an internal statement. This can be an error, for example into an iterative DO in PL/I, or require additions to the scope chain, for example jump into a compound statement in ALGOL. The considerations outlined above imply that the interpretation of a GOTO cannot be done directly from the pseudo-code and the stack, but needs an analysis of the control dictionary to determine the contexts of the GOTO and its target.

8. Conclusion The compilers described here represented interesting projects from the programming point of view, but are not necessarily economic in a commercial environment. First steps towards a decision concerning the viability of the products are measurement and use in a real system. Both of these are under way, but of course the first is easier than the second. The method of measurement chosen was the simplest—to compare the performances of the standard IBM compilers and ours. The results are not surprising, since they reinforce intuitive judgements. The incremental generators are about ten times faster than their batch counterparts, since they do much less work. The comparison of execution speeds is heavily dependent upon instruction type, but for PL/I the factor is about 100. The ALGOL interpreter runs about twice as fast as the PL/I, and since the batch ALGOL is worse than the batch PL/I the ALGOL figures can be made artificially reasonable. The reasons for the factors are obvious—interpretation at this level automatically costs at least an order of magnitude in efficiency, and PL/I is much more complicated than ALGOL. In particular the number of data types in PL/I implies that the routines which fetch variables and evaluate expressions will take a long time. Since descriptions of variables are also held at run time, PL/I is also much more expensive in terms of space. Outside the student environment these figures probably mean that the system is uneconomic. Students tend to have an execution time which is negligible compared with initialisation and loading. For commercial exploitation a pre-interpretation phase would be necessary, which at least constructs the symbol table for a segment and does name association. This operation would be repeated after edition, and its impact on the reactive facilities would need to be considered. Acknowledgements We would like to thank the various members of the IBM France Scientific Centre and the University of Grenoble who have contributed to these projects. Appendix. Pseudo-code for ALGOL 60 The pseudo-code is given in the form of a grammar with the following conventions : Characters between square brackets are in the control dictionary. Characters between round brackets are in the pseudo-code. Characters not between brackets are class names of the grammar. An asterisk indicates repetition.

Incremental Compilation and Conversational Interpretation Increment

Begin End Label Declaration If Else Goto Procedure For Assign Vide

Begin ~> [25] End -> [26] Label [29] (Index) Declaration -> Simpledec Arraydec Procdec Switchdec Labelspec Stringspec Valuepart Simpledec -> [Type] Idlist Type -> Real Boolean Integer Real 1 Boolean -> 2 Integer -> 3 Idlist -> (Numberofids Index*) Arraydec -> [4] Arraylist [4 + Type] Arraylist Arraylist -> Idlist Boundedlist Boundedlist -> Boundedarray Boundedarray Boundedlist Boundedarray -> Idlist (Numberofdimensions) Ex* Procdec -> Proctype Idlist Proctype Id Parpart Proctype -> [20] [20 + Type] Parpart -> (Pars) Idlist Switchdec -> [16] (Index Numberofelements) Ex* Labelspec -> [17] Idlist Stringspec ^> [24] Idlist Valuepart -> [19] Idlist

113

114

M. Berthaud and M. Griffiths

If-> [30] Ex Else-> [31] Goto ~> [32] Ex For [27] Var Forgroup* Forgroup -» (1) Ex (2) Ex Ex (3) Ex Ex Ex Procedure -> [33] (Index Numberofpars) Ex* Assign -> [28] (Numberofleftsides) Var* Ex Vide -» [34] Ex -> Exel* (9) String Exel -» Const Var Operator Bracket Function Condition Const -> (Consttype Value) Consttype -» Shortint Longint Realconst Booleanconst Var -> (1 Index) (2 Numberofdims) Ex* Function -> (10 Numberofpars) Ex* Condition -> (11) Ex (12) String -» (Numberofchars Char*) A new line indicates an alternative. Certain obvious expansions are not given, for example 'numberofpars' is any integer. 'Index' is the address of an identifier in the name table. The grammar should be treated as indicative rather than definitive.

References 1. M. GRIFFITHS, M. PECCOUD and M. PELTIER, Incremental interactive compilation, Proc. J.F.I.P., August 1968. 2. W. D . SKEES, Review of réf. 1, Computing Reviews, November 1968. 3. M. GRIFFITHS and M. PELTIER, Grammar transformation as an aid to compiler production, IMAG, February 1968. 4. J. M. FOSTER, A syntax improving device, Computer Journal, May 1968. 5. D . E. KNUTH, Top-down syntax analysis, Copenhagen, August 1968. 6. M. GRIFFITHS and M. PELTIER, A macro-generable language for the 360 computers, Computer Bulletin, November 1969. 7. J. W. BACKUS et al, Report on the algorithmic language ALGOL 60, CACM, December 1960. 8. IBM System/360, PL/I Language Specifications, IBM Form Y33-6003. 9. B. Randell and L. J. Russell, ALGOL 60 Implementation, Academic Press, 1964.

Dynamic Syntax: A Concept for the Definition of the Syntax of Programming Languages Κ. V. HANFORD and C. B. JONES Product Test Laboratory, IBM United Kingdom Laboratories Limited, Hursley Park, Winchester, Hampshire ABSTRACT. It is well known that the syntax of declarative programming languages is not context-free, and that this is due to their ability to declare names which may then occur only in spécifie contexts. This report explores the idea that declarations modify the context-free grammar of any program in which they appear. The name dynamic syntax has been given to this concept. The report presents a functional formulation of dynamic syntax and applies the resulting metalanguage to the description of the syntax of Algol 60.

1. Introduction The subject of this report is the formal specification of the syntactically valid programs in a declarative programming language. Conventionally, such a specification takes the form of a context-free grammar. However, the context-free grammar always specifies some superset of the actual set of valid programs. The members of this superset which are truly valid programs are those which satisfy a number of additional syntactic constraints which the context-free grammar is unable to express. Current practice is to express these additional constraints informally as a set of rules which require that certain relationships exist between the declarations of names and their use elsewhere in the program. The report explores the notion that the declarative statements of a program construct a context-free grammar for the imperative statements of that particular program, and that the required relationships can be represented by the rules for constructing this grammar. The concept has been termed dynamic syntax since it implies a dynamic context-free grammar. Using the language of the lambda-calculus, the report gives a functional realization of dynamic syntax, allowing the construction of an expression which denotes the set of language strings of a given programming language. In the Appendix the method is applied to the description of a large subset of Algol 60f. 2. Context-free Languages A context-free language is defined in the following way : A vocabulary Κ is a finite set of symbols. A string over the vocabulary is a finite sequence of these symbols. The set of all strings over Κ (where the set includes the empty string) will be t All subsequent, unqualified references to Algol should be taken as references to Algol 60.

115

116

Κ. V. Hanford and C. Β. Jones

denoted by V*. Arbitrary symbols will be denoted by upper-case Latin letters A, B,. . . and strings by lower-case Latin letters a, b , . . . . A context-free grammar G consists of :

1. A vocabulary V. 2. A non-empty subset of the cross-product set V V*. Let (A,a) be a pair belonging to this subset. Then (A,a) is called a production rule and the binary relation between the symbol A and the string a is denoted by A -> a. A symbol of F which occurs as the left hand element of some production rule is called a nonterminal symbol. A symbol for which there is no such production rule is called a terminal symbol. 3. One of the nonterminal symbols, S, called the sentence symbol. Define the binary relation -> between strings by: a

l >

b = (3 x, y, z, W) (a = x W y, b = χ ζ y, W -> ζ)

If a J-> b, we say that a directly produces b. This means that b can be obtained from a by the application of some production rule. Now define the binary relation ΐ> between strings to be the transitive closure of j^, i.e. a ï> b = (a = b) or (a

b) or ( 3 c) (a ±> c and c Λ> b)

If a 1> b, we say that a produces b. This means that b can be obtained from a by a sequence (possibly empty) of applications of production rules. Then, the context-free language L with grammar G is defined to be the set of strings, over the terminal symbols, which are produced by S. That is, if Tis the set of terminal symbols, then: L={xer*|S^x} As an example of a context-free language, the set of strings of a's and b's of the form: a ... a b ... b where the a and b sequences are of arbitrary non-zero length, is defined by the grammar: vocabulary: a, b, A, B, S production rules : S ->AB A->a A-^Aa B->b Β ->Bb sentence symbol : S This grammar has terminal symbols a, b and nonterminal symbols A, B, S. Some further terminology: A terminal string is a string over the terminal symbols. A phrase is a terminal string produced by a nonterminal symbol. Suppose A is a nonterminal symbol. Then a phrase produced by A is called an Α-phrase and the set of all phrases produced by A is called the Α-phrase class. We now introduce a variant of the above notation for context-free grammars which will be more convenient for development in the sequel. A nonterminal symbol is written as a descriptive multi-character identifier, possibly hyphenated, e.g. simple-arithmetic-expression. A terminal symbol is either a single character, e.g. q, or an identifier in bold type, e.g. then. We generalize the idea of a terminal symbol and use it to denote a string which we choose to leave undefined. This allows us to shorten grammars by using symbols like letter, letter-or-

Dynamic Syntax: Concept for Definition of Syntax of Programming Languages 117 Λ

digit. The operation of concatenation is indicated explicitly by the infix operator . The right-hand side of a production rule can contain any number of direct productions for the left-hand nonterminal, separated by the operator | ('or'). As an example, the definition of a simple arithmetic expression in Algol may be written : Λ

simple-arithmetic-expression -> term | adding-operator term | Λ

Λ

simple-arithmetic-expression adding-operator term We shall refer to such a multi-production rule simply as a production rule (or rule). The affinity with the BNF[1] metalinguistic formula: (simple arithmetic expression) : : = | (adding operator) | v() Ε -> the routine (μ : Ε ) μ -> union (. . . , μ,. ..) 'integer -» equivalent real real -> equivalent complex bits, bytes -> their field > V -> (v), W i t h μ -> TOW μ

η -> (η), with ref μ ref row μ ^empty -> ( ) provides goto 1 or skip or nil with a mode ν ignored

(g) Hipping (h) Voiding

χ + 3.14 χ : = random proc real ρ = χ + 3.14 union (int, real) ir : = 1 x: = 1 string s : = "a" [1:0 flex]real s : = χ : = skip . . . ; χ : = 1; . . .

The coercion package. Syntactic positions differ in the combination of coercions they allow. There are four kinds of positions, allowing successively less combinations, in particular less choice of the coercion at the top level. Position: Strong

allows next: (a)-(h)

Firm Weak Soft

(aHd) (a), (b) (b)

characterization! examples: μ completely given; e.g. rhs of : = or id-decl, actual parameters, conditions, subscripts e.g. operands, the Ρ in a call P( . . . ) e.g. the Ε in E [ . . . 1, id of Ε e.g. lhs of : = , : : =

(A fifth kind would be: allowing no coercion at all. There is only one such case: the rhs of : : or subsection 2.4 (j).)

= , see

Related restrictions. The reason why argument positions of operators are (only) firm is that otherwise one would be unable to decide, for example, whether a particular use of an operator identifies its declaration for real or that for int arguments. On the other hand, the two declarations must not have too similar argument modes, e.g. int and ref int, because firm coercions are allowed; more precisely: 1. There are no two declarations of the same operator at the same block level, in which all corresponding argument modes are firmly related, i.e. reachable through firm coercion from a common third mode. An analogous restriction is necessary for making uniquely distinguishable the alternatives of a unionmode: 2. There is no declarer specifying a union-mode two of whose non-union alternatives are firmly related. Balancing. Where several subpositions determine the mode of a given position, only one of them need be firm/weak/soft if the given position is ; the others may be strong. EXAMPLE: In if ρ then 5 else 3.14 fi the 5 will be widened regardless of the position of the conditional.

Appendix

II

Static Mode Checking In this appendix we describe certain restrictions which ensure that mode tests can be carried out statically i.e. without elaborating the program. (Important exception: the test of the "current" mode of a union.) To formulate these restrictions, we may follow the treatment in /R/ where modes are defined as syntactic objects, and production schemata are used for defining the syntax; or we may keep the semantic approach of the main text, but slightly change the definition of unions. Need for restrictions. We want, for example, that subscripting is only applied to arrays. The treatment in Section 2, on the other hand, does not preclude an expression like u[i], where u is a union variable. Cleaily, whether the current value of u is an array cannot in general be determined statically. We would like to ban this expression on the grounds that the mode of (the expression!) u is not an array mode. Treatment in jRj: production schemata, the mode of an expression. In /R/, the syntax is defined by production schemata like ref/xassignment : ref/Lidestination : = /^source which yield many rules, one for each value of the variable μ; these values, certain syntactic objects, are called modes and are defined by a second production system. Rule schemata like the one above, together with the context conditions (see subsection 4.1 ) ensure in a static way that the conditions on the modes of the argument values of operations, like, for example, the one on η and ν in subsection 2.4(i), are satisfied; they also permit to define the mode of (an occurrence of) an expression. Unions; the mode of a value. There remains one difficulty: in a conformity relation, see subsection 2.4(j), we have to test whether a value ν (usually: the value of a union-expression) is "of mode μ"; earlier, we defined this as being in the set μ, but now, where modes are not (even in one-one correspondence tof) sets, that does not work. /R/ solves the problem by defining the mode of (an instance of) a value; conoisseurs will have noted that operations in /R/ produce (v, /x)-pairs, where μ is a non-union mode, not just values. (The test in subsection 2.4(j) has now to be formulated thus : the mode of ν is μ, or, in case of a union μ, a non-union alternative of μ.) Alternative treatment. Finally, we note that we can keep the semantic approach of the main text if we change the definition of unions (subsection 1.1 (j)) as follows: union (μι, . . . , μ η) = μι U · · · U Μη where υ, like set-union u , is cumulative, commutative, and associative; for disjoint non-union μι and η > 2, μι i_j . . . [_j μ is in one-to-one correspondence to μι υ . . . υ /Ι Η, but disjoint from it, and allows to rediscover the μι. (The new definition corresponds to the representation of unions in a machine, where tags are used to distinguish alternatives; the two modes in the footnote below are now different sets.) In other words, there are now values which are unions. Requirements on argument and result modes can remain as in the main text: e.g. subscripting accepts only arrays, and hence no unions. It follows that the mode of (the value returned by) an expression, and hence those requirements, can be defined statically. The special role of conformity is readily shown by the fact that its rhs is the only place were deuniting occurs.

t witness union(struct(int id), struct(real id)) and struct(union(int,real)id) 168

Appendix

III

Glossary We list certain terms used in /R/, together with (more or less rough) equivalents in more conventional terminology. (a) Semantic name multiple value structured value routine element field subvalue component state mode scope identity conformity coercion to refer to to possess elaboration serial e. collateral e.

(b) Syntactic notion phrase clause mode clause void clause slice denotation indication range reach identification proper program

Terms

pointer, location, variable array structure procedure element of an array element of a structure subaggregate of an array iteration of "element or field or sub value of" property of an array bound to be fixed/changeable type lifetime of a value equality of names assignability (a dynamic mode test) implicit conversion the relation between a variable and its value, i.e. between a location and its contents to denote execution, evaluation sequential e. quasi-parallel e. Terms

syntactic category declaration or expression or statement expression or statement expression statement subscripted variable constant symbol used as declarer or operator block block minus contained blocks correspondence between uses and declarations of identifiers or indications program satisfying context-dependent conditions, like unique identification

169

A General Purpose Conversational System for Graphical Programming 0 . LECARMEf Universitc de Grenoble, Mathématiques appliquées et informatique, Grenoble, France Abstract It appears that the thrust of research in graphical display technology has been towards new applications and the development of economical and more efficient display hardware. There seems to have been a lack of effort in developing software systems by which devices could be used easily and efficiently. In this paper the author considers the basic problems of conversational graphic programming, and describes a general purpose system, Eulalie, in which his proposal has been implemented at the Université de Grenoble, France. With this system, which is operational, a user can write, debug and execute a graphical program, using only the display unit. The system includes a programming language, Euphémie, specifically oriented towards the simple use of the terminal.

1. Introduction LI.

DISPLAY UNITS

Devices which permit computers to produce results graphically are of two types. The first are simple output devices : drafting tables or plotters ; the second, which allow direct man-machine communication, are the graphical display units. A display unit [7] is principally a cathode-ray tube, connected to a computer by means of a digital-analog converter, capable of displaying the orders transmitted by the computer. These facilities allow the display of points on the screen, given their coordinates, and also, on some advanced units, the display of vectors and of alphanumeric character strings. The cathode-ray tube is essentially an output device, and as such input devices must be added to it in order to achieve two-way communication. These are an alphanumeric keyboard, similar to that of a typewriter (the characters typed by the operator appear on the screen), a function keyboard with numbered keys, and at least one means of localization, usually the light pen. This latter is a simple photo-electric cell which sends a signal to the computer when it detects light from a point of the displayed image. In order for a displayed image to remain visible, it must be repeatedly generated. This is done either by the computer itself which transmits at a desired frequency (15 to 20 times per second) the set of display commands, or by storing the commands in a buffer memory in the display unit, which executes the commands independently. Communication with the computer is accomplished through this memory, and must be done only when the image must be modified or when data is sent by the user from the alphanumeric keyboard. t Present Address: Department d'Informatique, Université de Montréal, Montréal, Canada.

171

172 1.2.

Ο. Lecarme GRAPHICAL LANGUAGES

In applications involving the use of a graphical display unit, the display unit may be used for operations of two different kinds : the composition and storing of graphical programs, and the use of graphical programs to solve specific problems. The first kind of operation is typically performed by a programmer who has knowledge of the display unit and its control, but no special knowledge of the problem to be solved. The second type of operation is performed by the user, that is the person who is knowledgeable in the problem to be solved but not necessarily in programming matters. Occasionally these operations will be performed by the same individual. In such a case, however, the individual plays a dual role: first programming, then using the program, then programming, etc. A graphical program performs the calculations which define the images to be displayed, generates orders to be sent to the display unit, and reads and interprets input from the program user. To develop such a program, the programmer needs a programming language in which to express the procedures to be followed by the computer and the display unit. In addition to the usual arithmetic and logical facilities found in ordinary languages, a graphical programming language must have a facility for generating display orders, and for transmitting these orders to the display unit. In addition, it must have a facility for accepting user input from the display unit and for interpreting this input. The programmer also requires a command language to enable him to control the program development process. A command language is used on three occasions: During composition of the graphical program it aids in using the display screen as a scratchpad on which the programmer writes, erases, corrects, advances, backs up, etc., with the advantage that erased information takes up no space and additions can be made at any desired place. During work with the system it aids in entering programs into the system library, making copies of programs, deleting programs, and other similar operations. When it is desired to make the composed program work, it allows starting program execution, interrupting it, executing simple instructions immediately, and restarting execution. The user solves his problem by invoking a previously entered graphic program and sending it commands and data to produce images, modify and save images, perform calculations, progress through successive phases of work, and finally terminate the use of the program. For these operations, the user requires a communication language of a relatively new form since he no longer deals with punched cards or tapes, but types words or numbers on the alphanumeric keyboard, pushes function keys, or points the light pen at a particular object of the displayed image. Communication languages are typically developed jointly by the programmer and the user, and can easily be made different for every different use of the system. A communication language has well-defined syntax and semantics, but they are usually carried implicitly in the graphical program. 1.3. PURPOSE AND PLAN OF PAPER

The objective of this paper is to give a description of a general purpose conversational graphical programming system called Eulalie. This system was developed by the author at the University of Grenoble in France. With this system, which is operational, a user can write, debug, and execute a graphical program, using only a display unit.

A General Purpose Conversational System for Graphical Programming

173

In Section 2, the general ideas of Eulalie are presented. Existing projects in graphical programming are briefly reviewed, and the objectives of Eulalie are stated and contrasted with other systems. In Section 3, the command language of Eulalie is presented, and examples of its use are given. Section 4 describes the graphical programming language, called Euphémie, which is provided in Eulalie. Examples of Euphémie programs are given, and the compilation and execution of Euphémie programs is discussed briefly.

2. General Ideas of Eulalie 2.1.

EXISTING PROJECTS

Much work has been done in the field of graphical programming languages, from the use of a machine language provided by the manufacturer [8, 21] to very advanced systems constructed from a large number of sub-routines written in Fortran or some other highlevel language [15, 17]. These languages are generally tedious and difficult to use, as one gets lost in myriads of details and loses sight of the initial problem, reminiscent of the early days of machine Example in 3 6 0 Assembly Language:

DISPLAY LENGTH POINTER BLOCK WORK GDOA PARTABLE EXAMPLE

OPEN ASGNBFR CALL GWRITE WAIT

DISPLAY DISPLAY, LENGTH GSTÖR, (POINTER, PARTABLE) W R I T E C B , STR, D I S P L A Y , POINTER ECB = W R I T E C B

DCB DC DC OACB DC DC DC GINIT GSRT GEVM GDV GDV GDV GDV GTRU GODEL

D S O R G = GS, GTYPE = BASIC, M A C R F = (RC, W C ) , D D N A M E = G R A P H I C S H'256' A(BLOCK, WORK) GDOA, 256, D U M M Y 160' 64FO' 2FO' BLIM = 256

1000,1000, Β 1500,1 5 0 0 , U 500,1 5 0 0 , U 1000,1000, U EXAMPLE EXAMPLE, PARTABLE(2)

Example in Fortran and G.S.P.: DIMENSION NULL(1), TRIANGLE(8) NULL(1) = - 5 CALL I N G S P ( I G S P , N U L L ) CALL I N D E V ( I G S P , 10, I 2 2 5 0 ) READ ( 5 , 2 0 ) T R I A N G L E 20 FORMAT(8F6.1) CALL P S G M T ( I M A G E , T R I A N G L E ( 1 ),TRI A N G LE ( 2 ) , T R I A N G LE ( 3 ) , X T R I A N G L E ( 4 ) , 1,2,4,4,4,4) CALL E X E C ( I M A G E )

FIG. 1. Instructions necessary to display a triangle (partial examples).

174

Ο. Lecarme

programming. In addition, these languages do not exploit the potential advantages of graphical programming, and appear to have been designed at the hardware's functional level, rather than as a convenient language for graphical programming. We give some examples (Fig. 1) of the instructions necessary for the simple display of a triangle in IBM 360 Assembler Language and in the set of sub-routines which can be called in Fortran and are grouped under the name Graphic Sub-routine Package (G.S.P.) [9, 10, 11, 24]. In the field of communication languages, developments are fewer and are mostly limited, in general, to specific applications. The general purpose systems [1, 22, 26] which have been developed were connected with special-purpose communication devices on which they depended heavily, but their main fault, in my opinion, was that they removed the user from their substratum of programming and organization. As a result the user was not aware of the implications of what he was doing. These systems have practically only served for drawings and sketching. There appears to be an emphasis on specific applications reported in literature, where the programming has been carried out at the hardware level in a language supplied by the manufacturer. It appears that each research group has had to develop its own higher order communication language, a necessary but redundant effort. 2.2.

OBJECTIVES OF EULALIE

We feel that fruitful work can only be done in a general-purpose system environment which would allow the user to sit down at his display terminal, with his own resources (and perhaps some scratch paper, as one of the inconveniences of the display unit is that it produces only transitory information, as opposed to usual means of communication, such as cards, printers, typewriters, etc.), and not to leave it until he has composed, debugged and used his program. The system, called Eulalie, requires a command language considerably different from those of the usual conversational systems, since it attempts to exploit the potential of manmachine communication facilities of the graphic unit to its full advantage. The conditions required for our system should be the following: Composition of programs, in the programming language to be defined, can be entirely accomplished by use of the terminal, in a continuous programmer-computer dialogue. A program composed one day may later be modified, completed and used, which implies the existence of a file of users' programs. During a run, the program may use all the display's potential capabilities, except some technique which allows control to be returned at any time to the system. The programming language allows the user as precise control as if he were using machine language. It also permits easy programming of all that is simple, without the necessity of writing ten pages of text when only a circle or a triangle is to be displayed. It is easily learned and quickly usable, as it relieves the user of everything that is not strictly linked to his purely graphic work. From the moment the user requests execution of his program, it has complete control of all error conditions. A program does not accidentally terminate until it is required by the user ; except in case of an error in the machine or system, absurd situations where the image suddenly disappears and the printer gives a memory dump do not occur. Consequently, a composed and stored program, which is ready to be executed, is always syntactically correct and completely compiled.

A General Purpose Conversational System for Graphical Programming 2.3.

175

DESIGN PRINCIPLES

The current realization of Eulalre [20] uses an IBM 2250 display terminal, model I, connected to an IBM 360, model 65/67. This terminal has generators for points, vectors and characters, a buffer memory, a function keyboard, an alphanumeric keyboard, a light pen, and a Sylvania tablet. The system relies on a set of sub-routines, G.S.P. [9, 10, 11, 24] provided by IBM. It was developed and perfected conversationally in the environment of the CP/67 and CMS system [14] which functions on the 360/67, but it is designed to work as well under OS/360 [12], in particular in a partition under control of the MFT or MVT options. The operational version of our system thus uses a specific machine, terminal and operating systems. One of the design principles is, however, to reduce these links to a minimum, both in the definition of command and programming languages, and in the programmed realization of the supervisor, the compiler and other system components. This should permit bringing out the fundamental and elementary concepts and rapid adaptation of the whole of the system to another terminal, another operating system or another machine. The programming language, called Euphémie, is defined at a rather elementary level for we have forced ourselves to place in it only the principal concepts of graphical programming. It is, therefore, as absurd to ask how the rotation of a three-dimensional figure is accomplished in this language as it is to ask how in Algol or PL/1 the inversion of a matrix or the solution of a differential system is obtained: in both cases, the language should provide the means to program the algorithm to be defined, but it should not provide the algorithm itself. Another important aspect is that Euphémie is experimental and its design should not be rigid. Its definition should thus allow easy modifications and extensions and above all, the compiler and other related parts should be easily adaptable to these modifications. In order to guarantee adaptability of the programming language and the system, during experimentation as well as for translation to another machine, the programming of the whole is built on intensive use of macro-instructions, which effectively define an intermediate language. Rewriting the definition of these macro-instructions then allows changing machines without difficulty, while modifications of the language's definition only have effect on the use of some macro-instructions, without revision of entire pages of programming. 3. Command Language 3.1.

EXAMPLE OF USE

In this example, U designates any user action and S any system action. In the case of user action, a bold-faced word indicates that the user sends this command by means of the function keyboard. The texts in upper-case letters appear on the screen, whether they be system messages or user replies ; the sign _ is the cursor placed by the system at the beginning of the area in which the user types his replies with the alphanumeric keyboard. U Begin S GIVE YOUR NAME : _ U M. CICERO. S GIVE YOUR PASSWORD : _ U (User writes his password but nothing appears on the screen) S (Acknowledges name and password) U Name D

176 S S U S U S U S U S U S U S U S U S U S U S U S U S U U U U U S U S U U U

Ο. Le carme GIVE YOUR PROGRAM NAME : _ B. BARDOT_ THIS PROGRAM WAS CREATED ON 10/1/70, USED ON 4/3/70. IT USES 00258 RECORDS. Correct (No action : this command is not yet authorized for it is not known if the declaration or the instructions of the specified program should be modified) Instructions (The first two pages of instructions of program B. BARDOT appear on the screen with the markers (-• e2

H "

M r

el

The first " 1 " is the length of the string "X", the second one represents the include option, taken by default. "PTEXT" is the name of the G.S.P. subroutine to plot a text. Markers are also shown in this schema, as small shaded rectangles and are required to signal the end of the parameter list and of each expression. The empty box stands for an omitted parameter, here the name of the generated object. The translation process is written with a set of macro-instructions, and is simply traced over the structure of each instruction of the language. For each instruction, we have simply to fill the boxes in a schema like the latter one, possibly translating in post-fixed notation the expressions, and putting pointers on them in the corresponding boxes. The translation of expressions is classical, and uses an operator and an operand stack, to make complete type-checking during compilation. 4.5.4. Decompilation

The decompiling process is also written with a set of macro-instructions, and the decompiling of a given instruction has almost exactly the same form as the corresponding translation code, the differences being principally in the names of macro-instructions. The latter are much simpler for decompiling than for compiling, because no checks are required. Some details of decompilation may be worthwhile, because of their effect on what the user sees on the screen. We have said before that symbols of the language, like figure, segment or lightpen, can be abbreviated up to four letters, and can be written in French or English. For decompilation, we choose some conventions: the language in which symbols are rewritten is fixed by a parameter given at the beginning of the job; all symbols are written in a standard form, not abbreviated but also without plural or other variations. Furthermore, some options can be omitted, in which case the system has a default option, which is explicitly specified at decompilation. Finally, instructions are written in a standard format, with blanks interspersed between almost all symbols, instructions beginning at the left margin, and continuation lines four characters after. We illustrate this with an example; the instruction keyed by the user as follows: 'ETAT' LEVEL (1, - 2 0 , 31) ARRAY'TABLE RESP'WHEREIS; is rewritten as follows (if the current language is English): 'STATUS' LEVEL (1, - 2 0 , 31) 'RESPONSE' WHEREIS 'ARRAY' TABLE 'WAIT'; 4.5.5. Loading and interpretation

The intermediate form in which object programs are stored on disk is not directly interprétable. It is processed by a loading module, which performs the following functions:

196

Ο. Lecarme

allocation in memory for all constants and variables, by means of the identifier list; initialization of constants and variables, by means of the value list; generation of a table mapping disk addresses to memory addresses for each variable; loading of instructions themselves, replacing all disk addresses by memory addresses, and instruction names by addresses of corresponding subroutines ; building of a label table. After this loading, interpretation is very simple and proceeds as follows : copy the parameter list in work; area ; scan the list for all unevaluated expressions ; evaluate the expressions by simulation of a stack machine ; replace each reference to an expression by a reference to a work register which contains the result; call the required subroutine with the thus constituted parameter list. 4.6. FUTURE DIRECTIONS OF WORK

The non-graphical portions of the programming language Euphémie have been reduced, for the moment, to their simplest expression, for we think it is better to concentrate our efforts on new problems. In the near future the language must be extended to include the multiple assignment instruction, a for instruction with value enumeration, use of twodimensional arrays and arrays whose elements are character strings. At present, the worst defect of the available possibilities is the total absence of procedures which we will remedy in several different ways: the system will provide a collection of standard procedures permitting simplification of certain common operations such as reading and writing numbers, using menus, displaying arcs of circles or grid patterns. The language will aid definition of procedures, in the classical sense, but with a syntax that will make each procedure a new instruction of the language. Finally, the system will provide interrelationships between a program and procedures compiled separately, especially in classical programming languages. The last feature will allow complete separation of all that is not graphical nor conversational in a program but serves simply for routine calculations. A final extension should elevate the level of the language, furnishing a means to compose and handle data structures [5, 13] with correlative means of interrelationship with graphical instructions in order to finally use the programming language for complex problems, such as satisfaction of certain imposed constraints or rotation of three-dimensional figures.

Acknowledgements I would like to thank Edouard Cleemann, who contributed to a part of this paper, and above all worked very hard on the project; Louis Bolliet, who encouraged me to write this paper; Jean Vaucher and Syed Hyder, who were an invaluable aid in keeping it in acceptable English; Mark Halpern and William McGee for their pertinent and helpful criticisms and suggestions on the matter and the presentation.

A General Purpose Conversational System for Graphical Programming

197

Bibliography 1. F. C . CHEN and R. L. DOUGHERTY, A system for implementing interactive applications, IBM Systems Journal, vol. 7, No. 3 & 4, pp. 257-270 (1968). 2. E. CLEEMANN, Un macro-langage pour la programmation des terminaux graphiques, Doctoral thesis, Grenoble, March 1969. 3. E. CLEEMANN, O. LECARME and M. LUCAS, Langages de programmation graphique, Revue Française d'Informatique et de Recherche Opérationnelle, No. 12 (1968). 4. S. A. COONS, An outline of the requirements for a computer-aided design system, AFIPS Conference Proceedings, S.J.C.C. 23, pp. 299-304 (1963). 5. D. EVANS and A. VAN DAM, Data structure programming system, IFIP 68 Congress Proceedings. 6. F. W . GAGLIANO, H . W . THOMBS and R . Ε . CORNISH, A conversational display capability, IBM

7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.

Systems

Journal, vol. 7, No. 3 & 4, pp. 281-291 (1968). IBM System/360 Component Description, IBM 2250 Display unit model 1, Form A27-2701. IBM System/360 Operating System, Graphic programming services for IBM 2250 display unit—Basic, Form C27-6912. IBM System/360 Operating System, Graphic programming services for Fortran IV, Form C27-6932. IBM System/360 Operating System, Graphic programming services for Fortran IV—Program logic manual, Form Y27-7152. IBM 1130 Computer Operating System, IBM 1130/2250 Graphic Subroutine Package, Form C27-6934. IBM System/360 Operating System, Concepts and Facilities, Form C28-6535. IBM System/360 General Program Library, GPAK—An on-line system/360 graphic data processing subroutine package with real time 2250 input and display, Version II. IBM Cambridge Scientific Center, CP/CMS User's Guide, Report 320-2015. C. I. JOHNSON, An experimental PL/I Extension for graphic programming, IBM Cambridge Scientific Center Report 320-2025 (1968). C. I. JOHNSON, Principles of interactive systems, IBM Systems Journal, vol. 7, No. 3 & 4, pp. 147-173 (1968). H. E. KULSRUD, A general-purpose graphic language, Communications of the ACM Vol. 11, N o . 4, pp. 247-254(1968). O. LECARME, Une système de programmation graphique conversationnelle, in Les Systèmes conversationnels by L. Bolliet (ed.), Dunod, Paris (1969). O. LECARME, Niveau des langages et puissance des outils en programmation graphique, Revue Française d'Informatique et de Recherche Opérationnelle, No. B-2, June 1970. O. LECARME, Contribution à l'étude des problèmes d'utilisation des terminaux graphiques—Un système de programmation graphique conversationnelle, Doctoral Thesis, Grenoble, September 1970. O. LECARME and M. LUCAS, LAGROL—Un langage pour l'utilisation d'un terminal graphique, Note technique de Vï.M.A.G., Grenoble (1968). M. LUCAS, Techniques de programmation et d'utilisation en mode conversationnel des terminaux graphiques, Doctoral Thesis, Grenoble, June 1968. W . M. NEWMAN, A system for interactive graphical programming, AFIPS Conference Proceedings, vol. 32, p. 47 (1968). A. D. RULLY, A subroutine package for Fortran, IBM Systems Journal, vol. 7, No. 3 & 4, pp. 248-256 (1968). P. H. SCHWINN, A problem-oriented graphic language, Proceedings of the 22nd National Conference of the ACM, P-67, pp. 471^76 (1967). I. E. SUTHERLAND, Sketchpad—a man-machine graphical communication system, AFIPS Conference Proceedings, S.J.C.C. 23, pp. 329-346 (1963).

'boolean-subscripted-variable' 'boolean-array' >

b o o l e a n Aa r r a y

and

and

and

where

where

where

χ

localsofy>

a r i t h m e t i c - o p e r a t o r arithmetic-primary | Λ a d d - o p e r a t o r list 1 a r i t h m e t i c - o p e r a t o r arithmetic-primary

ifΛ boolean-expression r sA t h e nA simple-arithmetic-expression r sA e l s Λe arithmetic-expression r s

simple-arithmetic-expression -» list 1

where

iAf boolean-expression r sA t h e nA simple-boolean-expression r sA e l s Ae boolean-expression r s

where

ifA boolean-expression r sA t h e nAsimple-designational-expression r sA e l s Ae designational-expression r s

simple-designational-expression r slabel r s | switch r sA [Aarithmetic-expression r sΛ ] | (Λ designational-expression r s Λ ) w h e r e label r s-»get-prod 'label' r s a n d switch r sget-prod 'switch' r s arithmetic-variable r s get-prod 'real-simple-variable' r s | get-prod 'integer-simple-variable' r s | get-prod 'real-subscripted-variable' r s | get-prod 'integer-subscripted-variable' r s real-variable r s->get-prod 'real-simple-variable' r s | get-prod 'real-subscripted-variable' r s integer-variable r s -»get-prod 'integer-simple-variable' r s | get-prod 'integer-subscripted-variable' r s boolean-variable r s -*get-prod 'boolean-simple-variable' r s| get-prod 'boolean-subscripted-variable1r s

where

simple-boolean-expression-+list 1 b o o l e a n - b i n a r y - o p e r a t o r boolean-secondary w h e r e boolean-secondary r s -> boolean-primary r s | ~~IA boolean-primary r s w h e r e boolean-primary r s -»· b o o l e a n - c o n s t a n t | boolean-variable r s | relation r s | ("boolean-expression r s A) Λ A w h e r e relation r s -*simple-arithmetic-expression : r r e l a t i o n a l - o p e r a t o r simple-arithmetic-expression r s a n d designational-expression r s->simple-designational-expression r s |

where

arithmetic-primary r s -* u n s i g n e d - n u m b e r | arithmetic-variable r s | (Aarithmetic-expression rs A] a n d boolean-expression r s -* simple-boolean-expression r s |

and

where

χ -»new-identifier 1 new-identifier l-*new-value 1 identifier () a n d t-> token () r e c arithmetic-expression r s-*• simple-arithmetic-expression r s |

w h e r e y-»construct-symbol χ t

symbols: unitset y locals : prefix χ 1 >

definiens: unitset Âr./s.if yes t h e n χ e l s e n u l l s t r i n g

declaration-identifier 1 -* < text :

locals:

Automatic

Theorem Proving on Resolution

Based

ALAIN PIROTTE MBLE Research Laboratory, Avenue Van Becelaere 2, 1170 Bruxelles

Abstract. J. A. Robinson's resolution principle has given rise to much research work and has contributed to the establishment of automatic theorem proving as a field of its own in artificial intelligence. The present paper is addressed to two kinds of readers : by its elementary introduction, it should enable a non-specialist in resolution theorem proving to grasp the essence of the method and read virtually any paper on the subject, whereas the researcher in artificial intelligence will find in specialized sections a collection of results on resolution-based procedures connected to the relevant papers in the literature.

Introduction The aim of the present paper is twofold: it can be viewed as an introduction to resolution and related topics, that should enable somebody not especially aware of automatic theoremproving methods to read virtually any paper on the subject; the second aspect of the paper consists of a survey of the theorem-proving procedures that are based on resolution. We present in some detail the underlying mathematics, remarkably simple in its principle. The goal of developing theorem-proving procedures is probably nearly as old as mathematics. In its modern form, it is based on the work of Herbrand [57] published in 1930. But until about the end of the nineteen-fifties, theorem-proving was the subject of purely theoretical investigations. It is only with the advent of computers that the procedures, completely impractical for human computation, could be tested. These early tests did not prove as satisfactory as one might have hoped ; they stimulated a lot of new research which culminated in J. A. Robinson's resolution, definitely designed for the computer. Resolution has been widely investigated during the last few years and an important part of the present paper is devoted to a survey of these recent results. Much theoretical work has been devoted to proving completeness results about strategies for applying resolution. (A complete strategy is guaranteed to find a solution to a given problem if a solution exists at all ; in the case of theorem-proving strategies, the solutions are proofs of alleged theorems.) More and more theorem-proving programs are being written to show the effectiveness of resolution and compare the merits of different strategies. Theorem provers are being applied to problems formulated in the language of the predicate calculus in several branches of mathematics and also in some domains of artificial intelligence such as question answering, problem solving and program writing. The method of completely formulating a problem in a logical formalism such as the 201 Β

202

A. Pirotte

predicate calculus is interesting for its generality and its simplicity, especially when the inference mechanism is complete and subject-independent like the resolution strategies. However, precisely because of their generality, even the best programs have not by now reached a level of performance (in terms of execution times) which makes them actually useful, nor have they been successful in proving difficult theorems in mathematics. While theoretical work is still going on to produce better resolution strategies, some researchers are investigating approaches where a resolution theorem prover is only a module in a program and is combined with heuristic and other problem-solving methods. As another attempt to improve the performance of theorem provers, interactive programs are being developed where a mathematician can guide the program by suggesting strategies, modifying parameters, etc. Section 1 is a short and elementary introduction to logical systems, automatic theorem proving and basic vocabulary. Section 2 briefly describes the propositional calculus: its main purpose is to illustrate the semantic approach to logical systems and to present a clear introduction to the more complicated resolution principle for the predicate calculus. The essential part of the paper is contained in Section 3 which is devoted to the first-order predicate calculus, and in Section 4 which discusses applications of automatic theorem proving. In Section 3.1 we give a definition of the calculus, following the semantic approach. Almost all the theorem-proving procedures are based on the Herbrand theorem: Section 3.2 is devoted to its presentation and to a proof of it. Section 3.3 describes the "Herbrand procedures": they were the first procedures to be run on computers about 10 years ago. Evolution of these procedures resulted in the resolution principle, the subject of Section 3.4. Section 3.4.1 introduces resolution and gives a proof of the completeness of the basic resolution procedure. Section 3.4.3 presents a survey of various strategies that were proposed to embed resolution in theorem-proving procedures. Strategies are only described and illustrated by examples and references to the original literature. The presentation is not the only one possible: for example, we think that "semantic resolution" differs from the "syntactic" strategies of Section 3.4.3.3 sufficiently to be clearly separated; or else, we do not want to over-emphasize the importance of clashes; and so on. Section 3.4.4 describes an important aspect of current and future theorem provers: the various efforts that are made to handle the equality relation in an efficient way. The practical importance of equality makes the overall efficiency of theorem provers very dependent on how well it is handled. Section 4 describes, essentially by means of simple examples, a few applications of resolution theorem provers that were recently devised. Some alternatives to methods exclusively based on resolution are also discussed. Section 5 sketches some conclusions about the state of the art and some other approaches to theorem proving. Finally we include a detailed bibliography which covers automatic theorem proving in general.

1. Logical Systems This section contains a simple and introductory presentation of logical systems. For a more detailed treatment, the reader is referred, for example, to Mendelson [92] or Rasiowa and Sikorski[110].

Automatic Theorem Proving Based on Resolution

203

1.1. SYNTACTIC AND SEMANTIC VIEWPOINTS

An axiomatic theory can be defined by specifying: (1) a language, i.e. a collection of symbols and rules for arranging symbols and building well-formed expressions of the language or well-formed formulas (hereafter "wffs"); (2) the deduction rules or inference rules, i.e. transformation rules which act on one or more wffs and produce another wff; the inference rules are the mechanism to build logical consequences of wffs; and (3) the axioms, i.e. a given subset of the wffs. By definition, the set of theorems of the axiomatic theory comprises the axioms together with the wffs which can be obtained from axioms or other theorems by applying the deduction rules. This definition of a logical system is the syntactic approach {deduction theory). No reference is made to the meaning carried by the wffs. The formal proof of a theorem is a sequence of wffs ending with the theorem, where each wff either is an axiom or is derived from preceding wffs in the sequence by the application of an inference rule. The basic question in the syntactic formalism is now to recognize whether a given wff is a theorem and if it is, how to construct a formal proof of the theorem. The semantic approach to logical systems consists in defining: (1) a language, i.e. the rules for building the wffs ; (2) the rules for assigning meaning to the wffs. This is achieved by defining how different interpretations for a wff can be built and by providing rules for assigning a truth value (true or false) to a wff in a given interpretation. The wffs can then be classified according to the following definitions. A wff is said to be satisfiable if there exists some interpretation under which it is true. A wff is said to be unsatisfiable if it is false under all possible interpretations. Ajwff is said to be valid if it is true under any possible interpretation. Thus a wff which is not valid is not necessarily always false (i.e. unsatisfiable) : it may instead be satisfiable. If a wff is unsatisfiable, then its negation is valid and conversely : this metatheorem is obvious if a consistent definition is assumed for the syntactic and semantic notions of negation, i.e. if the negation symbol has the semantic effect of making true what was interpreted as false and vice versa. The basic question in the semantic formalism is how to recognize whether or not a given wff is valid.

1.2. COMPLETENESS AND SOUNDNESS

Completeness and soundness are properties of logical systems which relate the syntactic and the semantic approaches : they specify the relative position of the set of theorems and of the set of valid wffs. A logical system is said to be complete if every valid wff is a theorem, or equivalently, if any true statement can be formally proved in the system. A logical system is said to be sound if every theorem is valid, or equivalently, if formal proofs only yield true statements. In fact, completeness is a property of the designation of the set of theorems: in a complete system, this set is large enough to include all the valid wffs. Similarly, what is sound or

204

A. Pirotte

unsound is the designation of the subset of the wffs to be called valid, with reference to truth or falsity considered in the possible interpretations. It was first hoped that the interesting systems would be both sound and complete, i.e. that the set of theorems would coincide with the set of valid wffs. However, a well-known theorem by Gödel (see, for instance, [36]) showed that this cannot be the case. An important example is ordinary arithmetic which cannot be formalized in a complete system. Since we will deal in the following sections only with the propositional calculus and the first-order predicate calculus which are sound and complete, from now on "theorem" and "valid wff" are considered as synonyms. The fact that the syntactic and the semantic descriptions are equivalent in their results will be made clearer in Sections 2 and 3.

1.3. DECISION PROCEDURE, PROOF PROCEDURE

The following definitions achieve a distinction among the procedures that test a wff for theoremhood according to their decision power. A decision procedure for a set is an algorithm which can tell whether or not a given element belongs to the set. A logical system is said to be decidable if there exists a decision procedure for the set of its theorems. A proof procedure for a set is an algorithm which can tell that a given element belongs to the set, if it does indeed, but which may not terminate when presented an element lying out of the set. A logical system is said to be semidecidable if there exists only a proof procedure for the set of its theorems (and no decision procedure). A famous theorem by Church (see, for instance, [36]) implies that the predicate calculus is semidecidable, whereas the propositional calculus is decidable.

1.4. APPROACHES TO AUTOMATIC THEOREM PROVING

The two approaches to defining logical systems lead to different theorem-proving procedures. The theorem-proving problem of the syntactic approach consists in generating formal proofs. The simplest strategy, the so-called British Museum Algorithm, consists in systematically applying inference rules to axioms in all possible manners. Any theorem will eventually be found in the list of theorems generated, but the algorithm is trivially inefficient. All the difficulties lie in deriving an algorithm to decide which inference rule to apply next, with reasonable efficiency. In the deductive systems and more generally in human theorem proving, it is a common procedure to generate a series of lemmas that shorten the distance between the axioms and the theorem to be proved. The derivation of these lemmas is not formally dependent on the theorem, although of course the direction taken by the proof is determined by the mathematician who knows what he is driving at. These human heuristic rules are very difficult to formulate in a clean algorithm, and that is why few automatic theorem provers are based on a deductive strategy. The semantic approach to proving that a wff is a theorem consists in showing that it is valid or, equivalently, that its negation is unsatisfiable. If this task is undertaken according to the definition of validity or unsatisfiability, it requires the computation of the truth value

Automatic Theorem Proving Based on Resolution

205

of the wff in every possible interpretation: this is feasible for the propositional calculus but not, as we shall clearly see, for the predicate calculus (the feasibility of such procedures would imply the decidability of the predicate calculus). Instead of merely applying the definitions, practical procedures derive consequences of the wff to be tested by applying to it transformation rules that preserve the property of being satisfiable or unsatisfiable. A proof of validity of a wff S is achieved when some clearly valid wff like Ρ V ~ Ρ has been derived from S by repeated applications of the transformation rules. Correspondingly, a proof of unsatisfiability of ^ S is achieved when some clearly unsatisfiable wff like Ρ Λ ~ Ρ has been obtained. The two methods are tightly connected: proving S valid can be formulated as an exact dual of proving ~ S unsatisfiable [68]. In the literature, some works are based on a search for a proof of validity (e.g. [27], [48], [68], [103], [104]), but most approaches are based on a search for a proof of unsatisfiability. Virtually all the present paper is devoted to the latter procedures, commonly termed refutation procedures (they report that S is valid, i.e. is a theorem in the systems we consider, when they have refuted the supposition that ~ S might be satisfiable). Deduction and refutation (or équivalently, proof of validity or validation) do not seem as different as one might have predicted when considering the syntactic and the semantic definitions of logical systems. A first difference essentially amounts to the distinction achieved between top-down and bottom-up systems in syntactic analysis. Deduction procedures are presented as proceeding from the axioms toward the theorem by applying inference rules, whereas refutation procedures start working on the theorems and attempt to reach always the same goal: the simple unsatisfiable wff with the structure Ρ Λ ^ Ρ . A second, more fundamental, difference consists in the properties of the wffs that must be preserved in each approach. The point will be made clearer after a precise definition of what is meant by "interpretation". In deduction systems, if a wff A is deduced from a wff S, then S logically implies A, i.e., in semantic terms, every interpretation of A and S which satisfies S also satisfies A. On the other hand, if we want to demonstrate unsatisfiability, we can accept as legal those transformations of the wffs which preserve only the property of being satisfiable or unsatisfiable. The difference arises in the predicate calculus, when the wffs are transformed into a canonical form (Section 3.1.3): the transformation preserves satisfiability (or unsatisfiability) but not necessarily logical equivalence. Deduction is the traditional point of view of human mathematicians, and the semantic approach was not much used in practice until a few years ago, when one started to devise proof procedures for computers. It has become the general approach, first because of the widespread use of computers and second because the algorithms turned out to be easier to discover for refutation procedures than for deduction procedures. Let us emphasize the fact that refutation procedures do not yield a formal proof from the axioms. Instead, they rely on the fact that, in sound and complete systems, it is sufficient to demonstrate the unsatisfiability of a wff to assert the existence of a formal proof of its negation. "Formal proof" is a technical term that specifies an object inside the logical system whereas "proof of validity" or "proof of unsatisfiability" imply operations performed outside the logical system (one could say "metaproof" by contrast with "formal proof") and have the meaning of, for example, "any correct evidence sufficient to establish validity or unsatisfiability". Yet, in sound and complete systems, "proof" is used in both senses without serious confusion.

206

A. Pirotte 2. Propositional Calculus

2.1. DEFINITION

We give here a definition of the propositional calculus, following the semantic approach. The definition comprises a syntactic part that defines a language (i.e. how the wffs can be built and recognized to be wffs) and a semantic part that specifies how interpretations can be chosen and how the truth value of a wff can be computed in a given interpretation. Since we adopt the semantic definition, neither axioms nor inference rules are introduced. A definition of the calculus following the syntactic approach to logical systems comprises (see, for instance, [92]) the definition of the language (the same definition as that given here) and the list of inference rules and logical axioms. Syntax Symbols (1) Propositional constants: T, F (2) Propositional variables : p, q, r

Semantics (1) T, F are the elementary truth values: they are interpreted as true and false respectively. (2) Propositional variables are interpreted as elementary propositions : they can be true or false; an interpretation is determined by an arbitrary assignment of truth values to all the propositional variables.

(3) Propositional connectives: ~ , Λ, V, 0, ο (4) Punctuation symbols : ( , ) Wffs (1) A propositional variable is a wff. (2) A propositional constant is a wff. (3) If A and Β are wffs, then so are :

—A (Α Β) Λ

(A VB) (A OB) (AB)

Propositional variables and constants are elementary propositions, interpreted as true or false. Composed wffs are interpreted as composed propositions; their truth value depends on the truth values of elementary propositions, by separating wffs in arguments of propositional connectives and applying the following semantic definitions of connectives: ~ A is (interpreted as) true if A is false, false if A is true. (Α Λ Β) is true if both A and Β are true, false otherwise. (A V B) is false if both A and Β are false, true otherwise. (A 0 B) is false if A is true and Β is false, true otherwise. (Α ο Β) is true if A and Β have the same truth value, false otherwise.

Automatic Theorem Proving Based on Resolution

207

Remark: We have used here the simplest formulation, in which punctuation symbols impose the order of evaluation in composed wffs. Instead, precedence relations for connectives can be defined. It is a simple matter (although it is not the place to do it here) to formalize the definitions, both syntactic and semantic, with or without precedence relations, using for example, a context-free formalism. In the examples, we often use the following usual order of precedence for connectives: ο , 0, V, Λ, ~ and we omit parentheses whenever this omission does not affect the clarity of the syntactic structures. 2.2. THEOREM PROVING IN THE PROPOSITIONAL CALCULUS

A wff in the propositional calculus contains a finite number of propositional variables. In a given interpretation, each of them is interpreted either as true or as false. Therefore the number of possible interpretations for a wff is finite, and the truth values of the wff for all of them can be collected in a truth table. Using truth tables directly yields a decision procedure: by a simple inspection, one can decide whether a wff is valid, satisfiable or unsatisfiable. The drawback of using truth tables is that they become impractically large as the number of propositional variables increases. 9

2.2.1. Wang s

Algorithm

Mention of Wang's algorithm [148] is made here as an example of an efficient algorithm which solves the theorem-proving problem in the propositional calculus. The algorithm is specifically designed for the propositional calculus, and it cannot be generalized to the predicate calculus. The method consists in systematically simplifying the wff to be tested until it becomes "obvious" whether or not it is a theorem. The simplification rules express axioms for the propositional calculus and aim at reducing the wff to the following form, φι and ψ\ being wffs: Φι Λ φζ Λ . . . Λ φ 0 φι V φ V . . . V 0 . η

2

m

The "obvious" decisions are: (1) If the same propositional variable appears on both sides as a full wff, then the initial wff is a theorem. (2) If no variable appears on both sides and if the i's and ^j's are all reduced to propositional variables, then the wff is not a theorem. The algorithm does not fit cleanly in the "syntactic" or "semantic" formalism: the reduction is "syntactic" since it uses axioms, and the "obvious" decisions are "semantic" (they are based on the semantics of D, V and Λ). 2.2.2. Propositional

Resolution

Resolution is a transformation rule used in proofs by refutation. In this section we introduce propositional resolution, a simplified version of the resolution principle for the predicate calculus to be described in Section 3.4. Let us recall how refutation procedures proceed: they negate the wff S to be tested for theoremhood and derive wffs from ~ S by using transformation rules that preserve the property of being satisfiable or unsatisfiable. The proof is achieved when some clearly unsatisfiable wff such as ρ Λ ~ ρ is obtained (p is a propositional variable). Refutation procedures

208

A. Pirotte

using resolution require the wff ^ S to be put into a canonical form, the conjunctive normal form ( C N F ) and we now describe this operation. A wff in C N F consists of a conjunction of disjunctions of propositional variables and negations of propositional variables, e.g. ( ~ ρ V q) Λ ( ~ q V r) Λ ( ~ s V ~ r) Λ Ρ Λ s. Each conjunct (e.g. ^ ρ V q) is called a clause, and C N F is also called clause form. The transformation of a wff into C N F is based on the equivalence rule, which is expressed as follows: if we can show that Α ο Β is a theorem (A, Β are wffs) and if A appears as a component in a wff S, then we can substitute Β for A in S without affecting satisfiability or unsatisfiability of S. The transformation to C N F applies the equivalence rule to the following propositional theorems (A, B, C are wffs): (Α ο

Β) ο

( A 0 Β)

Λ

(1)

(Β 3 Α ) ,

( A D B ) o ( ~ A VB),

(2)

- ( A V B ) O ( - A A - B ) ,

(3)

— ( Α Λ Β) ο

( ~ A V ~ Β),

(4)

( A V Β)

(5)

A V (Β

Λ

C)

ο

Λ

(A V C).

The rules should be applied in the order (1) then (2) then (3) or (4) then (5) since (1) eliminates " o " , (2) eliminates " 0 ", (3) and (4) reduce the scope of and (5) produces the conjunction of clauses. As an example of transformation to C N F , let the wff to be tested be: (((P 3 q) (q 3 r) (s 3 ~ r)) and let us transform to C N F its negation, i.e. Λ

Λ

0

(p

3

~ s))

~(((P 3 q)A (q 3 r) Λ (s 3 - r)) D (ρ 3 ~ s)). Rule (2) is first applied at the upper level, then at inner levels; then rules (3) and (4) are repeatedly applied : ~ ( ~ ( ( P 3 q) Λ (q 3 r) Λ (s 3 ~ r)) V (ρ 3 ~ s)), ~ ( ~ ( ( ~ Ρ V q) Λ (~q

V

r) Λ ( ~ s V ~ r)) V ( ~ ρ V ~ s)),

(((~ Ρ V q) Λ ( ~ q V r) Λ ( ~ s V ~ r)) Α ~ ( ~ Ρ V —' s)), (((~ Ρ V q) Λ ( ~ q V r) Λ ( ~ s V — r)) Λ (ρ Λ s)). The outer layers of parentheses can be removed, yielding the conjunction of clauses (the wff in C N F ) : (—' ρ V q) Λ ( ~ q V r) Λ ( ~ s V — r) Λ Ρ Λ s. We now proceed to describe how resolution is applied to a wff in C N F . A simple way to present resolution is the following (A, B, C and D are wffs): (1) If C 3 D is a theorem, then C C Λ D is obviously a theorem. (2) (ρ V A) /\ ( ~ ρ V B) 3 (A V B) is a theorem (p is a propositional variable). Therefore, from (1) we have that (3) (ρ V Α) Λ ( ~ Ρ V Β) ο (ρ V Α) Λ ( ~ Ρ V Β) Λ (A V Β) is a theorem.

Automatic Theorem Proving Based on Resolution

209

If a wff in CNF contains a pair of clauses of the form (ρ V A) and (— ρ V Β), then applying to the wff the equivalence rule with theorem (3) adds the clause (A V B) to the conjunction of clauses: the new and the old wffs will be simultaneously satisfiable or unsatisfiable. If neither A nor Β contains the propositional variable p, then the operation produces a clause (A V B) independent of p. Furthermore, if A is empty and Β is the propositional variable q, resolution produces the clause consisting of only q from the clauses ρ and ( ~ ρ V q). If —' q was already present as a clause, then q/\ ~ q arises in the conjunction of clauses and unsatisfiability is proved. The completeness of resolution (see Section 3.4.1) asserts that some such unsatisfiable conjunction necessarily arises if resolution is applied in all possible manners to the negation of an unsatisfiable wff in CNF. We can extend the operation and admit that resolution can be applied to the clauses q and — q to yield the empty clause. The proof of unsatisfiability thus amounts to a derivation of the empty clause by resolution. We now come back to the example presented above and exhibit a proof of unsatisfiability. The clauses from the wff in CNF are written in a column. A resolution operation is represented by writing the new clause (called the resolvent) at the right of its parent clauses and connecting it to its parents (Fig. 1).

F I G . 1.

( ~ ρ V q) and ρ are resolved and produce q; ( ~ s V ~ r ) and s yield — r; — r and ( ^ q V r) yield — q, and we are done since q /\ — q arises in the resulting conjunction. In Section 1.4, we mentioned that the method for proving the validity of S and the method for proving the unsatisfiability of — S can be formulated in a dual manner. We now illustrate the point by showing how resolution can be applied to a procedure that proves validity and we exhibit a proof of the same example as above. The wff to be tested was (((P 3 q) Λ (q 0 r) Λ (s Ο - r)) Ο (ρ 3 - s)). Instead of being negated and transformed into CNF, it is transformed into another canonical form, the disjunctive normal form, where the wff is expressed as a disjunction of conjunctions of propositional variables and negations of propositional variables. The rules to be applied to obtain this form are the same as those used to obtain the CNF. They readily yield (ρ Λ — q) V (q Λ — r) V (s Λ r) V — ρ V — s. Resolution is based upon the following two propositional theorems (where A and Β are

210

A. Pirotte

wffs and ρ is a propositional variable) :

(2') ( Α Β ) 3 ( ρ Α ) ν ( ~ Ρ Λ Β ) , Λ

Λ

(30 (ρ Λ A) V ( ~ ρ Λ Β) ο (ρ Λ A) V ( ~ ρ Λ Β) V (A Λ Β).

Note that the difference (implication reversed) between theorem (2') and the corresponding one of the refutation approach (theorem (2) above) does not appear in (3') and (3) above. The proof of validity of the wff in the example is isomorphic to the proof of unsatisfiability of its negation. One concludes that the wff is valid when obtaining q V ^ q , or by extension, the empty disjunction. In Section 3.1.3 we make further remarks on the parallelism between proofs of unsatisfiability and of validity for the predicate calculus. 3· First-order Predicate Calculus 3.1. DEFINITION

The definition presented here follows the semantic approach to logical systems. It is quite similar to the definition given for the propositional calculus. The syntactic part defines the language, i.e. the way to build and recognize the wffs. The semantic part specifies how to choose an interpretation for a wff and how to compute the truth value of the wff in an interpretation. However, unless the domain over which the quantified variables range is restricted to finite sets, the semantic rules are to be construed as intuitive means for evaluating the truth value of wffs. 3.1.1. Syntax

Symbols (a) Propositional connectives: Λ, V, 3, o (b) Individual variables: x, y, z, . . . (c) Function symbols : f, g, h, . . . (d) Predicate symbols: P, Q, R, . . . (e) Quantifier symbols: v> 3, (f) Punctuation symbols: (,) Terms (a) An individual variable is a term, (b) If f is a function of η arguments, and if ti, t2, . . . , t are terms then f(ti, . . . , t ) is a term. n

n

Note: constants are functions of no arguments f(), g() . . . ; they are also denoted a, b, c, . . .. Atomic formulas If Ρ is a predicate symbol of η arguments and if ti, t2,..., t are terms, then P(ti, . . . , t ) is an atomic formula. n

n

Note: propositional variables are atomic formulas of no arguments P(), Q() . . . ; they are also denoted p, q, . . ..

Automatic Theorem Proving Based on Resolution

211

Propositions (a) An atomic formula is a proposition. (b) If A and Β are propositions, so are ~ Α, (Α Λ Β), (A V Β), (A 0 Β), (Α ο Β). Quantifiers If χ is an individual variable, then (yx) and (3x) are quantifiers containing x. Wffs (a) Propositions are wffs. (b) If A is a wff and Q is a quantifier, then Q(A) is a wff and A is the scope of Q. Sentences A variable in a wff is bound if it appears within the scope of a quantifier containing this variable. A variable in a wff is free if it is not bound. A wff with no free variable is a sentence. The rest of the present paper only deals with sentences. The remarks made for the propositional calculus about the use of precedence relations among connectives and the omission of parentheses hold unchanged for the predicate calculus. 3.1.2. Semantics

Rules for choosing an interpretation for a wff (a) Choose a domain D = a set of individuals. (b) Choose a mapping D -> D for each function symbol of η arguments. (c) Choose a subset of D for each predicate symbol of η arguments. n

n

Intuitive rules for assigning a truth value to a wff with respect to an interpretation (a) Replace each wff of the form (Vx)(A) by A ai Λ A a Λ . . . Λ A ai Λ . . . where ai is the i-th element in D and A a means the result of substituting a for each free occurrence of χ in A; if there is no free occurrence of χ in A, (Vx) (A) is replaced by A. (b) Replace each wff of the form (3x) (A) by A ai V A a V . . . V A ai V . . . ; if x does not occur free in A, (3x) (A) is simply A. (c) Apply functions to their arguments according to the mapping associated with function symbols. (d) Assign "true" to each atomic formula whose ordered set of arguments is in the subset of D assigned to the predicate symbol when choosing the interpretation. Otherwise assign "false". (e) Evaluate propositions in the same way as in the propositional calculus (propositional connectives having the same usual meaning). x

x

x

2

x

r

x

x

x

2

n

Whereas the semantic definition of the propositional calculus yields a straightforward decision procedure, the rules just given for computing the truth value of a wff in a given interpretation cannot be implemented as an algorithm: steps (a) and (b) involve the replacement of quantifiers by a conjunction or a disjunction of wffs, infinite in number if D has an infinite number of elements. Moreover, an algorithm for testing validity or unsatisfiability on the basis of such rules would require considering every possible interpretation, but the

212

Α. Piro tie

number of possible interpretations is obviously not countable : choosing an interpretation involves choosing a domain D, functions whose only constraint is to be total on the domain, and subsets of the domain. An example

We now show how the rules listed above can be used to prove the validity of the following wff: ( x) (P(x)) 0 (vx) (P(f(x)))V

(a) (b) (c) (d)

Choose any domain D with elements di. Choose any total function f: D -> D. Choose any subset Ρ ç D where the predicate Ρ is true. Transform the wff into: P(di) P(d )A-.A

DP(f(di)) ....

2

A

If Ρ is not D, then the wff is true in the corresponding interpretation since at least one of the conjuncts in the antecedent is false and so is the antecedent. If Ρ is D, then every P(di) and every P(f(di)) is true and so is the wff in the corresponding interpretation. 3.1.3. Quantifier-free Conjunctive Normal Form

The first step performed by the proof procedures that will be described in the following sections is a transformation of the wff to be tested into a canonical form, the quantifier-free conjunctive normal form (CNF). Before describing the transformation, let us recall some definitions (Section 2.2.2). A literal is an atomic formula or its negation. A clause is a disjunction of literals. A wff in clause form or CNF is a conjunction of clauses. The transformation is performed in two steps. The first one consists in eliminating the " o " and "D" connectives reducing the scope of the symbol and obtaining the conjunction of clauses. All these operations are the same as for the propositional calculus (Section 2.2.2). Rules must be added for reducing the scope of the negation symbol in wffs containing quantifiers. The following two rules are needed (their justification can be derived from the semantics of quantifiers and from the negation of a conjunction and of a disjunction): ~( x)(P(x)) y), x' y') where we have already performed the renaming substitution {x'/x, y'/y} in (2). A unifying substitution, given by the unification algorithm, is σ = {g(x', y')/x, y/x', y/v, y'/u, y'/w}. The resolvent of (1) and (2) is ~Q(y,z,y)VQ(y\z,y').

(5)

We can say that (I) and (2) are a notation for the whole family of their respective instances. By performing the unifying substitution on (1) and (2) we restrict the family of instances, and we obtain exactly all the instances that can resolve together.

Automatic Theorem Proving Based on Resolution

225

More precisely, applying σ to (1) and the renamed (2) yields

d')

~ Q(g(x\ y'), y, y') V ~ Q(y, z, y) V Q(y', z, y'),

(2') Q(g(*', y'), y, y')Every ground instance of (Γ) can resolve with the corresponding ground instance of (2') to produce a ground instance of the resolvent (5). This correspondence and the interest of working at the highest possible level in the families of instances is best summarized by the property we used in proving the completeness of resolution, namely,

R (H(S)) ç H(R (S)). n

n

We terminate the proof of example El as follows: (4) and (5) can be resolved and yield: Q(y, z, y).

(6)

Clauses (3) and (5) can be resolved and yield the empty clause (usually denoted as Q ) . A comparison with the proof obtained with the Davis-Putnam algorithm illustrates the power of the resolution formalism. 3.4.3.

Strategies

Up to now we have described only the resolution principle and the simplest strategy to incorporate it in a proof procedure : this basic procedure merely consists in generating all the possible resolvents from a given set of clauses. It is possible to introduce restrictions in the choice of pairs of clauses to be resolved and in the literals to be resolved upon without losing the completeness property of the basic procedure. In other words, the "select" operations in steps (b) and (c) of the basic procedure (Section 3.4.1) need not be as trivially simple as the construction of all possible resolvents. Much work has been devoted to the search for such "restricted strategies" for applying the resolution principle. Example E2 Let us first give an example which shows that the basic procedure can be particularly inefficient. The wff S consists of a list of special axioms and of a wff to be tested for theoremhood with respect to the axioms. We generate the resolvents by levels: first R (S) — S; then R (S) — R (S) by first resolving one clause from R (S) — S with one clause from S and then two clauses from R (S) — S ; then we start generating R (S) — R (S) first by resolving one clause from R (S) — R*(S) with one clause from S, then one clause from R (S) — R (S) with one clause from R (S) — S, then two clauses from R (S) — R (S): the empty clause is obtained in R (S). All the resolvents are collected in Table 1. Several features are worth pointing out in the results of Table 1. Only six operations (underlined in Table 1) out of fifty actually performed were strictly needed to obtain the empty clause. Most obviously irrelevant is the work performed on the first two axioms, since their descendants cannot interfere with any literal from the other clauses. We also remark that, especially in computing the clauses in R (S) — R (S), many redundant steps were performed by the basic procedure. In this section we describe the means that have been suggested for improving the basic procedure. We first present two deletion principles, purity and subsumption, which can be in force in any resolution procedure at any moment to delete irrelevant clauses. X

2

X

X

X

3

2

2

2

X

2

1

3

3

2

X

226

A. Pirotte

Then we describe an alternative to resolution as a transformation rule (or "inference" rule) : binary resolution plus factoring. In Section 3.4.3.3 several strategies for applying resolution are reviewed. By strategy is meant a set of constraints on the selection of clauses to be resolved. Some strategies are addressed to the problem of avoiding irrelevant work, namely the production of clauses which do not contribute to a successful path to the empty clause. This problem is typical of many applications : a large number of axioms describe a theory or universe and the proof of a given theorem does not in general require information to be extracted from every axiom. TABLE 1 : EXAMPLE

S Axioms 1 P(x) 2 ~ P ( x ) V P(f(x)) 3 S(x) 4 ~ S ( x ) VT(x) 5 —T(x) V U(x) 6 ~ U ( x ) V Q(x) 7 —Q(x) V W(x) 8 ~ W ( x ) V R(x) Negated theorem 9 • ~R(f(g(x)))

RKS)—S

E2

2

10 + 2 11+5 12 + 3 12 + 6 13 + 4 13 + 7 14 + 5 14 + 8 15 + 6 15 + 9

: 17: : 18: : 18 : 19: : 19 : 20: . 20 : 21: : 21 : 22:

2

3

R ( S ) --RKS)

R ( S ) --R (S) 17 18 19 19 20 20 21 21 22 23 24 24 25 25 26 18 19 20 20 21 22 23 24 25 26 21 22 23

P(f(f(x)) U(x) ~S(x)VQ(x) ~ T ( x ) V W(x) ~U(x)VR(x) ~Q(f(g(x)))

16 + 7 : 22 11 + 13: 23: Q(x) 12 + 14 24: - S ( x ) V W ( x ) 13 + 15 25 ~ T ( x ) V R(x) 14 + 16 26: ~U(f(g(x)))

1 + 2: 10:P(f(x)) 3 + 4 : ll:T(x) 4 + 5: 12: ~ S ( x ) V U(x) 5 + 6: 13: ~ T ( x ) V Q(x) 6 + 7: 14: —U(x) V W(x) 7 + 8: 15: —Q(x) V R(x)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

2 : 27: 6 : 23 3 : 23 7 : 24 4 : 24 8 : 25 5 : 25 9 : 26 6 : 26 7 : 28: 3 : 28 8: 29: 4 : 29 9 : 39: 5 : 30 14: 28 15. 29 11. 28 16 30 12 29 13 30 15 31: 16. 32: 11. 31 12. 32 18 31 19 32 22 33

P(f(f(f(x))))

W(x) —S(x) V R(x) ~T(f(g(x)))

R(x) ~S(f(g(x)))



8 + 9:16:~W(f(g(x))) I

Then the set of clauses given to the theorem-prover is never "minimal", that is, many clauses are unnecessary to a derivation of the empty clause. Inferences on these clauses should be avoided. Other strategies aim at preventing the same inference steps from being performed several times. More specifically, if a clause is to contribute to the derivation of the empty clause, then each of its literals has to be removed. If the clause has η literals, then, in the worst case, n! possible orders are possible to remove the literals. Ideally restrictive strategies should constrain the resolution process and allow only one path to the empty clause. Finally, in Sections 3.4.3.4, 3.4.3.5 and 3.4.3.6 a generalization of resolution is presented together with strategies for including it in proof procedures.

Automatic Theorem Proving Based on Resolution

227

Little data is available about the relative efficiencies of different strategies, apart from theoretical investigations on the classification of strategies and their efficiency by Kowalski [65, 66, 67] and Meitzer [90], and recent experimental work by Reboh et al. [165]. Two often confused characteristics of a strategy are at stake when dealing with its efficiency: the simplicity of the proofs it produces and the difficulties it encounters when looking for a proof. Let us only make some very general remarks. First, the shortest proof is obtained by the basic procedure since it performs a breadthfirst search among all the resolvents that can be generated. Second, a strategy, as defined above, reduces the number of resolvents that are generated (hence it reduces memory requirements) and it reduces the candidate paths to a successful proof. Finally, nothing definite can be said a priori about the time requirements of different strategies; sophisticated strategies spend much time in selecting the clauses to be resolved, they yield longer proofs than simpler strategies but they generate fewer irrelevant clauses. The algorithms are described at a high level with respect to the implementation problems; therefore efficiency may be very dependent on subsequent implementations. Among others, the following operations are expensive and frequent, and they should be carefully programmed: applications of the unification and subsumption algorithms and insertion of a clause in thefileof clauses after testing whether or not it (or some alphabetical variant of it) is already present. 3.4.3.1 Deletion

principles

(a) Purity. A literal is pure in a set of clauses if it cannot be unified with another literal with the opposite sign from some other clause in the set [119]. In example E2, the literal P(f(x)) is pure in the set of clauses. It is not difficult to prove that if literal L from clause C is pure in the set of clauses S, then S is unsatisfiable iff S — C is unsatisfiable; therefore clause C may be deleted from the setS. In example E2 the second clause may be deleted ; then the first clause may also be deleted since P(x) has become pure; and the irrelevant work that the basic procedure would have performed is avoided. The purity principle directly corresponds on the ground level (i.e. for instances over the Herbrand universe) with rule 3 of the Davis-Putnam algorithm (Section 3.3.1). The purity principle is a simple criterion of relevance for clauses but, in a large set of clauses, its application involves numerous applications of the unification algorithm. (b) Subsumption. Given two clauses C and D, C is said to subsume D if there exists a substitution σ such that CG ^ D (all the literals of Co appear in D). The basic property of subsumption is stated in the following theorem [119]: if, in a finite set of clauses S, D is any clause subsumed by some clause in S — D, then S is unsatisfiable iff S — D is unsatisfiable. The corresponding deletion principle states that one may delete any such clause D without affecting unsatisfiability. In example E2 the first clause subsumes the second one since the substitution {f(x')/x} transforms P(x) into P(f(x')) which is a literal of the second clause. Subsumption can be implemented in a subsumption algorithm [119] which tests whether a clause C subsumes another clause D. The subsumption algorithm bears some resemblance to

228

A. Pirotte

the unification algorithm: they both look for a substitution that unifies some literals. The unification algorithm tests whether a set of literals can be unified, i.e. transformed into a singleton. All the literals play the same part in the operation. The subsumption algorithm has a unification operation to perform for every literal in the subsuming clause and, in this operation, the literals do not play the same part since substitutions can only be performed in the literals from the subsuming clause. Like purity, subsumption is a simple criterion for eliminating irrelevant clauses, but the subsumption cannot be applied throughout a large set of clauses for obvious reasons of efficiency. We shall see later that some strategies include a test of whether a given clause subsumes another given clause. 3.4.3.2. Binary resolution

Binary resolution is a restricted inference principle which consists in selecting a single literal from each parent clause for applying resolution. The task of the unification algorithm is simplified accordingly, but if binary resolution alone is used as the inference rule, the basic procedure loses its completeness property. For example the set S of two clauses : P(x) V P(a) — P(y) V — P(a) is unsatisfiable, since unifying the two literals in the first clause with the first literal in the second clause and applying resolution yields the empty clause (σ = {a/x, a/y}). By applying binary resolution, the following clauses are created in R (S) : X

P(a) V ~ P(a)

(tautology)

P(x) V — P(a) P(x) V — P(y)

(tautology)

P(a) V — P(y). It is easy to see that the empty clause will not be obtained. To restore completeness to the basic procedure, binary resolution must be combined with another inference rule : the factoring rule. By definition, if there exists a substitution σ that makes two or more literals of a clause C collapse into a single literal, then if σ is the most general of such substitutions, Ca is a factor ofC. Factors may be added to a set of clauses since they are instances of clauses in the set. The basic procedure is complete in the following sense: binary resolution may be used as the inference rule provided, at any moment, the current set of clauses contains all the factors of its clauses. In the rest of this paper "resolution" will refer equivalently either to general resolution defined in Section 3.4.1 or to binary resolution plus factoring. Consider the previous example : P(x) V P(a) — P(y) V—P(a). Both clauses have one factor clause : P(a) ~P(a) and the empty clause is obtained by a trivial application of binary resolution.

Automatic Theorem Proving Based on Resolution 3.4.3.3.

229

Strategies

(a) Set of support. This strategy aims at focusing attention on clauses which are actually connected to the theorem being tested. It aims at avoiding irrelevant inferences to be performed on satisfiable subsets of the given set of clauses (for example on the axioms of a theory). The strategy was described by Wos et al. [157]. Basic resolution could be described as generating larger and larger sets of clauses: R° = S = initial set of clauses R = R (J {B such that Β is a resolvent obtained from two clauses in R } . n

n _ 1

n _ 1

Similarly for the set of support strategy: T° = Τ ç S: subset of the initial set of clauses S h hat Β is a resolvent of C e T and D e S U T χη χη-ι y φ n _ 1

=

s u c

n _ 1

t

}.

The strategy is complete in the following sense: the empty clause is obtained in T for some n, iff S is unsatisfiable and S — Τ is satisfiable. In practice the strategy can be formulated as follows : 1. Choose a set of support T. In normal situations, the set of axioms of a problem is satisfiable ; therefore the clauses from the negated theorem constitute by themselves a legal set of support T; in addition Τ may also contain some clauses from the set of axioms. 2. Perform resolution only when at least one of the clauses being resolved either is in Τ or is a descendant of a clause in T. Applied to example E2, the strategy produces a very short proof when the negated theorem ~ R(f(g(x))) is chosen as set of support (Fig. 3). n

P(x) ~ P ( x ) V Ρ (f ( χ ) ) S(x) ~ S ( x ) V Τ (χ) ~ T ( x ) V U (χ) ~ U ( x ) I/O

(χ)

~Q(x) l/W

(

~S(f(g(x)))

—'

T(f(g(x))) x

w w / \ » / r~5/ \ -W (χ) V R ( x ) - ^

)



~

U

(

f

(

g

(

^Q(f(g(x))) /

x

)

)

)

/

-W(f(g(x))) '

-R(f (g(x)))

FIG.

3.

(b) Unit preference. Since the goal of the procedure is to obtain the empty clause, it seems advantageous to favour resolutions in which one of the parent clauses is a unit clause (i.e. consists of a single literal). Using this strategy, a proof is obtained for example E2 as shown in Fig. 4. Wos et al. [156] showed that the unit preference strategy coupled with introduction of a level bound is complete. As we saw above, every clause generated in a proof can be assigned a level η (i.e. belongs to some R ) ; the initial clauses have level O, and if two clauses A and Β are n

230

A. Pirotte

resolved into C, then the level of C is one greater than the maximum of the levels of A and B. To set a limit k to the level of clauses in the procedure means not to add to the set of clauses a clause whose level is greater than k, i.e. consider the corresponding unit resolution as impossible. If no more unit resolutions are possible, then in order that the strategy be complete, some other non-unit resolution has to be performed and, afterwards, unit resolution tried again. P

(

x

-

)

P(f(x)> —

~P(x) l^P(f(x))^

P(f(f(x»> —

^

P ( f ( f < f ( x » » — P(f(f(f(f»»



S(x) - S ( x ) l //TT( x( )x_)" J

T

( )x

U(x)

~T(x) V U (x) ~U(x)

l/Q(x)

~ Q ( x ) V W(x)

Q(f(g(x)))

~W(x)l/R(x) ~R(f(g(x)>)

MV(f(g(x)))

^

· FIG.

4.

The combination of set of support with unit preference plus level bound also yields a complete strategy. Chang [16] relates unit resolution to input resolution (i.e. resolution in which one of the two parent clauses belongs to the initital set of clauses) by the following theorem: a set of clauses containing its unit factors has a unit proof iff it has an input proof. Chang and Slagle [17] prove the corresponding theorem for resolution plus paramodulation in functionally reflexive systems (see Section 3.4.4.1). (c) Resolution with merging. A clause is called a merge if it is a resolvent of two clauses C and D and if it contains a literal which has a parent literal in both parent clauses C and D [7]. For example : C = P(x) V Q(x) V R(x) D=~P(y)VQ(y). Resolution upon P(x) and ~ P(y) yields the merge : Q(x) V R(x) where the literal Q(x) has parent literals Q(x) and Q(y) in C and D respectively. Q(x) is called a merge literal. The interest of merges is to provide a means of progressing toward shorter clauses. Let us point out that factoring, unit resolution and "lucky collapsing" also have this property. An example of the latter case is the resolution of the following clauses: R(x) V P(a) V P(x) V Q(x) yielding

— R(a) V S(y) P(a) V Q(a) V S(y).

Automatic Theorem Proving Based on Resolution

231

The literals P(x) and P(a) in the first clause have collapsed when the unifying substitution {a/x} was applied. Let us also point out that a literal can have more than one parent literal only by factoring, merging and collapsing. A proof procedure based on resolution with merging is a strategy in which one parent clause of every resolvent must be either an initial clause or a merge; in other words, two clauses which have been obtained by resolution but which are not merges cannot be resolved together. Andrews proved the completeness of resolution with merging. He also proved its compatibility with the set of support strategy [7]. ("Compatibility" means that the conditions set by each strategy to the acceptance of a resolvent may be simultaneously demanded without losing completeness.) (d) Linear format. A derivation by resolution of the empty clause from the set S of initial clauses is in linear format if there exists a sequence of clauses Bi, B2, . . ., B such that: n

(1) Bi e S, (2) for i > 1, Bi is the resolvent of Bi-i with: (a) either a clause in S, or (b) some Bj (j < i), (3) B is the empty clause. n

The strategy is complete (Loveland [74], Luckham [80]). The clauses in the derivation are in a linear sequence starting from a clause in S. Two clauses in S are never resolved together (except at the first step). In Section 3.4.3.3 (a) we gave a proof of unsatisfiability for example E2 which is in linear format. Moreover, every resolution is performed on the latest clause in the derivation and on a clause belonging to S. This particular case of linear format is called "fish-tail" derivation [108,161]. The strategy is still complete if a further refinement is introduced, as suggested by Loveland [74, 77]: in case (2)(b) above, the resolvent Bi must subsume an instance of B1-1. Loveland refers to this strategy as "s-linear deduction". He proved that it is compatible with the set of support strategy. (e) Ordering of literals. Several strategies reduce the number of resolvents that can be produced on the basis of an arbitrary ordering of the literals in the clauses. The ordering restricts the number of literals upon which resolution can be attempted. For a set S of ground clauses, an ordering A of the literals is a sequence Ai, . . ., A of all the atoms in S where i > j implies that Ai is "greater" than Aj. An atom and its negation are treated as "equal". This ordering is called an A-ordering of the atoms [112, 136]. A complete strategy is obtained when resolution is allowed only if the literal resolved upon is the greatest in one of the two parent clauses, given an arbitrary A-ordering. A partial Α-ordering for the literals in a set S of general clauses can be defined as follows. A total Α-ordering on all the ground instances of the atoms in S is first defined. This total Α-ordering induces a partial ordering on the atoms of S as follows : Li is greater than L2 iff Lia is greater than L2a for all the ground instances Lia, of Li and L2. A complete strategy is obtained when resolution is allowed only if the literal resolved upon is not less than any other literal in one of the two parent clauses [64, 112,142]. Another ordering, calledP-ordering [136], can be defined for general clauses: it consists in k

232

A. Pirotte

defining a total ordering on the predicate letters in the set S of clauses. P-ordering clearly permits less discrimination between the literals than A-ordering. Reiter [112] further refined the idea of ordering for general clauses by defining a C-ordering. All the clauses in S are ordered arbitrarily and independently from each other, that is, speaking of, for example, the rightmost literal in a clause is now meaningful. Reiter proved that a complete strategy is obtained if factoring and binary resolution are applied as follows. If C is an ordered clause and if σ is the mgu of the literals Li, . . ., L which appear in that order in C, then the ordered factor Ca is obtained by deleting L2,. . ., L from C and applying σ to the remaining literals, i.e. by "merging to the left". Binary resolution of two clauses C i and C2 is allowed only if the literal resolved upon is the rightmost literal of Ο . Let C i be L i . . . L and C2 be L'i . . . L' . Then L cr = Li'a for some i and mgu σ. The ordered resolvent is made of L\o . . . L _ i a followed by C2° where o, Si = Si — 1 U {all clauses that can be obtained by paramodulating two clauses in Si — 1}. (c) For even i > o, Si = Si — 1 U {all clauses that can be obtained by resolving two clauses in Si — 1}. (d) Then each deduction from S is in S for some η \ if Sn contains the empty clause, a refutation has been found. The completeness of the basic procedure is an open problem. Wos and Robinson [160] showed that it is complete if S contains the functionally reflexive axioms. For such systems, they also proved the compatibility of the set of support strategy with the procedure combining resolution and paramodulation [160]. Several results on combinations of paramodulation with other strategies have been reported in the literature. Chang and Slagle [17] showed that linear resolution with set of support can be extended to paramodulation while preserving completeness in a functionally reflexive system. Chang [15] showed how to combine paramodulation with renamable resolution. Kowalski [63] made clear the correspondence between paramodulation and hyper-resolution, by showing how the hyper-resolvents involving equality axioms are interpreted as paramodulation operations. From this connection, it follows that a strategy compatible with hyper-resolution translates into a strategy compatible with paramodulation. These ideas of Chang and Kowalski were elaborated upon by Slagle [142,143] who proposed a general method for building-in special theories. In the same way as some equality axioms can be dispensed with by introducing paramodulation, Slagle showed how some axioms of the theories of partial ordering and sets can be replaced by new inference rules which preserve the refutation completeness. Slagle suggested that such a special treatment of particularly important axioms would result in increased efficiency, mainly because inferences involving these axioms can be more effectively controlled with special rules than with resolution. Slagle and Norton [166] built a program having a partial ordering rule, which is quite successful compared with a program where partial ordering is expressed as axioms. 0

n

3.4.4.2. E-resolution

E-resolution was proposed by Morris [94] and later investigated by Anderson [4]. It is a combination of paramodulation and resolution, in which equality substitutions (paramodulation) are not applied unless they can lead to the production of a resolvent. The procedure is parallel to the basic resolution procedure (Section 3.4.1), the difference being that the latter systematically generates possible resolvents starting from a set of clauses S while the former generates "E-resolvents". An Ε-resolvent R of two clauses Ci and C 2 , h e Ο and h e C 2 being the literals resolved upon, is defined as follows: it is a resolvent of d and C'2, if C'I (resp. C ) is obtained from Ci (resp. C2) by paramodulating a finite number of times from clauses in S into the literals h (resp. I2) in Ci (resp. C2) with no paramodulation into any other literal of C. When resolving C'i and C'2 into R, the literals resolved upon are the descendants of h and I2 respectively. The algorithm has to ensure that all Ε-resolvents are obtained. Therefore all possible 2

240

A. Pirotte

paramodulations must be tried, but the corresponding sequences of substitutions have only to be carried out when they unify h and I2. That is how Ε-resolution limits the numbers of clauses generated: in paramodulation, each intermediate substitution leading from h to Γι or from I2 to Γ 2 would cause the addition of a clause to the file of clauses. Here only the Ε-resolvents are added. However, two clauses may give rise to more than one E-resolvent and those must be generated. Anderson [4] derived completeness results for Ε-resolution analogous to those obtained by Wos and Robinson for paramodulation plus resolution, i.e. Ε-resolution is complete for functionally reflexive systems and so is Ε-resolution coupled with set of support. Anderson also shows by exhibiting a counter-example that neither paramodulation with set of support nor Ε-resolution with set of support is complete without functional reflexivity. Brice and Derksen [12] have proposed and implemented a modified Ε-resolution, which is still complete: when two clauses Ci and C2 are Ε-resolved, it is required that paramodulation be performed in only one of the two clauses (i.e. Ci or C2). Their Ε-resolution rule includes an elaborate tree-searching algorithm which looks for a sequence of equality substitutions that unify two atoms with the same predicate letter. 3.4.4.3. Sibert's

system

Sibert proposed [131, 132] a system of three rules of inference and a reduction rule, and proved that the rules constitute a complete system, i.e. as usual that the rules, when applied in sequence to a finite unsatisfiable set of clauses, produce the empty clause after a finite number of steps. Equality and inequality predicates are distinguished from the other predicates. The equality predicate is E(ti, t ) where ti and t are terms, and the inequality predicate is NE(ti, . . ., t ) where ti, . . ., t are terms. The intended meaning of the latter is that it is true iff ti, . . ., t are not all equal. The reduction rule is supposed to act on any clause whenever possible. Its action consists in 2

2

n

n

n

(a) deleting any clause which contains a tautology, and (b) deleting from the remaining clauses any trivial inequality such as NE(t, t). In the following, we describe the three rules of inference in a slightly simplified manner for the sake of clarity. Rule 1 acts on two clauses : A V P(ti) V . . . V P(t ), B V - Ρ ( ί Ί ) V . . . V ~ P(t' ) and infers the clause: A V Β V NE(ti, . . ., t , t'l, . . ., t' ). Rules 2 and 3 apply to clauses with only equality and inequality literals and attempt to create trivial inequalitities to be eliminated by the reduction rule. Rule 2 is essentially substitution of equals applied to maximal terms. (A term is maximal in a clause if it does not appear as a subterm of another term in the clause.) For the ground case, rule 2 is formulated as follows. It acts on (r + 1) clauses: n

m

n

m

A V E(a, ft) V . . . V E(a, ß ) Bi r

B

r

Automatic Theorem Proving Based on Resolution

241

where α is maximal in A, Bi, . . ., B and α appears in Bi, . . ., B but not in A. The rule infers the clause : r

r

AVBi{ft/a} V . . . VB {j8 /a} r

r

where {ft/a} is an obvious extension of the notation for substitutions (a being a term instead of a variable). Rule 3 is introduced because of the maximality constraint in rule 2: it reduces the degree of functionality so that rule 2 can hopefully act. For the ground case, rule 3 acts on a clause A containing a term f(t) which is maximal in A. If f(t') is some other term such that f(t) is not a subterm of f(t'), then the following clause is inferred: NE(t, t')VA{f(t')/f(t)}. Sibert [131] also states a modified version of rule 1, using results of semantic resolution, and he proposes a subsumption search principle; these modifications preserve completeness. Paramodulation, Ε-resolution and Sibert's rules are methods which describe how to apply equality substitutions. Ε-resolution has the advantage over paramodulation that it generates less clauses. Practically, this is desirable for the theorem prover which performs worst on large sets of clauses. But more is needed to have a satisfactory treatment of equality, namely algorithms for deciding when to apply equality substitutions. The basic procedure combining resolution and paramodulation systematically performs all possible substitutions and generates a lot of useless clauses. Morris [94] proposed a simple rule which consists in calling Ε-resolution on two literals only if the two literals cannot be unified without equality substitutions. Anderson [4] showed that this rule makes the system incomplete. What could be more effective is an algorithm which identifies situations where an equality substitution could be profitable, and which does this by examining not only the formal structure of the clauses but also their meaning. But it is very difficult to include such "heuristic" information in the resolution framework (see Section 4.2). 4. Applications The number of resolution theorem-proving programs has become so large that is it difficult to cite them exhaustively. One the first and most successful programs was written by Wos, Carson and G. Robinson [156-8]. It is based on unit preference and set of support and it proved many theorems in abstract algebra that its predecessors were unable to prove. Since then, many programs have been developed either to demonstrate the effectiveness of proposed strategies or to experiment with the logical formalism as a representation for the problems of artificial intelligence. This chapter is devoted to the presentation of a sample of programs, whereas the bibliography at the end of this paper includes references to most existing programs. Section 4.1 presents in some detail examples of how resolution theorem provers have been used in question answering, problem solving and automatic programming. The programs described are typical of the "resolution-only" approach, that is, the whole problem has to be formalized in the language of the predicate calculus and the only inference mechanism is resolution. When theorem provers are applied to artificial intelligence, the problem to be solved is formulated as a theorem to be proved: whether this alleged theorem is indeed a theorem or

242

Α. Piro tie

not is not in general a sufficient answer for the original problem. Instead, the answer has to be reconstructed from a description of the proof generated by the theorem prover. How this can be done is shown in Section 4.1. The "resolution-only" method has failed so far to provide a really satisfactory approach to realistic problems and the method is now criticized by many as being too extreme : it is not always natural to describe the whole of a problem by writing axioms in the predicate calculus and, more importantly, it is unnatural to have as the only inference mechanism a uniform and subject-independent rule. Section 4.2 is devoted to the description of some recent proposals to use a resolution theorem prover as a module in a program where other problemsolving methods are available. Using resolution on subproblems might prove to be more efficient and more natural than the "resolution-only" approach. Section 4.2.4 briefly describes how interactive programs have been successful in enabling users to experiment with a problem domain or with strategies and combinations of strategies. 4.1. APPLICATIONS to SOME DOMAINS IN ARTIFICIAL INTELLIGENCE 4.1.1. Question Answering

Most generally, a question-answering system is a program that answers questions on the basis of a body of information called its data base. Usually question-answering systems are distinguished from information-retrieval systems in that the former necessarily require some deduction to derive the answers. In other words, in a question-answering system, all the information that is available is not stored explicitly. Therefore some automatic deduction has to be performed and theorem-proving methods are a possible solution: then the language of the question answerer is the predicate calculus and its deductive mechanism is an automatic theorem prover. We now describe the work performed by Green and others at Stanford Research Institute [24, 50-4]. It includes the application of a theorem-proving program to a question answerer. The structure of the system is fairly simple: the knowledge of the world, i.e. the data base of the question answerer, is expressed as a set of axioms and the questions asked are presented as theorems to be proved by a theorem prover. If a proof is possible, then the answer to the question is extracted from the proof. The following simple chemistry example illustrates the method [24, 52]. Suppose the data base includes, among others, the following axioms (stated in English and in predicate calculus) : (1) Magnesium burns rapidly. BRUNSRAP (MA) (2) Gasoline is a fuel. FUEL (GASO) (3) Gasoline is combustible. COMBUST (GASO) (4) Combustible things burn. (Vx) COMBUST (χ) 0 BURNS (x) (5) Things that burn are combustible. (Vx) BURNS (x) D COMBUST (x) (6) Fuels are combustible. (Vx) FUEL (x) 3 COMBUST (x)

Automatic Theorem Proving Based on Resolution

243

(7) Anything that burns rapidly burns. (Vx) BURNSRAP (x) 3 BURNS (x) (8) Gasoline does not burn rapidly. — BURNSRAP (GASO) If the question "Is magnesium combustible?" is asked, the theorem prover attempts to prove the unsatisfiability of the set of clauses built from the axioms and the question: "COMBUST (MA)". In this case it will fail to find a proof and, after a given amount of time, unsatisfiability will be searched for with the negated question: " ~ COMBUST (MA)". Now the empty clause is obtained, and the answer to the original question is "Yes". When unsatisfiability is obtained with the unnegated question, then the answer is "No". Whereas the mechanism for answering yes-no questions is straightforward, this is not the case for questions containing existential quantifiers. For such questions, in the case of a "Yes" answer, one also wants to know at least one example of an object that fulfils the conditions expressed in the question. For example, consider the question: "Does there exist some combustible that does not burn rapidly?" i.e. (3x) COMBUST (χ) Λ — BURNSRAP (x) The negated question is: (Vx) — COMBUST (χ) V BURNSRAP (x) A proof is easily found, but the theorem prover does not indicate that gasoline is the answer. Green [52] suggested a simple device that does the job: after the question has been negated and converted to CNF, then an "answer" literal is added to each clause in the negated question. In the previous example, the clause from the negated question becomes — COMBUST (χ) V BURNSRAP (χ) V ANSWER (x) The answer literals are ignored by the theorem-proving process except that they are instantiated just as other literals when a substitution is performed. Clauses containing only answer literals are answer clauses, and the search for an answer successfully terminates when an answer clause is obtained. In the above example, the negated question is resolved with axiom (3) yielding: BURNSRAP (GASO) V ANSWER (GASO) which is resolved with axiom (8) yielding: ANSWER (GASO) Another method for retrieving "realizations of existential quantifiers" was proposed by Luckham and Nilsson [81]. It differs from Green's method in that it extracts information from a proof after the proof has been completed. It essentially amounts to working out the substitutions in the answer literals only as it is required by the successful proof tree, pruned of its irrelevant branches. The problem of the representation of the data is crucial to all question-answering systems, and obviously the predicate calculus approach is not the most natural (see, for instance, axiom (7) in the previous example). In large data bases, problems of consistency arise in the choice of predicates, functions and objects because several representations in the predicate calculus could often equally well model some part of the subject matter.

A. Pirotte

244

The advantages of the theorem-proving approach to question answering lie in the universality of the predicate calculus and also in the generality of the inference mechanism, i.e. its independence of the subject matter. These advantages are effective where the theorem prover is presented a small set of axioms such as the "toy" chemistry example just presented or, say, the axioms of group theory. However, an essentially unsolved problem is that of large data bases, that is, the problem of how to perform inferences in a reasonably efficient way in the presence of a large set of irrelevant axioms. 4.1.2. Problem Solving

The distinction between question answering and problem solving is not always clear-cut. Suffice it to say that while question-answering systems derive merely answers to questions asked to them, the output of problem solvers is generally not a simple fact (e.g. a plan of action for a robot, a move for a game-playing program, etc.). Green's program [52, 54] was also applied to problem solving. We give here the flavor of the method by describing a simplified example from robot problem solving. The example uses a state-transformation method to help describe a problem in logic. At any moment the universe under consideration is supposed to be in a given state s. Changes of states are caused by the performance of actions: an action is represented by a function that maps a state into a new state. Suppose that an object, e.g. a robot, is in position a in the initial state so. The situation is represented by an axiom : AT(a, so)

(1)

Suppose that the robot can move to position b by performing action i or to position c by performing action h : (Vs) AT(a, s) 0 AT(b, i(s)) V AT(c, h(s))

(2)

If the robot can move from b to d and from c to d by performing j and k respectively: (Vs)AT(b,s)DAT(d,j(s))

(3)

(Vs) AT(c, s) 0 AT(d, k(s))

(4)

If we want to know whether a path exists from a to d, we ask the question "does there exist a state, resulting from applying action functions to the initial state, such that the robot is in d?": (q) (3s)AT(d, s) The following lines show how the answer is derived. First the axioms are transformed to CNF: AT(a, s )

(1)

~ AT(a,s) V AT(b,i(s)) V AT(c,h(s))

(2)

~AT(b,s)VAT(d,j(s))

(3)

~ AT(c,s) V AT(d,k(s))

(4)

0

The question is negated and an answer literal is added : (nq) ~ AT(d,s) V ANSWER (s)

Automatic Theorem Proving Based on Resolution

245

The proof proceeds as follows: (nq; + (3) : ~ AT(b, s) V ANSWER (j(s))

(5)

(nq) + (4): ~ AT(c, s) V ANSWER (k(s))

(6)

(2) + (6) : ~ AT(a, s) V AT(b,i(s)) V ANSWER (k(h(s)))

(7)

(5) + (7) : — AT (a, s) V ANSWER (j(i(s))) V ANSWER (k(h(s)))

(8)

(1) + (8): ANSWER (j(i(s ))) V ANSWER (k(h(s ))) 0

0

(9)

Now we can derive a plan of action (see Fig. 5) by interpreting the answer clause (9). b

c FIG.

5.

Two solutions are possible; they are extracted by starting with the innermost function and working outward in each answer literal : either perform i and then j or h and then k. Green [52] has applied his program to several test problems, e.g. the monkey and the bananas, the towers of Hanoi, and also to robot planning for the Stanford Research Institute robot. It is not the place here to discuss further the details of this problem-solving method. It seems clear that the state-transformation method cannot handle in a natural way even moderately complex successions of events in time. The "resolution-only" formalism prevents any modification of the set of axioms, although creating and deleting axioms might be natural as a description of the evolution of a system. This problem of creating and maintaining an appropriate description of the state of a process in evolution is called the frame problem and is an area of current research in artificial intelligence [109]. In Section 4.2.3 we present a simpler solution to the robot problem which is obtained by not depending exclusively on theorem-proving methods [40]. To keep this paper to a reasonable size, no comparison has been attempted between the resolution theorem-proving approach and the numerous other approaches to question answering and problem solving. Several approaches are surveyed in two recent textbooks by Nilsson [97] and Slagle [141], which are good introductions to the field. 4.1.3. Automatic Programming and Program

Analysis

The problem of automatic programming can be presented as the construction of some powerful problem-solving compiler in the following sense [21]. The task that a program has to perform is precisely specified in the form of a description of a relation between an initial situation and a final situation. Given such descriptive information, the problem-solving compiler has to produce a program in some language that achieves the transformation of the

246

A. Pivot te

input situation to produce the output situation. Implicit in the generation of the program is a proof of its correctness, i.e. a proof that it conforms to the given specifications. Much work is being devoted to studying the problems of automatic program synthesis, proof of program correctness and program verification and equivalence, but nothing like a complete system for automatic programming exists. The purpose of this section is to sketch briefly how resolution theorem provers have been applied to program synthesis and some aspects of program analysis. By no means is this section a survey of the various methods that are investigated in the approaches to automatic programming (see, for instance, Cheatham and Wegbreit [21] or Elspas et al. [162]. 4.1.3.1. Automatic program

synthesis

The problem of automatic program writing using theorem-proving methods can be formulated as follows [52, 71, 82, 146, 147]. A computer program can be considered as a function ζ = f(x) acting on a set χ of input variables (xi, . . ., x ) to produce a set ζ of output variables (zi, . . ., z ). Suppose we can describe in predicate calculus a desired relation φ(χ, y) between input and output with the intended meaning that ψ(χ, y) is true iff the correct relation holds between χ and z. The problem is then to prove the theorem n

m

(Vx)(3z) 0 Λ P(x)) Λ (Vy) [(P(y) Λ y > 0) 3 P(y — 1)]} D P(0). A first-order instance is selected by making P(x) = Q(xi χ (x - x), x), 2

where χ is the (uninterpreted) multiplication operator. How the particular induction axiom is chosen is a difficult part of the problem, as it is for program synthesis. Transformed into CNF, the induction axiom produces the following three clauses : —χ > 0 V ~Q(xi x (x - x), x) V Q(xi χ (x - a), a) V Q(xi χ x , 0),

, η an integer, denotes the actual parameter corresponding to the n-th syntactic element in the syntax string (cf. Leavenworth's meta-variables beginning with the symbol $). Finally, inc is a new basic symbol whose internal form has to be defined as follows: BASIC SYMBOL inc, internalvalue where internalvalue gives the internal code of inc. It should be noted that this feature of LACE allows changes to the character set to be made in a trivial manner. Data types are introduced by statements of the form TYPE complex, 64 TYPE string, variable where the second item is either the length in bits of the storage required for an item of the particular datatype or an indication that storage requirements may be variable. An operator can be defined by the specification of its priority and the code that has to be generated for particular operand-type combination. For example, PRIORITY, + , X 30 DOS + , complex, complex, complex, ". . .code. . ." DOS + , complex, real, complex, ". . .code. . ." DOS + , real, complex, complex, ". . .code. . ." where DOS stands for DYADIC OPERATOR SIGNIFICANCE and the code in the semantic part has been omitted because it has to be machine dependent since a very machinedependent view has been taken of storage allocation to structures. It is obvious that transfer functions from one type to another must also be defined.

A Survey of Extensible Programming Languages

297

As mentioned at the beginning of this section, the source text is to be translated by a compiler which can be altered by LACE statements. The compiler will not distinguish between base-language statements and the statements belonging to the augment text once the syntax and semantics of the latter have been defined. In Newey's paper there is no mention of the possibility of conditional replacement, and there is no adequate explanation of the manner in which the compiler is to be changed, although the intention seems to be to provide a mechanism for altering compiler table analogous to what is done in the MAD compiler. E3. ECT—The Extensible-Contractible

Translator

System

The ECT System [86] is a tool for producing language translators rather than an extensible language as such. It has been designed on the assumption that a single base language is insufficient to provide all conceivable extensions because any given base languge will in general be much too complicated for some directions of extension and at the same time be too simple for others. Thus the amount of effort required to introduce an extension may be large if the base language is unsuited to supporting the extension and at the same time the "overhead" of a given derived language may be large because of the presence of unwanted features in the translator. The ECT extension mechanism is independent of any particular base language and can be used with any number of base languages provided that these are written in the language in which the ECT system is itself written and have a grammar which can be analyzed by the analyzer used in the ECT system. The ECT system consists of an initially null set of base-language processors of graded complexity; for example, a FORTRAN-like base language, an Algol-60-like base language, a SNOBOL-like base language, and so on, and an extension mechanism for modifying these language processors or even creating a new one from scratch. The user specifies changes to the syntax and semantics of a par ticular base language by specifying the changes to be made in its processor in terms of a definition language called METALANG. These statements can modify the tables of the processor or can alter its structure. Each base-language processor is written in METALANG, which is an extension of XPL [55], and, in common with the METALANG processor, incorporates an extended-precedence analyzer similar to that of the XPL compiler. By means of METALANG statements (discussed more fully below), the user can select one of the base-language processors, introduce new features into it or delete features that are not required, so that a translator for a modified base language is produced. An important feature of the organization of the ECT system is that the parts of the base-language translator which do not need alteration remain in machine-executable form and do not need recompilation. The fact that a complete recompilation is not necessary for modifications greatly reduces the cost of language extension. METALANG has three distinct components or sublanguages : (1) A syntax-description language used to specify changes to the base-language syntax; (2) a semantics-description language used to specify the meaning of constructs in a language; and (3) a program restructuring language used to direct the insertion or deletion of translator components. This is essentially a text editor that works on object code. Syntax specifications are made in a modified BNF notation in which it is the terminal symbols rather than the nonterminal that are "quoted", concatenation is indicated by a

298

Ν. Solntseff and A. Yezerski

comma, and termination of a production is indicated by a period. For example, to introduce the operator f into the grammar (of arithmetic expressions) AE = Τ I AE, " + " , T. Τ = F I Τ, "*", F. F = V I C.

(E3.1)

we need the modification statements in PPL delete F = V | C. add Ρ = V j C. add F = Ρ I F, " f " , P.

(E3.2)

After these statements have been executed, the new grammar is AE = Τ I AE, " + " , T. χ χ | χ ρ F = Ρ I F [ " f \ P. Ρ = V I C. =

(E3.3)

The BNF statements are converted into tables used by the analyzer in the same way as in XPL. The semantics language is the language used to write the translators in the base-language set of the ECT system. It is an extended version of XPL, the main differences being that a procedure definition body is a single METALANG statement and that a single procedure may have several definition bodies, a particular one being selectable by an integer index. Procedure-array elements must have identical attribute sets, i.e. they must all return a value of the same type and the number and attributes of their formal parameters must be the same. The program restructuring language (PRL) is the component of METALANG that is provided to accomplish translator modification. PRL bears a superficial resemblance to a text-editing facility, but operates on object language files. The opening statement of a translator-modifying program is select

(E3.4)

if an existing language processor is to be modified, or create

(E3.5)

if a new language processor is to be constructed from scratch. A language processor written in METALANG consists of a set of declarations of global variables, followed by a sequence of procedure definitions. There is no block structure and one procedure must be labeled "MAIN". Each procedure can have its own set of local variables. The names of the global variables and procedures is kept in a symbol table which remains in core during execution, so that alterations to the symbol table can be made at any time by the programmer by means of suitable PRL statements; for example, the statements add (A,B,C) FIXED, add D:PROC. ( A - B + C ) delete Χ,Υ,Ζ.

(3.6)

A Survey of Extensible Programming Languages

299

result in the addition of the identifiers A,B,C of type FIXED and the procedure identifier D with the definition body (A = B+C) to the symbol table and the deletion of the identifiers Χ, Υ, Ζ together with their attribute entries. The statement replace D:PROC. ( A = B - C )

(E3.7)

results in the definition of procedure D in the symbol table being changed to (A=B—C). Changes to procedures are the main way in which changes to the semantics of a base language are made. Thus the syntax changes made by (E3.2) would be accompanied by a set of PRL statements effecting the corresponding changes to the semantics routines. In its overall strategy, the ECT system behaves as a one-pass compiler-compiler if a new baselanguage processor is being created, or a compiler-modifier if an existing base-language processor is being altered. Since the modifications are made at the level of object code, ECT is a type-Ε system. F . T Y P E - F EXTENSION

This type of extension differs from the preceding one in that, although both the augment text A and the base language text Β are translated into real-machine or abstract-machine code, Β gets converted into a text in the "standard" target code, whereas A is converted into a text S in "extended" machine code. The extension mechanism then converts S into a text in the "standard" real-machine or abstract-machine. If S is interpreted as a series of macro calls in a macro assembler language, then examples of type-F extension can be found among the translator-writing systems which have recently been reviewed by Feldman and Gries [22], and we have considered them to be outside the scope of the present survey. Extension schemes involving the rewriting of the control stores of microprogrammable computers also fall within this category. Although no examples of this technique are known to the authors, it is not difficult to foresee growing interest in this type of extensibility in view of the increasing number of microprogrammable computers that are appearing on the market. G.

C O M P I L E R / I N T E R P R E T E R E X T E N S I O N SCHEMES

The main difference between this type of extension mechanism and those described in sections 3.A to 3.Ε is that the definition-language constructs used in the latter form a set of declarations and are removed by the processor prior to the compilation or interpretation of the derived-language program. In contrast to this, the compiler-interpreter scheme strives to achieve variability by run-time processor modification, rather than by translation-time language mapping. In this section two proposals exemplifying this approach are reviewed. Gl. Lindstrom's

Proposal

Lindstrom's proposal [50] may be seen as an exercise in language design based on two philosophical ideas. The first, more basic premiss, is that significant language extension can be achieved through the variable interpretation of existing language constructs. The means for achieving this follows from the second premiss, namely, that variability can be attained in two steps : relevant compiler activities are made interpretive and, then, the language is extended to control the new run-time variability inherent in the new interpretive mode. Thus

300

Ν. Solntseff and A. Yezerski

new language behaviour can be achieved without the introduction of new language constructs, since a more flexible interpretation of existing language constructs suffices. The significant features of Lindstrom's proposal are that variability may be introduced into an existing language processor in a language-independent manner through the control of the degree of interpretation of a program. Added flexibility is achieved by allowing the programmer to cause recomposition of the program during program execution as the program is processed in an incremental manner. Variability in control or sequencing, such as the introduction of pseudo-parallel execution "threads", can be achieved through the availability of both static and dynamic interpretation of control statements. Lindstrom's system has not been implemented, but [50] contains a detailed discussion of the design of a derivative of the SIMULA language [17], the result of the extension being a conversational simulation language with added debugging facilities, an improved process organization, and a means for bottom-up simulation design. Gl. ECL—An Extensible Conversational Language

System

ECL [80] is an extensible language system which has much in common with Lindstrom's ideas although it goes further and incorporates a programming language ELI [79] which has a facility for the definition of structures, syntax, and operations as a built-in feature. ELI incorporates most of the concepts of Algol 60, LISP 1.5, and COBOL. It provides standard arithmetic operations on scalars and multidimensional arrays, dynamic storage allocation with automatic storage reclamation, record-handling and algorithm-independent data description. The treatment of datatypes in ELI differs substantially from that in other languages [81]. Data types, or "modes" as they are called in ELI, are legitimate values in the language, so that modes are not declared but may be computed and this provides a very powerful definitional mechanism since programmer-defined mode-valued procedures are possible. A "mode-compiler" [10] is provided within the system for the production of generation, selection, and assignment functions tailored to each mode. Syntax extension is built into the ELI processor which is organized as a conversational system and processes console commands one at a time. The parsing of a command is directed by parse tables previously derived from a syntactic specification of the source language. The parse tables may be changed by the programmer who can thus introduce syntax changes. The output of the parser is a list forming the intermediate text which is then interpreted. The interpretation of a command may result in a call on the compiler provided within the system and an important feature is that the compiler and interpreter accept identical languages so that compiled and interpreted code may be freely intermixed with no restrictions. For example, the value of an expression evaluated by compiled code may be used in another expression that is being interpreted, a go to statement in interpreted code may lead back into compiled code, or variables local to compiled code may be accessed by interpreted code. Because of this, the system is a true compiler-interpreter. Variability in control structures is provided within the ECL system by a mechanism which allows the programmer to create and manipulate multiple paths of control [63]. These paths may be executed in parallel, they may act as coroutines, or in any other relation which may be imposed by the programmer [23]. Since the number of paths which can be created for execution in parallel may be greater than the number of processors available on a given machine, control-path scheduling is necessary. The path scheduler is written in ELI and can be restructured by the programmer.

A Survey of Extensible Programming Languages

301

4. Discussions and Conclusions A. INTRODUCTION

At this point it is desirable to draw a comparison among extensible languages and systems surveyed in section 3. If carried out in a systematic manner, a comparison of this kind would be helpful in providing us with a perspective on the work already carried out in this area and would indicate the areas where further work was required. Unfortunately, as was demonstrated at the International Symposium on Extensible Programming Languages held in Grenoble, September 6-8, 1971 [66], there is still no agreement among the workers in the field as to what constitutes an extensible programming language and no clear coherent overview of the definitional structure of an extensible language has emerged. What is certain at this time is that extensible languages have attracted a considerable amount of attention, but it is equally clear that most of the promises that seemed very bright in 1969 [16] have largely remained unfulfilled. An increasing number of extensible languages are being implemented, but there is no sign yet that the general principles of extensible-language design have emerged from the preliminary stages. What can be done at this stage is to provide an indication of the areas where progress is most desirable and a comparison of the techniques used to achieve extensibility insofar as this is possible in the absence of a quantitative or even qualitative model. The model presented in Section 2 above is clearly only the first step in this direction.

B . BASE L A N G U A G E S

The characterization of the salient features of programming languages in general is in a far from satisfactory state at the present time, and although syntactics may be considered to be well understood and visible progress is being made in the area of semantics, very few results can be found pertaining to pragmatics, whereas the development of extensible languages and extensible-language systems has grown out of a need to adapt programming languages to humans, so that there is a large pragmatic component. An examination of the base languages used in the various extensible-language systems surveyed in section 3 shows that a variety of base languages have been proposed or implemented, and this is only to be expected considering that the choice of a language for a particular task is still largely a personal matter in the absence of any quantitative "figure of merit". We are unable to provide a quantitative scheme for the comparison of "ordinary" programming languages, let alone extensible ones, particularly with respect to their pragmatic features. A detailed comparison on qualitative grounds has been given by Sammet [65], and we shall therefore restrict ourselves only to those pragmatic aspects of programming languages that have a bearing on extensibility. The choice of the headings used in the discussion is once again a personal matter, and the authors do not lay claim to completeness. BI. Computing Power

Although it is probably well known, comparisons of languages on the basis of computing power alone are not helpful since the programming languages for general-purpose computers are universal in that any computational procedure can be written in any such language, but "to express in a given language [the] procedures for which it was not designed is a relatively

302

Ν. Solntseff and A. Yezerski

difficult task—sometimes miserably difficult—but never impossible" [2]. What is needed is a general theory of the complexity of mapping an algorithm into a procedure in the given language. B2.

Minimality

It is sometimes stated (e.g. see ref. 5) that the base language of an extensible-language system should be minimal in the sense that only a few primitive constructs are used. Since the expansion of a defined construct into the primitive set may involve a considerable amount of processing during the translation of the extended language text, it would surely be better to include in the primitive set everything that cannot be added at a "reasonable" cost by extension. This could lead to a large base language with all of the associated difficulties if only a single base language were contemplated, so that the concept of a language-independent extension mechanism appears to be more attractive. Language-independent macro systems have been used for a long time for language extension, and the principles and details of this technique are thoroughly discussed by Brown [12]. Extension mechanisms of this type are to be found in classes A, B, and C detailed above, but they suffer from the disadvantage that the chain of definitions may be too long for efficient translation. ECT [70] and Scowen's extensible compiler [67] are examples of type-D or type-Ε schemes which are truly language independent. In addition, Lindstrom [50] has proposed a compiler-interpreter system which is also language independent. More work is required in this area to explore the possibilities of a language-independent approach. B3. Flexibility

The exact choice of data structures or of an algorithm to manipulate them depends on the way in which the programmer thinks about the problem to be solved and on the manner in which he intends to manipulate the data. The base language should not be unduly restrictive in what can be expressed in it, otherwise, even assuming the existence of an "adequate" extension mechanism, a large amount of effort can be spent in providing the required extended language. One way to eliminate this potential inefficiency is to provide several base languages as mentioned above ; the other is to provideflexibilitywithin the base language. The authors would argue that programmer-defined data types such as those in SNOBOL 4 [32], PL/I [38], Algol 68 [76], or Pascal [85] are essentially a means for providing flexibility in the base language and are not per se part of the extensional facilities. Similarly, the redefinition of function calls as prefix, infix, or postfix operators should also be considered as a feature of the base language and not the extension mechanism. No one would claim that SNOBOL 4 is an extensible language, yet this feature is present in it. Another feature which is highly desirable is a programmable trap for exceptions to a regular sequence of processing steps. A plea for a feature of this kind has been made by Bagley [2], although it seems to have passed unnoticed. The power of the computer lies in its ability to perform a sequence of operations repeatedly, yet most of the effort in programming an algorithm lies in the provision of computational paths to move around obstacles to this regular progression. Something akin to the ON CONDITION of PL/I should be a feature of the base language. Programming would be made easier if to cope with the identification of a new exception, the programmer merely had to add a new "exception block" to his program without having to introduce the patches required by most current programming languages.

A Survey of Extensible Programming Languages B4. Dynamic Modification of Program

303

Structures

There should be as little restriction as possible on the kind of modification that can be performed during the execution of a base-language program. The type of modification possible should include mid-execution program recomposition, parallel execution of procedures as co-routines or tasks in the sense of PL/I, and programmer interaction with execution. This leads to the structuring of the base-language processor as a compilerinterpreter in which the invariant parts of a program are compiled while those that are to be dynamically varied are interpreted. The proposals of Lindstrom [50] and Wegbreit [79] are along these lines and the progamming language implemented by Wegbreit, ELI [81], has been discussed in section 3.G2 above. More work in this area is desirable. C . COMMENTS O N E X T E N S I O N M E C H A N I S M S C l . Extensions of Syntax

As can be seen from the extensible languages surveyed in section 3, a number of proposals for syntax extension have appeared in the last few years. They range from simple text-macro extension schemes requiring prefix macro name triggers, to recognition of arbitrary contextfree languages with complex parse-tree manipulation facilities, as well as schemes in which changes in syntactic specification are achieved by the modification of parse tables. The latter approach leads to higher efficiency in the case of arbitrary extensions because extended- and base-language constructs are treated completely equivalently and no time is spent in unraveling a series of definitions to arrive at the derived-language level, or the base-language level in the case of macro extension schemes. On the other hand, the introduction of specific extensions, such as the definition of new infix operators to replace parametrized function calls, may be done more efficiently by special techniques. New operators can be defined through the modification of symbol tables, i.e. predominantly at the lexical level. There is a considerable amount of further research to be carried out in this area, especially the study of the tradeoffs between generality and efficiency of syntax-extension schemes. C2. Extension of Data Types

The most popular means for the extension of data types is the mechanism proposed by Standish [73] which, with some modifications, is present in all extensible languages surveyed in section 3 and in some "ordinary" programming languages as well, notably, SNOBOL4, PL/I, Algol W, Pascal, and Algol 68. As noted above, a data-extension scheme of this type should really be considered to be a part of the base language. The language-extension mechanism proper should be capable of dealing with the case of the introduction of data types which are either not expressible in terms of the primitives chosen for the base language or which can only be introduced at great cost in terms of translation efficiency. The only extensible language systems that have come to grips with this problem are those based on the compiler-compiler approach. In the authors' opinion this is the only way to achieve data extensibility in the full sense of the word, especially the form of extensibility required for program transferrability from one computer to another. The use of a purely "shorthand" or paraphrasic form of extension has its merits, but this will not result in the introduction of new primitives into the language. Another area in which considerable work is required is the development of languageindependent means of describing data structures and their extensions. A start has been made

304

Ν. Solntseff and A. Yezerski

in this direction (for example, see refs. 3, 57, 2, and 21), but much work still remains to be done before we have a theoretical framework for the description of extensible languages. The notion of "metadata" introduced by Bagley [2] particularly deserves closer scrutiny. C3. Extension of Operations

In parallel with the introduction of new data primitives into a language is the need to introduce new primitive operations or to extend existing primitive operations. It is not enough merely to compose the new operations from existing primitives as can be done in every current programming language by means of the procedure-definition feature. This approach suffers from the inherent disadvantage, similar to those discussed in the case of composed data structures, that efficiency is sacrificed to obtain generality. The best approach seems to be to introduce changes in the language translator (or even the hardware interpreter by means of micro-programming) rather than build a definitional superstructure on top of a fixed translator. The answer seems to lie in a judicious blend of the compilercompiler approach and the compiler-interpreter approach discussed above. Further work is also needed to create an adequate description of operations and the means necessary to compose them into programs. C4. Extensions of Control

Structures

This is the newest area in which extension mechanisms have been proposed. Apart from the initial proposals by Bagley [2] and the work of Fisher [23], many of whose ideas have been incorporated in PPL [72, 62] and ECL [63], very little has been done in this area. It is not clear how much variability of control features should be a part of the base language and how much of the extension mechanism or even of the operating system surrounding the extensible language. The development of machines with several control units and the appearance of truly parallel machines should provide a stimulus in this area. Experimentation in this area is a pressing need at the moment so that adequate experience may be gained of non-standard forms of control. C5. Other Aspects of Extension

Mechanisms

Two other aspects of extensional mechanism need to be mentioned. Thefirstis the question of debugging aids to be provided in the system. The greater freedom allowed the programmer in the case of extensible-language systems means that the opportunities for creating meaningless programs are correspondingly greater, especially at levels which are inaccessible in the case of "ordinary" languages. The only published account of considerable experience in using an extensible language belongs to Irons [42] who discusses the question of the handling of syntactic ambiguities arising from language extension. It is interesting to note that, as Irons says ; "Experience has indicated that the question should not be brushed aside, as unintentional ambiguities can be introduced easily, and by the time an example occurs which is ambiguous one may be so committed to all the productions involved in the ambiguity that correcting the situation is very difficult. Ambiguities have arisen in some of the language versions of IMP which have been so annoying to repair that they have simply been left in." Error handling features have been incorporated into ELI from the start [79] and a system of interrupts has been provided to allow the user to take corrective actions when an error is recognized. In the ECT system [86], the constructor of the parse table acts as afilterto screen out errors introduced through extension and this coupled with a standard debugging aid

A Survey of Extensible Programming Languages

305

for the processor of the semantics-description language means that the ECT system maintains tight control over translator extension and contraction, detecting and preventing operations that would give rise to an erroneously structured translator. In general, published descriptions of extensible languages neglect to describe the errorhandling facilities and this omission should be corrected. Moreover, error-handling seems still to be treated in an ad hoc manner and a theory of error detection and correction is long overdue. The other aspect which has been largely neglected with few exceptions (notably, Galler and Perlis [25] in describing Algol D) is the problem of the optimization of code generated by an extensible language translator. There is nothing in the literature on this topic and the field is wide open for future work. Acknowledgements One of the authors (N.S.) would like to acknowledge the hospitality of Frank S. Barnes, Chairman, Department of Electrical Engineering, University of Colorado, which allowed him to make a start on the review, and the comments on an early version made by Harry Jordan. References 1. ARDEN, B . W., GALLER, B . A. and GRAHAM, R. M., The M A D definition facility, Comm. ACM 8 (Aug.

1969), 432-439. 2 . BAGLEY, P. R., Extension of Programming Language Concepts, Technical Report, University City Science Center, Philadelphia, Nov. 1968. 3. BALZER, R., Dataless programming, Proc. AFIPS 1967 FJCC 3 1 , 535-544. 4. BAYES, Α., PLITRAN—A generalized PL/I macrofacility, Proc. Fourth Australian Comp. Conf., Adelaide, 1960 1 , 291-293. 5. BELL, J. R., The design of a minimal expandable computer language, Doctoral dissertation, Computer Science Department, Stanford University, Stanford, Calif., 1968. 6. BELL, J . R., Transformations: The extension facility of Proteus, Proc. SIGPLAN Extensible Lang. Symp., SIGPLAN Notices 4 (Aug. 1969), 27-31. 7. BEMER, R. W., The PL/I family tree, PL/I Bulletin 6 (March 1968), 19-26. 8. BENNETT, R. K., BUILD—A Base for Uniform Language Definition, Technical Report, Computer Horizons Inc., Lincoln, Mass., 1968. 9. BERRY, M. D . , Introduction to OREGANO, Proc. SIGPLAN Symp. on Data Structures in Programming Lang., SIGPLAN Notices 6 (Feb. 71), 171-190. 10. BROSGOL, Β . M., An implementation of ECL data types, Technical Report, Division of Engineering and Applied Physics, Harvard University, Cambridge, Mass., 1971. 11. BROWN, P. J., The ML/I macro processor, Comm. ACM 1 0 (Oct. 1967), 618-623. 12. BROWN, P. J . , A survey of macro processors, Annual Review in Automatic Programming, Pergamon Press, London, 1969, 6 (2) 37-88. 13. CERF, V . , Thomson on REL, SIGPLAN Notices 4 (April 1969), 23-28. 14. CHEATHAM, T. E., The introduction of definitional facilities into higher level languages, Proc. AFIPS 1966 FJCC 2 9 , 623-637. 15. CHEATHAM, T. E., FISCHER, A. and JORRAND, P., On the basis for ELF—an extensible language facility, Proc. AFIPS 1968 FJCC 3 3 (2), 937-948. 16. CHRISTENSEN, C. and SHAW, C. J. (eds.), Proc. SIGPLAN Extensible Lang. Symp., SIGPLAN Notices 4 (Aug. 69), 1-62. 17. DAHL, Ο. and NYGAARD, K., SIMULA : An ALGOL-based simulation language, Comm. ACM 9 , (Sept. 1966), 671-682. 18. DAVIS, H. L., A syntax directed macro parameter analyzer, M.Sc. dissertation, Courant Institute of Mathematical Sciences, N Y U , New York, N Y , 1969. 19. DICKMAN, Β . N., ETC—An extensible macro-based compiler, Proc. AFIPS 1971 57CC 3 6 , 529-538.

306 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55.

Ν. Solntseff and A. Yezerski

DES JARDINS, P. R., RUSH: an interactive dialect of PL/I, PL/I Bulletin 6 (March 1968), 16-19. EARLEY, J., Towards an understanding of data structures, Comm. ACM 1 4 (Oct. 1971), 617-627. FELDMAN, J. and GRIES, D . , Translator writing systems, Comm. ACM 1 1 (Feb. 1968), 77-113. FISHER, D . Α., Control structures for programming languages, Doctoral dissertation, Computer Sciences Department, Carnegie-Mellon University, Pittsburgh, Penn., May 1970. FLECK, M., Formal definition of the PL/I compile-time facility, Technical Report TR 25.085, IBM Laboratory, Vienna, June 1969. GALLER, B. A. and PERLIS, A. J., A proposal for definitions in ALGOL, Comm. ACM 1 0 (April 1967), 204-219. GALLER, B. A. and PERLIS, A. J. A View of Programming Languages, Addison-Wesley, Reading, Mass., 1970. G AR WICK, J. V. A general purpose language (GPL), Intern Rapport S-32, The Norwegian Defense Research Establishment, Kjeller, Norway, June 1967. GARWICK, J. V., BELL, J. R. and KRTDER, L. D., The GPL Language, Report N o . TER-05, Control Data Corporation, Palo Alto, Calif., 1967. GARWICK, J. V., GPL, a truly general purpose language, Comm. ACM 9 (Sept., 1968), 634-638. GARWICK, J. V., The GPL compiler, Proc. IFIP Congress 1968, North-Holland, Amsterdam, 1970, Bl-3. GLASS, R. L., SPLINTER: A PL/I interpreter emphasizing debugging capability, PL/1 Bulletin 6 (March 1968), 5-16. GRISWOLD, R. E., POAGE, J. F. and POLONSKY, I. P. The SNOBOL 4 Programming Language, 2nd edn., Prentice-Hall, Englewood Cliffs, New Jersey, 1971. HALPERN, M. I., XPOP—A meta-language without metaphysics, Proc. AFIPS 1964 FJCC 2 6 , 57-68. HALPERN, M. I., Toward a general processor for programming languages, Comm. ACM 1 1 (Jan. 1968), 15-25. HARRISON, M. C , BALM—An extendable list-processing language, SIGPLAN Notices 4 (Sept. 1969), 46-52. HARRISON, M. C , Data-structures and Programming, Courant Institute of Mathematical Sciences, New York University, New York, 1970, 229-338. IBM CORPORATION, IBM System/360 Operating System: PL/I Language Specifications, Form C286594-0, IBM Data Processing Division, White Plains, New York, 1966. IBM CORPORATION, IBM System/360: PL/I Reference Manual, Form C28-8202, IBM Data Processing Division, White Plains, New York, 1967. IBM CORPORATION, Student Text: An Introduction to the Compile-Time Facilities of PL/I, Form C20-1689-1, IBM Technical Publications Department, White Plains, New York, 1968. IBM CORPORATION, Student Text: An APL Primer, Form C20-1702-0, IBM Technical Publications Department, White Plains, New York, 1969. IRONS, E. T., The extension facilities of IMP, Proc. SIGPLAN Extensible Lang. Symp., SIGPLAN Notices 4 (Aug. 1969), 18-19. IRONS, E. T., Experience with an extensible language, Comm. ACM 1 3 (January 1970), 31-40. IVERSON, K. E., A Programming Language, Wiley, New York, 1962. JOHNSTON, J. B., The contour model of block structured processes, Proc. SIGPLAN Symp. on Data Structures in Programming Lang., SIGPLAN Notices 6 (Feb. 1971), 55-82. KAY, A. C , FLEX—A Flexible Extendable Language, Technical Report 4-7, Computer Science, University of Utah, Salt Lake City, Utah, June 1968. KENT, W., Assembler-language macroprogramming, Computer Surveys 1 (Dec. 1969), 183-196. LAUER, P., Formal Definition of Algol 60, Technical Report TR25.088, IBM Laboratory, Vienna, Dec. 1968. LEAVENWORTH, R. M., Syntax macros and extended translation, Comm. ACM 9 (Nov. 1966), 790-793. LETICHEVSKII, Α. Α., On step-by-step extension of algorithmic languages, Kibernetika (Nov.-Dec. 1967), 1-6 (in Russian). LINDSTROM, G. E., Variability in language processors, Ph.D. thesis, Computer Science Department, Carnegie-Mellon University, Pittsburgh, Pa., July 1970. LUCAS, P., LAUER, P. and STIGLEITNER, H., Method and Notation for the Formal Definition of Programming Languages, Technical Report TR25-087, IBM Laboratory, Vienna, June 1968. LUCAS, P. and WALK, K . , On the formal description of PL/I, Annual Review in Automatic Programming. Pergamon Press, London, 1970, 6 (3), 105-182. MCCARTHY, J., A formal description of a subset of ALGOL, in Formal Language Description Languages (ed. T. Steel), North-Holland, Amsterdam, 1966, 1-7. MCILROY, M. D., Macro instruction extension of compiler languages, Comm., ACM 3 (April 1960), 214-220. MCKEEMAN, W. M., HORNING, J. J. and WORTMAN, D . B. A Compiler Generator, Prentice-Hall Inc., Englewood Cliffs, NJ, 1970.

A Survey of Extensible Programming Languages 56.

307

MACLAREN, M. D., Macro processing in EPS, Proc. SIGPLAN Extensible Lang. Symp., S1GPLAN Notices 4 (Aug. 1969), 32-36. 57. MEALY, G. H., Another look at data, Proc. AFJPS 1967 FJCC 3 1 , 525-534. 58. MILGROM, E., Design of an extensible programming system, D.Sc. thesis, Department of Electrical Engineering and Computer Science, Technion-Israel Inst, of Technology, Haifa, July 1971. 59. NEWEY, M. C , An efficient system for user extensible languages, Proc. AFIPS 1968 FJCC, 33 (2), 1339-1347. 60. ORGANICK, E. I. and CLEARY, J. G., A data structure model of the B6700 computer system, Proc. SIGPLAN Symp. on Data Structures in Programming Lang., SIGPLAN Notices 6 (Feb. 1971), 83-145. 61. PERLIS, A. J. The synthesis of algorithmic systems, JACM 1 4 , (Jan. 1967), 1-9. 62. POUPON, J., Control Structure of PPL, Technical Report 13-71, Center for Research in Computing Technology, Harvard University, Cambridge, Mass., 1971. 63. PRENNER, C. J., The control structure facilities of ECL, Technical Report N o 12-71, Division of Engineering and Applied Physics, Harvard University, Cambridge, Mass., 1971. 64. Ross, D . T., The A E D approach to generalized computer-aided design, Proc. ACM 22nd Natl. Conf 1967, 367-385. 65. SAMMET, J. E., Programming Languages: History and Fundamentals, Prentice-Hall, Englewood Cliffs, New Jersey, 1969. 66. SCHUMAN, S. Α. (ed.), Proc. International Symp. on Extensible Programming Lang., Grenoble, 1971, SIGPLAN Notices 6 (Dec. 1971), 1-147. 67. SCOWEN, R. S., BABEL and SOAP, an application of extensible compilers, Paper presented at the International Symposium on Extensible Languages, Grenoble, Sept. 1971. 68. SHAW, C. J., A specification of JOVIAL, Comm. ACM 6 (Dec. 1963), 721-735. 69. SOLNTSEFF, N., A classification of extensible languages, Information Processing Letters 1 (1972), 91-96, 70. SOLNTSEFF, N . and YEZERSKI, Α., ECT—An extensible contractible translator system, Information Processing Letters 1 (1972), 97-99. 71. SPITZEN, J. M., The Design and Implementation of a Conversational Extensible Language, Directorate of Systems Design and Development, Electronic Systems Division (AFSC), L. G. Hanscom Field, Bedford, Mass., Report N o . ESD-TR-141, May 1970. 72. STANDISH, Τ. Α., Some features of PPL, a polymorphic programming language, Proc. SIGPLAN Extensible Languages Symp. SIGPLAN Notices 4 (Aug. 1969), 20-26. 73. STANDISH, T. A. Some compiler-compiler techniques for use in extensible languages, Proc. SIGPLAN Extensible Lang. Symp., SIGPLAN Notices 4 (Aug. 1969), 55-62. 74. STEEL, T. B., UNCOL: the myth and fact, Annual Review in Automatic Programming, Pergamon Press, New York and London, 1961, 2 325-344. 75. STRACHEY, C , A general purpose macrogenerator, Comput. J. 8 (1965), 225-241. 76. V A N WIJNGAARDEN, A. (ed.), Report on the Algorithmic Language ALGOL 68, Report MT101, Mathematisch Centrum, Amsterdam, second printing, Oct. 1969. 77. WATTE, W. M., A language independent macro processor, Comm. ACM 1 0 (July 1967), 433-441. 78. WALK, K., Abstract Syntax and Interpretation of PL/I, Tech. Report TR25.082, IBM Laboratory, Vienna, June 1968. 79. WEGBREIT, B., Studies in extensible programming languages, Ph.D. thesis, Division of Engineering and Applied Physics, Harvard University, Cambridge, Mass., May 1970. 80. WEGBREIT, B., The ECL Programming System, Technical Report N o . 3-71, Division of Engineering and Applied Physics, Harvard University, Cambridge, Mass., April 1971. 81. WEGBREIT, B., The Treatment of Data Types in ELI, Technical Report N o . 4-71, Division of Engineering and Applied Physics, Harvard University, Cambridge, Mass., May 1971. 82. WEGNER, P., Theories of Semantics, Technical Report N o . 69-10, Center for Computer and Information Sciences, Brown University, Providence, RI, Sept. 1969. 83. WEGNER, P., Three computer cultures: computer technology, computer mathematics, and computer science, in Advances in Computers, Academic Press Inc., New York, 1970 1 0 , 7-78. 84. WEGNER, P., Information structure models, Proc. SIGPLAN Symp. on Data Structures in Programming Lang., SIGPLAN Notices 6 (Feb. 1971), 1-54. 85. WIRTH, N., The programming language Pascal, Acta Informatica 1 (1971), 35-63. 86. YEZERSKI, Α., Extendible-contractible translators, Ph.D. thesis, Department of Electronic Computation, The University of New South Wales, Sydney, NSW, 1971.

Contents

of Previous

Volumes

VOLUME 1

Opening Address A . D . BOOTH Future Trends in Automatic Programming A. E. GLENNIE Some Problems of a Universal Autocode K . A. REDISH The Mark 5 System of Automatic Coding for TREAC P. M. WOODWARD Assembly, Interpretive and Conversion Programs for PEGASUS G. E. FELTON Operational Experience with the PEGASUS Autocode W . F. M. PAYNE PEGASUS : An Example of an Autocoded Program for Sales Analysis and Forecasting P. M. RONALDSON The Application of Formula Translation to Automatic Coding of Ordinary Differential Equations J. P. CLEAVE

MERCURY Autocode: Principles of the Program Library R. A. BROOKER Automatic Programming of DEUCE C. ROBINSON Further DEUCE Interpretative Programs and some Translating Programs S. J. M. DENISON VOLUME 2

The Use of the GENIE System in Numerical Calculation J. F. ILIFFE A Description of MERCURY Autocode in Terms of a Phase Structure Language D.

R. A. BROOKER and

MORRIS

Interference with an ALGOL Procedure H. RUTISHAUSER The ELLIOTT 803 Autocode Mark II J. PYM and G. K. FINDLAY M A D C A P II

D . H. BRADFORD and M. B. WELLS

APT, a Common Computer Language R. P. RICH SAKO, an Automatic Coding System L. LUKASZEWICZ Arithmetic Formulae and Subroutines in SAKO A. W. MAZURKIEWICZ A Detailed Description of COBOL JEAN E. SAMMET FACT—A Business Compiler: Description and Comparison with COBOL and Commercial Translator R. F. CLIPPINGER

A Critical Discussion of COBOL E. L. WILLEY et a l The Growth of a Commercial Programming Language H. D . BAECKER The STANTEC-ZEBRA SIMPLE CODE and its Interpretation R. J. ORD-SMITH The Share Operating System for the IBM 709 Κ . V . HANFORD The Philosophy of Programming S. GILL Automatic Programming and Business Applications G. CUSHING The FLOW-MATIC and MATH-MATIC Automatic Programming Systems A. E. TAYLOR TIDE : A Commercial Compiler for the IBM 650 E. HUMBY Auto-programming for Numerically Controlled Machine Tools J. E. MEGGITT Appendix One : On Computable Numbers with an Application to the Entscheidungsproblem A. M. TURING Appendix Two: Preliminary Report of ACM-GAMM Committee on an International Algebraic Language Appendix Three: Automatic Programming—a Short Bibliography Appendix Four : List of Participants VOLUME 3

The Description of Computing Processes: Some Observations on Automatic Programming and ALGOL 60 M. WOODGER

Generalized ALGOL A. VAN WIJNGAARDEN On the Design of Machine Independent Programming Languages E. W . DIJKSTRA The Use of Recursive Procedures in ALGOL 60 H. RUTISHAUSER JOVIAL—A Programming Language for Real-time Command Systems C. J. SHAW Towards an ALGOL Translator B . HIGMAN

309

310

CONTENTS

OF PREVIOUS VOLUMES

A Multi-pass Translation Scheme for ALGOL 60 Ε. N . HAWKINS and D. H . R. HUXTABLE The Structure and Use of the Syntax Directed Compiler Ε. T. IRONS The Compiler Compiler

R. A. BROOKER, I. R. MACCALLUM, D. MORRIS and J . S. RÖHL

Progress in Some Commercial Source Languages Rapidwrite

k

A. D'AGAPEYEFF, H . D . BAECKER and B. J. GIBBENS

E. HUMBY

File Processing' in SEAL K. W. CLARK Appendix: Two Papers on an ALGOL Translator for the X I UNCOL: The Myth and the Fact T. B. STEEL, JR. General Views on COBOL JEAN E. SAMMET Appendix: Report on the Algorithmic Language ALGOL 60 VOLUME 4

An Experiment with a Self-compiling Compiler for a Simple List-processing Language The Design of the GIER ALGOL Compiler P. NAUR An ALGOL 60 Compiler A . E V A N S , JNR. A Parameterized Compiler based on Mechanical Linguistics H . H . METCALFE JOVIAL in Class D. G. MARSH A Commercial Use of Stacks

Μ . V. WILKES

H . D . BAECKER and B. J. GIBBENS

An Ideal Computer Support Program and a Specific IBM System D. C. FRIED Appendix: Revised Report on the Algorithmic Language ALGOL 60 P. NAUR VOLUME 5

Richard H. Goodman, 1911-1966 Data Structures and their Representation in Storage Generalized File Processing W . C. MCGEE A Politico-Social History of Algol R. W . BEMER Program Optimization F. E. ALLEN On Computational Cost S. WARSHALL

M . E. D'IMPERIO

VOLUME 6

The Language of Computers

LORD BOWDEN

Some Studies in Machine Learning Using the Game of Checkers. II—Recent Progress A. L. SAMUEL A Survey of Macro Processors P. J. BROWN A Machine-Independent Assembly Language for Systems Programs G. F. COULOURIS On the Formal Description of PL/1

P. LUCAS and K. WALK

Joss II : Design Philosophy J. W . SMITH A New Approach to Optimization of Sequencing Decisions A Compiler Generating System K. FUJINO

R. M. SHAPIRO and H. SAINT