Lecture Notes in Computer Science Edited by G. Goos, J. Hartmanis and J. van Leeuwen
1710
3
Berlin Heidelberg New York Barcelona Hong Kong London Milan Paris Singapore Tokyo
Ernst-R¨udiger Olderog Bernhard Steffen (Eds.)
Correct System Design Recent Insights and Advances
13
Series Editors Gerhard Goos, Karlsruhe University, Germany Juris Hartmanis, Cornell University, NY, USA Jan van Leeuwen, Utrecht University, The Netherlands Volume Editors Ernst-R¨udiger Olderog Fachbereich Informatik, Universit¨at Oldenburg Postfach 2503, D-26111 Oldenburg, Germany E-mail:
[email protected] Bernhard Steffen Fachbereich Informatik, Universit¨at Dortmund Baroper Str. 301, D-44221 Dortmund, Germany E-mail:
[email protected]
Cataloging-in-Publication data applied for
Die Deutsche Bibliothek - CIP-Einheitsaufnahme Correct system design : recent insights and advances / Bernhard Steffen ; Ernst-R¨udiger Olderog (ed.). - Berlin ; Heidelberg ; New York ; Barcelona ; Hong Kong ; London ; Milan ; Paris ; Singapore ; Tokyo : Springer, 1999 (Lecture notes in computer science ; Vol. 1710) ISBN 3-540-66624-9
CR Subject Classification (1998): F.3, D.3, D.4, D, F.4.1, I.2.3, C.3 ISSN 0302-9743 ISBN 3-540-66624-9 Springer-Verlag Berlin Heidelberg New York This work is subject to copyright. All rights are reserved, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, re-use of illustrations, recitation, broadcasting, reproduction on microfilms or in any other way, and storage in data banks. Duplication of this publication or parts thereof is permitted only under the provisions of the German Copyright Law of September 9, 1965, in its current version, and permission for use must always be obtained from Springer-Verlag. Violations are liable for prosecution under the German Copyright Law. © Springer-Verlag Berlin Heidelberg 1999 Printed in Germany Typesetting: Camera-ready by author SPIN: 10705026 06/3142 – 5 4 3 2 1 0
Printed on acid-free paper
Preface Computers are gaining more and more control over systems that we use or rely on in our daily lives. Besides the visible appearance of computers, for example in the form of PCs at home or at work, booking terminals in travel agencies, or automatic teller machines in banks, there is a growing demand for computers as invisible parts of systems in order to control their proper functioning. For example, computers inside washing machines or central heating systems should help in saving energy in our homes. Computer-controlled airbags in cars and automatic pilots in airplanes should bring more safety to the passengers. Computerised signalling systems should guarantee safe and efficient operation of railway traffic. Computer-operated telecommunication networks should bring individual services to their customers. But despite all these successes of computer applications, the question is how much can we really rely on these systems ? Every now and then we read about failures of computerised systems. It may only be annoying if the PC does not work as expected. More serious is a breakdown of a railway signalling system or an unwanted explosion of an airbag. Here the question of correctness of the system, of its software and hardware arises. In other words: does the computer system behave according to expectations and requirements ? This question is a challenge to software engineers and computer scientists: they need to understand the foundations of programming, need to understand how different formal theories are linked together, how compilers correctly translate high-level programs into machine code, why optimisations performed are justifiable. They need the intellectual power to understand all these aspects together in the framework of a suitable methodology for designing correct computerised systems. These are the questions this book is about. The concern about correctness goes in fact back to the origins of computer programming. Already in 1949 Alan M. Turing posed in a conference paper entitled “On Checking a Large Routine” 1 the question: “How can one check a routine in the sense of making sure that it is right ?” and went on to answer that “... the programmer should make a number of definite assertions which can be checked individually, and from which the correctness of the whole programme easily follows.” In modern terminology, Turing proposes the “inductive assertion method” to prove program correctness, but the “large routine” considered in the report is in fact quite small: a flow chart program for computing the square root. Where are we today, 50 years after Turing’s pioneering paper ? What is our current understanding of programming methodology, what has been achieved in automatic correctness proofs, how far are we with the production of correct compilers, what application domains of industrial relevance can be handled today ? To answer these questions we invited 15 researchers to help us by explaining their current understanding and contributions to the issue of correct system design. 1
A.M. Turing. On Checking a Large Routine. Report of a Conference on High Speed Automatic Calculating Machines, Univ. Math. Laboratory, Cambridge, pages 67– 69, 1949. (See also: F.L. Morris and C.B. Jones, An Early Program Proof by Alan Turing, Annals of the History of Computing 6, pages 139–143, 1984.)
VI
Preface
A Book Dedicated to Hans Langmaack How did we select the authors ? We took the opportunity of Prof. Dr. Dr. h.c. Hans Langmaack’s retirement from his professorship at the University of Kiel on October 1st, 1999, in order to present the area closest to his heart from a personal perspective. The contributors are on the one hand prominent scientists who had or have some close scientific contacts with Langmaack and on the other hand some of his former students who directly contributed to the area of correct system design. Hans Langmaack studied mathematics, physics, and logic at the Universities of M¨ unster and Freiburg. After receiving his doctorate in mathematics he became the assistant of Klaus Samelson, who together with Friedrich L. Bauer, is one of the German pioneers in the area of computer science in general and compiler construction in particular. The assistantship brought Langmaack to the University of Mainz and the Technical University of Munich where he worked on the topics of programming languages, compiler construction and formal languages. This is where contacts to Gerhard Goos and David Gries were established. Langmaack wrote one of the first compilers for the programming language ALGOL 60. After a visiting assistant professorship at Purdue University, Lafayette, Indiana, he took positions as a full professor of computer science at the Universities of Saarbr¨ ucken and Kiel. Hans Langmaack’s scientific interest is motivated by his work on compilers and his pursuit of correctness. Among others, he investigated the procedure concept of ALGOL 60 and ALGOL 68, where procedures are allowed as untyped and typed parameters, and formalised the semantics of procedures in a partly operational style in terms of a copy rule. This formalisation allowed him to attack and solve decidability questions of so-called “formal” run time properties of ALGOL-like programs, i.e. where the data are left uninterpreted. These questions concerned the formal reachability of procedures, their formally correct parameter transmission, and the formal “most-recent” property. The last property is concerned with an error occurring in an implementation of recursive procedures by Edsger W. Dijkstra.2 A major achievement was the decidability proof of the formal reachability of procedures within ALGOL 68 programs, which are typed in the sense of the Lambda calculus. Due to Edmund M. Clarke’s investigations on obtaining sound and relatively complete Hoare-like proof systems for programming languages with an ALGOLlike procedure concept, Langmaack’s interest turned to the issue of program correctness in the sense of Hoare. This is where contacts to Krzysztof R. Apt came about. Very interestingly, it turned out that essentially the same proof techniques that had been used to prove the decidability or undecidability of formal procedure properties could also be applied to show the presence or absence of sound and relatively complete Hoare-like proof systems for programming languages with ALGOL-like procedures. This topic was pursued further by Werner Damm, Ernst-R¨ udiger Olderog and Hardi Hungar. 2
A minimal program violating the ”most recent” property is shown on the cover.
Preface
VII
Besides his theoretical investigations Hans Langmaack has always been involved in practical compiler projects. These projects were conducted in cooperation with industrial partners. A major concern of these projects was to lift the level of specification of the compiling function. Due to contact with and visits by Dines Bjørner, VDM was used as a specification technique. Work on optimisation techniques and their scientific foundation also started from these practical projects. This topic, comprising abstract interpretation and data flow analysis, was pursued further by Bernhard Steffen, Jens Knoop and Oliver R¨ uthing, and, focussing on functional and parallel languages, by Flemming Nielson, who, on the initiative of Hans Langmaack, was guest professor at the University of Kiel in 1992. A major activity was the European basic research project ProCoS (Provably Correct Systems) founded by Tony Hoare, Dines Bjørner and Hans Langmaack. The project was conceived by Hoare in reaction to the so-called “CLInc stack”, a multi-level verification task solved by Robert S. Boyer and J S. Moore. It defined the so-called “ProCoS tower” of language levels and was concerned with the correct links between these levels. In this project Hans Langmaack’s group was responsible for correct compilers from an OCCAM-like programming language to transputer machine code. Martin Fr¨ anzle and Markus M¨ uller-Olm earned their first scientific merits in this project. Anders P. Ravn and Hans Rischel at Lyngby, and Ernst-R¨ udiger Olderog at Oldenburg also participated in ProCoS. The work of Langmaack’s group on compiler correctness in the ProCoS project is currently continued in the project Verifix conducted by Gerhard Goos, Friedrich von Henke and Hans Langmaack. Links to local companies in Kiel established contacts to Jan Peleska, who was rigorously applying formal methods in industry. Amir Pnueli brought “Turing power” to international meetings in Schleswig-Holstein. Hans Langmaack has also been successful as a teacher and advisor to many students. About 170 students graduated with a Diplom (MSc) from his reseach group, 22 completed a doctoral dissertation (PhD) under his supervison and 5 finished the habilitation procedure to qualify for a professorship with his guidance. Being among his students, we have closely experienced his continuous engagement for the topic of “Correct System Design”, in research, education and unforgettable grill parties. Here, Bengt Jonsson, who regularly visited Kiel, revealed unexpected talents, as an interpreter for both a Russian visitor and for Chopin at the piano. Structure of this Book This book consists of 17 chapters describing recent insights and advances in Correct System Design. They are grouped together under the five topics of methodology, programming, automation, compilation and application. Methodology. Tony Hoare discusses in his paper “Theories of Programming: Top-Down and Bottom-Up and Meeting in the Middle” complementary approaches to describing the behaviour of programs. The top-down approach starts from a
VIII
Preface
specification of the desired behaviour; the bottom-up approach from a collection of realisable components. A complete theory of programming will combine both approaches. Throughout the presentation Hoare stresses the advantages of algebraic laws in conveying the essence of both approaches. Dines Bjørner illustrates in his chapter “A Triptych Software Development Paradigm: Domain, Requirements and Software” his view of software engineering by describing a three-step approach to rigorous software development. The approach comprises descriptions of the application domain, the requirements, and the software architecture. It is exemplified in terms of a decision support software for sustainable development. Anders P. Ravn and Hans Rischel summarise in their chapter “Real-Time Constraints Through the ProCoS Layers” the results of the European research project ProCoS in which the Universities of Oxford, Lyngby, Kiel and Oldenburg collaborated. They concentrate on the main achievements of ProCoS in the area of real-time systems: the correct link between different layers of formal description ranging from requirements capture, through design and programming, down to machine code generation. David Gries looks in his chapter “Monotonicity in Calculational Proofs” at logic formulae as a basic formalism for specifying systems. He is interested in a specific aspect that is of importance in the calculational manipulation of logic formulae: the monotonicity of positions where substitutions of formulae for variables are applied, and he presents a suitable metatheorem concerning monotonicity. Programming. Krzysztof R. Apt and Andrea Schaerf explain in their chapter “The Alma Project, or How First-Order Logic Can Help Us in Imperative Programming” how a given imperative programming language like Modula-2 can be extended by concepts from the logic programming paradigm in order to raise the level of abstraction. As a result executable specification statements allowing bounded quantifiers can be formulated in the extended language. This leads to surprisingly clear and short programs. Flemming Nielson and Hanne Riis Nielson show in their chapter “Type and Effect Systems” how static inference techniques can be used to ensure that the dynamic behaviour of a program satisfies the specification. To this end, the basic type information is extended by suitable annotations to express further intensional or extensional properties of the semantics of the program. Automation. J S. Moore describes in his chapter “Proving Theorems about Java-Like Byte Code” how correctness theorems about Java programs compiled into code for a toy version of the Java Virtual Machine can be proved mechanically. The basis for this work is the mechanized logic ACL2 (A Computational Logic for Applicative Common Lisp) developed by Boyer and Moore. Armin Biere, Edmund M. Clarke and Yunshan Zhu present in their chapter “Multiple State and Single State Tableaux for Combining Local and Global Model Checking” a new algorithm for the automatic verification of reactive systems specified in linear temporal logic. It combines the advantages of local and explicit state model checking with those of global and symbolic model checking.
Preface
IX
Parosh A. Abdulla and Bengt Jonsson consider in their chapter “On the Existence of Network Invariants for Verifying Parametrized Systems” infinite classes of finite state systems consisting of an unbounded number of similar processes specified by a parametrised system. The aim is an inductive correctness proof of such systems using the notion of a network invariant. The paper presents sufficient conditions under which a finite-state network invariant exists. Compilation. Gerhard Goos and Wolf Zimmermann report in their chapter “Verification of Compilers” on the results of a joint research project of the Universities of Karlsruhe, Kiel and Ulm. They discuss a suitable notion of correctness for compilers and how it can be verified exploiting the traditional compiler architectures involving certain intermediate languages. A main achievement is the use of program checking for replacing large parts of compiler verification by the simpler task of verifying program checkers. As semantic basis for the programming language abstract state machines are used. Amir Pnueli, Ofer Shtrichman and Michael Siegel present in their chapter “Translation Validation: From Signal to C” an alternative approach to compiler verification where each run of a compiler is considered individually and followed by a validation phase. This phase verifies that the target code produced on this run correctly implements the submitted source program. The authors address the practicality of this approach for an optimising, industrial code generator from Signal to C. Martin Fr¨ anzle and Markus M¨ uller-Olm provide in their chapter “Compilation and Synthesis for Real-Time Embedded Controllers” an overview of two constructive approaches for the generation of hard real-time code from abstract specifications. The first approach starts from a real-time imperative programming language and pursues an incremental code generation. The second approach starts from formulae in a real-time logic and pursues a synthesis approach. Jens Knoop and Oliver R¨ uthing investigate in their chapter “Optimization Under the Perspective of Soundness, Completeness, and Reusability” the code optimization technique PRE (partical redundancy elimination) in various programming paradigms: imperative, parallel, and object-oriented. For each of these paradigms the authors analyse whether PRE is sound (i.e. admissible) and complete (i.e. optimal). Application. Tom Bienm¨ uller, J¨ urgen Bohn, Henning Brinkmann, Udo Brockmeyer, Werner Damm, Hardi Hungar and Peter Jansen describe in their chapter “Verification of Automotive Control Units” the application of automatic verification (model-checking) tools to specification models of electronic control units for automotive applications. The approach is based on the use of the design tool Statemate for dealing with the discrete part of the models. For dealing with values ranging over continuous domains, the authors also present a new technique of first-order model-checking. The approach has been successfully applied in cooperation with the car manufacturer BMW. Ernst-R¨ udiger Olderog shows in his chapter “Correct Real-Time Software for Programmable Logic Controllers” how ideas from the theory of real-time systems
X
Preface
can be applied to an area from industrial practice: the design of railway signalling systems to be implemented on PLCs (programmable logic controllers). The proposed approach comprises the levels of requirements, design specifications and programs for PLCs. Correctness between these levels is achieved on the basis of a real-time logic. Jan Peleska and Bettina Buth summarise in their chapter “Formal Methods for the International Space Station ISS” the results and experiences obtained in a project in collaboration with DaimlerChrysler Aerospace. The aim of this project was to check a number of correctness requirements for a fault-tolerant computer to be used in the International Space Station ISS. To this end, a combination of formal verification, simulation and testing was applied. The formal verifcation relied on the careful use of Hoare’s theory CSP (communicating sequential processes) and its associated model checker FDR. Bernhard Steffen and Tiziana Margaria explain in their chapter “MetaFrame in Practice: Design of Intelligent Network Services” how concepts from the theory of reactive systems, temporal logics, and model-checking can be applied to the area of intelligent networks. The problem considered is how to assist programmers in the correct design of new telecommunication services for customers. The approach, on the basis of the MetaFrame environment, led to a product that has been adopted, bought, and marketed by Siemens Nixdorf Informationssysteme AG. Acknowledgements In the first stages of the book project Krzysztof R. Apt and David Gries were helpful. Alfred Hofmann from Springer-Verlag was supportive from the very first moment. Annemarie Langmaack kindly helped us to obtain a photograph of Hans Langmaack. We are particularly grateful to Claudia Herbers for her devoted support in the production of this book. Last but not least all contacted authors were very easy to motivate to contribute and in the end kept their promise. They also helped in the mutual refereeing process of the contributed papers. Oldenburg and Dortmund July 1999
E.-R. Olderog and B. Steffen
Prof. Dr. Dr. h.c. Hans Langmaack Foto: Foto-Renard, Kiel
Table of Contents
I Methodology Theories of Programming: Top-Down and Bottom-Up and Meeting in the Middle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 C.A.R. Hoare A Triptych Software Development Paradigm: Domain, Requirements and Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 D. Bjørner Real-Time Constraints Through the ProCoS Layers . . . . . . . . . . . . . . . . . . . . . . . 61 A.P. Ravn, H. Rischel Monotonicity in Calculational Proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 D. Gries
II Programming The Alma Project, or How First-Order Logic Can Help Us in Imperative Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 K.R. Apt, A. Schaerf Type and Effect Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 F. Nielson, H.R. Nielson
III Automation Proving Theorems About Java-Like Byte Code . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 J S. Moore Multiple State and Single State Tableaux for Combining Local and Global Model Checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 A. Biere, E.M. Clarke, Y. Zhu On the Existence of Network Invariants for Verifying Parameterized Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 P.A. Abdulla, B. Jonsson
XIV
Table of Contents
IV Compilation Verification of Compilers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 G. Goos, W. Zimmermann Translation Validation: From SIGNAL to C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 A. Pnueli, O. Shtrichman, M. Siegel Compilation and Synthesis for Real-Time Embedded Controllers . . . . . . . . . 256 M. Fr¨ anzle, M. M¨ uller-Olm Optimization Under the Perspective of Soundness, Completeness, and Reusability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 J. Knoop, O. R¨ uthing
V Application Verification of Automotive Control Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 T. Bienm¨ uller, J. Bohn, H. Brinkmann, U. Brockmeyer, W. Damm, H. Hungar, P. Jansen Correct Real-Time Software for Programmable Logic Controllers . . . . . . . . . 342 E.-R. Olderog Formal Methods for the International Space Station ISS . . . . . . . . . . . . . . . . . . 363 J. Peleska, B. Buth MetaFrame in Practice: Design of Intelligent Network Services . . . . . . . . . . . 390 B. Steffen, T. Margaria Author Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
Theories of Programming: Top-Down and Bottom-Up and Meeting in the Middle C.A.R. Hoare Oxford University Computing Laboratory, Wolfson Building, Parks Road, Oxford, OX1 3QD
[email protected] Abstract. A theory of programming provides a scientific basis for programming practices that lead to predictable delivery of programs of high quality. A top-down theory starts with a specification of the intended behaviour of a program; and a bottom-up theory starts with a description of how the program is executed. The aim of both theories is to prove theorems (often algebraic laws) that will be helpful in the design, development, compilation,testing,optimisation and maintainance of all kinds of program. The most mature theories are those that are presented both in bottom-up and top-down fashion, where essentially the same laws are valid in both presentations.
1
Introduction
The goal of scientific research is to develop an understanding of the complexity of the world which surrounds us. There is certainly enough complexity out there to justify a wide range of specialist branches of science; and within each branch to require a wide range of investigatory styles and techniques. For example, among the specialists in Physics, cosmologists start their speculations in the vast distances of intergalactic space, and encompass the vast time-scales of the evolution of the stars. They work methodically downward in scale, until they find an explanation of phenomena that can be observed more or less directly by the naked eye. At the other end of the scale, particle physicists start with the primitive components of the material world, currently postulated to be quarks and gluons. They then work methodically upward in scale, to study the composition of baryons, hadrons, and leptons, clarifying the laws which govern their assembly into atoms and molecules. Eventually, they can explain the properties of materials that we touch and smell and taste in the world of every day. In spite of the difference in scale of their starting points, and in the direction and style of their investigations, there is increasing excitement about the convergence and overlap of theories developed by cosmologists and by particle physicists. The point at which they converge is the most significant event in the whole history of the universe, the big bang with which it all started. The same dichotomy between top-down and bottom-up styles of investigation may be found among mathematicians. For example, category theorists start E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 3–28, 1999. c Springer-Verlag Berlin Heidelberg 1999
4
C.A.R. Hoare
at the top with a study of the most general kind of mathematical structure, as exemplified by the category of sets. They then work downward to define and classify the canonical properties that distinguish more particular example structures from each other. Logicians on the other hand start from the bottom. They search for a minimal set of primitive concepts and notations to serve as a foundation for all of mathematics, and a minimal collection of atomic steps to define the concept of a valid proof. They then work methodically upward, to define all the more familiar concepts of mathematics in terms of the primitives, and to justify the larger proof steps which mathematicians need for efficient prosecution of their work. Fortunately in this case too, the top-down and the bottom-up styles of investigation both seek a common explanation of the internal structure of mathematics and clarification of the relationship between its many branches. Their ultimate goal is to extend the unreasonable power of mathematical calculation and make it more accessible to the experimental scientist and to the practicing engineer. Computer science, like other branches of science, has as its goal the understanding of highly complex phenomena, the behaviour of computers and the software that controls them. Simple algorithms, like Euclid’s method of finding the greatest common divisor, are already complex enough; a challenge on a larger scale is to understand the potential behaviour of the million-fold interlinked operating systems of the world-wide computing network. As in physics or in mathematics, the investigation of such a system may proceed in a choice of directions, from the top-down or from the bottom-up. In the following exposition, this dichotomy will be starkly exaggerated. In any particular scientific investigation, or on any particular engineering project, there will be a rapid alternation or mixture of the two approaches, often starting in the middle and working outward. A recommendation to this effect is made in the conclusion of the paper. An investigation from the top-down starts with an attempt to understand the system as a whole. Since software is a man-made artifact, it is always relevant to ask first what is its purpose? Why was it built? Who is it for? What are the requirements of its users, and how are they served? The next step is to identify the major components of the system, and ask how they are put together? How do they interact with each other? What are the protocols and conventions governing their collaboration? How are the conventions enforced, and how does their observance ensure successful achievement of the goals of the system as a whole? A top-down theory of programming therefore starts by modelling external aspects of the behaviour of a system, such as might be observed by its user. A meaningful name is given to each observation or measurement, so that the intended behaviour of the system can be described briefly and clearly, perhaps in a user manual for a product, or perhaps even in a specification agreed with the user prior to implementation. The set of observations is extended to include concepts needed to describe the internal interfaces between components of the system. The goal of the theory is to predict the behaviour of a complex
Theories of Programming: Top-Down and Bottom-Up
5
assembly by a calculation based only on descriptions of the behaviour of its major components. The collection of formulae used for these calculations effectively constitutes a denotational semantics for the languages in which a system is specified, designed, and eventually implemented. The programming language used for ultimate implementation is defined by simply selecting an implementable subset of the mathematically defined notations for describing program behaviour. The correctness of a program simply means that all possible observations of its behaviour under execution are included in the range defined by its specification. The development of the theory starts from the denotational definitions and continues by formalisation and proof of theorems that express the properties of all programs written in the language. The goal is to assemble a collection of mathematical laws (usually equations and inequations) that will be useful in the top-down design of programs from their specifications, and ensure that the resulting code is correct by construction. Investigation of a complex system from the bottom-up starts with an attempt to discover a minimum collection of primitive components from which it has been made, or in principle could have been. These are assembled into larger components by primitive combinators, selected again from a minimal set. The notations chosen to denote these primitives and combinators constitute the syntax of a simple programming language. Since programs are intended for execution by a machine, their operational meaning is defined by enumerating the kinds of primitive step that will be taken by the machine in executing any program that is presented to it. The theory may be further developed by investigation of properties of programs that are preserved by all the possible execution steps; they are necessarily preserved throughout execution of any program. The resulting classification of programs is presented as a set of axioms that can be used in proofs that a program enjoys the relevant property. The properties are often decidable, and the axioms can be used as a type system for the programming language, with conformity checkable by its compiler. In favourable cases, the type system allows unique or canonical types to be inferred from an untyped program. Such inference can help in the understanding of legacy code, possibly written without any comprehensible documentation describing its structure or purpose (or worse, the original documentation often has not been kept up to date with the later changes made to the code). The benefits of a top-down presentation of a theory are entirely complementary to those of a bottom-up presentation. The former is directly applicable to discussion and reasoning about the design of a program before it has been written, and the latter to the testing, debugging, and modification of code that has already been written. In both cases, successful application of the theory takes advantage of a collection of theorems proved for this purpose. The most useful theorems are those which take the form of algebraic laws. The advantages of both approaches can be confidently combined, if the overlap of laws provided by both of them is sufficiently broad. The laws are a specification of the common interface where the two approaches meet in the middle. I suggest that such a convergence of laws developed by complementary approaches and applied to
6
C.A.R. Hoare
the same programming language should be a rigorous scientific criterion of the maturity of a theory and of a language, when deciding whether it is ready for practical implementation and widespread use.
2
Top-Down
A top-down presentation of a theory of programming starts with an account of a conceptual framework appropriate for the description of the behaviour of a running program as it may be observed by its users. For each kind of observation, an identifier is chosen serve as a variable whose exact value will be determined on each particular run of the program. Variables whose values are measured as a result of experiment are very familiar in all branches of natural science; for example in mechanics, x is often declared to denote the displacement of a particular object from the origin along a particular axis, and x˙ denotes the rate of change of x. We will find that such analogies with the normal practice of scientists and engineers provide illumination and encouragement at the start as well as later in the development of theories of programming. There are two special times at which observation of an experiment or the run of a program are especially interesting, at the very beginning and at the very end. That is why the specification language VDM introduces special superscript ← arrow notations: x to denote the initial value of the global program variable → x, and x to denote its final value on successful termination of the program. (The Z notation uses x and x0 for these purposes). Fragments of program in different contexts will update different sets of global variables. The set of typed variables relevant to a particular program fragment is known as its alphabet. In the conventional sequential programming paradigm, the beginning and the end of the run of a program are the only times when it is necessary or desirable to consider the values of the global variables accessed and updated by it. We certainly want to ignore the millions of possible intermediate values calculated during its execution, and it is a goal of the theory to validate this simplification. A full understanding of a description of program behaviour requires prior specification of its alphabet, and agreement on the way in which the value of each variable in it can be determined by experiment. To interpret the meaning of a program without knowing its alphabet is as impossible as the interpretation of a message in information theory without knowing the range of message values that might have been sent instead. Not all the relevant parameters of program behaviour have to be directly observable from outside the computer; some may be observable only indirectly, by their effect on other programs. Actually, even the values of the program variables inside the computer are inaccessible to a user; they can be controlled or observed only with the aid of an input-output package, which is written in the same language as the program under analysis. The indirect observations are needed to make successful predictions about the behaviour of larger programs, based on knowledge of the behaviour of their components parts.
Theories of Programming: Top-Down and Bottom-Up
7
Successful termination is one of the most important properties of a program →
to predict, so we need a special variable (called ok) which is true just if and ←
when termination occurs. The corresponding initial variable ok indicates that →
the program has started. Of course a false value of ok will never be conclusively observed; but that doesn’t matter, because the intention of the theorist and the →
programmer alike is to ensure it that ok is necessarily true, and to prove it. Such a proof would be vacuous if the possibility of its falsity were not modelled in the theory. In general, for serious proof of total correctness of programs, it is essential to model realistically all the ways in which a program can go wrong, even if not directly observable. In fact, the progress of science is marked by acceptance of such unobservable abstractions as force and mass and friction as though they were directly measurable quantities. As Einstein pointed out, it is the theory itself which determines what is observable. In the interactive programming paradigm, the most important observable component of program behaviour is an interaction between the system and its environment. Each kind of interaction has a distinct name. For example, in the process algebra CCS[Milner] the event name coin may stand for the insertion of a pound coin in the slot of a vending machine, and the event name choc may stand for the selection and extraction of a chocolate bar by the user. The CSP[Roscoe] variant of process algebra allows the user to record a trace of the sequence in which such events have occurred while the machine is running; so hcoin, choc, coini is a value of trace observed in the middle of the second transaction of the machine; the empty trace h i is the value when the machine is first delivered. We also model the possibility of deadlock (hang-up) by recording the set of events currently offered by the machine’s environment, but which it refuses to accept. For example, initially the machine refuses {choc} because it has not been paid (or perhaps because it has run out of chocolates). A deadlocked machine is one that refuses all the events offered by its environment. Practical programming of useful systems will involve a combination of interactive and imperative programming features; and the relevant alphabet must include both internal variable names and external event names. The special vari→
able ok should be reinterpreted as successful stabilisation, or avoidance of livelock →
(divergence). A new special variable wait is needed to distinguish those stable states in which the program is waiting for an interaction with its environment from those in which it has successfully terminated. An important achievement in the theory of programming has been to formalise separate models for sequential and for interactive programs, and then to combine them with only a minimum of extra complexity. A top-down theory of programming is highly conducive to a top-down methodology for program design and development. The identifiers chosen to denote the relevant observations of the ultimate program are first used to describe the intended and permitted behaviour of a program, long before the detailed programming begins. For example, a program can be specified not to decrease the value of x by the statement
8
C.A.R. Hoare ←
→
x≤x
A precondition for termination of a program can be written as the antecedent of a conditional ←
←
→
( x < 27 ∧ ok) ⇒ ok The owner of a vending machine may specify that the number of choc events in the trace must never exceed the number of coin events. And the customer certainly requires that when the balance of coins over chocs is positive, extraction of a chocolate will not be refused. Explicit mention of refusals is a precise way of specifying responsiveness or liveness of a process, without appeal to the concept of fairness. But there is nothing wrong with fairness: it can be treated simply by allowing traces to be infinite. A fair trace is then one that contains an infinite number of occurrences of some relevant kind of event. It is not an objective of a programming theory to place finitary or other restrictions on the language in which specifications are written. Indeed, our goal is to place whole power of mathematics at the disposal of the engineer and scientist, who should exercise it fully in the interests of utmost clarity of specification, and utmost reliability in reasoning about correctness. We will therefore allow arbitrary mathematical statements as predicates: as in the mu-calculus, we will even allow the definition of weakest fixed points of monotonic predicate transformers. In an observational semantics of a programming language, the meaning of an actual computer program is defined simply and directly as a mathematical predicate that is true just for all those observations that could be made of any execution of the program in any environment of use. For example, let x, y, and z be the entire alphabet of global variables of a simple program. The assignment statement x := x+1 has its meaning completely described by a predicate stating that when it is started, the value of x is incremented, and that termination occurs provided the value of x is not too large. The values of all the other global program variables remain unchanged ←
←
→
→
←
→
←
→
←
x < max ∧ ok ⇒ ok ∧ x = x + 1 ∧ y = y ∧ z = z
Similarly, the behaviour of the deadlock process in a process algebra can be described purely in terms of its trace behaviour – it never engages in any event, and so the trace remains forever empty trace = <> (Here and in future, we will simplify our treatment of processes by ignoring issues of divergence). This kind of definition of programming concepts enables us to regard both specifications and programs as predicates placing constraints on the range of values for the same alphabet of observational variables; the specification restricts the range of observations to those that are permitted; and the program defines exhaustively the full range of observations to which it could potentially give rise. As a result, we have the simplest possible explanation of the important concept of program correctness. A program P meets a specification S just if
Theories of Programming: Top-Down and Bottom-Up
9
the predicate describing P logically implies the predicate describing S. Since we can identify programs and specifications with their corresponding predicates, correctness is nothing but the familiar logical implication P ⇒S For example, the specification of non-decreasing x is met by a program that increments x, as may be checked by a proof of the implication ←
←
ok ∧ x < max ∧ x := x + 1
←
→
→
⇒ x ≤ x ∧ ok
This simple notion of correctness is obviously correct, and is completely general to all top-down theories of programming. Furthermore it validates in complete generality all the normal practices of software engineering methodology. For example, stepwise design develops a program in two (or more) steps. On a particular step, the engineer produces a design D which describes the properties of the eventual program P in somewhat greater detail than the specification S, but leaving further details of the eventual program to be decided in later steps. The general design method is defined and justified by the familiar cut rule of logic, expressing the mathematical property of transitivity of logical implication D ⇒ S
P ⇒ D
P ⇒ S In words this rule may be read: if the design is correct relative to the specification, and if the program meets its design requirement, then the program also meets its original specification. The most useful method of constructing the specification of a large system is as the conjunciton of its many requirements. Programs and designs can also be combined by conjunction, provided that they have completely disjoint alphabets. In that case, the conjunction can generally be implemented by parallel execution of its operands. Such a parallel implementation is also possible when programs share parts of their alphabet, provided that these include observations of all the ways in which the programs can interact with each other during their execution. In these cases, the stepwise approach to implementation can be greatly strengthened if each step is accompanied by a decomposition of the design D into separately implementable parts D1 and D2 . The correctness of the decomposition can be checked before implementation starts by proof of the implication D1 ∧ D2 ⇒ D Further implementation of the designs D1 and D2 can be progressed independently and even simultaneously to deliver components P1 and P2 . When the components are put together they certainly will meet the original design requirement D. The proof principle that justifies the method of design by parts is just the expression of the monotonicity of conjunction with respect to implication
10
C.A.R. Hoare
P1 ⇒ D1
P2 ⇒ D2
P1 ∧ P2 ⇒ D1 ∧ D2 An even more powerful principle is that which justifies the reuse of a previously written library component, which has been fully described by the specification L. We want to implement a program P which uses L to help achieve a specification S. What is the most general description of a design for P that will achieve this goal in the easiest way? The answer is just S ∨ L, as described by the proof rule P ⇒ S ∨ L P ∧ L ⇒ S The Boolean term S ∨ L is often written as an implication (e.g., L ⊃ S); indeed, the above law, together with the inference in the opposite direction, is used in intuitionistic logic to define implication as an approximate inverse (Galois connection) of conjunction. An implication is always a predicate, but since it is antimonotonic in its first argument, it will rarely be a program The identification of programs with more abstract descriptions of their behaviour offers a very simple and general explanation of a number of important programming concepts. For example, a non-deterministic program can be constructed from two more deterministic programs P and Q by simply stating that you do not care which one of them is selected for execution on each occasion. The strongest assertion you can make about any resulting observation is that it must have arisen either from P or from Q. So the concept of non-determinism is simply and completely captured by the disjunction P ∨ Q, describing the set union of their observations. And the proof rule for correctness is just the familiar rule for disjunction, defining it as the least upper bound of the implication ordering P1 ⇒ D
P2 ⇒ D
P1 ∨ P2 ⇒ D In words, if you want a non-deterministic program to be correct, you have to prove correctness of both alternatives. This extra labour permits the most general (demonic) interpretation of non-determinism, offering the greatest opportunities for subsequent development and optimisation. Existential quantification in the predicate calculus provides a means of concealing the value of a variable, simultaneously removing the variable itself from the alphabet of the predicate. In programming theory, quantification allows new variables local to a particular fragment of program to be introduced and then eliminated. In a process algebra, local declaration of event names ensures that the internal interactions between components of an assembly are concealed, as it were in a black box, before delivery to a customer. Observations of such interactions are denoted by some free variable, say x occurring in the formula Px ; on each execution of Px this variable must have some value, but we do not know or care what it is. The value and even the existence of the variable can be concealed by using it as the dummy variable of the quantification (∃x.Px ).
Theories of Programming: Top-Down and Bottom-Up
11
An important example of concealment is that which occurs when a program component P is sequentially composed with the component Q, with the effect that Q does not start until P has successfully terminated. The assembly (denoted P ; Q) has the same initial observations as P , and the same final observations as Q. Furthermore, we know that the initial values of the variables of Q are the same as the final values of the variables of P . But in normal sequential programs we definitely do not want to observe these intermediate values on each occasion that execution of the program passes a semicolon. Concealment by existential quantification makes the definition of sequential composition the same as that of composition in the relational calculus ←
→
(P ; Q) =df ∃x. P ( x , x) ∧ Q(x, x ) Here we have written x and its superscripted variants to stand for the whole list of global variables in the alphabet of P and Q. In a procedural programming language sequential composition is the commonest method of assembling small components. The definition given above shows that the properties of the assembly can be calculated from a knowledge of its components, just as they can for conjunction. Surprisingly, sequential composition is like conjunction also in admitting an approximate inverse, – a generalisation of Dijkstra’s weakest precondition [Dijkstra]. L \ S is defined as the weakest specification [Hoare & He] of a program P such that P ; L is guaranteed to meet specification S. There is also a postspecification, similarly defined. Such inverses can be invaluable in calculating the properties of a design, even though they are not available in the eventual target programming language. In the explanation of stepwise composition of designs, we used conjunction to represent assembly of components. Conjunction of program components is not an operator that is generally available in a programming language. The reason is that it is too easy to conjoin inconsistent component descriptions, to produce a description that is logically impossible to implement, for example, (x := x + 1) ∧ (x := x + 2),
which equals false
So a practical programming language must concentrate on operators like sequential composition, which are carefully defined by conjunction and concealment to ensure implementability. Negation must also be avoided, because it turns true, which is implementable, to false, which is not. That is why prespecifications, which are antimonotonic in their first argument, cannot be allowed in a programming language. But there is a compensation. Any operator defined without direct or indirect appeal to negation will be monotonic, and the programmer can use for the newly defined operator the same rules for stepwise decomposition that we have described for conjunction. The whole process of software engineering may be described as the stepwise replacement of logical and mathematical operators used in specifications and designs by the implementable operators of an actual programming language. Ideally, each step should be small and its correctness should be obvious. But in many interesting and important cases, the structure
12
C.A.R. Hoare
of the implementation has to differ radically from the usual conjunctive structure of the specification, and the validity of the step must be checked by a more substantial proof. You do not expect to build an engine that is fast, eco-friendly, and cheap from three simpler components, each of which enjoy only one of these properties. A mismatch with implementation structure can throw into question the value of prior specification. But it should not; indeed, the value of specification to the user is greatest just when it is fundamentally and structurally simpler than its delivered implementation. The simplest implementable operator to define is the conditional, in which the choice between components P and Q depends on the truth or falsity of a boolean expression b, which is evaluated in the initial state. So b can be interpreted as a ← predicate b , in which all variables are replaced by their initial values. ←
←
if b then P else Q =df b ∧ P ∨ (¬ b ) ∧ Q All the mathematical properties of the conditional follow directly from this definition by purely propositional reasoning. The most important feature of a programming language is that which permits the same portion of program to be executed repeatedly as many times as desired; and the most general way of specifying repetition is by recursion. Let X be the name of a parameterless procedure, and let F (X) be the body of the procedure, written in the given programming language, and containing recursive calls on X itself. Since F is monotonic in the inclusion ordering of the sets of observations desribed by predicates, and since these sets can be regarded as a complete lattice, we can use Tarski’s fixed point theorem to define the meaning of each call of X as the weakest possible solution of the implication X ⇒ F (X). This definition applies also to recursively defined specifications. Incidentally, if F is expressed wholly in programming notations, it will be a continuous function, and an equivalent definition can be given as the intersection of a descending chain of iterates of F applied to true. A non-terminating recursion can all too easily be specified as a procedure whose body consists of nothing but a recursive call upon itself. Our choice of the weakest fixed point says that such a program has the meaning true, a predicate satisfied by all observations whatsoever. The programmer’s error has been punished in the most fitting way: no matter what the specification was (unless it was also trivally true), it will be impossible to prove that the product is correct. This interpretation of divergence does not place any obligation on an implementor of the programming language actually to exhibit the full range of allowable observations. On the contrary, the implementor may assume that the programmer never intended the divergence, and on this assumption may validly perform many useful optimisations on the program before executing it. As a result of such optimisations, the program may even terminate, for example, (while x ≤ 0 do x := x − 1) ; x := abs(x) can be optimised to nothing, because the optimiser assumes that the intention of the while loop was to terminate, which only happens when x starts positive. The anomalous terminating
Theories of Programming: Top-Down and Bottom-Up
13
behaviour of the optimised program for negative x is allowed by the semantics, and is entirely attributed to the fault of the programmer. Our theory of programming, whose objective is to avoid non-termination, can afford to treat all instances of non-termination as equally bad; and the whole theory can often be simplified just by regarding them as equal. After definition of the relevant programming concepts, the next stage in the top-down exploration of the theory of programming is the formalisation and proof of the mathematical properties of programs. The simplest proprieties are those that can be expressed as algebraic laws, either equations or inequations; they are often pleasingly similar to algebraic properties proved of the familiar operators of the arithmetic of numbers, which are taught at school. For example, it is well known that disjunction (used to define non-determinism in programming) is like multiplication, in that it is associative and commutative, with false serving as its unit and true as its zero. Furthermore, conjunction distributes through disjunction, and so do most simple programming combinators, including sequential composition (Table 1). Laws are the basis for algebraic reasoning and calculation, in which professional engineers often develop considerable skill.
P ∨Q =Q∨P P ∨ (Q ∨ R) = (P ∨ Q) ∨ R P ∨ false = P P ∨ true = true P ∧ (Q ∨ R) = (P ∧ Q) ∨ (P ∧ R) P ; (Q ∨ R) = (P ; Q) ∨ (P ; R) (Q ∨ R); P = (Q; P ) ∨ (R; P )
Table 1. Basic algebra of non-determinism. The same principles of programming language definition apply to process algebras, which have the observational variable trace in their alphabet. One of the risks of interactive programming is deadlock; and the worst deadlock is the process that never engages in any recordable action, no matter what events the environment may offer to engage in at the same time. As a result, its trace is always empty 0 =df (trace = h i) This definition is equally applicable to the process STOP in CSP. A fundamental operation of a process algebra is external choice P + Q, which allows the environment to choose between its operands by appropriate selection of the first event to occur. It has an astonishingly simple definition P + Q =df (P ∧ Q ∧ 0) ∨ (0 ∧ (P ∨ Q))
14
C.A.R. Hoare
While the trace is empty, an event can be refused by P + Q just if it can be refused by both of them. When the trace is non-empty, the subsequent behaviour is determined by either P or Q, whichever is consistent with the first event in the trace. If both are, the result is non-deterministic. As in the case of the conditional, the algebraic properties of this simple definition can be simply verified by truth tables. External choice is commutative, idempotent and associative, with unit 0; and it is mutually distributive with non-deterministic union. The corresponding operator in CSP has the same properties, but its definition has been made a little more complicated, to take account of the risk of divergence of one of its two operands. The top-down approach to both theories helps to elucidate exactly how two very similar theories may in some ways be subtly different. The aim of the top-down method of system development is to deliver programs that are correct. Assurance of correctness is obtained not just by testing or debugging the code, but by the quality of the reasoning that has gone into its construction. This top-down philosophy of correctness by construction is based on the premise that every specification and every design and every program can be interpreted as a description of some subset of a mathematically defined space of observations. But the converse is certainly not true. Not every subset of the observation space is expressible as a program. For example, the empty predicate false represents a specification that no physical object could ever implement: if it did, the object described would be irretrievably unobservable. The question therefore arises, what are the additional characteristics of those subsets of observations that are in fact definable in the restricted notations of a particular programming language? The answer would help us to distinguish the feasible specifications that can be implemented by program from the infeasible ones that cannot. The distinguishing characteristics of implementable specifications have been called healthiness conditions [Dijkstra]. They act like conservation laws or symmetry principles in physics, which enable the scientist quickly to dismiss impossible experiments and implausible theories; and similarly they can protect the engineer from many a wild-goose chase. As in the natural sciences, healthiness conditions can be justified by appeal to the realworld meaning of the variables in the alphabet. Analysis of termination gives a good example. A characteristic feature of a program in any programming language is that if its first part fails to terminate, any fragment of program which is written to be executed afterwards will never be started, and the whole program will also fail to terminate. In our top-down theory, the non-terminating program is represented by the predicate true; so the relevant healthiness condition can be neatly expressed as an algebraic law, stating that true is a left zero for sequential composition true ; P = true,
for all programs P
This law is certainly not true for all predicates P ; for example, when P is false, we have true ; false = false
Theories of Programming: Top-Down and Bottom-Up
15
This just means that the healthiness condition is succeeding in its primary purpose of showing that unimplementable predicates like false can never be expressed as a program. The majority of simple algebraic laws that are applicable to programs can be proved once-for-all as mathematical theorems about sets of observations; and they can be applied equally to designs and even to specifications. But healthiness conditions, as we have seen, are just not true for arbitrary sets: they cannot be proved and they must not be applied to specifications. Their scope is mainly confined to reasoning about programs, including program transformation and optimisation. It is therefore an obligation on a programming theorist to prove that each healthiness condition holds at least for all programs expressible in the restricted notations of the programming language, and perhaps to certain design notations as well. The method of proof is essentially inductive on the syntax of the language. All the primitive components of a program must be proved to satisfy the healthiness condition; furthermore, all the operators of the language (including recursion) must be proved to preserve the health of their operands. Here is a proof that union and sequential composition preserve the healthiness condition that they respect non-termination true; (P ∨ Q) = (true; P ) ∨ (true; Q) = true ∨ true
{rel. composition distributes through disjunction} {by induction hypothesis, P and Q are healthy} {∨ is idempotent}
= true For sequential composition true; (P ; Q)
{composition is associative}
= (true; P ); Q
{by inductive hypothesis, P is healthy}
= true; Q
{by inductive hypothesis, Q is healthy}
= true Algebraic laws are so useful in reasoning about programs, and in transforming them for purposes of optimisation, that we want to have as many laws as possible, provided of course that they are valid. How can we know that a list of proven laws is complete in some appropriate sense? One possible sense of completeness is given by a normal form theorem, which shows that every program in the language can be reduced (or rather expanded) to a normal form (not necessarily expressible in the programming language). A normal form should be designed so that the identity of meaning of non-identical normal forms is quite easy to decide, for example, merely by rearranging their sub-terms. Furthermore, if two normal forms are unequal, it should always be possible to find an observation described by one of them but not the other. Unfortunately, there may be no finite set of algebraic laws that exactly characterises all true facts about the programming language. For example, even the simple relational calculus has no complete finite axiomatisation. One interpretation of the Church-Turing hy-
16
C.A.R. Hoare
pothesis states that no top-down analysis can ever exactly characterise those sets of observations that are computable by programs from those that are not. It is only by modelling computation steps of some kind of machine that we can distinguish the computable from the incomputable. Specifications are inherently incomputable. It is their negations that are recursively enumerable: and they need to be, because we want to be able to prove by counterexample that a program is not correct. If your chief worry is accidental description of something that is incomputable or even contradictory, top-down theory development does not immediately address this concern. Complete protection can be obtained only by starting again from the bottom and working upward.
3
Bottom-Up
A bottom-up presentation of a theory of programming starts with a definition of the notations and syntactic structure of a particular programming language. Ideally, this should be rather a small language, with a minimum provision of primitive features; the hope is that these will be sufficiently expressive to define the additional features of more complex languages. As an example language, we choose a subset of the pi-calculus at about the level of CCS. Figure 1 expresses its syntax in the traditional Backus-Naur form, and Figure 2 gives an informal specification of the meaning. heventi :: = hidentifieri | hidentifieri hprocessi :: = 0 | heventi. hprocessi | (hprocessi | hprocessi) | ! hprocessi | (new hidentifieri) hprocessi Figure 1. Syntax 0 is the deadlock process: it does nothing. coin.P is a process that first accepts a coin and then behaves like P . nx .0 first emits a control signal nx and then stops. nx.Q first accepts a control signal nx and then behaves as Q. P | Q executes P and Q in parallel. Signals emitted by one may be accepted by the other. !P denotes parallel execution of an unbounded number of copies of P : P | P | P | ... (new e) P declares that e is a local event used only for interactions within its scope P . Figure 2. Explanation
Theories of Programming: Top-Down and Bottom-Up
17
The traditional first example of a process expressed in a new process algebra is the simple vending machine V M (Figure 3). It serves an indefinite series of customers by alternately accepting a coin and emitting a chocolate. The expected behaviour of a single customer engaging in a single transaction is cust =df coin.choc.0 The behaviour of the whole population of customers is modelled by the unbounded set (!cust). This population can insert an indefinite number of coins; and at any time a lesser number of chocolates can be extracted. But we plan to install a simple V M that can serve only one customer at a time. To implement this sequentialisation, we need an internal control signal nx, by which the machine signals to itself its own readiness for the next customer. The complete definition of the vending machine is given in Figure 3. one =df nx.coin.choc.nx .0 many =df (!one) | (nx . 0) VM =df (new nx) many Figure 3. Vending Machine The operational semantics of the programming language is presented as a collection of formulae, describing all the permitted steps that can be taken in the execution of a complete program. Each kind of step is described by a transition rule written in the form P → Q, where P gives a pattern to be matched against the current state of the program, and Q describes how the program is changed after the step. For example, the rule (e.P ) | (e.Q) → (P | Q) describes an execution step in which one process accepts a signal on e which is sent by the other. Emission and acceptance of the signal are synchronised, and their simultaneous occurrence is concealed; the subsequent behaviour is defined as parallel execution of the rest of the two processes involved. The reduction shown above can be applied directly to a complete program consisting of a pair of adjacent processes written in the order shown and separated by the parallel operator |. But we also want to apply the reduction to processes written in the opposite order, to processes which are embedded in a larger network, and to pairs that are not even written adjacently in that network. Such reductions can be described by a larger collection of formulae, for example (e.Q) | (e.P ) → Q | P ((e.Q) | (e.P )) | R → (Q | P ) | R (e.Q | R) | (e.P ) → (Q | R) | P
18
C.A.R. Hoare
But even this is only a small subset of the number of transition rules that would be needed to achieve communication in all circumstances. A much easier way to deal with all cases is to just postulate that | is a commutative operator, that it is associative, and that it has unit 0. P |0=P P |Q=Q|P P | (Q | R) = P | (Q | R)
1
These are called structural laws in a process calculus. They represent the mobility of process, because the implementation may use the equations for substitution in either direction, and so move a process around until it reaches a neighbour capable of an interaction with it. In a bottom-up presentation, these laws are just postulated as axioms that define a particular calculus; they can be used in the proof of other theorems, but they themselves are not susceptible of proof, because there is no semantic basis from which such a proof could be constructed. The laws governing reduction apply only to complete programs; and they need to be extended to allow reduction steps to take place locally within a larger context. For example a local reduction can occur anywhere within a larger parallel network, as stated by the rule If P → P 0 then (P | Q) → (P 0 | Q) A similar law applies to hiding. If P → P 0 then (new e) P → (new e) P 0 . But there is no similar rule for e.P. A reduction of P is not permitted until after e has happened. It is only this omission of a rule that permits terminating programs to be distinguished from non-termination. One of the main objectives of a theory of programming is to model the behaviour of computing systems that exist in the world today. The world-wide network of interconnected computers is obviously the largest and most important such system. Any of the connected computers can emit a communication into the network at any time. There is reasonable assurance that the message will be delivered at some later time at some destination that is willing to accept it (if any). But the exact order of delivery does not necessarily reflect the order of sending: messages in the net can overtake each other. This aspect of reality is very simply encoded in the calculus by adding a single new reduction step. This just detaches a message from its sender, and allows the message to proceed independently in its own timescale through the network to its destination. e.P → (e.0) | P 1
These equations are more usually written with equivalence (≡) in place of equality, which is reserved for syntactic identity of two texts. They are called structural congruences, because they justify substitution in the same way as equality.
Theories of Programming: Top-Down and Bottom-Up
19
This means that the sender P is not delayed if the receiver is unready at the time of sending. The subsequent actions of the sender proceed in parallel with the journey undertaken by its message. A calculus with such a reduction rule is called asynchronous, and output prefixing is usually omitted from its syntax. That is why the algebraic laws for an asynchronous calculus are different from those of a synchronous one. Structural laws are also used in addition to reductions to formalise the intended meaning of the constructions of the language. For example, the repetition operator (!P ) denotes an unbounded set of parallel instances of the same process P . The addition of a new instance of P therefore makes no difference, as stated in the unfolding law !P = P | (!P ) This law can be applied any number of times P | (!P ) = P | P | (!P ) = . . . If each application allows a reduction, we can generate an infinite reduction sequence leading to potential non-termination. Consider for example the process P that reduces in one step to the empty process P =df (e.0 | e.0) → (0 | 0) = 0 This can be put into a repetition !P = (e.0 | e.0) |!P → 0 |!P = !P It follows that !P can be subjected to an infinite series of reductions, without ever engaging in a useful interaction with its environment. This is just what is known as divergence or livelock, and it is clearly and obviously definable on the basis of an operational semantics. A top-down presentation cannot give such an obviously appropriate definition of non-termination, and has to postulate that →
the artificial variable ok is mysteriously allowed to take the value false whenever there is a risk of divergence. Another useful definition in operational semantics is that of a labelled transition, in which the transition relation → is labelled by a trace of interactions with the environment that can occur during the evolution of the process. <>
∗
P −→ Q =df P → Q <e>b s
∗
P −→ Q =df ∃P 0 . P → e.P 0 ∧ P 0 → Q ∗
s
where → is the reflexive transitive closure of →. Now we can trace the evolution of our vending machine, using a few structural laws which seem reasonable
20
C.A.R. Hoare
many = = → =
nx .0 |! one nx .0 | (nx.coin.choc.nx.0) |! one 0 | (coin.choc.nx.0) |! one coin.choc.nx.0 |! one
→
coin.(choc.nx.0 |!one)
coin
choc.nx .0 |! one
choc
nx.0 |! one
→
→
) )
many
−→
{expanding !} {reduction} {0 is unit of !} {reduction, etc } coin
{def → } {similarly}
{local reduction}
many
V M = ((new nx) many)
−→
VM
This mathematical derivation is a close simulation of the execution of the program. But does it prove that the program is correct? And what does correctness mean for a programming language that has been defined only in terms of its internal execution rather than what can be observed from outside? The usual answer to the more general question is that a program is adequately specified in the programming language itself by displaying the equations that it should satisfy. For example, perhaps what we really want to prove about the vending machine is V M = coin. choc. V M. (In a more abstract language like CCS or CSP, such an equation would be permitted as a recursive definition of VM). In constructing the proof of such equations, free use may be made of all the structural laws of the calculus. But in general the structural laws are deliberately restricted to transformations on the static shape of a formula, and they do not give enough information about equality of dynamically evolving behaviour. Such reasoning would require a set of laws much larger than those postulated by the calculus. What laws should they be? And how are they justified? The solution to this problem is of startling originality. The user of the calculus is allowed to extend its set of laws by any new equations that may be desired, provided that this does not lead to a contradiction. A contradiction is defined as the proof of an equation between processes that obviously ought to be different, like a divergent process and a non-divergent one. For example, an equation P = Q leads to contradiction if you can find some program C[P ] containing P which does not diverge, but when P is replaced by Q, C[Q] actually can diverge. Finer discriminations may be imposed by defining a function obs(P ), which maps a program P to some simple set of observations that may be made of it. For example, obs(P ) might map P onto the set of environments in which it might deadlock. In each case, one might observe the set of events offered by the environment but refused by the process. Then a contradiction is defined as a law that equates two programs with different observable refusal sets. An equation established in this way is called a contextual equivalence
Theories of Programming: Top-Down and Bottom-Up
21
Proving that a proposed law P = Q leads to contradiction is quite a challenge, because the context C[ ] that reveals it may be very large. But proving that something is not a contradiction can be even harder, because it involves consideration of the infinite set of all possible contexts that can be written around P and Q; such a universal hypothesis requires an inductive case analysis over all the combinators of the calculus. Sometimes, only a reduced set of contexts is sufficient; this fact is established by proof of a context lemma. As a result of their syntactic orientation, proofs by induction tend to be specific to a particular calculus, and care is needed in extending their results to calculi with a slightly different syntax, different reductions, or different structural laws. For this reason, each new variation of a familiar calculus is usually presented from scratch. Heavy reliance on induction certainly provides a strong motive for keeping down the number of notations in the original syntax to an inescapable core of primitives, even if this makes the language less expressive or efficient in practical use. The pursuit of minimality tends to favour the design of a language at a relatively low level of abstraction. The power of such a language matches that of machine code, which offers enormous power, including the opportunity for each instruction to interfere with the effect of any other. In the presence of multi-threading or non-determinacy, understanding of the behaviour of an arbitrary program becomes rapidly impossible. And there are few general theorems applicable to arbitrary programs that can aid the understanding, or permit optimising transformations that preserve behavioural equivalence. The solution to this problem is to confine attention to programs that follow defined protocols and restrictive conventions to limit their mutual interaction. The meaning of conformity with the convention is defined by means of a type system, which is also usually presented in a bottom-up fashion. The syntax gives a notation for expressing all the types that will be needed. Then a collection of axioms and proof rules provide a means of deducing which parts of each program can be judged to belong to a particular type. In a higher level programming language the programmer may be required or allowed to provide adequate type information for variables and parameters; but most of the labour of type checking or even type inference can be delegated to a compiler. The consistency of the typing system is established by showing that pairs of programs equated by the structural laws have the same type, and that each reduction step in execution preserves the proper typing of its operand. This is called a subject reduction theorem. Subsequent development of the theory can then be confined to properly typed programs. A type system based on an operational model may be designed to supply information that is highly relevant to program optimisation. For example, it can detect dead code that will never be executed, and code that will be executed at most once. Other type systems can guarantee absence of certain kinds of programming error such as deadlock. If it is known that no type can be deduced for such an erroneous program, then type consistency ensures that the error can never occur a run time. Because type systems enforce disciplined interaction, well-typed programs often obey additional laws, useful both for comprehension
22
C.A.R. Hoare
and for optimisation. Type systems thereby raise the level of abstraction of an operationally defined programming language; their role in the bottom-up development of a theory is complementary to that of healthiness conditions, which in a top-down development bring abstract denotational specifications closer to implementable reality. Operational presentations of semantics are particularly appropriate for analysis of security aspects of communication in an open distributed network, where co-operation between a known group of agents is subject at any time to accidental or deliberate interference by an outsider. The main role of the language is to define and limit the capabilities of the outsider. For example, the localisation operator (new e) enables an agent in the system to invent an arbitrary secret code or a nonce, and the structural laws of the language are designed to ensure that it remains secret except to those who have received it in an explicit communication. It is then the responsibility of an implementation of the language to enforce this level of secrecy by choice of an appropriate cryptographic method. Furthermore, if the proof of security of a protocol depends on observance of type constraints, it is essential at run time to check the types of any code written by an outsider before executing it in a sensitive environment. The purpose of a secure protocol can often be described most clearly by an equation P = Q, where P describes the situation before some desired interaction takes place, and Q describes the desired result afterwards. For example, we might use the equation (e.P | e.Q) = P | Q to describe the intended effect of transmission of a signal e from Q to P . But this is not a valid equation in the calculus, because it is not secure against interference by an outsider R, which can intercept and divert the signal, as permitted by the reduction e.P | e.Q | e.R
→
e.P | Q | R
This reduction will be inhibited if the name e is kept secret from the outside, so it is valid to equate (new e) (e.P | e.Q)
=
(new e) (P | Q)
Since it is assumed that the outsider is limited to the capabilities of the programming language, an arbitrary attack can be modelled by a context C[ ] placed around both sides of the equation. A standard proof of contextual equivalence would be sufficient to show that there is no such context. That is exactly what is needed to show that no outsider can detect or affect the desired outcome described by the equation. As in this example, the required protection is often achieved with the aid of the new operator, which prevents an outsider from detecting or communicating a signal with the new name. It is much more difficult to design a top-down theory for application to problems of security, privacy and authentication. A top-down theory has to start with a decision of exactly what an intruder could observe of another agent in the system, and what attacks are
Theories of Programming: Top-Down and Bottom-Up
23
possible upon it. But this understanding is exactly what the security analysis seeks to develop; it cannot be postulated in advance. A great deal of research effort has been expended on designing proof techniques that are simpler to apply and more efficient to mechanise than proof by non-contradiction. Many of these methods use a variation of the technique of bisimulation [Milner]. A bisimulation is a postulated equivalence between programs that is respected by the individual steps of the operational semantics of the language, i.e., if two programs belong to the same equivalence class before the step, they belong to the same equivalence class afterwards. For particular calculi and for particular kinds of bisimulation, theorists have proved that the postulation of the bisimulation as an equality will not lead to a contradiction. Then that kind of bisimulation may safely be used to prove equality of arbitrary programs in the language. For a well-explored calculus, there may be a whole range of bisimulations of varying strength, some suitable for mechanisation, and some suitable for quick disproof. They are all approximations to the truly intended notion of equality, which is defined by the more elusive concept of contextual equivalence. As described above, much of the effort in a bottom-up theory goes into the determination of when two programs are equal. This is absolutely no problem in a top-down theory, where normal mathematical equality of sets of observations is used throughout. Conversely, much of the effort of a top-down theory goes into determination of which subsets of observations correspond to implementations. This is absolutely no problem in a bottom-up theory, where programs are always by definition computable. In each case the theorist approaches the target by a series of approximations. In the happy circumstance that they are working on the same language and the same theory, top-down and bottom-up will eventually meet in the middle.
4
Meeting in the Middle
A brief summary of the merits and deficiencies of top-down and bottom-up presentations show that they are entirely complementary. – A top-down presentation of a theory of programming gives excellent support for top-down development of programs, with justifiable confidence that they are correct by construction. By starting with observable system properties and behaviour, it permits and encourages the advance specification of a system yet to be implemented, and the careful design of the interfaces between its major components. It provides concepts, notations and theorems that can be used throughout the design and implementation of software systems of any size and complexity. On the other hand, an abstract denotational semantics gives no help at all in the debugging of incorrect programs. It is therefore useless in the analysis of legacy systems, many of which have been written and frequently changed without regard to general design principles, clarity of structure, or correctness of code.
24
C.A.R. Hoare
– A bottom-up presentation of a theory of programming gives excellent support for reasoning about the execution of programs that have already been written. By starting with a definition of the individual steps of execution, it models directly the run-time efficiency of programs. Execution traces provide the primary diagnostic information on debugging runs of incorrect programs. On the other hand, an operational semantics gives no help at all in relating a program to its intended purpose. It is therefore useless in reasoning about programs before they have been written in the notations of a particular programming language. If programming theory is ever to make its full contribution to the practice of programming, we must offer all the benefits of both styles, and none of the deficiencies. Neither approach could be recommended by itself. It is clearly foolish to provide a conceptual framework for program design if there is no way of executing the resulting program step by step on a computer. It would be equally unsatisfactory to present an operationally defined theory if there is no way of describing what a program is intended to do. In the natural sciences, it is a necessary condition of acceptability of a theory that it should agree with experiment. Experiments are equally important in validation of theories of programming. They test the efficiency with which a new programming concept can be implemented and the convenience with which it can be used. An experiment which requires the design, implementation and use of a completely new programming language is prohibitively time-consuming. For rapid scientific progress, it is preferable just to add a single new feature to an existing programming language, its compiler and its run time system. The first trial applications may be conducted by a group of experimental programmers, who have accepted the risk that the new feature may soon be changed or withdrawn. Even such a limited experiment is expensive; and worse, it is difficult to interpret the results, because of uncontrollable factors such as the skill and the experience of the people involved. That is why it is advisable to restrict experimentation to test only theories that have shown the highest initial promise. The promise of a theory is not judged by its popularity or by its novelty or by its profitability in competition with rival theories. Quite the reverse: it is by its coherence and close agreement with other theories that a new theory can be most strongly recommended for test. Such agreement is much more impressive if the theories are presented in radically differing styles. From the practical point of view, it is the stylistic differences that ensure complementarity of the benefits to the user of the programming language. And the results of the experiment are much more convincing if the implementors and trial users are completely independent of the original theorists, as they usually are in more mature branches of Science. The unification of theories is not a goal that is easy to achieve, and it often requires a succession of adjustments to the details of the theories, and in the way they are tested. The development of an abstract denotational model to match a given operational semantics is known as the problem of full abstraction. It took many years to discover fully abstract models for PCF, a simple typed functional
Theories of Programming: Top-Down and Bottom-Up
25
programming language that was presented by an operational semantics. A recent model [Abramsky, Hyland] represents a type of a programming language by the rules of a two-person game, and a function by a strategy for playing the game. A large and complex collection of healthiness conditions is imposed on the games and strategies to ensure that every strategy that satisfies them can be denoted by a program expressed in the syntax of PCF. It is generally considered sufficient to prove this just for finite games, which correspond to programs that do not use recursion or any other form of unbounded iteration. That is the best that can be done, because it is impossible within an abstract model to formulate healthiness conditions that will select exactly those sets of observations that are implementable as iterative programs. In the practical development and analysis of programs, it is quite uncommon to make a direct appeal to the definition of the programming language, whether denotational or operational. Much more useful are theorems that have been based on those definitions; many of these take the form of algebraic laws, either proven from definitions or postulated as healthiness conditions. The importance of laws is recognised both by top-downers and by bottom-uppers, who measure progress in their chosen direction by accumulation of larger collections of useful laws. When both theories have been adequately developed, I suggest that an appropriate measure of successful meeting in the middle is provided by the overlap of the two collections of laws. Adjustments can (and should) then be made to the details of both theories, until the overlap is sufficiently broad to meet all the needs of practice. If the practitioner uses just the appropriate laws in the appropriate circumstances, the merits of both approaches can be safely combined. In a perfect meeting, the laws derived from the top-down and from the bottom-up would be exactly the same. In fact, this is not necessary. All that is needed is that the operationally defined axioms and laws should be a subset of those provable from the denotational definitions. Then all the remaining laws proveable from the denotations will be contextual equivalences. The existence of the denotational model guarantees their consistency, even without the need for an exhaustive inductive argument on contexts. Identity of differently derived theories is not the only goal; and when applying the same derivational techniques to different programming paradigms, differences in the algebraic laws are to be expected and even welcomed. It turns out that a great many algebraic laws are common to nearly all paradigms, but it is the laws that they do not share that are even more interesting. The fundamental property that distinguishes two paradigms is often very neatly expressed by an algebraic law, free of all the clutter of detail involved in a formal definition, and unaltered when the detail changes. For example, functional programming languages are classified as lazy or non-lazy. In a non-lazy language, each function evaluates its arguments first, so if an argument aborts, so does the function call. As a consequence, functional composition (denoted by semicolon) has abortion as its left zero: true ; P = true. However, a lazy functional language does not satisfy this law. It allows a constant function K to deliver its answer without
26
C.A.R. Hoare
even looking at its argument: true ; K = K. However, a lazy language still satisfies a right zero law: P ; true = true. So does a non-lazy language, unless it allows an argument E to raise an exception or jump. In this case the aborting function does not get the chance to start, so: E ; true = E. Discussion of such laws is highly relevant to the selection and design of a programming language, as well as its implementation and optimisation. Future texts on comparative programming languages will surely exploit the power of algebra to explain the fundamental principles of the subject. Fascination with the elegance and expressive power of laws was what inspired the development of abstract algebra as a branch of modern mathematics. Since the earliest days, mathematics has been primarily concerned with the concept of number. Its progress has been marked by the discovery of new and surprising varieties. Starting with positive integers, even the discovery of zero was a major advance. Then come negative numbers, fractions, reals, and complex numbers. In modern times, study of the foundations of mathematics has given a denotational semantics to each of these different kinds of number. Natural numbers are defined as sets, integers and fractions as pairs, and reals as sequences. Correspondingly different definitions are given for the arithmetic operations that are performed on the different kinds of number. In each case, algebraic laws are proved on the basis of the definitions. In spite of the fact that the definitions are so different, most of the laws turn out to be the same. It is the sharing of laws that justifies the use of the same arithmetic operator to denote operations with such radically different definitions. The laws have then inspired the development of other interesting mathematical structures, like quaternions and matrices, for which algebraically similar operations can be defined. Algebra, among all branches of mathematics, is the one that takes re-usability as its primary goal. Computing Science makes progress by discovery of new patterns and paradigms of programming. These are embodied in new programming languages, and subjected to the test of trial implementation and use. The procedural paradigm was among the earliest, and still has the widest application. Now there is also a declarative paradigm, which already splits into two major branches, the logical paradigm which permits backtracking, and the functional paradigm that does not. The functional paradigm splits into lazy and non-lazy varieties. The advent of multiprocessors and networking has introduced a new paradigm of distributed computing, with even more variations. Some of them are based on sharing of global random access memory, and others on explicit communication. Communications may be ordered or unordered; they may be global or directed along channels; and they may be synchronised or buffered. In addition to notations traditionally recognised in the community as programming languages, we should consider the languages used for database queries, spreadsheets, menu generators, and other complex interfaces that are coming into wide-spread use. A significant challenge for programming theory is to bring some order into this growing range of tools, and develop an understanding to assist in the selection of an appropriate tool for each purpose, and for using them in combination when necessary. For purposes of classification, comparison, and combination, both de-
Theories of Programming: Top-Down and Bottom-Up
27
notational and operational semantics have far too much detail to convey the desired understanding and illumination. It is only the algebra that captures the essence of the concepts at an appropriately high level of abstraction. It is perhaps for the same reason that algebraic laws are also the most useful in practice for engineering calculation. The primary role of algebraic laws is recognised in the most abstract of branches of algebra, namely category theory. Categories provide an excellent source of elegant laws for programming. Its objects nicely represent the types of a programming language, and its basic operation of composition of arrows is a model for the combination of actions evoked by parts of a program. Additional important operators and their types are specified entirely by the algebraic laws that they satisfy. The specification of an operator is often accompanied by a proof that there is only one operator that satisfies it – at least up to isomorphism. This gives assurance that the stated laws are complete: no more are needed, because all other categorial properties of the operator can be proved from them. Finally, a wide range of differing categories can be explored and classified simply by listing the operators which they make available and the laws which they satisfy. These considerations suggest a third approach to the development of programming theory, one that starts with a collection of algebraic laws as a definitive presentation of the semantics of a programming language [Baeten and Weijland]. The theory then develops by working outwards in all directions. Working upwards explores the range of denotational models for languages which satisfy the laws. Working downwards explores the range of correct implementations for these languages. And working sideways explores the range of similar theories and languages that might have been chosen instead. The work of the theorist is not complete until the consequences of theory have been fully developed in all relevant directions. Such an ambitious programme can be achieved only by collaboration and accumulation of results by members of different research traditions, each of whom shares an appreciation of the complementary contributions made by all the others.
Acknowledgements The views put forward in this paper evolved during a long collaboration with He Jifeng on research into unifying theories of programming. They contribute towards goals pursued by the partners in the EC Basic Research Project CONCUR; and they have been subjected to test in the EC Basic Research Project PROCOS. They are more fully expounded in the reference [Hoare, He], which contains a list of 188 further references. Significant contributors to this work at Oxford include Carroll Morgan, Jeff Sanders, Oege de Moor, Mike Spivey, Jeff Sanders, Annabelle McIver, Guy McCusker, and Luke Ong. Other crucial clarifications and insights were obtained during a sabbatical visit to Cambridge in conversations with Robin Milner, Andy Pitts, Martin Hyland, Philippa Gardner, Peter Sewell, Jamey Leifer, and many others. I am also grateful to Microsoft
28
C.A.R. Hoare
Research Limited for supporting my visit to Cambridge, and to researchers at Microsoft who have devoted their time to my further education, including Luca Cardelli, Andy Gordon, Cedric Fournet, Nick Benton and Simon Peyton Jones. The organisers of POPL 1999 in San Antonio invited me to present my thoughts there, and the participants gave useful encouragement and feedback. Krzysztof Apt and John Reynolds have suggested many improvements that have been made since an earlier draft of the paper, and more that could have been.
References S. Abramsky, R. Jagadeesan and P. Malacaria. Full abstraction for PCF. To appear in Information and Computation. Baeten and Weijland. Process Algebra. CUP 1990, ISBN 0521 400430. E.W. Dijkstra. A Discipline of Programming. Prentice Hall 1976, ISBN 013 215871X. C.A.R. Hoare and He Jifeng. Unifying Theories of Programming. Prentice Hall International 1998, ISBN 0-13-458761-8, available from amazon.co.uk. J.M.E. Hyland and C.H.L. Ong. On Full Abstraction for PCF: I, II and III. To appear in Informatics and Computation. A.W. Roscoe. Theory and Practice of Concurrency. Prentice Hall 1998, ISBN 013 674409 5.
A Triptych Software Development Paradigm: Domain, Requirements and Software Towards a Model Development of a Decision Support System for Sustainable Development Dines Bjørner Department of Information Technology, The Technical University of Denmark, DK–2800 Lyngby, Denmark. E–Mail: [email protected]
Abstract. A paradigmatic three stage approach to software development is sketched in terms of a torso-like, but schematic development of informal and formal descriptions (i) of the domain of sustainable development, (ii) of requirements to decision support software for developing models for and monitoring development (claimed to be sustainable), and (iii) of rudiments of a software architecture for such a system. In “one bat we tackle three problems”: (i) illustrating a fundamental approach to separation of concerns in software development: From domain via requirements to software descriptions; (ii) contributing towards a theory of sustainable development: Bringing some precision to many terms fraught by “political correctness”; and (iii) providing, we believe, a proper way of relating geographic information system+demographic information system systems to decision support software. Perhaps a fourth result of this paper can be claimed: (iv) Showing, as we believe it does, the structural main parts of a proper presentation of software.
1
Introduction
A paradigmatic three stage approach to software development is sketched in terms of a torso-like, but schematic development of informal and formal descriptions (i) of the domain of sustainable development, (ii) of requirements to decision support software for developing models for and monitoring development (claimed to be sustainable), and (iii) of rudiments of a software architecture for such a system. In “one bat we tackle three problems”: (i) illustrating a fundamental approach to separation of concerns in software development: From domain via requirements to software descriptions; (ii) contributing towards a theory of sustainable development: Bringing some precision to many terms fraught by “political correctness”; and (iii) providing, we believe, a proper way of relating E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 29–60, 1999. c Springer-Verlag Berlin Heidelberg 1999
30
D. Bjørner
geographic information system+demographic information system systems to decision support software. Perhaps a fourth result of this paper can be claimed: (iv) Showing, as we believe it does, the structural main parts of a proper presentation of software. The current paper primarily presents data models. They are in the style used in denotational and in algebraic semantics domain, respectively sort definitions. But we sketch some observer functions and some axioms. The notation used is that of RSL [1], the Raise Method’s [2] Specification Language. This paper is a torso: It sketches the application of a formal specification and refinement-based software development paradigm to a field either not very well understood or covered by AI (artificial intelligence) researchers and AI programmers. AI contributions, valuable as they may be, usually, as do most contributions in software engineering, zooms in on a narrow problem, solvable (ie. expressible, programmable) in some AI–language (or other). But usually such contributions do not try to isolate the domain from possible requirements; nor the requirements from the implementation. Instead the solution “drives” the development and its presentation. We advocate a far more comprehensive approach. First we cover, in isolation, domain problems. In the jargon of software engineering these are the “up-stream” issues based on whose precise understanding one may formulate requirements. Then we relate domains to requirements, and finally to software (more precisely software architectures). Throughout we try to make more precise such software engineering and such international aid organisation jargon as decision support system, respectively sustainable development — as well as many other terms: indicator, equity, etc. The triptych paradigm: from domains via requirements to software (descriptions, has been covered more comprehensively in other papers, for example the recent [3,4,5,6,7,8,9], and is claimed to have stood its first tests of usefulness by the well-reported work of the last seven years at UNU/IIST1 . The present paper, to be fully appreciated by readers not familiar with formal development in the styles of VDM and RAISE, must therefore be complemented by the study of for example [10] or [2], preferably both. Then a professional reader can see how to turn the sketch of this paper into full reality. We leave it to others to compare the present approach to those of UML etc.
2
Summary Review
2.1
The Application
We Domain analyse (Section 4) the notions of Development as based on Resources. We then analyze the concept of Resources, their Attributes and Attribute Values and Indicators. Based on Value Indicators we define Equities. Sustainable Development is then defined in terms of Equities.. 1
United Nations University International Institute for Software Technology, P.O.Box 3058, Macau: http://www.unuiist.iist.unu.edu
A Triptych Software Development Paradigm
31
Based on these concepts we then analyze (Section 5) the Decision Making Processes and Capture Requirements for a Decision Support System for Sustainable Development (DSS for SD). In this section we introduce the notion of Resource Representations. Independently we introduce (Section 6) a Software Architecture model for a Federated Geographic and spatially related Demographic Information System. This model is then related (Section 7) to the DSS for SD system: (GaD)2 I2 S. Section 4–7 thus relate (→) as shown in figure 1:
Fig. 1. Main Paper Section Relations Section 4
Sustainable Development (SD)
Section 5
Decision Support System for SD (DSS for SD)
Section 7
Section 6
Federated GIS+DIS
2.2
Federated GIS+DISbased DSS for SD (GaDIIS)
The Development Paradigm
It is here emphasized that the Domain Analysis of Section 4 does not refer to any software, nor to any computing or communications support. It is strictly an analysis, and a formal model, of the concept of Sustainable Development and its constituent notions. Only in Section 5 do we refer, rather implicitly, to software, computing and communications support. It is also to be emphasized that we do not refer to any conventional notion of geographic information systems or demographic information systems. Thus Section 4, perhaps rather surprisingly to many readers, does not assume geographic information systems or demographic information systems. That “connection” is only made in the last technical section, Section 7. To prepare for that, Section 6 “speaks” solely of geographic information systems and demographic information systems — with no reference to Section 4’s or 5’s decision support system for sustainable development! This decomposition of the problem is a main contribution of this paper as are the models of Sections 4–7, in decreasing order!
32
3 3.1
D. Bjørner
Introduction Background, Aims and Objectives
This paper has three objectives: A Triptych Software Paradigm: We wish to illustrate the triptych notions of: – domain engineering, – requirements engineering and – software design Domain engineering builds a theory of the application domain. It does so by describing it: Informally and formally. As it, the domain, is, without any reference to computing, ie. also without any reference to requirements. Normally a domain is described normatively: encompassing many actual as well as possible instantiations. And the domain need be described from the point of view of all relevant stake-holders, and at a variety of abstractions: the very basics, the domain with its support technologies, with its rules & regulations, human behaviours, etc. Requirements engineering builds a theory of some software for the support of some activities within the domain. It does so by describing domain requirements, interface requirements and machine requirements. Domain requirements projects and instantiates the normative domains; and, in cases, also extends it. Interface requirements specify the human-computer interface (HCI): the way human users “see” the system (multi-media), dialogues between man and machine, etc. Machine requirements specify dependability (availability, accessibility, security, reliability, etc.), performance, and maintainability (perfective, adaptive and corrective), as well as development and execution platforms. Finally software design specify the architecture of th software: How users and other software perceive or use it, its organisation: How the internal interfaces are composed. Architecture usually ‘implements’ domain and interface requirements. Program organisation ‘implements’ machine requirements. Decision Support Systems: We attempt to combine two main streams of software technology: decision supports systems and geographic information systems in the specific context of environmentally sustainable development. Sustainable Development: The main text of this paper will deal with this subject. The next sections will detail the points to be made. 3.2
Sustainable Development
The concept of sustainable development was brought into focus at the United Nations Conference on Environment and Development. That conference was held in Rio de Janeiro, Brasil, in June 1992.
A Triptych Software Development Paradigm
33
An important document [11] submitted to that conference, and a document whose main enunciation, namely a definition of the concept of sustainable development, became a cornerstone of the result of the conference, was commonly known as the Brundtland Report. The final document of the conference was the Agenda’21 report [12]. Definition 1 Sustainable Development is development that meets the needs of the present without compromising the ability of future generations to meet their own needs. [11] It seems assumed in the above definition that it is indeed possible to meet the needs of the present without compromising the ability of future generations to meet their own needs! ¿From [13] we lift the quote taken from [14]: Quotation 1 Sustainable Development is a process of social and economic betterment that satisfies the needs and values of all interest groups, while maintaining future options and conserving natural resources and diversity. The above appears to have been a “first” definition of sustainable development. It also appears that it did not drew much attention. The next characterisation is due to [15]: Characterisation 1 Sustainable Development does not mean no development. It means improving methods for resource management in an environment of increasing demand for resource. It was referred to in [16]. The next quotation is due to [17]: Characterisation 2 Sustainability means that the evolution and development of the future should be based on continuing and renewable processes and not on the exploitation and exhaustion of the principal or the capital of living resource base. It was also referred to in [16]. The last characterisation is due to [18]: Characterisation 3 There are over 70 different definitions of sustainable development, offering a number of possible modifications of the development process and a number of different reasons for doing so. Also this was quoted in [16]. Finally we quote from: Source: Paul Samson, July 1995 http://greencross.unige.ch/greencross/digiforum/concept.html
34
D. Bjørner
Quotation 2 Sustainable development is currently a “catch-word”2 , and as such, is often used and abused. Therefore, before we can examine an issue of sustainable development, it is necessary to examine the concept itself. Some parameters for defining the concept are given here, and a number of competing visions are offered in the spirit of pluralism. The concept of, as opposed to the term of, “sustainable development” is not new; the profound and complex problems subsumed by the term can be traced back to the earliest human civilizations and the perennial tension between population growth and economic development, on the one hand, and the use of natural resources and ecosystems on the other. There is strong evidence suggesting that sustainable development constituted a challenge to our earliest societies, dating back to the ancient Sumerian, Mayan and Mediterranean civilizations [19]. The term “sustainable development”, however, is a recent invention, coming into common usage following the publication of the Brundtland Report [11], although even the term’s origins may be traced back to before the 1972 United Nations Conference on the Human Environment [20]. The Brundtland Commission is also responsible for the most frequently cited definition of sustainable development: to meet the needs of the present without compromising the ability of future generations to meet their own needs. As this section emphasizes, such a definition can be interpreted to have various meanings and is of little use if it is not placed within a specific context, or if the assumptions lying behind it are not clear. Indeed, as the following paragraphs will show a central point of this chapter is that the concept of sustainable development has multiple meanings, and that each is equally legitimate. It is noteworthy that a universally accepted definition does not exist for many basic concepts used by society, even for those which are seen to concern our well being. For example, it is often argued that the concept of security is useful precisely because its remains contested. This is why sustainable development, without a commonly accepted definition, appeals to virtually all groups who choose to participate in the environmental debate. Under such conditions, being “pro” sustainable development entails no risk or commitment to a specific set of goals or conditions since none are agreed upon [21]. Almost any group can find their own interest somewhere within the concept, and it is therefore hard to be against it in general. This allows the banner of sustainable development to be used by competing groups toward different or even contradictory ends. A number of these contradictions have been identified, and included among these are issues no less stark than “growth versus limits”, “individual versus collective interests”, “intergenerational versus intragenerational equity” and “adaptability versus resistance” [22]. However, these contradictions are part and parcel of human institutions and therefore, no less of Sustainability. Further complication occurs because the concept of sustainable development can be broken into two parts. On the one hand, “Sustainability” relates to the question of the “carrying capacity” of the earth, while giving no attention to social issues, particularly those concerning equity and social justice. “Development”, on 2
The use of double quote: “. . . ” is Paul Samson’s
A Triptych Software Development Paradigm
35
the other hand, would appear to assume and even necessitate continual economic growth and ignore the question of ecological constraints or “carrying capacity”. When these two concepts are put together, a very different one emerges, and the result is much more than the sum of the parts. It is therefore a multi-dimensional concept, and it must be addressed at various levels simultaneously. Sustainability may be divide into three types: social, ecological and economic. The ecological definition is perhaps the clearest and most straightforward, measuring physical and biological processes and the continued functioning of ecosystems. Economic definitions are sharply contested between those who emphasize the “limits” to growth and carrying capacity, [23] and those who see essentially no limits [24]. Similar to global environmental change, sustainable development remains first and foremost a social issue. Although the precise geo-spheric/bio-spheric “limits” of the planet are unknown, it is suggested here that the limits to the globe’s Sustainability for humans are more urgently social than they are physical. In other words, we will reach the social limits of Sustainability before we reach the physical ones. Thus, our focus should be on society-based solutions for managing the multiple aspects of global change rather than on technology-based ones. It is important to emphasize the human aspect of sustainable development — for example, institutional and political constraints. Any conclusions about the meaning of sustainable development remain dependent on considerations of context and spatial and time delimitations. At a global level, the following set of definitions serves well: In the narrowest sense, global Sustainability means indefinite survival of the human species across all the regions of the world... A broader sense of the meaning specifies that virtually all humans, once born, live to adulthood and that their lives have quality beyond mere biological survival... the broadest sense of global Sustainability includes the persistence of all components of the biosphere, even those with no apparent benefit to humanity [25].
4
Sustainable Development — A Domain Analysis
We analyze the concept of sustainable development. The analysis is decomposed into a number of parts. 4.1
Development
Development is about resources: be they natural resources, monies people, equipment, capabilities, or other. “Raw” development is (like) a function: from a set of resources to a set of resources: type R value ∼ D0: R∗ → R∗
36
D. Bjørner
In “raw” development we just develop! — without any consideration to resources at hand, in particular: whether sustainable or not! Two developments with exactly, if that was ever possible, resources need not yield the same resulting resources. The above expresses that there is an abstract type, a sort, named R, which stands for all resources, and that there is some further unspecified, ie. “grossly” ∼ underspecified function (hence partial →), D0 , from sequences of resources into sequences (∗ ) of resources. 4.2
Resources
Resources “fall” in (“main”) categories (C): Examples 1 Land, Monies, Minerals, Crops, People, etc. Each category (has a name and) designates a set of resources possessing same attributes (A): Examples 2 Land: quality, area, location, cost, . . . ; Monies: kind, currency, amount, . . . ; . . . ; People: profession, quality, quantity, . . . ; etc. Each category and attribute (pair) designates a value class (VAL): Examples 3 (l:Land,a:Area): from one acre to maybe 20,000 acres; (p:People, a:Amount): from one to perhaps 2,000; etc. type C, A, VAL value obs RC: R → C obs CRs: C → R-set obs RAs: R → A-set ∼ obs RAV: R × A → VAL obs AVs: A → VAL-infset axiom ∀ c:C • ∀ r,r0:R • {r,r0} ⊆ obs CRs(c) ⇒ obs RAs(r) = obs RAs(r0) ∧ obs RC(r) = obs RC(r0) = c ∧ ... The above RSL notation expresses that there are further algebraic sorts: categories, attributed and values, and that there are some further unspecified observer functions. Each resource “belongs” to one main category (obs RC).3 Each resource relates to a set (-set) of attributes (obs RAs). Any given resource may or may not have a value for a given attribute (obs RAV). 3
We could postulate another category-observer function (obs RCs, not shown) which to resources associated “related” categories, such that, for example two different resources of the same main category associated to not necessarily the same set of “related” categories.
A Triptych Software Development Paradigm
37
Our (domain) observer functions are not definable by us, but are defined by the domain. Observer functions are, however, characterisable by two kinds of axioms. Firstly general axioms that characterise the general model of sustainable development. One is shown above: It expresses that all resources of a specific category must have the same set of attributes and, of course, be of that category. We may relax the former (same set of attributes), but cannot relax the latter (be of that category). (The symbols • and ⇒ can be “pronounced” ‘such that’ and ‘implies/imply’, respectively.) Secondly instantiated, specific axioms: For a given, ie. an instantiated case of sustainable development, for example the building of a chemical plant, or fertilisation of crops, the resources, categories, attributes and values are “fixed” and a (possibly) consistent, but not necessarily complete axiom scheme “set up”: one which approximates relations that are believed to hold between these specific resources, categories, attributes and values. 4.3
Indicators
An indicator is a measure of desired values of resource attributes. Sometimes an indicator is a value with, perhaps, some fuzzy membership (or probability) function. Sometimes an indicator is a pair of values (a range) (perhaps adorned with some sort of fuzziness). And, sometimes an indicator is a function, for example a simple function from time to attribute values, or a more complex function, for example a function from time and another attribute value to (perhaps fuzzy) values. An indicator thus expresses a desirable interval within which actual resource attribute values are to range at given times and/or in the presence of other (fuzzy) valued attributes, etc. type I Fuzzy value ∼ is in Rng: R × A × I → Fuzzy
4.4
Resources, Attributes and Indicators
In development we are interested in certain resources, and for each of these, in certain attributes, and, for each of these, in focusing on certain (intervals of) indicators. We may speak of such a “thing” as a RAIs: A resource to attribute indicator range “table”: type RAIs = R → m (A → m (I×I)) The above defines RAIs to be a space of maps from resources to maps from (their) attributes to pairs of (“lo–hi”) indicators. An ‘abstract’ example could be:
38
D. Bjørner
Examples 4 rais:
a11 7→ (i111 , i112 ) r1 7→ a12 7→ (i12 , i12 ) 1 2 r2 7→ a21 7→ (i211 , i212 )
The example, rais:RAIs, expresses that we are concerned with exactly two resources, and, for resource r1 in two of its attributes. We do not, in RAIs, express resource categories nor resource attribute values: these properties are part of the resources, r1 , respectively r2 . Cf. observation functions obs RC, respectively obs RAV, etc. 4.5
Equities: Constraints and Objectives
Sustainable Development: Development is said to be sustainable if (i) it maintains an invariant (an equity) between resources before and after development. Other variants of what an equity is are: if (ii) it, after development, achieves certain (indicated) resource attribute values, respectively if (iii) development is constrained, ‘before and after’, by indicated attribute value ranges (“within interval”). An equity, E0 , is therefore chosen to express a fuzzy (in general a multicriteria, underspecified) relation. type Small ∼ E0 = (RAIs × RAIs) → Fuzzy 0 0 ES = En → m E Acceptable = Fuzzy × Small → Bool We do not mandate any specific equity relation. The construction of equity relations entail oftentimes rather serious mathematical, control-theoretic, operations-analytic, knowledge-based (expert) system, or other modeling (see Section 7.3). When applying a fuzzy equity function to pairs of resource sets combined with their attributes and the indicators of these attributes: namely a pair designating a “before–after” (development) relation, we expect to get an acceptable level (below ‘small’). Thus the class ‘Acceptable’ denotes predicates, each of which we supply with an acceptance factor (‘small’). The primed type names, for example E0 and ES0 , designate precursors for subsequent, stepwise “refined” unprimed type names. For E see Section 5.7. 4.6
Analysis = Modeling “in the Small”
Such modeling — as was just mentioned at the end of the previous section — may stabilize only after repeated analytical experiments. That is: fixing which are the relevant indicators and which are the relevant equity functions require various kinds of mathematical modeling, i.e. analysis. Analysis with respect to sustainable development involves:
A Triptych Software Development Paradigm
39
1. 2. 3. 4.
identifying relevant resources (rs:RS), affected attributes (a:A), their indicator intervals ((li,hi):I×I), specimen (analysis labeled (lbl:Lbl)) combinations of resources, attributes and indicators (rais:RAIs, and lrais:Lbl RAIss) 5. relevant (named, En) equity functions (in ES0 ). Formally, analysis amounts to: type Lbl RS = R-set Lbl RAIss = Lbl → m RAIs Analysis0 = RS × Lbl RAIss × ES0 value ∼ A Result: Analysis0 → (En → m Fuzzy) axiom [ proper analysis ] ∀ (rs,lraiss,es0):Analysis0 • ∀ rais:RAIs • rais ∈ rng lraiss ⇒ dom rais ⊆ rs ∧ ∀ e0:E0 • e0 ∈ rng es0 ⇒ (rais,) ∈ dom e0 The result of analysis associates with each equity some fuzzy judgment as to whether a planned development, as expressed by the equity functions, achieve equity. The keywords dom and rng designate the map definition (domain), respectively the range set yielding operations.
4.7
Planning
Planning is concerned with creating descriptions of development (functions, d:D). Since these have to satisfy a variety of equities, planning also involves analysis. type DS = Dn → m D ∼ D = RAIs → RAIs Plan = Analysis0 × DS axiom ∀ ((rs,nmrais,es0),ds):Plan • ∀ d:D, rais:RAIs • d ∈ rng ds ⇒ rais ∈ dom d ∧ let rais0 = d(rais) in ∀ e:E • e ∈ rng es0 ⇒ ∃ s:Small • Acceptable(e(rais,rais0),s) end
40
4.8
D. Bjørner
Sustainable Development
Sustainable development is now the act of actually carrying out the planned development after analysis of plans has validated these according to desired equities. type ∼ Development = (Plan × RS) → RS Here we have taken a very simplistic view of development. A more realistic view would only add details and not further illustrate the formalisation principles we strive to adhere to. 4.9
Time Frames
Among the resources treated is time. In the RAIs arguments there will undoubtedly be various forms of time attributes and indicators: past, present and future time, time intervals, etc. Non-time attribute indicators may themselves be functions of times and intervals. Thus we believe, that in the above model we capture “all” conceivable needs for time parameters, time considerations, etc. 4.10
Discussion
Resources vs. Resource Representations: As always our language of communication, in the daily pursuit of our business: here sustainable development, mixes references to “real” resources with references to representations of resources. As long as we are fully aware of the dangers in possibly confusing them, OK. So far we have been referring to “real” resources, not their representation. That will be done in Section 5.1. Function Arguments and Results: In this paper we “lump” all conceivable arguments to functions and predicates into the convenient form of one single rais:RAIs argument. Readers may find that when they start understanding what all these functions, like Equity “predicates”, Experimental Analysis and Analysis functions, Planning and Development functions, are doing, then they may start wondering: what happened to time considerations?; what happened to financial expenditures, what happened to the deployment of engineers, designers, construction workers, etc.? The simple answer is: They are all gathered together, not as separate parameters to conventionally type functions, as in mathematics or programming, but as a rais:RAIs argument. Let us just show an example: Examples 5 A ‘before’/‘after’ development relation:
A Triptych Software Development Paradigm
41
– Before development:
7 [a 7→ iia , t 7→ iit ] r1 → r2 → 7 [aα 7→ iiα ]
– After development: 7 [a 7→ ii0a , t 7→ ii0t ] r10 → r20 → 7 [aα 7→ iiα ] r3 → 7 [aβ 7→ iiβ ]
An interpretation of the above could be that in this development three resources are being changed (r1 , r2 ) or created (r3 ). Resource r1 has a time attribute. Before development its value satisfied some equity indicator interval iit , afterwards is satisfies ii0t . Etcetera. What we mean by ‘satisfy’ is again open for wide interpretation. This example serves to show that the preparer, the analyzer and planner have very wide degree of freedom in formulating functions over almost any combination of resources and, within these, of interpretation.
5
Requirements Capture: A “DSS for SD”
By a ‘DSS for SD’ we mean a decision support system for sustainable development. Section 4 described what we mean by sustainable development. In this section we will analyze the actions needed in preparing for, making plans and analyzing plans for sustainable development, and, in particular, identify the computer and communications support of these actions. That is: we capture, in this section, the requirements for a DSS for SD. In doing so we shall repeatedly refer to subsections of section 4. 5.1
Resource Representation
In section 4 we “dealt” with “real” resources. In real reality we “deal” with representations of resources. That is: we assume that every resource (r:R) that we wish to handle can be “formally” represented, ie. modelled by some rr:RR, the class of resource representations. We therefore redefine the functions over R to also apply to RR: type RR value obs RRC: RR → C obs RRAs: RR → A-set ∼ obs RRAV: RR × A → VAL ∼ is in Rng: RR × A × I → Fuzzy
42
D. Bjørner
With this follows that we redefine: type RRAIS = RR → m (A → m (I × I)) ∼ E = (RRAIS × RRAIS) → Fuzzy Etcetera.
5.2
Problem Synopsis
We refer to section 4.1. The problem synopsis — in a “gross” way, to be detailed (detail-resolved) by subsequent actions — identifies (including names) the major (initially “raw”) resources and development functions. Text stands for text that explains the pragmatics of whatever is being represented. type Q /∗ text ∗/ Resources = Q × (Rn → m (Q × RR)) DevtFct = (Q × (C∗ × C∗ )) DevtFuncts = Q × (Dn → m DevtFct) Synopsis = Q × Resources × DevtFuncts Location value ∼ obs RLoc: RR → Location obs RLoc is an observer function which to every resource representation associates its physical Location. Observe that only now did we actually use the notion of a resource category (c:C). When we, earlier, dealt with “real” resources there basically was no need to introduce categories of resources. Now that we work (mostly) with representations of resources, then we must introduce that type notion. The overall problem synopsis is informally described (Text). Each resource and development function is named (Rn, Dn) and explained (Text), and, for the development functions, a “type”-definition of the function is given in terms of the resource categories involved. Resources themselves are, of course, not present in the decision support system for sustainable development “machinery”: only representors (RR) which further locates the resources (etc.). Requirements Capture 1 Hence the decision support system for sustainable development must provide a repository (a data base) for ‘Synopsis’ as well as appropriate functions, for example for initializing PS, for inserting new, and for displaying, searching, sorting, updating, deleting existing resource representor and development function entries.
A Triptych Software Development Paradigm
5.3
43
Resource Mappings
We need establish mappings between real resources and their representors. type RRRM0 = RR → m R RRRM = {| rrrm | rrrm:RRRM0 • dom rrrm = RRS |} IRRRM0 = R → m RR-set IRRRM = {| irrrm | irrrm:IRRRM0 • ∪ rng irrrm ⊆ RRS |} RMs0 = RRRM × IRRRM RMs = {| (rrrm,irrrm) | (rrrm,irrrm):RMs0 • ∀ rr:RR • rr ∈ dom rrrm ⇒ rrrm(rr) ∈ dom irrrm ∧ rrrm(rr) ∈ irrrm(rrrm(rr)) |} The {| a | a:A • P(a) |} expression defines a sub-type of A, namely all those a of A that satisfy P(a). The prefix ∪ denotes distributed set union — since, in this case, rng irrrm yields a set of sets. Requirements Capture 2 Hence the decision support system for sustainable development must provide a repository (a data base) for these mapping as well as appropriate functions, for example for initializing RMs, for inserting new, and for displaying, searching, sorting, updating, deleting existing map entries. 5.4
Resource Names and Resource Representations
Resources are clustered in categories and maps between representors of real resources and their (non-unique) denotations must be established: type Resource Clusters = C → m Rn-set RR R Mapping = txt:Q × RRRM R RR Relation = txt:Q × IRRRM Resource Info = Resource Clusters × RR R Mapping × R RR Relation Requirements Capture 3 Hence the decision support system for decision support must provide a repository (a data base) for Resource Info as well as appropriate functions, for example for initializing Resource Info, for inserting new, and for displaying, searching, sorting, updating, deleting existing category and resource representor to “actual” resource mapping entries. 5.5
Resource Attributes, Values and Indicators
We refer to sections 5.1 and 4.4. For each resource category we must identify all relevant attributes, (Cluster Atrs) and for each specific resource (identified by its name) and attribute the (Sustainability) indicators (Resource Inds).
44
D. Bjørner
type Cluster Atrs = C → m A-set Resource Inds = Rn → m (A → m (I × I)) Atrs Inds = Cluster Atrs × Resource Inds
Requirements Capture 4 Hence the decision support system for decision support must provide a repository (a data base) for Atrs Inds as well as appropriate functions, for example for initializing Atrs Inds, for inserting new, and for displaying, searching, sorting, updating, deleting existing category and resource representor to “actual” attribute sets, respectively attribute and indicator sets. 5.6
Equity Identification and Definition
Preparation and analysis includes identifying equities and defining a suitable collection of equity functions: their signature (type) and their “behaviour”. Some “behaviours” may be only informally defined (Text). type Q /∗ text ∗/ Equity Ty = C → m (A → m I-set) Equity Df = E | Q Equity Functs = En → m (Equity Ty × Equity Df)
Requirements Capture 5 Hence the decision support system for decision support must provide a repository (a data base) for Equity Functs as well as appropriate functions, for example for initializing Equity Functs, for inserting new, and for displaying, searching, sorting, updating, deleting equity function types and definitions. In defining equity functions modelling experiments have to be performed in order to establish appropriate models. type Type X Type = typ txt:Q × ((Equity Ty × Type) × Type) ∼ X Funct = fct txt:Q × ((RRAIs × VAL) → VAL) Nmd Xs = Xn → m (txt:Q × (X Type × X Funct)) X Res = i txt:Q × ((RRAIs × VAL) → m (r txt:Q × VAL)) Exec Xs = Nmd Xs × (Xn → X Res) m The experiment functions (hence the use of X) form part of the model being built. They also must first be identified and defined. They finally must be executed and results recorded and annotated.
A Triptych Software Development Paradigm
45
Requirements Capture 6 Hence the decision support system for decision support must provide a repository (a data base) for Exec Xs as well as appropriate functions, for example for initializing Exec Xs, for inserting new, and for displaying, searching, sorting, updating, deleting experiment function types and definitions. Finally the decision support system for sustainable development must allow execution of the experiment functions. 5.7
Analysis Function Identification and Execution
Analysis functions are defined in terms of sets, ES, of equity functions. These functions now have to be executed, results recorded and interpreted. Analysis can be viewed as a set of analyses, each named (Lbl), provided with varieties of commented (Text) analysis data (RAIs), and with Results also commented (interpreted) and recorded. Each analysis function argument, besides the rais:RAIS arguments must also be provided with a resource mapping argument. So we need redefine Analysis: type iARGS0 = RRAIs × RMs EARGs0 = iARGS0 × RRAIs EARGs = {| ((rr,rm),rr0) | ((rr,rm),rr0):EARGs0 • dom rr ∧ ... |} ∼ E = (Val × EARGs) → Fuzzy ES = En → m E ∼ D = RAIs → RAIs DS = Dn → m D Analysis = RRS × NmRRAIs × ES Allocation and Scheduling Plan = Analysis × DS × Allocation and Scheduling
Requirements Capture 7 Hence the decision support system for decision support must provide a repository (a data base) for Plan as well as appropriate functions, for example for initializing, for inserting new, and for displaying, searching, sorting, updating, deleting analyses, including execution of functions and recording results. All insertions and updates usually require the user to provide textual comments (Text). Executing the modelling and analysis functions require naming the executions: type EAn Exec Res = (q:Q × (En → m (q:Q × (Lbl → m (q:Q × VAL))))) Exec Res Exec Plan = EAn → m
46
D. Bjørner
Requirements Capture 8 Hence the decision support system for decision support must provide a repository (a data base) for Exec Plan as well as appropriate functions, for example for initializing Exec Plan, for inserting new, and for displaying, searching, sorting, updating, deleting analyses, including execution of functions and recording results. All insertions and updates usually require the user to provide textual comments (Text). We end our example Requirements Capture here as no new principles are being illustrated and as the rest is, from now on, trivial! 5.8
The “Grand” State Σ
Summarizing we can say that the state of a DSS for SD consists of: type Σ = Synopsis × Resource Info × Atrs Inds × Equity Functs × Exec Xs × Plan × Exec Plan Requirements Capture 9 Hence the decision support system for sustainable development must provide a user interface to this state, to its various parts, easy selection and execution of functions: main and auxiliary, user- as well as systems defined. 5.9
Decision Making
Throughout this and the previous section we have implied that (i) resources had to be identified, (ii) representations sought, (iii) attributes (“of interest”) and (iv) indicators (likewise “of interest”) had to be determined amongst alternatives, (v) equity and (vi) analysis functions defined, likewise exposing the analyzer and planner to many options. Once analysis functions were executed and (vii) results interpreted choices again arise. Finally when planning, based on analysis, commences (viii) final options present themselves (or otherwise). All these situations must be carefully recorded; chosen paths (ie. decisions) must also be recorded and it must all be related to the various (i–iix) alternatives. Requirements Capture 10 Hence the decision support system for sustainable development must provide easy means for the user: preparer, analyzer and planner, to record all alternatives, to mitivate choices taken, and to “play–back” paths of identification, defintions, executions and choices, also along rejected alternative paths.
A Triptych Software Development Paradigm
5.10
47
“The Model”
Throughout this and the previous section we have also implied that a model of the development problem emerges. That model is, in fact, the hypertext–like woven path along alternative and chosen identifications, definitions, executions and interpretations of results and plans. Requirements Capture 11 Hence the decision support system for sustainable development must itself, as the user “navigates” around alternatives, selects and rejects choices, etc., build up a graph-like web of the paths taken, with nodes and edges suitably labelled with references to data and functions, explanatory, informal text that the systems elicits from the user, etc. We will have more to say about this in section 7.3.
6
A Federated GIS+DIS: (GaD)2 I2 S
By a federated geographic information system we understand a GIS+DIS whose main information, the spatial and (spatially related) census (and other) data and operations over these may reside across a global (i.e. worldwide) network of “ordinary”, already established or future geographic information systems “plus” demographic information systems. These latter GISs+DISs may represent their information each in their own way. From a practical point of view such GISs+DISs may be managed on APIC [26], ArcInfo [27], ArcView [28], ERMapper [29], IDRISI [30], InterGraph [31], MapInfo [32], PopMap [33], Redatam [34], and other platforms. The problem to be dealt with in this section is to properly integrate the concepts of geographic and demographic information systems (GISs, DISs) with the resource representation notions of the previous section. Hence we need take a look at GISs and DISs. These are aggregations spatially and statistically (tabular) data. By ‘federation’ we mean the further aggregation of individual GISs and DISs — as they may have been created and are maintained locally, around the world, each covering “separate” but eventually, increasingly more related resources. 6.1
A First Narrative
To explain our notion of ‘federation’ further we first present a “picture”, then some narrative, and finally a formal model. A Picture: A “picture is sometimes worth a thousand words”. Later we shall claim that a formula is oftentimes worth a thousand pictures. Yet even pictures need be explained: Squares with emanating arrows designate storage cells of type pointer. “Landscape” rectangles labelled ‘text’ designate unstructured, textual data (ie. text which informally describes formatted
48
D. Bjørner
Fig. 2. A Hierarchical GIS+DIS Federated Information System H = (D -> (C -> (V -> (H x Text x O x M)) x Text x O) x Text x O) x Text x O text h
Domain Name
os d q
text
Table os
ts c
Type Designator
text GIS data
Table
q
os
h’ v
Version Identifier Table
either/or
q
Ops
Spatially Related DIS data
Ops Ops
either / or
DIS data
Ops: Operations Table: os
h’ - next layer Computational Procedure
text
type o q
Operation opn.signature
Textual Procedure
l
DB Database
n
Stg Result Storage
data — here, from top left to right texts may explain domain, category and version information). “Landscape” rectangles labelled ‘opn.signature’ designate descriptions of operation types. “Curtain” figures — of which there are two kinds — designate domain/category/version sub-directories, respectively (operation, ie. executable) code directories. The top left to right “curtain” designate sub-directories of domains, categories, and versions (DCV). Directories have fixed format entries (“rows”). Initial DCV sub-directory rows link to further DCV sub-directories. Final DCV sub-directory rows link to either formatted or unformatted data: viz. relations, respectively images — and either directly, the upper arrow, or indirectly, via a database reference, the lower arrow. The final sub-directory rows also links, in the fashion of “recursive descent”, to another, lower, layer of domain/category/version directories. The formatted or unformatted data is shown as grey squares or grey “clouds”. Code directories link (i) to text briefly explaining the operation, (ii) to the type of the data needed as input to the formally or informally “executed” operation and resulting from those operations, and (iii) to either (formal, executable) code (the arrow-infixed pair of grey “clouds”), or to text (the arrow-infixed pair of grey squares) explaining
A Triptych Software Development Paradigm
49
how the human analyser can go about performing the analysis “by hand”! Performing an analysis function takes input from a database and delivers output to a result storage. Administrative operations, not shown, may move data from the result storage to the database. 6.2
A Second Narrative
Next we reformulate, more systematically, the above symbol explication: Layers and Levels: Figure 2 displays one layer, with three levels, of a hierarchically structured federated and combined geographic information system and demographic information system: GIS+DIS. (Further layers are referred to implicitly.) Each of the three large “curtains” (cascaded in the upper left corner of the figure) diagram a table like structure: Domain Name Table (the D level), Category (or rype) Designator Table (the C level), respectively Version Identifier Table (the V level). Domain Name Tables: One accesses the (or, in general, a) Domain name table from a root, a sentinel, Hierarchy designator (h). Each entry in the Domain name table contains a distinct domain name (d:D), a (reference to explanatory) text (q:Text), (a reference to) an operations table (os), and a (reference to a Category designator table (the latter only shown by an arrow). One accesses a Category designator table “through” (or via) a Domain name table entry. Type Designator Tables: Each Category designator table entry contains a distinct type designator (c:C), a (reference to explanatory) text (q:Text), (a reference to) an Operations table (os), and a (reference to a) Version identifier table. One accesses a Version identifier table through a Category designator table entry. Version Identifier Tables: Each Version identifier table entry contains a distinct version identifier (v:V), a (reference to explanatory) text (q:Text), (a reference to) an operations table (os), (a reference to) data, and a (reference to an) [sub]hierarchy (h). Data Access: One accesses Data through a version identifier table entry. Traversing Hierarchy Layers: One also accesses a sub-hierarchy (the “next” layer) through the H item of a version identifier table entry. Operations Tables: At any D, C or V level one can access an operations table. Each Operations table (O) entry contains a distinct operations name (on:On), (a reference to) explanatory text (q:Text), (a reference to) the type of the operation designated, and (a reference to) the operation [itself!].
50
D. Bjørner
Federation means that data may reside on different GIS, DIS, etc, platforms: commercial, experimental, public domain or otherwise: APIC, ArcInfo, MapInfo, IDRISI, PopMap, Redatam, winR+/GIS, etc. 6.3
A Third Narrative
Geographic, Demographic and other Data — Data: We now describe, more generally, but still informally, and from a slightly different viewpoint, the components of the proposed federated GIS+DIS. The base information unit, which usually is a highly composite entity, will be referred to as ‘Data’. Examples of specific data are: Examples 6 A Geodetic Map of China, A Political Map of Europe, A Vegetation & Natural Crops Map of GuangDong Province (in China), A Mineral Deposits Map of France, A Spatially related Population Census of Zhuhai4 , A Cartographic and Cadestral Map of Macau, etc. Domain Names: By D we understand the set of domain names: Examples 7 China, GuangDong, Zhuhai, . . . Data Category Designators: By C we understand the set of composite data types: Examples 8 Geodetic Map, Political Map, Vegetations & Natural Crops Map, . . . , Cadestral Map, Population Consensus Data, Import/Export Statistics, . . . , Election Data. Version Identifiers: By V we understand the set of version designators (time stamps) of data: Examples 9 1982, 1996, . . . , September 21, 1999, . . . The Database: Data is kept in a conceptual data base (DB). The data base, as we shall see, can be interpreted as being distributed globally. Each data has a location (L). Hierarchical Directory Structure: A (d,c,v) identification designates (geographic (GIS), demographic (DIS) and other) data in a hierarchical fashion. Assume fixed type and arbitrary version, then the domain name China could, for example, give access to some data on all of China and then to a set of properly domain-named sub-data of the same (and also other) type(s), etc. One for each (, say) Province of China. And so on, recursively, until some user-defined “smallest grain of data” — which could be a floor plan of a specific residence, a single plot of land for 4
Zhuhai is a Special Economic Zone of GuangDong Province in China
A Triptych Software Development Paradigm
51
agriculture, etc. This hierarchical (directory-like) recursion is modeled by the below recursion in H. Data identified “occur” only at the V level of a ‘complete’ (list of one or more) (D,C,V) triples. Use of the hierarchy (H) entails navigating “up and down” the layers of the hierarchy of (D,C,V) levels. At any one time a user has traversed a Stack of such (d,c,v)’s. Unary and N -ary Functions — O, On: With each data version there may be some specific, named (unary) functions applicable to that specific data. Designating an operation for application shall mean that the operation is applied to the data designated by the current stack top (which will be a list of (d,c,v) triples — with the list length denoting the current depth of the traversed hierarchy wrt. the root System Hierarchy). With each specific type we may likewise associate a set of named, unary functions. Each such function is then understood to be applicable to any version of data of that type and domain. The actual data is designated by the topmost stack element whose type matches the operation type. With each domain we may associate a set of usually n-ary functions. Each such function is then understood to be applied to data designated by the n topmost stack elements whose types matches, in order, the designated operation type. Some operations may not be computable. Instead text is given which directs the user to “perform” an appropriate evaluation and to enter a resulting value! Function Result Storage — Stg: Results of operation applications must be uniquely named (by the user) and are stored in a local storage (Stg) under that name together with a historical record of the stack of the time of application, and the appropriately (D,C,V) marked operation name. At any layer and level domain names, type names, version names, data and operations are annotated by explanatory, descriptive and other text (Text). Operations can be shared across domains, types and versions, as well as across layers of the recursive hierarchy. Database Sharing and Data Filtering — F: Since also data can be shared across domains, types, versions and layers of the recursive hierarchy, a filter function (F) is provided which, for different levels and layers (etc.) may specialize, generalize or otherwise instantiate the immediately location designated data. This potentially allows a simple information repository to be viewed, through the (D,C,V) hierarchy as a highly structured (network) of data. 6.4
A Formal (Data Structure) Model
“A small set of formulas is often worth a thousand pictures”:
52
D. Bjørner
type D, C, V, Res Typ, Res VAL, N S = H × DB × Stg × Stack Stack = DCV∗ H = (D → m (C → m (V → m (M×H×Q×O))×Q×O)×Q×O)×Q×O M=L×F ∼ F = Data → Data DB = L → m Data Stg = N → m (Res VAL × Stack × DCV × On) DCV = D | D×C | D×C×V OTup = ((A∗ × C∗ ) × Res Typ) ∼ OFct = (((VAL∗ × Data∗ )|Q) → Res VAL) O = On → m OTyp × OFct × Q Yet even the formulas may have to be narrated — and that was done in the three Sections 6.1—6.3. 6.5
Data Sharing, Viewing and Gluing
The indirect reference, via M, in the database DB to the geographic information system or demographic information system Data is provided for a number of reasons: Local Layering: For each layer descending M’s (i.e. L’s) may refer, in fact, to “overlapping” (probably embedded) Data. At one (say an “upper”) layer an L refers to a “large” spatial area (or a large census table), whereas at a “lower” the L may refer to an “smaller” area probably properly contained in the “larger” area. The View functions F therefor serve to sub-locate the right sub-Data! More concretely: If a domain name at an “upper” layer is ‘Europe’ then through the recursive decent through some (C,V) designated H we get the domain names: ‘Denmark’, etc. The “upper” L designated perhaps a map of Europe, whereas the “lower” should designate a map of Denmark. Quite specifically: In a Cartographic & Cadestral Service the maps of a city may be in the database DB as a set of “gluable” sub-maps. These may cover areas not related to administrative or other domain nameable entities. The various layers now “zoom” in on successively “smaller”, but administratively “wellrounded” areas. The purpose of the view functions are to collect from one or more sub-maps Data covering the located area and “glue” it together. Global Distribution: The database may itself be distributed — and across the globe! Now L’s (with their F’s, i.e. the M’s) also contain for example Internet information (etc.) so that the Data can be located “in somebody else’s database”!
A Triptych Software Development Paradigm
6.6
53
A Relational View
In the presentation of the Federated GIS+DIS given so far we may have left the reader with the impression that access to the global information is through a strict sequence of triples of domain, then type and finally version identifiers. We now lift this seeming restriction to allow for a relational access approach. Instead of the (d,c,v)-list view so far proposed and formalized: type H=D → m (C → m (V → m (M × H × ...) × ...) × ...) × ... we instead suggest a relational view: type rH RelH = (rH × H)-set H = D × C × V× rH × O × Q rH is like a relation tuple identifier. It is easy to see that any relation RelH can be mapped into either of: type H=D → m (C → m (V → m (M × H × ...) × ...) × ...) × ... H0 = C → m (D → m (V → m (M × H × ...) × ...) × ...) × ... H00 = V → m (C → m (D → m (M × H × ...) × ...) × ...) × ... etc. Given a relational representation the user can then determine, at any layer to view the information base, which ordering of the (d,c,v)’s to select — and the system can respond by presenting the tables as selected. Initially the system “sets” the hierarchy layer (H), for example: rhr0 . Subsequently the user sets, in sequence two of either of the D, C, or V “buttons”.
7
A GIS+DIS–based DSS for SD
In the decision support system for sustainable development we dealt with resources, with representations of resources, with attributes and indicators, and with functions over resources and resource representations, attributes and indicators. 7.1
Spatial Resource Maps and Filters
With respect to spatially related resources, we do not record the individual resources or their representations. Instead we typically, when it comes to for example environmental resources, record highly complex aggregations of numerous such resources in the form of for example remotely sensed images.
54
D. Bjørner
Fig. 3. Relational View of Federated GIS+DIS
{
rhr
0
rhr
{
d d d
c c c’
v v’ v
m m’ m"
rhr rhr rhr’
o o o’
q q’ q"
d’
c
v"
sm
nil
o"
q"’
H rhr o
D 2
C
V
1
From Relational to the CDV Functional View
Category/Type Domain c
q1
o1
Version d
q2
o2
q3’ q3
v’ v
o3’ o3
m’ m
o = o1+o2+o3 q = q1;q2;q3 rhr
¿From these we are then, somehow, able to extract, or as we shall call it: filter, representations of resources, one-by-one. Typically, however, the (for example) remotely sensed data also contains a confusing aggregation of other data that somehow must be screened away.
type Φ Coordinate = Real × Real × Real Area = Coordinate-set SpaResMap = Area → m (RR → m Fuzzy) AIs = A × I-set ∼ Filter = (AIs × Data) → (AIs × SpaResMap) Filters = Φ → m Filter So what we have, usually in a geographic information system are maps, or images, of complex aggregations of Data, and what we want are simple recordings, in the form of well-defined Spatial Resource Maps of resources. By a Spatial Resource Map, we understand a mapping from a an area, that is: a set of three dimensional coordinates to a map from Resource Representations to Fuzzy qualifiers. The idea is that the spatial map “cleanly” represents only those resources for which certain attribute values are present and within given indicator ranges. We choose to map from an area in order to capture averaging properties. Thus a Filter is a function from a triple of Attribute designators, Indicator ranges and (for example an image of remotely sensed) Data to a Spatial Resource Map.
A Triptych Software Development Paradigm
55
Fig. 4. A Generic Spatial Resources Map and its Filters a d1
Filter
data a’ d2
Filter
data
is
Legend: srm-1
φ
i is’
φ
d: a: is:
DCV* | Nm A I-set
srm:
A x I-set x SpatResMap
srm-2 j Equity- or Analysis Function
a" dm data
Filter
DCV = D | C | V SpatResMap = Area x (RR -> Fuzzy)
is" φ
k
result
srm-m
Several filter functions usually are needed to prepare input for the Equity and Analysis functions: Requirements Capture 12 A GIS+DIS–based DSS for DS must therefore allow the preparer, analyzer and planner to develop, record and apply filter functions (Φ). 7.2
The “Grand” System
The Data provided to the Filter functions “come” from the (GaD)2 I2 S repositories: either accessed through an appropriate DTV name list or by the name of a stored result. This basically completes the GIS+DIS–based DSS for SD System description. Requirements Capture 13 A GIS+DIS–based DSS for DS must therefore allow the preparer, analyzer and planner to “link” up the DSS for SD resource concepts with the Data concepts accessible through the recursive hierarchy of domain, type and version names and through the names of results stored, with comments, after human evaluation or computed execution of Equity, Analysis and Planning functions. 7.3
Towards “The Model”
Very briefly: the hyper-text “woven path” also includes the generation of graphs like the below:
56
D. Bjørner
Fig. 5. Towards a Development Model Database rsi
rsj
rsk
Fc Fa
Fe
Fb Fd
n2 n1 Storage
n
n3
n4 n’
n" n5
Figure 5 shows a number of Analysis functions and their interrelations with respect to input and output data. Output from some function applications serve as input to other function applications. Outputs (results) are named, and so are input arguments. The above graph (albeit conceptual and very simple) shows an overall “functionality”, an overall “structure” of the problem, one that is often, in the demographic information system literature, referred as being “ill-defined” and “unstructured”! In the above picture we have simplified many aspects: simple provision of resource arguments (rather than their prior filtering through filters etc., no user provided invocation time arguments, etc. Requirements Capture 14 A GIS+DIS–based DSS for DS must therefore be able to draw, upon request from the preparers, analyzers, planners, developers, and decision makers, the “model” graph of all Functions invoked — whether their results were ever again applied or not — together with a complete “trace” of Data used, whether originating from the Database or from Storage (where it would reside if that Data was the result of previous Function applications).
8 8.1
Conclusion On DSS for SD
We have sketched a main outline of how we intend to tackle the issue of decision support system for sustainable development, for how we intend to tackle the issue of a federated geographic information system and demographic information
A Triptych Software Development Paradigm
57
system, and for how we intend to combine them into (GaD)2 I2 S: a Federated GIS+DIS DSS for SD. We have separated two concerns: the DSS for SD from the Federated GIS+DIS. And then we have combined them. We usually find the issue of DSS for SD “cluttered up” by the mixing of problems of for example deciphering what spatial maps contain of information and the “pure” issues of resources, their attributes, indicators and equity functions. So we have separated the two issues. To then make the whole separation work we bring the issues together. 8.2
On Software Development
We have sketched main phase and some techniques of a new approach to software development: One that is based on domain models on which requirements are then based, and on requirements models on which software development is then based. This approach is currently under intense research, development and application [3,4,5,6,7,8,9]. But much work needs to be done before we can fully justify our claims: we need now carefully study relevant papers. The study will emphasize our “isolation” of the resource, attribute, indicator, equity function etc. issues in order to validate sections 4–5. The paper studies will then analyze the issues of geographic information system and demographic information system functionalities in order to validate section 6. Meanwhile we will be “building” a “prototype” (GaD)2 I2 S to make more precise the requirements Capture items mentioned in sections 5–7, and to check the conceptual elegance, consistency and comprehensiveness of the (GaD)2 I2 S proposal. 8.3
Acknowledgements
I thank (i) participants in the February 1996 UNU/IIST Workshop on Software Technology for Agenda’21: Decision Support Systems of Sustainable Development [35,36] for instigating the modelling effort of this paper and for kind remarks, (ii) my colleagues at UNU/IIST for enabling me to enjoy five stimulating years as first and founding UN director of that flourishing UN University software technology research and post-doctoral training centre in Macau, (iii) members of the IFIP WG 2.2 and IFIP WG 2.3 Working Groups for providing stimulating critique of my work, and (iv) Hans Langmaack for 20 years of close friendship.
References 1. The RAISE Language Group. The RAISE Specification Language. The BCS Practitioner Series. Prentice-Hall, Hemel Hampstead, England, 1995.
58
D. Bjørner
2. The RAISE Method Group. The RAISE Method. The BCS Practitioner Series. Prentice-Hall, Hemel Hampstead, England, 1992. 3. Dines Bjørner. Domains as Prerequisites for Requirements and Software &c. In M. Broy and B. Rumpe, editors, RTSE’97: Requirements Targeted Software and Systems Engineering, volume 1526 of Lecture Notes in Computer Science, pages 1–41. Springer-Verlag, Berlin Heidelberg, 1998. 4. Dines Bjørner and Jorge M. Cuellar. The Rˆ ole of Formal Techniques in Software Engineering Education. Annals of Software Engineering, 1999. Editors: Norman E. Gibbs and N. Coulter. 5. Dines Bjørner. Where do Software Architectures come from ? Systematic Development from Domains and Requirements. A Re–assessment of Software Engneering ? South African Journal of Computer Science, 1999. Editor: Chris Brink. 6. Dines Bjørner. Pinnacles of Software Engineering: 25 Years of Formal Methods. Annals of Software Engineering, 1999. Editors: Dilip Patel and Wang YingYu. 7. Dines Bjørner. Domain Modelling: Resource Management Strategics, Tactics & Operations, Decision Support and Algorithmic Software. In J.C.P. Woodcock, editor, Festschrift to Tony Hoare. Oxford University and Microsoft, September 13–14 1999. 8. Dines Bjørner et al. Formal Models of Railway Systems: Domains. Technical report, Dept. of IT, Technical University of Denmark, Bldg. 344, DK–2800 Lyngby, Denmark, September 23 1999. Presented at the FME Rail Workshop on Formal Methods in Railway Systems, FM’99 World Congress on Formal Methods, Toulouse, France. Avaliable on CD ROM. 9. Dines Bjørner et al. Formal Models of Railway Systems: Requirements. Technical report, Dept. of IT, Technical University of Denmark, Bld.g 344, DK–2800 Lyngby, Denmark, September 23 1999. Presented at the FME Rail Workshop on Formal Methods in Railway Systems, FM’99 World Congress on Formal Methods, Toulouse, France. Avaliable on CD ROM. 10. John Fitzgerald and Peter Gorm Larsen. Developing Software using VDM–SL. Cambridge University Press, The Edinburgh Building, Cambridge CB2 1RU, England, 1997. 11. Gro Harlem Brundtland, editor. Our Common Future. World Commision on Environment and Development. Oxford University Press, WCED, UN, 1987. 12. UN. Agenda’21. United Nations, The Rio de Janeiro, Brasil, Conference on Environment, June 14 1992. 13. LI Xia and Anthony Gar-On YEH. A dss for sustainable land development in china using remote sensing and gis — a case study in dongguan. In [35], 1996. Centre for Urban Planning and Environmental Management + GIS/LIST Research Centre, University of Hong Kong, Pokfulam Road, Hong Kong; [email protected]. 14. International Union for the Conservation of Nature. World conservation strategy. Technical report, International Union for the Conservation of Nature, Gland, Switzerland, 1980. Report highlights sustainability of natural resources. 15. A.G.Levinsohn and S.J. Brown. Gis and sustainable development in natural resource management. In M. Heit and A. Shrtreid, editors, GIS Applications in Natural Resources, pages 17–21. GIS World, Inc., 1991. 16. Anthony Gar-On YEH. Gis in decision support systems for sustainable development. In [35], 1996. Centre for Urban Planning and Environmental Management + GIS/LIST Research Centre, University of Hong Kong, Pokfulam Road, Hong Kong; [email protected].
A Triptych Software Development Paradigm
59
17. U.E. Loening. Introductory comments: The challenge for the future. In A.J. Gilbert and L.C. Braat, editors, Modelling for Population and Sustainable Development, pages 11–17, London, England, 1991. Routeledge. 18. A. Steer and W. Wade-Grey. Sustainable development: Theory and practice for a sustainable future. Sustainable Development, 1(3):223–35, 1993. 19. C. Ponting. Historical perspectives on sustainable development. Environment, (4-9):31–33, November 1990. 20. L.K. Caldwell. Political aspects of ecologically sustainable development. Environmental Conservation, 11(4):299–308, 1984. 21. M.R. Redclift. Sustainable Development: Exploring the Contradictions. Methuen, London and New York, 1987. 22. S.R. Dovers and J.H. Handmer. Contradictions in sustainability. Environmental Conservation, 20(3):217–222, 1993. 23. Nicholas Georgescu-Roegen. The Entropy Law and the Economic Process. Harvard University Press, Cambridge, 1971. 24. Julian Simon. The Ultimate Resource. Princeton University Press, Princeton, N.J., 1981. 25. B.J. Brown, M.E. Hanson, D.M. Liverman, and R.W. Meredith Jr. Global sustainability: Toward definition. Environmental Management, 11(6):713–719, 1987. 26. Apic. Apic news: Le journal d’apic systems. Technical Report 6, Apic Systems, 25, rue de Stalingrad, F-94742 Arcueil, Cedex, France, 1995. 27. Environmental Systems Research Institute (ESRI). Understanding GIS: The ARC/INFO Methods. Number Version 7 for UNIX and Open VMS. GeoInformation International, 307 Cambridge Science Park, Milton Road, Cambridge, CB4 4ZD, United Kingdom, 3 edition, 1995. 28. Environmental Systems Research Institute. Introducing arcview. Manual, Environmental Systems Research Institute (ESRI), ESRI Inc. 380 New York Street, Redlands, California 92373-2853, USA, 1994. 29. Earth Resource Mapping. Er mapper 5.0 – product information. Literature with demo version, Earth Resource Mapping, Level 2, 87 Colin Street, West Perth, Western Australia, 6005, 17 January 1995. 30. J. Ronald Eastman. Idrisi for windows. User’s Guide Version 1.0, Clark Labs for Cartographic Technology and Geographic Analysis, Clark University 950 Main St., Worcester, MA 01610-1477 USA, May 1995. 31. INTERGRAPH. Geographic information systems. Product info. folder, Intergraph Corporation, One Madison Industrial Park, Huntsville Albama 35807-4210, USA, 1995. 32. MapInfo. Mapinfo reference. Reference manual version 3.0, MapInfo Corporation, One Global View, Troy, New York 12180-8399, 1994. 33. UNSTAT/DESIPA. Popmap: Integrated software package for geographical information, maps and graphics databases – user’s guide and reference manual. Technical Report ST/ESA/STAT/107, Department for Economic and Social Information and Policy Analysis, Statistical Division (UNSTAT), United Nations, New York, New York 10017, USA, 1994. 34. CELADE/ECLAC. Redatam-plus version 1.1. User’s Manual Distr. GENERAL: LC/DEM/G.90 Series A, Nr. 201, Latin American Demographic Centre (CELADE)/United Nations Economic Commission for Latin American and Caribbean (ECLAC), Casilla 91, Santiago, Chile, December 1991. 35. Dines Bjørner, Zbigniew Mikolajuk, Mohd Rais, and Anthony Gar On Yeh, editors. Decision Support Systems for Environmentally Sustainable Development —
60
D. Bjørner
Software Technology for Agenda’21, UNU/IIST, P.O.Box 3058, Macau, February 25 — March 8 1996. IDRC (International Development Research Centre, Ottawa, Canada) and UNU/IIST (United Nations University, International Institute for Software Technology), UNU/IIST. Unpublished Workshop Hand-outs. (Workshop co-sponsored by IDRC: The Canadian Governments’ Intl. Devt. Research Centre, Ottawa.) 36. P.A.V.Hall, D.Bjørner, and Z.Mikolajuk (eds.). Decision Support Systems for Sustainable Develpoment: Experience and Potential. Position Paper 80, UNU/IIST, P.O.Box 3058, Macau, August 1996. International workshop on Decision Support Systems for Environmentally Sustainable Development — Software Technology for Agenda’21 co-sponsored by IDRC: The Canadian Governments’ Intl. Devt. Research Centre, Ottawa.
Real-Time Constraints Through the ProCoS Layers Anders P. Ravn1 and Hans Rischel2 1
Department of Computer Science, Aalborg University, Fr. Bajers vej 7E, DK-9220 Aalborg Ø, Denmark, [email protected] 2 Department of Information Technology, Technical University of Denmark, DK-2800, Lyngby, Denmark
Abstract. The Provably Correct Systems project [5, 6] developed links between layers of formal specifications for real-time systems. These layers cover requirements capture, design, programming and code generation. In this paper we trace real-time constraints through the layers in order to inspect their changing forms. They originate in constraints on continuous dynamical models of physical phenomena. However, in a digital system it is desirable to abstract the complexities of these models to simple clocks, and further to events in a reactive system. This paradigm is the main topic of this paper. We illustrate the different forms of timing constraints in duration calculus, a real-time interval logic. Keywords: embedded system, hybrid system, real-time, requirements, design, formal specification.
1
Introduction
When the Provably Correct Systems (ProCoS) project was near its completion, the Lyngby team, who was responsible for case-studies and requirements, received a very long mail from Markus M¨ uller-Olm, then in Kiel. It essentially said: “Here is your code!” and continued 01010001010100001001011101010101011 11010101111111010101011111111111100 10101001001000001000001111010101010 ...
It serves no purpose to explain details of this binary code; such interpretation is better left to digital computers. However, the main result of ProCoS was that we had some reason to believe that this particular code would have controlled suitable hardware, such that top level requirements for a gas burner [11] were satisfied. These requirements are specified in duration calculus [14], a real-time interval logic. In order to illustrate the gap between requirements and code we give the formal requirements here, along with an informal explanation of the duration E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 61–78, 1999. c Springer-Verlag Berlin Heidelberg 1999
62
A.P. Ravn and H. Rischel
calculus. The logical foundations of duration calculus are treated thoroughly in [3], while other selected applications are found in [7, 9, 12, 13, 10]. The basis for duration calculus is a dynamical systems model with state functions that for each point of real time assign a value to the states. In the case of the gas burner Heatreq, Flame, Gas, Ignition : Bool express the physical state of the thermostat, the flame, the gas supply, and the ignition transformer. The requirements are then given by the invariance of the following formulas over arbitrary, closed intervals of time [b, e] with b, e denoting non-negative real numbers, satisfying b ≤ e. Safe. For Safety, gas must never leak for more than 4 seconds in any period of at most 30 seconds R ` ≤ 30 ⇒ (Gas ∧ ¬Flame) ≤ 4 In this formula, the R interval function ` is the length of the interval (e − b), and the duration term (Gas ∧ ¬Flame) is the integral over the interval of the state expression Gas ∧ ¬Flame. It denotes exactly the (accumulated) duration of the unsafe state when gas is leaking. Off. Heat request off shall result in the flame being off after 60 seconds d¬Heatreqe ⇒ ` ≤ 60 ∨ ((` = 60); d¬Flamee) The premise in this formula asserts that the state ¬Heatreq essentially holds for def R the full interval: d¬Heatreqe = ( ¬Heatreq = `) ∧ (` > 0). In this sub-formula, the conjunct ` > 0 ensures that it is a proper interval, and not a point where b = e. The conclusion (` = 60); d¬Flamee asserts that the interval can be “chopped” (the ‘; ’ operator) into subintervals [b, m] and [m, e] such that ` = 60 holds for [b, m] and d¬Flamee for [m, e]. On. Heat request shall after 60 seconds result in gas burning unless an ignite or flame failure has occurred dHeatreqe ⇒ ` ≤ 60 ∨ ((` = 60); dFlamee) ∨
3 (IgniteFail ∨ FlameFail )
The exceptional conditions are specified by 3 (IgniteFail ∨ FlameFail ) which asserts that somewhere in the interval an IgniteFail or an FlameFail occur. For the moment we leave the formulas denoted by IgniteFail and FlameFail unspecified. It is clear that the requirements On and Off are bounded progress properties; they require that a certain state is reached within a given time. Such properties are analogous to stability of a dynamical system: after some time the system remains in some bounded region. It is also intuitively clear that in programming
Real-Time Constraints Through the ProCoS Layers
63
terms they correspond to upper bounds on the time to pass through certain paths of the program. The Safe requirement on the other hand is analogous to a constraint of the type found in optimal control, where the objective is to minimize the unsafe state Gas ∧ ¬Flame over the given period of 60 seconds. It is also intuitively clear that this is programmed by staying long enough in safe states before passing as quickly as possible through potentially unsafe states. It is therefore reasonable to expect that the top level requirements are transformed into upper and lower bounds on the duration of certain program states in a design. The binary code, however, does not mention anything about upper bounds and lower bounds. The only duration that can be associated with a machine code instruction, is the number of cycles of the processor and the delays on input/output operations, including communication with (hardware) timers. The correspondence between the bounds of the design and the low level properties must be checked during compilation. The main achievement of ProCoS was to establish semantic links and in particular corresponding syntactic transformations that allowed refinement from such top level requirements down to machine code or hardware circuits. This story has, however, been told quite a number of times, and has inspired much further work of which some is reported in other papers of this volume. The focus of this paper is on the real-time properties, and how they surface in a ProCoS design trajectory. The aim is to highlight suitable abstractions for real-time properties in a systematic development. Activity Requirements analysis System design Program design
Documents Requirements System specs Program source
Language RL Requirements logic SL System specification language PL Programming language
Either: Hardware synthesis
Circuits
HL Hardware Language
Or: Compilation
Machine code
ML Machine language
Fig. 1. ProCoS tower of development stages
Overview. The investigation follows the “ProCoS tower” shown in Figure 1. Section 2 analyzes the specification of requirements with respect to real-time properties. Section 3 introduces the architectural components: sensors, actuators and (programmed) controllers. The latter are specified by “implementable” forms which are related to timed automata. Section 4 touches briefly on transformation to programs and compilation. Finally, in the concluding Section 5 we discuss the overall development process. In particular, we enquire whether it would be
64
A.P. Ravn and H. Rischel
useful to work from the middle out, i.e., to postulate a design in terms of timed automata and check upwards and compile downwards.
2
Requirements
In order to understand requirements for an embedded computer system one must know a little about the physical plant that it monitors or controls. Such plants are usually modelled by dynamical systems, i.e. systems with a state that evolves over time. Within the engineering disciplines, the background for the study of such systems is control theory. We outline central elements of control theory below. However, we shall use duration calculus to express top level requirements, so the next step is to make this notation precise. The final part of the section then introduces and discusses the kinds of requirements usually encountered in our case studies and gives analogies to corresponding dynamical systems properties. At the end of this section we have thus illustrated an informal link between control engineering and embedded systems requirements. 2.1
Control Theory
Typically, a model of a plant is given in terms of a vector x of state variables that evolve smoothly over time modelled by the reals. The characteristics of the particular plant are specified by associating a differential equation with the state: ˙ ) = F (x(t )) for all time points t x(t Here, x˙ denotes the component-wise derivative of x with respect to time, and F is a vector function that characterizes the relationship between the different state components of the plant. When a plant is to be controlled, the model is extended by superimposing a control input component u such that the model becomes ˙ ) = F (x(t ), u(t )) x(t There are variations of this framework, e.g. with discrete time, adding disturbance to the model, or with the state as a stochastic variable. However, the main effort in control engineering is not to modify this framework, but to find a mathematically tractable model, investigate its mathematical properties, and most importantly to check that it is a good enough model of the physical plant. In formulating requirements to an embedded computer system that controls the plant, one uses explicitly or implicitly some mathematical model of the plant. The computer program is in effect observing x through sensors and controlling u through actuators, and program requirements must unavoidably be formulated in terms of these or precisely related states. The key property that one would require of a dynamical system is stability, i.e. if it started in a reasonable state, then it will eventually settle in a bounded
Real-Time Constraints Through the ProCoS Layers
65
region. A stronger concept is asymptotic stability where the system tends to an equilibrium point as time grows beyond any bounds. However, there might be many ways of choosing a u term such that the system is stable. Thus one can consider additional constraints on the control input and the plant state. A general formulation is to introduce a non-negative cost function K and consider the accumulated cost RT 0 K (x(t ), u(t ))dt R∞ where T is a fixed bound, or the amortized cost 0 K (x(t ), u(t ))e −at dt where a is a positive discount factor. One can then try to find an optimal control which minimizes the cost. In summary, we would expect to find stability and some sort of optimality as the generic top level requirements also for an embedded system. Hybrid Systems. In practical engineering, it has long been recognized that a plant might have several operating modes with different characteristics. When mode changes happen infrequently, one can analyze each mode in isolation and use the conventional theory outlined above. However, if modes change rapidly, for instance when controlled by computers, it is uncertain whether the transients can be ignored. Thus there is increasing interest in theories combining the effects of discrete transitions and continuous evolutions - theories for hybrid systems. However, the classical questions of stability and optimal control are still central to any extended theory. We shall not detour into hybrid systems theory, but refer the interested reader to the presentation by Branicky in [1]. 2.2
Duration Calculus
The usual language for control engineering is the conventional notation of mathematical analysis, and it serves its purpose very well, when used in in traditional mathematical argumentation. However, formal reasoning is rather cumbersome when all formulas contain several quantifiers over time points, state values, etc. This was the rationale for Duration Calculus which we summarize in the following. Syntax. The syntax of Duration Calculus distinguishes (duration) terms, each one associated with a certain type, and (duration) formulas. Terms are built from names of elementary states like x or Gas, and rigid variables representing time independent logical variables and are closed under arithmetic and propositional operators. Examples of terms are ¬Gas and x = 0 (of Boolean type) and x˙ − c (of type vector of real). Terms of type (vector of) real are also called state expressions and terms of Boolean type are called state assertions. We use f , g for typical state expressions and P , Q for typical state assertions. Duration terms are built Rfrom b.f and e.f denoting the initial and final value of f in a given interval, and f denoting the integral of f in a given interval. For
66
A.P. Ravn and H. Rischel
R a state assertion P , the integral P is called the duration, because it measures the time P holds in the given interval, when the Boolean values are encoded with 0 for false and 1 for true. Duration formulas are built from duration terms of Boolean type and closed under propositional connectives, the chop connective, and quantification over rigid variables and variables of duration terms. We use D for a typical duration formula. Semantics. The semantics of Duration Calculus is based on an interpretation I that assigns a fixed meaning to each state name and operator symbol of the language, and a time interval [b, e]. For given I and [b, e] the semantics defines what domain values duration terms and whatRtruth values duration formulas R e denote. For example, f denotes the integral b f (t )dt , b.f denotes the limit from the right in b (f (b+)), and e.f denotes the limit from the left in e (f (e−)). A duration formula D holds in I and [b, e], abbreviated I, [b, e] |= D, if it denotes the truth value true for I and [b, e]. The boolean connectives and quantifiers have their usual meaning. The chop operator is the only modality; given duration formulas D1 and D2 , the formula (D1 ; D2 ) holds on the interval [b, e] just when there is a chop point m such that D1 holds on the initial subinterval [b, m] and D2 holds on the final subinterval [m, e], see Fig. 2. D is true in I, abbreviated I |= D, if I, [0, t ] |= D for every t ∈ Time. A model of D is an interpretation I which makes D true, i.e. with I |= D. The formula D is satisfiable if there exists an interpretation I with I |= D . A behaviour is an interpretation restricted to the names of the elementary states.
D1 ; D2 D2
D1 Time
b
m
e
-
Fig. 2. Semantics of chop.
Abbreviations. The lengthRof an interval is often used; it is the duration of the constant assertion true ( true) which is abbreviated (`), pronounced ‘the length’. The property that an assertion P holds R (essentially everywhere) in an interval is thus given by the atomic formula P = `. This holds trivially for a point interval of length zero, so we consider proper intervals of a positive length. The two properties are combined in the abbreviation def R dP e = ( P = `) ∧ (` > 0),
Real-Time Constraints Through the ProCoS Layers
67
read as ‘P holds’. We also use a variant of this notation when P holds for some time t ≥ 0: def R dP et = ( P = `) ∧ (` = t ) Initialization and Invariants. Notice that when a behaviour satisfies a formula D , then D holds for every prefix [0, t ] of time. It means that initialization can be specified by a formula that typically has the form ` = 0 ∨ (D0 ; true), where ` = 0 holds for the starting point [0, 0], while D0 gives initial constraints on the states which will hold for some arbitrarily small but positive time. Most properties are, however, invariants, so we must express that they hold in any subinterval. For this purpose, the operators “somewhere” ( 3 ) and its dual
“everywhere” ( 2 ) are introduced:
3D
def
= true; D ; true and
2D
= ¬ 3 ¬D .
def
Proof System. The proof system for Duration Calculus is built on four kinds of elementary laws or rules: Math is a lifting rule that allows any result R about values or integrals which can be proven to hold for any interval using mathematical analysis (MA): MA` ∀b, e : Time • b ≤ Re ⇒ Re e R(f1 (b+), f1 (e−), b f1 (t )dt , . . . , fn (b+), fn (e−), b fn (t )dt ) R R R(b.f1 , e.f1 , f1 , . . . , b.fn , e.fn , fn ) Lifting is crucial for a smooth interface to other engineering disciplines where mathematical analysis is the standard tool. Interval laws deal with properties of chop. This binary operator is associative and monotone w.r.t. implication: D1 ⇒ D10 D2 ⇒ D20 (D1 ; D2 ) ⇒ (D10 ; D20 ) Monotonicity is very useful in proofs, because it allows us to drop unimportant constraints within a chopped formula. Chop distributes over disjunction, has false as a zero, and a point as a unit. Chop also distributes over conjunction when the chop-points are aligned with each other: ((D1 ∧ ` = r ); D2 ) ∧ ((D3 ∧ ` = r ); D4 ) ⇒ ((D1 ∧ D3 ); (D2 ∧ D3 )). The converse follows immediately from monotonicity. Duration-Interval laws link integrals and values over a chop. The use of integrals (durations) is really justified by the additive properties in this link. R R R Integral-Chop. ( f = v1 ); ( f = v2 ) ⇒ f = v1 + v2 . When the state expression f is restricted to a state assertion P with non-negative duration, the converse also holds.
68
A.P. Ravn and H. Rischel
Sum.
R
R R P = r1 + r2 ⇔ ( P = r1 ); ( P = r2 ) for non-negative r1 , r2 .
This law expresses that Time is dense, as also seen in the derived property: dP e; dP e ⇔ dP e. Values. b.f = v ⇔ (b.f = v ); true and e.f = v ⇔ true; (e.f = v ). Induction. Finite variability of state assertions is crucial for proving invariant properties. Simple induction over time is not possible, thus it is replaced by induction over discrete state changes. We do not include the general induction principle, but its most important consequence, the P-cover property dP e; true ∨ d¬P e; true ∨ ` = 0 with a mirror image true; dP e ∨ true; d¬P e ∨ ` = 0 Note that ‘;’ binds stronger than ‘∨’ and ‘∧’. Standard Form. In principle, constraints can be formulated using arbitrary formulas, but a standard form has turned out to be useful because it simplifies reasoning and refinement. The basis is a binary operator (−→). It expresses that whenever a pattern given by a formula D is observed, then it is ‘followed by’ a goal state P , or stated in a negative form: def
D −→ dP e =
2 ¬(D; d¬P e)
This operator behaves like an implication and has a number of distributive laws. When the pattern says that an assertion holds for an interval, a Transitive law holds: (dP1 et1 −→ dP2 e) ∧ (dP2 et2 −→ dP3 e) ⇒ (dP1 et1 +t2 −→ dP2 ∧ P3 e) This is the law that allows a goal to be achieved through a number of intermediate states. 2.3
Requirements Analysis
Requirements are constraints on the behaviours of a system. In order to specify requirements, application specific plant states must be fixed. This is illustrated by the gas burner where the thermostat is modelled by the command state Heatreq : Bool while controlled states Flame, Gas, Ignition : Bool
Real-Time Constraints Through the ProCoS Layers
69
express the physical state of the flame, gas and ignition. A particular requirement is typically a commitment that the design shall satisfy under certain assumptions about the plant. Assumptions are essentially properties which we during the design assume satisfied by the plant. In other words, they are commitments in the design of the plant as such with the role of command and controlled states reversed. Thus, we can reasonably expect that commitments and assumptions express similar properties which typically are specified by the following kinds of formulas. Progress. The first kind specifies progress properties: When the command or the controlled states satisfy an assertion P , the controlled states will move to a region specified by an assertion Q within a given time t . dP et −→ dQe These commitments are analogous to concrete stability requirements for a mode of operation that is given by P . It is easy to see that the commitments Off ( d¬Heatreqe60 −→ d¬Flamee) and On ( dHeatreqe60 −→ dFlamee ) for the burner are of this form. In fact, also the assumptions for On can be given this form, e.g., ¬FlameFail is dGas∧Flamee −→ dFlamee, and ¬IgniteFail is dGas∧Ignitione1 −→ dFlamee. A progress commitment allows a design to ignore unstable modes. If P is oscillating with a period shorter than t (An example could be the thermostat going on and off with a period shorter than 60,) the formula is trivially true, and the design may focus on other commitments. This is in contrast to the bounded progress property of [4] which states that occurrence of P leads to Q within t , or
2 (dP e; (` = t ) ⇒ 3 dQ e) This formula requires a design to react on any occurrence of P . Any practical design must therefore at some point assume some minimal period, or alternatively weaken the commitment to express that an unstable mode is ignored: 2 (dP e; (` = t ) ⇒ 3 d¬P ∨ Q e). A formula that is equivalent to
2 (dP et ⇒ 3 dQ e) This looks like a very reasonable formulation of progress. However, it is inconvenient when the commitment says that the system should leave a mode P within time t , because taking Q to be ¬P in the formula above gives a contradiction, while dP et −→ d¬P e expresses exactly the desired property within the progress framework. Bounded Invariance. A progress constraint ensures that a system will move towards a goal when the current state is stable. The constraint is trivial if the current state is unstable. At the top level of requirements it is very useful to
70
A.P. Ravn and H. Rischel
have such under-determined constraints. They absorb gracefully all questions about the behaviour of the system under unstable command inputs, because they allow any implementation. However, when components are designed or when stating assumptions, it is useful to give additional constraints that ensure orderly progress by limiting the selection of goal states. When a progress constraint dP et −→ dQ e is implemented by some atomic transition, it satisfies an invariant dP e −→ dP ∨ Qe, i.e., when P is entered, it is stable until left for Q . Due to progress, it must be left at the latest after t time units. If we want to express that this invariance is time-bounded by t , we must identify the start of the P phase in the pattern: (d¬P e; dP e ∧ ` ≤ t ) −→ dP ∨ Q e This formula states that a current state P for a period of t time units will either remain stable or transit to Q . A special case of invariance keeps a current state stable. This is important in communication, because it gives other systems time to observe the current state. Unbounded invariance of P is dP e −→ dP e. If the system ever enters state P , then it will stay there for ever on. More useful is bounded invariance, where a system stays in P for some fixed period t : (d¬P e; dP e ∧ ` ≤ t ) −→ dP e Such an invariance ensures stability of P , as expressed in the following law, (d¬P e; dP e ∧ ` ≤ t ) −→ dP e ⇔
2 (d¬P e; dP e; d¬P e ⇒ ` > t )
In order to illustrate the flavour of a proof in duration calculus, we prove the implies part by contradiction. d¬P e; dP e; d¬P e ∧ ` ≤ t ⇒ {Sum} (d¬P e; dP e; d¬P e ∧ ` ≤ t ); d¬P e ⇒ {Assumption} false The proof uses that the negation of 2 (d¬P e; dP e; d¬P e ⇒ ` > t ) is the formula 3 (d¬P e; dP e; d¬P e∧` ≤ t ). Using monotonicity of chop, we will have disproved this formula if we disprove the initial formula. The second step uses the Sum law to chop the last subinterval where ¬P holds and to deduce that the length of subintervals is not greater than the length of the initial interval. The third step uses the assumption (d¬P e; dP e ∧ ` ≤ t ) −→ dP e which by definition is 2 ¬((d¬P e; dP e ∧ ` ≤ t ); d¬P e) which directly gives the contradiction.
Bounded invariance commitments are strong constraints that remove much non-determinism and thus design options. They should not be introduced without some consideration of the intended implementation technology. In a design, they can be refined to formulas of the same form and involving the same states, but ultimately they depend on assumption of some atomic invariance, analogous to Lipschitz conditions in a continuous model. It will thus assist a designer, if bounded invariance constraints are replaced by the weaker critical duration constraints, discussed in a following.
Real-Time Constraints Through the ProCoS Layers
71
Bounded Critical Durations. These formulas constrain the duration of some critical controlled state. These states are typically intermediate states which are unavoidable; nevertheless they should not endure. Another interpretation of a critical duration constraint on a state P is to see it as approximate stability of the non-critical state ¬P . A critical duration constraint defines the duration of a critical state P . This state shall only have a duration of c within at most t time units: R ( P > c ∧ ` ≤ t ) −→ d¬P e For nontrivial constraints, the parameters c and t satisfy 0 ≤ c ≤ t . Another formulation is the following law. R R (( P > c ∧ ` ≤ t ) −→ d¬P e) ⇔ 2 (` ≤ t ⇒ P ≤ c) Only-if is trivial. The implies is by contradiction. R `≤t∧ P >c R ⇒ {Sum} R ` ≤ t ∧ ((` ≤ t ∧ R P > c); P > 0) ⇒ {Finite Variability} ` ≤ t ∧ ((` ≤ t ∧ R P > c); 3 dP e) ⇒ {Definition} ` ≤ t ∧ ((` ≤ t ∧ P > c); true; dP e; true) ⇒ {Sum} R (` ≤ t ∧ P > c); dP e; true ⇒ {Assumption} false The first step applies the Sum law and a simple property of reals: If r > c then there exists positive r1 , r2 such that r1 > c and r1 + r2 = r . The second step appeals to the finite variability underlying induction: If P has a positive duration, then there is at least one subinterval where P holds. The fourth step uses the global length constraint and the Sum law to combine the first and second subinterval. The final step use that the assumption is violated on the first subintervals. The proof is completed using that false is a zero for chop. A critical duration constraint ensures that for a critical state P the proportional upper bound is c/t in the limit. R R (( P > c) ∧ ` ≤ t ) −→ d¬P e ⇒ 2 ( P ≤ (c/t ) · ` + c) R The mean value of the critical duration ( P /`) thus tends to c/t . A critical duration constraint is like an optimality constraint in dynamical systems; in a design it is refined to more concrete constraints with instability of the critical state and stability of its complement.
3
Design
Requirements are in the ProCoS approach the starting point for the design. However, another constraint on the design is a desire for a systematic decomposition of the embedded computer system. A standard paradigm is given in Figure 3
72
'
$
A.P. Ravn and H. Rischel
Environment
&
Sensors
* HHj Plant
Controller
YHH Actuators
Fig. 3. Structure of an Embedded System
%
with sensors, actuators and the controller with its program. In the following we assume that components communicate by observing each others states. We discuss the interface provided by sensor and actuator components; but we will not cover paradigms for intelligent sensors and actuators that integrate knowledge of the plant model. Examples that illustrate such aspects are found in the design for the Steam Boiler case study [12]. 3.1
Sensors
A sensor is characterized by its ability to detect that the plant is in some specific state, and it communicates this fact to the control program. We shall start with a description of a general sensor that transmits a value from the plant state to the controller state. The value of the plant state X is determined by a given formula D(x ) parameterized by a rigid variable x . The controller state ranges over a phase π where the sensor is enabled, and phases πx which are entered when D(x ) is observed during the π phase. Progress: When D(x ) holds for δ in phase π, the phase is left for the continuation phase πx : ∀x • (D(x ) ∧ dπeδ ) −→ dπx )e Selection: When D (x ) is stable, phase π moves only to πx . d¬πe; (dπe ∧ D (x )) −→ dπ ∨ πx e The selection constraint is essential for the further use of the value of x in the continuation phase. Without this constraint a sensor might just move rapidly from π with an arbitrary value.
Real-Time Constraints Through the ProCoS Layers
73
A common case is a guard sensor that distinguishes between a finite set of mutually exclusive plant modes P1 , . . . , Pn and ensures transition to corresponding continuation phases π1 , . . . , πn . If the set of modes do not cover the plant state, it is convenient to specify that the sensor will remain enabled until one of the modes occur. The commitments of a guard sensor in phase π are: Progress: When Pi holds for δ in phase π, the phase is left. Vn δ i=1 dPi ∧ πe −→ d¬πe Selection: The phase π will under Pi move to πi only. Vn i=1 d¬πe; dπ ∧ Pi e −→ dπ ∨ πi e Vn Stability: The default mode P 0 = i=1 ¬Pi freezes the π phase. d¬πe; dπ ∧ P 0 e −→ dπe In general, consistency is not preserved if sensor commitments on the same phase π are combined, because one sensor may want to be stable while another may decide to progress. One shall therefore avoid introducing more than one sensor in an elementary phase. If more are needed, decomposition of the phase is generally required. 3.2
Actuators
An actuator is characterized by its ability to move the plant to a state determined by the controller. It is thus the dual of a sensor. We shall start with a description of a general actuator that transmits a value from the controller state to the plant state: Consider controller phases πx and a state assertion P (x ) over the plant state which both are dependent on a rigid variable x . An P (x ) actuator with reaction time δ and enabled in phases πx is given by: Progress: When the phase πx has held for δ, the plant state P (x ) is established. ∀x • dπx eδ −→ dP (x )e Framing: If the πx phase is reentered and P (x ) still holds, it continues to hold. ∀x • d¬πx e; dπx ∧ P (x )e −→ dP (x )e The framing property specifies that the actuator avoids unnecessary transients in the plant state. It will ultimately reduce to an assumption about time bounded stability of a plant state. The unbounded framing can be refined to bounded framing (a bounded invariance) (d¬πx e; dπx ∧P (x )e∧` ≤ δ) −→ dP (x )e and synchronization dπx eδ −→ dP (x )e. Actuator commitments over the same phase combine when they control disjoint plant states.
74
A.P. Ravn and H. Rischel
3.3
Control Program
The design for the controller program is essentially a specification of a timed automaton, The program design is given in terms of the so called “implementables” which are formulas that reflect properties of timed automata. When π, π1 , . . . denote states or phases of a control program, and ϕ, ϕ1 , . . . denote combinations of sensor/actuator states or phase states, the implementable forms are: Sequencing: dπe −→ dπ ∨ π1 ∨ · · · ∨ πn e, where n = 0 means that the program is stuck in phase π, while n > 1 means that there is a choice of a successor phase. Sequencing constraints specify non-deterministic transitions of an untimed automaton. Progress: dπ ∧ϕec −→ d¬πe, where the phase π is left at the latest when ϕ holds for c time units. A progress constraint specifies an upper bound on a transition. Note that c is an upper bound, the transition may be taken earlier, if selection allows it. Progress also includes active stability of a state: dπ ∧ ϕec −→ dπe. Selection: (d¬πe; dπ ∧ ϕe ∧ ` ≤ c) −→ dπ ∨ π1 ∨ ... ∨ πn e, where the sequencing of state π is constrained under the condition ϕ for c time units (or forever, if the time-bound is omitted). If n = 0 the formula defines conditional, time-bounded invariance of the state. Note that c is a lower bound, an implementation may keep the selection open for a longer time, but not for a shorter. Synchronization: dπ1 ∨ ... ∨ πn ec −→ dϕe, where the combined state π1 ∨ ... ∨ πn will cause ϕ to hold after c time units. Note that c is an upper bound, an implementation is allowed to cause ϕ sooner but not later. Framing: (d¬πe; dπ∧ϕe∧` ≤ c) −→ dϕe, is dual to selection. It is a commitment that the state ϕ will remain stable for c time units if it is present when π is entered. These forms define a timed automaton which observes (reads) plant states or states of other automata through the ϕ conditions in progress and selection forms, and which changes control and plant states through synchronization and framing. If controlled states are kept disjoint then conjunction of implementables corresponds to parallel composition of automata. 3.4
Controller Design
In ProCoS, refinement by phase splitting is pursued. We shall illustrate it by a cyclic controller. For a finite collection of exclusive modes P1 , . . . , Pn , a detection phase π and continuation phases π1 , . . . , πn , a cyclic controller with a δ delay is specified by
Real-Time Constraints Through the ProCoS Layers
75
1. Sequencing: The selection phase π is followed by the continuation phases. dπe −→ dπ ∨
Wn
j =1
πj e
2. Sequencing: The continuation phases return to the selection phase. Vn
j =1 dπj e
−→ dπj ∨ πe
3. Progress: When Pi holds for δ in the selection phase, it is left. Vn
i=1 dπ
∧ Pi eδ −→ d¬πe
4. Progress: When Pi holds for δ in πj , with j 6= i, it is left. Vn
i,j =1 (i
6= j ) ⇒ (dπj ∧ Pi eδ −→ d¬πj e)
5. Selection: The phase πi is selected under Pi . Vn
i=1 (d¬πe;
dπ ∧ Pi e ∧ ` ≤ δ) −→ dπ ∨ πi e
6. Selection: The phase πi will be δ-stable under Pi . Vn
i=1 (d¬πi e;
dπi ∧ Pi e ∧ ` ≤ δ) −→ dπi e
7. Progress: The phase πi is maintained by Pi . Vn
i=1 dπi
∧ Pi eδ −→ dπi e
A cyclic controller implements the progress constraint d(π ∨
Wn
j =1
πj ) ∧ Pi e3·δ −→ dπi e
for an arbitrary index i. Within three delay periods control will be in the phase corresponding to a stable external state. The worst case occurs when the selection phase is left after almost a δ-period for another continuation phase (1,3). Within δ, control returns to the selection phase (2,4). The final δ-period ensures transition to the correct phase (1,5,3), where it remains (6,7). This controller can be extended with suitable actuators enabled in the continuation phases such that the Transitive law ensures a correct implementation of progress commitments. In the ProCoS case studies, designs were made more complex by a distributed framework with CSP-like channels. It required a major effort by Schenke [13] to develop systematic transformation rules from the level of implementables to this framework.
76
4
A.P. Ravn and H. Rischel
Implementation
At the level of programs, the timing constraints on the control program states are translated into explicit timing constructs in the programming language PL. A lower bound is translated into an delay statement of the form DELAY r , where r is a non-negative real constant. It is easily implemented by a conventional timer in the hardware, and acts functionally as a skip-statement. An upper bound on a program segment P is specified by prefixing P with UPPERBOUND r , where r is a non-negative real constant. This is taken to be an assertion to be checked by the compiler. It must check that the code generated for P does not use more than r time units to execute. Time which is spent in an idle state during a delay is not included. It cannot in any feasible way be checked by compilation. A check that upper bounds are satisfied by the binary code is not trivial. It requires quite an effort to prove correct compilation, but this story is better told in [8].
5
Conclusion
We have traced real-time properties from constraints on plant states through specifications for sensors, actuators and control programs to simple delay statements and upper bounds on the execution of code segments. The properties have been formulated using a few stereotypical forms. In requirements we have used bounded progress and bounded critical duration and occasionally bounded invariance which all can be expressed within the standard form for duration calculus formulas. We have outlined, how specialized forms of bounded progress and bounded invariance are used to specify constraints on timed automata that define sensor, actuator and control program properties. In the exposition we have followed the ProCoS development process and its refinement view. We still consider the standard forms for requirements generally useful. This has been borne out by a considerable number of case studies, and is supported by the analogy to similar properties of dynamical systems. We have sometimes been asked: “why exactly these formulas?” And the honest answer is that these are the forms which we can systematically decompose and check. This is, however, not different from the situation with dynamical systems in general. It is often more efficient to model the problem reasonably well in a known framework instead of having an extremely precise model within an unexplored mathematical universe. With respect to the design activity we are less certain that direct refinement from requirements is an effective approach. In some of the case studies there has been an amount of re-engineering taking place. The design, in the form of state machines, has been rather obvious, and the refinement has really been a way of presenting a verification. Perhaps it is more fruitful to start from the middle with a design and then check requirements, possibly even using model checking tools. Another promising approach is to work within a cyclic controller framework.
Real-Time Constraints Through the ProCoS Layers
77
This approach is well illustrated by the work by Dierks on PLC-automata [2]. An extension to such a framework could integrate model checking with proof strategies for standard forms in a development tool. A remaining concern is the link to the code and to a run time system. Verified compilers and compilers that check scheduling information are not common; programming language technology has been geared more towards the large market for general programming than the niche of embedded systems. Perhaps the problem will be solved by integrated development environments that translate directly from state machines to binary code, avoiding all the complications of general purpose programming languages. ProCoS is now in the past, but it has left the challenge to develop an engineering practise for embedded systems; a practise that is based on mathematically sound techniques and linking top level requirements to the computer system at the bottom. This was the vision of the ProCoS ‘fathers: Dines Bjørner, Tony Hoare and Hans Langmaack. Acknowledgment. We thank Tony Hoare and Ernst-R¨udiger Olderog for instructive comments on previous drafts of this paper.
References 1. M. S. Branicky. Analyzing and synthesizing hybrid control systems. In G. Rozenberg and F. W. Vaandrager, editors, Embedded Systems, volume 1494 of LNCS, pages 74–113. Springer-Verlag, 1998. 2. H. Dierks. PLC-Automata: A New Class of Implementable Real-Time Automata. In M. Bertran and T. Rus, editors, Transformation-Based Reactive Systems Development (ARTS’97), volume 1231 of LNCS, pages 111–125. Springer-Verlag, 1997. 3. M. R. Hansen and Zhou Chaochen. Duration calculus: Logical foundations. Formal Aspects of Computing, 9(3):283–33, 1997. 4. T. A. Henzinger, Z. Manna, and A. Pnueli. Timed transition systems. In J. W. de Bakker, C. Huizing, W.-P. de Roever, and G. Rozenberg, editors, Real-Time: Theory in Practice, REX Workshop, volume 600 of LNCS, pages 226–252. SpringerVerlag, 1992. 5. H. Langmaack. The ProCoS approach to correct systems. Real-Time Systems, 13:253–275, 1997. 6. H. Langmaack and A. P. Ravn. The ProCoS project: Provably correct systems. In J. Bowen, editor, Towards Verified Systems, volume 2 of Real-Time Safety Critical Systems, chapter Appendix B. Elsevier, 1994. 7. Z. Liu. Specification and verification in dc. In Mathai Joseph, editor, Mathematics of Dependable Systems, Intnl. Series in Computer Science, chapter 7, pages 182– 228. Prentice Hall, 1996. 8. M. M¨ uller-Olm. Modular Compiler Verification, volume 1283 of LNCS. SpringerVerlag, 1997. 9. E-R. Olderog, A. P. Ravn, and J. U. Skakkebæk. Refining system requirements to program specifications. In C. Heitmeyer and D. Mandrioli, editors, Formal Methods in Real-Time Systems, Trends in Software-Engineering, chapter 5, pages 107–134. Wiley, 1996.
78
A.P. Ravn and H. Rischel
10. A. P. Ravn, T. J. Eriksen, M. Holdgaard, and H. Rischel. Engineering of realtime systems with an experiment in hybrid control. In G. Rozenberg and F. W. Vaandrager, editors, Embedded Systems, volume 1494 of LNCS, pages 316–352. Springer-Verlag, 1998. 11. A.P. Ravn, H. Rischel, and K. M. Hansen. Specifying and verifying requirements of real-time systems. IEEE Trans. Softw. Eng., 19(1):41–55, 1993. 12. H. Rischel, J. Cuellar, S. Mørk, A. P. Ravn, and I. Wildgruber. Development of safety-critical real-time systems. In M. Bartoˇsek, J. Staudek, and J. Wiedermann, editors, SOFSEM’95: Theory and Practice of Informatics, volume 1012 of LNCS, pages 206–235. Springer-Verlag, 1995. 13. M. Schenke and A. P. Ravn. Refinement from a control problem to programs. In J. R. Abrial, E. B¨ orger, and H. Langmaack, editors, Formal Methods for Industrial Applications: Specifying and Programming the Steam Boiler Control, volume 1165 of LNCS, pages 403–427. Springer-Verlag, 1996. 14. Chaochen Zhou, C. A. R. Hoare, and A. P. Ravn. A calculus of durations. Information Proc. Letters, 40(5), Dec. 1991.
Monotonicity in Calculational Proofs David Gries Computer Science, Cornell University, [email protected] Computer Science, University of Georgia, [email protected]
Abstract. We discuss the use of weakening and strengthening steps in calculational proofs. We present a metatheorem concerning monotonicity of positions in a formula that should have a more prominent place in the teaching of such proofs and give supporting examples.
Introduction We are dealing with a calculational predicate logic with equality, using the notation of [3]. The universal quantification (∀x R : P ) is equivalent to the more standard ∀x.R ⇒ P and the existential quantification (∃x R : P ) is equivalent to ∃x.R ∧ P . R is called the range of the quantification. Using this notation allows us to have a unified notation for expressing all sorts of quantifications, including summations and products. A few more notational conventions: The operator ≡ denotes equality on booleans; it is more traditionally represented by symbol ⇔ . And f.x denotes the application of function f to argument x . Now for the reason for this little paper. In making a calculational step like ⇒
(∀x : P ∧ R) hWeakening P ⇒ P ∨ Q i (∀x : (P ∨ Q) ∧ R)
we are implicitly using the fact that the occurrence of variable P that is being replaced is in a monotonic position —weakening that position weakens the whole formula. To make the proof more precise and complete, the fact should be made explicit. We use a long-known but basically forgotten theorem for this purpose and show how it is used in several calculational proofs.
Monotonicity A function f is monotonic in its argument if x ⇒ y implies f.x ⇒ f.y (for all x, y ). It is antimonotonic if x ⇒ y implies f.x ⇐ f.y (for all x, y ). The following facts are well-known: ∨ and ∧ are monotonic in each of their operands, negation is antimonotonic in its operand, ⇒ is monotonic in its consequent and antimonotonic in its antecedent, (∀x R : P ) is monotonic in E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 79–85, 1999. c Springer-Verlag Berlin Heidelberg 1999
80
D. Gries
P but antimonotonic in R , and (∃x R : P ) is monotonic in both P and R . Formally, we have: Monotonic ∨: (P ⇒ Q) ⇒ (P ∨ R ⇒ Q ∨ R)
(1)
Monotonic ∧: (P ⇒ Q) ⇒ (P ∧ R ⇒ Q ∧ R) Antimonotonic ¬: (P ⇒ Q) ⇒ (¬P ⇐ ¬Q)
(2)
Monotonic consequent: (P ⇒ Q) ⇒ ((R ⇒ P ) ⇒ (R ⇒ Q)) Antimonotonic antecedent: (P ⇒ Q) ⇒ ((P ⇒ R) ⇐ (Q ⇒ R)) Antimonotonic ∀-range: (P ⇒ Q) ⇒ ((∀x P : R) ⇐ (∀x Q : R)) Monotonic ∀-body: (P ⇒ Q) ⇒ ((∀x R : P ) ⇒ (∀x R : Q)) Monotonic ∃-range: (P ⇒ Q) ⇒ ((∃x P : R) ⇒ (∃x Q : R)) Monotonic ∃-body: (P ⇒ Q) ⇒ ((∃x R : P ) ⇒ (∃x R : Q))
(3)
But which of the following two formulas is valid, if either? (∀x ¬P : S) ⇒ (∀x ¬(P ∨ Q) : S) (∀x ¬P : S) ⇐ (∀x ¬(P ∨ Q) : S) The answer is given by the following definition and theorem. Throughout, EPz denotes non-capture-avoiding substitution of free variable z by P in formula E . Also, E[z := P ] denotes capture-avoiding substitution: E[z := P ] is a copy of expression E in which all occurrences of variable z have been replaced by expression P , with names of dummies (bound variables) being first replaced to avoid capture. Definition 1. Consider an occurrence of free variable z in a formula E (but not within an operand of ≡ ). The position of z within E is called monotonic if it is nested within an even number of negations, antecedents, and ranges of universal quantifications; otherwise, it is antimonotonic. Theorem 2. Metatheorem Monotonicity. Suppose P ⇒ Q is a theorem. Let expression E contain exactly one occurrence of free variable z . Then: (a) Provided the position of z in E is monotonic, z EPz ⇒ EQ is a theorem. (b) Provided the position of z in E is antimonotonic, z is a theorem. EPz ⇐ EQ [Note: Actually, E can contain more than one occurrence of z , as long as all its positions are monotonic or all its positions are antimonotonic.] We can state (a) and (b) as inference rules: Monotonicity: Provided z’s position in E is monotonic, z P ⇒ Q −→ EPz ⇒ EQ
(4)
Antimonotonicity: Provided z’s position in E is antimonotonic, z P ⇒ Q −→ EPz ⇐ EQ
(5)
Monotonicity in Calculational Proofs
81
Sketch of proof of (2). The proof is by induction on the structure of expression E . One can reduce the case analysis by first manipulating E so that one has to deal only with formulas that contain variables, constants, negations, disjunctions in which z is not in the second operand, and existential quantifications with range true . Thus, perform the following steps, in order: – – – – – – – –
Replace (∀x F 1 : F 2) by ¬(∃x F 1 : ¬F 2) . Replace (∃x F 1 : F 2) by (∃x : F 1 ∧ F 2) . Replace F 1 6⇐ F 2 by ¬(F 1 ⇐ F 2) . Replace F 1 ⇐ F 2 by F 2 ⇒ F 1 . Replace F 1 6⇒ F 2 by ¬(F 1 ⇒ F 2) . Replace F 1 ⇒ F 2 by ¬F 1 ∨ F 2 . Replace F 1 ∧ F 2 by ¬(¬F 1 ∨ ¬F 2) . If z is in the second operand F 2 of F 1 ∨ F 2 , replace F 1 ∨ F 2 by F 2 ∨ F 1 .
These manipulations change neither the monotonicity of the position of z nor the truth value of the formula. Now, comes a straightforward proof by induction on the structure of the more restricted expressions E , which will rely on monotonic/antimonotonic properties (1), (2), and (3). Incidently, when teaching calculational logic and induction, this inductive proof is a nice exercise for students.
A Convention for Citing Monotonicity In a weakening/strengthening step of a calculation, the hint should explain why the step is sound. Here is a simple example, where it is presumed that Weakening was proved earlier. ⇒
P
hWeakening, P ⇒ P ∨ Q i P ∨Q
But in the following example, the hint is not precise. This is because the soundness of the step depends not only on Weakening but also on Monotonic ∧ . ⇒
P ∧R hWeakening, P ⇒ P ∨ Q i (P ∨ Q) ∧ R
We seek a uniform way of substantiating steps like the above one. Rather than rely directly on all the individual monotonicity properties (1)–(3), it is easier to rely on inference rules (4) and (5), which can be used to substantiate all such weakening/strengthening steps. We suggest the use of “Monotonicity:” and “Antimonotonicity:” to show reliance on these inference rules, as shown below. The word “Monotonic” suggests that a monotonic position is being replaced; “Antimonotonic” suggests that an antimonotonic position is being replaced. In the examples given below, to the right we have shown how the formulas can be rewritten in terms of variable z , so that the use of the inference rules is more easily seen.
82
D. Gries
⇒
(∀x : P ∧ R) hMonotonicity: Weakening P ⇒ P ∨ Q i (∀x : (P ∨ Q) ∧ R)
(∀x : z ∧ R)zP (∀x : z ∧ R)zP ∨ Q
¬(∀x ¬P ∧ R : S) ¬(∀x ¬z ∧ R : S)zP ⇐ hAntimonotonicity: Weakening P ⇒ P ∨ Q i ¬(∀x ¬(P ∨ Q) ∧ R : S) ¬(∀x ¬z ∧ R : S)zP ∨ Q
Examples of the Use of Monotonicity When dealing with theorems of propositional logic, monotonicity is not needed at all; as [3] shows, all proofs can be done easily without weakening/strengthening steps. However, for predicate logic proofs, weakening/strengthening steps are very useful, as the following examples show. These calculational proofs, using monotonicity/antimonotonicity, are surprisingly simple, especially compared to similar proofs in other proof systems. Each step of the proof is guided by the shapes of the current formula and goal. The theorems used in these proofs are from [3]. Proving Instantiation In [3], the One-point rule is an axiom and Instantiation is a theorem: One-point rule: Provided x does not occur free in E, (∀x x = E : P ) ≡ P [x := E]
(6)
Instantiation: (∀x : P ) ⇒ P [x := E] We prove Instantiation. Let z be a variable that does not occur free in P or E . We have: (∀x true : P ) hDummy renaming — z not free in P i (∀z true : P [x := z]) ⇒ hAntimonotonicity: true ⇐ z = E i (∀z z = E : P [x := z]) = hOne-point rulei P [x := z][z := E] = hProperty of textual substitution — z is not free in P i P [x := E] =
Mortality of Socrates This example concerns proving English arguments sound by formalizing them and proving their formalizations. Consider the following statement. All men are mortal. Socrates is a man. Therefore, Socrates is mortal.
Monotonicity in Calculational Proofs
83
We introduce two predicates. man.m : person m is a man. mortal .m : person m is mortal. We formalize the statement as follows, with S standing for Socrates, and prove the formalization. The proof relies on inference rule Modus ponens, Q ⇒ P, Q −→ P . (∀m : man.m ⇒ mortal .m) ∧ man.S ⇒ mortal.S (∀m : man.m ⇒ mortal .m) ∧ man.S hMonotonicity: Instantiation, with S for m i (man.S ⇒ mortal .S) ∧ man.S ⇒ hModus ponensi mortal .S ⇒
Here is a second proof, which transforms the whole formula into a known theorem. ⇐
(∀m : man.m ⇒ mortal .m) ∧ man.S ⇒ mortal .S hAntimonotonicity: Instantiation, with S for m i (man.S ⇒ mortal .S) ∧ man.S ⇒ mortal .S —Modus ponens
Having a Heart Now consider the English statement: None but those with hearts can love. Some liars are heartless. Therefore, some liars cannot love. Using hh.p for “ p has a heart”, cl.p for “ p can love”, and li.p for “ p is a liar”, we formalize this as (∀p : cl.p ⇒ hh.p) ∧ (∃p : li.p ∧ ¬hh.p) ⇒ (∃p : li.p ∧ ¬cl.p) . We prove this formula. (∀p : cl.p ⇒ hh.p) ∧ (∃p : li.p ∧ ¬hh.p) hDistributivity of ∧ over ∃ —to get same outer quantification as in consequenti (∃p : (∀p : cl.p ⇒ hh.p) ∧ li.p ∧ ¬hh.p) ⇒ hMonotonicity: Instantiationi (∃p : (cl.p ⇒ hh.p) ∧ li.p ∧ ¬hh.p) = hContrapositivei (∃p : (¬hh.p ⇒ ¬cl.p) ∧ li.p ∧ ¬hh.p) ⇒ hMonotonicity: Modus ponens)i (∃p : ¬cl.p ∧ li.p)
=
84
D. Gries
EA Implies AE In [4], Carroll Morgan derives a nice proof of (∃x : (∀y : P )) ⇒ (∀y : (∃x : P )) .
(7)
Wim Feijen [2] presents convincing heuristics for the development of the proof. Here is the proof. Note that it uses Metatheorem Monotonicity, twice, although neither Morgan nor Feijen cite it. (∃x : (∀y : P )) hMonotonicity: R ⇒ (∀y : R) , prov. y doesn’t occur free in R —introduce the necessary universal quantification over y i (∀y : (∃x : (∀y : P ))) ⇒ hMonotonicity: Instantiation —Eliminate universal quantificationi (∀y : (∃x : P )) ⇒
When we generalize (7) to allow ranges other than true , the proof becomes more complicated. Below, we prove: Provided x not free in Q and y not free in R, (∃x R : (∀y Q : P )) ⇒ (∀y Q : (∃x R : P ))
(8)
Since x does not occur free in the consequent, by Metatheorem Witness (9.30) of [3], (8) can be proved by proving instead R ∧ (∀y
Q : P ) ⇒ (∀y
Q : (∃x R : P )) ,
which we now do: R ∧ (∀y Q : P ) h ∧ over ∀ , since y not free in R i (∀y Q : R ∧ P ) ⇒ hMonotonicity: ∃ -Introductioni (∀y Q : (∃x : R ∧ P )) = hTradingi (∀y Q : (∃x R : P )) ⇒
Discussion Monotonicity properties (1)–(3), as well as Metatheorem Monotonicity, are wellknown. They can be found, in one guise or another, in several texts on logic. But the two major books that deal with the calculational approach do a bad job of explaining how monotonicity/antimonotonicity is to be used. On page 61 of [1], Dijkstra and Scholten discuss the monotonic properties of negation and implication. But they don’t state the general theorem (2) and they don’t give a convention for indicating its use. On page 93 of [1], a hint explicitly states the use of monotonicity of ∧ and ∃ in a weakening step, but on pages 73 and
Monotonicity in Calculational Proofs
85
77, monotonicity of ∀ -body is used without mention. We think the authors just didn’t anticipate the frequent use of monotonicity and the problem readers would have with it if it were not well explained. Gries and Schneider [3] also don’t treat montonicity well, and this has resulted in confusion among students about monotonicity and its use. The next edition of [3] is expected to use the approach of this note in order to eliminate the confusion. The message of this little article is meant to be the apparent simplicity and brevity of many proofs in the calculational system when the right tools, like metatheorem Monotonicity, are available.
Acknowledgements Thanks to an anonymous referee, who helped improve this presentation.
References 1. Edsger W. Dijkstra and Carel S. Scholten. Predicate Calculus and Program Semantics. Springer Verlag, New York, 1990. 2. Wim H.J. Feijen. ∃∀ ⇒ ∀∃ . WHJ189, September 1994. 3. David Gries and Fred B. Schneider. A Logical Approach to Discrete Math. Springer Verlag, New York 1993. 4. Carroll Morgan. Email communications in September 1995.
The Alma Project, or How First-Order Logic Can Help Us in Imperative Programming Krzysztof R. Apt1,2 and Andrea Schaerf3 1
2
CWI P.O. Box 94079, 1090 GB Amsterdam, The Netherlands [email protected] Dept. of Mathematics, Computer Science, Physics & Astronomy University of Amsterdam, The Netherlands 3 Dipartimento di Ingegneria Elettrica, Gestionale e Meccanica Universit` a di Udine via delle Scienze 208, I-33100 Udine, Italy [email protected]
Abstract. The aim of the Alma project is the design of a strongly typed constraint programming language that combines the advantages of logic and imperative programming. The first stage of the project was the design and implementation of Alma0, a small programming language that provides a support for declarative programming within the imperative programming framework. It is obtained by extending a subset of Modula-2 by a small number of features inspired by the logic programming paradigm. In this paper we discuss the rationale for the design of Alma-0, the benefits of the resulting hybrid programming framework, and the current work on adding constraint processing capabilities to the language. In particular, we discuss the role of the logical and customary variables, the interaction between the constraint store and the program, and the need for lists.
1 1.1
Introduction Background on Designing Programming Languages
The design of programming languages is one of the most hotly debated topics in computer science. Such debates are often pretty chaotic because of the lack of universally approved criteria for evaluating programming languages. In fact, the success or failure of a language proposal often does not say much about the language itself but rather about such accompanying factors as: the quality and portability of the implementation, the possibility of linking the language with the currently reigning programming language standard (for instance, C), the existing support within the industry, presence of an attractive development environment, the availability on the most popular platforms, etc. The presence of these factors often blurs the situation because in evaluating a language proposal one often employs, usually implicitly, an argument that the E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 89–113, 1999. c Springer-Verlag Berlin Heidelberg 1999
90
K.R. Apt and A. Schaerf
“market” will eventually pick up the best product. Such a reasoning would be correct if the market forces in computing were driven by the desire to improve the quality of programming. But from an economic point of view such aspects as compatibility and universal availability are far more important than quality. Having this in mind we would like to put the above factors in a proper perspective and instead concentrate on the criteria that have been used in academia and which appeal directly to one of the primary purposes for which a programming language is created, namely, to support an implementation of the algorithms. In what follows we concentrate on the subject of “general purpose” programming languages, so the ones that are supposed to be used for developing software, and for teaching programming. Ever since Algol-60 it became clear that such programming languages should be “high-level” in that they should have a sufficiently rich repertoire of control structures. Ever since C and Pascal it became clear that such programming languages should also have a sufficiently rich repertoire of data structures. But even these seemingly obvious opinions are not universally accepted as can be witnessed by the continuing debate between the followers of imperative programming and of declarative programming. In fact, in logic programming languages, such as Prolog, a support for just one data type, the lists, is provided and the essence of declarative programming as embodied in logic and functional programming lies in not using assignment. Another two criteria often advanced in the academia are that the programming language should have a “simple” semantics and that the programs should be “easy” to write, read and verify. What is “simple” and what is “easy” is in the eyes of the beholder, but both criteria can be used to compare simplicity of various programming constructs and can be used for example to argue against the goto statement or pointers. In this paper we argue that these last two criteria can be realized by basing a programming language on first-order logic. The point is that first-order logic is a simple and elegant formalism with a clear semantics. From all introduced formalisms (apart from the propositional logic that is too simplistic for programming purposes) it is the one that we understand best, both in terms of its syntax and its semantics. Consequently, its use should facilitate program development, verification and understanding. One could argue that logic programming has realized this approach to computing as it is based on Horn clauses that are special types of first-order formulas. However, in logic programming in its original setting computing (implicitly) takes place over the domain of terms. This domain is not sufficient for programming purposes. Therefore in Prolog, the most widely used logic programming language, programs are augmented with some support for arithmetic. This leads to a framework in which the logical basis is partly lost due to the possibility of errors. For instance, Prolog’s assignment statement X is t yields a run-time error if t is not a ground arithmetic expression. This and other deficiencies of Prolog led to the rise of constraint logic programming languages that overcome some of Prolog’s shortcomings. These pro-
The Alma Project, or How First-Order Logic Can Help Us
91
gramming languages depend in essential way on some features as the presence of constraint solvers (for example a package for linear programming) and constraint propagation. So this extension of logic programming goes beyond firstorder logic. It is also useful to reflect on other limitations of these two formalisms. Both logic programming and constraint logic programming languages rely heavily on recursion and the more elementary and easier to understand concept of iteration is not available as a primitive. Further, types are absent. They can be added to the logic programming paradigm and in fact a number of successful proposals have been made, see, e.g., [15]. But to our knowledge no successful proposal dealing with addition of types to constraint logic programs is available. Another, admittedly debatable, issue is assignment, shunned in logic programming and constraint logic programming because its use destroys the declarative interpretation of a program as a formula. However, we find that assignment is a useful construct. Some uses of it, such as recording the initial value of a variable or counting the number of bounded iterations, can be replaced by conceptually simpler constructs but some other uses of it such as for counting or for recording purposes are much less natural when simulated using logic formulas. 1.2
Design Decisions
These considerations have led us to a design of a programming language Alma-0. The initial work on the design of this language was reported in [3]; the final description of the language, its implementation and semantics is presented in [2]. In a nutshell, Alma-0 has the following characteristics: – it is an extension of a subset of Modula-2 that includes assignment, so it is a strongly typed imperative language; – to record the initial value of a variable the equality can be used; – it supports so-called “don’t know” nondeterminism by providing a possibility of a creation of choice points and automatic backtracking; – it provides two forms of bounded iterations. The last two features allow us to dispense with many uses of recursion that are in our opinion difficult to understand and to reason about. As we shall see, the resulting language proposal makes programming in an imperative style easier and it facilitates (possibly automated) program verification. Additionally, for several algorithmic problems the solutions offered by Alma-0 is substantially simpler than the one offered by the logic programming paradigm. The following simple example can help to understand what we mean by saying that Alma-0 is based on first-order logic and that some Alma-0 programs are simpler than their imperative and logic programming counterparts. Consider the procedure that tests whether an array a[1..n] is ordered. The customary way to write it in Modula-2 is:
92
K.R. Apt and A. Schaerf
i:= 1; ordered := TRUE; WHILE i < n AND ordered DO ordered := ordered AND (a[i] <= a[i+1]); i := i+1 END;
In Alma-0 we can just write: ordered := FOR i:= 1 TO n-1 DO a[i] <= a[i+1] END
This is much simpler and as efficient. In fact, this use of the FOR statement corresponds to the bounded universal quantification and the above one line program equals the problem specification. In the logic programming framework there are no arrays. But the related problem of finding whether a list L is ordered is solved by the following program which is certainly more involved than the above one line of Alma-0 code: ordered([]). ordered([X]). ordered([X, Y | Xs]) :- X =< Y, ordered([Y| Xs]).
1.3
Towards an Imperative Constraint Programming Language
In Alma-0 each variable is originally uninitialized and needs to be initialized before being used. Otherwise a run-time error arises. The use of uninitialized variables makes it possible to use a single program for a number of purposes, such as computing a solution, completing a partial solution, and testing a candidate solution. On the other hand, it also provides a limitation on the resulting programming style as several first-order formulas, when translated to Alma-0 syntax, yield programs that terminate in a run-time error. With the addition of constraints this complication would be overcome. The idea is that the constraints encountered during the program execution are moved to the constraint store and evaluated later, when more information is available. Then the above restriction that each variable has to be initialized before being used can be lifted, at least for the variables that are manipulated by means of constraints. Additionally, more programs can be written in a declarative way. In fact, as we shall see, an addition of constraints to Alma-0 leads to a very natural style of programming in which the constraint generation part of the program is often almost identical to the problem specification. Constraint programming in a nutshell consists of generating constraints (requirements) and solving them by general and domain specific methods. This approach to programming was successfully realized in a number of programming languages, notably constraint logic programming languages. Up to now, the most successful approach to imperative constraint programming is the object-oriented approach taken by ILOG Solver (see [16], [9]). In this system constraints and variables are treated as objects and are defined within
The Alma Project, or How First-Order Logic Can Help Us
93
a C++ class library. Thanks to the class encapsulation mechanism and the operator overloading capability of C++, the user can see constraints almost as if they were a part of the language. A similar approach was independently taken in the NeMo+ programming environment of [18]. In our approach constraints are integrated into the imperative programming paradigm, as “first class citizens” of the language. The interaction between the constraint store and the program becomes then more transparent and conceptually simpler and the resulting constraint programs are in our opinion more natural than their counterparts written in the constraint logic programming style or in the imperative languages augmented with constraint libraries. The reason for this in the case of constraint logic programming is that many uses of recursion and lists can be replaced by the more basic concepts of bounded iteration and arrays. In the case of the imperative languages with constraint libraries, due to the absence of non-determinism in the language, failure situations (arising due to inconsistent constraints) must be dealt with explicitly by the programmer, whereas in Alma-0 they are managed implicitly by the backtracking mechanism. When adding constraints to a strongly typed imperative programming language one needs to resolve a number of issues. First, constraints employ variables in the mathematical sense of the word (so unknowns) while the imperative programming paradigm is based on the computer science concept of a variable, so a known, but varying entity. We wish to separate between these two uses of variables because we want to manipulate unknowns only by means of constraints imposed on them. This precludes the modelling of unknowns by means of uninitialized variables since the latter can be modified by means of an assignment. Second, one needs to integrate the constraints in such a way that various features of the underlying language such as use of local and global declarations and of various parameter passing mechanisms retain their coherence. Additionally, one has to maintain the strong typing discipline according to which each variable has a type associated with it in such a way that throughout the program execution only values from its type can be assigned to the variable. Finally, one needs to provide an adequate support for search, one of the main aspects of constraint programming. So the situation is quite different than in the case of the logic programming framework. Namely, the logic programming paradigm is based on the notion of a variable in the mathematical sense (usually called in this context a logical variable). This greatly facilitates the addition of constraints and partly explains why the integration of constraints into logic programming such as in the case of CHIP (see [19]), Prolog III (see [4]) and CLP(R) (see [11]), to name just three examples, has been so smooth and elegant. Further, logic programming languages provide support for automatic backtracking. However, as already mentioned, in constraint logic programming languages types are not available. Moreover, there is a very limited support for scoping and only one parameter mechanism is available.
94
K.R. Apt and A. Schaerf
Let us return now to Alma-0. The language already provides a support for search by means of automatic backtracking. This support is further enhanced in our proposal by providing a built-in constraint propagation. In [2] we stated that our language proposal should be viewed as “an instance of a generic method for extending (essentially) any imperative programming language with facilities that encourage declarative programming.” That is why we think that the proposal here discussed should be viewed not only as a suggestion how to integrate constraints into Alma-0, but more generally how to integrate constraints into any strongly typed imperative language. In fact, Alma-0 can be viewed as an intermediate stage in such an integration. The remainder of the paper is organized as follows. In Section 2 we summarize the new features of Alma-0 and in Section 3 we illustrate the resulting programming style by two examples. Then, in Section 4 we discuss the basics of our proposal for adding constraints to Alma-0 and in Section 5 we explain how constraints interact with procedures. In turn in Section 6 we discuss language extensions for expressing complex constraints and for facilitating search in presence of constraints. Finally, in Section 7 we discuss related work and in Section 8 we draw some conclusions and discuss the future work.
2
A Short Overview of Alma-0
Alma-0 is an extension of a subset of Modula-2 by nine new features inspired by the logic programming paradigm. We briefly recall most of them here and refer to [2] for a detailed presentation. – Boolean expressions can be used as statements and vice versa. This feature of Alma-0 is illustrated by the above one line program of Subsection 1.2. A boolean expression that is used as a statement and evaluates to FALSE is identified with a failure. – Choice points can be created by the non-deterministic statements ORELSE and SOME. The former is a dual of the statement composition and the latter is a dual of the FOR statement. Upon failure the control returns to the most recent choice point, possibly within a procedure body, and the computation resumes with the next branch in the state in which the previous branch was entered. – The created choice points can be erased or iterated over by means of the COMMIT and FORALL statements. COMMIT S END removes the choice points created during the first successful execution of S. FORALL S DO T END iterates over all choice points created by S. Each time S succeeds, T is executed. – The notion of initialized variable is introduced: A variable is uninitialized until the first time a value is assigned to it; from that point on, it is initialized. The KNOWN relation tests whether a variable of a simple type is initialized. – The equality test is generalized to an assignment statement in case one side is an uninitialized variable and the other side an expression with known value.
The Alma Project, or How First-Order Logic Can Help Us
95
– In Alma-0 three types of parameter mechanisms are allowed: call by value, call by variable and call by mixed form. The first two are those of Pascal and Modula-2; the third one is an amalgamation of the first two (see [2]). Parameters passed by mixed form can be used both for testing and for computing. Let us summarize these features of Alma-0 by clarifying which of them are based on first-order logic. In the logical reading of the programming language constructs the program composition S; T is viewed as the conjunction S ∧ T. A dual of “;”, the EITHER S ORELSE T END statement, corresponds then to the disjunction S ∨ T. Further, the FOR i:= s TO t DO S END statement is viewed as the bounded universal quantification, ∀i ∈ [s..t] S, and its dual, the SOME i:= s TO t DO S END statement is viewed as the bounded existential quantification, ∃i ∈ [s..t] S. In turn, the FORALL S DO T END statement can be viewed as the restricted quantification ∀¯ x(S → T), where ¯ x are all the variables of S. Because the boolean expressions are identified with the statements, we can apply the negation connective, NOT, to the statements. Finally, the equality can be interpreted both as a test and as an one-time assignment, depending on whether the variable in question is initialized or not.
3
Programming in Alma-0
To illustrate the above features of Alma-0 and the resulting programming style we now consider two examples. 3.1
The Frequency Assignment Problem
The first problem we discuss is a combinatorial problem from telecommunication. Problem 1. Frequency Assignment ([7]). Given is a set of n cells, C := {c1 , c2 , . . . , cn } and a set of m frequencies (or channels) F := {f1 , f2 , . . . , fm }. An assignment is a function which associates with each cell ci a frequency xi ∈ F . The problem consists in finding an assignment that satisfies the following constraints. Separations: Given h and k we call the value d(fh , fk ) = | h − k | the distance between two channels fh and fk . (The assumption is that consecutive frequencies lie one unit apart.) Given is an n × n non-negative integer symmetric matrix S, called a separation matrix, such that each sij represents the minimum distance between the frequencies assigned to the cells ci and cj . That is, for all i ∈ [1..n] and j ∈ [1..n] it holds that d(xi , xj ) ≥ sij . Illegal channels: Given is an n × m boolean matrix F such that if Fij = true, then the frequency fj cannot be assigned to the cell i, i.e., xi 6= fj .
96
K.R. Apt and A. Schaerf
Separation constraints prevent interference between cells which are located geographically close and which broadcast in each other’s area of service. Illegal channels account for channels reserved for external uses (e.g., for military bases). The Alma-0 solution to this problem does not use an assignment and has a dual interpretation as a formula. We tested this program on various data. We assume here for simplicity that each ci equals i and each fi equals i, so C = {1, . . ., n} and F = {1, . . ., m}. MODULE FrequencyAssignment; CONST N = 30; (* number of cells *) M = 27; (* number of frequencies *) TYPE SeparationMatrix = ARRAY [1..N],[1..N] OF INTEGER; IllegalFrequencies = ARRAY [1..N],[1..M] OF BOOLEAN; Assignment = ARRAY [1..N] OF [1..M]; (* solution vector *) VAR S: SeparationMatrix; F: IllegalFrequencies; A: Assignment; noSol: INTEGER; PROCEDURE AssignFrequencies(S: SeparationMatrix; F: IllegalFrequencies; VAR A: Assignment); VAR i, j, k: INTEGER; BEGIN FOR i := 1 TO N DO SOME j := 1 TO M DO (* j is a candidate frequency for cell i *) NOT F[i,j]; FOR k := 1 TO i-1 DO abs(A[k] - j) >= S[k,i] END; A[i] = j END END END AssignFrequencies; BEGIN InitializeData(S,F); AssignFrequencies(S,F,A); PrintSolution(A) END FrequencyAssignment.
The simple code of the procedures InitializeData and PrintSolution is omitted. The generalized equality A[i] = j serves here as an assignment and the SOME statement takes care of automatic backtracking in the search for the right frequency j. In the second part of the paper we shall discuss an alternative solution to this problem using constraints.
The Alma Project, or How First-Order Logic Can Help Us
3.2
97
Job Shop Scheduling
The second problem we discuss is a classical scheduling problem, namely the job shop scheduling problem. We refer to [5, page 242] for its precise description. Roughly speaking, the problem consists of scheduling over time a set of jobs, each consisting of a set of consecutive tasks, on a set of processors. The input data is represented by an array of jobs, each element of which is a record that stores the number of the tasks and the array of tasks. In turn, each task is represented by the machine it uses and by its length. The output is delivered as an integer matrix that (like a so-called Gantt chart) for each time point k and each processor p stores the job number that p is serving at the time point k. The constraint that each processor can perform only one job at a time is enforced by using generalized equality on the elements of the output matrix. More precisely, whenever job i requires processor j for a given time window [d1 , d2 ], the program attempts for some k to initialize the elements of the matrix (j, k + d1 ), (j, k + d1 + 1), . . . , (j, k + d2 ) to the value i. If this initialization succeeds, the program continues with the next task. Otherwise some element in this segment is already initialized, i.e., in this segment processor j is already used by another job. In this case the execution fails and through backtracking the next value for k is chosen. The constraint that the tasks of the same job must be executed in the provided order and cannot overlap in time is enforced by the use of the variable min start time which, for each job, initially equals 1 and then is set to the end time of the last considered task of the job. To perform this update we exploit the fact that when the SOME statement is exited its index variable k equals the smallest value in the considered range for which the computation does not fail (as explained in [2]). We provide here the procedure that performs the scheduling. For the sake of brevity the rest of the program is omitted. TYPE TaskType
= RECORD machine : INTEGER; length : INTEGER; END; JobType = RECORD tasks : INTEGER; task : ARRAY [1..MAX_TASKS] OF TaskType END; JobVectorType = ARRAY [1..MAX_JOBS] OF JobType; GanttType = ARRAY [1..MAX_MACHINES],[1..MAX_DEADLINE] OF INTEGER;
PROCEDURE JobShopScheduling(VAR job: JobVectorType; deadline:INTEGER; jobs :INTEGER; VAR gantt: GanttType); VAR i, j, k, h : INTEGER; min_start_time : INTEGER;
98
K.R. Apt and A. Schaerf
BEGIN FOR i := 1 TO jobs DO min_start_time := 1; FOR j := 1 TO job[i].tasks DO SOME k := min_start_time TO deadline - job[i].task[j].length + 1 DO (* job i engages the processor needed for task j from time k to k + (length of task j) - 1. If the processor is already engaged, the program backtracks. *) FOR h := k TO k + job[i].task[j].length - 1 DO gantt[job[i].task[j].processor,h] = i; END END; min_start_time := k + job[i].task[j].length; (* set the minimum start time for the next task to the end of the current task *) END; END END JobShopScheduling;
In this program the “don’t know” nondeterminism provided by the use of the SOME statement is combined with the use of assignment. Furthermore, as already mentioned, for each value of i and j the equality gantt[job[i].task[j].processor,h] = i acts both as an assignment and as a test. The array gantt should be uninitialized when the procedure is called. At the end of the execution the variable gantt contains the first feasible schedule it finds. Preinitialized values can be used to enforce some preassignments of jobs to processors, or to impose a constraint that a processor is not available during some periods of time. For example, if processor 2 is not available at time 5, we just use the assignment gantt[2,5] := 0 (where 0 is a dummy value) before invoking the procedure JobShopSchedule. As an example, suppose we have 3 jobs, 3 processors (p1 , p2 , and p3 ), the deadline is 20, and the jobs are composed as follows: task 1 job tasks proc len 1 4 p1 5 2 3 p2 6 3 4 p3 6
task 2 proc len p2 5 p1 6 p2 4
task 3 proc len p3 5 p3 4 p1 4
task 4 proc len p2 3 p2
1
The first solution (out of the existing 48) for the array gantt that the program finds is the following one, where the symbol ’-’ means that the value is uninitialized, i.e., the processor is idle in the corresponding time point. 1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 1 -
2 1 -
2 1 -
2 1 -
2 1 -
2 3 1
3 1
3 1
3 1
3 1
3 1 2
3 1 2
3 1 2
3 2
The Alma Project, or How First-Order Logic Can Help Us
99
For some applications, it is necessary to make the schedule as short as possible. To this aim, we can use the following program fragment. COMMIT SOME deadline := 1 TO max_deadline DO JobShopScheduling(JobVector,deadline,jobs,Gantt) END END
It computes the shortest schedule by guessing, in ascending order, the first deadline that can be met by a feasible assignment. The use of the COMMIT statement ensures that once a solution is found, the alternatives, with larger deadline values, are discarded.
4
Introducing Constraints
In what follows we discuss a proposal for adding constraints to Alma-0. This Section is organized as follows. In Subsection 4.1 we discuss the addition of constrained types and unknowns to the language and in Subsections 4.2 and 4.3 we define the constraint store and illustrate its interaction with the program execution. To illustrate how the proposed addition of constraints to Alma-0 provides a better support for declarative programming we illustrate in Subsection 4.4 their use by means of three example programs. To simplify our considerations we ignore in this section the presence of procedures. In particular, we assume for a while that all declarations are at one level. 4.1
Adding Constrained Types, Unknowns and Constraints
We start by adding a new kind of variables of simple types, called unknowns. This is done by using the qualifier CONSTRAINED in declarations of simple types, that is INTEGER, BOOLEAN, REAL, enumeration and subrange types. Definition 1. – A type qualified with the keyword CONSTRAINED is called a constrained type. – A variable whose type is a constrained type is called an unknown. We shall see in Section 5 that this way of defining unknowns simplifies the treatment of parameter passing in presence of unknowns. From now on we distinguish between variables and unknowns. In the discussion below we assume the following declarations. CONST N = 8; TYPE Board = ARRAY [1..N] OF CONSTRAINED [1..N]; Colour = (blue, green, red, yellow); Info = RECORD
100
K.R. Apt and A. Schaerf
co: Colour; No: CONSTRAINED INTEGER; END; VAR i, j: INTEGER; a: ARRAY [1..N] of INTEGER; C: CONSTRAINED [1..N]; X, Y: Board; Z: Info;
So a, i and j are variables while C is an unknown. In turn, X and Y are arrays of unknowns and Z is a record the first component of which is a variable and the second an unknown. Because of the syntax of Alma-0, boolean expressions can appear both in the position of a statement and inside a condition. Definition 2. A constraint is a boolean expression that involves some unknowns. We postulate that the unknowns can appear only within constraints or within the right hand side of an assignment. The values of unknowns are determined only by means of constraints that are placed on them. In particular, by the just introduced syntactic restriction, one cannot use assignment to assign a value to an unknown. So in presence of the above declarations the statements X[1] := 0 and C := 1 are illegal. In contrast, the constraints X[1] = 0 and C = 1 are legal. Further, the assignments i := X[1] + X[2] and i := Y[X[2]] are also legal statements. Initially each unknown has an undetermined value that belongs to the domain associated with the type. By placing constraints on an unknown its domain can shrink. The unknown continues to have an undetermined value until the domain gets reduced to a singleton. If the program control reaches an occurrence of an unknown outside of a constraint, so within the right hand side of an assignment, this unknown is evaluated. If its value is at this moment undetermined, this evaluation yields a run-time error. If the value is determined (that is, the domain is a singleton), then it is substituted for the occurrence of the unknown. So the occurrences of an unknown outside of a constraint are treated as usual variables. Note that during the program execution the domain of an unknown monotonically decreases with respect to the subset ordering. This is in stark contrast with the case of variables. Initially, the value of a variable of a simple type is not known but after the first assignment to it its value is determined though can non-monotonically change to any other value from its type. Intuitively, a program is viewed as an “engine” that generates constraints. These constraints are gradually solved by means of the constraint solving process that we shall explain now.
The Alma Project, or How First-Order Logic Can Help Us
4.2
101
Adding the Constraint Store
We now introduce the central notion of a constraint store. This is done in a similar way as in the constraint logic programming systems, though we need to take into account here the presence of variables and constants. Definition 3. We call a constraint C evaluated if each constant that occurs in it is replaced by its value and each variable (not unknown) that occurs in it is replaced by its current value. If some variable that occurs in C is uninitialized, we say that the evaluation of C yields an error. Otherwise we call the resulting boolean expression the evaluated form of C. So no variables occur in the evaluated form of a constraint. For technical reasons we also consider a false constraint, denoted by ⊥, that can be generated only by a constraint solver to indicate contradiction. Definition 4. A constraint store, in short a store, is a set of evaluated forms of constraints. We say that an unknown is present in the store if it occurs in a constraint that belongs to the store. We call a store failed if ⊥ is present in it or if the domain of one of the unknowns present in it is empty. By a solution to the store we mean an assignment of values from the current domains to all unknowns present in it. Further, we say that a constraint is solved if its evaluated form is satisfied by all combinations of values from the current domains of its unknowns. For example, in the program fragment i := 1; j := 2; X[i] <= j; Y[X[i+2]] <> Y[N];
we have two constraints, X[i] <= j and Y[X[i+2]] <> Y[N]. Here X[1] <= 2 is the evaluated form of the first one, while Y[X[3]] <> Y[8] is the evaluated form of the second one. If we deleted the assignment i := 1 the evaluations of both constraints would yield an error. The notion of a failed store is a computationally tractable approximation of that of an inconsistent store, i.e., a store that has no solutions. Indeed, a failed store is inconsistent but an inconsistent store does not have to be failed: just consider X[1] = X[2], X[1] < X[2]. 4.3
Interaction Between the Program and the Constraint Store
The program interacts with the store in the following two ways: – By adding to it the evaluated forms of the encountered constraints. If the evaluation of such a constraint yields an error, a run-time error arises.
102
K.R. Apt and A. Schaerf
– By generating possible values for unknowns that are present in the store by means of some built-in primitives to be introduced in Subsection 6.2. The store is equipped with a number of procedures called constraint solvers. Their form depends on the applications. One or more of them can become activated upon addition of (an evaluated form of) a constraint to the store. An activation of constraint solvers, in the sequel called constraint solving, can reduce the domains of the unknowns, determine the values of some unknowns by reducing the corresponding domains to singletons, delete some constraints that are solved, or discover that the store is failed, either by generating the false constraint ⊥ or by reducing the domain of an unknown to the empty set. We assume that constraint solving is a further unspecified process that depending of application may be some form of constraint propagation or a decision procedure. We require that the result of constraint solving maintains equivalence, which means that the set of all solutions to the store does not change by applying to it constraint solvers. The store interacts with the program as follows. Definition 5. Upon addition of a constraint to the store, constraint solving takes place. – If as a result of the constraint solving the store remains non-failed, the control returns to the program and the execution proceeds in the usual way. – Otherwise the store becomes failed and a failure arises. This means that the control returns to the last choice point created in the program. Upon backtracking all the constraints added after the last choice point are retracted and the values of the variables and the domains of the unknowns are restored to their values at the moment that the last choice point was created. This means that we extend the notion of failure, originally introduced in Section 2, to deal with the presence of the store. Note that constraints are interpreted in the same way independently of the fact whether they appear as a statement or inside a condition. For example, the following program fragment IF X[1] > 0 THEN S ELSE T END is executed as follows: The constraint X[1] > 0 is added to the store. If the store does not fail S is executed, otherwise T is executed. So we do not check whether X[1] > 0 is entailed by the store and execute S or T accordingly, as one might intuitively expect. This means that constraints are always interpreted as so-called tell operations in the store, and never as so-called ask operations, which check for entailment (see Section 8 for a discussion on this point). 4.4
Examples
To illustrate use of the introduced concepts we now consider three examples. We begin with the following classical problem.
The Alma Project, or How First-Order Logic Can Help Us
103
Problem 2. Eight Queens. Place 8 queens on the chess board so that they do not attack each other. We present here a solution that uses constraints. We only write the part of the program that generates constraints. The code that actually solves the generated constraints would make use of the built-in INDOMAIN as explained in Subsection 6.2. CONST N = 8; TYPE Board = ARRAY [1..N] OF CONSTRAINED [1..N]; VAR i, j: [1..N]; X: Board; BEGIN FOR i := 1 TO N-1 DO FOR j := i+1 TO N DO X[i] <> X[j]; X[i] <> X[j]+j-i; X[i] <> X[j]+i-j END END END;
Each generated constraint is thus of the form X[i] <> X[j] or X[i] <> X[j] + k for some values i,j ∈ [1..N] such that i < j and k being either the value of j-i or of i-j. Note that the above program text coincides with the problem formulation. Next, consider the following problem that deals with the equations arising when studying the flow of heat. Problem 3. Laplace Equations. Given is a two dimensional grid with given values for all the exterior points. The value of each interior points equals the average of the values of its four neighbours. Compute the value of all interior points. The solution using constraints again truly coincides with the problem specification. It is conceptually much simpler than the solution based on constraint logic programming and given in [10]. TYPE Board = ARRAY [1..M], [1..N] OF CONSTRAINED REAL; VAR i:[1..M]; j:[1..N]; X: Board; BEGIN FOR i := 2 TO M-1 DO FOR j := 2 TO N-1 DO X[i,j] = (X[i+1,j] + X[i-1,j] + X[i,j+1] + X[i,j-1])/4 END END END;
104
K.R. Apt and A. Schaerf
We assume here that the constraint solver that deals with linear equations over reals is sufficiently powerful to solve the generated equations. Finally, we present a solution to the Frequency Assignment problem (Problem 1) that uses constraints. Again, we only write the part of the program that generates constraints. We assume here that the variables S and F are properly initialized. TYPE SeparationMatrix = ARRAY [1..N],[1..N] OF INTEGER; IllegalFrequencies = ARRAY [1..N],[1..M] OF BOOLEAN; Assignment = ARRAY [1..N] OF CONSTRAINED [1..M]; VAR S: SeparationMatrix; F: IllegalFrequencies; X: Assignment; i, j: INTEGER; BEGIN FOR i := 1 TO N DO FOR j := 1 TO M DO IF F[i,j] THEN X[i] <> j END END END; FOR i := 1 TO N DO FOR j := 1 TO i-1 DO EITHER X[i] - X[j] >= S[i,j] ORELSE X[j] - X[i] >= S[i,j] END END END END;
The use of the ORELSE statement creates here choice points to which the control can return if in the part of the program that deals with constraints solving a failed store is produced. Alternatively, one could use here a disjunction and replace the ORELSE statement by (X[i] - X[j] >= S[j,i]) OR (X[j] - X[i] >= S[j,i]). In this case no choice points are created but the problem of solving (disjunctive) constraints is now “relegated” to the store. The latter solution is preferred if the constraint solver in use is able to perform some form of preprocessing on disjunctive constraints, such as the constructive disjunction of [8]. On the other hand, the former solution allows the programmer to retain control upon the choice generated by the system. For example, she/he can associate different actions to the two branches of the ORELSE statement. It is important to realize that the integration of constraints to Alma-0 as outlined in this section is possible only because the unknowns are initially uninitialized.
The Alma Project, or How First-Order Logic Can Help Us
5
105
Constraints and Procedures
So far we explained how the program interacts with the store in absence of procedures. In Alma-0 one level (i.e., not nested) procedures are allowed. In presence of procedures we need to explain a number of issues. First, to keep matters simple, we disallow local unknowns. This means that the constrained types can be only introduced at the outer level. However, unknowns can be used within the procedure bodies provided the restrictions introduced in Definition 2 are respected. Next, we need to explain how unknowns can be passed as parameters. Formal parameters of constrained types are considered as unknowns. This means that in the procedure body such formal parameters can occur only within the constraints or within the right hand side of an assignment. We discuss first call by variable. An unknown (or a compound variable containing an unknown) passed as an actual variable parameter is handled in the same way as the customary variables, by means of the usual reference mechanism. For example consider the following problem. Problem 4. Given is an array which assigns to each pixel on an M × N board a colour. A region is a maximal set of adjacent pixels that have the same colour. Determine the number of regions. To solve it we represent each pixel as a record, one field of which holds the colour of the pixel and the other is an unknown integer. Then we assign to each pixel a number in such a way that pixels in the same region get the same number. These assignments are performed by means of constraint solving. For instance, in the case of Figure 1 the constraint solving takes care that the value 1 is assigned to all but two pixels once it is assigned to the leftmost uppermost pixel.
Fig. 1. Constraint Solving and Pixels
To achieve this effect in the program below we assume that the constraint solving process is able to reduce the domain of y to {a} given the constraint x = y and the fact that the domain of x equals {a}. The program uses both constraints and an assignment. In addition, the program uses the built-in KNOWN that, when used on unknowns, checks whether the domain of the argument is a singleton.
106
K.R. Apt and A. Schaerf
TYPE Colour = (blue, green, red, yellow); Info = RECORD co: Colour; No: CONSTRAINED INTEGER; END; Board = ARRAY [1..M],[1..N] OF Info; PROCEDURE Region(VAR X: Board; VAR number: INTEGER); VAR i, j, k: INTEGER; BEGIN FOR i := 1 TO M DO FOR j := 1 TO N DO IF i < M AND X[i,j].co = X[i+1,j].co THEN X[i,j].No = X[i+1,j].No END; IF j < N AND X[i,j].co = X[i,j+1].co THEN X[i,j].No = X[i,j+1].No END END END; k := 0; FOR i := 1 TO M DO FOR j := 1 TO N DO IF NOT KNOWN(X[i,j].No) THEN k := k+1; X[i,j].No = k END END END; number = k END Region;
Note that for any i in [1..M] and j in [1..N], the record component X[i,j].No is of a constrained type. Here the first double FOR statement generates the constraints while the second double FOR statement solves them by assigning to the pixels that belong to the same region the same number. Due to the call by variable mechanism, the actual parameter corresponding the formal one, X, is modified by the procedure. In particular, the second component, No, of each array element is instantiated after the procedure call. Next, we explain the call by value mechanism in presence of unknowns. An unknown passed as an actual value parameter is treated as a customary variable: it is evaluated and its value is assigned to a local variable associated with the formal parameter. If the value of this unknown is at this moment undetermined, this evaluation yields a run-time error. This evaluation process also applies if a field or an element of a compound actual value parameter is an unknown.
The Alma Project, or How First-Order Logic Can Help Us
6
107
Language Extensions
In this section we discuss some built-in procedures of the proposed language that make it easier for the user to program with constraints. In particular, in Subsection 6.1 we discuss built-ins for stating constraints, and in Subsection 6.2 we present built-ins for assigning values to unknowns. 6.1
Built-ins for Expressing Constraints
The practice of constraint programming requires inclusion in the programming language of a certain number of language built-ins that facilitate constraint formulation. For example, if we wish to state that the unknowns of the array X must have pairwise different values, we write ALL_DIFFERENT(X);
This call results in a constraint which is equivalent to the set of all the corresponding constraints of the form X[i] <> X[j], for i ∈[1..N-1] and j ∈[i+1..N]. 1 Similarly, if we wish to state that at most k among the unknowns belonging to the array X can have the value v, we write AT_MOST(k,X,v);
This sort of built-ins on arrays are present in other imperative constraint languages. We do not list all of them here, but we envision their presence in the language. Such built-ins on arrays are the counterparts in imperative languages of the corresponding built-ins on lists provided by constraint logic programming systems such as CHIP. These languages also support symbolic manipulation of terms which makes it easy to generate arithmetic constraints. The traditional imperative programming languages lack this power and exclusive reliance on arrays can lead to artificial and inefficient solutions. For example, suppose we are given an n × n matrix A of integer unknowns and we wish to state the constraint that the sum of the elements of the main diagonal must be equal to a given value b. A customary solution would involve resorting to an auxiliary array of unknowns in the following way: VAR A: ARRAY [1..N], [1..N] OF CONSTRAINED INTEGER; V: ARRAY [1..N] OF CONSTRAINED INTEGER; b: INTEGER; V[1] = A[1,1]; 1
In some systems, such a constraint is kept in its original form in order to exploit constraint propagation techniques that deal specifically with constraints of this kind, see [17].
108
K.R. Apt and A. Schaerf FOR i := 2 to N DO V[i] = A[i,i] + V[i-1]; END; V[N] = b;
This solution, which one would write for example in ILOG Solver, has the obvious drawback of creating N new unknowns for stating one single constraint. Therefore we propose the use of lists of unknowns (as done for example in the ICON programming language of [6] for the case of variables), identified by the keyword LIST, upon which constraints of various forms can be stated by means of built-ins. The above program fragment would then be replaced by VAR A: ARRAY [1..N], [1..N] OF CONSTRAINED INTEGER; L: LIST OF CONSTRAINED INTEGER; b: INTEGER; Empty(L); FOR i := 1 to N DO Insert(L, A[i,i]) END; Sum(L,’=’,b);
where Sum is a built-in with the expected meaning of constraining the sum of the unknowns in L to be equal to b. Once the constraint Sum(L,’=’,b) has been added to the store, the variable L can be used again for a different purpose. Note that in this solution no additional unknowns are created. In order to obtain a similar behaviour in ILOG Solver one needs either to add a similar built-in to it or to make explicit use of pointers to objects representing unknowns. Consider now again the Frequency Assignment problem. We discuss here the formulation of an additional constraint for this problem which requires the use of lists. Suppose that we wish to state that in a particular region (i.e., a set of cells) a given frequency is used no more than a given number of times. This type of constraint is useful in real cases. In fact, in some situations even though the pairwise interference among cells is below a given threshold and no separation is required, the simultaneous use of a given frequency in many cells can create a interference phenomenon, called cumulative interference. The following procedure states the constraints for preventing cumulative interference in region R (where the type Region is an array of booleans representing a subset of the set of cells). Here max is the maximum number of cells in the region that can use the same frequency. PROCEDURE RegionConstraint(R: Region; max: INTEGER; VAR X: Assignment); VAR i, k: INTEGER; L: LIST OF CONSTRAINED [1..M]; BEGIN FOR k := 1 TO M DO Empty(L);
The Alma Project, or How First-Order Logic Can Help Us
109
FOR i := 1 TO N DO IF R[i] THEN Insert(L,X[i]) END END; AT_MOST(max,L,k) END END RegionConstraint;
6.2
Built-ins for Assigning Values
In order to search for a solution of a set of constraints, values must be assigned to unknowns. We define the built-in procedure INDOMAIN which gets an unknown of a finite type (so BOOLEAN, enumeration or a subrange type) as a parameter, and assigns to it one among the elements of its domain. The procedure also creates a choice point and all other elements of the domain are successively assigned to the unknown upon backtracking. The choice of the value to assign to the unknown is taken by the system depending on the current state of the store, based on predefined value selection strategies. We do not discuss the issue of which are the best value selection strategies. We only assume that all consistent values are eventually generated, and that the choice point is erased after the last value has been generated. The procedure INDOMAIN can be also used on arrays and on lists. For example, the call INDOMAIN(A), where A is a matrix of integer unknowns, generates (upon backtracking) all possible assignments for all elements of A. The order of instantiation of the elements of A is taken care of by the store, which applies built-in strategies to optimize the retrieval of the first instantiation of the unknowns. As in the case of value selection, we do not discuss here the issue of the variable ordering.
7
Related Work
We concentrate here on the related work involving addition of constraints to imperative languages. For an overview of related work pertaining to the Alma-0 language we refer the reader to [2]. As already mentioned in the introduction, the most successful imperative constraint language is the C++ library ILOG Solver [9]. The main difference between our proposal and ILOG Solver is that the latter is based on the conventional imperative language C++ and consequently it does not support automatic backtracking. Therefore the interaction with the store cannot be based on failures issued by the store constraint solvers while evaluating the statements. In ILOG Solver such an interaction is always explicit, whereas in our proposal we aim at making it transparent to the user. We are aware of two other language proposals in which constraints are integrated into an imperative language — the commercial language CHARME of [14] and 2LP of [13]. In each language some of the issues here discussed have been addressed, but not all of them.
110
K.R. Apt and A. Schaerf
More specifically, in CHARME unknowns (called logical variables) and linear constraints on them are allowed. The language supports use of Prolog-like terms, arrays and sequences of logical variables and a number of features (like demons and the element primitive, an equivalent of INDOMAIN) adopted from the CHIP language. Also, it provides a nondeterministic or statement and iterations over finite domains, arrays and sequences of logical variables. The C like syntax creates an impression that CHARME supports imperative programming. However, from the paper it is not clear whether it is actually the case. If it is, then it is not clear how the logical variables, constraints and nondeterministic statements interact with the usual features of the underlying imperative language. In particular, the use of logical variables outside of constraints, the impact of backtracking on the assignment statements and the status of choice points created within procedure bodies is not explained (probably due to space limitations). CHARME does provide bidirectional connection with C. 2LP was designed for linear programming applications. In 2LP unknowns (called continuous variables) are global. They vary over the real interval [0, +∞) and can be either simple ones or arrays. The only way these variables can be modified is by imposing linear constraints on them. Constraints can also appear in conditions. This leads to a conditional way of adding them to the store. Whenever a constraint is added to the store, its feasibility w.r.t. the old constraints is tested by means of an internal simplex-based algorithm. This algorithm maintains the current feasible region, which is a polyhedron, together with a witness point which is a distinguished vertex. The continuous variables can appear outside of the constraints as arguments of any procedure whose signature has a continuous variable, and as arguments to some predeclared functions like wp that returns the value of a witness point. In the latter case when a continuous variable is passed as a parameter, the witness point value is used. 2LP provides the nondeterministic statements analogous to the ORELSE and SOME statements of Alma-0 and a limited form for the FORALL statement. Automatic backtracking over assignment and combination of continuous and customary variables in compound variables is not supported.
8
Conclusions and Future Work
In this paper we discussed the programming language Alma-0 that integrates the imperative and logic programming paradigm and illustrated the resulting programming style by a number of examples. Alma-0 is based on first-order logic in the sense that it provides a computational interpretation for the standard connectives, so negation, disjunction and conjunction, and for various forms of quantification. In fact, many first-order formulas and their extensions by bounded quantifiers, sorts (i.e., types), and arrays, can be interpreted and executed as Alma-0 programs. The precise logical nature of this computational interpretation of first-order logic was worked out in [1].
The Alma Project, or How First-Order Logic Can Help Us
111
Then we discussed a proposal how to integrate constraint programming features into the language. In this regard we believe that the use of an underlying language based on first-order logic, such as Alma-0, rather than a conventional imperative language, makes the integration of constraints more natural and conceptually simpler. We analyzed here a number of issues related to the proposed integration, such as the use of constrained types and the unknowns, interaction between the program and the constraint store, and the parameter passing mechanisms. Finally, we presented some examples that illustrate the resulting style of programming. In our future work we plan to extend the work carried out in [2] to the language proposal here outlined. More specifically, we envisage to – extend the executable, operational semantics based on the ASF+SDF MetaEnvironment of [12]; – extend both the Alma-0 compiler and its underlying abstract machine AAA; – implement a set of constraint solvers or provide an interface between the language and existing constraint solvers. The first item can be dealt with by adding to the executable semantics of Alma-0 given in [2] a few rules that formalize the interaction between the program and the store stipulated in Subsection 4.3. These rules are parameterized by the constraint solvers attached to the store. Regarding the last item, we plan to develop a simple solver for constraints over finite domains to be used for prototyping and testing purposes. We also plan to exploit more powerful external solvers already available for subsequent releases of the system. As already mentioned in Section 4.3, we do not allow so-called ask operations in the store. This is a deliberate design decision which allows us to keep the language design simple and the underlying execution model easy to implement. Nevertheless, in future versions of the language, we plan to investigate the possibility of equipping the store with an entailment procedure. This procedure should check whether an evaluated form of a constraint is logically implied (or entailed) by the store. Upon encounter of an ask constraint, the entailment procedure would check whether the evaluated form is entailed by the store. If it is the case, the constraint evaluates to TRUE. Otherwise the constraint evaluates to FALSE. We would require that the entailment procedure returns correct results but would not assume that it is complete. We did not deal here with some of the issues related to the design of the language. Specifically, we omitted discussion of – a full set of built-ins, in particular the ones appropriate for constraint optimization, – primitives for selecting variable and value selection strategies, – the language support for the dynamic creation of unknowns. These can be taken care of in a systematic way and lead to a complete and rigorous definition of an imperative constraint programming language.
112
K.R. Apt and A. Schaerf
Acknowledgements We would like to thank Jan Holleman, Eric Monfroy and Vincent Partington for useful discussions on the subject of this paper. Helpful comments by Tony Hoare and other two, anonymous, referees allowed us to improve the presentation.
References 1. K. R. Apt and M. A. Bezem. Formulas as programs. In K.R. Apt, V.W. Marek, M. Truszczy´ nski, and D.S. Warren, editors, The Logic Programming Paradigm: A 25 Year Perspective, pages 75–107, 1999. 2. K. R. Apt, J. Brunekreef, V. Partington, and A. Schaerf. Alma-0: An imperative language that supports declarative programming. ACM Toplas, 20(5):1014–1066, 1998. 3. K. R. Apt and A. Schaerf. Search and imperative programming. In Proc. 24th Annual SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL ’97), pages 67–79. ACM Press, 1997. 4. A. Colmerauer. An introduction to Prolog III. Communications of ACM, 33(7):69– 90, 1990. 5. M. R. Garey and D. S. Johnson. Computers and Intractability—A guide to NPcompleteness. W.H. Freeman and Company, San Francisco, 1979. 6. R. E. Griswold and M. T. Griswold. The Icon Programming Language. PrenticeHall, Englewood Cliffs, New Jersey, USA, 1983. 7. W. K. Hale. Frequency assignment: Theory and applications. In Proc. of IEEE, pages 1497–1514, 1980. 8. P. Van Hentenryck, Vijay Saraswat, and Y. Deville. Design, implementation, and evaluation of the constraint language cc(FD). In Andreas Podelski, editor, Constraint Programming: Basics and Trends, LNCS 910. Springer-Verlag, 1995. (Chˆ atillon-sur-Seine Spring School, France, May 1994). 9. ILOG. ILOG optimization suite — white paper. Available via http://www.ilog.com, 1998. 10. J. Jaffar and J.-L. Lassez. Constraint Logic Programming. In 14th ACM Principles of Programming Languages Conference, pages 111–119, Munich, F.R.G., 1987. ACM, New York. 11. Joxan Jaffar, Spiro Michaylov, Peter J. Stuckey, and Roland H. C. Yap. The CLP(R) language and system. ACM Transactions on Programming Languages and Systems (TOPLAS), 14(3):339–395, July 1992. 12. P. Klint. A meta–environment for generating programming environments. ACM Transactions on Software Engineering and Methodology, 2(2):176–201, 1993. 13. K. McAloon and C. Tretkoff. 2LP: Linear programming and logic programming. In P. Van Hentenryck and V. Saraswat, editors, Principles and Practice of Constraint Programming, pages 101–116. MIT Press, 1995. 14. A. Oplobedu, J. Marcovitch, and Y. Tourbier. CHARME: Un langage industriel de programmation par contraintes, illustr´e par une application chez Renault. In Ninth International Workshop on Expert Systems and their Applications: General Conference, Volume 1, pages 55–70, Avignon, France, 1989. EC2. 15. F. Pfenning, editor. Types in Logic Programming. MIT Press, Cambridge, Massachusetts, 1992.
The Alma Project, or How First-Order Logic Can Help Us
113
16. J.-F. Puget and M. Leconte. Beyond the glass box: Constraints as objects. In Proc. of the 1995 International Symposium on Logic Programming, pages 513–527, 1995. 17. J.-C. Regin. A filtering algorithm for constraints of difference in CSPs. In AAAI94: Proceedings of the 12th National Conference on Artificial Intelligence, pages 362–367, 1994. 18. I. Shvetsov, V. Telerman, and D. Ushakov. NeMo+ : Object-oriented constraint programming environment based on subdefinite models. In G. Smolka, editor, Artificial Intelligence and Symbolic Mathematical Computations, Lecture Notes in Computer Science, vol. 1330, pages 534–548, Berlin, 1997. Springer-Verlag. 19. P. Van Hentenryck, Helmut Simonis, and Mehmet Dincbas. Constraint satisfaction using constraint logic programming. Artificial Intelligence, 58:113–159, 1992.
Type and Effect Systems Flemming Nielson and Hanne Riis Nielson Department of Computer Science, Aarhus University, Denmark.
Abstract. The design and implementation of a correct system can benefit from employing static techniques for ensuring that the dynamic behaviour satisfies the specification. Many programming languages incorporate types for ensuring that certain operations are only applied to data of the appropriate form. A natural extension of type checking techniques is to enrich the types with annotations and effects that further describe intensional aspects of the dynamic behaviour. Keywords. Polymorphic type systems, effect annotations, subeffecting and subtyping, semantic correctness, type inference algorithms, syntactic soundness and completeness. Analyses for control flow, binding times, side effects, region structure, and communication structure.
1
Introduction
Static analysis of programs comprises a broad collection of techniques for predicting safe and computable approximations to the set of values or behaviours arising dynamically during computation; this may be used to validate program transformations, to generate more efficient code or to increase the understanding of the software so as to demonstrate that the software satisfies its specification. We shall find it helpful to divide the techniques into the following two approaches. The flow based approach includes the traditional data flow analysis techniques for mainly imperative and object-oriented languages; it also includes the constraint based control flow analysis techniques developed for functional and object oriented languages; finally, it includes the use of mathematical modelling in the abstract interpretation of imperative, functional, concurrent and logic languages. The inference based approach includes general logical techniques touching upon program verification and model checking; it also includes type and effect systems developed for functional, imperative and concurrent languages and it is this latter group of techniques that we consider here. We shall suppose that a typed programming language is given. In soft typing all programs can be typed because a “top” type can be used in the absence of meaningful “ordinary” types; this perspective is similar to that of the flow based approach and is quite useful for analysing the behaviour of programs but is less useful for enforcing the absence of dynamic errors. In this paper we focus on strong typing where no “top” type is around and where certain erroneous E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 114–136, 1999. c Springer-Verlag Berlin Heidelberg 1999
Type and Effect Systems
115
programs are rejected by the type system; in this way types are not only used for analysing the behaviours of programs but also for enforcing the absence of certain kinds of dynamic errors. The overall approach of type systems is to associate types to programs; normally the types merely describe the form of the data supplied to, and produced by, programs. The association of types to programs is done by a set of inference rules that are largely syntax-directed; since subprograms may contain free variables this needs to be relative to a type environment that maps the free variables to their types. We express the typing by means of a typing judgement that is usually a ternary relation on type environments, programs and types; it is frequently written Γ ` p : τ where p is the program, τ is the type, and Γ is the type environment. The main challenges of devising type systems is (i) to ensure that they are semantically correct (with respect to some dynamic semantics), (ii) to ensure that they are decidable so that types can be checked by an algorithm, and (iii) to ensure that there always is a “best” type, called a principal type, so that an algorithm can produce the intended type automatically. Type and effect systems refine the type information by annotating the types so as to express further intensional or extensional properties of the semantics of the program [18,19,20,21]. In Section 2 this takes the form of annotating the base types or the type constructors. In Section 3 we study effect systems where the annotations describe certain intensional aspects of the actions taking place during evaluation. In Section 4 we further enrich the expressivenes of effects so as to obtain causal information in the manner of process algebras. We then expose the overall methodology behind type and effect systems in Section 5 and indicate those combinations of features that challenge state-of-the-art. Further Reading. A more thorough development of the techniques of static analysis can be found in [30] (particularly in Chapter 5 that deals with type and effect systems) as well as in the references given.
2
Annotated Type Systems
Many programming languages incorporate types as a static technique for ensuring that certain operations are only applied to data of the appropriate form; this is useful for ensuring that the dynamic behaviour satisfies the specification. Example 1. A Typed Language. We shall use the following simple functional language to illustrate the development; constructs for iteration, recursion and conditionals present no obstacles and have only been left out in the interest of brevity. We shall later extend the language with side effects (as in Standard ML) and communication (as in Concurrent ML) thereby suggesting that type and effect systems apply equally well to imperative and concurrent languages.
116
F. Nielson and H.R. Nielson
The language has expressions (or programs) e and types τ given by: e ::= c | x | fnπ x => e0 | e1 e2 | · · · τ ::= int | bool | · · · | τ1 → τ2 Here c denotes a family of constants (each of type τc ), x denotes a family of variables, and π is an identification of the function abstraction to be used in the control flow analysis to be presented in Example 2. The typing judgements of the underlying or original type system have the form Γ `UL e : τ where the type environment Γ maps variables to types; the definition is as follows: Γ `UL c : τc
Γ [x 7→ τx ] `UL e0 : τ0 Γ `UL fnπ x => e0 : τx → τ0
Γ `UL x : Γ (x)
Γ `UL e1 : τ2 → τ0 Γ `UL e2 : τ2 Γ `UL e1 e2 : τ0
That a function has type τ1 → τ2 means that given an argument of type τ1 it will return a value of type τ2 in case it terminates. u t Perhaps the simplest technique for extending the expressiveness of types is to add annotations to the type constructors or base types. One popular class of analyses that can be expressed using this technique consists of interprocedural control flow analyses which track the origins of where functions might have been defined [7,8,11]; this can be extended with components for tracking where functions are applied and thus has strong similarities to the classical use-definition and definition-use analyses of data flow analysis. Example 2. Control Flow Analysis. To obtain a control flow analysis we shall annotate the function type τ1 → τ2 with information, ϕ, about which function it might be: ϕ ::= {π} | ϕ1 ∪ ϕ2 | ∅ ϕ
τb ::= int | bool | · · · | τb1 → τb2 So ϕ will be a set of function names – describing the set of function definitions that can result in a function of a given type. The typing judgements of the control flow analysis have the form Γb `CFA e : τb where the type environment Γb maps variables to annotated types. The judgements are defined in Table 1; note that the clause for function abstraction annotates the arrow of the resulting function type with the information that the abstraction named π should be included in the set {π}∪ϕ of functions that could be returned. In the presence of conditionals it is essential that we use {π} ∪ ϕ
Type and Effect Systems
117
Γb[x 7→ b τx ] `CFA e0 : b τ0 {π}∪ϕ b Γ `CFA fnπ x => e0 : b τx → τ0
Γb `CFA c : b τc Γb `CFA x : Γb(x)
ϕ Γb `CFA e1 : b τ2 → τb0
Γb `CFA e2 : b τ2
Γb `CFA e1 e2 : b τ0
Table 1. Control Flow Analysis: Γb `CFA e : τb (Example 2).
rather than {π} because the latter choice does not give rise to a conservative extension of the underlying type system: this means that there will be expressions that are typed in the underlying type system but that have no analysis in the control flow analysis; (this point is related to the issue of subeffecting to be discussed in Section 3.) 1 2 τb2 by τb1 ϕ→ τb2 whenever We should point out that we allow to replace τb1 ϕ→ ϕ1 and ϕ2 are “equal as sets”. More generally we allow to replace τb1 by τb2 if they have the same underlying types and all annotations on corresponding function arrows are “equal as sets”. To be utterly formal this can be axiomatised by a set of axioms and rules expressing that set union has a unit and is idempotent, commutative, and associative, together with axioms and rules ensuring that equality is an equivalence relation as well as a congruence; the abbreviation UCAI is often used for these properties. t u
Subtyping and Polymorphism Another popular class of analyses that can be expressed by annotations is the binding time analyses (e.g. [13]) which distinguish data as to whether they are static (available at compile-time) or dynamic (available at run-time); these analyses form the basis of partial evaluation and can also be used as the basis for security analyses (e.g. [12]) that distinguish between secret and public information. Example 3. Binding Time Analysis. For binding time analysis we extend the language of Examples 1 and 2 with a let-construct: e ::= · · · | let x = e1 in e2 (In fact let x = e1 in e2 is semantically equivalent to (fn x => e2 ) e1 .) The annotations of interest for the binding time analysis are: ϕ ::= β | S | D ϕ τb2 τb ::= intϕ | boolϕ | · · · | τb1 →
σ b ::= ∀(β1 , · · · , βn ).b τ | τb
118
F. Nielson and H.R. Nielson
The annotation S is used to model data that is available statically, D is used to model data that is available dynamically, and β is an annotation variable that can take its values among S and D. A partial ordering on annotations ϕ v ϕ0 may be defined by: ϕvϕ
SvD
Types contain annotations on the type constructors as well as on the base types; a static function operating on dynamic integers will thus have the annotated S type intD → intD . This type system is motivated by applications to partial evaluation and this suggests imposing a well-formedness condition on types so D as to rule out types like intS → intS that are regarded as being meaningless. This is performed by the auxiliary judgement τb . ϕ that additionally extracts the top-level annotation ϕ from the annotated type τb: intϕ . ϕ
boolϕ . ϕ
τb1 . ϕ1 τb2 . ϕ2 if ϕ v ϕ1 and ϕ v ϕ2 ϕ τb1 → τb2 . ϕ In short, a static function is allowed to operate on dynamic data but not vice versa. Since we have annotation variables we can express a limited form of annotation polymorphism and we use σ b to denote the corresponding type schemes; for simplicity we do not incorporate type variables or type polymorphism. b where the type environment The typing judgements have the form Γb `BTA e : σ Γb maps variables to type schemes (or types) and σ b is the type scheme (or type) for the expression e. The analysis is specified by the axioms and rules of Table 2 and is explained in the sequel. The first five axioms and rules are straightforward; note that the rule for function abstraction checks that the type is well-formed and that the rule for let makes use of type schemes. The next rule is a subtyping rule that allows to weaken the information contained in an annotated type. The subtype ordering τb ≤ τb0 is given by: 0
intϕ ≤ intϕ if ϕ v ϕ0 0
boolϕ ≤ boolϕ if ϕ v ϕ0 τb10 ≤ τb1
τb2 ≤ τb20
ϕ τb1 → τb2 ≤ τb10
0
→ τb20
ϕ
if ϕ v ϕ0 ∧ τb10
ϕ0
→ τb20 . ϕ0
This ensures that only well-formed types are produced and that the ordering is → τb2 is contravariant in reversed for arguments to functions; we say that τb1 ϕ 0 τb1 but covariant in ϕ and τb2 . (Think of the annotated type τb ϕ→ τb0 as being 0 0 analogous to the logical formula τb ⇒ ϕ ∧ τb and use that the inference rule expresses the monotonicity of logical implication.) The final two rules are responsible for the polymorphism. The first rule is the generalisation rule that is used to construct type schemes: we can quantify over
Type and Effect Systems Γb `BTA c : b τc
119
Γb `BTA x : Γb(x)
Γb[x 7→ b τx ] `BTA e0 : τb0 ϕ b Γ `BTA fnπ x => e0 : b τx → τ0 b ϕ Γb `BTA e1 : b τ2 → τ0 b
ϕ if (b τx → τ0 ) . ϕ b
Γb `BTA e2 : b τ2
Γb `BTA e1 e2 : b τ0 Γb `BTA e1 : b σ1
Γb[x 7→ b σ1 ] `BTA e2 : τb2 b Γ `BTA let x = e1 in e2 : τb2 Γb `BTA e : b τ
Γb `BTA e : b τ0 Γb `BTA e : b τ b Γ `BTA e : ∀(β1 , · · · , βn ).b τ Γb `BTA e : ∀(β1 , · · · , βn ).b τ Γb `BTA e : (θ b τ)
if b τ ≤ τb0
if β1 , · · · , βn do not occur free in Γb τ) . ϕ if dom(θ) ⊆ {β1 , · · · , βn } and ∃ϕ : (θ b
Table 2. Binding Time Analysis: Γb `BTA e : τb & ϕ (Example 3).
any annotation variable that does not occur free in the type environment; this rule is usually used immediately before the rule for the let-construct. The second rule is the instantiation rule that can be used to turn type schemes into annotated types: we just apply a substitution in order to replace the bound annotation variables with other annotations; this rule is usually used immediately after the axiom for variables. t u References for type systems with subtyping include [9,10,23] as well as the more advanced [16,37,38] that also deal with Hindley/Milner polymorphism (as found in Standard ML). To allow a general treatment of subtyping, these papers generally demand constraints to be an explicit part of the inference system and this is somewhat more complex than the approach taken here; such considerations are mainly motivated by the desire to obtain principal types and in order to develop syntactically sound and complete type inference algorithms as will be discussed in Section 5. Indeed, our formulation of subtyping only allows shape conformant subtyping, where the underlying type system does not make use of any form of subtyping, and is thus somewhat simpler than atomic subtyping, where an ordering is imposed upon base types, and general subtyping, where an ordering may be imposed between arbitrary types. Strictness analyses and classical data flow analyses can also be expressed as annotated type systems but to be useful they may require the type system to be extended with conjunction or disjunction types [4,5,14,15] thereby touching
120
F. Nielson and H.R. Nielson
upon the logical techniques. In annotated type systems, as well as in the type and effect systems considered below, the annotations are normally sets of some kind, but linking up with abstract interpretation it should be possible to allow more general annotations that are elements of a complete lattice (that is possibly of finite height as in the “monotone frameworks” of data flow analysis); however, this possibility is hardly considered in the literature except in the case of binding time analysis where the binding times (e.g. static and dynamic) are partially ordered, c.f. [13,24].
3
Type and Effect Systems
The typing judgements of type systems take the following general form: a type is associated with a program (or an expression or a statement) relative to a type environment providing the type (or type scheme) for each free variable; this also holds for the typing judgements used for the annotated type systems presented above. Effect systems can be viewed as an outgrowth of annotated type system where the typing judgements take the following more elaborate form: a type and an effect is associated with a program relative to a type environment. Formally, effects are nothing but the annotations already considered, but conceptually, they describe intensional information about what takes place during evaluation of the program unlike what was the case above.
Subeffecting and Subtyping The literature has seen a great variation in the uses to which effects have been put: collecting the set of procedures or functions called [41], collecting the set of storage cells written or read during execution [40], determining what exceptions can be raised during evaluation, and collecting the regions in which evaluation takes place [44] to mention just a few. We begin by considering an analysis for collecting the set of storage cells written or read during execution. Example 4. Adding Imperative Constructs. To facilitate the side effect analysis we shall add imperative constructs (resembling those of Standard ML) for creating reference variables and for accessing and updating their values: e ::= · · · | newπ x := e1 in e2 | !x | x := e0 The idea is that newπ x:= e1 in e2 creates a new reference variable x for use in e2 and initialises it to the value of e1 ; as above we use π to identify the creation point. The value of the reference variable x can be obtained by writing !x and it may be set to a new value by the assignment x := e0 . The type of a reference
Type and Effect Systems
121
cell for values of type τ is τ ref and the underlying type system of Example 1 is extended with the rules: Γ `UL !x : τ if Γ (x) = τ ref Γ `UL e : τ if Γ (x) = τ ref Γ `UL x := e : τ Γ `UL e1 : τ1 Γ [x 7→ τ1 ref] `UL e2 : τ2 Γ `UL newπ x := e1 in e2 : τ2 Example 5. Side Effect Analysis. In the side effect analysis a reference variable is represented by a set % of program points where it could have been created; this set is called a region and has the general form {π1 } ∪ · · · ∪ {πn } which we write as the set {π1 , · · · , πn }. The annotations of interest are: ϕ ::= {!π} | {π:=} | {new π} | ϕ1 ∪ ϕ2 | ∅ % ::= {π} | %1 ∪ %2 | ∅ ϕ
τb ::= int | bool | · · · | τb1 → τb2 | τb ref % Here τb ref % is the type of a location created at one of the program points in the region %; the location is used for holding values of the annotated type τb. The annotation !π means that the value of a location created at π is accessed, π:= means that a location created at π is assigned, and new π that a new location has been created at π. The typing judgements have the form Γb `SE e : τb & ϕ. This means that under the type environment Γb, if the expression e terminates then the resulting value will have the annotated type τb and ϕ describes the side effects that might have taken place during evaluation. As before the type environment Γb will map variables to annotated types; no effects are involved because the semantics is eager rather than lazy. The analysis is specified by the axioms and rules of Table 3; these rules embody the essence of effect systems. In the clauses for constants and variables we record that there are no side effects so we use ∅ for the overall effect. The premise of the clause for function abstraction gives the effect of the function body and this effect is used to annotate the arrow of the function type whereas we use ∅ as the overall effect of the function definition itself: no side effects can be observed by simply defining the function. In the rule for function application we see how the information comes together: the overall effect is what can be observed from evaluating the argument e1 , what can be observed from evaluating the argument e2 , and what is obtained from evaluating the body of the function called. Turning to the rules involving reference variables we make sure that we only assign a value of the appropriate type to the reference variable. Also, in each of
122
F. Nielson and H.R. Nielson Γb `SE c : τbc & ∅
Γb `SE x : Γb(x) & ∅
Γb[x 7→ τbx ] `SE e0 : b τ0 & ϕ0 0 b Γ `SE fnπ x => e0 : b τx ϕ→ τb0 & ∅ Γb `SE e1 : b τ2
Γb `SE e2 : b τ2 & ϕ2
ϕ0
→ τb0 & ϕ1
Γb `SE e1 e2 : b τ0 & ϕ1 ∪ ϕ2 ∪ ϕ0 Γb `SE !x : b τ & {!π1 , · · · , !πn } if Γb(x) = τb ref {π1 , · · · , πn } Γb `SE e : b τ &ϕ τ ref {π1 , · · · , πn } if Γb(x) = b b Γ `SE x := e : b τ & ϕ ∪ {π1 :=, · · · , πn :=} Γb `SE e1 : b τ1 & ϕ1
Γb[x 7→ τb1 ref(% ∪ {π})] `SE e2 : b τ2 & ϕ2
Γb `SE newπ x := e1 in e2 : b τ2 & (ϕ1 ∪ ϕ2 ∪ {new π}) Γb `SE e : b τ &ϕ
Γb `SE e : b τ & ϕ0
if ϕ ⊆ ϕ0
Table 3. Side Effect Analysis: Γb `SE e : τb & ϕ (Examples 5, 6 and 7).
the rules we make sure to record that a location at the relevant program point might have been created, referenced or assigned. The purpose of % in the rule for new in Table 3, and the purpose of the last rule in Table 3, is to ensure that we obtain a conservative extension of the underlying type system. The last rule is called a subeffecting rule and is essential in the presence of conditionals. The notation ϕ ⊆ ϕ0 means that ϕ is “a subset” of ϕ0 (modulo UCAI ). t u Example 6. Subtyping for Side Effect Analysis. The last rule in Table 3 can be augmented with a rule for subtyping: Γb `SE e : τb & ϕ if τb ≤ τb0 Γb `SE e : τb0 & ϕ The ordering τb ≤ τb0 on annotated types is derived from the ordering on annotations as follows: τb ≤ τb
τb10 ≤ τb1
τb2 ≤ τb20
ϕ τb1 → τb2 ≤ τb10
ϕ ⊆ ϕ0 0
→ τb20
ϕ
τb ≤ τb0 τb0 ≤ τb % ⊆ %0 τb ref % ≤ τb0 ref %0
Here ϕ ⊆ ϕ0 means that ϕ is “a subset” of ϕ0 (modulo UCAI ) and similarly ϕ % ⊆ %0 means that % is “a subset” of %0 (modulo UCAI ); as before τb1 → τb2 is
Type and Effect Systems
123
contravariant in τb1 but covariant in ϕ and τb2 . Also τb ref % is both covariant in τb (when the reference variable is used for accessing its value as in !x) and contravariant in τb (when the reference variable is used for assignments as in x := · · ·) whereas it is only covariant in %. This form of subtyping amounts to shape conformant subtyping because τb1 ≤ τb2 implies that the two annotated types have the same underlying types. t u Subeffecting alone suffices for obtaining a conservative extension of the underlying type system – provided that we regard the use of % in the rule for new as being an integral part of subeffecting; the general idea is that subeffecting allows to “enlarge” the effects at an early point so that they do not conflict with the demands of the type and effect system. This reduces the usefulness of the effects but by incorporating subtyping we can “enlarge” the types at a later point; hence more informative types and effects can be used in subprograms. Coming back to our treatment of control flow analysis in Example 2 we note that basically it is a subeffecting analysis.
Polymorphism and Polymorphic Recursion Subtyping is one of the classical techniques for making a type more useful by allowing to adapt it to different needs. Another classical technique is Hindley/Milner polymorphism as found in Standard ML and other functional languages. Both techniques are useful for increasing the precision of the information obtainable from type and effect systems. Example 7. Polymorphism for Side Effect Analysis. We now once more extend the language of Examples 5 and 6 with a polymorphic let-construct: e ::= · · · | let x = e1 in e2 We also allow types to contain type variables α, effects to contain annotation variables β and regions to contain region variables ρ: τb ::= · · · | α
ϕ ::= · · · | β
% ::= · · · | ρ
We can then define type schemes: a type scheme is a type where a (possible empty) list ζ1 , · · · , ζn of type, effect and region variables has been quantified over: σ b ::= ∀(ζ1 , · · · , ζn ).b τ If the list is empty we simply write τb for ∀().b τ. b & ϕ where the type The typing judgements will be of the form Γb `SE e : σ environment Γb now maps variables to type schemes (or types) and σ b is a type
124
F. Nielson and H.R. Nielson
scheme (or type). The clauses are as in Table 3 with the addition of the following rules: b1 & ϕ1 Γb[x 7→ σ b1 ] `SE e2 : τb2 & ϕ2 Γb `SE e1 : σ Γb `SE let x = e1 in e2 : τb2 & ϕ1 ∪ ϕ2 Γb `SE e : τb & ϕ
τ &ϕ Γb `SE e : ∀(ζ1 , · · · , ζn ).b Γb `SE e : ∀(ζ1 , · · · , ζn ).b τ &ϕ b Γ `SE e : (θ τb) & ϕ
if ζ1 , · · · , ζn do not occur free in Γb and ϕ if dom(θ) ⊆ {ζ1 , · · · , ζn }
The second and third rules are responsible for the polymorphism and are extensions of the last two rules of Table 2. The second rule is the generalisation rule: we can quantify over any type, annotation or region variable that does not occur free in the assumptions or in the effect. The third rule is the instantiation rule: we just apply a substitution in order to replace the bound type, annotation and region variables with other types, annotations and regions. t u Both subtyping and polymorphism improve subeffecting by giving finer control over when to “enlarge” the types; we already explained the advantage: that more informative types and effects can be used in subprograms. Since the mechanisms used are incomparable it clearly makes sense to combine both. However, as discussed in Section 5, it may be quite challenging to develop a type and effect inference algorithm that is both syntactically sound and complete. Example 8. Region Inference. The let-construct can be used to give polymorphic types to functions. But in the Hindley/Milner approach a recursive function can only be used polymorphically outside of its own body – inside its own body it must be used monomorphically. The generalisation to allow recursive functions to be used polymorphically also inside their own bodies is known as polymorphic recursion but gives rise to an undecidable type system; this means that no terminating type inference algorithm can be both syntactically sound and complete. This insight is a useful illustration of the close borderline between decidability and undecidability that holds for the inference based approach to the static analysis of programs. Even though we abstain from using polymorphic recursion for ordinary types there is still the possibility of using polymorphic recursion for the effects annotating the ordinary and possibly polymorphic types given to recursive functions. In this way, distinct uses of a recursive function inside its body can still be analysed in different ways. This approach is taken in an analysis known as region inference [44] that is used when implementing functional languages in a stack-based regime rather than a heap-based regime. More precisely, the memory model is a stack of regions of data items, and the analysis facilitates determining at compile-time in which region to allocate data and when to deallocate a region (rather than using a garbage collector at run-time).
Type and Effect Systems
125
The use of polymorphic recursion for effect and region annotations allows the inference system to deal precisely with the allocation of data inside recursive functions. Furthermore, the inference system implicitly incorporates a notion of constraint between annotation variables and their meaning (via a dot notation on function arrows); as discussed in Section 5 this is a common feature of systems based on subtyping as otherwise principal types may not be expressible. To obtain effects that are as small as possible, the inference system uses “effect masking” [21,39,40] for removing internal components of the effect: effect components that only deal with regions that are not externally visible. It is unclear whether or not this system is decidable but nonetheless it has proved quite useful in practice: a syntactically sound inference algorithm has been devised and it is sufficiently accurate that a region-based implementation of Standard ML has turned out to compete favourably with a heap-based implementation. t u Mutually Recursive Types and Effects So far the annotations and effects have not included any type information; as we shall see in Section 5 this is essential for being able to develop type and effect inference algorithms using a two-stage approach where first the types are determined and next the effects annotating the types. It is possible to be more permissive in allowing effects to contain type information and in allowing even the shape of types and type schemes to be influenced by the type information contained in the effects; as will be explained in Section 5 this calls for a more complex one-stage approach to type and effect inference algorithms. Example 9. Polymorphic Typing in Standard ML. The Hindley/Milner approach to polymorphism was originally conceived only for pure functional languages. Extending it to deal with side effects in the form of reference variables has presented quite a few obstacles. As an example consider the following program fragment in an ML-like language: let x = new nil in (· · · x:=cons(7,x) · · · x:=cons(true,x) · · ·) Here x is declared as a new cell whose contents is initially the empty list nil and it might be natural to let the type of x be something like ∀α. (α list) ref; but then both assignments will typecheck and hence the type system will be semantically unsound as Standard ML only permits homogeneous lists where all elements have the same type. Several systems have been developed for overcoming these problems (see e.g. [42]). One approach is to restrict the ability to generalise over “imperative” type variables: these are the type variables that may be used in an imperative manner. It is therefore natural to adapt the side effect analysis to record the imperative type variables and to prohibit the generalisation rule from generalising over imperative type variables. In this way the shape of type schemes is clearly influenced
126
F. Nielson and H.R. Nielson
by the effect information. This idea occurred already in [39,40,48] in the form of an extended side effect analysis with polymorphism and subeffecting. u t
4
Causal Type Systems
So far the annotations and effects have had a rather simple structure in that they have mainly been sets. It is possible to be more ambitious in identifying the “causality” or temporal order among the various operations. As an example, we now consider the task of extracting behaviours (reminiscent of terms in a process algebra) from programs in Concurrent ML by means of a type and effect system; here effects (the behaviours) have structure, they may influence the type information (as in Example 9), and there are inference rules for subeffecting and shape conformant subtyping. These ideas first occurred in [27,29] (not involving polymorphism) and in [2,33,34] (involving polymorphism); our presentation is mainly based on [33,34] because the inference system is somewhat simpler than that of [1] (at the expense of making it harder to develop an inference algorithm); we refer to [1, Chapter 1] for an overview of some of the subtle technical details. An application to the validation of embedded systems is presented in [32] where a control program is shown not to satisfy the safety requirements. Example 10. Adding Constructs for Communication. To facilitate the communication analysis we shall add constructs for creating new channels, for generating new processes, and for communicating between processes over typed channels: e ::= · · · | channelπ | spawn e0 | send e1 on e2 | receive e0 Here channelπ creates a new channel identifier, spawn e0 generates a new parallel process that executes e0 , and send v on ch sends the value v to another process ready to receive a value by means of receive ch. We shall assume that there is a special constant () of type unit; this is the value to be returned by the spawn and send constructs. t u Example 11. Communication Analysis. Turning to the communication analysis the annotations of interest are: ϕ ::= β | Λ | ϕ1 ; ϕ2 | ϕ1 + ϕ2 | recβ.ϕ | τb chan % | spawn ϕ | %!b τ | %?b τ % ::= ρ | {π} | %1 ∪ %2 | ∅ ϕ τb ::= α | int | bool | · · · | unit | τb1 → τb2 | τb chan %
σ b ::= ∀(ζ1 , · · · , ζn ).b τ The behaviour Λ is used for atomic actions that do not involve communication; in a sense it corresponds to the empty set in previous annotations although it
Type and Effect Systems Γb `COM c : b τc & Λ
127
Γb `COM x : Γb(x) & Λ
Γb[x 7→ τbx ] `COM e0 : τb0 & ϕ0 0 b Γ `COM fnπ x => e0 : b τx ϕ→ τ0 & Λ b Γb `COM e1 : b τ2
ϕ0
→ τb0 & ϕ1
Γb `COM e2 : b τ2 & ϕ2
Γb `COM e1 e2 : τb0 & ϕ1 ; ϕ2 ; ϕ0 Γb `COM channelπ : τb chan {π} & b τ chan {π} Γb `COM e0 : τb0 & ϕ0 b Γ `COM spawn e0 : unit & spawn ϕ0 Γb `COM e1 : τb & ϕ1
Γb `COM e2 : b τ chan %2 & ϕ2
Γb `COM send e1 on e2 : unit & ϕ1 ; ϕ2 ; (%2 !b τ) Γb `COM e0 : b τ chan %0 & ϕ0 b Γ `COM receive e0 : b τ & ϕ0 ; (%0 ?b τ) Γb `COM e : b τ &ϕ
if b τ ≤ τb0 and ϕ v ϕ0
Γb `COM e : τb0 & ϕ0 Γb `COM e : b τ &ϕ
Γb `COM e : ∀(ζ1 , · · · , ζn ).b τ &ϕ
if ζ1 , · · · , ζn do not occur free in Γb and ϕ
Γb `COM e : ∀(ζ1 , · · · , ζn ).b τ &ϕ Γb `COM e : (θ b τ) & ϕ
if dom(θ) ⊆ {ζ1 , · · · , ζn }
Table 4. Communication Analysis: Γb `COM e : τb & ϕ (Example 11).
will be more intuitive to think of it as the empty string in regular expressions or as the silent action in process calculi. The behaviour ϕ1 ; ϕ2 says that ϕ1 takes place before ϕ2 whereas ϕ1 + ϕ2 indicates a choice between ϕ1 and ϕ2 ; this is reminiscent of constructs in regular expressions as well as in process algebras. The construct recβ.ϕ indicates a recursive behaviour that acts as given by ϕ except that any occurrence of β stands for recβ.ϕ itself. The behaviour τb chan % indicates that a new channel has been allocated for communicating entities of type τb; the region % indicates the set of program points {π1 , · · · , πn } where the creation could have taken place. The behaviour spawn ϕ indicates that a new process has been generated and that it operates as described by ϕ. The construct %!b τ indicates that a value is sent over a channel of type τb chan %, and %?b τ indicates that a value is received over a channel of that type; this is reminiscent of constructs in most process algebras (in particular CSP).
128
F. Nielson and H.R. Nielson
The typing judgements have the form Γb `COM e : σ b & ϕ where the type environment Γb maps variables to type schemes (or types), σ b is the type scheme (or type) for the expression e, and ϕ is the behaviour that may arise during evaluation of e. The analysis is specified by the axioms and rules of Tables 4 and have many points in common with those we have seen before; we explain the differences below. The axioms for constants and variables differ from the similar axioms in Table 3 in that Λ is used instead of ∅. A similar remark holds for the rule for function abstraction. In the rule for function application we now use sequencing to express that we first evaluate the function part, then the argument and finally the body of the function; note that the left-to-right evaluation order is explicit in the behaviour. The axiom for channel creation makes sure to record the program point in the type as well as the behaviour, the rule for spawning a process encapsulates the behaviour of the spawned process in the behaviour of the construct itself and the rules for sending and receiving values over channels indicate the order in which the arguments are evaluated and then produce the behaviour for the action taken. The rules for generalisation and instantiation are much as before. The rule for subeffecting and subtyping is an amalgamation of the rules in Table 3 and Example 6. Also note that there is no % in the axiom for channel unlike in the axiom for new in Table 3; this is because the presence of subtyping makes it redundant. The ordering τb ≤ τb0 on types is given by τb ≤ τb
τb10 ≤ τb1
τb2 ≤ τb20
ϕ τb1 → τb2 ≤ τb10
ϕ v ϕ0 0
→ τb20
ϕ
τb ≤ τb0 τb0 ≤ τb % ⊆ %0 τb chan % ≤ τb0 chan %0
and is similar to the definition in Example 6: τb1 ϕ→ τb2 is contravariant in τb1 but covariant in ϕ and τb2 , and τb chan % is both covariant in τb (for when a value is sent) and contravariant in τb (for when a value is received) and it is covariant in %. As before, the ordering % ⊆ %0 means that % is “a subset of” of %0 (modulo UCAI ). However, the ordering ϕ v ϕ0 on behaviours is more complex than what has been the case before because of the rich structure possessed by behaviours. The definition is given in Table 5 and will be explained below. Since the syntactic categories of types and behaviours are mutually recursive also the definitions of τb ≤ τb0 and ϕ v ϕ0 need to be interpreted recursively. The axiomatisation of ϕ v ϕ0 ensures that we obtain a preorder that is a congruence with respect to the operations for combining behaviours. Furthermore, sequencing is an associative operation with Λ as identity and we have a distributive law with respect to choice. It follows that choice is associative and commutative. Next the axioms for recursion allow us to unfold the rec-construct. The final three rules clarify how behaviours depend upon types and regions: τb chan % is both contravariant and covariant in τb and is covariant in % (just as was the case for the type τb chan %); %!b τ is covariant in both % and τb (because a value is sent) whereas %?b τ is covariant in % and contravariant in τb (because a value is
Type and Effect Systems
ϕvϕ
ϕ1 v ϕ2 ϕ2 v ϕ3 ϕ1 v ϕ3
ϕ1 v ϕ2 ϕ3 v ϕ4 ϕ1 ; ϕ3 v ϕ2 ; ϕ4
ϕ1 v ϕ2 ϕ3 v ϕ4 ϕ1 + ϕ3 v ϕ2 + ϕ4
ϕ1 ; (ϕ2 ; ϕ3 ) v (ϕ1 ; ϕ2 ); ϕ3
(ϕ1 ; ϕ2 ); ϕ3 v ϕ1 ; (ϕ2 ; ϕ3 )
ϕ v Λ; ϕ
Λ; ϕ v ϕ
(ϕ1 + ϕ2 ); ϕ3 v (ϕ1 ; ϕ3 ) + (ϕ2 ; ϕ3 ) ϕ1 v ϕ1 + ϕ2
ϕ2 v ϕ1 + ϕ2
ϕ v ϕ; Λ
129
ϕ; Λ v ϕ
(ϕ1 ; ϕ3 ) + (ϕ2 ; ϕ3 ) v (ϕ1 + ϕ2 ); ϕ3 ϕ+ϕvϕ
ϕ1 v ϕ2 spawn ϕ1 v spawn ϕ2
ϕ1 v ϕ2 recβ.ϕ1 v recβ.ϕ2
recβ.ϕ v ϕ[β 7→ recβ.ϕ]
ϕ[β 7→ recβ.ϕ] v recβ.ϕ
τ1 ≤ τb2 % 1 ⊆ %2 b %1 !b τ1 v %2 !b τ2
%1 ⊆ %2 b τ2 ≤ τb1 %1 ?b τ1 v %2 ?b τ2
τb ≤ b τ 0 τb0 ≤ b τ % ⊆ %0 τb chan % v τb0 chan %0
Table 5. Ordering on behaviours: ϕ v ϕ0 (Example 11).
received). There is no explicit law for renaming bound behaviour variables as we shall regard recβ.ϕ as being equal to recβ 0 .ϕ0 when they are α-equivalent. t u
5
The Methodology
So far we have illustrated the variety of type and effect systems that can be found in the literature. Now we turn to explaining the individual steps in the overall methodology of designing and using type and effect systems: – devise a semantics for the programming language, – develop a program analysis in the form of a type and effect system (this is what Sections 2, 3 and 4 have given numerous examples of), – prove the semantic correctness of the analysis, – develop an efficient inference algorithm, – prove that the inference algorithm is syntactically sound and complete, and – utilise the information for applications like program transformations or improved code generation.
130
F. Nielson and H.R. Nielson
Each of these phases have their own challenges and open problems that we now consider in some detail; many of these issues are rather orthogonal to the more syntactic differences used to distinguish between the formulations used in Sections 2, 3 and 4.
Semantics. Semantics is a rather well understood area. In principle both denotational and operational semantics can be used as the foundations for type and effect systems but most papers in the literature take an operational approach. This is indeed very natural when the analysis needs to express further intensional details than are normally captured by a denotational semantics. But even when taking an operational approach one frequently needs to devise it in such a manner that it captures those operational details for which the analysis is intended. The term instrumented semantics [17] has been coined for a class of denotational or operational semantics that are more precise about low-level machine detail (say concerning pipe-lining or the number and nature of registers) than usual. It is therefore wise to be cautious about the precise meaning of claims stating that an analysis has been proved correct with respect to “the” semantics.
The inference system. Previous sections have illustrated some of the variations possible when developing type and effect systems as well as some of the applications for which they can be used. However, it would be incorrect to surmise that the selection of components are inherently linked to the example analysis where they were first illustrated. At the same time we illustrated a number of design considerations to be taken into account when devising a type and effect system. In our view the major design decisions are as follows: – whether or not to incorporate • subeffecting, • subtyping, • polymorphism, and • polymorphic recursion, – whether or not types are allowed to be influenced by effects (as was the case in Example 9 and Section 4), and – whether or not constraints are an explicit part of the inference system (unlike what simplicity demanded us to do here). The choices made have a strong impact on the difficulties of obtaining a syntactically sound and complete inference algorithm; indeed, for some combinations it may be beyond state-of-the-art (or even impossible) and in particular it may be hard (or impossible) to deal with subtyping without admitting constraints to the inference system. An important area of further research is how to identify those features of the annotated type and effect systems that lead to algorithmic intractability.
Type and Effect Systems
131
Often the type and effect system is developed for a typed programming language. It is then important to ensure that whenever a program can be typed in the original type system then there also exists a type in the type and effect system, and whenever there exists a type in the type and effect system then the program can also be typed in the original type system. This is established by proving that the type and effect system is a conservative extension of the original or underlying type system. It is also possible to investigate whether or not the type and effect system admits principal types and effects; luckily this will always be the case if a syntactically sound and complete inference algorithm can be developed. Further studies are needed to understand the interplay between type and effect systems and the other approaches to static analysis of programs. It is interesting to note that the existence of principal types is intimately connected to the notion of Moore families used in abstract interpretation: a principal type roughly corresponds to the least solution of an equation system.
Semantic correctness. Many of the techniques needed for establishing semantic soundness (sometimes called type soundness) are rather standard. For operational semantics the statement of correctness generally take the form of a subject reduction result: if a program e has a type τ and if e evaluates to e0 then also e0 has the type τ ; this approach to semantic correctness has a rather long history [24,25,49] and applies both to small-step Structural Operational Semantics and to big-step Natural Semantics [36]. It is important to stress that the correct use of covariance and contravariance (in the rules for subtyping) is essential for semantic correctness to hold. For more complex situations the formulation of “has a type” may have to be defined coinductively [42], in which case also the proof of the subject reduction result may need to exploit coinduction (e.g. [30]), and the notions of Kripke relations and Kripke-logical relations (see e.g. [28]) may be useful when using a denotational semantics [26]. We refer to [3,39,40,45] for a number of applications of these techniques.
The inference algorithm. The development of a syntactically sound and complete inference algorithm may be based on the ideas in [20,41]. The simplest approach is a two-stage approach where one first determines the underlying types and next determines the (possibly polymorphic) effects on top of the explicitly typed programs. The basic idea is to ensure that the type inference algorithm operates on a free algebra by restricting annotations to be annotation variables only (the concept of “simple types”) and by recording a set of constraints for the meaning of the annotation variables. This suffices for adapting the established techniques for polymorphic type inference, by means of the classical algorithm W developed in [6,22] for Hindley/Milner polymorphism, to the setting at hand. In this scheme one might have W(Γ, e) = (S, τ, ϕ, C) where e is the program to
132
F. Nielson and H.R. Nielson
be typed, τ is the form of the resulting type and ϕ summarises the overall effect of the program. In case e contains free variables we need preliminary information about their types and this is provided by the type environment Γ ; as a result of the type inference this preliminary information may need to be modified as reported in the substitution S. Finally, C is a set of constraints that record the meaning of the annotation variables. For efficiency the algorithmic techniques often involve the generation of constraint systems in a program independent representation. In the case of polymorphic recursion decidability becomes an issue. Indeed, polymorphic recursion over type variables makes the polymorphic type system undecidable. It is therefore wise to restrict the polymorphic recursion to annotation variables only as in [44]. There the first stage is still ordinary type inference; the second stage [43] concerns an algorithm S that generates effect and region variables and an algorithm R that deals with the complications due to polymorphic recursion (for effects and regions only). The inference algorithm is proved syntactically sound but is known not to be syntactically complete; indeed, obtaining an algorithm that is syntactically sound as well as complete, seems beyond stateof-the-art. Once types and effects are allowed to be mutually recursive, the two-stage approach no longer works for obtaining an inference algorithm because the effects are used to control the shape of the underlying types (in the form of which type variables are included in a polymorphic type). This suggests a one-stage approach where special care needs to be taken when deciding the variables over which to generalise when constructing a polymorphic type. The main idea is that the algorithm needs to consult the constraints in order to determine a larger set of forbidden variables than those directly occurring in the type environment or the effect; this can be formulated as a downwards closure with respect to the constraint set [31,48] or by taking a principal solution of the constraints into account [39,40]. Adding subtyping to this development dramatically increases the complexity of the development. The integration of shape conformant subtyping, polymorphism and subeffecting is done in [3,31,35] that develop an inference algorithm that is proved syntactically sound; these papers aimed at integrating the techniques for polymorphism and subeffecting (but no subtyping) from effect systems [39,40,48] with the techniques for polymorphism and subtyping (but no effects) from type systems [16,37,38]. A more ambitious development where the inference system is massaged so as to facilitate developing an inference algorithm that is also syntactically complete is described in [1]; the inference system used there has explicit constraints in the inference system (as is usually the case in type systems based on subtyping).
Syntactic soundness and completeness. The syntactic soundness and completeness results to be established present a useful guide to developing the infer-
Type and Effect Systems
133
ence algorithm. Formulations of syntactic soundness are mostly rather straightforward: the result produced by the algorithm must give rise to a valid inference in the inference system. A simple example is the following: if W(Γ, e) = (S, τ, ϕ) then S(Γ ) ` e : τ & ϕ must hold; here it is clear that the substitution produced is intended to refine the initial information available when first calling the algorithm. A somewhat more complex example is: if W(Γ, e) = (S, τ, ϕ, C) then S 0 (S(Γ )) ` e : S 0 (τ ) & S 0 (ϕ) must hold whenever S 0 is a solution to the constraints in C. The proofs are normally by structural induction on the syntax of programs. The formulations of syntactic completeness are somewhat more involved. Given a program e such that Γ ` e : τ & ϕ , the main difficulty is to show how this can be obtained from W(Γ, e) = (S, τ, ϕ) or W(Γ, e) = (S, τ, ϕ, C). The solution is to formally define when one “typing” is an instance of another; the notion of lazy instance [9] is very useful here and in more complex scenarios Kripke-logical relations (see e.g. [28]) may be needed [1]. The proofs are often challenging and often require developing extensive techniques for “normalising” deductions made in the inference system so as to control the use of non-syntax directed rules. For sufficiently complex scenarios syntactic completeness may fail or may be open (as mentioned above); luckily soundness often suffices for the inference algorithm to be of practical use.
Exploitation. Exploitation is a rather open-ended area although it would seem that the integration of program analyses and program transformations into an inference based formulation is quite promising [46]. Indeed, inference-based formulations of analyses can be seen as an abstract counterpart of the use of attribute grammars when developing analyses in compilers, and in the same way inference-based formulations of analyses and transformations can be seen as an abstract counterpart of the use of attributed transformation grammars [47].
6
Conclusion
The approach based on type and effect systems is a promising approach to the static analysis of programs because the usefulness of types has already been widely established. The main strength lies in the ability to interact with the user: clarifying what the analysis is about (and when it may fail to be of any help) and in propagating the results back to the user in an understable way (which is not always possible for flow based approaches working on intermediate representations). The main areas of further research concern the expressiveness of the inference based specifications, the complexity and decidability of the inference algorithms and the interplay with the other approaches to static analysis of programs.
134
F. Nielson and H.R. Nielson
Acknowledgements. We wish to thank Torben Amtoft for working with us for many years on type and effect systems; we would also like to thank the referees for their careful reading and helpful comments.
References 1. T. Amtoft, F. Nielson, and H. R. Nielson. Type and Effect Systems: Behaviours for Concurrency. Imperial College Press, 1999. 2. T. Amtoft, F. Nielson, and H.R. Nielson. Type and behaviour reconstruction for higher-order concurrent programs. Journal of Functional Programming, 7(3):321– 347, 1997. 3. T. Amtoft, F. Nielson, H.R. Nielson, and J. Ammann. Polymorphic subtyping for effect analysis: The dynamic semantics. In Analysis and Verification of MultipleAgent Languages, volume 1192 of Lecture Notes in Computer Science, pages 172– 206. Springer, 1997. 4. P. N. Benton. Strictness logic and polymorphic invariance. In Proc. Second International Symposium on Logical Foundations of Computer Science, volume 620 of Lecture Notes in Computer Science, pages 33–44. Springer, 1992. 5. P. N. Benton. Strictness properties of lazy algebraic datatypes. In Proc. WSA ’93, volume 724 of Lecture Notes in Computer Science, pages 206–217. Springer, 1993. 6. L. Damas and R. Milner. Principal type-schemes for functional programs. In Proc. POPL ’82, pages 207–212. ACM Press, 1982. 7. K.-F. Fax´en. Optimizing lazy functional programs using flow inference. In Proc. SAS ’95, volume 983 of Lecture Notes in Computer Science, pages 136–153. Springer, 1995. 8. K.-F. Fax´en. Polyvariance, polymorphism, and flow analysis. In Proc. Analysis and Verification of Multiple-Agent Languages, volume 1192 of Lecture Notes in Computer Science, pages 260–278. Springer, 1997. 9. Y.-C. Fuh and P. Mishra. Polymorphic subtype inference: Closing the theorypractice gap. In Proc. TAPSOFT ’89, volume 352 of Lecture Notes in Computer Science, pages 167–183. Springer, 1989. 10. Y.-C. Fuh and P. Mishra. Type inference with subtypes. Theoretical Computer Science, 73:155–175, 1990. 11. N. Heintze. Control-flow analysis and type systems. In Proc. SAS ’95, volume 983 of Lecture Notes in Computer Science, pages 189–206. Springer, 1995. 12. Nevin Heintze and Jon G. Riecke. The SLam calculus: Programming with Secrecy and Integrity. In Proc. POPL ’98, pages 365–377. ACM Press, 1998. 13. F. Henglein and C. Mossin. Polymorphic binding-time analysis. In Proc. ESOP ’94, volume 788 of Lecture Notes in Computer Science, pages 287–301. Springer, 1994. 14. T. P. Jensen. Strictness analysis in logical form. In Proc. FPCA ’91, volume 523 of Lecture Notes in Computer Science, pages 352–366. Springer, 1991. 15. T. P. Jensen. Disjunctive strictness analysis. In Proc. LICS ’92, pages 174–185, 1992. 16. M. P. Jones. A theory of qualified types. In Proc. ESOP ’92, volume 582 of Lecture Notes in Computer Science, pages 287–306. Springer, 1992. 17. N. D. Jones and F. Nielson. Abstract Interpretation: a Semantics-Based Tool for Program Analysis. In Handbook of Logic in Computer Science volume 4. Oxford University Press, 1995.
Type and Effect Systems
135
18. P. Jouvelot. Semantic Parallelization: a practical exercise in abstract interpretation. In Proc. POPL ’87, pages 39–48, 1987. 19. P. Jouvelot and D. K. Gifford. Reasoning about continuations with control effects. In Proc. PLDI ’89, ACM SIGPLAN Notices, pages 218–226. ACM Press, 1989. 20. P. Jouvelot and D. K. Gifford. Algebraic reconstruction of types and effects. In Proc. POPL ’91, pages 303–310. ACM Press, 1990. 21. J. M. Lucassen and D. K. Gifford. Polymorphic effect analysis. In Proc. POPL ’88, pages 47–57. ACM Press, 1988. 22. R. Milner. A theory of type polymorphism in programming. Journal of Computer Systems, 17:348–375, 1978. 23. J. Mitchell. Type inference with simple subtypes. Journal of Functional Programming, 1(3):245–285, 1991. 24. F. Nielson. A formal type system for comparing partial evaluators. In D. Bjørner, A. P. Ershov, and N. D. Jones, editors, Proc. Partial Evaluation and Mixed Computation, pages 349–384. North Holland, 1988. 25. F. Nielson. The typed λ-calculus with first-class processes. In Proc. PARLE’89, volume 366 of Lecture Notes in Computer Science, pages 355–373. Springer, 1989. 26. F. Nielson and H. R. Nielson. Two-Level Functional Languages, volume 34 of Cambridge Tracts in Theoretical Computer Science. Cambridge University Press, 1992. 27. F. Nielson and H. R. Nielson. From CML to process algebras. In Proc. CONCUR’93, volume 715 of Lecture Notes in Computer Science, pages 493–508. Springer, 1993. 28. F. Nielson and H. R. Nielson. Layered predicates. In Proc. REX’92 workshop on Semantics — foundations and applications, volume 666 of Lecture Notes in Computer Science, pages 425–456. Springer, 1993. 29. F. Nielson and H. R. Nielson. From CML to its process algebra. Theoretical Computer Science, 155:179–219, 1996. 30. F. Nielson, H. R. Nielson, and C. L. Hankin. Principles of Program Analysis. Springer, 1999. 31. F. Nielson, H.R. Nielson, and T. Amtoft. Polymorphic subtyping for effect analysis: The algorithm. In Analysis and Verification of Multiple-Agent Languages, volume 1192 of Lecture Notes in Computer Science, pages 207–243. Springer, 1997. 32. H. R. Nielson, T. Amtoft, and F. Nielson. Behaviour analysis and safety conditions: a case study in CML. In Proc. FASE ’98, number 1382 in Lecture Notes in Computer Science, pages 255–269. Springer, 1998. 33. H. R. Nielson and F. Nielson. Higher-Order Concurrent Programs with Finite Communication Topology. In Proc. POPL ’94. Springer, 1994. 34. H. R. Nielson and F. Nielson. Communication analysis for Concurrent ML. In F. Nielson, editor, ML with Concurrency, Monographs in Computer Science, pages 185–235. Springer, 1997. 35. H.R. Nielson, F. Nielson, and T. Amtoft. Polymorphic subtyping for effect analysis: The static semantics. In Analysis and Verification of Multiple-Agent Languages, volume 1192 of Lecture Notes in Computer Science, pages 141–171. Springer, 1997. 36. G. D. Plotkin. A structural approach to operational semantics. Technical Report FN-19, DAIMI, Aarhus University, Denmark, 1981. 37. G. S. Smith. Polymorphic inference with overloading and subtyping. In Proc. TAPSOFT ’93, volume 668 of Lecture Notes in Computer Science, pages 671–685. Springer, 1993. 38. G. S. Smith. Polymorphic type schemes for functional programs with overloading and subtyping. Science of Computer Programming, 23:197–226, 1994.
136
F. Nielson and H.R. Nielson
39. J.-P. Talpin and P. Jouvelot. The type and effect discipline. In Proc. LICS ’92, pages 162–173, 1992. 40. J.-P. Talpin and P. Jouvelot. The type and effect discipline. Information and Computation, 111(2):245–296, 1994. 41. Y.-M. Tang. Control-Flow Analysis by Effect Systems and Abstract Interpretation. PhD thesis, Ecole des Mines de Paris, 1994. 42. M. Tofte. Type inference for polymorphic references. Information and Computation, 89:1–34, 1990. 43. M. Tofte and L. Birkedal. A region inference algorithm. ACM TOPLAS, 20(3):1– 44, 1998. 44. M. Tofte and J.-P. Talpin. Implementing the call-by-value lambda-calculus using a stack of regions. In Proc. POPL ’94, pages 188–201. ACM Press, 1994. 45. M. Tofte and J.-P. Talpin. Region-based memory management. Information and Computation, 132:109–176, 1997. 46. M. Wand. Specifying the correctness of binding-time analysis. In Proc. POPL ’93, pages 137–143, 1993. 47. R. Wilhelm. Global flow analysis and optimization in the MUG2 compiler generating system. In S. S. Muchnick and N. D. Jones, editors, Program Flow Analysis: Theory and Applications, chapter 5. Prentice Hall International, 1981. 48. A. K. Wright. Typing references by effect inference. In Proc. ESOP ’92, volume 582 of Lecture Notes in Computer Science, pages 473–491. Springer, 1992. 49. A. K. Wright and M. Felleisen. A syntactic approach to type soundness. Information and Computation, 115:38–94, 1994.
Proving Theorems About Java-Like Byte Code J Strother Moore Department of Computer Sciences University of Texas at Austin Austin, Texas 78712 USA [email protected], WWW home page: http://www.cs.utexas.edu/users/moore
Abstract. We describe a formalization of an abstract machine very similar to the Java Virtual Machine but far simpler. We develop techniques for specifying the properties of classes and methods for this machine. We develop techniques for mechanically proving theorems about classes and methods. We discuss two such proofs, that of a static method implementing the factorial function and of an instance method that destructively manipulates objects in a way that takes advantage of inheritance. We conclude with a brief discussion of the advantages and disadvantages of this approach. The formalization and proofs are done with the ACL2 theorem proving system.
1
Specification of the TJVM
The Java Virtual Machine (JVM) [10] is a stack-based, object-oriented, type-safe byte-code interpreter on which compiled Java programs are executed. We develop a simplified JVM for the purpose of exploring verification issues related to proofs about object-oriented byte code. We refer to our machine as a “toy JVM” or “TJVM.” Because we are interested in formal, mechanically checked proofs, we formalize the TJVM in a formal, mechanized logic, namely ACL2: A Computational Logic for Applicative Common Lisp. The tradition of formalizing machines in ACL2, and its predecessor, Boyer and Moore’s Nqthm, is well established [1,14,11,3,5] and we follow in those well-trodden footsteps. Indeed, our TJVM is just a simplification of Rich Cohen’s “defensive JVM,” [6], which was formalized at Computational Logic, Inc., in the standard ACL2/Nqthm style. That style employs an operational semantics, in which the state of the machine is represented as a Lisp object. An interpreter for the machine’s programming language is defined as a Lisp function. The main purpose of this paper is to illustrate how those established techniques can be applied in an object-oriented setting. This paper provides a brief sketch of our TJVM. The details may be obtained at http://www.cs.utexas.edu/users/moore/publications/tjvm/index.html. The state of the TJVM is a triple consisting of a call stack of “frames,” a heap, and a class table. A frame contains four fields, a program counter, a variable binding environment called the locals of the frame, an operand stack, and the E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 139–162, 1999. c Springer-Verlag Berlin Heidelberg 1999
140
J S. Moore
byte code program of the method being evaluated. The heap is an association of integer addresses to “objects,” which are “instances” of classes. An instance is a list of n tables, one for each of the n superclasses of the object. Each table enumerates the fields of a given class and specifies the contents of those fields in this particular instance. Finally, the class table is a list of class declarations, each of which specifies a class name, the names of its superclasses, the names of its fields, and the “method declarations” of the class. A method declaration specifies a method name, its formal parameters, and the byte coded body of the method. Readers familiar with the JVM will recognize the TJVM as a similar machine. Here is a Java program for computing the factorial function. public static int fact(int n){ if (n>0) {return n*fact(n-1);} else return 1; }
Here is an example of a TJVM method declaration corresponding to the compiled code for fact above. The comments (on the right, following the semicolons) indicate the TJVM program counter of the instruction and the JVM byte code produced by Sun’s Java compiler. Fact: ("fact" (n) (load n) (ifle 8) (load n) (load n) (push 1) (sub) (invokestatic "Math" "fact" 1) (mul) (xreturn) (push 1) (xreturn))
; 0 ; 1 ; 2 ; 3 ; 4 ; 5 ; 6 ; ; 7 ; 8 ; 9 ; 10
iload 0 ifle 12 iload 0 iload 0 iconst 1 isub invokestatic <Method int fact(int)> imul ireturn iconst 1 ireturn
This method declaration, Fact, might be found in the class declaration of the "Math" class on the TJVM. The name of the method is "fact". It has one formal parameter, n, and a byte code program of eleven instructions. Fact is actually a Lisp constant whose first element is the string "fact", whose second element is the list containing the single symbol n, etc. We discuss later the correspondence between TJVM byte codes and JVM byte codes, but a shallow correspondence is obvious. On the TJVM, methods refer to their local variables by name; on the JVM methods refer to their locals by position. The “8” in the TJVM ifle instruction is an instruction offset by which the program counter is incremented. The corresponding offset on the JVM counts bytes rather than instructions and some JVM instructions take more than
Proving Theorems About Java-Like Byte Code
141
one byte. Finally, the JVM has typed instructions, e.g., the JVM’s iload loads an integer-valued variable on the stack while the TJVM’s load loads any value. When this program is invoked on the TJVM, one actual parameter, n, is popped from the operand stack of the topmost frame of the TJVM call stack; a new frame is built and pushed onto the call stack of the TJVM state. The new frame has program counter 0 and the eleven instructions above as the program. The locals of the new frame bind n to the actual n. The operand stack of the new frame is empty. The program operates as follows. The parenthesized numbers refer to program counter values. (0) The local value, n, of n is pushed onto the operand stack. (1) The ifle instruction pops the operand stack and compares the item obtained, here n, to 0. If n ≤ 0, the program counter is incremented by 8; otherwise it is incremented by 1. (9-10) In the former case, the program pushes a 1 on the operand stack and returns one result to the caller. The JVM uses a special, single byte instruction for pushing the constant 1, while the TJVM has one general-purpose push instruction for pushing any constant. (2) In the case that n > 0, the program pushes n, (3-5) pushes n − 1 (by (3) pushing n and (4) 1 and (5) executing a sub which pops two items off the operand stack and pushes their difference), (6) invokes this procedure recursively on one actual, in this case, the n − 1 on the stack, obtaining one result, here (n − 1)!, which is pushed on the stack in place of the actual, (7) multiplies the top two elements of the stack, and (8) returns that one result to the caller. From the above description it should be clear how we define the semantics of the instructions illustrated above. For example, here is the function which gives semantics to the add instruction, (add). (defun execute-ADD (inst s) (declare (ignore inst)) (make-state (push (make-frame (+ 1 (pc (top-frame s))) (locals (top-frame s)) (push (+ (top (pop (stack (top-frame s)))) (top (stack (top-frame s)))) (pop (pop (stack (top-frame s))))) (program (top-frame s))) (pop (call-stack s))) (heap s) (class-table s)))
This Lisp function – which in the ACL2 setting is taken as an axiom defining the expression (execute-ADD inst s) – takes two arguments, the add instruction to be interpreted and the TJVM state s. Because the TJVM add instruction has no operands, execute-ADD does not actually need the instruction and so inst above is ignored. The function computes the state obtained from s by executing an add. The new state contains a modified call stack but the same heap and class table as s. The call stack is modified by changing only its topmost frame so that the program counter is incremented by one and the operand stack is modified by popping two items off of it and pushing their sum. The locals and program
142
J S. Moore
of the frame are unchanged. We call execute-ADD the semantic function for the TJVM add instruction. Each instruction on the TJVM is defined by an analogous semantic function. The semantic function for the instruction (new "class"), which constructs a new instance of the class named "class", is shown below. The instruction takes as its single argument the name of a class. On our TJVM, new builds a new, uninitialized instance of that class, allocating some address in the heap for that instance and leaving that address on the top of the stack in the top frame of the call stack. (defun execute-NEW (inst s) (let* ((class (arg1 inst)) (table (class-table s)) (obj (build-an-instance (cons class (class-decl-superclasses (bound? class table))) table)) (addr (length (heap s)))) (make-state (push (make-frame (+ 1 (pc (top-frame s))) (locals (top-frame s)) (push (list ’REF addr) (stack (top-frame s))) (program (top-frame s))) (pop (call-stack s))) (bind addr obj (heap s)) (class-table s))))
In the ACL2 definition above, inst is the new instruction to be executed, and s is the state to be “modified.” The let* in the definition above just binds four variables and then evaluates the make-state expression in the “body” of the let*. The first variable, class, is bound to the class name in the instruction. The second variable, table, is bound to the class table of the state s. This table contains a description of all the loaded classes, their fields and their methods. The third variable, obj, is the uninitialized instance object constructed by new. Logically speaking, it is constructed by the ACL2 function build-an-instance from the superclass chain of class (starting with class) and the class table. The fourth variable, addr is the heap address at which obj will be placed. In the TJVM, this just the number of objects allocated so far. The state constructed by execute-NEW above modifies the top frame of the call stack of s and also modifies the heap of s. The class table of s is unchanged. In the modified top frame, the program counter is incremented and a reference to addr is pushed onto the operand stack. (Note that the address is “tagged” with the symbol REF so that it is possible on the TJVM to distinguish integers from references to heap addresses.) In the modified heap, the new instance object, obj, is associated with the address addr.
Proving Theorems About Java-Like Byte Code
143
The semantic function for the instruction (invokevirtual "class" "name" n) is shown below. Invokevirtual is the most complicated instruction on the TJVM. It invokes a named method, name, on a given number, n, of parameters. The n parameters are obtained from the operand stack. But the method invoked is determined by “method resolution,” which is a function of the class of the object to which the method is applied. This object is denoted, both in Java and the TJVM, by the value of the variable symbol this. The “this” object is in essence an n + 1st parameter and is the deepest one on the operand stack at the time of call but it is special because of its role in method resolution. (defun execute-INVOKEVIRTUAL (inst s) (let* ((name (arg2 inst)) (n (arg3 inst)) (ref (top (popn n (stack (top-frame s))))) (class (class-name-of-ref ref (heap s))) (method (lookup-method name class (class-table s))) (vars (cons ’this (method-formals method))) (prog (method-program method))) (make-state (push (make-frame 0 (reverse (bind-formals (reverse vars) (stack (top-frame s)))) nil prog) (push (make-frame (+ 1 (pc (top-frame s))) (locals (top-frame s)) (popn (length vars) (stack (top-frame s))) (program (top-frame s))) (pop (call-stack s)))) (heap s) (class-table s))))
In the ACL2 function above, name and n are the name of the method to be invoked and the number of parameters (not counting the “this” object). The instruction obtains a reference, ref , to the “this” object of the invocation by looking down the operand stack an appropriate distance, given n, the number of formals of the named method. It then obtains the class, class, of the referenced object and uses the given method name and object class to determine the nearest appropriate method, method, using the ACL2 function lookup-method, which formalizes method resolution. Let vars be the formal parameters of the resolved method, extended with one additional formal, named this, and let prog be the byte code program for method. The instruction then modifies the existing top frame of the call stack by incrementing the program counter and popping n+1 items off the operand stack.
144
J S. Moore
It then pushes a new frame poised to execute the resolved method, initializing the locals in the new frame by binding vars to the items just popped. Recall that our fact method used the instruction invokestatic. That instruction is similar to invokevirtual but does not involve a “this” object. Static method resolution is based on the class name used in the invokestatic instruction. Observe that the class name argument in the invokevirtual instruction is ignored (the ACL2 function above does not use (arg1 inst)). Why is it provided in the first place? This is a reflection of the design of the JVM (as opposed to an oddity in the TJVM). The JVM provides a class argument in invokevirtual and the argument is irrelevant to the semantics of the instruction. But the argument is used in the implementation (via dispatch vectors) to make method resolution faster. A nice little “metatheorem” one can prove about the TJVM is that in a properly configured implementation lookup-method finds the same method identified by the dispatch vector algorithm. Such a theorem was proved by Bill Young and Rich Cohen about Cohen’s dJVM. After defining a semantic function for each TJVM instruction, we define: (defun do-inst (inst s) (case (op-code inst) (PUSH (execute-PUSH inst s)) (POP (execute-POP inst s)) (LOAD (execute-LOAD inst s)) (STORE (execute-STORE inst s)) (ADD (execute-ADD inst s)) (SUB (execute-SUB inst s)) (MUL (execute-MUL inst s)) (GOTO (execute-GOTO inst s)) (IFEQ (execute-IFEQ inst s)) (IFGT (execute-IFGT inst s)) (INVOKEVIRTUAL (execute-INVOKEVIRTUAL inst s)) (INVOKESTATIC (execute-INVOKESTATIC inst s)) (RETURN (execute-RETURN inst s)) (XRETURN (execute-XRETURN inst s)) (NEW (execute-NEW inst s)) (GETFIELD (execute-GETFIELD inst s)) (PUTFIELD (execute-PUTFIELD inst s)) (HALT s) (otherwise s)))
so that (do-inst inst s) returns the state obtained by executing inst in state s. The definition enumerates the instructions supported on the TJVM and calls the appropriate semantic function. Each of the supported instructions is modeled after one or more JVM instructions. TJVM instructions are generally simpler than their JVM counterparts. For example, we are not concerned with access attributes, types, resource limitations, or exceptions on the TJVM. The TJVM classes provide for “instance fields” but do not provide the JVM’s “static fields.” Unlike their counterparts on the JVM,
Proving Theorems About Java-Like Byte Code
145
our INVOKEVIRTUAL and INVOKESTATIC do not take “signatures.” On the JVM, a method’s “this” object is in local variable 0; on the TJVM it is an implicit formal parameter named this. Like its JVM counterpart, the method actually invoked by our INVOKEVIRTUAL depends on the “this” object: both invoke the nearest method of the given name found in the superclass chain of the object, but the JVM discriminates between candidate methods via their signatures and we do not. That is, the JVM supports “overloading” and the TJVM does not. The “single stepper” for the TJVM is (defun step (s) (do-inst (next-inst s) s))
where next-inst retrieves the instruction indicated by the program counter in the topmost frame of the call stack. The TJVM is then defined as an iterated step function: (defun tjvm (s n) (if (zp n) s (tjvm (step s) (- n 1))))
Thus (tjvm s n) is the result of applying step to s n times, or (stepn s). The TJVM can be viewed as a simplification of the JVM. The TJVM is in fact a simplification of Rich Cohen’s “defensive JVM”, [6], which includes many more JVM instructions and deals carefully with the preconditions assumed for each instruction. In principle, Cohen’s specification could be used to analyze whether a given byte code verifier is sufficient to guarantee the absence of certain classes of runtime errors. Both the TJVM and the defensive JVM omit major aspects of the JVM, including floating point numbers, arrays, multiple threads, exceptions, and native methods. All but native methods could be formalized in an implementation independent way, following the basic approach.
2
Example TJVM Executions
Having defined the TJVM in Lisp, it is possible to execute it on concrete data. Consider the byte code for the "fact" program shown earlier in the constant Fact. Let Math-class denote the list constant partially displayed below. Math-class: ("Math" ("Object") () (... Fact ...)).
This is a class declaration for a class called "Math" which is an extension of the class named "Object" (literally, the declaration says that the superclass chain of "Math" is the list containing only the class named "Object"). The "Math" class contains no fields and its methods are those listed and include Fact. Consider the TJVM state
146
J S. Moore
s0 : (make-state (push (make-frame 0 nil nil ’((push 5) (invokestatic "Math" "fact" 1) (halt))) nil) nil ’( Math-class))
This state is poised to execute the three instruction program above, starting with the (push 5) at program counter 0. Note that the program pushes 5 on the stack and then invokes "fact". The class table for the state includes our Math-class, so "fact", here, means the byte code given in Fact. The Lisp expression (top (stack (top-frame (tjvm s0 52)))) steps s0 52 times, and then recovers the topmost item on the operand stack of the topmost frame of the call stack. Evaluating this expression produces 120, which is indeed 5!. How did we know to take 52 steps? The answer is: by analysis of the code in Fact. The following function, which we call the “clock function” for "fact", returns the number of TJVM instructions required to execute (invokestatic "Math" "fact" 1) on n. The function was written based on an inspection of the byte code in Fact. (defun fact-clock (n) (if (zp n) 5 (++ 7 (fact-clock (- n 1)) 2)))
Here, ++ is just the normal arithmetic addition function. Fact-clock has been written this way (rather than 5 + 9n) to make it obvious how such functions are generated. To execute a call of "fact" on 5 evidently takes 50 TJVM cycles (including the call). Thus, the program in s0 takes 52 cycles.
3
Proofs About TJVM Programs
Of more interest than mere execution is the following theorem we can prove about "fact". Theorem. "fact" is correct: Suppose s0 is a TJVM state whose next instruction is (invokestatic "Math" "fact" 1), where the meaning of the name "Math" in the class table is our Math-class. Let n be the top of the operand stack in the
Proving Theorems About Java-Like Byte Code
147
topmost frame of the call stack of s0 and suppose n is a natural number. Then the TJVM state obtained by stepping s0 (fact-clock n) times is state s0 with the program counter incremented by one and the n on the operand stack replaced by n!. The heap is unchanged. This informal statement can be phrased formally as follows. Theorem. "fact" is correct: (implies (and (equal (next-inst s0 ) ’(invokestatic "Math" "fact" 1)) (equal (assoc-equal "Math" (class-table s0 )) Math-class) (equal n (top (stack (top-frame s0 )))) (natp n)) (equal (tjvm s0 (fact-clock n)) (make-state (push (make-frame (+ 1 (pc (top-frame s0 ))) (locals (top-frame s0 )) (push (fact n) (pop (stack (top-frame s0 )))) (program (top-frame s0 ))) (pop (call-stack s0 ))) (heap s0 ) (class-table s0 ))))
The theorem states the total correctness of the "fact" byte code. Weaker theorems can be stated and proved, but we here focus on theorems of this kind because they are easiest to prove. We proved this theorem in a very straightforward manner using ACL2. The proof takes 0.33 seconds on a 200 MHz Sun Ultra 2. The theorem only looks complicated because the notation is unfamiliar! ACL2 is an automatic theorem prover in the sense that its behavior on any given proof attempt is determined by its state immediately prior to the attempt, together with goal-specific hints provided by the user. Of great importance is the set of lemmas the system has already proved. Those lemmas determine how ACL2 simplifies expressions. To configure ACL2 to prove theorems about TJVM we followed the example described in [3]. Roughly speaking, we did the following: – We proved half a dozen simple arithmetic lemmas; we could have loaded any of several standard ACL2 arithmetic “books.” – We proved lemmas that let ACL2 manipulate the data structures used on the TJVM, including stacks, frames, and states, as abstract data structures. One such theorem is (top (push x stack)) = x. We then “disabled” the definitions of the primitive stack, frame, and state functions so that their “implementations” in terms of conses were not visible. – We proved the standard theorem for expanding the single step function, step, when the next-inst is explicit. We then disabled the step function. This prevents case explosion on what the next instruction is.
148
J S. Moore
– We defined the standard “clock addition” function, ++, which is really just natural number addition, and disabled it. This allows us to define clock function in the structured style illustrated fact-clock and prevents the arithmetic rules from rearranging the expressions and destroying the structural “hints” implicit in the definitions. We proved the rules that allow tjvm expressions to be decomposed according to their clock expressions. For example, (tjvm s (++ i j)) is rewritten to (tjvm (tjvm s i) j). Thus, when ACL2 encounters, for example, (tjvm s0 (++ 7 (fact-clock (- n 1)) 2)) it decomposes it into a run of length seven, followed by a run of length (fact-clock (- n 1)), followed by a run of length two, and each run must be fully simplified to a symbolic state before the next can be simplified (because of the way the step function has been limited). – Finally we prove the standard “memory management” rules, which in the case of the TJVM tell us the algebra of association lists (used to bind variables, associate programs with method names, method names with methods, fields with their contents, etc.). Having so configured ACL2, the theorem about "fact" above is proved by giving the theorem prover a single hint, namely to do the induction that unwinds the code in "fact". It is important to realize that the theorem above about "fact" contributes to the further configuration of ACL2 in this capacity. The theorem causes the following future behavior of ACL2: Suppose the system encounters an expression of the form (tjvm α (fact-clock β)) to simplify. Then it first determines whether the next instruction of the state α is (invokestatic "Math" "fact" 1) where the meaning of "Math" in α is our Math-class, and whether β is on top of the operand stack of α and is a natural number. If so, it replaces (tjvm α (fact-clock β)) by the corresponding make-state expression in which the program counter has been incremented by one and β has been replaced by (fact β). Thus, after this theorem is proved, the theorem prover no longer looks at the code for "fact". It steps over (invokestatic "Math" "fact" 1) as though it were a primitive instruction that computes the factorial of the top of the stack. The verification of a system of methods is no harder than the combined verification of each method in the system. This remark, while trivial, has profound consequences if one clearly views the software verification problem as the specification and verification of the component pieces.
4
More Example TJVM Executions
The "fact" method does not affect the heap. That is, it does not create any new objects or modify existing objects. How does our verification strategy cope with that? We will consider a simple example of a heap modifying method. But we first illustrate such methods by simple execution. Consider the following TJVM class declaration for a class named "Point", which extends the "Object" class
Proving Theorems About Java-Like Byte Code
149
and has two fields, named "x" and "y". Instances of the "Point" class represent points in the Cartesian plane. Point-class: ("Point" ("Object") ("x" "y") (xIncrement inBox))
Notice that the class has two methods. The first is defined by the list constant: xIncrement: ("xIncrement" (dx) (load this) (load this) (getfield "Point" "x") (load dx) (add) (putfield "Point" "x") (return))
; ; ; ; ; ; ;
0 1 2 3 4 5 6
We discuss this method now and will display the second constant, inBox, later. The method "xIncrement" is an “instance method.” It has an implicit formal parameter, this, and one explicit parameter, dx. When "xIncrement" is called with invokevirtual, two items are expected on the operand stack of the caller. The deeper of the two is expected to be an instance of some class and is used to select which method named "xIncrement" is actually run. That instance object is bound to the parameter this in the newly built frame and the other item on the stack is bound to the variable dx. The byte code above increments the "x" field of this by the amount dx. Ignore for a moment the load instruction at 0. Instructions 1 and 2 push the contents of the "x" field onto the operand stack. Instruction 3 pushes dx and instruction 4 adds the two together, leaving the sum on the stack. The load instruction we ignored above, at 0, has pushed a reference to the this object onto the stack, now just under the sum. The putfield at 5 deposits the sum into the "x" field of that object, changing the heap. The return at 6 returns (no results) to the caller (i.e., this method is of return type “void”). It is convenient whenever we define a method to define the corresponding clock function for it. In the case of "xIncrement", which consists seven primitive, non-branching byte codes, the clock function is constant and returns 8. (Our convention is that the clock for a method includes the cycle for the byte code that invokes it.) Before discussing the inBox method, we consider an extension to the "Point" class, called the "ColoredPoint" class. Here is the list constant denoting the TJVM declaration of that class. ColoredPoint-class: ("ColoredPoint" ("Point" "Object") ("color") (setColor setColorBox))
150
J S. Moore
The class extends "Point" (and thus "Object") and provides the new field "color" and two methods. The first is called "setColor" and is defined below. It sets the "color" of a "ColoredPoint". The clock for this method returns 5. setColor: ("setColor" (c) (load this) (load c) (putfield "ColoredPoint" "color") (return))
Consider the TJVM state s1 : (make-state (push (make-frame 0 ’((p . nil)) nil ’((new "ColoredPoint") (store p) (load p) (push -23) (invokevirtual "ColoredPoint" "xIncrement" 1) (load p) (push "Green") (invokevirtual "ColoredPoint" "setColor" 1) (load p) (halt))) nil) nil ’(Point-class ColoredPoint-class))
This state is poised to execute the ten instruction program above, with one local, p, which is initially nil. The class table of the state contains both "Point" and its extension "ColoredPoint". Inspection of the code above shows that it creates a new "ColoredPoint" and stores it into p. It then invokes "xIncrement" to increment the "x" field of p by -23 and invokes "setColor" to set the "color" field of p to "Green". Of interest is the fact that the first method is in the class "Point" and the second is in the class "ColoredPoint". The "ColoredPoint" p inherits the fields and methods of its superclass, "Point". Had the "ColoredPoint" class overridden the method "xIncrement" by including the definition of such a method, then the program above would have invoked that method rather than the one in "Point", since the method is selected by searching through the superclass chain of the this object of the invocation, which is here p, an object of class "ColoredPoint". Consider, s’1 , the result of running the TJVM on s1 for 21 steps, s’1 : (tjvm s1 21).
Proving Theorems About Java-Like Byte Code
151
“21” is obtained by adding up the clocks for each instruction above. Of interest is (deref (top (stack (top-frame s’1 ))) (heap s’1 )). This expression dereferences the topmost item on the operand stack of s’1 , with respect to the heap of that state. The topmost item on the stack is, of course, the reference that is the value of the local p. That reference was created by new at the beginning of the program. Dereferencing it through the final heap produces the “logical meaning” of p at the conclusion of the program. The result is (("ColoredPoint" ("color" . "Green")) ("Point" ("x" . -23) ("y" . 0)) ("Object"))
This is an instance in the ACL2 semantics of the TJVM. It represents an object of class "ColoredPoint". It enumerates the fields of that class and of all its superclasses and specifies the value of each field. We see that at the conclusion of the program above the "color" of the object is set to "Green", the "x" field (in the "Point" superclass) is set to -23 as a result of our "xIncrement" and the "y" field is set to (the “uninitialized” value) 0. The "Object" class in the TJVM has no fields.
5
Proving Theorems About Objects
Our "Point" class contains a second method, called "inBox", which determines whether its this object is within a given rectangle in the plane. The rectangle is specified by two points, p1 and p2, which are the lower-left and upper-right corners of the box. Here is the definition of the method. inBox: ("inBox" (p1 p2) (load p1) (getfield "Point" (load this) (getfield "Point" (sub) (ifgt 21) (load this) (getfield "Point" (load p2) (getfield "Point" (sub) (ifgt 15) (load p1) (getfield "Point" (load this) (getfield "Point" (sub) (ifgt 9) (load this)
"x") "x")
"x") "x")
"y") "y")
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
152
J S. Moore (getfield "Point" "y") (load p2) (getfield "Point" "y") (sub) (ifgt 3) (push 1) (xreturn) (push 0) (xreturn))
; ; ; ; ; ; ; ; ;
19 20 21 22 23 24 25 26 27
This is a straightforward compilation (for the TJVM) of the following Java (which is written in a slightly awkward style to make the correspondence with the byte code more clear). public boolean inBox(Point p1, Point p2){ if (p1.x <= this.x & this.x <= p2.x & p1.y <= this.y & this.y <= p2.y) {return true;} else {return false;}}
We will specify and prove the correctness of this method in a moment. But we must develop some Lisp functions for dealing with points and in so doing illustrate our preferred style for dealing with TJVM objects in general, at the logical level. Consider the two Lisp functions below for retrieving the x- and y-coordinates of a point. (defun Point.x (ref s) (field-value "Point" "x" (deref ref (heap s)))) (defun Point.y (ref s) (field-value "Point" "y" (deref ref (heap s))))
Observe that they take the TJVM state, s, as arguments. That is because we apply them to references to Points, not to instances. Had we chosen the latter course, we would have defined Point.x as (defun Point.x (p) (field-value "Point" "x" p))
but would have to call it by writing (Point.x (deref ref (heap s))). We belabor this point for a reason: when defining the Lisp concepts necessary to speak formally about TJVM objects should we focus on references or on instances? If we focus on references, we must also have available the state, or at least the heap, with respect to which those references are to be dereferenced. This is the choice we have made and yet it seems complicated. The problem with focusing on instances is that instances may contain references. Thus, even if we focus on instances the heap is still relevant. This does not
Proving Theorems About Java-Like Byte Code
153
arise with "Point" instances because their fields do not contain references. But consider the class "LinkedList", with two fields, "head" and "next". Suppose the "next" field generally contains a (reference to a) "LinkedList" instance. Then a typical instance of "LinkedList" might be: (("LinkedList" ("head" . 1) ("next" . (REF 45))) ("Object")).
Since the object itself might be “circular” we cannot, in general, replace (REF 45) by the instance to which it dereferences. Thus, we see that while instances may be more convenient than references for simple classes like "Point", they are no more convenient than references in general. We therefore chose references because it tends to induce a uniform style in the definition of the logical functions for manipulating objects, that style being to dereference the reference with respect to the state, use the resulting instance and then recursively deal with the interior references. This means that the Lisp formalization of the semantics of a TJVM method may very closely resemble the algorithm implemented by the byte code. This is convenient because the verification of a method generally takes place in two steps. In the first step we prove that the interpretation of the byte code produces the same TJVM state transformation as described at a higher level by the Lisp function. In the second step we prove that the Lisp function enjoys some desirable properties. The first step is complicated by the semantics of the byte code interpreter and so it is convenient for the Lisp to be “close” to the byte code. Once we have gotten away from the byte code to the simpler applicative Lisp world, we deal with the complexity of proving that the Lisp “does the right thing.” In this paper we do not further consider instances that reference other instances. We next consider the "inBox" method and focus on its “clock function.” How many TJVM cycles are required to execute an invocation of that method? We can express the clock function for "inBox" with: (defun inBox-clock (this p1 p2 s) (cond ((> (Point.x p1 s) (Point.x this s)) 9) ((> (Point.x this s) (Point.x p2 s)) 15) ((> (Point.y p1 s) (Point.y this s)) 21) (t 27)))
Despite the apparent simplicity of the "inBox" method, the time it takes depends not only on the inputs this, p1 , and p2 , but on the state in which it is called. This is unavoidable since the very meaning of references to objects change as the heap changes.
154
J S. Moore
What theorem might we wish to prove about "inBox"? The obvious theorem is that it returns 1 or 0 (the TJVM and JVM “booleans”) according to whether the this object is within the box defined by p1 and p2. We define the Lisp function inBox as follows: (defun inBox (this p1 p2 s) (and (<= (Point.x p1 s) (Point.x this s)) (<= (Point.x this s) (Point.x p2 s)) (<= (Point.y p1 s) (Point.y this s)) (<= (Point.y this s) (Point.y p2 s))))
Observe that the Lisp inBox predicate is dependent upon the TJVM state with respect to which the TJVM objects are dereferenced. Again, this is unavoidable. Even though the references to the three points in question are constants, the x-y locations of the denoted points may change over time and whether a point is in a given box is, quite literally, a function of the TJVM state. (Indeed, the locations may be changed even by methods that are not directly passed these three references because other objects in the heap may contain these references.) Before we state the correctness of the "inBox" method formally we do so informally. Our first statement, below, is just an approximation, modeled on the theorem we proved about "fact". First Approximation Suppose s0 is a TJVM state whose next instruction is (invokevirtual "Point" "inBox" 2), where the meaning of the name "Point" in the class table is our Point-class. Let this be the third item on the operand stack, let p1 be the second item, and let p2 be the topmost item. Then the TJVM state obtained by stepping s0 (inBox-clock this p1 p2 s0 ) times is state just s0 with the program counter incremented by one and the three items removed from the operand stack and replaced by 1 or 0 according to whether (inBox this p1 p2 s0 ). The heap is unchanged. This approximation is inadequate in two respects. First, we are not concerned with the just the instruction (invokevirtual "Point" "inBox" 2) but in any instruction of the form (invokevirtual class "inBox" 2). A careful reading of the semantic function for invokevirtual reveals that the semantics is independent of the first operand of the instruction! The actual method invoked is the one named "inBox" in the superclass chain of the “this” object, not the method named "inBox" in the class named in the invokevirtual instruction.1 Therefore, rather than require that (next-inst s0 ) be (invokevirtual 1
This is also true of the JVM invokevirtual instruction. The reason invokevirtual has that operand is so that in a JVM implementation the given class name can be used to find a “dispatch vector” associated with the named class to shortcut the search up the superclass chain.
Proving Theorems About Java-Like Byte Code
155
"Point" "inBox" 2) we require that it be a list whose first, third and fourth elements are invokevirtual, "inBox" and 2, respectively. The second change to this approximation is that we must insist that the method found by looking up the superclass chain of this be inBox. In particular, just because we invoke "inBox" in a TJVM state in which "Point" is defined as above, do we know that the resolved method will be inBox? No! The superclass chain of this might include a class that overrides "inBox" and defines it a different way. If we add the hypothesis that the resolved method is inBox then we may delete the hypothesis, in our approximation above, requiring that "Point" be as defined here: it does not matter how "Point" is defined as long as the resolved method is our inBox. Theorem. "inBox" is correct: Suppose s0 is a TJVM state whose next instruction is of the form (invokevirtual class "inBox" 2). Let this be the third item on the operand stack, let p1 be the second item, and let p2 be the topmost item. Suppose the nearest method named "inBox" in the superclass chain of this is inBox. Then the TJVM state obtained by stepping s0 (inBox-clock this p1 p2 s0 ) times is state s0 with the program counter incremented by one and the three items removed from the operand stack and replaced by 1 or 0 according to whether (inBox this p1 p2 s0 ). The heap is unchanged. Here is the formal rendering of the theorem: Theorem. "inBox" is correct: (implies (and (consp (next-inst s0 )) (equal (car (next-inst s0 )) ’invokevirtual) (equal (caddr (next-inst s0 )) "inBox") (equal (cadddr (next-inst s0 )) 2) (equal this (top (pop (pop (stack (top-frame s0 )))))) (equal p1 (top (pop (stack (top-frame s0 ))))) (equal p2 (top (stack (top-frame s0 )))) (equal (lookup-method "inBox" (class-name-of-ref this (heap s0 )) (class-table s0 )) inBox)) (equal (tjvm s0 (inBox-clock this p1 p2 s0 )) (make-state (push (make-frame (+ 1 (pc (top-frame s0 ))) (locals (top-frame s0 )) (push (if (inBox this p1 p2 s0 ) 1 0) (popn 3 (stack (top-frame s0 )))) (program (top-frame s0 ))) (pop (call-stack s0 ))) (heap s0 ) (class-table s0 ))))
156
J S. Moore
This theorem is proved by straightforward symbolic evaluation, i.e., the repeated unfolding of the definition of tjvm, together with Boolean and arithmetic simplification. Once proved, how is this theorem used? Suppose the ACL2 rewriter encounters a call of tjvm in which the second argument is an inBox-clock expression. (Previously proved rules about tjvm will insure that arithmetic combinations of such expressions are decomposed into appropriate nests of tjvm expressions applied to these clock functions.) Then the rewriter tries to establish that the next-inst of the TJVM state is an invokevirtual of "inBox" and the resolved method named "inBox" in the superclass chain of the this object is inBox. These actions are caused by backchaining. The three hypotheses equating this, p1 , and p2 to stack expressions are not restrictive: they are established by binding this, p1 , and p2 to the corresponding expressions. Provided the hypotheses are established, the rewriter then replaces the target call of tjvm by a new state expression in which the program counter is advanced by one, the three actuals of "inBox" are removed from the stack and the appropriate value is pushed. Thus, as with our earlier theorem about "fact", this theorem configures ACL2 to simplify a call of "inBox" almost as though it were a built-in TJVM instruction whose semantics is given in terms of the Lisp function inBox. Before proceeding with our presentation we take a slight detour to illustrate an important but obscure aspect of using ACL2. Readers uninterested in such details can skip this paragraph. The aspect in question is the fact that ACL2 uses a pattern matcher and backchaining to determine when an equality theorem is applicable as a rewrite rule. The pattern match is based on the left-hand side of the concluding equality: when a potential “target term” matching that term is seen by the rewriter, and the hypotheses can be relieved, the target term is replaced by the corresponding instance of the right-hand side. So consider the left-hand side of the conclusion above. Note that ‘s0 ’ occurs twice, once as the first argument to tjvm and then again inside the inBox-clock expression. In actual applications, the expressions in the target term corresponding to these two occurrences of ‘s0 ’ may not be syntactically identical. The first state is that in which inBox is being invoked; the second is the state used to compute how many steps to take. The two states could be syntactically different; indeed, they could be semantically different (i.e., not equal). This would prevent a pattern match and thus prevent the application of the theorem. A logically equivalent rephrasing of the theorem has the left-hand side (tjvm s0 k) and the additional hypothesis that k is equal to (inBox-clock this p1 p2 s0 ). That is, we do not need to insist that the clock expression be ‘(inBox-clock this p1 p2 s0 )’, only that it be an expression with the same value. We follow this line of thinking just one more step before returning to the main flow of our presentation. If we rephrase the left-hand side as (tjvm s0 k) ACL2 performs slowly because the pattern now matches every possible call of tjvm and the applicability of the theorem is entirely dependent on whether the hypotheses can be relieved. In general, pattern matching is faster than backchaining, so it is wise to put some syntactic “hint” in the pattern that the theorem applies to an invocation of
Proving Theorems About Java-Like Byte Code
157
inBox rather than, say, fact. We can recover most of the former efficiency while preserving the wide applicability of the theorem by using the left-hand side (tjvm s0 (inBox-clock this p1 p2 s1 )) and adding the additional hypothesis that (inBox-clock this p1 p2 s1 ) is equal to (inBox-clock this p1 p2 s0 ). That is, we can give the two original occurrences of s0 different names and merely insist that inBox-clock return the same thing on both of them. This is our preferred phrasing. We now return to the main flow of our presentation. We finally turn to a theorem about a method that modifies an object, i.e., that modifies the heap. This is the second method of the "ColoredPoint" class: setColorBox: ("setColorBox" (p1 p2 color) (load this) (load p1) (load p2) (invokevirtual "ColoredPoint" "inBox" 2) (ifeq 4) (load this) (load color) (putfield "ColoredPoint" "color") (return))
This void instance method takes three arguments, two points and a color. If the “this” object is in the box specified by the two points, the method sets the color of the “this” object to the specified color. The clock function for "setColorBox" is (defun setColorBox-clock (this p1 p2 c s) (declare (ignore c)) (++ 4 (inBox-clock this p1 p2 s) (if (inBox this p1 p2 s) 5 2)))
The primary effect of invoking "setColorBox" is to produce a new heap. That heap is described by (defun setColorBox-heap (this p1 p2 c s) (if (inBox this p1 p2 s) (let ((instance (deref this (heap s))) (address (cadr this))) (bind address (set-instance-field "ColoredPoint" "color" c instance) (heap s))) (heap s)))
The theorem stating the correctness of "setColorBox" is
158
J S. Moore
Theorem. "setColorBox" is correct: (implies (and (consp (next-inst s0 )) (equal (car (next-inst s0 )) ’invokevirtual) (equal (caddr (next-inst s0 )) "setColorBox") (equal (cadddr (next-inst s0 )) 3) (equal (equal (equal (equal
this (top (pop (pop (pop (stack (top-frame s0 ))))))) p1 (top (pop (pop (stack (top-frame s0 )))))) p2 (top (pop (stack (top-frame s0 ))))) color (top (stack (top-frame s0 ))))
(equal (lookup-method "inBox" (class-name-of-ref this (heap s0 )) (class-table s0 )) inBox) (equal (lookup-method "setColorBox" (class-name-of-ref this (heap s0 )) (class-table s0 )) setColorBox)) (equal (tjvm s0 (setColorBox-clock this p1 p2 color s0 )) (make-state (push (make-frame (+ 1 (pc (top-frame s0 ))) (locals (top-frame s0 )) (popn 4 (stack (top-frame s0 ))) (program (top-frame s0 ))) (pop (call-stack s0 ))) (setColorBox-heap this p1 p2 color s0 ) (class-table s0 ))))
This theorem is exactly analogous to the one about "inBox". The effect of the theorem is to configure ACL2 so that when it sees a tjvm expression with the setColorBox-clock it increments the program counter by one, pops four things off the operand stack, and sets the heap to that described by setColorBox-heap. Such a move is interesting by virtue of the following easy-to-prove theorem about that heap: Theorem. (implies (and (refp ref ) (refp this)) (equal (deref ref (setColorBox-heap this p1 p2 color s)) (if (and (equal ref this) (inBox this p1 p2 s)) (set-instance-field "ColoredPoint" "color" color (deref this (heap s))) (deref ref (heap s)))))
This theorem specifies the key property of the new heap. It defines how to dereference an arbitrary reference, ref , with respect to the new heap. If ref is
Proving Theorems About Java-Like Byte Code
159
the this object of the "setColorBox" invocation, and that object is within the specified box, then the dereferenced object is the result of setting the "color" of the same object in the old heap. Otherwise, dereferencing with respect to the new heap produces the same result as dereferencing with respect to the old heap. Thus, setColorBox-heap is just a succinct symbolic representation of the heap produced by "setColorBox" and whenever references arise with respect to it, they are eliminated and replaced by modified instances obtained through the old heap. While we have not illustrated classes that chain instances together or instance methods that are recursive or iterative, these aspects of the TJVM should raise no problems not predicted by our handling of the recursive factorial and the simple instance methods shown. That is not to say that such proofs are trivial, only that their nature is entirely predictable from what has been shown here. The expectation is that the ACL2 user able to do the proofs shown would be able to develop the techniques necessary to do proofs of this more involved nature.
6
Conclusion
We have shown how a simple version of the Java Virtual Machine can be formalized in the applicative Common Lisp supported by the ACL2 theorem prover. We have discussed how ACL2 can be configured to make it straightforward to reason about static and instance methods, including recursive methods and methods which modify objects in the heap. A common criticism of this approach is our use of “clocks.” Basically, clocks arise for a deep logical reason: the function tjvm is inadmissible otherwise because it is not total. We make tjvm total by limiting the number of instructions. There are other means, e.g., limiting the stack depth (i.e., method invocation depth) and imposing some bound or measure on back jumps, or, equipping every state with a measure establishing termination. These means free the user from counting instructions, at the expense of counting some other unit of computation. We personally find instruction-level clocks conceptually simplest. Instruction-level clocking provides “little step” operational semantics but allows the proof of lemmas, like those shown here, that provide “big step” semantics for subroutine call. Furthermore, we have shown how the two are naturally mixed. Whether one uses instruction-level clocking or some other form of counting, clock expressions allow the user to structure proofs. Every addend in a ++-nest gives rise to a single call of tjvm which must be simplified. Thus, by choice of an appropriate clock expression one can decompose proofs into the segments about which one is prepared to reason by specially-tailored lemmas. To the extent that one can decompose a computation mechanically into such regions, one can mechanically generate clock expressions to control the proof decomposition. Clock expressions compose in the obvious way with invokevirtual and invokestatic. Iterative computations are handled similarly.
160
J S. Moore
While both clock expressions and the Lisp functions describing the semantics of TJVM methods might appear complicated, it is crucial to remember the compositional nature of specifications and proofs. Once the clock expression for a method has been written and the corresponding specification has been proved, it is not necessary to think about or reveal the details. For example, one need not know that (fact-clock 5) is 50, only that (fact-clock n) is cost of running fact on n. The use of clocks encourages a focus on terminating computations but does not preclude consideration of non-terminating computations. By adding a flag to the TJVM state indicating whether the computation halted normally or “ran out of time” it is possible to phrase partial correctness results in this framework. In this setting, typical partial-correctness theorems have the additional hypothesis “provided n is sufficient to guarantee termination.” Furthermore, one can use explicit clocks, as we do, but address oneself to non-terminating computations and still characterize the state produced at certain points in the infinite computation. Our toy JVM ignores many aspects of the JVM, as noted earlier, including the omission of many byte code instructions, the finiteness of resources, error handling, exceptions, and multiple threads. Many of these aspects could be incorporated into a formal model. Some, such as the inclusion of additional byte codes, would not affect the complexity of proofs at all. The others would preserve the basic character of the theorems and proofs described here but, in some cases, would require the explicit statement of additional hypotheses to insure the sufficiency of available resources and the absence of errors. New proof machinery would have to be created (via the proofs of suitable lemmas) to enable ACL2 to reason about TJVM computations in which exceptions are thrown or multiple threads are used. Our experience, notably that reported in Young’s dissertation, [13] and in the author’s work on Piton [11], is that when dealing with resource limitations and exceptions it is best to produce several layers of abstraction, each formally related to the next by lemmas, one of which is free of those concepts and corresponds to our tjvm. That is, we see a model like our TJVM as being a component of a stack of abstract machines that enables formal discussion of programming language concepts not included in tjvm. Cohen’s defensive JVM, dJVM, [6] is an example of a machine in such a hierarchy. Since Cohen’s dJVM deals realistically with a significant fragment of the actual JVM, we cannot relate it to our TJVM. But we can explain the basic concept of a “defensive machine” by imagining a “defensive TJVM.” Consider the behavior of our TJVM on the add instruction: the top two items on the operand stack are added together. What if they are non-numeric? Our TJVM model answers this question by appealing simply to the untyped ACL2 logic: add uses the total ACL2 function + to combine the two items. This is simple and allows proofs of byte code program properties. But we probably do not intend to implement the TJVM fully, i.e., we probably do not intend to mimic the model’s behavior on non-numeric input. To address this we define another
Proving Theorems About Java-Like Byte Code
161
function, dtjvm, which is like tjvm. But we modify every semantic function so that before an instruction is executed we check that the state is acceptable. If it is not, we set some “non-normal termination” flag in the state and halt. By defining these defensive semantic functions explicitly in terms of the TJVM’s semantic functions — i.e., the defensive add performs the TJVM’s execute-ADD unless the check fails — it is easy to prove that dtjvm and tjvm return the “same” results when the dtjvm’s non-normal termination flag is off. Now suppose someone presents us with a “byte-code verifier.” We are in a position to say what property it must have: when verified code is executed by the dTJVM, the non-normal termination flag remains off. If that property is proved of the verifier and the verifier, in turn, approves of a given byte-coded method, then we can prove the correctness of the method using the full (and simple) TJVM semantics, instead of having to reason about the dTJVM semantics and all of its error conditions. The most problematic aspect of our TJVM may appear to be the fact that TJVM objects cannot be represented by (the non-circular) objects of applicative Common Lisp, necessitating the “reference versus instance” debate summarized here and the explicit provision of the heap in our specification functions. It cannot be denied that this is a complication. Similar problems have been dealt with in Flatau’s dissertation [7], where pure Lisp is implemented on a von Neumann machine in a way that is mechanically proved correct. However, we do not think this can be avoided simply because it reflects the underlying reality of object oriented programming, in which objects contain a von Neumann sense of state.
7
Acknowledgments
I am especially grateful to Rich Cohen, who patiently explained his ACL2 model of his “defensive” Java Virtual Machine, upon which my TJVM is modeled. I am also very grateful to the undergraduates at UT to whom I have taught the TJVM, as well as my teaching assistant for that course last year, Pete Manolios.
References 1. W. R. Bevier, W. A. Hunt, J S. Moore, and W. D. Young. Special Issue on System Verification. Journal of Automated Reasoning, 5(4):409–530, December, 1989. 2. R. S. Boyer and J S. Moore. A Computational Logic. Academic Press: New York, 1979. 3. R. S. Boyer and J S. Moore. Mechanized Formal Reasoning about Programs and Computing Machines. In R. Veroff (ed.), Automated Reasoning and Its Applications: Essays in Honor of Larry Wos, MIT Press, 1996. 4. R. S. Boyer and J S. Moore. A Computational Logic Handbook, Second Edition, Academic Press: London, 1997. 5. B. Brock, M. Kaufmann and J S. Moore, “ACL2 Theorems about Commercial Microprocessors,” in M. Srivas and A. Camilleri (eds.) Proceedings of Formal Methods in Computer-Aided Design (FMCAD’96), Springer-Verlag, pp. 275– 293, 1996.
162
J S. Moore 6. R. M. Cohen, The Defensive Java Virtual Machine Specification, Version 0.53, Electronic Data Systems, Corp, Austin Technical Services Center, 98 San Jacinto Blvd, Suite 500, Austin, TX 78701 (email: [email protected]). 7. A. D. Flatau, A verified implementation of an applicative language with dynamic storage allocation, PhD Thesis, University of Texas at Austin, 1992. 8. M. Kaufmann and J Strother Moore “An Industrial Strength Theorem Prover for a Logic Based on Common Lisp,”IEEE Transactions on Software Engineering, 23(4), pp. 203–213, April, 1997 9. M. Kaufmann and J Strother Moore “A Precise Description of the ACL2 Logic,” http://www.cs.utexas.edu/users/moore/publications/km97a.ps.Z, April, 1998. 10. T. Lindholm and F. Yellin The Java Virtual Machine Specification, AddisonWesley, 1996. 11. J S. Moore. Piton: A Mechanically Verified Assembly-Level Language. Automated Reasoning Series, Kluwer Academic Publishers, 1996. 12. G. L. Steele, Jr. Common Lisp The Language, Second Edition. Digital Press, 30 North Avenue, Burlington, MA 01803, 1990. 13. W. D. Young, A Verified Code-Generator for a Subset of Gypsy, PhD Thesis, University of Texas at Austin” 1988. 14. Y. Yu. Automated Proofs of Object Code For a Widely Used Microprocessor. PhD thesis, University of Texas at Austin, 1992. Lecture Notes in Computer Science, Springer-Verlag (to appear). ftp://ftp.cs.utexas.edu/pub/techreports/tr93-09.ps.Z.
Multiple State and Single State Tableaux for Combining Local and Global Model Checking ? Armin Biere1 , Edmund M. Clarke1,2 , and Yunshan Zhu1 1
Verysys Design Automation, Inc, 42707 Lawrence Place, Fremont, CA 94538 [email protected], [email protected] 2 Computer Science Department, Carnegie Mellon University 5000 Forbes Avenue, Pittsburgh, PA 15213, U.S.A [email protected]
Abstract. The verification process of reactive systems in local model checking [2, 9, 28] and in explicit state model checking [14, 16] is on-the-fly. Therefore only those states of a system have to be traversed that are necessary to prove a property. In addition, if the property does not hold, than often only a small subset of the state space has to be traversed to produce a counterexample. Global model checking [8, 24] and, in particular, symbolic model checking [6, 23] can utilize compact representations of the state space, e.g. BDDs [5], to handle much larger designs than what is possible with local and explicit model checking. We present a new model checking algorithm for LTL that combines both approaches. In essence, it is a generalization of the tableau construction of [2] that enables the use of BDDs but still is on-the-fly.
1 Introduction Model Checking [8, 24] is a powerful technique for the verification of reactive systems. With the invention of symbolic model checking [6, 23] very large systems, with more than 1020 states, could be verified. However, it is often observed, that explicit state model checkers [11] outperform symbolic model checkers, especially in the application domain of asynchronous systems and communication protocols [12]. We believe that the main reasons are the following: First, symbolic model checkers traditionally use binary decision diagrams (BDDs) [5] as an underlying data structure. BDDs trade space for time and often their sheer size explodes. Second, depth first search (DFS) is used in explicit state model checking, while symbolic model checking usually traverses the state space in breadth first search (BFS). DFS helps to reduce the space requirements and is able to find counterexamples much faster. Finally, global model checking traverses the state space backwards, and can, in general, not avoid visiting non reachable states without a prior reachability analysis. ?
This research is sponsored by the Semiconductor Research Corporation (SRC) under Contract No. 98-DJ-294, and the National Science Foundation (NSF) under Grant No. CCR-9505472. Any opinions, findings and conclusions or recommendations expressed in this material are those of the authors and do not necessarily reflect the views of SRC, NSF, or the United States Government.
E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 163–179, 1999. c Springer-Verlag Berlin Heidelberg 1999
164
A. Biere, E.M. Clarke, and Y. Zhu
In [3] a solution to the first problem, and partially to the second problem, was presented, by replacing BDDs by SAT (propositional satisfiability checking procedures). In this paper we propose a solution to the second and third problems of symbolic model checking. Our main contribution is a new model checking algorithm that generalizes the tableau construction [2] of local model checking for LTL and enables the use of BDDs. It is based on a mixed DFS and BFS strategy and traverses the state space in a forward oriented manner. Our research is motivated by the success of forward model checking [17, 18]. Forward model checking is a variant of symbolic model checking in which only forward image computations are used. Thus it mimics the on-the-fly nature of explicit and local model checking in visiting only reachable states. Note that [18] presented a technique for the combination of the BFS, used in BDD based approaches, with the DFS of explicit state model checkers. It was shown that especially this feature enables forward model checking to find counterexamples much faster. However, only a restricted class of properties, i.e. path expressions, can be handled by the algorithms of [17, 18]. Henzinger et. al. in [15] partially filled this gap by proving that all properties specified by B¨uchi Automata, or equivalently all ω-regular properties, can be processed by forward model checking. In particular, they define a forward oriented version of the modal µ-calculus [20], called post-µ, and translate the model checking problem of a ωregular property into a post-µ model checking problem. Because LTL (linear temporal logic) properties can be formulated as ω-regular properties [29], their result implies that all LTL properties can be checked by forward model checking. The fact, that LTL can be checked by forward model checking, can also be derived by applying the techniques of [17] to the tableau construction of [7]. However, this construction and also [15] do not allow the mixture of DFS and BFS, as in the layered approach of [18]. In addition, DFS was identified as a major reason that explicit state model checking is able to outperform symbolic model checking on certain examples. The contribution of our paper is the following. First we present a new model checking algorithm that operates directly on LTL formulae. For example [15] requires two translations, from LTL to B¨uchi Automata and then to post-µ. A similar argument applies to [7, 10]. Second it connects the local model checking paradigm of [2] with symbolic model checking in a natural way, thus combining BDD based with on-the-fly model checking. For the modal µ-calculus this connection has already been made in [4]. However, a direct application of [4] to the tableau construction of [2], our multiple state tableau construction, results in a tableau that is exponential in the size of the model. Only the introduction of a split rule in combination with efficient splitting heuristics allows us to keep the tableau linear in the size of the model. Finally our approach shows, that the idea of mixing DFS with BFS can be lifted from path expressions [18] to LTL. Our paper is organized as follows. In the next section our notation is introduced. Section 3 presents a variation of the single state tableau construction of [2], on which our multiple state tableau construction, introduced in Section 4, is based. The following section discusses implementation details of the algorithm. In Section 6 we investigate heuristics to generate small tableau. An important optimization is presented in Section 7. The technical part ends with a discussion of the complexity and comparison with related work in Section 8. Finally we address open issues.
Multiple State and Single State Tableaux
165
2 Preliminaries A Kripke structure is a tuple K = (Σ, Σ0 , δ, `) with Σ a finite set of states, Σ0 ⊆ Σ the set of initial states, δ ⊆ Σ × Σ the transition relation between states, and `: Σ → IP(A ) the labeling of the states with atomic propositions A = {p, . . .}. For technical reasons we assume that every state has at least one successor state. A path π = (s0 , s1 , . . .) is an infinite sequence of states si ∈ Σ. Define π(i) = si as the i-th state in π. We also use the notation πi = (π(i), π(i + 1), . . .) for the suffix of π starting at π(i). The image operation on a set of states S ⊆ Σ is defined as Img(S) := {t ∈ Σ | ∃s ∈ S. (s,t) ∈ δ}. As temporal operators we consider, the next time operator X, the finally operator F, the globally operator G, the until operator U, and its dual, the release operator R. An LTL formula f is called an eventuality iff f = Fh or f = (g U h). In this case h is called the body of f . We assume the formulae to be in negation normal form, as in [2, 9, 10]. Thus negations only occur in front of atomic propositions. This restriction does not lead to an exponential blow up because we have included the R operator that fulfills the property ¬( f U g) ≡ ¬ f R ¬g. An LTL formulae f holds on a path π, written π |= f , according to the following definitions: π |= p
iff p ∈ `(π(0))
π |= g ∧ h iff π |= g and π |= h ∀i. πi
π |= Gg
iff
π |= Xg
iff π1 |= g
|= g
π |= ¬p
iff p 6∈ `(π(0))
π |= g ∨ h iff π |= g or π |= h π |= Fh
iff ∃i. πi |= h
π |= g U h iff ∃i. πi |= h and ∀ j < i. π j |= g π |= g R h iff ∀i. πi |= h or ∃ j < i. π j |= g Since we are only concerned with finding witnesses for LTL formulae, we define an LTL formula f to hold at state s ∈ Σ (written s |= f ) iff there exists a path π in Σω starting at π(0) = s with π |= f . In addition we define f to hold in a set of states S ⊆ Σ (written S |= f ) iff there exists s ∈ S with s |= f .
3 Single State Tableaux In this section we present a variation on a tableau construction for explicit state model checking of LTL properties based on [2, 19]. The nodes in these hybrid tableaux also contain states of the model under investigation and not just temporal formulae. The main contribution of our paper is a symbolic extension to this tableau construction and is introduced Section 4. The LTL model checking algorithm of [19] is the dual to the tableau construction of [2]. In [2] universal path quantifiers are considered, whereas [19] and our approach solve the dual model checking problem for existential path quantifiers. A tableau in the sense of [19] can be transformed into a tableau of [2] by replacing every literal by its negation, every temporal operator by its dual, e.g. every occurrence of F by G, every E by A, and every boolean operator by its dual as well, e.g. ∧ by ∨. In essence this
166
A. Biere, E.M. Clarke, and Y. Zhu
transformation is just a negation of every formula in the tableau. The terminology of a successful tableau has also to be revised, which can be found further down. We call the type of tableau of [19] a single state tableau (S-Tableau), since every node in the tableau only contains a single state. Our tableau construction, introduced in section 4, allows a set of states at each tableau node. These tableaux are called multiple state tableaux (M-Tableau). In the rest of this section we will present a slight modification of the S-Tableau construction of [19] and note some facts that can be derived from [2, 19].
RA + :
s ` E(Φ, p) s ` E(Φ)
p ∈ `(s),
p∈A
RA − :
s ` E(Φ, ¬p) s ` E(Φ)
p 6∈ `(s),
RU :
s ` E(Φ, f U g) s ` E(Φ, g) s ` E(Φ, f , X f U g)
R∧ :
s ` E(Φ, f ∧ g) s ` E(Φ, f , g)
RR :
s ` E(Φ, f R g) s ` E(Φ, f , g) s ` E(Φ, g, X f R g)
R∨ :
s ` E(Φ, f ∨ g) s ` E(Φ, f ) s ` E(Φ, g)
RF :
s ` E(Φ, F f ) s ` E(Φ, f ) s ` E(Φ, XF f )
RG :
s ` E(Φ, G f ) s ` E(Φ, f , XG f )
RX :
s ` E(XΦ1 , . . . , XΦn ) s1 ` E(Φ1 , . . . , Φn ) . . . sm ` E(Φ1 , . . . , Φn ) Rsplit :
p∈A
{s1 , . . . , sm } = Img({s})
s ` E(Φ) s ` E(Φ)
Fig. 1. S-Rules: Single state tableau rules.
A single state sequent (S-Sequent) consists of a single state s and a list of LTL formulae Φ = (Φ1 , . . . , Φn ), written s ` E(Φ). The order of the formulae in the list is not important. An S-Sequent s ` E(Φ) holds in a Kripke structure K iff s |= Φ1 ∧· · · ∧Φn in K. An S-Tableau is a finite directed graph of nodes labeled with S-Sequents that are connected via the rules shown in figure 1. The application of a rule results in edges between the premise and each conclusion. If not otherwise stated, we assume that a tableau is fully expanded, i.e. no rule can generate new sequents or edges. For technical reasons a sequent may occur several times in a tableau. In particular, we assume that two nodes labeled with the same sequent are connected with an edge generated by application of the split rule Rsplit . This assumption allows us to extract an S-Tableau from an M-Tableau without shortening paths in the tableau. Refer to Lemma 6 for more details. We further assume that the split rule is only applied finitely often which keeps the tableau finite, since the number of different sequents is finite and nodes labeled with identical sequents can only be introduced by the split rule. An S-Path x is defined as the sequence of labels (sequents) of the nodes on a path through an S-Tableau. Since a path through a tableau can be both, finite or infinite,
Multiple State and Single State Tableaux
167
the same applies to an S-path. A finite S-Path x is successful iff it ends with a sequent s ` E(), where the list of formulae is empty. An S-Tableau is partially successful iff the tableau contains a finite successful S-Path. It is partially unsuccessful iff no finite S-Path is successful. An eventuality f , contained in the list of formulae of x(i), is called fulfilled iff there exists j with i ≤ j < |x| and the body of f is contained in x( j). This definition also applies to infinite paths. An infinite S-Path x is called successful iff every eventuality in x is fulfilled. Finally a tableau is successful iff it is partially successful or it contains an infinite successful S-Path. With these definitions we can derive the following theorem from [2, 19]: Theorem 1. An S-Tableau with root s ` E( f ) is successful iff s |= f . This theorem implies that s |= f iff every S-Tableau with root s ` E( f ) is successful. Therefore completeness and correctness is independent of the order in which the rules are applied. In the construction of the tableau no backtracking is required. The freedom to choose a rule, if several are applicable, can be used to minimize the size of the tableau, and thus the running time of the model checking algorithm (see Section 6 and Section 7). Finding successful paths seems to be an algorithmically complex problem. However, we will show that this problem can be reduced to the search for a successful strongly connected component. A strongly connected component (SCC) of a directed graph is a maximal subgraph in which every node can be reached from every other node in the subgraph. Note that in our notation a single node, not contained in any cycle, is not an SCC. We call an SCC of an S-Tableau successful iff every eventuality occurring in the SCC is fulfilled in the SCC, i.e. with every eventuality the SCC also contains its body. For an efficient implementation the following theorem is very important. As a result the search for a successful infinite path can be replaced by the search for a successful SCC, which is algorithmically much simpler. Theorem 2. A partially unsuccessful S-Tableau is successful iff it contains a successful SCC. This theorem is an easy consequence of the following Lemma, which can be used for the generation of an infinite witness, respectively counterexample, as explained below. Lemma 3. An S-Tableau contains an infinite successful S-Path iff it contains a successful SCC. Proof. For the proof from left to right let x be an infinite successful S-Path. First note that there has to be an SCC C in which a suffix of x is fully contained, since the STableau is finite. Further let σ be a sequent in C with an eventuality f on the right hand side (RHS). We need to show that f is fulfilled in C. Since C is an SCC, there exists a path segment connecting σ to the start of the suffix of x in C. If the body of f occurs on this path segment then we are done. Otherwise, by the structure of the rules for eventualities, the first sequent of the suffix of x in C reached by this segment still contains f or X f . Since x is successful the body of f has to occur in the suffix of x which is part of C.
168
A. Biere, E.M. Clarke, and Y. Zhu
The other direction is proven by constructing a successful S-Path from a successful SCC. This is easily done by generating a cyclic path segment through the SCC containing every sequent in the SCC. From the start of the cycle we can find another path segment back to the root of the tableau. Combining these two segments, repeating the cyclic segment infinitely often, results in an infinite successful S-path. t u If the tableau is unsuccessful then the root sequent can not hold. If the tableau is successful then it contains a finite successful path or a successful SCC. In the first case we can extract a finite witness for the root sequent by extracting a list of states from the finite successful path. In the second case we extract the witness from the S-Path generated in the second part of the proof for Lemma 3. If we apply our approach to a universal model checking problem by using the negation of the universal property to be checked in the root of the tableau, then the procedure described in the previous paragraph serves as an algorithm for generating counterexamples. To find the successful SCCs of an S-Tableau in linear time, a variation of the standard algorithm of Tarjan for the decomposition of a directed graph into its strongly connected components can be used. In particular, whenever a new SCC in Tarjan’s algorithm is found, we check on-the-fly if it is successful. Thus the model checking problem can be solved in linear time in the size of the tableau as well. The size of the tableau is bounded by the number of different S-Sequents. Note that the split rule is never applied in this context. The number of different S-Sequents in a tableau with root s ` E( f ) is in O(|Σ| · 2| f | ), since the RHS of a sequent may contain an arbitrary subset of subformulae of f . This gives an explicit state model checking algorithm with worst case complexity linear in the size of the Kripke structure and exponential in the size of the formula. For more details compare with [2]. A cyclic path is an infinite path of the form A · Bω , that starts with a finite prefix A and continues with a path segment B repeated infinitely often. Not all infinite paths through a tableau are cyclic paths. However, the proof of Lemma 3 shows that it is enough to consider cyclic paths only, when looking for successful paths to determine whether a tableau is successful.
4 Multiple State Tableaux In this section we extend the tableau construction of the last section to handle multiple states in one sequent. In combination with a symbolic representation, such as BDDs, this extension potentially leads to an exponential reduction in tableau size. The idea of handling set of states on the left hand side (LHS) of sequents already occurred in [4] as an extension of local model checking for the modal µ-calculus [28]. The tableau construction in this section extends the LTL model checking algorithm of [2] in a similar way. A multiple state sequent (M-Sequent) consists of a set of states S and a list of LTL formulae Φ = (Φ1 , . . . , Φn ), written S ` E(Φ). We use the same symbol ‘`’ to separate left and right hand side of S-Sequents and M-Sequents, but capital letters, e.g. S, for set of states on the LHS of M-Sequents and lower case letters, e.g. s, for S-Sequents. An
Multiple State and Single State Tableaux RA + :
S ` E(Φ, p) S+ p ` E(Φ)
RA − :
S ` E(Φ, ¬p) S− p ` E(Φ)
RU :
S ` E(Φ, f U g) S ` E(Φ, g) S ` E(Φ, f , X f U g)
R∧ :
S ` E(Φ, f ∧ g) S ` E(Φ, f , g)
RR :
S ` E(Φ, f R g) S ` E(Φ, f , g) S ` E(Φ, g, X f R g)
R∨ :
S ` E(Φ, f ∨ g) S ` E(Φ, f ) S ` E(Φ, g)
RF :
S ` E(Φ, F f ) S ` E(Φ, f ) S ` E(Φ, XF f )
RG :
S ` E(Φ, G f ) S ` E(Φ, f , XG f )
Rsplit :
S ` E(Φ) S1 ` E(Φ) · · · Sk ` E(Φ) RX :
·
·
S = S1 ∪ · · · ∪ Sk ,
S ` E(XΦ1 , . . . , XΦn ) T ` E(Φ1 , . . . , Φn )
169
Si 6= {}, for i = 1 . . . k
T = Img(S)
− Fig. 2. M-Rules: Multiple state tableau rules (‘S+ p ’ and ‘S p ’ are defined in the text).
M-Sequent holds in a Kripke structure K iff S |= Φ1 ∧ · · · ∧ Φn , i.e. there exists a path π in K with π(0) ∈ S and π |= Φ1 ∧· · ·∧Φn . An M-Tableau is a rooted finite directed graph of nodes labeled with M-Sequents that are connected via the rules shown in figure 2, where we define the following short hand for p ∈ A : S+ p := {s ∈ S | p ∈ `(s)},
S− p := {s ∈ S | p 6∈ `(s)}
In the split rule Rsplit the set of states S on the LHS is partitioned into a nonempty pairwise disjunctive list of sets S1 , . . . , Sk that cover S. For M-Tableaux we require every node to be labeled with a unique M-Sequent. M-Paths, successful M-Path, and SCC are defined exactly as in the single state case of the last section. The only exception is a finite M-Path ending with an M-Sequent {} ` E(Φ), with an empty set of states on the left side. By definition, such an M-Path is always unsuccessful even if the list of formulae Φ is empty. To lift Theorem 1, Theorem 2, and in particular Lemma 3 to M-Tableaux we first note that the definitions of successful paths, SCCs, and successful tableau do only depend on the RHS of the sequents, in both cases, for S-Tableaux and M-Tableaux. As an immediate consequence we have: Theorem 4. A partially unsuccessful M-Tableau is successful iff it contains a successful SCC. Lemma 5. An M-Tableau contains an infinite successful M-Path iff it contains a successful SCC. The second step is to map an M-Tableau to a set of S-Tableau, where the M-Tableau is successful iff one S-Tableau is successful. The mapping Ψ0 is defined along the graph
170
A. Biere, E.M. Clarke, and Y. Zhu
structure of the M-Tableau. If σ = ({r1 , . . . , rn } ` E(Φ)) is the root sequent of the MTableau, the result of the mapping will be n S-Tableaux with roots σi = (ri ` E(Φ)) for i = 1 . . . n. Now we apply the rule that has been applied to the root M-sequent to each individual root S-sequent as well, obtaining valid successor sequents in the S-Tableau. Then the newly generated nodes are extended by applying the same rule as in the MTableau. This process is repeated until the constructed tableau can not be extended anymore. Let T be an M-Tableau with root σ, as above, then Ψ0 (T ) is defined as the set of STableaux {Ψ(T , σ, σ1 ), . . . , Ψ(T , σ, σn )}, where Ψ is defined along the graph structure of T starting with the root sequent σ, as defined below. Note that Ψ returns a single S-Tableau while Ψ0 returns a set of S-Tableaux. To define Ψ we map every instance of an M-Rule in the M-Tableau to an application of the corresponding S-Rule in the S-Tableau using the fact that in an M-Tableaux every node can be identified uniquely by its label. Let σM = (S ` E(ΦM )) be an M-Sequent of T and σS = (s ` E(ΦS )) be an S-Sequent. Then Ψ(T , σM , σS ) is only defined iff s ∈ S and Φ = ΦS = ΦM . Now let RΛ be the M-Rule that is applied in T to σM : RΛ :
S ` E(Φ) S1 ` E(Φ1 ) · · · Sk ` E(Φk )
By definition of the rules, if Λ ∈ {U, R, F, G, ∧, ∨}, then RΛ is applicable to σS as an S-Rule and yields: RΛ :
s ` E(Φ) s ` E(Φ1 ) · · · s ` E(Φk )
In this case s ∈ S = S1 = · · · = Sk and we continue our construction by expanding the S-Sequent s ` E(Φi ) by Ψ(T , S ` E(Φi ), s ` E(Φi )) for i = 1 . . . k. If Λ = split, then there exists an j with s ∈ S j , since the partition covers S. Therefore we can apply the S-Rule Rsplit on σS which yields a new node labeled with σS again. This new node is expanded by Ψ(T , S j ` E(Φ), σS ). Regarding the rules for atomic propositions we only consider the positive case RA + . The definition of Ψ for RA − is similar. If RA + is applicable to σS then we proceed as above. Otherwise the construction of the S-Tableau is terminated with an unsuccessful finite path and Ψ(T , σM , σS ) consists of a single node labeled with σS . Finally consider the RX rule that involves the image operator. Let T = Img(S), Ts = Img({s}) = {t1 , . . . ,tm } ⊆ T , A = (Φ1 . . . , Φl ), and XA = (XΦ1 , . . . , XΦl ). RX :
S ` E(XA) T ` E(A)
RX :
s ` E(XA) t1 ` E(A) · · · tm ` E(A)
And again we expand the nodes labeled ti ` E(A) with Ψ(T , T ` E(A),ti ` E(A)). This simple recursive definition of Ψ may result in an infinite S-Tableau. We can keep the result finite if we exit the recursion by introducing a loop as soon as the same arguments to Ψ occur the second time, as in the following example for mapping an M-Tableau into its corresponding S-Tableaux. Consider the Kripke structure K with two states 0 and 1, both initial states, and two transitions from state 0 to state 1 and from state 1 to state 0. Both states are labeled with
Multiple State and Single State Tableaux
171
p, the only atomic proposition. An M-Tableau for checking EGp looks as follows {0, 1} ` E(Gp) {0, 1} ` E(p, XGp) {0, 1} ` E(XGp)
0
1
p
p
and the application of RX to the leaf sequent leads back to the root sequent. The tableau represents one successful M-Path that contains only one image calculation. The given M-Tableau is mapped into the following two S-Tableaux: 0 ` E(Gp) 0 ` E(p, XGp) 0 ` E(XGp) 1 ` E(Gp) 1 ` E(p, XGp) 1 ` E(XGp)
1 ` E(Gp) 1 ` E(p, XGp) 1 ` E(XGp) 0 ` E(Gp) 0 ` E(p, XGp) 0 ` E(XGp)
Again the application of RX to the leaf nodes yields the root. In general, mapping an M-Tableau may produce larger tableaux. For each generated S-Tableau it is easy to construct a graph homomorphism λ that maps nodes and edges of the S-Tableau to the nodes, respectively edges, of the MTableau, with the following property: If λ(nS ) = nM , where nS is a node of the STableau, labeled with the S-Sequent s ` E(ΦS ), and nM is a node in the M-Tableau, labeled with an M-Sequent S ` E(ΦM ), then s ∈ S and ΦM = ΦS . Further every edge, that was generated by the application of an S-Rule RΛ is mapped into an edge of the M-Tableau that was generated by the M-Rule RΛ . Let TM be an M-Tableau and TS be an S-Tableau with TS ∈ Ψ0 (TM ). Then we say that TS matches TM . We call an S-Path x a matching path to an M-Path X iff the STableau in which x occurs matches the M-Tableau of X and λ(x) = X for the corresponding graph homomorphism λ. Lemma 6. Let X be a successful finite or cyclic M-Path in an M-Tableau TM . Then there exists an S-Tableau TS that matches TM and contains an successful S-Path x matching X. Proof. First let X be a finite successful path. Then X ends with a sequent S ` E() with S 6= {}. We pick an arbitrary state s ∈ S and traverse X backward until the root is reached. At X(i) we generate the S-Sequent x(i) starting with s ` E(). Let X(i) = (Si ` E(Φi )), then we generate x(i) = (si ` E(Φi )) with si ∈ Si and the following restriction. As long as no RX rule is applied to X (i) we define the LHS of x(i) to be the state on the LHS of x(i + 1). If RX is applied to X (i) then we define si as an arbitrary predecessor of si+1 in Si . Second let X = Y · Z ω be a cyclic successful path. The generated x will also be of the form x = y · zω , where y matches Y and z matches Z n for some n > 0. We start with an arbitrary s ∈ Z(m) where m = |Z| − 1 and traverse Z backward until Z(0) is reached, generating S-Sequents as in the finite case. After we have reached Z(0) we continue at Z(m). This process is repeated until the same S-Sequent was generated twice during the
172
A. Biere, E.M. Clarke, and Y. Zhu
visit of Z(0). Termination is guaranteed because the set of states in Z(0) is finite. Then z is defined as the path segment from the last occurrence of the same S-Sequent to the first. From z(0) we can find a finite prefix y to the root as in the finite case. By construction TS = Ψ(TM , X (0), x(0)) is defined, matches TM , contains the successful S-Path x, and x matches X . t u
1
2 B
A
3
5
4
6 Y
Z
Fig. 3. Extracting an S-Path from an M-Path.
Consider the example of figure 3 where each ellipsis depicts the LHS of a sequent on which the RX rule is applied. The small filled circles represent single states of the Kripke structure. The arrows between those circles are transitions of the Kripke structure. Thus the picture visualizes a sequence Y · Z ω of set of states with Y (1) = Img(Y (0)) and Z(0) = Img(Y (1)),
Z(1) = Img(Z(0)),
Z(2) = Img(Z(1)),
Z(0) = Img(Z(2))
Our goal is to extract a sequence of single states from Y · Z ω . We start with 1, transition to 2 and pick 3 as predecessor of 2. The next transition, from 3 to 4, brings us back to the last sequent of Z but no cycle can be closed yet. We continue with 5 and reach 3 again with 6. From there we find a prefix (B, A), that leads from the initial state B to the start of the cycle at 6. The resulting witness is (B, A) · (6, 5, 4)ω . Lemma 6 allows us to derive the following completeness and correctness result for M-Tableau. Recall that S |= f iff there exists s ∈ S with s |= f . Theorem 7. An M-Tableau with root S ` E( f ) is successful iff S |= f . Proof. If an M-Tableau TM is successful then it contains a successful path. Using Lemma 6 we can construct a matching successful path in a matching S-Tableau TS with root sequent s ` E( f ) and s ∈ S. The correctness of the S-Tableaux construction (one part of Theorem 1) proves s |= f which in turn implies S |= f . Now let TM be unsuccessful. Then for every s ∈ S every matching S-Tableau TS with root s ` E( f ) is unsuccessful as well. With Theorem 1 we conclude s 6|= f for all s ∈ S. t u
Multiple State and Single State Tableaux
173
The algorithm described in the proof of Lemma 6 can be used to construct a witness for the root sequent from a successful M-Tableau, or a counterexample for the negation of the root sequent. First a matching path is constructed. Then a witness, a finite or cyclic path of states, can easily be extracted.
5 Algorithm A more detailed description of the tableau construction follows in this section. The overall approach expands open branches in DFS manner and stops when a successful finite path has been generated, a successful SCC has been found, or finally no rule can be applied without regenerating an edge that already exists in the tableau. In the first two cases a witness for the root sequent can be generated. In the last case it is shown that the root sequent can not hold. Finite successful paths are easy to detect. To detect and not to miss any successful SCC we use a modified version of Tarjan’s algorithm for decomposing a directed graph into its strongly connected components. It is the same algorithm as used for S-Tableau in Section 3. During the construction we have to remember the sequents that already occurred in the tableau. This can be accomplished by a partial function mapping a sequent to a node. To implement this we can sort the sequents in the tableau, use a hash table, or simply an array. In practice a hash table is the best solution. Up to this point the algorithm is identical for both, single and multiple state tableaux. Our intention, of course, is to represent set of states with BDDs. We associate with each formula E(Φ) the list of sequents in the tableau that have E(Φ) on the RHS. To check if a sequent σ ≡ (S ` E(Φ) already occurred, we just go through the list of sequents associated with E(Φ) and check whether the BDD representing the set of states on the LHS of one of the sequents in the list is the same as the BDD representing S.
6
Heuristics
The rule Rsplit is not really necessary for the completeness but it helps to reduce the search space, i.e. the size of the generated tableau. For instance consider the construction of a tableau for the formula EFp. This formula is the negation of a simple safety property. In this case a good heuristics is to build the tableau by expanding the left successor of the rule RF first. Only if the left branch does not yield a successful path, then the right successor is tried. If during this process a sequent σ0 = S0 ` E(F f ) is found and a sequent σ00 = S00 ` E(F f ) occurs on the path from the root to σ0 and S00 ⊆ S0 then we can remove the set S00 from S0 by applying Rsplit with S1 = S00 and S2 = S0 − S00 . The left successor immediately leads to an unsuccessful infinite path and we can continue with the right successor. A successful path in a tableau for EFp is a counterexample for the dual safety property AG¬p. Thus applying the heuristic of the last paragraph essentially implements an algorithm that computes the set of reachable states in a BFS manner while checking on-the-fly for states violating the safety property (as the early evaluation technique in
174
A. Biere, E.M. Clarke, and Y. Zhu
[1]). An example of this technique is shown in figure 4 using the Kripke structure of figure 5.
-
{1} ` E(Fp) RF {1} ` E(p) {1} ` E(XFp) {} ` E(p) {1, 2} ` E(Fp) {1} ` E(Fp)
Rsplit {2} ` E(Fp)
RF {2} ` E(XFp) {2, 3} ` E(Fp)
{2} ` E(p) {} ` E(p)
{3} ` E(Fp) RF {3} ` E(p) {} ` E(p)
Rsplit {2} ` E(Fp)
{3} ` E(XFp) {1, 2} ` E(Fp)
{1} ` E(Fp)
Rsplit {2} ` E(Fp)
Fig. 4. Example tableau for on-the-fly model checking of safety properties.
¬p 1
2 ¬p
3
¬p
Fig. 5. Example Kripke structure for on-the-fly checking of safety properties.
Similar heuristics can be used for liveness properties. Consider the Kripke structure in figure 6 and the property EGp. If we split a sequent as soon it LHS contains a state that already occurred in a sequent with the same RHS, then the following tableau finds a witness for EGp with just one image computation: {1} ` E(Gp) {1} ` E(p, XGp) {1} ` E(XGp) {1, 2} ` E(Gp) {1} ` E(Gp)
RG RA + RX
{2} ` E(Gp)
Rsplit
Multiple State and Single State Tableaux
1 p
2 p
999 p
175
1000 ¬p
Fig. 6. Example Kripke structure for on-the-fly model checking of liveness properties.
The left sequent that results from the application of the split rule is the same as the root sequent. Thus a successful infinite path has been found and the right branch does not need to be expanded. A model checking algorithm based on standard fixpoint calculations requires 1000 image computations, i.e. traverses the whole state space, before the witness can be found. Another heuristic is to avoid splitting the tableau as long as possible. In particular, if several rules are applicable to a sequent, then, if possible, a rule is chosen that does not result in multiple branches. For example if both RG and RF are applicable, then RG is always preferred. This is one of the heuristics proposed in [27] for the construction of small tableau as an intermediate step of translating LTL into the modal µ-calculus with the algorithm of [10]. In general, these heuristics are also applicable to our approach.
7 Optimization In an M-Tableau the number of different LHS of sequents is exponential in |Σ|, the number of states of the Kripke structure. In this section we present an optimization that reduces the maximal number of different LHS with the same RHS to 2·|Σ|. In particular, with this optimization the size of an M-Tableau becomes linear in the number of states. Without this optimization the tableau construction would not be feasible at all, even in combination with BDDs. Note that the size of the tableau may still be exponential in the size of the formula, since the RHS of a sequent is an arbitrary set of subformulae of the original property. In practice the size of the properties to be checked is usually small, but the size of the models we deal with can be arbitrary large. Thus it is much more important to have an algorithm that is linear in the size of the model. The basic idea is to maintain the following invariant by applying the split rule: Let S1 ` E(Φ) and S2 ` E(Φ) be two M-Sequents in the M-Tableau. Then S1 ∩ S2 = {}, S1 ⊆ S2 , or S2 ⊆ S1 . Lemma 8. Let P ⊆ IP(S) be a set of nonempty subsets of a finite set S 6= {}. If for all S1 , S2 ∈ P either S1 ∩ S2 = {}, S1 ⊆ S2 or S2 ⊆ S1 holds, then |P| < 2 · |S|. Proof (Induction over |S|). In the base case let |P| ≤ 1, which implies |P| < 2 ≤ 2 · |S|. In the induction step, we assume |P| > 1. The sets contained in P are partially ordered by set inclusion and contain at least one maximal set S1 . By defining S2 := S\S1 we
176
A. Biere, E.M. Clarke, and Y. Zhu
partition S = S1 ∪ S2 into two mutually exclusive sets, S1 and S2 . If S2 = {}, i.e. S1 is the only maximal set in P, then we define P0 := P\{S1 } and S0 :=
[T
T ∈P0
and with 0 < |S0 | < |S1 | ≤ |S| the induction hypothesis shows |P| = 1 + |P0| < 1 + 2 · |S0| < 2 · (|S0| + 1) ≤ 2 · |S1| ≤ 2 · |S| Now we assume S2 6= {}, which implies S1 6= S, and induces a partition on P with P = P1 ∪ P2
Pi := {T ∈ P | T ⊆ Si } for i = 1, 2
and
Finally the induction hypothesis applied to S1 and S2 results in |P| ≤ |P1 | + |P2| < 2 · |S1| + 2 · |S2| = 2 · (|S1| + |S2|) = 2 · |S| t u Since the LHS of a sequent can also be an empty set, Lemma 8 shows that the number of sequents with the same RHS is bounded by 2 · |S| if the invariant is maintained. This is also the best bound that we can get, as the following example shows. Let Si = {0, . . ., 2i − 1}. Then we associate a balanced binary tree of height i with each Pi ⊆ IP(Si ). We label each node in the tree by exactly one element of Pi , which implies |Pi | = 2i+1 − 1 = 2 · |Si | − 1. The i leaves are labeled with the singleton sets {0}, . . ., {2i − 1}. Each inner node of the binary tree is labeled with the union of the labels of its children. Note that the image rule RX and the atomic rules RA + and RA − are the only rules, except the split rule Rsplit , that actually manipulate the LHS. All other rules only generate sequents that contain the same set of states as their parents. The application of these rules can not violate the invariant. To maintain the invariant in the case of RX , RA + and RA − as well we have to apply the split rule in combination with these rules: After each image calculation or application of an atomic rule the sequent is split to fulfill the invariant. For instance if the application of RX yields: RX :
··· {1, 2, 3, 4} ` E(Φ)
and the tableau already contains the two sequents: {1, 2} ` E(Φ)
and
{4, 5} ` E(Φ)
Then the split rule is applied as follows. For every non empty intersection of {1, 2, 3, 4} with the LHS of an already existing sequent a new sequent is generated: Rsplit :
{1, 2} ` E(Φ)
{1, 2, 3, 4} ` E(Φ) {3} ` E(Φ)
{4} ` E(Φ)
Multiple State and Single State Tableaux
177
where the first sequent is not actually generated since it already exists in the tableau. We have to combine the Rsplit rule with the image and atomic rules to technically avoid introducing an intermediate sequent, {1, 2, 3, 4} ` E(Φ) in the example, that might violate the invariant. The correctness and completeness results can be proven for this modification as well. Without combining these rules each application of RX , RA + or RA − could potentially need an additional application of Rsplit . This could potentially double the number of sequents and the number of sequents with the same RHS can only be bounded by 4 · |Σ|, which is still linear in the number of states.
8 Complexity and Related Work In this section we discuss the complexity of our new algorithm based on M-Tableaux and compare it with other local and global techniques for LTL model checking. The size of a tableau with root Σ0 ` E( f ), not using the optimization of the last section, is in O(2|Σ| · 2| f | ). The time taken is polynomial in the size of the tableau. Thus the time complexity is (roughly) the same as the space complexity. With the optimization of the last section the size of the tableau is reduced to O(|Σ| · 2| f | ). As a consequence the time complexity of our algorithm is at most polynomial in the number of states, with a small degree polynomial, and exponential in the size of the formula. The explicit state model checking algorithms of [2, 16, 21] are linear in the number of states and the number of transitions. Note that the number of transitions may be quadratic in the number of states. If an explicit state representation is used, we conjecture that our tableau construction can be implemented with the same linear time complexity. However, with our approach we are able to use compact data structures, such as BDDs, to represent sets of states symbolically and thus can hope to achieve exponentially smaller tableaux and exponentially smaller running times for certain examples. The method of [10] translates an LTL formula into a tableau similar to the tableaux in our approach. In [10] the nodes contain only formulae and no states. The size of the tableau can be exponential in the size of the LTL formula. The second step is a translation of the generated tableau into a µ-calculus formula that is again exponential in the size of the tableau. Additionally, the alternation depth of the µ-calculus formula can not be restricted. With [13, 22] this results in a model checking algorithm with time and space complexity that is double exponential in the size of the formula and single exponential in the size of the model K. In [15] an ELTL formula is translated to a B¨uchi automata with the method of [29]. This leads to an exponential blow up in the worst case. But see [14] for an argument why this explosion might not happen in practice, which also applies to our approach. The resulting B¨uchi automata is translated to post-µ, a forward version of the standard modal µ-calculus, for which similar complexity results for model checking as in [13, 22] can be derived. This translation produces a µ-calculus formula of alternation depth 2 which results in an algorithm with an at least quadratic running time in |Σ|. The LTL model checking algorithm of [15] is also forward oriented. A forward state space traversal potentially avoids searching through non reachable states, as it is usually the case with simple backward approaches. However, it is not clear how DFS can be incorporated into symbolic µ-calculus model checking.
178
A. Biere, E.M. Clarke, and Y. Zhu
The method of [7] translates an LTL model checking problem into a FairCTL model checking problem. With the result of [13] this leads to a model checking algorithm that is linear in the size of the model and exponential in the size of the formula. Again, these complexity results are only valid for explicit state model checking. The algorithms of [7, 15] are based on BFS and it is not clear how to implement them depth first. The work by Iwashita [17, 18] does not handle full LTL and no complexity analysis is given. But if we restrict our algorithm to the path expressions of [17, 18], then our algorithm subsumes the algorithms of [17, 18], even for the layered approach of [18]. In [4] an M-Tableau construction for the modal µ-calculus was presented. The main motivation in [4] for using set of states in sequents was to be able to handle infinite state systems. Therefore no complexity results were given. In addition, the modal µ-calculus, as already discussed above, can not represent LTL properties directly without a prior translation [10, 29]. Our tableau construction is on-the-fly (see liveness example in Section 6) and only needs O(|Σ|) image computations. Previous symbolic model checking algorithms for LTL [7, 15], based on fixpoint calculations, require O(|Σ|2 ) image computations.
9 Conclusion Although our technique clearly extends the work of [17, 18] and bridges the gap between local and global model checking, we still need to show that it works in practice. We are currently working on proving the conjecture that our tableau construction can be implemented with linear complexity. We also want to investigate heuristics for applying the split rule. The approximation techniques of [25, 26] are a good starting point.
References [1] I. Beer, S. Ben-David, C. Eisner, D. Geist, L. Gluhovsky, T. Heyman, A. Landver, P. Paanah, Y. Rodeh, G. Ronin, and Y. Wolfsthal. Rulebase: Model checking at IBM. In CVA’97, number 1254 in LNCS, pages 480–483. Springer-Verlag, 1997. [2] G. Bhat, R. Cleaveland, and O. Grumberg. Efficient on-the-fly model checking for CTL*. In LICS’95. IEEE Computer Society, 1995. [3] A. Biere, A. Cimatti, E. Clarke, and Y. Zhu. Symbolic model checking without BDDs. In TACAS’99, LNCS. Springer, 1999. [4] J. Bradfield and C. Stirling. Local model checking for infinite state spaces. Theorectical Computer Science, 96:157–174, 1992. [5] R. E. Bryant. Graph-based algorithms for boolean function manipulation. IEEE Transactions on Computers, 35(8), 1986. [6] J. R. Burch, E. M. Clarke, and K. L. McMillan. Symbolic model checking: 1020 states and beyond. Information and Computation, 98, 1992. [7] E. Clarke, O. Grumberg, and K. Hamaguchi. Another look at LTL model checking. Formal Methods in System Design, 10:47–71, 1997. [8] E. M. Clarke and E. A. Emerson. Design and synthesis of synchronization skeletons using branching time temporal logic. In Logic of Programs: Workshop, LNCS. Springer, 1981. [9] R. Cleaveland. Tableau-based model checking in the propositional mu-calculus. Acta Informatica, 27, 1990.
Multiple State and Single State Tableaux
179
[10] M. Dam. CTL* and ECTL* as fragments of the modal mu-calculus. Theoretical Computer Science, 126, 1994. [11] D. L. Dill. The MurΦ verification system. In CAV’96, LNCS. Springer, 1996. [12] Y. Dong, X. Du, Y.S. Ramakrishna, C. T. Ramkrishnan, I. V. Ramakrishnan, S. A. Smolka, O. Sokolsky, E. W. Starck, and D. S. Warren. Fighting livelock in the i-protocol: A comparative study of verification tools. In TACAS’99, LNCS. Springer, 1999. [13] E. A. Emerson and C.-L. Lei. Modalities for model checking: Branching time strikes back. Science of Computer Programming, 8, 1986. [14] R. Gerth, D. Peled, M. Y. Vardi, and P. Wolper. Simple on-the-fly automatic verification of linear temporal logic. In Proceedings 15th Workshop on Protocol Specification, Testing, and Verification. North-Holland, 1995. [15] T. A. Henzinger, O. Kupferman, and S. Qadeer. From Pre-historic to Post-modern symbolic model checking. In CAV’98, LNCS. Springer, 1998. [16] G. J. Holzmann. The model checker SPIN. IEEE Transactions on Software Engineering, 5(23), 1997. [17] H. Iwashita and T. Nakata. CTL model checking based on forward state traversal. In ICCAD’96. ACM, 1996. [18] H. Iwashita, T. Nakata, and F. Hirose. Forward model checking techniques oriented to buggy design. In ICCAD’97. ACM, 1997. [19] A. Kick. Generierung von Gegenbeispielen und Zeugen bei der Modellpr¨ufung. PhD thesis, Fakult¨at f¨ur Informatik, Universit¨at Karlsruhe, 1996. [20] D. Kozen. Results on the propositional µ-calculus. Theoretical Computer Science, 27, 1983. [21] O. Lichtenstein and A. Pnueli. Checking that finite state concurrent programs satisfy their linear specification. In Symposium on Principles of Programming Languages, New York, 1985. ACM. [22] D. E. Long, A. Browne, E. M. Clarke, S. Jha, and W. R. Marrero. An improved algorithm for the evaluation of fixpoint expressions. In CAV’94, LNCS. Springer, 1994. [23] K. L. McMillan. Symbolic Model Checking. Kluwer, 1993. [24] J. P. Quielle and J. Sifakis. Specification and verification of concurrent systems in CESAR. In Proc. 5th Int. Symp. in Programming, 1981. [25] K. Ravi, K. L. McMillan, T. R. Shiple, and F. Somenzi. Approximation and decomposition of binary decision diagrams. In DAC’98. ACM, 1998. [26] K. Ravi and F. Somenzi. High-density reachability analysis. In ICCAD’95. ACM, 1995. [27] F. Reffel. Modellpr¨ufung von Unterlogiken von CTL*. Masterthesis, Fakult¨at f¨ur Informatik, Universit¨at Karlsruhe, 1996. [28] C. Stirling and D. Walker. Local model checking in the modal mu-calculus. Theoretical Computer Science, 89, 1991. [29] M. Y. Vardi and P. Wolper. Reasoning about infinite computations. Information and Computation, 115(1), 1994.
On the Existence of Network Invariants for Verifying Parameterized Systems? Parosh Aziz Abdulla and Bengt Jonsson Dept. Computer Systems Uppsala University P.O.Box 325, 751 05 Uppsala, Sweden {parosh,bengt}@docs.uu.se
Abstract. Over the last decade, finite-state verification methods have been developed to an impressive tool for analysis of complex programs, such as protocols and hardware circuits. Partial-order reduction and BDD-based symbolic model checking have been instrumental in this development. Currently, much effort is devoted to advancing further the power of automated verification to cover also infinite-state systems. In this paper, we consider the class of so-called parameterized systems, i.e., systems with many similar processes, in which the number of processes is unbounded and their interconnection pattern may vary within the range of some constraints. We partially review the use of induction over the system structure for the verification of parameterized systems. Wolper and Lovinfosse have introduced the term network invariant for the induction hypothesis in such a proof by induction. They also observe that well-behaved (e.g., finite-state) network invariants do not always exist, even if the system itself satisfies the property to be verified. The main contribution of the paper is to present some sufficient conditions, under which the existence of a finite-state network invariant is guaranteed. We also relate the construction of network invariants to the search for standard inductive invariants. Two small examples of network invariants and standard invariants for parameterized systems are included.
1
Introduction
One of the advantages of producing formal models of algorithms and systems is the possibility to analyze and verify them in a rigorous way, in the best case totally automatically by computer. For nondeterministic and parallel programs, relevant verifications include absence of deadlocks, or proving that all executions of a program satisfy a desirable property expressed in temporal logic. Over the last decade, impressive tools have been developed for verification of finite-state systems. Partial-order reduction and BDD-based symbolic model checking have been instrumental in this development. ?
Supported in part by the Swedish Board for Industrial and Technical Development (NUTEK) and by the Swedish Research Council for Engineering Sciences (TFR).
E.-R. Olderog, B. Steffen (Eds.): Correct System Design, LNCS 1710, pp. 180–197, 1999. c Springer-Verlag Berlin Heidelberg 1999
On the Existence of Network Invariants for Verifying Parameterized Systems
181
Currently, much effort is devoted to advancing further the power of automated verification to cover also infinite-state systems. Potentially practical tools for automated verification of infinite-state systems have been developed for significant special cases, such as timed automata [ACD90,BGK+ 96], hybrid automata [Hen95], data-independent systems [JP93,Wol86], Petri nets [JM95], pushdown processes [BS95,Sti96], and systems with unbounded communication channels [Fin94,AJ93,ABJ98]. On the border between finite-state and infinite-state systems, there is the class of parameterized systems. By a parameterized system, we mean a family of similar systems that depend in a regular way on a parameter. Typically, parameterized systems are built from a (small) finite set of processes, which are replicated and interconnected into networks. Examples of parameterized systems abound: a distributed algorithm can be modeled as a system of many identical processes whose interconnection topology may be arbitrary, a bus protocol consists of a linear array of identical processes where the parameter is the number of processes, etc. Also unbounded data structures, such as queues and trees, could be regarded as parameterized systems by letting each node (cell) be viewed as a process which is connected to its neighbour nodes (cells). A queue would thus be viewed as a linear array of processes of arbitrary length. In order to make the discussion more concrete, let us consider families of systems of the form P0 k P k P k · · · k P composed of one instance of a “global” component P0 which is common to all systems in the family, and an arbitrary number of instances of some process P . The processes are composed by some associative composition operator k , which for the moment will be left unspecified. The verification problem for parameterized systems consists in verifying that P0 k P k P k · · · k P |= φ for some correctness formula φ, for any number of copies of P . We assume that the formulation of φ is independent of the system size. An example of a correctness property could be “there are never two processes simultaneously in the critical section”. The most straight-forward approach to verifying a parameterized system is to verify the system for a suitable chosen number (say 5) of processes. Finite-state state-space exploration methods can be used to analyze the system efficiently. However, there is no a priori guarantee that the system will function correctly with 6 processes. It is therefore of interest to consider methods that verify the correctness of the system with an arbitrary number of components. It may even (as argued, e.g., by Wolper and Boigelot [WB98]) turn out that the parameterized version of the system is easier to verify, since in the best case it may concern the essential reason for correctness, and avoid the particularities of the case with 5 processes.
182
P.A. Abdulla and B. Jonsson
If we look at the problem of actually verifying correctness for any number of copies of P , we notice that the problem has an unbounded structure along two dimensions. One dimension is “time”, since we must check a property of potentially unbounded execution sequences. Another dimension is “space”, since the property should hold for an arbitrary system size. To verify that the system is correct, in spite of any of these unboundednesses, we may use induction. In the following two paragraphs, we describe the use of induction, first in the time dimension and then in the space dimension. Throughout the paper, we will only be concerned with safety properties. The standard way to handle the time dimension in verification of safety properties (e.g., [MP95]) is to find an (inductive) invariant of the system, which is preserved by all computation steps of the system, and which implies φ. For instance, if φ is the correctness property “there are never two processes simultaneously in the critical section”, then an inductive invariant of the system could be obtained by conjoining “at most one process has the token” (assuming that possessing the token is necessary for entering the critical section). This method of verification assumes that we can express sets of system states of arbitrary size. Finding an invariant may involve some ingenuity. However, once it is found, the rest of the verification is relatively simple and possible to automate. Computational invariants expressed in some formalism for represented sets of states of unbounded system ˇ sizes have been used e.g., in [JK95,KMM+ 97,EFM99,ACJYK96,AJ98,ABJN99]. A method for handling the space dimension in parameterized system verification is to find a uniform abstraction of the system which is independent of system size. Such an abstraction is a single system N whose behavior “contains” (in a sense to be made more precise later in the paper) the behavior of any system in the family. In particular, if N |= φ, then P0 k P k · · · k P |= φ for any system size. One sufficient criterion for checking that N is indeed an abstraction is to check that it is inductive. Letting ≤ denote the relation “contained in”, this means that it should be checked that P0 ≤ N and that N k P ≤ N besides checking that N |= φ. The term “network invariant” has been introduced by Wolper and Lovinfosse [WL89] (the method was also suggested by Kurshan and McMillan [KM89]) for an abstraction which is inductive in this sense. Again, finding a network invariant N may involve some ingenuity. However, the point is that once N is found, the correctness checks should be relatively simple and possible to automate. Network invariants have been employed in e.g., [KM89,WL89,EN95,LHR97]. For verifying a parameterized system, there are thus two basically different ways to employ induction: either using standard (computational) induction, or using induction over the structure of the parameterized system. To avoid confusion, we will use the term computational invariant to mean an inductive invariant in the “time-dimension”. In this paper, we will consider the question “when does there exist a computational or network invariant of a certain simple form?” If we consider the case that each component is finite-state, it is natural to try to look for “finite” com-
On the Existence of Network Invariants for Verifying Parameterized Systems
183
putational and network invariants. In the case of computational invariants, we will take this to mean an invariant which considers an arbitrary “finite” part of the system structure. In the case of network invariants, we will take this to mean an invariant which can be expressed by a finite-state transition system. As observed by Wolper and Lovinfosse [WL89], it follows from a basic undecidability result by Apt and Kozen [AK86], that such invariants do not exist in general. In this paper, we will give some sufficient criteria for the existence of these invariants. We hope that this gives a better understanding in particular of the network invariant method. Mechanized search for network invariants have been considered by Lesens et al [LHR97], who employ maximal fixpoint iteration, enhanced by approximation techniques, in the verification of some examples. Abstractions can also be constructed without checking that it is in inductive, e.g., as in [LS97,CGJ95]. German and Sistla [GS92] have given a direct algorithm for model-checking of parameterized systems with an unordered system topology, in a slightly more restricted framework than that considered here. The paper is organized as follows. In the next section, we introduce the basic definitions of parameterized systems. The use of invariants in verification is described in Section 3. Section 4 contains criteria for the existence of computational and network invariants. In Section 5, we illustrate the verification of a parameterized system in which the components are non-finite state (timed automata).
2
Basic Definitions
Parameterized Systems By a parameterized system, we mean a family of systems, each of which is a composition of form Mn ≡ P0 k P [1] k P [2] k · · · k P [n] where P0 is an optional “global” component, common to all instances in the family, and where P [1], . . . , P [n] are identical processes. Each component P [i] and P0 is modeled as a labeled transition system. For the moment, we do not require that each component be finite-state. The labels on transitions are taken from a set of visible actions, extended by an invisible action (denoted τ ). We assume that any component can always perform an idling component transition, labeled by τ , which does not change its state. We use M to denote the (infinitestate) system which is the “union” of the family {Mn }∞ n=0 of system instances. One could think of M as a system, which initially decides on a value of the parameter n, and then becomes Mn . Each transition of the system Mn may involve one or more components. The possible synchronizations between components are constrained by a synchronization predicate Φ. In the remainder of this paper, we will consider a totally unordered system topology, in which any component can communicate with any other,
184
P.A. Abdulla and B. Jonsson
regardless of their positions in the syntactic description of Mn . The synchronization predicate Φ is then a set of multisets of actions. Each multiset describes a possible combination of labels on component transitions that make up a transition of the parameterized system. For instance, if the pair {send, receive} is in Φ, but neither of send nor receive is in any other set of the synchronization predicate, then each occurrence of a send must be synchronized with a matching receive. In order to be able to model broadcast and global synchronizations, we allow one of the actions in a synchronization to have the special superscript ω, meaning “all other processes”. For instance, the set {send, receiveω } denotes a broadcast by one process to all other processes. The above requirements on synchronization concern a system Mn , which is closed in the sense that it does not interact with its environment. Later, in Section 3.2, we will consider open systems which represent a part of some Mn which can synchronize with other components. Synchronizations of an open system need only contain a subset of the labels of some multiset of the synchronization predicate. Two open systems may synchronize, and the labels on transitions are formed as the union of labels of the synchronizing systems in the natural way. Continuing the above example where {send, receive} is in Φ, a transition of an open system may be labeled by send only. We could also have considered parameterized systems with a linearly ordered topology, in which components are arranged in an order, as shown in the syntactic description of Mn . The synchronization predicate will then be a set of strings of labels. Correctness Properties We will only consider linear-time safety properties of parameterized systems, which can be stated as a requirement on the executions of the controller, and a bounded arbitrary set of distinct components. Such properties can be transformed into invariants of the form ∀i1 , . . . , ik . alldiff(i1 , . . . , ik ) =⇒ φ(i1 , . . . , ik ) where φ is a predicate on the local states of the controller and the components with indices i1 , . . . , ik , and where alldiff(i1 , . . . , ik ) states that all indices i1 , . . . , ik are distinct. We shall call such a formula a universal assertion. As an example, we can specify mutual exclusion by the invariant ∀i 6= j. ¬(critical[i] ∧ critical[j]) Examples of correctness properties that can be expressed in this form are: mutual exclusion, clock synchronization, security properties, etc. The checking of an invariant can be equivalently reformulated as a reachability property. For instance, the above invariant means that it is not possible to reach a state which satisfies the negation ∃i 6= j.(critical[i] ∧ critical[j]) of the above invariant. We shall call such a formula an existential assertion
On the Existence of Network Invariants for Verifying Parameterized Systems
185
Example A simple example of a parameterized system is the following simple token-passing mutual exclusion algorithm. An arbitrary set of processes compete for a critical resource. Access to the resource is modeled by a process being in its critical section. In order to enter the critical section, a process must first acquire a token, which is passed in some arbitrary manner between components. We model each process as a labeled transition system with three states: n (not possessing the token), t (possessing the token), and c (in the critical section), and two visible actions: send-token and rec-token. A state-transition diagram of a process is given below:
?
n
rec-token
-
send-token
t
τ τ
-
c
The synchronization predicate requires send-token and rec-token to occur in synchronized pairs. In a network, all process are initialized in the state n, except for one process, which starts in state t. There is no controller process. For this particular example, we could imagine both an unordered and a linearly ordered system topology (of course, any reasonable topology could be considered, but that is not in the scope of this paper). A correctness property for this system is mutual exclusion, formulated as the invariant ∀i 6= j. ¬(c[i] ∧ c[j])
3
Methods for Verification of Invariants of Parameterized Systems
In this section, we present the use of computational and of network invariants in the verification of a parameterized system.
3.1
Computational Invariants
A parametrized system can be viewed as an (infinite-state) program M (which initially decides a value of n), to which standard verification methods can be applied. A safety property in the form of an invariant can be proved in the standard way by finding a computational (inductive) invariant for M . In order to automate this method, we must find a representation of (possibly infinite) sets of states of M . For instance, if each component P [i] is finite-state, then in the case of unstructured topology one might use constraints on the number of
186
P.A. Abdulla and B. Jonsson
occurrences of each control state of P [i]. In the case of a linear network, regular expressions could serve this purpose [CGJ95,KMM+ 97,ABJN99]. The requirements on a computational invariant I are: 1. any initial state of any Mn satisfies I, 2. each transition from a system state satisfying I leads to a system state which also satisfies I. We say that I is sufficiently strong if additionally 3. I implies φ. It is a standard result that the set of invariants I that satisfy these requirements form a lattice. The lattice is non-empty if and only if φ is an invariant of Mn for all n. There is a least computational invariant I (with respect to set-inclusion) which satisfies the first two conditions: this is the set of reachable states of M . There is also a largest I which satisfies conditions 2. and 3. It is well-known that a sufficiently strong computational invariant always exists if φ is an invariant of each Mn , but there is no guarantee that it can in general be expressed in the particular chosen representation (this follows from the undecidability of parameterized system verification [AK86]). Methods for automatically searching for computational invariants include forward and backward reachability analysis, sometimes augmented by approximation techniques, using a symbolic representation of sets of states. In what follows, we shall be particularly interested in finding computational invariants that are expressed as universal assertions. It turns out that backward reachability analysis suits the problem of finding universal assertions. Example To continue the example in the previous section, we see that a sufficiently strong computational invariant of any Mn is ∀i 6= j. ¬[(t[i] ∨ c[i]) ∧ (t[j] ∨ c[j])] which is indeed a universal assertion. Below, we describe the relation to backward reachability in more detail. Backward Reachability Analysis The basic idea of backward reachability analysis is to start from the negation of the invariant to be checked. If the invariant is a universal assertion, then the negation is an existential assertion. We assume that we can represent sets of states of an arbitrary but bounded set of components. The idea in backward reachability analysis is to compute the set of states from which a state satisfying the negated invariant can be reached.
On the Existence of Network Invariants for Verifying Parameterized Systems
187
If we further assume that each action of the parameterized system involves a bounded number of components (i.e., the synchronization predicate does not contain any occurrence of the superscript ω), then the set of predecessors of an existential assertion can again be expressed as an existential assertion. Having a procedure for calculating pre(φ), a formula that represents the set of predecessors of states that satisfy φ, we can now perform symbolic verification as follows. Assume that f inal is the existential constraint that represent the set of undesirable states, and let initial be a characterization of the initial states of a parameterized system. Typically initial will contain a universal quantification over the set of all processes in the network, e.g., saying that they are in their initial states. A simple description of an algorithm for checking whether f inal is reachable from initial is as follows [KMM+ 97]. Let φ0 := f inal For i = 0, 1, 2, . . . repeat If (φi ∧ initial) 6= false then return reachable Let φi+1 := φi ∨ pre(α, φi ) until φi+1 = φi return unreachable Note that, under the assumption that each action of the parameterized system involves a bounded number of components, each φi generated by the algorithm can be expressed as an existential assertion. This follows by induction from the observation that φi+1 is a disjunction of the existential assertions φi+1 and pre(α, φi ). 3.2
Network Invariants
A method, which has been proposed for the verification of infinite-state systems, is to find a finite-state abstraction of the system, which preserves the correctness properties of interest, and thereafter model-checking this finite-state abstraction [LS97,LHR97,ID99]. Adapted to our framework, this would entail the construction of an abstract process N , whose behavior “contains” the behavior of any instance Mn of the family. Considering that we are interested in verifying invariants which are universal assertions, we define an abstract process to be a process in which each state n is labeled by an assertion L(n) over the states of M . We define a refinement relation v between networks and abstract processes as follows. We say that Mn v N, if there is a simulation relation R between the states of Mn and the states of N such that 1. Each initial state of Mn is related to some state of N ,
188
P.A. Abdulla and B. Jonsson
2. whenever s R n for a state s of Mn and a state n of N , and if s −→ s0 is a a transition of Mn , then there is a transition n −→ n0 of N with s0 R n0 , 3. whenever s R n, then s satisfies the assertion L(n). a
We also define v to a preorder on abstract processes, by saying that N v N 0 if there is a simulation R between states of N and N 0 in the usual sense such that whenever n R n0 for a state n of N and a state n0 of N 0 , then the assertion L(n) implies the assertion L(n0 ). A methodology, which has been proposed [KM89,WL89], is to find a process N , for which the above relation can be checked by induction, checking 1. P0 v N , 2. N k P v N , and 3. φ is implied by each assertion that labels some control state of N The composition N k P between an abstract process N and a component process P is defined in the standard way. Each state of N k P is obtained as a composition n k t of a state n of N and a state t of P , which is labeled by an assertion which states that “all processes except the last one satisfy L(n), and the last process is in state t”. For instance, if L(n) is “at most one process has the token” and t is a state where process P has the token, then L(n k t) could be “one or two processes have the token, and one of these is in state t”. It should be noted that each Mn and N here are considered as open systems, in the sense of Section 2. Thus in the first condition P0 v N , the component P0 is regarded as an open system so that N must be able to simulate all its potential synchronizations with other components. We define a network invariant to be an abstract process which satisfies the two first conditions. A network invariant is said to be sufficiently strong if it also satisfies the third condition. There is a least network invariant N : this is the “union” of all Mn . There is also a largest N which satisfies the two last conditions: this is the limit of the so-called quotient construction [And95,KLL+ 97]. However, there is no guarantee that any of these be expressible by a finite-state program even if P0 and P are finite-state. The discovery of a suitable N is therefore often performed manually (as e.g., in [WL89,KM89]), or using approximation techniques [LHR97].
Example A sufficiently strong network invariant of the system in the preceding section is the finite-state process rec-token
send-token
- ?
τ τ
-
On the Existence of Network Invariants for Verifying Parameterized Systems
189
where the two left states are labeled by the assertion ∀i. ¬c[i] and where the right state is labeled by the assertion ∀i 6= j. ¬(c[i] ∧ c[j]). We note that the disjunction of all L(n) for states n of the network invariant need not be a computational invariant of M . It can be weaker, as long as we can check the invariant to be verified on the basis of these labels.
4
Generating Simple Invariants
In this section, we shall consider the question of finding a computational or network invariant of a particularly simple form. Recall that we only consider the verification of invariants expressed by universal assertions.
4.1
Universal Computational Invariants
We shall be concerned with finding computational invariants that are universal. For instance, in the small mutual exclusion example, it was possible to find a ˇ universal invariant. From results by Abdulla et al. [ACJYK96], the following theorem follows directly. Theorem 1. If P0 and P are finite-state, and all synchronizations occur between a bounded number of components, then the largest invariant is universal. Furthermore, it (or rather its negation) can be found after a finite number of iterations of the backward reachability algorithm in Section 3.1. The main reason why the backward reachability algorithm terminates is that it is impossible to generate a strictly increasing and infinite sequence φ0 , φ1 , φ2 , φ3 , . . . of existential assertions. Any such sequence will converge to a largest set after a finite number of iterations. This can be seen as follows. Since we are considering an unordered system topology, a system state can be represented as a multiset of states of P0 and P . Each existential assertion denotes an upward closed (wrp. to multiset inclusion) set of system states. By Dickson’s lemma [Dic13], any upward closed set of multisets can be represented by a finite set of minimal elements (multisets). When we apply this to an infinite sequence φ0 , φ1 , φ2 , φ3 , . . . of upward closed sets of multisets, it follows that its limit is also upward closed, and that the finitely many minimal elements that characterize this limit must be included after a finite number of iterations. These results have been extended to cover a class of finite-state systems that allow also broadcast [EFM99], and to timed automata with one clock in [AJ98]. For a slightly more restrictive framework, German and Sistla [GS92] have given an algorithm for model-checking arbitrary temporal properties of the controller.
190
4.2
P.A. Abdulla and B. Jonsson
Finite-State Network Invariants
Let us thereafter consider network invariants. A natural desideratum is that such an invariant should not be more difficult to analyze than a component process P . That is, if the processes are finite-state, then the network invariant should be finite-state. In the running example of Section 3, it was easy to find a finite-state abstraction. However, Wolper and Lovinfosse [WL89] observe that by basic undecidability results [AK86], there must be cases where a network invariant does not exist (at least if we assume that linearly structured networks are also allowed). In this section, we will present conditions under which their existence can be guaranteed. To this end, let us employ a standard framework for describing abstractions of concurrent systems. The abstraction N will be generated by collecting states of M into equivalence classes. This can be described by an abstraction mapping h from states of the family M to states of N [Lam89]. Essentially, an abstraction mapping is a simulation relation which is also a function. The condition for N to be an abstraction is then that 1. h(s) is an initial state of N whenever s is an initial state of M , a a 2. if s −→ s0 is a transition of M then h(s) −→ h(s0 ) is a transition of N , 3. s satisfies the assertion that labels h(s). We will now investigate conditions for when the process N is a sufficiently strong network invariant. Note that not all abstractions N are good enough. For instance, the trivial N which has only one state with self-loops for all actions will in general either not be inductive, or not strong enough. In the running example of Section 3, the single state of such a process would have to be labeled by an assertion which implies mutual exclusion (in order to be strong enough) but allows one process to be in its critical section. However, when composed in parallel with a copy of P , it would also have to be able to synchronize with a transition of P that moves from state t to state c, and the resulting composed state would then not satisfy the assertion of the state of N (since it implies mutual exclusion). Definition 1. An abstraction mapping is inductive if 1. whenever h(s1 ) = h(s2 ), then for any state t of P we have h(s1 k t) = h(s2 k t), and 2. the conjunction of the assertion L(h(s)) and the fact that the last process is in state t implies the assertion L(h(s k t)). Inductive abstraction mappings generate inductive abstractions, as shown by the following: Theorem 2. An abstraction N of M which is obtained from M by an inductive abstraction function, is an inductive network invariant.
On the Existence of Network Invariants for Verifying Parameterized Systems
191
Proof. The first condition P0 v N follows from the fact that N is an abstraction. To check the second condition, consider the parallel composition N k P of N and P . We shall prove that there exists an abstraction mapping g from states of N k P to N , from which the theorem follows. We first observe that an inductive abstraction mapping h from states of M to states of N induces a mapping g from states of N k P to states of N by letting g(h(s) k t) = h(s k t), where s is a state of M and t is a state of P , and where s k t denotes the state s of M extended with one extra component in state t. The mapping g is well-defined since h is inductive. It can also be checked that g is indeed an abstraction mapping. 1. If n and t are initial, then n = h(s) for some initial s, and so g(n k t) = h(s k t) is initial. 2. If n k t −→ n0 k t0 is a transition of N k P , then there is a transition s −→ s0 of M with h(s) = n and h(s0 ) = n0 . Thus s k t −→ s0 k t0 is a transition of M , and hence h(s k t) −→ h(s0 k t0 ) = g(n k t) −→ g(n0 k t0 ) is a transition of N . Finally, by the second condition of Definition 1, the the conjunction of the assertion L(h(s)) and the fact that the last process is in state t implies the assertion L(h(s k t)). We will apply this theorem to obtain a result concerning the existence of finitestate abstraction mappings. Theorem 3. Assume that P0 and P are finite-state, and that there is a sufficiently strong universal computational invariant which proves that M satisfies the invariant. Then there is a suffiently strong finite-state network invariant. Proof. Assume that that the computational invariant has k quantified variables. For each mapping from component states of P0 and P to the set {0, 1, . . . , k, ∞}, there is a state of N . Label each state of N by the conjunction of assertions of form “there are at most i occurrences of component state t” for each component state t which is mapped to some i different from ∞. Define an abstraction mapping h from states of M to states of N , by mapping each state s of M to the state of N which corresponds to the number of occurrences of component states of s, where ∞ means “more than k”. Make N into an abstract process by inserting transitions and initial states, as required by the conditions on the abstraction function h. It can now be checked that h is inductive. Moreover, the computational invariant corresponds to a set of equivalence classes of N whose labeling imply the invariant to be verified. Hence N is also sufficiently strong. We have thus shown that if there is a universal computational invariant, then there also exists a finite-state network invariant.
192
P.A. Abdulla and B. Jonsson
v 6= i
{} A[i]
{x[i]}
true v=0
B[i] {}
true x[i] < 1
{x[i]}
v := i v := 0
C[i]
x[i] > 1 v=i
{}
CS[i]
true
Fig. 1. Fischer’s Protocol for Mutual Exclusion.
Example In the example of the mutual exclusion algorithm, the three states of the network invariant correspond to the following partitioning of the states. left state : 0 occurrences of both t and c middle state : 1 occurrence of t and 0 of c right state : 0 occurrences of t and 1 of c
5
Application: Fischer’s Protocol
In this section, we will illustrate the results of the preceding section by verifying a parameterized version of Fischer’s protocol. The protocol has been used as a measure of the performance of tools for verification of timed automata. The example was suggested by Fred Schneider and has been verified manually (e.g., [AL92]) and using theorem provers (e.g., [Sha93]). Several tools for verifying automata with a fixed number of clocks have been used to verify it for an increasing number of processes (e.g., [ACHH92]). Kristoffersen et al. [KLL+ 97] describes an experiment where the number of processes is 50. The purpose of the protocol is to guarantee mutual exclusion in a concurrent system consisting of an arbitrary number of processes, using clocks and a shared variable. Each process has a local clock, and runs a protocol before entering the critical section. Each process has a local control state, which in our model assumes values in the set {A, B, C, CS} where A is the initial state and CS represents the critical section. The processes also read from and write to a shared variable whose value is either ⊥ or the index of one of the processes. A description in a graphical pseudo-code (taken from [KLL+ 97]) of the behavior of a process with index i is given in Figure 1. Intuitively, the protocol behaves as follows: A process wishing to enter the critical section starts in state A. If the value of the shared variable is ⊥, the process can proceed to state B and reset its local clock. From state B, the process can proceed to state C if the clock value is still less than 1. In other words, the clock
On the Existence of Network Invariants for Verifying Parameterized Systems
193
implements a timeout which guarantees that the process either stays in state B at most one time unit, or gets stuck in B forever. When moving from B to C, the process sets the value of the shared variable to its own index i and again resets its clock. From state C, the process can proceed to the critical section if the clock is strictly more than 1 and if the value of the shared variable is still i, the index of the process. Thus, in state C the clock enforces a delay which is longer than the length of the timeout in state B. Finally, when exiting the critical section, the process resets the shared variable to ⊥. Processes that get stuck in state C can reenter the protocol by returning to state A. Since we do not intend to model liveness properties, such as e.g., absence of starvation, we do not impose requirements that force processes to change their state1 . A rough argument for the correctness of the protocol goes as follows. The conditions on the shared variable ensure that a process cannot reach B if any other process is in C or CS. The timing conditions on the clocks ensure that a process cannot move from C to CS if some other process is still in B. Thus, if a set of processes start the mutual exclusion protocol and all arrive in C, then the process which was the last to enter C will read its own identity in the shared variable and enter the critical section. Verification by Backwards Reachability Analysis If we perform a backwards reachability analysis for Fischer’s protocol, starting from negation of the invariant being equivalent to ∃i, j.CS[i] ∧ CS[j] then we end up with convergence and the following fixedpoint ∨ ∨ ∨ ∨ ∨
∃i, j. CS[i] ∧ CS[j] ∃i, j. C[i] ∧ v = i ∧ CS[j] ∃i, j. B[i] ∧ x[i] < 1 ∧ CS[j] ∃i, j. B[i] ∧ x[i] < 1 ∧ C[j] ∧ v = j ∧ x[i] < x[j] ∃i, j. A[i] ∧ v = 0 ∧ CS[j] ∃i, j. C[i] ∧ v = 0 ∧ CS[j]
The negation of this assertion is a universal invariant, which can be written as follows. ∀i, j. ¬(CS[i] ∧ CS[j]) ∧ ∀i, j. (C[i] ∧ CS[j]) =⇒ v 6= i ∧ ∀i, j. (B[i] ∧ CS[j]) =⇒ x[i] ≥ 1 ∧ ∀i, j. (B[i] ∧ C[j]) =⇒ (x[i] ≥ 1 ∨ v 6= j ∨ x[i] ≥ x[j]) ∧ ∀i. (A[i] ∧ CS[i] =⇒ v 6= 0 ∧ ∀i. (C[i] ∧ CS[i] =⇒ v 6= 0 1
In fact, our formalism cannot express such requirements, although they can be added in terms of e.g., fairness constraints.
194
P.A. Abdulla and B. Jonsson
However, a simpler to write computational invariant is the following: ∀i. CS[i] =⇒ v = i ∧ ∀i, j. (B[i] ∧ CS[j]) =⇒ x[i] ≥ 1 ∧ ∀i, j. (B[i] ∧ C[j]) =⇒ (x[i] ≥ 1 ∨ v 6= j ∨ x[i] ≥ x[j]) Finding a Network Invariant The interface between components concerns the global variable v, the timing, and whether or not a component is in the critical section. We can therefore find a network invariant as a system with four states, shown in Figure 2. The figure shows an abstraction of a network containing v 6∈ J
{} {x}
true 1
v=0
2 {}
true x<1
{x}
v := 0
3
x>1
{} v∈J
4
true
Fig. 2. Network Invariant for Fischer’s Protocol. Not shown in the graph is a self-loop at state 2, which sets v to an arbitrary index in J indices in a set J of indices. Here, the four states are abstractions of network states with the following properties. We use idle[i] to denote the property A[i] ∨ (B[i] ∧ x[i] ≥ 1) ∨ (C[i] ∧ v 6= i) denoting processes that are not active in competing for the critical section. ∀i. idle[i] (∀i. idle[i] ∨ B[i] ∨ (C[i] ∧ x[i] < 1)) ∧ (∀i, j. (B[i] ∧ C[j]) =⇒ x[i] ≥ x[j]) 3: ∀i. idle[i] ∨ C[i] 4: ∀i. idle[i] ∨ C[i] ∨ (CS[i]) ∧ v = i) 1: 2:
Not shown in the graph is a self-loop at state 2, which sets v to an index in J.
6
Conclusion
In this paper, we have considered methods for verifying parameterized systems using induction. We have considered the use of computational induction, and of induction over the network structure. The main contribution has been to give conditions under which there are guarantees for the existence of inductive invariants of a simple form. For the case of computational induction, we have
On the Existence of Network Invariants for Verifying Parameterized Systems
195
merely repeated earlier results. For network invariants, we have presented a result that guarantees the existence of a network invariant, provided that there is a simple computational invariant. We should point out that our results are only partial, and we believe that they can be made stronger. As they are, they indicate that simple network invariants exists whenever simple computational invariants exist. The results also show that the construction of both simple network and computational invariants can be automated for finite-state systems with only bounded synchronization.
References ABJ98.
Parosh Aziz Abdulla, Ahmed Bouajjani, and Bengt Jonsson. On-the-fly analysis of systems with unbounded, lossy fifo channels. In Proc. 10th Int. Conf. on Computer Aided Verification, volume 1427 of Lecture Notes in Computer Science, pages 305–318, 1998. ABJN99. Parosh Aziz Abdulla, Ahmed Bouajjani, Bengt Jonsson, and Marcus Nilsson. Handling global conditions in parameterized system verification. In Proc. 11th Int. Conf. on Computer Aided Verification, 1999. ACD90. R. Alur, C. Courcoubetis, and D. Dill. Model-checking for real-time systems. In Proc. 5th IEEE Int. Symp. on Logic in Computer Science, pages 414–425, Philadelphia, 1990. ACHH92. R. Alur, C. Courcoubetis, T. Henzinger, and P.-H. Ho. Hybrid automata: An algorithmic approach to the specification and verificationof hybrid systems. In Grossman, Nerode, Ravn, and Rischel, editors, Hybrid Systems, number 736 in Lecture Notes in Computer Science, pages 209–229, 1992. ˇ ˇ ans, Bengt Jonsson, and Tsay Yih-Kuen. ACJYK96. Parosh Aziz Abdulla, Karlis Cer¯ General decidability theorems for infinite-state systems. In Proc. 11th IEEE Int. Symp. on Logic in Computer Science, pages 313–321, 1996. AJ93. Parosh Aziz Abdulla and Bengt Jonsson. Verifying programs with unreliable channels. In Proc. 8th IEEE Int. Symp. on Logic in Computer Science, pages 160–170, 1993. AJ98. Parosh Aziz Abdulla and Bengt Jonsson. Verifying networks of timed processes. In Bernhard Steffen, editor, Proc. TACAS ’98, 7th Int. Conf. on Tools and Algorithms for the Construction and Analysis of Systems, volume 1384 of Lecture Notes in Computer Science, pages 298–312, 1998. AK86. K. Apt and D.C. Kozen. Limits for automatic verification of finite-state concurrent systems. Information Processing Letters, 22:307–309, 1986. AL92. M. Abadi and L. Lamport. An old-fashioned recipe for real time. In de Bakker, Huizing, de Roever, and Rozenberg, editors, Real-Time: Theory in Practice, volume 600 of Lecture Notes in Computer Science, 1992. And95. H.R. Andersen. Partial model checking (extended abstract). In Proc. 10th IEEE Int. Symp. on Logic in Computer Science, pages 398–407. IEEE Computer Society Press, 1995. BGK+ 96. J. Bengtsson, W. O. D. Griffioen, K.J. Kristoffersen, K.G. Larsen, F. Larsson, P. Pettersson, and W. Yi. Verification of an audio protocol with bus collision using UPPAAL. In R. Alur and T. Henzinger, editors, Proc. 8th Int. Conf. on Computer Aided Verification, volume 1102 of Lecture Notes
196
P.A. Abdulla and B. Jonsson
in Computer Science, pages 244–256, New Brunswick, USA, 1996. Springer Verlag. BS95. O. Burkart and B. Steffen. Composition, decomposition, and model checking of pushdown processes. Nordic Journal of Computing, 2(2):89–125, 1995. CGJ95. E. M. Clarke, O. Grumberg, and S. Jha. Verifying parameterized networks using abstraction and regular languages. In Lee and Smolka, editors, Proc. CONCUR ’95, 6th Int. Conf. on Concurrency Theory, volume 962 of Lecture Notes in Computer Science, pages 395–407. Springer Verlag, 1995. Dic13. L. E. Dickson. Finiteness of the odd perfect and primitive abundant numbers with n distinct prime factors. Amer. J. Math., 35:413–422, 1913. EFM99. J. Esparza, A. Finkel, and R. Mayr. On the verification of broadcast protocols. In Proc. 14th IEEE Int. Symp. on Logic in Computer Science, 1999. EN95. E.A. Emerson and K.S. Namjoshi. Reasoning about rings. In Proc. 22th ACM Symp. on Principles of Programming Languages, 1995. Fin94. A. Finkel. Decidability of the termination problem for completely specified protocols. Distributed Computing, 7(3), 1994. GS92. S. M. German and A. P. Sistla. Reasoning about systems with many processes. Journal of the ACM, 39(3):675–735, 1992. Hen95. T.A. Henzinger. Hybrid automata with finite bisimulations. In Proc. ICALP ’95, 1995. ID99. C. Norris Ip and David L. Dill. Verifying systems with replicated components in Murϕ. Formal Methods in System Design, 14(3), May 1999. JK95. Bengt Jonsson and Lars Kempe. Verifying safety properties of a class of infinite-state distributed algorithms. In Proc. 7th Int. Conf. on Computer Aided Verification, volume 939 of Lecture Notes in Computer Science, pages 42–53. Springer Verlag, 1995. JM95. P. Janˇcar and F. Moller. Checking regular properties of Petri nets. In Proc. CONCUR ’95, 6th Int. Conf. on Concurrency Theory, pages 348– 362, 1995. JP93. B. Jonsson and J. Parrow. Deciding bisimulation equivalences for a class of non-finite-state programs. Information and Computation, 107(2):272–302, Dec. 1993. KLL+ 97. K.J. Kristoffersen, F. Larroussinie, K. G. Larsen, P. Pettersson, and W. Yi. A compositional proof of a real-time mutual exclusion protocol. In TAPSOFT ’97 7th International Joint Conference on the Theory and Practice of Software Development, Lecture Notes in Computer Science, Lille, France, April 1997. Springer Verlag. KM89. R.P. Kurshan and K. McMillan. A structural induction theorem for processes. In Proc. 8th ACM Symp. on Principles of Distributed Computing, Canada, pages 239–247, Edmonton, Alberta, 1989. KMM+ 97. Y. Kesten, O. Maler, M. Marcus, A. Pnueli, and E. Shahar. Symbolic model checking with rich assertional languages. In O. Grumberg, editor, Proc. 9th Int. Conf. on Computer Aided Verification, volume 1254, pages 424–435, Haifa, Israel, 1997. Springer Verlag. Lam89. L. Lamport. A simple approach to specifying concurrent systems,. Communications of the ACM, 32(1):32–45, Jan. 1989. LHR97. D. Lesens, N. Halbwachs, and P. Raymond. Automatic verification of parameterized linear networks of processes. In Proc. 24th ACM Symp. on Principles of Programming Languages, 1997.
On the Existence of Network Invariants for Verifying Parameterized Systems LS97. MP95. Sha93.
Sti96.
WB98.
WL89.
Wol86.
197
D. Lesens and H. Saidi. Abstraction of parameterized networks. Electronic Notes in Theoretical Computer Science, 9, 1997. Z. Manna and A. Pnueli. Temporal Verification of Reactive Systems: Safety. Springer Verlag, 1995. N. Shankar. Verification of real-time systems using PVS. In Courcoubetis, editor, Proc. 5th Int. Conf. on Computer Aided Verification, volume 697 of Lecture Notes in Computer Science, pages 280–291, 1993. C. Stirling. Decidability of bisimulation equivalence for normed pushdown processes. In Proc. CONCUR ’96, 7th Int. Conf. on Concurrency Theory, volume 1119 of Lecture Notes in Computer Science, pages 217–232. Springer Verlag, 1996. Pierre Wolper and Bernard Boigelot. Verifying systems with infinite but regular state spaces. In Proc. 10th Int. Conf. on Computer Aided Verification, volume 1427 of Lecture Notes in Computer Science, pages 88–97, Vancouver, July 1998. Springer Verlag. P. Wolper and V. Lovinfosse. Verifying properties of large sets of processes with network invariants (extended abstract). In Sifakis, editor, Proc. Workshop on Computer Aided Verification, number 407 in Lecture Notes in Computer Science, pages 68–80, 1989. Pierre Wolper. Expressing interesting properties of programs in propositional temporal logic (extended abstract). In Proc. 13th ACM Symp. on Principles of Programming Languages, pages 184–193, Jan. 1986.
!
"
$
!
'
)
;
<
~
]
]
_
@
[
O
U
R
K
<
Y
R
A
M
U
<
O
A
<
K
R
A
K
<
K
G
@
R
`
b
d
f
g
g
h
+
@
R
i
B
-
D<
T
G
k
F
X
f
R
m
'
B
U
j
$
A
K
.
@
D
)
G
B
D<
n
I
B
o
1
K
F
Y
f
2
r
G
G
_
5
G
t
6
<
X
B
@
q
6
O
A
o
4
M
<
q
f
R
[
!
6
$
-
-
>
U
w
x
y
i
z
`
i
t
|
h
o
n
h
U
G
_
)
>
S
\
U
S
U
X
X
A
U
G
B
M
M
O
G
R
¡
<
K
@
[
<
R
B
M
M
K
R
@
B
M
<
B
<
K
M
M
U
M
U
@
X
R
K
B
G
G
R
M
B
B
M
R
G
G
O
K
M
U
B
R
B
U
B
A
[
M
M
U
B
G
U
F
O
R
M
M
G
G
[
A
G
G
U
U
U
U
X
X
@
G
B
K
F
K
M
R
M
U
K
T
G
U
G
X
X
<
X
G
U
O
U
K
R
A
B
R
@
R
X
X
U
U
X
B
R
<
B
M
X
F
B
B
X
Y
G
<
M
<
M
G
@
B
G
G
G
F
A
<
X
O
G
M
U
O
<
K
B
<
G
O
<
B
G
"
®
·
R
!
!
R
U
-
U
F
R
M
M
T
U
G
G
<
O
R
U
T
U
F
O
O
U
K
A
K
G
A
R
U
R
¡
G
¨
G
B
<
<
B
<
X
O
U
G
B
R
M
B
R
[
B
O
X
M
U
X
G
R
@
K
U
X
[
U
M
B
R
[
A
G
B
U
U
[
U
X
G
F
B
U
@
M
ª
G
X
G
U
M
K
F
M
U
G
G
@
<
M
O
[
U
R
R
U
O
X
R
>
A
U
[
T
M
©
[
[
X
@
O
[
U
K
X
<
T
R
U
R
K
X
R
K
<
K
<
M
X
@
A
M
B
F
B
M
A
G
B
>
U
M
<
@
U
G
U
X
[
G
X
F
U
R
G
R
F
A
X
<
G
X
B
R
>
U
<
<
B
ª
B
<
K
B
G
A
R
B
U
ª
<
X
R
K
G
M
B
B
O
<
T
X
X
M
A
M
[
G
U
B
<
G
G
B
<
X
O
³
¸
M
U
A
X
<
A
R
R
²
·
<
[
G
±
@
B
K
>
X
M
O
°
K
U
<
<
K
B
M
U
¯
)
R
K
[
A
[
R
F
B
<
M
<
O
¬
U
´
+
¯
+
µ
)
±
®
2
¸
"
·
)
'
¹
-
!
$
¸
'
º
»
·
)
6
¼
5
1
!
+
5
+
$
¸
¸
"
"
$
!
¸
)
2
$
1
1
½
¾
$
1
5
¸
»
¶
¼
!
½
)
º
¾
1
$
É
1
5
·
6
¸
»
¾
$
1
$
-
¸
$
-
¾
+
¹
Ì
Ú
"
ß
·
"
À
5
+
-
á
$
1
+
¸
)
1
Ç
$
¸
!
5
+
2
$
!
Á
Ç
5
Â
¸
+
!
)
'
¸
6
)
$
+
¸
-
'
¸
)
2
¸
·
¸
È
!
¸
À
"
"
1
$
¼
¸
5
6
2
¸
5
5
¸
)
1
"
"
"
+
2
$
·
)
!
!
!
+
$
+
·
¾
!
)
6
+
$
¼
5
·
¸
-
$
+
2
1
!
!
+
!
Ê
$
)
"
¸
+
$
È
!
Ã
-
$
+
-
1
1
2
»
)
!
¼
!
5
)
6
'
¼
¾
!
·
)
Å
5
!
-
!
¹
)
¸
-
"
)
¾
+
+
'
+
¸
»
+
!
$
5
¸
5
1
!
º
·
5
¸
+
)
$
5
¾
)
·
-
¸
"
Ú
+
·
!
"
+
6
!
2
¾
·
Å
$
)
!
!
)
$
¹
6
»
+
6
!
$
$
!
¼
+
!
6
"
¼
¸
)
¸
¸
"
¼
!
¹
5
¹
¸
)
2
-
2
!
¹
!
5
5
$
-
¼
Ð
¸
¸
'
¹
Ò
»
'
1
-
Ñ
1
)
1
Ú
Ð
$
·
-
!
Ï
¾
Ü
1
¸
6
Ý
+
$
¼
5
+
1
!
Ê
)
6
À
1
$
Á
¾
6
¸
1
¸
Î
!
!
$
-
»
1
$
!
¹
¸
5
+
º
5
·
¹
-
¸
$
$
5
¸
+
»
À
¼
1
¼
$
2
)
1
¸
1
5
!
$
)
º
!
5
Ç
¼
¼
1
¸
Ê
!
$
Ù
·
+
6
"
Ê
Ê
!
)
!
»
¸
Å
$
¸
5
¾
¸
+
+
)
Ç
"
5
2
Ç
+
)
¸
1
6
+
+
+
$
)
Ð
6
5
¾
-
$
+
½
+
!
)
¹
!
-
5
·
!
"
+
)
Ò
)
¹
¸
5
!
)
2
-
¸
¹
¼
!
)
¸
$
$
¸
'
·
"
¼
¸
·
¸
¾
¼
$
-
¹
$
¹
-
!
-
6
$
!
·
¸
!
6
¸
¸
!
+
5
$
5
+
)
¸
)
"
-
-
1
¾
á
1
¸
º
)
5
Ê
¼
$
+
6
¹
!
¹
5
!
2
6
)
'
)
)
-
$
)
$
+
+
»
1
¾
!
¸
Ç
$
¸
¹
·
¹
+
$
-
+
!
)
)
-
5
$
5
É
!
¸
!
Ì
!
Å
·
$
)
-
¸
!
$
6
·
À
À
$
$
¼
)
¸
À
¸
)
¸
·
!
"
1
2
º
·
2
Ð
)
!
5
5
6
-
¾
2
Ï
·
$
)
5
)
Ê
¼
¸
)
+
¹
-
À
$
$
Þ
¸
¾
6
6
¹
+
+
1
)
$
2
2
º
·
¹
)
)
Ë
1
+
'
+
5
1
1
¸
È
º
)
-
º
¸
$
"
+
-
)
È
1
!
'
Å
+
¸
)
'
¸
¾
º
+
¾
º
-
2
â
'
)
!
·
!
+
¸
À
¸
)
$
2
-
¸
$
"
'
!
5
Ê
!
+
5
.
Å
¼
$
$
¼
¸
!
Ê
¶
.
$
À
-
5
'
¸
1
1
"
¸
"
"
5
5
-
6
+
¼
¼
¼
1
$
!
¼
+
6
!
-
-
5
¸
¸
+
6
$
º
¸
5
$
)
+
¸
"
-
'
!
)
1
)
'
+
Å
-
2
1
!
)
!
Å
!
5
2
»
5
-
¹
·
)
!
!
·
¸
-
+
+
º
)
¸
"
)
-
¸
"
+
¼
·
5
È
·
$
¸
5
)
-
Ê
+
¾
1
¸
+
$
·
"
5
Å
'
5
-
¼
!
)
â
·
¸
ã
!
5
È
É
Ç
$
-
)
-
¹
)
5
-
¹
â
)
5
-
¸
¶
¼
!
)
â
·
¸
)
-
·
)
6
¼
5
1
!
Å
5
È
·
$
¸
5
)
-
$
¸
¸
"
¾
-
5
Å
!
+
5
¸
5
+
ä
$
!
1
+
!
¾
"
Ç
ä
5
1
$
-
'
å
1
6
Ê
"
¶
6
$
¾
+
)
¹
1
5
-
ç
-
·
¸
!
»
1
2
¾
$
è
¸
5
ë
ì
í
î
·
¸
$
5
)
1
$
6
ï
¾
-
¹
)
5
º
)
-
·
¸
5
5
5
2
·
!
¸
+
)
!
ê
-
'
+
¼
é
)
$
)
Å
è
5
º
¼
-
·
+
5
1
+
)
¸
5
+
6
!
-
)
¼
$
·
¹
2
5
1
¸
$
!
!
+
-
$
$
$
¸
!
$
'
¸
¸
!
·
"
¸
"
5
6
"
¸
$
¾
+
-
·
·
¸
"
5
)
2
ï
ø
ò
î
ï
-
2
)
)
+
!
)
+
¼
5
¹
!
)
Å
2
!
·
-
'
$
)
2
+
6
!
)
·
·
!
!
!
"
·
Å
5
º
·
¸
5
Ã
-
5
-
!
5
+
È
¹
-
+
)
¹
Ç
'
¼
2
)
¸
·
!
!
"
)
5
6
$
¸
6
-
¼
$
5
+
5
)
Ã
-
1
5
5
$
-
¹
!
"
¸
+
1
+
¹
¸
Ç
¸
¸
"
"
"
$
6
$
¸
À
6
-
À
¸
)
ò
ó
î
ô
ï
è
ì
õ
ò
ö
ô
î
÷
î
î
ï
ì
ø
ù
ø
ç
í
î
ú
í
è
û
î
ü
ì
ý
ð
î
ï
ï
ò
ï
î
þ
ö
õ
ÿ
ú
ö
î
î
ú
ò
ø
ó
ý
õ
ó
è
ó
5
!
Ã
¸
·
è
6
"
)
+
2
Ê
ð
é
¸
!
-
þ õ
)
¾
)
$
$
'
-
+
»
)
1
5
$
º
æ
1
1
1
"
#
&
)
*
Ù
2
¸
+
$
"
M
$
;
G
O
"
¾
Q
O
Q
;
¸
5
-
<
'
$
¾
!
$
)
'
5
-
;
5
+
¸
U
5
"
<
9
9
G
!
·
5
>
L
V
!
·
G
+
P
F
;
F
¸
)
¹
¼
)
2
!
¸
$
·
"
·
$
!
+
-
)
¾
¸
·
-
)
-
)
À
5
+
)
9
¹
$
·
>
1
1
-
5
N
G
P
Q
)
Ç
;
!
-
U
"
F
G
I
¸
5
!
¸
D
À
)
"
;
"
"
·
¸
<
+
!
5
>
¸
O
9
»
'
1
À
@
-
$
;
-
>
)
¼
M
)
<
1
6
>
!
;
6
)
L
9
5
!
2
"
À
)
)
¸
"
ß
!
<
)
¸
Ú
-
;
-
¹
¼
¸
$
-
Þ
5
-
2
5
Ì
!
È
5
)
)
Ý
)
'
5
"
Ü
+
¸
+
Ú
"
5
¾
6
¸
É
+
2
!
6
¹
5
¼
$
)
Ú
¹
"
!
!
Ë Ê
-
;
·
!
6
+
5
$
¸
$
-
-
U
1
¼
¹
!
)
$
¼
)
¹
5
.
!
)
¸
°
À
$
!
5
6
D
W
¸
¸
'
+
!
¼
-
8
»
"
K
µ
$
)
K
$
¸
-
·
<
6
¸
)
»
O
6
6
¾
¸
G
4
$
5
)
5
¼
$
"
¸
+
1
U
±
!
¾
+
5
O
¸
·
º
G
¹
»
¸
+
O
*
)
$
É
+
6
!
+
R
1
¼
¹
'
±
$
À
-
'
+
-
5
.
2
-
!
$
.
)
)
-
+
-
"
¾
Å
5
K
®
)
¸
R
$
¼
5
+
$
!
<
¯
¸
¸
Ê
"
'
X
Q
·
+
1
X
´
¾
¾
P
M
+
·
+
º
¸
°
¸
N
6
6
É
!
M &
°
> L
±
6
+
"
¼
·
<
G
¾
¸
¸
-
9
K
"
+
9
+
G
+
L
> V
Ê
W
]
^
`
.
a
¹
È
·
-
'
)
-
!
b
+
!
¸
$
5
c
'
1
¸
5
5
5
t
i
¾
5
+
g
·
¸
-
f
+
$
)
"
d
j
+
)
l
+
-
i
+
¸
)
m
½
¼
n
¾
l
$
!
-
$
i
¸
1
1
5
p
$
l
1
1
d
¼
$
q
!
-
r
)
¹
'
!
'
5
$
+
6
¸
+
!
5
Ë Ê
º
¾
¸
¸
¸
"
'
¼
!
)
-
¹
'
!
)
$
2
6
¸
+
Ê
"
5
.
+
+
¾
'
º
+
)
-
·
)
¸
¸
5
·
)
-
)
Ç
-
+
À
5
'
+
!
Ã
!
¸
$
·
1
"
¸
$
5
6
Ê
É
·
¹
¾
¸
5
)
-
)
2
$
¼
!
)
¹
!
$
6
·
$
-
º
!
¼
!
+
-
¸
'
º
»
$
+
½
¾
-
·
)
2
+
¸
$
¸
+
¶
º
u
5
-
-
5
-
¹
5
-
$
-
5
-
5
¸
5
$
1
+
¸
$
¸
Ê
u
$
!
5
v
$
w
º
w
1
w
¾
·
)
¸
!
¸
5
)
-
·
-
+
Þ
6
¸
"
¸
"
z
z
¼
¾
5
5
2
$
·
)
)
!
)
!
¸
¸
À
·
$
-
¹
5
!
5
·
5
$
)
)
¹
-
+
!
$
'
1
¾
-
¸
"
+
-
5
!
!
¹
'
¸
)
+
È
-
+
¸
"
¸
$
¾
¸
$
¹
5
5
¸
-
!
2
¸
+
¸
1
$
¸
6
)
5
¸
5
$
·
-
+
¸
·
)
+
6
¼
¼
$
·
+
)
+
)
¸
¼
-
$
¸
'
2
!
!
!
)
$
Å
$
)
¸
¹
2
¸
"
Å
$
1
¾
+
)
"
¼
!
)
¹
!
$
6
2
É
æ
+
6
¾
·
"
5
¸
1
$
-
¹
¾
¼
$
!
º
'
¸
+
¼
-
-
+
$
$
Ù
¸
"
¸
Ê
)
+
¸
"
-
5
"
-
)
"
·
¸
5
¾
!
6
$
5
!
$
6
Ò
Ð
2
¸
·
5
$
"
'
·
!
)
-
$
¹
¹
¸
¼
)
¸
)
¼
º
-
5
"
$
-
+
¹
+
!
+
)
!
¸
!
Å
$
$
·
º
¸
-
¸
1
!
+
¸
)
¸
¸
¼
¸
+
5
¸
¸
¸
"
$
$
¾
¸
À
+
¸
»
6
$
$
¾
1
'
2
)
º
Ã
'
-
"
»
$
¸
-
2
!
¸
¾
5
Ê
)
$
'
¼
$
-
1
-
¸
)
Å
!
5
-
5
»
)
-
)
¸
'
1
À
5
·
+
º
+
$
»
¸
$
)
'
¸
-
$
»
2
$
5
-
"
$
!
+
)
!
6
¹
)
¸
¸
!
¸
¸
·
¾
»
)
¸
·
)
-
-
5
'
¸
"
$
$
.
)
¸
"
2
Ê
½
5
¸
-
"
¸
¸
·
¾
·
¸
"
-
·
¸
+
5
$
5
$
Ð
À
Ê
¸
1
»
!
$
+
ß
$
É
!
Ï
Ê
!
É
"
5
É
º
$
¾
¸
>
-
)
)
Ê
6
+
5
V
+
6
5
L
-
6
+
;
'
Å
¹
Ê
$
À
N
"
+
$
$
Ç
6
!
-
Q
¸
º
"
)
>
$
-
5
9
¸
)
¸
L
¸
$
)
º
$
¾
+
6
·
$
¹
¹
¸
)
)
!
)
-
·
+
!
¹
!
$
-
)
¼
·
¹
5
!
1
â
¼
¼
·
+
-
¸
¹
5
5
5
¹
+
!
¸
¸
1
º
-
O
5
5
$
¾
+
)
Ü
"
¹
!
'
!
¸
5
1
'
É
!
¾
!
-
)
-
-
Å
Ç
Ú
¸
5
+
6
5
¾
¸
2
À
-
$
'
À
5
¹
·
$
!
6
1
-
)
¸
6
+
5
6
!
1
1
!
)
1
)
º
º
º
'
¸
+
$
$
¾
+
1
!
)
"
¸
!
¾
"
$
+
'
»
·
5
'
!
!
¹
¸
¹
5
+
)
¸
-
!
+
"
)
¼
5
+
$
·
¸
9
!
6
Ç
¹
+
'
>
¼
2
¸
!
¸
-
F
)
+
Å
$
)
·
5
;
¹
!
»
1
F
+
1
!
·
Å
'
+
¼
$
-
-
5
5
5
$
"
-
'
'
!
5
5
$
$
-
º
$
9
$
6
¸
)
¸
¸
¾
+
>
$
"
6
-
V
5
5
¸
¸
!
'
"
5
·
!
$
5
L
$
2
"
¸
¸
·
;
·
¸
$
)
¹
Ú
Å
!
)
$
N
º
5
·
6
·
)
6
Þ
)
5
)
Q
'
1
À
¸
$
+
+
¼
¼
>
2
5
5
-
É
"
!
¸
+
9
)
¸
+
"
'
+
¾
·
¹
5
}
5
L
À
¸
¸
-
"
6
!
+
¾
5
)
¸
Ê
+
À
$
$
)
·
$
$
¼
1
5
¸
5
)
-
»
O
1
"
!
¸
¸
)
!
$
¼
-
+
·
'
$
"
"
!
+
Å
)
¸
¸
6
¾
!
¾
"
·
À
$
2
ß
·
6
"
'
1
|
!
"
·
¸
¸
+
6
¼
)
"
v
¾
¸
$
6
2
¸
)
6
'
¾
Á
¾
2
+
¼
!
)
+
2
1
¼
w
)
1
!
+
-
·
$
t
-
'
Å
¸
1
'
w
+
$
-
¸
w
$
2
$
$
v
!
)
+
¸
+
)
+
Ù
1
}
¸
+
)
¼
+
¸
·
Ê
5
$
"
·
+
·
$
u
v
Å
x
1
+
-
$
"
+
Ê
"
"
¶
+
½
¾
-
·
)
2
Å
$
1
¾
+
)
2
¸
"
)
º
+
!
Å
$
º
1
Å
$
!
5
$
º
1
+
5
-
¸
"
+
+
¸
$
¸
+
·
u
º
"
$
Å
5
Ë
)
¸
"
!
+
¸
+
)
$
¾
¾
¸
)
¹
!
¾
)
!
"
2
·
$
Ü
¼
$
+
+
u
$
-
¸
!
!
$
¸
-
·
6
$
!
6
-
+
¸
5
¸
¾
¸
¸
u
¹
$
¾
)
'
½
"
!
)
¹
)
¾
+
º
)
·
¼
)
"
¸
2
¸
É
1
¾
!
+
)
'
¸
5
¹
!
Ê
$
$
!
-
!
Å
$
)
6
º
1
+
1
$
¸
"
+
5
)
)
¸
À
$
5
¸
-
¹
+
-
u
"
+
Ü
u
¸
$
5
-
+
-
+
$
6
}
¾
!
5
5
-
¹
º
Ê
¹
¸
"
"
Ê
$
$
¸
Å
¸
5
¸
"
)
¾
À
)
!
6
¾
º
-
+
·
!
+
)
Å
¸
!
$
º
!
º
1
)
+
¸
¼
"
)
Å
!
$
-
!
¾
'
5
-
$
5
-
º
¹
1
+
u
v
5
-
º
)
¸
"
+
¸
$
¸
+
·
)
-
¸
$
5
-
Þ
-
·
)
'
5
-
¹
+
)
2
ß
¸
"
+
$
6
Å
$
1
¾
+
Ê
6
$
»
º
'
5
·
¾
1
¸
¸
)
'
È
-
Á
Ù
-
$
¾
-
5
+
½
)
¾
¾
!
1
·
»
¼
'
!
È
)
¹
-
!
$
6
'
5
º
»
-
$
¸
"
"
5
5
!
¹
"
-
1
$
6
Å
1
1
$
Ç
-
)
¹
¾
!
$
$
¹
-
¸
$
·
"
·
+
)
º
+
+
¼
$
!
¸
Å
$
"
º
+
1
¾
·
Å
$
"
!
$
5
+
$
º
1
+
$
)
!
!
¾
+
"
¸
¸
)
"
-
¸
+
!
$
$
)
¸
¹
¹
)
!
6
º
'
+
$
¸
¸
¼
¸
!
¼
Å
!
¹
-
$
!
)
À
º
'
!
1
5
"
$
6
-
¹
Å
$
!
Ç
"
)
!
À
5
)
À
-
$
¸
º
È
1
"
Å
-
+
+
!
'
$
¸
$
!
¸
Ç
¸
"
¸
¸
"
6
"
$
·
-
)
!
'
$
5
!
-
¸
!
"
¹
+
+
¸
¾
¾
)
¼
)
+
$
'
6
6
!
-
¹
-
$
¸
-
»
+
Ê
5
¹
)
º
Å
2
$
5
'
!
)
5
5
$
º
)
·
¼
1
¾
1
6
!
¸
$
$
¸
¸
»
5
)
·
)
!
-
"
+
¸
-
5
$
!
$
-
¹
'
Å
5
¸
Ê
¸
1
¼
-
¾
1
+
Ù
"
$
w
¸
¾
+
¼
1
!
5
w
$
¸
-
5
-
·
$
5
»
·
'
¸
)
5
·
+
U
G
R
¡
<
B
R
M
K
M
F
M
O
R
A
U
G
X "
#
initial state …
source r
r
r
r
…
target initial state á
)
!
!
+
¼
)
-
'
5
-
¹
+
¸
$
¸
+
g
Ù
)
¾
¸
¸
5
¼
¾
+
¸
+
+
¼
)
2
·
¸
5
$
"
1
1
»
+
5
)
6
¾
¼
!
·
)
!
¸
¼
$
!
p
-
)
^
¸
¹
`
¸
!
^
"
$
$
¸
6
¸
"
Ú
$
·
-
)
'
6
-
¼
)
5
¸
1
'
6
¼
)
!
!
)
Ê
¹
!
¸
$
6
"
Ú
!
Ü
À
5
¼
+
!
)
'
¾
!
)
·
â
$
+
-
É
"
$
)
!
·
¸
+
+
1
»
¸
Ç
"
Ç
¶
·
)
¾
)
¸
1
"
'
º
!
Ù
¹
!
$
$
-
5
$
5
1
$
¸
º
»
-
5
È
1
1
$
5
¹
5
Å
5
¹
5
!
!
!
"
¸
!
"
Ú
6
+
¾
)
6
5
!
'
¼
$
!
¸
5
+
$
º
)
¾
¸
¸
"
É
·
¾
¸
5
)
-
)
2
Ú
Ü
)
!
+
"
)
À
Ê
"
¸
)
!
¸
!
$
2
¾
)
"
-
)
"
1
¸
¸
"
À
$
$
·
$
»
-
¸
5
"
'
-
+
"
¾
$
'
1
À
º
¸
¸
-
'
+
)
6
'
·
$
¸
¸
¾
¸
»
1
$
-
'
¼
+
¼
$
)
$
6
+
1
!
·
5
¸
·
+
+
¸
-
$
5
-
5
5
-
¸
6
È
5
1
º
$
-
¸
+
+
!
'
À
Þ
Å
$
Ú
"
5
º
ß
1
+
"
2
Ü
·
)
"
$
!
¸
À
)
2
¸
"
À
¸
!
¹
6
¾
"
$
5
+
È
Å
¸
+
-
5
-
¸
6
-
-
$
5
+
$
¸
¼
º
5
¸
+
6
¾
1
º
¾
"
º
+
"
¸
$
Ê
5
)
)
Ù
"
Å
!
-
!
"
1
!
+
¸
¾
2
5
$
5
¸
+
5
º
+
·
¸
2
¼
$
)
)
¸
$
+
!
¼
5
)
-
"
!
Å
-
2
1
)
!
¸
¸
æ
$
»
!
)
+
¸
"
"
+
¸
À
)
+
¸
$
Ë
)
2
$
!
$
!
º
¸
+
)
º
+
Ù
¸
!
Å
$
)
'
¸
!
1
¸
1
5
·
+
5
·
¸
+
+
5
$
¸
-
$
+
5
'
!
¸
$
6
»
1
+
·
!
$
"
5
-
º
¸
$
Ê
¾
!
º
-
+
½
-
5
5
À
¸
5
'
Å
"
5
"
¹
+
Ã
!
¾
+
»
-
'
¼
$
5
-
Å
!
-
$
5
6
)
¸
+
$
·
¸
-
!
+
·
)
º
¾
)
¸
!
»
6
·
'
¼
$
·
5
6
)
)
+
¸
1
"
)
5
)
"
)
¸
6
5
'
)
-
5
+
¸
1
¾
)
$
1
)
»
!
-
¸
¼
$
1
¹
5
"
¸
5
$
6
·
+
-
2
5
"
$
¸
À
1
)
·
Ú
·
¼
-
!
6
5
$
¾
$
"
½
'
!
¹
-
¹
·
¾
+
1
!
!
$
$
¼
º
¸
+
5
5
¹
$
-
·
+
-
'
!
)
5
¸
¾
¼
-
!
)
5
5
¸
)
I
·
É
I
-
5
5
·
;
È
6
$
-
-
-
"
¾
·
>
5
L
½
¾
¼
Á
)
Ù
5
>
Ê
!
»
I
+
"
$
·
¹
¸
6
>
-
-
2
-
> V
¼
¸
¸
;
+
$
-
¾
F
6
)
¸
·
º
P
F
G
O
D
W
;
F
M
Ê
"
¸
!
$
-
+
1
$
¸
'
¼
!
)
¹
!
$
6
Ú
Ü
Ý
Ì
Þ
Ú
ß
6
$
»
6
$
Ã
$
!
º
5
¸
!
$
!
»
·
"
)
5
·
+
$
+
¶
W
u
u
1
)
-
¹
v
$
+
5
v
¸
w
+
w
w
É
·
¾
¸
5
)
-
¼
$
¸
"
Ü
Ü
u
+
v
v
É
·
¾
¸
5
)
-
¼
$
¸
"
)
Ñ
i
£
l
j
¸
¤
¢
«
2
¦
"
+
¨
)
¾
!
"
)
À
+
¸
"
+
$
6
º
"
$
Å
5
)
¾
!
$
+
$
-
$
·
·
¼
¸
$
º
1
u
·
w
w
w
¼
!
)
!
'
¹
!
$
6
Ê
x
Ê
¹
Ê
Ç
¸
"
5
-
'
¸
!
6
5
-
5
+
¸
5
·
¼
!
)
¹
!
$
6
©
b
¬
Ñ
£
l
j
¤
¦
¨
®
b
¢
5
i
-
°
$
+
±
+
"
²
"
³
)
!
´
À
µ
¶
-
2
)
5
!
¸
¹
-
+
1
}
$
5
·
$
¹
)
-
Ê
¹
»
6
¾
Ê
¼
5
$
¹
x
1
+
¼
!
)
2
·
6
$
5
¹
$
¾
1
»
1
¹
$
»
¸
-
"
'
!
·
¼
$
¸
)
$
6
¸
¸
6
"
$
À
"
"
¸
-
5
$
!
'
·
+
"
¹
$
$
1
¸
+
+
À
¼
5
$
!
¹
-
»
)
+
+
¹
!
$
$
+
Ý
+
6
5
2
¹
!
-
)
+
)
!
6
Á
¸
"
Ý
Ý
º
+
5
5
$
+
6
!
$
¼
1
º
·
5
5
·
È
¸
!
¼
$
¸
'
!
+
$
5
1
º
)
»
1
¾
!
Ê
·
¶
Ñ ¢
2
¸
Ù
i
)
"
-
)
-
-
+
1
¾
»
·
$
!
)
º
£
¸
"
¸
"
'
"
$
1
Å
$
$
!
$
1
1
5
¸
¨
©
1
!
$
-
-
¢
º
¸
'
5
!
5
)
5
¸
6
"
+
¸
$
-
º
¾
¸
¹
¸
'
'
¸
¼
!
¸
)
¹
!
!
$
!
1
)
'
'
¹
¼
!
)
"
"
)
·
!
º
¸
¼
)
2
"
+
-
)
+
$
¸
1
)
-
¸
$
$
6
5
$
1
¸
+
1
)
+
+
5
¾
¹
+
-
¾
-
'
-
5
!
6
!
·
1
+
6
+
"
+
+
1
'
5
$
$
¸
-
'
!
¸
5
'
5
·
-
$
-
6
5
5
$
Å
!
"
Å
$
6
¸
$
1
"
-
1
!
'
À
º
"
-
»
!
¦
i
¸
5
¸
¤
b
)
'
)
!
j
$
+
-
+
l
!
-
1
5
2
)
2
5
º
+
"
)
-
º
-
!
¸
Å
5
!
!
$
+
"
+
+
À
¸
)
2
)
+
¸
)
!
)
Ü Ú
+
Å
'
6
Å
¾
1
¸
'
)
$
·
º
-
+
º
5
1
)
¾
¸
6
$
!
¸
5
-
¸
!
5
)
$
+
¹
+
6
+
-
)
»
5
¼
¸
º
$
!
+
+
¸
·
-
+
¸
!
-
·
¸
Å
-
5
)
)
¾
!
À
5
¸
)
-
·
-
5
·
6
!
·
$
5
!
¼
"
¾
-
"
Ê
!
¸
º
6
'
'
'
5
$
+
+
+
-
6
+
)
!
¸
+
)
2
Ê
!
$
6
+
¹
-
!
$
1
5
t
+
¸
"
5
+
+
5
¸
¾
$
¸
5
)
-
Ë Á
+
¸
$
¸
)
2
$
¿
u
ù
¼
!
)
¹
!
$
6
É
·
¾
¸
5
)
-
5
+
·
)
6
¼
)
+
'
2
!
)
6
¸
"
+
¸
$
¸
À
û
)
2
$
1
1
¸
"
!
$
'
+
Â
·
¾
!
!
-
¸
1
»
u
!
¾
-
-
5
-
¹
5
-
¼
$
!
$
1
1
1
Ê
" ¶
+
)
¾
!
·
¼
!
)
¹
!
$
6
Ú
'
È
-
+
$
¼
$
!
¸
5
$
1
)
!
'
!
Ã
$
6
)
-
¹
+
¸
$
1
1
"
#
Ä
&
M &
M
X
<
K
'
R
O
O
U
G
O
<
K
K
x := ?
x := 1
x := 0
x := ?
x := 1
x := 0
x := ?
¾
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
¹
!
$
¼
"
)
2
$
-
5
-
'
¸
!
6
5
-
5
+
¸
5
·
¼
!
)
¹
!
$
6
g
p
^
]
^
ù
¸
"
)
º
+
!
Å
$
º
1
¸
"
!
$
'
+
¸
$
¸
À
û
+
Ê
¾
»
-
·
"
!
)
-
5
t
$
¸
5
)
-
+
$
-
'
·
)
6
6
¾
-
5
·
$
¸
5
)
-
+
º
¸
À
-
u
'
5
¼
!
!
-
¸
¸
"
!
$
'
+
5
-
'
¾
·
$
-
)
!
'
!
º
¸
À
ù
)
¹
!
$
6
Ú
Ü
+
"
)
À
5
-
¹
¸
"
!
$
'
+
¸
$
¸
+
À
-
+
¸
$
¸
+
)
2
'
5
!
-
¸
¸
"
!
$
'
+
Ë Ê
¸
!
$
-
+
1
$
¸
'
û
Ü
5
+
¸
$
Ã
5
-
¹
$
-
$
·
·
¼
¸
$
º
1
É
·
¾
¸
5
)
-
¼
$
¸
"
u
ù
5
2
5
-
¸
"
!
5
+
$
æ
¸
)
æ
6
$
¼
¼
5
-
¹
º
¸
À
-
¸
"
+
¸
+
À
û
È
ù
Ç
$
-
¾
·
'
)
!
'
!
)
2
¸
"
¸
"
!
$
'
+
¸
$
¸
+
À
À
û
È
Ü
'
Ç
u
ù
'
+
¾
·
"
¸
"
$
¸
¸
"
u
û
Ü
5
+
$
!
È
-
6
-
¸
)
2
¸
"
)
!
'
!
Ã
2
)
!
¸
"
5
!
u
ù
·
)
¾
-
¸
!
¼
$
!
¸
À
û
ù
+
Ê
"
)
º
+
!
Å
$
º
1
Å
$
!
5
$
º
1
+
5
-
·
)
!
!
+
¼
)
-
'
5
-
¹
+
¸
$
¸
À
û
ù
+
À
û
Ü
6
¾
+
¸
¶
u
u
u
v
)
2
·
)
¾
!
º
"
¹
+
-
Å
5
»
'
5
-
+
¼
·
¾
¸
5
!
"
"
-
2
$
¸
¸
¸
$
+
)
6
·
·
¸
¸
)
5
)
1
-
¸
!
5
.
¸
1
$
5
Ê
¹
1
¸
'
!
-
$
-
È
Ç
¸
2
)
Å
!
$
)
!
!
!
'
·
'
Å
-
!
º
À
¾
)
)
+
+
!
+
¼
+
1
!
1
!
!
¾
º
$
º
¹
+
1
$
!
5
)
º
$
Å
¸
+
!
)
!
5
)
¸
Å
º
¼
!
º
$
¹
¾
6
)
»
"
!
'
$
5
+
»
¸
Ê
º
¸
5
¹
"
·
-
6
Ê
¸
¸
5
x
1
$
É
¼
6
$
¸
)
$
Å
Ê
1
+
t
-
¸
$
Ê
)
'
¸
À
5
5
5
¾
!
!
+
5
"
5
¸
·
'
)
¸
-
¼
È
À
À
¸
+
-
¸
¸
'
-
-
¸
)
"
-
+
"
)
1
!
!
5
1
5
¾
º
¸
1
+
¼
6
"
¼
"
)
)
·
6
¸
1
¸
$
)
$
¸
x
·
$
¾
)
Ê
$
·
'
º
-
"
·
"
5
5
t
5
¸
+
¼
Þ
+
5
$
À
»
1
"
$
º
-
5
À
-
1
·
-
»
1
¸
)
1
'
À
$
5
¼
'
-
"
-
$
-
)
À
»
$
¸
2
É
$
-
$
)
6
¹
5
-
"
!
6
5
·
-
5
·
Ç
6
1
)
·
ß
6
Ê
¢
]
^
]
É
)
º
q
$
'
g
6
r
5
r
+
g
+
5
Ê
g
º
1
Ë
g
£
Ì
$
¼
!
)
¹
!
$
6
Ú
6
¾
+
¸
º
À
1
1
æ
2
)
!
6
'
$
·
·
)
!
'
5
-
¹
¸
)
¸
"
!
¾
1
+
)
2
¶
¸
"
·
5
+
!
'
¸
!
5
-
+
·
È
·
5
¸
5
·
!
·
$
¹
·
!
¸
$
5
¾
!
+
¾
¸
·
¼
'
¹
-
)
$
¸
-
$
+
+
$
$
6
!
5
1
!
·
+
5
5
)
!
-
¸
¾
+
¾
$
½
$
)
5
+
Ï
)
-
-
+
¹
+
5
$
2
·
Ð
)
Ç
+
¸
+
!
-
-
$
·
5
º
+
¸
6
·
$
'
5
Ç
»
5
1
¸
Ê
·
!
$
$
Ê
Å
6
6
5
1
+
)
-
·
5
)
5
"
¸
¸
5
!
¼
¸
¾
+
'
+
!
Ê
¾
)
)
+
»
æ
¾
'
2
6
¸
+
!
)
+
-
À
º
-
¾
5
+
)
·
¸
$
"
"
È
$
-
"
$
»
¸
+
$
¸
!
·
)
·
5
-
)
5
1
¹
$
¹
¸
¾
-
-
$
-
!
'
1
5
5
¼
"
¸
Å
»
·
¸
$
!
¾
¸
¼
1
)
·
-
+
º
+
!
»
¾
)
'
6
$
)
+
·
+
¹
-
1
Ê
$
!
!
$
Ð
$
1
$
'
$
¸
¹
2
Ï
.
)
2
5
1
)
æ
6
5
+
2
)
5
2
+
!
2
6
$
+
'
-
6
6
-
)
1
5
-
-
¸
È
1
$
'
$
5
1
!
!
º
¾
5
º
1
+
'
»
1
1
+
¸
$
+
·
Ã
¶
)
¸
"
1
¸
¸
5
+
¼
"
!
-
5
"
!
5
)
-
¹
¸
½
!
¹
À
!
$
¾
5
6
1
6
!
$
¸
1
æ
6
5
2
+
)
É
-
!
-
)
)
¼
6
¸
¸
)
-
'
1
-
»
2
"
-
$
À
+
Ê
+
)
Å
"
Ê
'
5
5
$
-
·
¹
$
"
·
2
»
·
)
À
2
)
¾
!
+
!
)
-
5
+
¾
6
+
+
$
¸
$
¾
$
1
1
1
-
1
1
'
·
+
·
·
¾
»
+
»
·
·
¼
5
)
+
5
¸
'
·
-
5
-
"
)
!
)
-
'
5
¸
'
)
5
5
!
-
)
)
-
¸
5
¼
2
+
)
!
¸
$
-
)
"
!
+
¸
6
º
1
+
¾
¾
!
º
+
6
)
)
+
¸
º
)
2
·
·
'
¸
»
1
"
¼
$
-
·
·
5
¹
Ã
'
$
'
$
·
¾
º
)
1
-
¹
2
+
2
+
Ê
x
!
5
)
¸
!
)
Å
+
¸
6
-
º
¸
·
-
$
»
æ
"
º
æ
¶
À
)
¸
·
»
¼
-
-
5
'
'
5
-
¸
¹
5
)
·
1
·
-
$
+
)
-
!
Ê
$
¸
'
5
5
¾
)
¸
5
-
)
¸
+
-
6
$
+
$
$
-
!
-
'
»
¾
+
¼
)
!
-
1
)
)
»
¹
2
!
·
'
$
"
6
·
1
·
6
$
Ã
5
'
!
-
$
¹
'
¸
1
$
-
!
-
¸
¾
-
¹
5
æ
¾
¸
5
¸
$
5
¹
+
6
5
+
-
·
$
5
-
É
¼
-
!
¸
$
"
1
5
+
+
+
+
)
-
º
·
)
5
$
+
+
$
·
¼
+
)
!
À
6
)
¼
¼
5
1
!
1
1
2
æ
¸
'
)
»
!
¼
+
6
5
¾
-
·
¹
'
"
-
5
¸
+
+
"
$
¸
-
)
¸
+
$
À
+
)
1
6
1
æ
2
)
!
É
"
6
¸
-
¸
'
-
¸
)
!
+
+
-
6
5
·
'
-
$
¸
)
+
5
-
5
)
'
¹
5
-
¸
5
'
-
º
)
"
Ë
-
·
Ê
5
$
+
5
Å
'
)
5
-
)
6
5
+
¾
)
!
+
+
2
)
5
¸
º
"
2
5
1
5
¸
·
$
¼
»
)
!
)
6
)
2
¼
¹
!
+
5
$
1
)
U
¾
!
!
·
¡
!
$
R
·
À
6
G
<
¼
5
¸
!
-
R
)
!
-
B
M
K
¹
M
!
$
F
6
M
+
O
'
R
¼
A
U
-
G
X
'
"
+
¸
"
¾
#
Í
+
¸
)
Ê
Å
!
º
$
À
1
1
æ
2
)
!
6
'
-
+
+
¶
·
)
-
'
'
$
Å
¸
5
5
$
)
¸
Ê
1
)
5
1
2
¸
¸
+
$
5
!
¹
¸
.
¼
!
·
"
)
·
5
6
+
¼
¸
5
2
$
-
!
Ê
¾
6
$
¼
»
!
¾
¸
¸
5
!
!
5
5
¸
"
·
$
$
-
¸
¼
-
À
5
1
¸
)
!
º
)
»
'
¸
!
"
5
5
!
)
â
Ý
¸
¸
!
-
6
¹
¾
Á
+
5
$
¹
)
+
+
×
5
É
¼
·
À
-
¼
'
¸
)
5
)
5
!
5
-
-
!
5
+
-
'
¸
"
¼
¾
)
+
5
-
¸
-
)
¾
5
!
1
6
5
Ã
"
¼
¹
$
6
·
¸
'
!
'
$
¹
$
6
5
)
+
·
¸
É
!
5
)
·
6
5
¼
Î
2
!
1
$
É
»
¸
2
¸
!
5
$
$
!
+
)
6
'
¸
+
×
'
$
"
!
)
·
-
¸
¸
5
6
+
¸
Ê
á
-
º
¸
¸
+
5
1
5
"
$
6
+
6
¸
!
$
¸
$
»
"
·
Ö
1
"
¸
5
'
¾
$
5
'
Õ
"
¹
!
¾
Ò
+
6
$
!
)
-
'
!
¼
!
5
+
-
¸
)
À
!
"
!
æ
$
-
6
1
¸
}
$
1
$
-
$
)
Ê
)
$
·
'
+
¹
!
!
!
-
!
-
"
1
$
5
-
)
5
"
¸
)
¼
$
»
)
!
-
¾
$
¹
6
½
-
)
Å
6
5
t
·
+
¹
»
!
-
1
º
"
$
5
º
-
Î
-
$
¸
$
-
'
)
+
6
5
-
É
5
2
¸
5
-
!
+
$
1
¾
¸
·
5
'
2
¸
5
-
¸
$
Å
)
6
)
6
¾
'
5
Å
Ò
·
¼
-
'
+
Ý
"
¾
$
+
5
+
-
Ð
¸
6
1
5
·
$
"
-
¾
-
!
1
5
$
-
¹
5
5
¹
5
!
1
"
¸
+
)
º
¸
$
·
!
+
¹
6
2
+
5
5
·
)
+
$
1
-
Å
$
-
5
2
Ê
¸
)
5
)
Ç
-
-
Î
¾
)
$
'
»
)
5
Å
¸
+
¸
6
¹
1
¹
5
-
+
¸
)
5
5
$
6
Ë
)
)
1
¸
+
¸
!
-
!
5
+
-
6
)
º
æ
¾
¼
+
5
Ê
5
$
2
»
-
º
æ
+
-
6
+
1
+
)
¸
$
+
)
5
À
5
!
1
$
¸
"
-
5
¸
¸
6
+
'
-
-
¹
5
-
Á
À
-
¸
)
+
5
-
'
Å
5
·
)
Ù
$
Ë
+
5
-
5
-
+
6
5
¹
+
¸
»
"
$
)
+
¸
¸
¾
5
1
)
'
-
º
+
6
)
"
2
Ø
-
"
¾
1
'
6
)
!
!
º
¸
5
!
·
5
+
+
¼
)
$
Ç
$
-
-
-
+
+
5
'
¸
º
2
-
1
!
2
)
'
)
6
¸
!
1
)
·
¼
5
!
6
)
5
-
+
)
¸
¸
º
$
!
1
¸
5
¾
6
)
·
+
+
¼
!
¸
-
$
)
!
2
)
5
+
¹
!
+
5
¼
-
$
¹
6
2
'
!
)
$
+
$
6
-
-
!
'
'
+
¸
$
¸
)
-
)
¹
!
¼
!
$
$
¹
)
Å
-
)
¸
'
2
$
"
5
!
5
+
¶
·
)
!
)
!
2
!
¸
)
¸
)
-
-
¸
¸
)
5
1
1
5
¸
»
)
+
5
)
$
·
+
$
5
+
$
$
¹
6
¾
!
-
¼
)
·
5
6
!
+
'
!
)
¸
-
¾
!
¹
·
$
!
-
$
$
+
)
¹
!
Á
5
5
!
¼
'
6
+
»
¹
¾
5
·
1
1
$
'
!
º
$
!
)
+
¾
5
5
)
Å
+
)
+
-
+
+
)
¸
¹
¸
¸
¼
)
-
·
"
+
¼
5
+
5
-
-
1
·
¼
!
)
)
+
5
¸
5
5
¼
5
+
5
-
$
·
·
)
+
¸
¼
¸
·
¼
¸
5
¹
¸
6
5
5
¸
!
-
¾
À
$
)
$
¼
)
'
1
·
-
"
¸
$
!
5
Ç
¾
À
)
¸
1
5
-
-
$
º
¸
5
"
$
·
-
!
)
$
$
!
+
!
"
¸
!
'
¼
¸
-
-
¹
¹
Ù
-
Å
-
-
Ê
'
5
'
+
'
-
!
-
!
)
2
"
)
¸
!
¾
+
+
$
)
+
¸
+
!
·
5
¾
2
·
)
6
-
+
!
5
-
¸
¼
1
"
$
·
¹
º
"
¸
!
-
·
'
¾
"
Ê
»
5
!
·
!
1
$
!
¾
$
1
+
1
)
$
5
¹
!
¹
À
¼
!
-
$
!
"
¸
-
"
¸
¸
-
¸
5
!
)
!
Ã
Å
)
$
À
6
2
!
Ã
¸
1
$
"
¸
·
5
"
6
¸
+
5
º
·
+
¾
5
5
!
"
"
+
¸
6
)
¸
À
5
)
2
$
$
"
Ç
"
6
¼
¸
!
À
¸
$
$
¸
'
Å
5
¼
1
æ
+
5
+
¶
¸
)
2
$
1
"
+
)
1
·
¾
)
!
¸
)
!
'
$
¸
6
1
»
·
)
!
·
)
6
^
!
·
1
È
$
å
â
æ
ã
â
1
á
á
l
»
b
â
Ü
$
ã
ç
!
ß
Ú
è
v
Ü
v
w
w
w
¸
!
»
!
Ç
5
·
Ù
¸
¸
·
!
5
1
)
1
6
5
¼
)
5
-
1
1
5
!
-
6
¾
+
)
+
¸
2
º
·
)
'
$
1
1
)
Å
À
-
'
5
¸
2
¸
)
!
"
2
»
¾
$
+
!
·
$
)
6
'
¼
6
5
5
+
1
+
5
$
¸
º
5
1
)
-
5
-
-
¸
·
)
·
¸
!
!
5
'
5
+
5
1
6
!
Å
$
$
"
)
!
5
!
¸
¸
¸
1
"
¸
5
6
·
5
$
¸
¼
À
$
"
!
!
)
5
¼
1
!
À
·
-
¸
!
5
6
$
$
¾
¸
'
·
-
)
$
$
»
6
+
+
5
!
6
"
"
"
"
5
¸
¸
-
$
·
»
6
2
+
$
"
1
À
6
À
¹
!
6
-
'
$
+
$
5
+
¼
$
¹
)
6
!
)
+
¸
6
¹
!
-
¹
)
)
¼
)
-
!
·
!
¸
)
1
¼
1
$
'
!
1
5
5
Ë
!
¸
á
â
ä
"
ç
ä
é
·
Ê
¾
¼
6
-
+
)
$
ñ
$
6
5
¼
!
!
¾
+
)
-
$
+
Ë 1
5
·
$
)
1
6
¸
¸
+
5
)
1
5
¹
¼
t
5
$
¸
1
¸
5
¾
¼
)
+
$
-
6
5
¸
+
Å
"
$
"
·
¾
¸
+
!
$
)
-
)
'
)
"
¸
!
!
-
+
¸
¸
¸
!
$
À
»
6
Ê
+
¼
1
$
!
-
+
!
"
¹
1
¸
)
!
-
$
¹
-
'
Ê
r
â
æ
1
$
)
)
"
r
ã
æ
)
$
·
·
1
+
æ
!
º
¸
b
í
í
5
Å
â
ô
æ
5
Ý
5
å
+
$
¾
5
"
£
!
ä
+
'
¸
·
Ç
¸
)
À
-
Ë Á
2
$
+
+
2
2
)
"
5
)
)
l
1
ß
·
»
1
+
¸
!
6
¸
Ê
2
$
+
¸
i
-
Þ
+
5
Û
-
+
6
+
'
'
¸
$
¸
¾
$
!
)
5
É
1
5
·
-
6
-
Ú
.
!
¸
¼
!
!
·
)
¹
¼
-
5
1
)
+
)
¸
¸
!
$
$
À
5
¼
!
·
)
$
$
]
5
¼
Å
6
·
"
.
2
)
ö
â
2
Ú
ä
ö
â
1
ð
ä ì
)
À
5
Ì
á
ñ
1
Ý
÷
á
)
Ü
Þ
ç
á
¹
é
ß
'
ß
è
ß é
-
Ú
é
è
ä
è
ñ
í
È
-
â
¸
æ
ë è
æ
5
ê
ä ì
é
á é
-
ä
ò
ï
)
â
å
ß
5
â
ß
ß
ï
æ é
2
ß
ß
ä
)
ê
ä
ò
·
â
â
â
)
á
è
ä
¼
5
á
é
ä
ê
6
ë
ì
ß
á é
å
â
æ
1
!
æ è
·
ë
ë
á
ã
â
ê
á
)
æ
!
!
í
ê
ä
ç
ß
å
ë
¸
-
ä
ß
á
·
ï
á
á ñ
ð
+
ð
ä ì
á
+
Á
ç è
ä
ë
é
ä
ù
é
ä
ù
è
ñ
ê
ä
ê
ä ì
ò
ß
ò
ß
ò
ë
æ è
æ é
æ è
â
å
ë
ê
ä
á
å
ß
á
ï
ß
ï
v
æ Ü
í
ß
ï
ä
ß
á
â
ã
ä
ß
å
â
æ
ã
â
á
ç
ò é
ê
ï
ß
ï
á
ß
ï Ü
æ
ð ì
í é
æ
â
Ý
º
Ú
ç Ü
á
÷
v
v
ß
ä
ß
á
w
w
w
ý
v
â
v
w
w
w
ý
ç
ë è
á
ß
ä
å
â
ä
ç
á
ß
ò
â
ä
÷ ì
þ
ß
ï
è
á
ë
ä
â
â
æ
â
ç
ä é
á é
ã
ä
ð
ò
ä
ß
æ
ö
æ è
á ì
ß
æ è
ë
æ
í
â
ä
æ é
ò
â
ê
ä ì
ç è
è
ß
æ è
ë
æ é
ä
ù
ä
ê
ò
ß
æ è
ë
å
á
ß
ï
æ
í Ú
ê Ü
æ
ë
ß
á
ë è
æ é
ñ
ä
â
é
ö
á
ä
ñ
ì
ß é
á
ß
ä
þ é
ï
ê è
ï
ð
æ
ë
æ
ß
â
ä
á ì
ß
ä
ß
æ
å
æ é
é
è
ñ
ä ì
ß é
á
ß
ä
æ é
í
ä Ú
ù
ê
ä
å
ß
í
æ
â
ä
â
â
æ
â
ß é
á
ß
ä é
Ë +
º
2
)
!
5
+
¸
"
Þ
+
¸
$
¸
'
¼
-
'
-
¸
ß
!
1
$
¸
5
)
-
!
½
¾
5
!
5
-
¹
¸
"
$
¸
$
1
1
)
º
+
!
Å
$
º
1
Å
$
!
5
$
º
+
Ë
1
)
¾
!
·
·
)
+
·
6
¼
)
¼
!
)
-
5
¹
!
1
¸
$
$
!
6
5
-
¸
+
+
5
-
"
-
¸
)
+
¸
5
$
$
$
º
1
6
1
»
5
5
¸
+
Å
+
$
$
1
½
¾
¸
¾
-
É
+
·
¸
Ê
6
$
·
$
-
1
5
1
¼
¾
'
1
¸
$
"
¸
5
)
-
¸
$
¸
!
)
¹
)
1
¸
Ç
¼
¸
!
!
)
$
-
¹
+
!
$
2
)
6
!
6
5
Ê
-
" ¶
¹
¸
'
"
È
¸
-
5
É
¸
¸
5
)
)
-
2
'
¸
"
)
+
"
#
-
)
)
2
)
2
&
¸
'
¸
5
"
!
É
5
·
¸
!
1
·
¾
X
!
5
M
»
É
¸
M &
·
)
<
1
¾
$
¸
-
K
¸
5
6
)
¼
-
)
!
Ç
'
)
5
1
¼
Ê
+
'
R
Ê
O
!
Ç
¸
+
Ê
"
O
5
U
)
+
¾
G
)
!
+
O
2
·
<
K
+
)
$
6
$
K
¾
-
-
!
·
'
¸
5
¸
·
$
$
+
!
)
-
'
¹
2
¸
¸
¸
$
"
¼
!
!
¹
¼
)
¹
!
¸
!
)
¼
$
¹
!
6
!
$
6
)
¹
$
!
+
!
$
6
+
¸
À
"
5
º
É
·
¾
¸
¸
¾
"
$
)
6
1
-
!
¾
+
1
»
¼
¼
¸
!
º
!
+
)
!
¼
-
1
¸
$
!
$
¸
¸
¸
5
5
)
+
-
'
+
$
!
¶
¸
"
+
É
"
5
·
+
¾
5
¸
-
5
+
5
)
-
¹
6
"
)
¸
1
'
$
'
1
+
+
Ê
¸
)
¸
"
'
5
$
¹
!
$
6
}
5
¹
Ê
Ù
5
-
'
5
·
$
¸
+
¸
"
·
)
6
¼
)
+
5
¸
!
1
$
¸
5
)
-
¶
interprete
SL-prog
SL-exec
r
compile
interprete
TL-prog
á
)
!
!
·
¸
TL-exec
-
+
+
'
5
$
¹
!
$
6
g
º
¸
À
-
)
º
+
!
Å
$
º
1
+
¸
$
¸
+
p
2
^
!
Ú
)
^
6
}
5
¹
Ê
Ê
"
'
5
$
¹
!
$
6
6
¾
+
¸
·
)
6
6
¾
¸
Á
.
"
¸
"
!
¶
À
)
¹
º
¸
'
)
·
!
$
+
¸
¾
¸
-
!
)
·
!
·
¸
!
"
¸
¸
+
"
)
!
+
6
5
¸
5
5
)
¸
1
5
Å
º
!
!
!
+
·
$
+
+
5
¸
Å
-
)
+
6
!
¸
)
)
)
2
)
+
¸
$
!
º
$
!
"
)
5
)
¸
)
6
+
-
-
¾
$
"
¸
1
¸
1
"
+
5
$
¸
Å
·
-
6
Å
6
1
!
)
)
È
!
À
¾
2
!
+
)
'
»
¼
2
¾
1
$
+
)
!
¸
+
+
-
)
·
¸
¸
5
5
-
+
!
'
'
5
)
)
º
Å
+
$
¹
$
$
Ù
1
$
·
5
-
Å
5
)
º
!
!
º
¼
5
)
Å
À
!
Ê
$
¤
1
5
Å
º
Å
$
$
1
1
º
)
¸
1
+
$
'
+
'
$
1
1
!
+
!
¾
-
$
¼
$
$
6
Ê
+
5
-
5
È
)
)
'
1
¹
-
2
!
¸
5
)
-
$
5
À
$
+
)
'
¸
-
!
¸
)
+
¸
+
-
5
¼
"
¸
-
!
6
¹
-
·
¸
!
)
$
¤
$
5
¼
¾
¼
2
·
¸
)
)
-
6
!
·
5
¸
)
È
!
À
+
5
¹
6
$
5
$
¼
"
+
!
6
¸
!
¾
5
1
¸
-
¸
6
!
À
$
¸
5
)
-
Ê
5
¸
)
¼
-
2
)
!
À
"
5
·
"
+
)
¾
!
·
¼
!
)
¹
!
$
6
+
¸
"
·
)
6
¼
5
1
!
À
5
1
1
¶
6
5
6
¸
¾
'
$
+
·
¸
È
º
-
5
¼
5
!
+
)
Å
·
¸
¸
·
$
5
!
¹
-
¸
1
¸
¼
»
1
!
$
)
!
¹
¹
!
$
6
Ê
º
¾
}
)
¸
¸
!
$
"
5
·
+
!
)
6
½
¼
¾
5
5
!
1
!
¸
6
)
-
º
¸
5
¼
+
!
-
$
)
·
¸
¸
5
¼
·
$
$
!
1
1
»
¸
¾
)
+
2
¸
2
"
¾
1
¸
·
)
"
5
!
!
+
·
·
1
¸
$
-
+
+
+
+
Ê
+
)
¾
-
6
!
!
¸
)
)
´
µ
¸
"
´
!
·
¯
)
µ
6
±
®
6
.
¾
¸
!
$
¸
5
®
Å
²
5
¸
*
»
)
±
2
¸
4
"
6
µ
$
º
8
)
+
°
Å
#
'
5
°
$
¹
´
!
%
$
µ
¯
6
+
´
À
¯
³
-
°
+
'
$
2
)
!
6
$
1
'
+
·
!
5
¼
¸
5
)
-
¶
)
1
2
¸
$
"
-
¹
¾
$
¹
.
6
$
'
+
¾
+
¸
·
¸
5
½
5
!
¾
-
+
5
5
)
-
6
"
5
+
"
º
¸
·
-
¹
"
·
¸
$
-
¸
-
¾
À
·
º
¹
·
)
'
1
+
Ç
5
Ê
Ê
Ç
$
2
)
!
6
$
1
+
6
$
-
¸
5
·
+
)
2
¸
"
+
)
¾
!
·
$
-
'
¸
"
¸
$
!
¹
¸
Ê
·
5
-
"
-
·
É
+
+
+
¸
·
)
+
-
5
)
¸
!
)
+
¸
¸
·
6
$
¸
$
¾
$
¸
)
6
'
·
)
5
¸
5
¸
$
Ê
-
)
·
-
"
-
+
$
5
5
¼
"
-
¹
2
1
}
$
!
)
$
Á
1
)
+
6
$
-
-
5
"
¸
"
»
)
¹
¼
$
2
5
!
·
!
5
)
"
5
+
$
-
¼
$
$
¹
È
6
!
¾
)
2
-
-
6
)
-
¸
·
+
2
5
+
¸
+
+
+
+
¹
¸
·
1
¸
·
'
5
)
-
5
5
$
$
-
º
¾
¸
6
$
6
!
!
)
¸
!
$
)
·
-
$
¸
)
-
-
¹
"
5
2
5
+
$
¹
6
¹
-
¾
-
-
+
+
6
¸
¸
2
)
)
!
!
¾
"
!
-
»
·
5
¸
5
5
Å
)
¸
!
-
'
-
+
2
»
5
¾
+
¸
·
)
)
!
-
5
¸
+
¸
6
+
'
$
!
¾
!
¾
º
-
1
+
·
»
¸
5
¸
5
·
æ
)
-
É
æ
)
-
Ü
v
È
Ç
È
'
Ç
(
È
Ç
È
(
Ü
Ç
à Þ
È
"
Ç
)
1
'
+
À
"
!
'
(
Ã
v
6
$
»
!
+
·
"
'
¾
1
$
!
'
+
·
!
5
¼
¸
5
)
-
+
ß
È
'
)
2
¸
Ü
"
Ç
Ã
6
$
·
"
5
-
+
¸
$
¸
Ê
x
Å
-
5
2
¸
"
"
$
!
'
À
$
!
v
¸
"
)
!
'
!
)
2
5
-
+
¸
!
¾
·
¸
5
)
-
É
·
¾
¸
5
)
-
)
-
¸
"
*
»
$
+
)
-
¸
"
¿
-
¸
5
¾
6
Ù
Ù
5
¸
5
!
+
¹
5
-
+
¸
Ë
.
¾
$
6
º
·
¸
!
+
)
¾
¾
å
5
2
»
5
¼
¸
¾
+
1
$
1
¸
2
+
!
6
$
¸
)
-
¸
!
"
1
$
'
5
6
-
¸
!
¼
¾
¹
+
5
+
-
¹
-
+
!
¾
¸
1
+
<
-
$
B
R
+
+
$
-
$
M
2
5
¹
K
!
¾
M
)
F
6
-
5
$
+
M
$
$
5
'
O
-
+
'
R
¸
¸
+
5
)
·
-
Ç
1
·
)
¸
+
)
¹
·
5
¸
-
-
¾
¾
-
-
¹
º
6
1
¹
6
6
!
)
!
·
¾
5
¹
$
5
¡
A
U
)
G
X
)
"
º
+
!
Å
#
$
,
º
1
Ê
)
Ç
¸
·
¸
¹
!
-
R
'
-
¼
)
$
5
$
¸
!
¹
6
1
6
+
-
6
5
¼
$
º
+
+
)
"
$
+
5
·
!
+
!
"
!
-
)
5
É
¸
)
¾
6
+
¸
+
'
Ç
·
+
-
¼
$
+
¾
5
1
1
-
'
'
$
Å
1
)
-
6
$
¸
$
2
'
1
$
!
G
)
2
!
Å
¼
'
$
)
6
'
-
1
-
)
»
5
¹
¸
5
)
+
!
)
"
¸
-
+
»
$
1
+
-
+
)
1
)
5
º
$
·
¸
5
5
-
!
!
+
·
¸
¸
-
æ
¸
¾
¸
·
$
Á
-
$
!
1
$
æ
¸
·
¸
+
5
·
Ê
·
2
¹
'
)
+
)
-
5
!
-
¹
¼
6
1
)
5
-
$
"
$
2
5
"
5
Ê
¸
!
)
¸
-
·
6
!
$
2
$
+
¸
¹
·
)
$
)
'
)
+
)
!
!
·
"
!
¼
5
Ç
¼
¸
·
!
1
6
+
"
-
¸
¾
)
»
+
5
!
-
"
!
"
¸
5
+
¹
»
$
¸
¾
¸
"
)
6
¸
-
¸
6
¸
'
2
-
-
5
¸
+
)
$
¹
5
·
$
+
1
)
)
!
+
-
6
!
"
6
¸
¼
6
·
¸
'
"
)
1
Ç
'
-
¸
-
¸
»
+
)
-
$
)
¹
!
+
+
'
¾
!
1
¹
+
U
+
)
)
2
!
¸
"
"
5
¹
"
1
1
$
-
Å
¹
¾
1
$
1
¹
$
-
¹
¾
Ê
$
"
¹
5
+
+
5
6
+
'
$
»
+
·
º
!
5
º
$
¾
'
¹
º
6
»
5
-
¸
-
2
)
!
'
6
$
À
5
1
¸
1
»
"
+
·
¼
!
¸
·
$
5
æ
-
¶
À
·
1
)
1
æ
2
6
)
!
¼
5
6
1
'
!
-
·
)
!
+
!
+
·
·
)
¸
-
À
'
5
¸
-
5
)
-
+
À
'
"
$
2
5
)
·
!
"
$
6
$
·
1
)
'
6
+
¼
·
5
!
5
1
¼
!
¸
5
6
)
¾
-
+
)
¸
2
¸
¸
$
"
Ã
5
·
-
¸
$
!
!
¼
)
!
2
¸
Ê
$
}
¸
)
5
)
!
¼
-
!
)
Ê
Å
"
5
-
!
¹
$
$
!
¶
+
Å
·
$
!
2
¸
!
5
)
$
)
$
-
¸
5
!
1
+
)
)
!
¸
$
"
¼
!
5
Ê
+
)
¾
Ê
Ç
À
¾
6
)
¾
1
"
¸
$
$
1
!
$
5
-
$
º
¹
+
¸
$
6
¸
5
2
$
!
6
5
$
¸
)
º
À
)
6
$
+
-
!
-
Å
5
$
·
º
1
¸
!
¹
+
"
!
¸
¸
$
+
+
+
5
$
¾
1
¸
!
$
·
$
)
-
-
$
+
$
¹
!
"
Ê
+
$
5
¸
º
$
1
$
5
·
+
¸
+
¹
5
¸
¾
¸
!
¼
Å
6
·
-
5
$
È
æ
·
)
"
5
¼
æ
-
+
Ê
5
¸
º
·
+
+
)
5
+
¹
'
+
¹
¸
$
5
-
¸
-
¾
"
1
+
6
¸
)
$
¾
'
+
·
1
Ç
)
-
$
+
6
+
$
1
¸
·
1
1
1
5
+
1
¸
$
)
-
·
¾
-
)
!
6
5
5
¸
)
!
$
$
"
¾
2
6
-
)
¸
+
·
+
$
6
+
$
)
6
¸
5
"
"
$
1
6
"
¸
$
¸
·
)
-
2
Å
)
+
)
)
5
¹
$
+
!
¸
!
"
¼
'
$
$
¸
¼
¸
¸
¸
·
¸
)
)
¹
-
"
â
¸
!
¸
!
$
'
Ã
¸
)
-
·
"
+
!
+
Á
·
¼
+
$
+
-
!
¸
'
5
¾
$
)
¸
"
)
¾
)
¸
!
"
Ê
+
"
)
¸
+
¸
6
$
·
¹
2
5
-
-
¸
1
¸
"
+
¾
6
-
5
¸
-
)
-
"
»
5
$
5
2
5
-
+
·
5
"
)
5
·
)
$
À
·
5
6
$
¸
6
'
¸
2
$
'
¼
6
¼
6
5
+
+
1
!
1
¸
»
¹
1
·
$
$
)
+
-
+
¸
¾
)
¸
1
'
¸
5
¾
!
)
¸
$
¸
¼
"
'
+
-
+
-
$
»
+
·
5
5
1
!
6
º
º
!
$
¸
!
"
5
»
$
¸
!
1
$
)
¹
!
+
¼
1
+
+
)
$
¼
6
)
Ç
-
.
¹
¼
5
"
+
-
)
¾
6
·
!
!
$
¸
À
$
·
·
"
"
¼
5
-
¸
»
$
!
$
!
!
)
)
2
æ
)
!
¹
¾
-
¸
'
Ç
Ê
"
5
-
+
Ï
.
Ï
.
Ü
º
»
$
·
"
)
¸
"
!
·
$
-
º
'
)
-
5
-
+
Å
æ
v
!
$
1
+
¸
¼
+
Á
.
6
$
»
5
-
Å
-
¸
+
¸
$
¸
6
$
·
"
5
-
+
Ï
.
$
-
'
¸
"
-
¼
!
)
Å
¸
"
$
¸
5
-
¸
"
ý
+
½
¾
-
·
Ï
.
Ý
Ï
.
Ï
1
$
¸
+
5
¸
+
+
¾
·
·
+
+
)
!
Ê
.
.
Ï
v
$
!
!
5
Å
v
w
w
$
w
.
1
3
Ï
¸
v
¸
"
¼
5
·
¸
¾
.
1
!
Ý
Ï
.
Ü
$
5
-
}
5
¹
Ê
À
"
!
initial state …
source = SM0 r1
r1
r1
r1
…
SM1 r2
r2 …
…
r n-1
r n-1
r2
r2
…
… r n-1
r n-1
…
SMn-1 rn
rn
rn
rn
SMn = target
… initial state R
g
p
^
6
^
·
)
6
¼
)
+
'
·
"
6
$
·
"
5
-
º
5
+
5
6
¾
æ
v
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
+
¸
"
)
!
5
¹
5
-
$
1
!
1
$
¸
5
)
-
"
#
7
&
1 Ý
M &
8
1
M
X
3
<
8
K
:
:
:
8
·
)
6
¹
¼
Ê
5
1
!
O
+
+
$
º
1
'
5
+
"
·
)
U
+
O
¼
<
¼
K
K
$
!
+
'
·
)
6
¼
)
+
$
1
'
Ê
¸
6
G
¸
À
O
$
5
R
8
}
'
¼
"
)
+
º
!
¸
5
"
'
¹
¸
¸
!
$
)
-
¸
+
5
!
¸
$
5
'
)
5
¸
-
5
)
Ï
-
Ð
·
Ñ
)
6
Ò
¼
Ð
5
5
1
-
¸
!
¸
)
¸
!
·
"
$
-
-
)
+
5
1
¸
5
)
¹
)
»
-
Ê
+
Ù
-
Ï
¼
Ð
!
$
Ý
·
<
¸
5
·
$
Ð
1
Ñ
<
Ð
: Ñ
:
: Ñ
<
Ð
1
3
Ñ
¹
¾
<
Ð
1
Ý
Ò
Ð
º
»
·
!
$
¸
5
-
¹
$
-
¾
6
º
!
)
2
5
-
¸
!
6
'
$
¹
+
<
Ð
Ê
Ù
2
À
$
+
+
5
¹
-
+
6
$
-
¸
5
·
+
'
+
·
!
5
º
'
º
»
+
¸
$
¸
6
$
·
"
5
-
+
Ï
-
¸
$
.
¸
¸
ý
5
5
1
$
-
æ
!
6
'
5
)
¸
"
+
ý
$
¸
1
$
-
¹
¾
$
¹
+
<
Ð
¸
"
-
}
5
¹
Ê
5
-
'
5
·
$
¸
+
¸
"
¼
!
)
)
2
)
º
1
5
¹
$
¸
5
)
-
+
2
)
!
¸
"
+
ý
¸
!
$
+
-
»
+
-
¸
5
¸
$
5
)
É
-
¸
+
!
Ë Ê
+
Ë
5
+
·
¾
¾
$
+
+
¸
$
)
6
-
$
5
-
!
¸
»
5
!
-
6
6
'
$
5
$
¸
-
»
·
1
$
)
-
6
¹
¼
¾
$
5
¹
1
!
+
$
À
-
'
·
$
$
1
-
)
·
À
æ
1
"
)
Å
)
+
1
5
¸
-
¸
"
!
$
6
¸
¸
'
!
5
5
$
º
¾
¸
¸
1
'
$
-
æ
¶
¹
¾
+
$
¹
·
6
B
$
)
6
-
B
¸
¼
5
5
1
·
+
!
É
)
"
2
5
¸
º
5
"
¸
5
-
¸
¹
$
¸
!
¹
"
¸
·
)
6
-
$
·
¸
"
!
5
)
-
1
*
Ê
)
À
.
Ç
'
$
$
!
!
¸
5
$
Å
¸
»
$
¼
¸
¸
+
"
$
-
'
'
)
·
)
¼
6
!
¼
$
)
¸
+
5
5
¸
)
-
5
+
)
¼
-
5
!
-
+
}
5
-
¹
¸
5
Ê
E
-
)
2
¸
"
¸
"
Ê
source program p
frontend: lexer, parser, attribution
AST
transformation
LL
optimization, code generation
assembly code
assembly, linking, loading
executable p ’
á
)
6
¼
5
1
!
+
¸
!
¾
·
¸
¾
!
g
R
·
$
¾
-
"
-
)
¸
¸
)
)
'
¼
¸
5
!
!
$
"
·
¸
¸
5
)
·
1
)
»
-
6
$
$
¼
¸
1
¸
6
)
$
·
+
5
¸
"
$
5
+
-
5
)
-
-
F
1
$
5
^
$
6
¹
p
-
-
+
¸
5
^
$
5
-
¸
¾
·
+
!
6
¸
$
)
$
'
2
-
$
5
¸
¸
¼
-
!
¹
$
)
¸
·
"
¹
!
$
)
¸
'
6
6
"
¸
5
¸
)
¸
"
-
¹
É
1
¸
$
¼
)
"
-
¹
2
!
¾
$
$
$
+
+
¹
+
)
¾
)
+
!
2
·
¸
6
"
$
¼
-
!
·
)
¸
)
¹
-
5
·
!
¸
+
$
À
6
É
Ú
¸
2
!
Ê
¶
¹
!
$
6
6
$
!
)
2
$
¸
¸
"
+
)
¾
!
·
1
$
-
¹
¾
$
¹
$
+
¼
!
+
-
¸
5
-
¸
"
Ë
¾
Ê ¶
ã
+
6
$
!
-
5
¸
È
5
·
·
+
5
)
)
2
-
¸
)
"
2
$
+
·
)
)
¾
!
6
·
¼
1
5
$
1
-
!
2
¹
¾
!
$
)
-
¹
¸
æ
º
-
¾
'
5
¸
"
+
$
¸
+
"
)
¾
+
-
1
-
)
»
¸
¸
·
)
+
)
-
"
)
·
!
À
-
¸
"
'
$
À
¸
¸
5
"
¸
"
¸
Ë
"
'
¾
»
·
-
)
$
!
!
6
5
·
¸
1
·
»
Ë
!
¶
¼
6
'
!
$
'
+
-
5
¸
¸
5
5
-
·
)
¸
+
+
-
¸
)
$
2
1
"
1
+
¸
»
"
À
»
-
+
"
)
¸
¾
$
!
$
·
Å
·
¸
5
·
1
¸
¼
"
$
)
-
+
¹
!
"
$
¾
)
+
$
À
+
$
¹
¸
$
"
-
!
$
'
¸
¸
·
¸
"
"
"
5
·
·
Ã
!
·
)
'
-
)
+
6
$
5
+
+
¼
¸
5
)
+
+
-
·
·
5
¸
5
¾
»
)
+
·
¸
-
)
)
5
6
-
'
-
¸
$
5
!
¸
»
5
"
)
5
-
+
-
+
)
¾
$
)
!
1
2
1
·
·
¸
)
"
¼
6
!
¼
+
)
5
¸
1
$
¹
¸
!
!
5
$
+
·
6
Ê
+
Ê
æ
¾
¸
"
5
¾
1
$
$
¾
!
)
¼
.
$
¸
+
5
¸
1
5
$
¸
¾
-
¸
5
1
$
!
¾
$
Ú
^
-
$
¹
$
H
I
O
"
¸
¾
-
j
<
)
'
¾
q
G
¸
!
5
¸
"
¸
5
)
¸
)
"
"
¸
¾
-
-
2
)
-
¹
¸
!
2
!
+
$
-
¸
À
5
)
!
!
Ã
$
)
¼
¼
¸
2
¸
¸
5
-
5
1
+
¸
!
¹
$
¹
!
1
5
-
5
·
Ã
5
æ
6
G
5
¸
-
¹
-
#
$
$
Ç
¾
5
¹
¼
-
-
-
+
)
)
1
!
-
-
æ
¸
+
·
¸
Ð
2
Ç
"
$
-
-
$
¸
$
+
!
!
$
æ
+
+
º
¸
¸
5
6
¹
'
¹
·
-
'
+
æ
!
-
)
æ
-
¾
!
)
)
6
'
5
¸
¹
$
·
+
-
6
+
"
'
¹
$
¸
·
º
"
2
'
Ð
'
¼
)
)
)
-
+
!
)
¹
·
1
1
·
)
·
$
¼
·
5
Ë Á
)
-
$
'
5
5
-
Þ
$
"
-
5
2
-
¸
¸
-
$
1
)
X
+
2
¼
»
$
$
-
)
¾
-
-
6
)
'
¹
$
)
$
5
G
Ê
!
5
¸
-
-
6
5
1
U
$
)
6
A
"
+
)
·
R
¼
5
º
5
¸
)
¸
·
6
¹
Ç
·
)
6
$
$
¸
2
t
1
$
$
+
6
O
-
"
+
+
¸
t
5
-
"
+
·
6
-
+
M
'
5
¸
$
$
"
!
F
)
!
$
+
)
$
"
5
6
"
5
5
!
!
¸
1
·
$
5
¸
¹
'
¸
¾
"
¼
M
$
"
)
Ê
¸
Ê
6
)
K
'
¸
¸
!
·
"
$
"
!
1
»
¼
Ç
¸
-
1
)
-
-
!
M
6
¼
R
-
¸
"
¸
B
$
)
<
¹
¹
+
+
!
'
2
$
+
-
!
¹
)
¡
À
"
R
5
$
-
-
5
+
"
Ã
)
-
)
¸
5
6
·
¸
5
)
¸
¸
¸
·
$
+
$
5
5
¾
5
$
"
5
+
6
6
"
+
¼
6
¸
!
Ã
'
¼
2
)
+
$
)
$
5
-
¸
¸
'
+
5
+
)
+
1
"
·
-
6
2
+
Ç
¸
¾
-
)
!
+
¹
-
!
+
5
-
¸
!
$
5
»
2
½
¸
1
)
"
º
»
5
$
+
$
"
»
!
¸
¸
¸
·
5
Ù
!
¼
¸
Ê
"
5
¸
¸
6
+
"
'
6
!
À
¾
)
À
)
½
1
2
1
"
!
$
¸
$
¸
-
¾
+
·
-
)
·
+
+
-
5
·
¸
5
º
1
$
5
)
¸
}
1
"
+
$
É
Ê
¼
$
"
$
¸
'
·
¹
!
+
2
+
-
¹
-
-
-
5
6
·
5
5
1
)
5
-
-
»
5
'
+
)
2
·
'
5
5
¼
-
-
Å
¸
!
$
$
5
$
-
¸
È
5
¼
"
5
Ç
!
·
!
"
+
À
6
"
6
¸
!
À
¸
"
$
¸
!
-
¼
q
>
d
Q
V
9
1
æ
1
$
»
-
æ
!
$
Ì
I
G
I
J
O
I
b
;
F
l
G
g
O
L
Ü
D
d
·
£
)
g
-
+
i
5
Ý
+
M
¸
+
d
)
2
r
2
N
)
r
!
6
$
1
'
+
·
!
5
¼
¸
5
)
-
+
)
2
5
¸
+
+
)
¾
!
·
Ç
5
-
¸
!
6
'
5
$
¸
W
$
·
l
>
W
$
!
)
º
+
"
Å
·
"
¸
¸
5
'
¸
!
'
)
¸
+
-
)
2
+
·
)
¸
ß
"
¸
-
G
Ê
`
Ë
1
'
¹
¸
¸
"
"
$
»
$
-
+
¸
5
¸
!
)
1
6
¸
!
À
2
)
"
¼
·
"
2
¼
+
·
¸
)
)
¸
¸
2
$
·
!
)
·
¸
"
!
À
)
·
"
¸
¹
¾
¹
-
-
-
¹
$
)
-
¸
Å
¹
1
+
+
5
)
'
-
$
+
¾
)
!
$
Ã
6
á
-
5
!
$
Ê
"
¸
$
-
$
¸
"
-
5
·
¸
¹
)
'
¼
6
¸
Ç
$
-
+
+
+
»
!
-
)
)
!
!
'
!
'
5
!
1
$
¸
$
$
¸
)
·
1
¾
-
1
!
¼
¸
5
'
¸
5
·
!
-
+
6
$
U
¹
+
¸
¸
1
"
$
-
1
¹
$
¾
$
-
¹
¹
¾
$
+
Ç
¹
$
-
+
'
$
¸
!
"
+
¼
¸
!
·
5
$
-
È
+
2
'
)
!
º
6
»
$
¸
¸
"
5
5
)
-
!
+
)
2
¼
!
)
!
6
$
)
¸
5
)
-
-
$
1
1
$
+
-
¹
¾
6
$
$
-
¹
¸
5
¸
·
+
)
¸
Ê
"
"
5
-
+
·
)
É
¸
6
Ê
¼
Ù
5
-
1
!
¶
+
¼
¼
!
·
·
)
)
5
¹
!
È
·
!
!
$
$
¸
5
6
·
)
-
6
¸
1
5
»
5
6
-
¾
¹
-
¸
1
)
+
$
¸
º
-
¹
É
¾
·
5
$
¾
6
¹
¸
¼
$
1
5
º
1
6
6
¼
·
1
)
-
¸
6
'
'
-
·
P
¸
Ü
5
2
)
-
!
!
¹
)
¸
!
¸
·
"
"
¸
1
»
Ê
·
¼
Ù
)
!
2
P
6
)
¼
5
·
5
+
1
+
+
¸
!
)
"
Ì
!
¼
¸
É
"
!
·
)
¹
-
¾
!
$
¸
P
6
5
5
-
6
¹
¾
Ì
-
+
Ç
$
¸
·
"
º
2
Ê
5
}
¹
·
5
"
¹
)
æ
1
6
Ê
Å
¼
5
Ê
1
1
"
'
¾
+
¶
¸
"
Å
Ê
!
ã
¼
5
)
ã
$
È
¸
·
¹
1
5
$
!
!
$
)
¸
$
-
5
5
)
+
-
6
'
)
Ú
!
)
Ç
+
)
$
·
¾
2
·
¸
Å
-
)
"
5
1
6
¼
!
·
»
¸
Á
5
!
+
-
)
)
¸
-
-
+
6
$
1
'
¼
!
¸
$
·
¹
!
¹
!
+
5
5
5
1
¸
-
¸
!
Ú
)
+
Ü
¸
5
1
¸
¼
)
º
!
-
·
"
·
¸
!
5
$
È
5
·
-
¸
$
¸
$
5
'
+
)
2
Ã
+
-
!
Á
Ì
)
Á
6
5
¸
6
Ú
º
¾
+
»
¸
Ì
º
5
+
+
$
"
·
)
)
À
!
-
!
¸
·
"
¸
$
¸
!
¸
$
2
-
)
+
!
1
$
¸
Å
5
)
!
»
-
)
2
5
"
6
)
¼
À
1
6
-
¸
"
-
$
¸
¸
$
¸
¸
"
5
)
-
5
P
6
Þ
¼
1
5
-
$
6
"
-
5
¸
$
¹
"
¸
5
æ
)
1
Å
-
5
1
+
¼
!
$
!
)
¹
!
È
$
-
6
6
6
5
-
-
¹
¸
)
2
Ê
¾
P
$
+
)
2
1
¸
É
)
5
º
$
-
¼
¸
·
)
6
+
È
"
5
)
¾
·
¸
$
¸
6
2
+
'
"
¸
¼
)
$
$
2
ß
)
!
¹
5
¸
·
)
Ð
¸
¸
!
)
¼
·
5
6
È
!
¸
¹
)
5
!
$
$
·
·
·
¾
ã
È
¹
"
Ê
5
-
¸
"
·
Ê
Ê
Ù
È
!
!
Ú
»
5
¸
$
º
1
·
)
6
¼
5
1
!
Ü P
Á
5
¸
6
¾
+
¸
º
+
"
)
À
-
¸
"
$
Ü
¸
P
5
+
$
Ê
-
¹
¾
$
¹
+
$
!
5
-
5
¸
5
$
1
1
»
)
-
1
»
5
-
2
)
!
6
$
1
1
»
'
+
·
!
5
º
'
Ê
"
¶
!
æ
¶
2
)
1
$
5
'
!
¼
-
¹
$
$
¾
¸
5
$
!
T
)
¹
)
-
+
+
#
"
¸
º
Ç
¾
U
+
"
$
¸
'
+
$
!
5
È
¾
+
°
·
-
¯
5
¸
·
5
.
$
2
¹
´
¾
$
$
5
¯
1
-
)
¸
1
¸
!
¸
+
º
¸
¯
2
$
»
+
$
¸
Ç
-
$
"
¯
"
Ã
·
2
+
$
"
)
5
!
2
)
Å
6
1
t
·
º
+
%
5
»
'
1
´
$
1
$
!
!
6
V
6
$
¸
·
5
+
)
·
®
5
»
¼
µ
"
É
Ã
5
¼
È
)
!
$
¸
!
-
¹
·
.
-
2
5
5
®
¸
6
)
-
¸
º
1
$
!
1
¹
$
$
$
1
$
µ
¹
+
'
'
6
¾
1
5
-
4
-
6
Å
"
±
$
)
»
*
"
2
-
+
²
¸
"
$
¼
¸
5
)
·
5
È
-
·
)
$
-
¸
1
5
»
)
-
Ç
!
+
¾
)
-
2
-
5
¸
-
"
¹
Å
+
$
1
æ
Ê
8
+
+
°
6
6
$
-
+
¸
´
5
·
µ
+
5
´
+
!
¸
¯
)
µ
·
±
®
)
.
-
+
5
¼
!
'
!
¶
¸
"
+
¸
$
¸
+
)
2
¼
!
)
¹
!
$
6
+
$
+
$
-
$
1
¹
º
!
$
)
Å
!
$
¹
5
Å
-
+
5
¹
-
$
¸
¾
!
Ê
"
5
-
¸
!
¸
$
5
$
¸
æ
¶
+
)
+
-
5
)
¹
-
2
6
+
)
-
6
¸
·
+
"
»
$
6
-
º
¹
)
+
1
+
¸
)
"
2
¸
5
"
-
¸
+
!
¼
5
¹
!
-
$
¸
¸
$
¾
¸
!
5
)
-
6
)
$
2
»
$
·
"
6
$
-
6
¹
)
)
!
»
-
Ê
+
Ë
¸
º
$
+
¸
¸
!
¸
$
·
!
$
¸
-
+
+
¸
5
$
¸
5
¸
)
-
Ç
6
+
$
·
Ê
"
¹
5
Ê
-
$
-
+
"
Z
#
&
M &
M
X
<
K
'
R
O
O
U
G
O
<
K
K
p
is correct translation
Compiler
is correct
Specification
implementation
Compiler Implementation (in language L) is correct translation
p’
executable compiler
ã
!
5
È
·
$
¸
5
)
-
·
)
-
+
¸
!
¾
·
¸
5
)
-
)
2
·
)
!
!
·
¸
·
)
6
¼
5
1
!
+
g
¼
!
¸
)
"
¹
!
+
¸
^
$
Þ
¾
+
¸
!
$
$
·
!
·
+
$
`
-
+
æ
5
¸
¸
!
5
!
)
+
)
·
¸
"
Ê
¸
5
À
£
b
5
)
·
¸
1
5
$
Å
¸
À
-
+
5
+
5
)
+
5
ß
"
Ê
-
¸
Þ
+
+
ß
¸
+
º
¾
»
¹
¾
5
$
¾
¸
-
Å
¸
Ê
+
)
)
+
+
+
¸
!
¹
2
¾
·
¼
-
)
·
!
¼
!
'
º
)
¼
¼
¾
}
$
Þ
Ê
6
)
À
+
2
5
-
5
)
$
)
¹
+
-
¾
^
-
+
Ç
$
2
¸
»
+
d
+
¸
+
-
5
5
6
¾
"
¸
·
$
·
¸
5
)
-
"
6
)
2
¸
+
¸
¸
-
6
5
$
·
$
¸
2
·
¹
+
¾
¸
·
6
2
-
'
$
!
)
5
)
¸
)
+
¼
!
+
+
+
¼
-
¸
-
$
!
!
·
»
Ê
¸
!
!
º
"
!
)
-
$
'
)
6
¸
)
¼
-
·
-
"
+
5
!
æ
·
2
À
+
)
$
+
¸
!
!
¸
-
º
1
¼
º
+
5
'
$
$
5
6
$
+
6
$
)
ß
¸
)
!
-
Ê
-
+
¸
$
5
¹
ß
¹
)
!
+
+
-
2
$
Þ
5
"
-
)
¼
$
d
·
5
-
+
1
£
º
)
-
¸
$
-
º
)
5
5
+
¹
6
¾
5
H
!
¸
-
£
·
$
-
+
t
-
5
Ü
2
-
5
¸
»
Ù
º
^
"
¸
Ê
5
d
$
'
$
+
¸
l
5
$
!
·
£
+
)
[
¸
6
·
r
¸
2
"
+
Ê
$
-
-
1
+
!
+
^
$
À
)
5
º
6
)
2
"
'
+
1
+
·
»
!
1
-
É
x
$
1
)
$
!
1
6
º
6
2
À
6
$
`
Ë
$
¸
6
6
5
6
!
"
'
Å
$
)
¸
5
+
$
¸
2
Å
5
p
)
¸
º
$
¸
g
b
$
!
-
1
+
Ý
6
!
)
c
!
6
¸
Ü
·
"
1
+
5
Î
»
$
¸
5
$
r
5
¸
¹
+
)
-
-
-
1
)
"
·
+
»
¸
5
1
¸
+
"
$
+
¹
!
1
'
$
+
'
+
-
6
Ê
¸
¾
1
¾
¸
»
¾
!
+
-
¸
$
$
)
Â
6
¸
5
+
2
·
!
Î
Ý
)
$
'
Î
Þ
!
Å
6
)
)
È
-
1
'
Å
+
1
$
Â
Â
5
1
-
¹
-
1
$
'
`
ß
2
1
$
æ
)
¹
+
$
!
!
+
$
!
¹
»
º
1
+
º
6
1
$
$
·
¸
Ç
!
¼
$
$
5
2
Î
¼
'
!
+
Ê
-
¾
¹
-
Ê
·
æ
¶
¸
5
)
-
+
Î
$
-
'
+
1
·
¸
'
$
!
¹
¾
6
-
¸
+
Þ
Â
Â
Ë Þ
¾
d
ß
5
+
$
¸
¾
¼
1
Ý
Þ
e
Î
v
Ê
e
$
-
'
$
!
¸
À
)
Þ
+
f
)
D
v
!
¸
v
v
'
w
G
w
Q
v
'
5
+
â
1
ß
Ê
}
)
!
6
$
1
1
»
v
Ç
w
$
w
w
-
v
;
9 L
F
Q
;
I
F
9
F
;
F
>
<
;
I
M
G
D
>
v
F
g
ß
w
;
D
9
ß
À
"
!
h
)
5
-
¸
+
5
¹
-
$
¸
¾
!
+
Þ
¸
"
+
5
¹
-
$
¸
¾
!
)
2
9
F
;
F
G
I
$
-
'
f
U
»
Ê
Ù
Ê
Ê
j
D
Î
;
5
D
<
+
G
G
$
F
I
2
-
5
)
+
¾
!
$
-
'
+
·
¸
!
5
æ
¸
)
+
)
-
)
+
!
2
ß
¸
½
Ê
'
¾
e
$
¸
æ
5
)
$
1
-
¹
+
)
º
Å
!
$
Þ
!
¸
"
Î
'
9
È
F
-
;
5
F
-
G
I
$
¹
¸
1
"
¹
º
5
!
-
5
$
¸
ß
5
Ê
$
1
+
¸
$
¸
+
)
2
Ê
g
Q
;
D
9
5
+
$
+
¸
)
2
F
Q
;
D
9
G
F
G
O
D
Q
P
> V
9
2
)
!
'
È
-
5
-
¹
¸
"
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
+
º
»
·
"
$
-
¹
5
-
¹
h
Þ
)
!
¾
¼
'
$
¸
5
-
¹
ß
¸
"
5
-
¸
!
¼
!
¸
$
¸
5
)
-
+
)
2
2
¾
-
·
¸
5
)
-
+
)
2
Ê
f
Ë Þ
e
l
ß
æ
$
1
¹
º
!
$
5
+
$
9
F
;
F
>
)
2
5
5
¸
+
!
+
¸
!
5
·
¸
5
)
-
¸
)
e
5
+
¸
"
+
¸
$
¸
5
·
$
1
¹
º
!
$
u
f
Î
Ê
å
¼
'
$
¸
+
)
2
$
-
5
-
¸
!
¼
!
¸
$
¸
5
)
-
$
!
'
È
-
'
$
+
2
)
1
1
)
À
+
Á
B
¸
º
$
+
¸
$
¸
Ç
Î
n
Ç
u
f
Â
¸
!
6
+
)
Å
!
e
l
$
-
'
5
-
¸
!
¼
!
¸
$
¸
5
)
-
+
5
-
Ê
"
¾
¼
'
$
¸
¶
u
ý
f
ý
Î
Þ
Â
'
È
-
+
¸
"
-
À
5
-
¸
!
¼
!
¸
$
¸
5
)
-
)
2
1 Â
Î
v
w
5
w
-
w
¸
ß
Á
Ý
Â
v
"
+
¸
$
¸
Ü
Á
u
p
5
2
2
)
!
$
1
1
Ç
r
r
`
Ç
Ý
Â
Ý
u
Ü
ý
p
Ý
Î
Þ
1
ß
Ý
u
v
w
w
w
v
Î
t
Þ
v
w
w
w
v
1
ß
)
¸
"
!
À
5
+
ý
Ë ¸
"
$
!
$
+
-
¸
+
"
5
¸
5
2
O
g
m
)
-
)
1
!
D
1
)
¾
À
1
5
-
'
¹
2
È
)
-
!
+
6
$
+
¸
)
2
¾
¼
'
$
¸
+
À
"
5
·
"
U
$
G
!
R
¡
<
É
B
R
·
M
K
¾
M
¸
F
'
5
M
O
-
¼
$
R
!
A
U
$
1
G
1
X "
1
Ë Ê
!
Z
Z
¾
1
Á
U
u
£
U
;
c
F
b
Ý
>
U
w
;
F
>
w
1
W
W
w
w
w
¢
b
Ý
g
m
p
"
¾
¼
'
$
¸
+
U
;
F
>
x
$
!
É
·
¾
¸
'
5
-
$
+
¸
$
¸
5
2
Ý
O
D
U
Ý
F
Q
P
>
Ê
w ¶
u
W
}
6
^
2
¾
n
$
¾
-
+
ã
!
]
d
1
)
1
!
!
$
5
l
»
¸
¸
È
;
!
i
$
"
p
-
!
l
¹
¸
É
¸
'
d
¾
"
q
$
¸
$
q
¹
u
6
g
+
5
$
'
y
Å
)
-
p
$
"
+
Ý
"
¸
1
d
'
º
À
$
Ý
5
¸
º
º
p
j
2
!
¾
d
-
"
!
p
)
1
Å
$
¸
b
!
5
H
6
$
+
2
5
1
)
-
b
1
!
)
+
q
d
»
'
6
À
Ý
¸
!
£
+
"
·
g
!
Ü
5
+
2
r
º
¼
u
¸
z
!
g
'
·
£
º
5
È
"
c
¸
$
5
¾
)
'
H
Ë
$
É
»
·
!
!
^
+
+
)
¸
)
»
Ê
r
d
-
Ç
·
2
¸
2
"
Ê
+
1
·
$
¸
-
5
¹
)
-
¾
|
$
¹
Ê
.
+
¾
+
5
1
'
æ
5
-
Á
<
>
~
V
}
@
G
X
M
>
N
>
V
;
D
X
P
;
X
>
9
K
"
)
¼
!
$
¸
5
)
-
$
1
+
6
$
-
¸
5
·
+
5
+
$
¸
¸
$
·
"
'
¸
)
¸
"
¶
W
Ë ¾
Ê
¾
)
6
Ë
¾
æ
¶
-
)
'
+
!
¼
!
+
-
¸
'
»
-
$
6
5
·
¸
$
+
Ã
+
Ç
Ê
¹
Ê
¸
"
-
)
'
+
)
2
+
)
!
¸
}
¶
g
!
¼
)
!
2
+
+
)
!
-
¸
¸
¸
"
'
·
5
+
5
!
)
-
¼
À
!
"
+
-
¸
"
¸
$
!
+
¸
+
5
)
¹
5
-
¸
6
!
$
-
¸
¸
+
¸
"
Ê
"
º
)
'
Ë
»
¾
g
Ê
-
¹
Ê
$
1
6
5
2
¸
·
"
¸
$
$
+
-
"
È
!
+
¸
Ã
¸
¸
$
+
)
+
)
5
'
º
Ã
¼
)
À
¾
+
"
¸
5
·
1
)
1
-
¸
)
$
)
5
¼
Ç
-
+
$
)
-
'
6
¸
"
$
¸
¸
-
!
5
)
º
'
¾
¸
+
+
Ç
¶
+
$
É
-
'
·
!
¾
¸
5
¹
"
'
¸
-
"
É
$
-
¸
'
+
2
¸
"
º
)
'
»
)
2
5
Þ
$
À
'
ß
Ç
+
¸
)
"
2
$
·
!
$
¸
5
)
-
$
1
+
6
$
-
¸
5
·
+
5
"
+
)
+
-
5
'
¹
5
-
¸
5
6
)
-
-
¸
)
+
2
Þ
$
M V
À
9
"
5
$
1
-
'
1
Q
)
)
M
9
¼
Þ
ß
I
Ç
O
¸
"
D
U
ß
'
Ç
»
$
æ
-
'
h
"
1
1
)
)
¼
Þ
ß
h
"
$
'
¸
2
6
¶
)
$
+
$
¼
)
5
-
Ê
h
¸
!
¸
)
¸
"
¸
$
+
Ã
¸
)
º
É
·
¾
¸
'
Þ
Ç
¶ u
h
·
¾
!
!
-
¸
¸
$
+
Ã
ß
Ê
5
+
6
)
Å
5
-
¹
¸
"
!
)
¾
¹
"
¸
"
¼
!
)
¹
!
$
6
'
¾
!
5
-
¹
É
·
¾
¸
5
)
-
Ç
5
Ê
Ê
5
u
h
$
-
$
º
+
¸
!
$
·
¸
¼
!
+
u
)
¹
h
!
$
6
·
)
¾
-
¸
!
Ê
"
2
)
1
1
)
À
5
-
¹
¸
!
$
-
+
5
¸
5
)
-
!
¾
1
'
È
-
+
¸
"
+
6
$
-
¸
5
·
+
¶
)
2
¸
"
À
"
5
1
1
n
)
)
¼
Á
}
g
m
u
£
h
N
g
;
P V
>
Þ
I
m
O
D
h
Á
Ë
r
-
1
b
$
2
ß
Ý
F
Q
P
>
b
Ý
w
h
h
Ý
u
+
¸
c
u
u
h
Ë
U
w
Ý
h
b
Ý
£
h
"
b
u
Á
u
¸
c
g
+
"
5
¹
$
h
-
-
6
'
+
5
-
¸
'
w
$
Ç
+
5
Ê
+
h
5
¹
Ê
-
Ç
+
¸
¸
"
"
+
¸
Å
)
$
!
1
$
¾
¹
)
Þ
2
9
F
¸
O
"
Q
>
!
ß
5
5
¹
+
"
·
¸
"
"
$
$
-
-
¹
'
+
'
$
5
'
¸
¸
¸
"
5
)
¸
+
$
"
'
'
'
!
+
+
+
5
¹
-
Ê
$
"
¸
)
!
-
)
Ç
¸
2
"
¶
¸
$
+
Ã
$
2
¸
!
¸
"
$
+
+
5
¹
-
6
-
¸
5
+
É
·
¾
¸
'
Ê
"
¸
!
$
-
+
5
¸
5
)
-
!
¾
1
5
+
¶
n
g
m
u
£
h
9
F
g
O
Q
>
Þ
;
U
U
Q
c
b
Ý
Þ V
M
9
ß
ß
Á
Ý
N
;
P V
>
Þ
Q
u
)
¸
!
$
!
"
¹
5
h
9
ß
w
u
¹
¸
w
Ý
h
}
M
u
h
Á
u
h
"
æ
æ
6
1
$
Å
·
"
1
5
-
1
w
$
-
h
+
¹
Ê
¾
Ù
$
¹
-
¸
"
+
5
Ç
¸
+
"
É
$
$
6
'
'
¼
1
!
+
Ç
+
À
+
-
$
+
+
'
¾
-
6
)
¸
º
$
º
+
!
¸
!
$
1
·
$
¸
¸
$
'
¸
'
'
!
)
¸
+
+
"
+
$
'
Ê
'
"
!
+
+
+
¸
)
+
!
)
$
2
¹
¶
9
'
F
O
Q
È
>
-
·
5
¸
$
5
-
)
+
-
¸
)
)
2
!
¼
$
)
¸
5
-
¸
$
·
!
+
"
Á
$
¸
'
"
'
!
»
·
+
$
+
$
-
-
º
»
Å
!
$
1
¼
¾
!
Ë Ê
+
º
-
¸
+
¸
'
!
$
º
·
»
¸
$
+
¸
'
)
'
!
!
5
-
+
¹
+
$
+
'
'
'
)
!
-
+
)
+
¸
+
Ê
É
·
1
¾
'
¸
"
"
Z
"
&
"
¸
!
$
-
M &
+
5
¸
5
M
)
X
<
-
!
K
¾
1
2
)
'
!
R
O
$
O
Å
U
$
!
G
5
O
$
<
º
1
K
K
$
+
'
+
5
¹
-
$
¸
)
!
5
+
¶
n
g
m
u
£
c
b
Ý
h
N
;
P V
>
Þ
ß
Á
Ý
9
F
O
Q
>
Þ
G L
D
U
Þ
>
D
N
G
u
U
U
Q
v
Þ
ß
Á
Ý
G
D
L
U
Þ
>
D
N
G
u
>
v
5
-
¸
5
2
;
5
-
¸
h
<
"
$
¸
$
á
)
t
-
¼
!
'
5
h
w
h
-
·
¸
¸
)
5
t
)
+
2
!
¾
5
-
5
5
)
¸
+
5
¸
)
!
¸
!
1
'
+
¾
+
¾
5
>
-
)
)
¸
$
!
¸
5
"
)
¸
)
-
¼
1
+
+
6
)
¸
'
·
'
"
-
6
Q
)
¸
6
'
O
6
-
F
Ê
º
¹
¸
9
)
)
5
-
-
¸
¸
+
5
)
$
!
$
)
Å
$
+
æ
¸
À
+
"
$
"
!
¸
'
¸
)
!
!
»
¼
2
'
)
º
¾
¸
'
2
!
"
$
)
"
¹
1
}
¸
+
$
"
¾
Ê
Á
)
!
¸
!
-
¸
+
-
¾
)
'
+
-
5
1
¸
È
¸
$
·
!
5
5
Å
$
¸
+
¸
½
Ç
'
$
"
+
+
á
!
¸
º
!
+
¸
$
1
+
Ã
1
5
"
-
!
1
¸
$
·
'
Ç
+
»
'
¹
+
'
!
$
$
+
5
)
»
¾
$
"
Å
¹
+
6
º
$
"
¾
6
w
B
¸
·
1
5
-
·
¾
"
1
~
Ù
!
!
Ê
-
)
Q
)
)
6
ß
u
h
ß
w
ß
Ý
u
·
h
U
u
h
Á
U
u
h
;
»
-
!
¸
"
-
Å
+
¹
¾
5
$
"
6
!
$
$
1
1
5
¸
5
æ
2
¸
+
$
»
æ
Ã
-
'
6
$
¸
¼
!
¸
¸
¸
¸
2
-
!
+
)
$
¹
¾
)
!
!
6
º
5
$
¸
$
!
!
¸
¸
-
$
5
+
+
)
"
6
$
¼
¸
Ç
+
¸
2
¸
+
)
!
·
æ
)
2
Ê
;
<
> V
}
@
;
9
G
I
O V
I
Q
;
M
W
9
K
Ë
º
$
+
5
·
º
1
)
·
Ã
5
+
$
+
½
¾
-
·
)
2
5
-
+
¸
!
¾
·
¸
5
)
-
+
Ê
W
-
É
·
¾
¸
5
)
-
$
1
1
5
-
+
¸
!
¾
·
¸
5
)
-
+
$
!
É
·
¾
¸
'
Ê
"
1
$
+
¸
5
-
+
¸
!
¾
·
¸
5
)
-
º
!
$
-
·
"
+
·
)
-
'
5
æ
¶
¸
5
)
-
$
1
1
»
)
!
¾
-
·
)
-
'
5
¸
5
)
-
$
1
1
»
Ê
x
$
·
"
º
$
+
5
·
º
1
)
·
Ã
5
+
-
$
6
'
º
»
$
1
$
º
1
Ê
"
·
¾
!
!
-
¸
1
»
¶
É
·
¾
¸
'
5
-
+
¸
!
¾
·
¸
5
)
-
5
+
'
+
5
¹
-
$
¸
'
º
»
$
¼
$
5
!
·
)
-
+
5
+
¸
5
-
¹
)
2
+
¾
·
"
$
1
$
º
1
Þ
Á
u
·
¾
!
!
-
¸
1
$
º
1
ß
$
-
'
$
-
5
-
+
¸
!
¾
·
¸
5
)
-
¼
)
5
-
¸
!
Ý Þ
G
D
9
F
Q
Þ
g
$
+
+
5
¹
-
6
-
¸
5
-
+
¸
!
¾
·
¸
5
)
-
Þ
ß
v
¸
"
¸
"
$
!
¹
Å
$
¸
1
Þ
¾
$
À
¸
"
5
5
)
·
"
-
6
5
¾
+
¼
+
¸
!
2
º
)
!
$
6
-
$
'
)
'
'
-
¸
"
+
+
ß
·
$
!
h
Ç
¾
v g
g
!
n
¡
g
-
!
'
ß
$
-
¸
+
+
ß
Ë Ê
-
5
-
¸
¹
!
u u
+
¸
5
$
¹
-
¸
Å
$
1
¾
$
¸
g
+
¸
"
+
)
¾
!
·
$
-
'
+
¸
Þ
2
"
¾
Å
-
·
¸
$
5
1
)
¾
-
¸
>
N
)
¸
;
ß V
"
Ê
$
'
2
)
'
!
!
+
¸
+
Ê
"
¶
Å
$
6
1
¾
$
6
¸
)
5
!
)
-
»
5
)
Å
¸
5
!
+
·
*
)
"
À
·
Ã
À
)
'
¾
À
1
"
'
)
·
¸
·
"
¾
!
!
$
'
'
¾
!
5
5
Å
-
5
+
¹
5
¸
)
"
-
5
º
+
»
t
Å
$
1
!
¾
)
$
Ç
¸
5
$
)
-
-
$
!
Ê
5
"
¸
"
6
¸
!
$
¸
5
-
·
+
5
)
¸
5
Å
)
!
-
*
!
)
¾
À
1
Ç
5
)
+
!
$
Á
¶
n
g
m
u
£
g
g
U
g
G
N
h
g
j L
£
>
Q
O
Þ
c
b
Ý
9
Q
I
Þ
ß
m
ß
>
u
£
c
b
I
>
F
G
O
D
Á
Ý
¤
¥
¦
§
¨
©
ª
«
¬
®
¤
Ý
W
g
O
b
Ë
r
g
m
b
Ë
r
g
m
N
>
Q
¯
O
±
Þ
9
Q
I
Þ
ß
ß
>
u
£
c
b
I
>
F
G
O
D
Á
Ý
¤
²
¬
¦
³
´
µ
«
³
¦
¶
®
§
«
¬
·
¸
®
¹
¤
Ý
W
g
<
>
<
O
N
>
Q
¯
O
±
Þ
U
>
9
F
Þ
ß
ß
º
<
>
<
O
N
>
Q
¯
O
±
Þ
9
Q
I
Þ
ß
u
g
>
£
c
b
I
>
F
G
O
D
Á
Ý
¤
µ
«
µ
®
ß
u
¬
g
©
®
§
«
¬
·
¸
®
¹
¤
Ý
W
I
b
Ë
r
O
D
F
>
D
F
Þ
>
N
;
Þ
U
V
>
9
F
Þ
ß
b
ß
ß
Á
Ý
>
N
;
Þ
9
V
Q
I
Þ
ß
u
g
"
+
6
Ý
$
g
-
¸
5
·
+
)
ß
»
u
g
Á
g
»
½
2
$
·
)
-
'
5
¸
5
)
-
$
1
â
¾
6
¼
¾
¿
À
Þ
Ð
Ð
ß
n
Å
$
1
¾
$
¸
+
¸
"
É
¼
!
+
æ
¶
¡
+
5
)
-
Ê
Ù
2
¸
"
!
+
¾
1
¸
5
+
¼
)
+
5
¸
5
Å
¸
"
-
5
¸
â
¾
6
¼
v
+
¸
v
)
¸
"
g
È
!
+
Á
¸
5
-
+
¸
!
¾
·
º
1
¸
5
)
-
)
2
¸
"
º
1
)
·
1
¡
Ã
$
º
1
'
Ð
Ç
)
¸
"
!
À
5
+
5
¸
â
¾
6
¼
+
¸
)
¸
"
È
!
+
¸
5
-
+
¸
!
¾
·
¸
5
)
-
)
2
¸
"
)
·
Ã
1
$
º
Â
Ã
Å
Æ
È
Ã
Î
Æ
Ï
É
Ñ
Ó
Ê
Ô
Ë
Õ
Ö
Í
×
Ø
Ù
Ú
×
Û
Ù
Å
Æ
Ü
Ü
Ê
Ë
Í
Ö
Ý
Û
Ö
Þ
ß
Ï
Ø
à
á
â
f
è
Â
Ã
Ø
Ë
è
Â
Ã
ï
Ë
è
Â
Ã
Ö
Ñ
Ö
×
é
Ø
ë
Ù
Ú
×
Û
Ù
Å
Æ
Ü
Ü
Ê
Ë
Í
Ö
Ý
Û
Ö
Þ
ß
Ï
Ø
à
á
ä
æ
ç
d
â
Ñ
ï
ð
Ø
ñ
Ù
Ú
Ñ
×
Ö
Û
×
Ù
é
Ø
Å
ë
Æ
Ü
Ù
Ü
Ú
×
Û
Ù
Å
Æ
ò
Ü
#
Ê
Ë
Í
Å
Æ
ó
ö
á
á
â
#
Ë
è
Ë
Å
ó
ß
×
ô
Ö
ß
ð
×
õ
Ö
ß
Ù
Å
Æ
Ü
â
á
â
÷
ø
ð
ñ
Ú
Ö
ß
ð
×
õ
Ö
ß
Ù
Å
Æ
Ü
Ü
Ê
Ë
Í
Ö
Ý
Û
Ö
Þ
i
_
ã
i
f
ì
|
g
h
ì
f
í
_
ä
h
i
r
z
_
î
ã
ã
g
Ö
h
ã
y
Ë
1
'
Ð
Á
n
Â
ß
Ï
Ø
à
á
â
ã
h
g
_
i
ç
_
ä
h
i
r
z
_
î
ã
Æ
ö
á
Ë
!
¹
)
$
Ç
!
5
-
$
Ç
5
+
5
¸
R
¡
<
B
R
M
K
M
F
M
O
R
A
U
G
X "
Z
÷
6
+
G
â #
t
U
$
¾
-
+
$
¸
!
5
º
¸
"
·
6
"
¸
5
·
·
Ã
)
Å
'
À
!
*
"
)
À
¸
Ç
"
)
!
!
¸
$
"
6
Å
6
$
)
1
!
¾
$
»
¸
)
5
Å
)
-
!
¼
*
)
À
!
2
)
!
6
+
$
'
5
Å
5
+
5
)
-
º
»
Ê
;
<
>
ù
V
}
@
ú
M V
}
;
û
;
I
M
G
D
>
;
D
X
P
;
X
>
K
"
)
¼
!
$
¸
5
)
-
$
1
+
6
$
-
¸
5
·
+
)
2
¸
"
¶ u
W
R
x
W
Ë
á
æ
1
¼
"
$
6
$
·
"
5
-
1
$
-
¹
¾
$
¹
'
¼
-
'
+
)
-
¸
"
6
$
·
"
5
-
$
!
·
"
5
¸
·
¸
¾
!
Ê
"
+
¸
$
¸
¶
·
)
-
+
5
+
Þ
¸
ß
+
)
Ê
2
"
¸
"
$
!
¾
É
5
¹
1
5
5
$
+
¸
!
!
»
+
2
¾
¸
-
Þ
·
¸
5
Q
)
>
X
ß
-
Ç
¸
O V
D
"
X
6
$
·
·
6
)
+
+
!
»
+
Þ
2
)
<
>
¾
!
<
·
ß
)
Ç
-
$
+
-
·
'
¾
¸
¸
5
"
Å
¼
º
!
»
)
¸
¹
!
+
$
)
6
·
2
<
)
>
¾
-
<
¸
Ç
¸
!
"
¶ u
2
¾
-
·
1
·
$
·
¸
+
)
5
+
-
)
5
'
-
2
5
ü
»
5
¸
5
-
P
;
¹
)
U
¼
-
$
!
1
â
5
¹
'
¾
"
5
¸
·
6
º
$
¸
¼
»
)
¸
+
-
Ç
+
¼
)
Ë Ê
Ê
¹
+
5
·
Ê
¸
5
G
Å
)
6
9
5
6
O V
-
;
¸
$
U
Þ
¹
-
ý
'
5
ß
!
5
+
+
+
$
¸
Ê
6
!
"
¾
$
!
·
2
"
)
$
5
!
!
-
1
2
)
À
$
¾
)
'
!
!
5
¸
"
'
-
¸
+
¸
!
"
!
)
$
¾
¼
¸
·
·
¸
!
5
$
$
)
¸
-
-
5
º
+
)
Ç
-
G
+
'
9
É
·
X L
¸
)
F
!
'
Þ
$
ý
·
'
ß
¸
5
º
2
-
)
»
!
¹
$
¸
"
¶
)
¼
ý
Q
·
)
â
$
>
¾
'
;
¸
6
Q
-
5
)
ý
I
+
+
$
5
'
)
¸
+
$
¾
$
¼
¸
-
¼
º
ß
-
$
6
ý
5
!
)
"
Þ
¸
·
¸
Q
¼
ß
¹
9
'
!
Þ
-
ý
¼
1
)
U
5
¼
¾
+
U
$
6
!
-
V
-
¾
â
!
·
È
+
$
5
¹
6
5
$
Å
¸
U
'
'
!
9
ß
!
+
¸
-
¾
¸
"
¸
5
¸
¸
5
)
)
¸
"
!
â
¸
)
$
2
'
¹
)
º
Ê
·
¹
'
!
¼
+
Ê
$
¸
6
Ç
1
¹
¾
"
ý
$
"
-
º
¹
.
·
+
ß
5
Ê
¸
ý
-
+
+
!
Þ
È
+
-
'
F
5
'
>
!
'
-
$
'
+
$
)
¸
-
5
!
$
$
Å
2
1
Ç
!
¸
+
+
1
+
!
"
+
!
¸
!
"
'
+
$
!
¸
'
Þ
'
+
$
5
-
'
+
!
5
5
5
1
;
!
¸
Å
$
L
¸
'
º
!
Ç
5
-
)
9
Ê
)
>
5
)
'
ý
)
5
ß
¸
!
$
¸
$
Þ
}
-
$
)
-
F
+
¸
!
-
Q
F
!
5
5
¸
!
-
ß
+
-
¸
)
ý
-
)
+
5
Þ
$
¸
¹
5
>
¸
·
'
X
¾
!
)
;
"
¸
·
'
+
"
$
-
-
$
¸
5
1
¸
"
5
)
-
+
G
g
9
O
;
V
U
Þ
O V
D
X
Þ
ß
m
ß
u
£
c
b
Ý
Q
>
X
Þ
F
;
Q
X
>
F
Þ
O
D
V
X
Þ
ß
ß
ß
Á
Ý
ü
P
;
U
Þ
Q
>
X
Þ
; L
9
>
Þ
O V
D
X
Þ
ß
u
Ý
þ
þ
Q
>
; V
U
U
Q
Þ
O V
D
X
Þ
ß
ß
ß
ß
u
u
G
g
ß
u
Á
u
9
X L
F
Þ
O V
D
X
Þ
ß
m
ß
u
£
c
b
Ý
Q
g
>
X
Þ
9
Q
I
Þ
O V
D
X
Þ
ß
m
ß
ß
ÿ
º
u
Á
£
c
b
Ý
Ý
þ
u
Ë
r
b
¼
·
5
2
»
1
)
$
Q
X
>
F
Þ
9
Q
I
Þ
O V
D
X
Þ
ß
ß
ß
u
Ý
þ
u
u
+
;
Á
b
F
u
'
5
-
¹
2
!
)
6
6
6
)
!
»
$
-
'
·
)
-
'
5
¸
5
)
-
$
1
â
¾
6
¼
5
-
¹
Ê
6
^
Ú
^
·
+
Ù
5
!
'
¸
+
¼
6
$
-
+
5
Ù
5
!
2
5
º
-
¸
+
»
£
)
$
+
Ý
·
-
·
$
i
5
·
¸
¸
!
b
+
¸
º
1
"
-
¸
1
+
»
¸
5
·
+
-
¸
¸
5
5
O
!
)
"
û
$
-
·
'
$
r
¾
$
¹
»
p
5
!
æ
-
+
¸
)
d
D
º
!
5
>
)
¸
2
'
¸
$
¼
!
¾
6
)
'
Ë !
+
"
!
-
)
¸
$
$
+
"
»
9
-
¹
º
X
5
1
-
'
;
¸
¾
Ã
F
¾
-
·
'
Å
$
1
+
+
5
¸
!
-
d
-
)
¸
5
$
5
)
$
5
¼
Ê
·
¸
)
1
¸
»
5
Ê
5
)
5
)
¾
¸
5
$
-
-
d
º
2
$
¾
+
!
+
6
$
¸
+
+
+
¾
$
1
1
$
!
$
$
'
-
"
-
-
5
È
¸
)
¼
)
2
¹
2
6
+
'
$
-
)
·
-
)
·
¸
!
!
¸
)
)
-
·
¾
+
À
6
É
"
"
6
¸
1
¸
$
+
!
5
2
!
¸
¸
!
¸
)
¼
·
æ
)
1
)
!
!
1
!
2
$
-
¸
!
Ã
'
)
+
¾
º
'
¸
$
1
5
5
!
-
)
!
¹
·
¹
$
2
¾
¼
À
¹
É
¾
)
5
-
5
*
Å
$
¸
Ê
$
1
»
6
'
æ
¸
"
¶
'
$
¸
¸
!
$
5
1
$
æ
º
¹
)
¸
*
¾
º
5
;
!
À
)
5
-
$
)
<
+
¾
2
1
¸
> V
}
+
!
¼
"
+
·
5
È
$
$
}
5
Ç
º
¹
-
'
º
'
+
Ê
¸
¸
|
!
$
Ç
»
"
$
·
¸
+
¹
·
+
"
)
¸
$
)
!
-
¸
À
$
¸
¼
!
"
)
1
6
¸
"
Ê
}
æ
$
$
·
"
6
)
-
5
)
!
6
'
-
-
$
'
¸
¸
'
$
1
$
¹
1
»
$
È
+
Ç
æ
"
)
-
2
¸
*
)
2
'
!
$
À
¸
º
º
)
»
"
+
!
¸
$
)
À
·
¸
$
6
!
6
"
-
+
5
1
¸
$
æ
+
¾
¹
1
»
º
)
-
æ
+
)
¸
$
$
1
É
¹
Ç
$
º
!
¸
$
¸
!
)
5
º
¾
2
¸
¸
"
+
Ç
+
$
¸
¸
$
¸
æ
5
·
Ê
¼
$
-
'
¸
"
$
+
+
5
¹
-
6
-
¸
Ê
W
á
Å
!
¸
)
5
·
-
¸
+
!
)
+
1
¸
*
$
-
)
'
À
2
)
'
!
¹
¹
+
-
$
!
!
$
'
1
$
·
)
+
-
"
¸
!
'
)
Ç
1
'
$
$
-
¸
'
$
*
'
)
$
À
¸
$
*
'
)
¹
À
+
Þ
¹
!
¾
$
+
¼
"
æ
'
+
2
¸
ß
"
$
$
¸
!
·
+
$
-
)
1
5
º
'
Ê
¾
'
½
¾
!
$
5
Å
!
'
"
Z
Ä
&
M &
M
X
<
K
Æ
'
ó
R
O
O
U
G
O
<
Ê
K
Â
K
è
Ë
ö
©
Û
Ø
à
Ë
Í
©
Î
ö
Æ
I
ó
©
Â
Ã
Å
ö
Ã
Ñ
Ê
Ë
ñ
è
ô
Ù
Å
Å
Ë
ø
Î
ß
Ö
ó
ð
Ó
ø
ß
ð
Ó
Ê
Ë
á
â
á
â
Æ
ó
Î
Ö
ø
ß
ð
Ó
Æ
ó
Î
Ö
ø
ß
ð
Ó
Í
Ö
Í
Ö
Æ
ð
Ë
Î
È
Â
Å
á
á
Û
Ø
â
à
Å
Î
â
Ü
Å
â
ß
×
ô
Ö
d
)
-
¸
$
¹
2
)
!
¸
"
À
"
5
1
1
)
)
¼
g
Æ
'
p
^
)
$
^
+
á
â
+
ö
Ú
×
Û
)
ö
Æ
'
I
Î
)
Î
Ö
ø
ß
ð
Ó
á
â
Æ
'
á
â
Æ
'
Î
Ö
ø
ß
ð
Ó
Î
Ö
ø
ß
ð
Ó
Ö
Ú
©
ß
ö
Î
Ö
ø
ß
ð
Ó
Â
Ã
Å
È
Æ
'
Ê
Ë
Í
ß
ö
Ú
×
Ø
Ø
×
Û
Ö
Ö
Ù
Ö
Å
Î
Î
Ö
Ú
ß
ð
Î
Î
×
Ü
á
â
Å
Ú
×
Û
Ñ
ð
ñ
1
1
d g
p
^
3
^
)
-
¸
$
¹
2
)
!
¸
"
$
+
+
5
¹
-
6
-
¸
2
!
)
6
$
-
·
-
)
Ç
-
$
¸
d
!
)
6
5
-
¸
-
$
$
¹
1
Ç
·
+
5
¼
!
·
·
¾
5
1
È
$
·
!
$
Å
¸
5
)
!
¸
-
5
·
·
$
+
+
-
¸
º
$
-
'
·
2
)
-
)
+
!
5
¸
'
$
!
U
+
G
Ã
R
¡
+
'
$
$
<
-
+
B
R
M
'
K
$
$
¹
M
!
!
F
$
-
¼
M
)
"
æ
O
¸
!
2
¾
À
R
!
!
A
¸
5
U
G
"
¸
X
"
!
+
!
»
+
È
¸
Z
-
Í
'
6
2
Ê
)
!
4
¹
-
6
^
!
$
¸
6
5
-
M
Ë ¸
!
$
¹
l
-
+
¸
d
2
"
Ý
)
r
!
m
6
·
i
)
l
$
¸
-
¸
q
5
!
d
)
)
£
-
2
1
g
!
$
i
)
-
Ý
'
'
$
¸
$
*
)
À
¹
!
$
¼
$
!
5
$
º
1
+
)
2
¸
)
¸
6
"
)
)
+
Ê
r
-
1
$
-
¹
¾
$
¹
¸
)
2
Þ
<
>
)
¸
"
<
O
)
æ
¼
!
)
¹
ý g
!
$
6
+
Þ
Q
O
X
Q
;
5
<
É
¸
Ç
Ç
ý
5
g
Q
j
<
;
G
W
ý g
¸
-
ý g
Å
"
D
X
ß
$
-
'
6
$
¼
+
¸
!
$
-
+
2
)
!
6
Q
æ
D
9
7
O
Q
<
;
F
G
O
D
ß
$
¼
¸
!
$
)
$
¹
!
-
$
'
6
+
W
ý g
;
'
F
"
¸
Ê
"
6
6
)
!
»
æ
6
$
¼
¼
5
-
¹
5
+
+
¼
·
5
È
'
¶
W
g
º
ý
»
¸
$
!
$
5
+
-
+
¸
2
Ù
)
)
!
-
2
'
6
¸
$
$
"
¸
¸
2
5
$
)
)
!
-
1
1
!
È
)
-
¾
À
1
5
-
6
+
¹
-
¸
!
¾
1
+
Ç
¸
"
¼
!
)
¹
!
$
6
¸
Ç
·
2
Ê
}
5
¹
Ê
Ç
1
¸
Ú
º
$
-
º
¸
$
5
-
'
º
»
6
6
)
$
¼
g
)
!
-
+
2
)
2
)
!
6
$
¸
5
¸
5
)
-
)
-
º
»
$
+
¸
)
2
!
»
æ
6
$
¼
¼
5
-
¹
$
-
'
¼
!
)
¹
!
!
)
¹
!
$
6
$
-
'
Ú
Ü
$
-
ý
$
û
$
-
'
û
!
)
!
)
¼
g
6
¸
!
$
-
+
!
6
$
2
!
)
ý
5
6
¹
!
$
6
¹
!
$
6
¸
g
¼
Ê
$
!
¸
"
$
º
+
¸
!
$
·
¸
+
¸
$
¸
6
$
·
"
5
-
+
)
2
Ú
$
-
'
Ú
Ü
)
ý
Ê
Ê
g
"
6
ý
5
6
)
!
»
¶
ý
6
$
ý
¼
¼
5
-
¹
6
6
$
¼
'
6
$
¼
)
¾
+
$
¸
5
¸
$
¸
»
¼
+
)
2
û
¸
)
'
$
¸
$
¸
»
¼
+
)
2
û
Ç
ý
ý
5
9
º
â
·
¸
+
)
2
Ú
¸
)
)
º
â
·
¸
+
)
2
Ú
Ü
Ç
$
-
'
9
5
-
¸
!
)
'
¾
·
$
¾
É
5
1
5
$
!
»
)
º
â
·
¸
+
5
-
Ú
Ü
$
+
!
½
¾
5
!
'
2
)
!
¼
!
)
¹
!
$
6
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
Ê
9
}
)
!
!
·
+
)
-
!
¸
!
·
'
¸
-
¾
-
5
+
½
+
Ç
¾
5
1
¸
5
»
+
º
+
¾
»
$
·
-
5
$
¸
-
)
¸
¸
6
5
"
$
·
¸
)
º
â
Å
·
!
¸
»
5
$
-
¸
¸
)
"
6
5
·
·
)
)
!
!
º
â
+
¼
·
)
¸
5
-
'
-
5
$
-
+
¹
+
¸
¸
$
$
¸
¸
)
)
2
Ú
2
Ú
5
Ü
+
!
Ê
¼
-
æ
·
Ç
4
¸
"
6
6
)
!
»
6
$
¼
¼
5
-
¹
'
È
-
+
¼
$
!
¸
)
2
¸
"
!
1
$
¸
5
)
-
Ê
"
6
6
)
!
»
6
$
¼
¼
5
-
¹
5
+
¶
ý
¾
+
¾
$
1
1
»
-
)
¸
¸
)
¸
$
1
¸
"
!
6
5
¹
"
¸
º
+
¸
$
¸
+
)
2
Ú
¸
"
$
¸
·
$
-
-
)
¸
º
6
$
¼
¼
'
¸
)
$
+
¸
$
¸
Ü )
2
Ú
'
;
¾
<
¸
>
6
:
V
}
)
Þ
6
d
)
!
6
»
)
!
!
»
+
)
¾
d
!
$
¼
·
¼
·
5
-
)
¹
-
+
¸
ß
!
$
"
5
-
¸
+
+
¸
Ê
$
¸
+
)
2
¼
!
)
¹
!
$
6
+
)
2
$
1
$
-
¹
¾
$
¹
À
5
¸
"
¶
W
g
!
·
$
¾
-
!
)
!
!
$
!
)
1
'
+
)
·
6
5
2
+
!
-
'
+
¼
!
)
!
'
5
"
)
'
Å
Å
Ç
·
5
-
»
+
-
¼
-
¾
¸
¸
!
'
-
¹
)
$
Ç
"
!
'
$
1
-
$
)
·
+
"
)
"
¸
¾
-
"
-
!
Ç
¸
¸
$
5
¸
-
!
-
'
5
'
6
+
-
2
Å
-
+
5
-
¸
!
º
$
)
)
)
-
â
+
1
+
Å
¸
¸
)
¸
·
5
+
1
¸
!
6
'
5
$
¸
º
$
+
5
·
º
1
)
·
Ã
1
$
-
¹
¾
$
¹
û
À
5
¸
"
$
*
$
¸
Ç
È
-
5
¸
º
»
¸
æ
¸
$
)
Ç
·
¸
!
5
ý
-
5
5
$
!
Á
æ
5
¸
$
+
6
¸
+
¸
Å
5
!
6
¸
"
)
$
$
$
+
¼
'
2
À
-
)
º
g
¸
2
Ç
Ã
$
$
+
·
$
!
"
5
¸
$
+
º
$
$
)
·
+
·
¼
+
¸
5
)
¼
¸
+
¸
1
¾
·
-
¾
1
"
Ê
â
º
6
2
)
)
!
)
)
+
+
$
!
+
¾
Å
5
¹
·
)
)
-
»
¹
-
5
¼
)
5
Ë
º
·
-
'
Ê
5
$
-
+
"
¸
'
º
·
¹
+
-
¸
â
-
$
-
º
5
¹
!
)
5
¸
5
$
)
¼
·
¸
-
¸
·
2
)
!
·
¸
+
5
¹
+
¸
¸
-
!
5
¸
5
¾
¾
)
+
-
$
'
¼
Ç
È
Å
·
+
)
'
!
)
-
¾
!
-
-
5
-
æ
¸
'
6
6
)
!
»
Ê
g
¾
¾
¼
¼
)
+
2
¾
!
¸
"
!
¸
"
$
¸
û
"
$
+
-
)
)
)
1
$
-
¸
»
¼
+
Ê
"
6
6
)
!
»
6
$
¼
¼
5
-
¹
)
2
¸
)
¶
g
û
·
)
-
+
5
+
¸
+
)
g
2
g
<
$
g
6
$
¼
¼
5
-
¹
2
!
)
6
$
¸
)
6
5
·
'
$
¸
$
¸
»
¼
+
)
2
û
¸
)
+
½
¾
-
·
+
)
2
º
»
¸
+
=
g
5
-
·
1
¾
'
5
-
¹
5
-
·
1
¾
'
5
-
¹
¸
"
+
5
t
)
2
)
º
â
·
¸
+
9
G
£
>
$
-
'
$
1
5
¹
-
6
-
¸
·
)
-
'
5
¸
5
)
-
+
;
G V
X
D
Ç
$
-
'
9
$
6
$
¼
¼
5
-
¹
2
!
)
6
)
)
1
$
-
+
¸
)
5
-
¸
¹
!
+
Ç
Ê
¹
Ê
7
;
9 V
> Ý
º
F
Q
P
>
Ý
v
9
<
$
g
g
!
È
-
6
-
¸
)
2
¸
"
·
)
6
¼
)
+
5
¸
'
$
¸
$
¸
»
¼
+
)
2
¸
)
$
¸
)
6
5
·
'
$
¸
$
¸
»
¼
+
)
2
=
g
û
g
<
$
g
g
g
6
$
¼
¼
5
-
¹
2
!
)
6
¸
"
-
Å
5
!
)
-
6
-
¸
¸
)
¸
"
6
6
)
!
»
)
2
û
À
"
5
·
"
'
)
+
=
g
·
)
6
¼
¾
¸
!
1
$
¸
5
Å
$
'
'
!
+
+
+
)
2
1
)
·
$
1
Å
$
!
5
$
º
1
+
)
2
¼
!
)
·
'
¾
!
+
Ç
9
È
É
¼
!
$
!
1
$
¸
5
Å
$
'
'
!
+
+
2
)
!
¸
"
!
¸
¾
!
-
$
'
'
!
+
+
$
-
'
¸
"
¼
)
5
-
¸
!
¸
)
+
¸
$
¸
5
·
9
5
-
'
¸
!
)
·
'
+
¾
+
·
)
!
Ç
$
-
À
Å
$
!
5
$
º
1
$
-
'
5
¸
+
!
1
$
¸
5
Å
$
'
'
!
+
+
"
)
1
'
5
-
¹
$
¼
)
5
-
¸
!
¸
)
¸
"
9
'
·
»
-
)
$
6
6
¼
5
¾
¸
·
¼
!
+
5
t
'
·
$
-
+
+
'
)
$
!
1
Ç
5
¹
-
6
-
¸
)
2
¸
"
$
·
¸
5
Å
$
¸
5
)
-
!
·
)
!
'
Ç
9
¾
+
¸
"
û
æ
Å
$
!
5
$
º
1
V
O
g
I
9
)
-
¸
"
¸
)
¼
)
2
¸
"
+
¸
$
·
Ã
; V
2
)
!
¸
"
º
$
+
$
'
'
!
+
+
)
2
¸
"
$
·
¸
5
Å
$
¸
5
)
-
!
·
)
!
'
"
Z
&
M
M
&
X
<
K
'
R
O
O
U
G
O
<
K
K
<
$
g
f
6
$
¼
¼
5
-
¹
2
!
)
6
æ
$
'
'
!
+
+
+
¸
)
û
æ
$
'
'
!
+
+
+
Á
=
g
Þ
5
5
ß
$
-
'
Þ
5
5
5
ß
'
g
È
-
¸
"
6
$
¼
¼
5
-
¹
2
)
!
1
)
·
$
1
Å
$
!
5
$
º
1
+
)
2
¼
!
)
·
'
¾
!
+
Ç
9
$
-
)
-
»
6
)
¾
+
·
)
6
¼
)
+
5
¸
)
º
â
·
¸
+
$
!
'
·
)
6
¼
)
+
'
$
·
·
)
!
'
5
-
¹
¸
)
Þ
5
5
ß
$
-
'
6
$
¼
æ
9
¼
¸
'
"
)
!
-
¸
5
)
$
+
'
$
'
"
!
$
+
+
¼
¼
+
)
)
5
¾
-
¸
¸
+
5
!
'
F
)
O
O
2
7
¸
M
"
>
+
;
¸
¸
W
$
·
)
Ã
Þ
6
$
5
¸
"
-
¸
"
$
5
-
$
¸
¼
"
ß
Ç
"
$
¼
Ê
W
9
Ù
¸
6
'
)
'
5
¼
!
¾
+
-
+
¸
)
â
º
¸
)
5
-
¾
)
¸
¾
¼
Å
6
¼
!
!
1
¼
)
)
Å
$
)
-
Ç
6
+
¼
!
¸
¸
$
-
»
"
"
!
¸
¸
¸
$
$
$
'
¸
Þ
"
$
"
5
$
5
+
ß
1
Ê
5
¸
}
6
5
5
¸
¾
-
Å
!
¸
6
!
)
)
"
)
â
!
'
º
!
»
¾
·
·
¸
6
)
)
+
¸
À
!
2
+
+
Ç
û
$
"
·
)
$
1
5
5
Ã
+
º
¹
-
+
Å
1
6
$
1
"
$
!
$
¾
Å
5
-
5
$
¸
)
)
»
Ç
-
·
'
!
+
-
¸
¸
5
$
'
'
"
"
¸
¸
5
6
¸
"
'
1
)
-
$
+
6
"
¸
¸
'
6
º
2
-
¸
)
$
!
+
»
¼
$
¾
!
$
!
6
)
"
¸
$
+
"
¼
$
¸
R
¼
+
5
+
x
¸
'
È
á
$
·
)
'
¸
)
Ê
Ë æ
Ã
-
1
¼
"
$
g
)
·
+
+
)
!
Ê
"
-
Ç
¸
"
6
6
)
!
»
6
$
¼
¼
5
-
¹
2
!
)
6
û
¸
)
R
x
á
Ë æ
1
¼
"
$
º
$
+
5
·
$
1
1
»
6
$
¼
+
¶
g
¸
"
¼
)
5
-
¸
!
+
O V
I
;
$
-
V
'
F
O
O
7
M
>
;
¸
W
É
1
¼
)
!
·
$
+
¸
+
5
)
'
-
5
+
2
Ç
¸
6
"
6
$
)
Å
$
!
5
1
»
1
$
º
)
1
·
$
!
¸
)
!
¹
5
+
¸
!
+
Ç
$
-
'
$
+
+
5
¹
-
+
!
¹
5
+
¸
!
+
¸
)
Å
$
1
¾
$
¸
W
5
¹
)
5
-
+
+
¸
Ç
¼
!
$
+
!
$
$
!
6
-
¸
)
¸
!
+
+
¾
¸
·
·
Ë Ê
5
-
'
¸
'
2
5
)
¸
5
!
)
-
Å
$
$
1
1
6
¾
$
¸
5
6
-
)
¹
!
»
É
6
¼
¾
!
+
+
+
¸
5
º
)
-
+
$
1
æ
Ê
!
)
¹
!
$
6
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
+
$
!
·
)
-
'
5
¸
5
)
-
$
1
¹
!
$
¼
"
!
À
!
5
¸
!
¾
1
+
¸
!
$
-
+
2
)
!
6
5
-
¹
¸
"
¿
·
)
¸
-
¸
!
+
+
¸
!
)
1
6
!
$
½
¾
$
¸
À
-
'
!
·
-
5
6
'
¸
)
$
$
"
¸
!
2
·
$
5
¾
*
1
¼
-
$
¼
+
1
)
5
$
·
;
<
> V
A
}
5
¹
!
$
¸
5
¹
!
)
Ê
B
¼
+
-
5
"
¼
)
+
5
$
$
û
ý
}
À
)
2
·
¸
6
5
"
¾
2
$
1
1
¼
·
!
$
¸
!
$
)
+
À
+
¹
!
¸
!
Ê
5
"
$
6
}
¸
)
!
!
$
·
¾
º
1
+
1
6
)
¸
!
+
!
!
1
$
·
-
·
$
¸
¸
¸
+
¸
$
-
'
+
+
+
¸
$
¸
+
!
+
5
)
!
6
!
6
¼
¸
¼
)
$
¾
¹
·
+
+
!
"
$
5
-
¸
º
6
-
¸
+
Ú
»
"
Ü
)
6
À
À
)
)
-
"
û
+
º
+
'
)
2
¸
+
¸
"
Ú
-
$
$
$
¹
¸
º
+
$
+
¸
-
!
»
$
·
¸
Ê
ý
"
)
À
+
$
¹
!
$
¼
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
2
)
!
¸
"
À
"
5
1
1
)
)
¼
Ç
}
5
¹
Ê
º
¸
"
W
¹
!
$
¼
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
2
)
!
¸
"
$
+
+
5
¹
-
6
-
¸
Ê
"
¹
!
$
¼
"
5
·
$
1
-
)
¸
$
¸
5
)
-
5
+
$
-
É
¸
-
+
5
)
-
¶
)
2
¹
!
¸
"
$
¼
'
¹
"
¹
!
+
$
+
Ç
¼
$
·
!
5
"
!
5
·
·
)
·
1
$
1
-
Å
-
¸
)
!
!
)
1
¸
¸
æ
$
5
¸
·
*
5
)
)
-
+
)
$
À
!
2
6
'
$
¹
)
¸
+
)
-
¸
6
$
5
Ê
)
¹
·
Ç
À
+
+
Å
Ë Á
)
1
!
5
+
'
Ç
5
¸
"
-
'
6
¹
)
-
-
+
$
$
6
¸
!
$
¹
+
'
)
+
$
2
+
¸
Å
½
$
¾
æ
!
$
*
¸
5
!
)
·
Å
À
+
'
6
!
¸
¹
$
5
»
·
+
Ç
º
+
+
$
-
¸
¸
$
-
'
!
'
'
6
2
$
+
+
!
)
"
!
¼
'
!
æ
4
+
-
º
¸
5
-
¼
¹
!
¸
)
'
!
¾
·
+
Ê
å
'
¼
º
¼
»
¸
"
!
·
$
·
+
)
-
-
¸
$
É
6
¸
2
!
+
Þ
-
)
¹
!
-
$
¸
6
!
6
6
5
$
!
-
$
1
Ê
+
ß
"
+
¸
$
-
-
$
'
6
2
)
!
;
+
D
»
j
-
+
¸
¸
$
$
É
-
¸
'
!
+
2
)
+
¸
!
$
"
$
-
¸
»
·
¸
$
!
-
6
Ê
¶
Ù
2
¸
"
-
$
6
+
5
-
$
¹
!
$
¼
"
$
!
-
)
¸
¾
-
5
½
¾
Ç
¸
"
»
$
!
+
¾
º
+
·
!
5
¼
¸
'
Ê
"
$
¼
¼
1
5
·
$
º
5
1
5
¸
»
¶
·
)
+
-
¸
5
5
'
5
6
¸
$
)
-
-
5
-
+
¸
)
¸
$
"
-
5
·
$
-
+
·
'
$
-
$
'
+
$
1
$
6
º
+
¸
¸
$
+
æ
À
"
*
$
)
»
¸
¸
!
»
¾
¼
À
·
5
$
¸
-
¾
!
¹
-
$
$
·
1
1
»
)
+
$
-
5
+
'
+
5
$
5
¸
!
5
-
)
¸
-
$
"
+
1
2
+
¸
)
)
!
!
¹
$
¸
!
-
"
$
+
¼
2
$
"
æ
)
!
+
¸
6
+
!
5
$
$
¹
¸
-
-
+
5
6
2
)
-
)
!
+
-
2
¸
6
)
Ê
$
!
¸
5
¸
¼
)
¸
-
"
5
+
À
6
5
$
-
"
t
5
'
5
-
1
¹
·
$
1
¸
-
!
)
)
$
º
¼
-
+
Ç
2
6
$
)
!
)
-
'
6
'
$
1
æ
'
Ê
C
D
"
°
º
5
±
¹
E
¹
°
+
!
4
¸
¼
*
!
$
·
%
¸
5
·
+
$
´
1
G
¼
µ
!
)
®
º
E
1
6
5
-
·
)
-
+
¸
!
¾
·
¸
5
-
¹
$
·
)
!
!
·
¸
·
)
6
¼
5
1
!
5
+
¸
"
+
5
t
)
2
¶
¸
"
·
)
'
À
"
5
·
"
6
¾
+
¸
º
Å
!
5
È
'
Ê
!
$
'
5
¸
5
)
-
$
1
$
¼
¼
!
)
$
·
"
+
¸
)
¼
!
)
¹
!
$
6
Å
!
5
È
·
$
¸
5
)
-
¶
$
!
-
)
¸
À
1
1
æ
+
¾
5
¸
'
2
)
!
1
$
!
¹
¼
!
)
¹
!
$
6
+
+
¾
·
"
$
+
·
)
6
¼
5
1
!
+
Ê
"
¾
+
)
2
¼
!
)
¹
!
$
6
¶
·
"
·
Ã
5
-
¹
+
)
1
Å
+
¸
"
5
+
¼
!
)
º
1
6
5
-
+
)
6
·
$
+
+
Ç
5
-
¼
$
!
¸
5
·
¾
1
$
!
2
)
!
·
)
6
¼
5
1
!
+
Ê
"
¸
¶
·
"
-
5
½
"
¾
À
º
)
$
+
5
!
Ã
·
+
5
2
'
)
!
$
$
5
1
+
1
¼
¸
!
)
)
¹
Å
!
!
5
$
6
2
+
»
¸
¸
"
"
$
$
¸
¸
¸
¸
"
!
$
-
+
)
¾
2
)
¸
!
¼
6
5
¾
¸
-
¼
6
¾
¸
¸
+
¸
+
)
·
)
!
¾
¸
¸
$
5
¼
¾
-
¸
·
)
+
Ê
-
'
5
¸
5
)
-
+
2
!
)
6
¶
"
'
À
¾
5
·
·
"
¸
'
"
Ê
5
¹
Ê
·
" ¶
}
Ê
)
5
!
-
!
¼
¾
·
¸
¸
-
5
+
+
+
!
)
2
2
¾
¸
+
"
'
)
5
¾
2
¸
¸
¼
"
¾
¸
·
À
"
5
¸
·
"
Ã
!
!
¹
2
$
$
5
!
1
'
+
¸
¸
)
)
"
Å
¸
!
¹
5
2
»
5
Å
¸
"
-
5
+
-
¼
·
¾
)
¸
-
·
'
$
5
-
¸
5
º
)
-
+
'
Ç
·
æ
2
Ê
U
G
R
¡
<
B
R
M
cond
K
any1
NT
F
M
O
R
A
U
G
X "
NT
WHILE
any2
NT
any1
NT
EXPR
WHILE
NT
any2
TT
TT
NT STATS
EXPR does not contain function calls
STATS is not empty EXPR does not contain function calls
L1:
NT
L2: any2
ifjmp(EXPR,L1,L2)
NT
any1
ifjmp(EXPR,L1,L2)
NT L1:
!
$
-
+
2
)
!
6
5
-
¹
À
"
5
1
1
)
)
¼
+
¶ g
any1
p
^
H
^
NT
DES
NT
EXPR
src
any2
ASSIGN
dest
EXPR.type=int
DES.type=int
EXPR does not contain function calls
any1
any2
intassign(DES,EXPR)
!
$
-
+
2
)
!
6
5
-
¹
$
+
+
5
¹
-
6
-
¸
+
¶ g
p
^
`
I
^
π
x
checker
any1
y
y
refuse x Ë
g
Z
cond
NT
EXPR
M
p
^
`
`
^
!
·
"
5
¸
·
¸
¾
!
)
2
·
"
·
Ã
'
2
¾
-
·
¸
5
)
-
+
L2: any2
,
"
Z
·
7
)
&
¾
¾
'
5
-
¼
¼
¸
5
)
)
M
M
&
+
-
Ç
X
<
À
'
Þ
K
"
ß
$
$
-
)
-
Å
'
R
$
'
O
¼
¼
)
O
!
+
)
¸
U
¹
·
G
!
)
O
$
-
<
K
6
'
K
Ú
5
¸
5
5
)
6
-
¼
(
1
Þ
6
Ú
-
Þ
¸
5
ß
-
¹
ß
$
)
2
-
5
¾
-
-
·
¼
¸
¾
¸
5
)
-
+
Î
Á
Ê
<
B
Ñ
J
¸
I
M
À
>
I
5
>
¸
"
Q
Þ
¼
O
O
º
V
$
2
¾
-
·
¸
5
¸
"
$
¸
!
¸
¾
!
-
+
¸
"
Å
$
1
v
¾
)
2
(
Þ
ß
v
Ú
m
j
Ý
Ü
£
Á
g
i
Ü
Þ
Á
<
ß
Á
Ê
á
)
-
+
5
'
!
¸
"
¼
!
)
¹
!
$
æ
ß
v
!
Á
L
6
L
J
Ý
Ý
Ú
Þ
ß
»
L
I
g
M
>
I
>
Q
Þ
Ú
Þ
ß
ß
m
£
c
b
Ý
l
b
£
j
l
Ý
v
b
Ë
r
Ù
2
L
»
» ¢
b
O
b
Ý
I
M
>
I
>
Q
5
+
·
)
!
!
·
¸
1
»
5
6
¼
1
6
-
¸
'
¸
"
-
(
Þ
Ú
Ü
Þ
ß
ß
$
1
À
$
»
+
"
)
1
'
+
Ê
å
-
'
!
¸
"
5
+
v
·
)
¸
-
"
'
5
¸
¼
5
"
)
$
!
-
!
2
5
¸
5
)
2
$
!
Ü Ú
1
·
'
)
À
)
!
!
·
+
·
$
-
¸
)
-
-
¸
¾
+
+
!
+
2
)
¾
+
2
Ú
Ú
À
5
¸
Ü
¸
"
'
"
)
)
5
¾
-
¼
+
¸
¾
-
Å
¸
)
!
¸
5
¸
"
'
È
·
$
-
¼
¸
5
¸
)
"
-
-
)
'
)
¾
¸
-
¼
¸
¾
"
¸
5
+
¼
·
$
)
!
!
¸
5
!
$
·
1
¸
·
Ê
)
Ù
!
-
!
¼
·
$
¸
!
-
¸
5
+
·
¾
+
1
)
$
!
2
Ç
Ú
Ê
Ê
¶
!
)
¹
!
$
6
·
"
·
Ã
5
-
¹
$
1
1
)
À
+
2
)
!
Å
!
5
2
»
5
-
¹
¸
"
!
+
¾
1
¸
+
)
2
1
$
!
¹
¼
!
)
¹
!
$
6
+
Ê
Ù
¸
$
Å
)
5
'
+
¿
Å
!
6
5
¾
2
»
+
5
¸
-
¹
º
¸
"
Å
¼
!
5
!
È
)
¹
'
!
$
6
Ê
5
"
5
+
¸
5
+
+
1
2
¼
$
5
!
¸
-
5
+
·
¸
¾
1
$
$
'
!
)
1
-
»
5
1
-
»
¸
¸
!
"
+
·
¸
5
-
"
¹
·
Ã
À
"
!
$
-
-
¸
'
"
5
¸
·
+
"
5
·
6
¼
Ã
1
!
5
6
+
!
-
¸
1
$
$
¸
¸
5
5
)
Å
-
1
»
¶
+
6
$
1
1
$
-
"
'
5
'
$
+
»
$
¸
·
$
)
!
Å
!
5
!
+
5
2
»
$
·
¼
!
)
5
6
·
¼
Ç
$
"
!
)
'
À
¸
Å
)
¸
!
Á
"
}
¹
)
5
!
·
Å
)
-
¼
6
¼
!
5
1
)
¹
!
!
+
$
6
À
Ê
'
)
-
)
1
)
-
¹
!
Å
!
5
2
»
¸
"
$
¸
¶
>
N
¸
$
¸
"
>
Q
¸
j
5
$
)
-
·
)
â
!
·
·
+
5
-
·
5
¼
Å
·
µ
!
1
¸
$
6
ã
º
)
!
4
¸
+
Ã
±
5
$
*
!
6
+
"
Q
'
È
5
8
!
)
¼
+
1
¸
¹
$
5
$
6
'
5
-
µ
+
Ù
"
°
¾
Ú
Ê
¸
+
+
$
¸
R
"
!
¸
+
°
É
)
+
¸
-
µ
!
!
'
À
'
¯
"
)
$
!
¸
·
À
´
'
+
±
·
1
"
1
»
¼
$
!
µ
¸
¸
®
6
·
!
)
'
)
1
$
!
$
µ
+
!
¼
¯
¼
$
6
´
'
¸
)
'
¸
$
·
»
1
+
°
¹
+
·
$
)
-
¾
D
'
!
Ú
®
)
¸
5
´
!
¹
1
$
)
Å
¸
º
5
¼
1
'
!
)
Þ
'
¹
¸
º
!
"
$
»
$
6
¸
¸
Ç
"
5
!
·
+
"
·
+
)
)
·
¾
!
6
Ã
·
5
¼
5
1
¸
1
Ç
!
$
ß
5
6
-
5
æ
'
5
2
Ê
+
·
!
5
º
'
+
)
2
$
!
2
)
!
+
)
1
Å
5
-
¹
¸
"
¸
"
!
¿
Å
¸
!
5
5
)
[
È
·
-
^
5
J
¸
)
-
¸
$
+
Ã
+
2
!
)
6
+
·
¸
5
)
-
Ù
Ê
Ê
Ù
-
¸
"
5
+
+
·
¸
5
)
-
À
'
5
+
·
¾
+
+
'
¸
$
5
1
+
)
2
¸
"
5
+
+
)
1
¾
æ
Ê
`
.
+
$
+
6
¸
$
b
$
!
-
¸
l
g
¸
5
L
2
·
Ü
!
+
)
d
£
g
6
)
i
¸
2
¸
Ý
"
"
i
m
$
+
)
+
£
+
¾
c
¾
!
b
6
Û
·
¼
1
i
¸
$
5
-
)
q
U
-
¹
¸
¾
$
g
"
¹
Ë
$
b
l
¸
H
¸
º
"
»
U
b
"
5
1
Ü
-
g
5
¼
¸
L
5
)
Ü
$
d
1
2
£
+
g
¼
i
·
Ë
$
Ý
-
5
¾
È
·
$
¸
d
5
5
)
+
-
·
)
)
!
2
!
¸
·
"
¸
)
Ê
¼
"
!
$
-
¸
5
$
)
-
·
$
)
1
6
æ
¶
¼
5
1
6
!
$
¾
1
+
·
$
"
¸
¼
5
-
·
5
+
È
)
¸
"
·
2
$
¸
$
5
$
-
)
-
»
º
+
5
¸
¸
!
$
$
+
!
·
·
¹
¸
)
!
¸
+
!
¼
¸
$
!
¸
·
)
¸
¹
5
!
6
$
2
6
$
·
)
!
Ú
"
5
Ü
-
Å
¼
!
)
!
)
2
»
'
+
Ú
¾
·
)
Ê
¾
!
'
"
·
$
·
¼
¼
·
!
)
)
!
!
)
)
'
¹
2
5
5
!
-
$
6
¹
+
Ú
¸
'
)
·
¸
¸
)
"
"
6
+
¼
)
$
¼
+
º
·
+
5
'
¸
È
Å
!
·
$
$
!
·
¸
¸
5
¸
5
·
+
)
¸
-
$
1
$
+
1
¸
5
»
6
æ
$
-
'
-
'
¶
"
)
¼
5
!
5
t
)
-
¸
$
1
1
»
Ê
"
Å
!
¸
5
·
$
1
'
·
)
6
¼
)
+
5
¸
5
)
-
2
)
1
1
)
À
+
¼
!
5
-
·
5
¼
1
+
)
2
·
)
-
Å
-
¸
5
)
-
$
1
·
)
6
æ
5
¶
1
-
¸
!
'
!
!
·
$
6
)
·
!
6
¸
·
"
5
'
¼
5
)
Ê
$
5
À
·
¸
+
)
¸
¸
¸
$
5
¾
)
Å
!
º
¸
Ç
!
Ê
+
-
2
Ç
!
-
$
)
$
Ù
¼
·
!
¸
+
À
!
+
Å
¸
$
$
·
!
¸
5
·
1
À
6
¸
1
5
»
À
¸
!
+
$
$
·
-
"
+
2
1
5
)
$
5
-
¸
!
-
Ç
)
¸
$
!
!
+
6
¸
¸
1
"
5
)
'
¾
$
)
·
-
!
$
1
6
'
-
·
¾
·
1
)
¼
5
!
)
·
Ç
!
!
¸
$
¸
-
-
'
1
·
5
¸
5
)
·
!
-
6
}
$
+
1
5
+
+
'
5
)
¹
5
Ê
6
'
¾
¸
Ê
1
+
$
}
$
-
¸
)
1
)
5
!
)
¸
$
-
¸
"
-
5
-
·
¹
¾
$
+
"
¼
+
¹
)
!
+
!
)
$
!
5
Å
5
+
t
)
1
$
-
-
¸
»
·
5
$
1
)
6
!
¼
æ
1
»
4
¹
1
)
º
$
1
ã
·
!
)
¸
!
5
·
!
$
·
¸
1
-
'
·
+
+
)
Ç
·
6
2
¼
Ê
)
+
5
E
»
¸
5
)
Ê
-
5
-
¸
!
)
'
¾
·
+
¸
"
5
-
¸
!
6
'
5
$
"
5
-
¸
1
$
-
¹
¾
$
¹
Ë +
¾
Þ
$
¸
¸
!
5
æ
¶
º
¾
¸
'
+
¸
!
¾
·
¸
¾
!
¸
!
+
ß
Ç
º
$
+
5
·
º
1
)
·
Ã
¹
!
$
¼
"
+
Ç
$
-
'
6
$
·
·
)
'
Ê
"
5
!
+
6
$
-
¸
5
·
+
5
+
¶
¹
5
Å
-
º
»
$
º
+
¸
!
$
·
¸
+
¸
$
¸
6
$
·
"
5
-
+
û
W
Ç
û
Ç
$
-
'
û
Y
Ê
"
'
»
-
$
6
5
·
¶
õ
2
¾
-
·
¸
5
)
-
+
)
2
¸
"
+
Ë ¾
d
+
·
$
-
º
·
1
$
+
+
5
È
X
'
ô
$
+
5
-
+
¸
ô
!
¾
ý
·
¸
5
)
-
¼
)
5
-
¸
!
+
Ç
Ê
¹
Ê
Ç
u
h
$
-
'
$
+
1
6
$
-
¹
6
¾
)
$
¹
!
»
2
¾
-
·
¸
5
)
-
-
·
¸
¸
5
+
)
)
)
-
+
¸
Ê
"
ý
Ë
¹
$
5
g
2
Ç
ý g
2
¾
¾
Ê
-
>
)
¸
D
N
"
Ç
9
!
+
F
O
Q
6
>
$
Ç
-
Q
¸
5
>
·
X
Ê
+
}
2
)
)
!
)
!
Ê
"
5
+
+
6
$
-
¸
R
$
¡
¼
5
<
¼
+
5
B
'
R
-
M
K
M
¹
¸
È
-
F
"
M
+
'
¾
O
+
6
5
R
$
-
A
U
-
¹
G
¸
¸
X
5
"
"
·
+
)
2
6
Z
)
G
-
6
)
!
»
ý g
2
G
6
!
d
U
5
·
+
+
5
6
¾
1
$
¸
+
Ç
¾
¼
¸
)
!
+
)
¾
!
·
·
)
-
æ
¶
ý g
+
¸
+
¸
!
$
5
-
¸
¼
5
+
Ç
-
¸
¸
"
"
)
)
!
1
5
¹
5
-
Ë '
$
¾
1
+
d
6
$
Ê
-
"
¸
5
-
5
·
+
¸
Ç
"
5
Ê
1
Ê
$
Ç
-
)
¹
-
¾
$
+
¹
¸
¼
5
+
-
¸
$
"
-
-
'
Ë À
¾
d
$
!
·
5
)
-
!
¸
!
¹
+
!
¼
)
$
¸
-
'
'
+
Ê
¸
)
)
»
-
"
1
¼
¶
g
)
2
¸
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
!
¾
1
+
5
-
+
¸
!
¾
·
¸
5
)
ý
-
g
+
$
!
·
ý
)
5
6
¼
1
¸
1
»
1
5
6
5
-
$
¸
'
Ê
"
-
$
¶
g
æ
6
$
¼
¼
5
-
¹
¸
)
5
g
+
"
)
À
_
+
¸
"
+
¸
¼
ý
+
5
+
$
¼
¼
1
ý
5
'
$
-
'
¸
"
5
-
+
¸
!
¾
·
¸
5
)
-
¼
)
5
-
¸
!
+
$
!
6
$
¼
¼
b
b ^
_
`
b
_
k
l
n
c
b
^
_
h
{
|
x
u
g
l
o
n
v
g
i
h
r
d
e
_
g
u
l
o
n
v
i
h
v
_
`
x
^
_
k
l
n
r
d
h
b
[
g
u
l
o
n
v
i
z
h
z
v
i
x
u
i
g
n
v
ã
i
!
¸
|
5
·
i
$
\
1
c
c
i
'
|
x
»
d
e
z
i
·
x
\
z
h
)
g
6
|
|
\
\
u
e
c
+
5
¸
n
v
i
h
f
r
g
n
v
i
h
n
v
i
h
u
l
o
c
e
f
r
h
h
g
u
l
o
5
)
-
2
)
!
Å
!
5
2
b
[
»
5
-
\
\
\
c
c
)
o
c
\
z
¼
x
l
\
b
[
v
{
u
b
f
n
c
[
n
g
h
\
x
f
h
u
_
{
b
h
[
\
f
b
\
n
Ê
b
d
e
o
`
n
e
h
[
f
d
o
[
v
i
n
b
c
e
h
l
\
\ c
k
c
d
^
[
i
`
\
[
h
c
f
b
\
[
[
f
h
b
u
c
h
`
g
¹
\
[
^
c
e
z
f
b
[
n
e
h
[
x
c
o
`
v
5
b
\ [
i
}
[
h
Ê
Ê
`
g
'
¹
·
)
|
6
i
¼
5
1
i
z
!
i
+
x
n
¼
v
g
·
|
5
z
È
·
$
¸
5
)
-
+
g
Ù
-
¸
p
^
"
`
]
È
^
!
+
¸
+
¸
¼
Ç
$
+
6
$
-
¸
5
·
+
:
2
)
!
¸
"
+
)
¾
!
·
1
$
-
¹
¾
$
¹
Ç
!
¼
!
æ
g
+
-
¸
'
º
Ë »
¾
+
Ç
5
+
·
)
-
+
¸
!
¾
·
¸
'
¾
+
5
-
¹
¸
"
6
6
)
!
»
+
¸
$
¸
+
¼
$
·
)
2
û
5
Ê
Ê
Ç
¸
"
¶
g
-
¸
Å
"
5
!
)
-
¼
)
6
5
-
¸
-
¸
!
>
+
D
V
O
N
I
$
;
-
'
$ V
-
¸
'
"
F
+
O
O
¸
)
7
!
M
$
>
¹
;
$
+
Ã
)
2
·
$
-
º
¸
!
$
-
+
2
9
Ê
W
¸
F
.
O
5
Q
¸
>
$
"
¸
!
"
5
6
+
$
6
¼
$
¼
¼
¼
5
'
-
¸
¹
)
Ç
¸
Å
"
!
6
»
¸
!
6
$
)
-
+
!
5
»
¸
<
5
)
>
-
!
<
$
¾
1
-
)
'
2
$
W
)
!
6
'
5
-
¸
)
$
¸
!
$
-
+
5
¸
5
)
-
!
¾
1
º
$
+
'
)
-
¸
"
-
À
6
6
)
!
»
g
+
¸
$
¸
+
¼
$
·
Ê
"
6
6
)
!
»
6
$
¼
¼
5
-
¹
·
)
-
+
5
+
¸
+
)
2
¸
À
)
¼
$
!
¸
+
Á
¹
1
)
º
$
1
1
»
¸
"
-
Å
5
!
)
-
æ
¶
6
$
-
'
¸
'
)
!
2
+
+
+
)
¾
+
!
2
·
)
!
)
¸
¼
¸
!
"
)
¹
!
1
$
)
6
·
+
$
5
1
Å
+
6
$
!
$
5
$
¼
º
1
¼
'
+
)
1
2
)
·
$
$
º
1
1
1
)
»
$
·
6
Ã
$
Ê
¼
"
¼
5
!
-
¹
Q
$
!
>
; V
G
U
V
U
> V
Q
X
·
;
)
+ V
6
¸
¼
$
¸
¾
¸
+
+
)
!
2
Ù
1
¾
$
¸
5
Å
d
Ù
¾
¶
À
"
5
6
$
·
"
¼
'
¼
5
$
)
1
-
-
1
¹
5
5
-
5
¸
5
!
¸
5
$
+
¼
+
1
!
¾
+
¸
+
·
$
¸
5
-
¸
-
+
¼
¸
)
!
¸
2
Ù
)
¼
)
¾
¼
!
!
6
d
)
Ù
Å
6
)
!
»
+
¸
$
¸
+
)
2
Ù
¾
d
Ù
¾
Ê
}
)
!
$
·
)
!
!
·
¸
6
6
)
!
»
¾
$
!
1
¹
$
1
9
5
2
5
+
$
1
¹
$
1
+
¸
$
¸
Ç
Ñ
u
Ü
u
Ç
$
-
'
Ü
u
5
+
1
¹
$
1
¸
"
-
Þ
ß
u
Ñ
Þ
Ü
u
ß
Ê
u
9
5
!
5
+
¸
"
6
$
¼
¼
5
-
¹
¸
"
$
¸
!
·
)
Å
!
+
¸
"
)
!
5
¹
5
-
$
1
+
¸
$
¸
Ê
Ù
2
$
·
)
6
¼
¾
¸
$
¸
5
)
-
!
¾
-
+
4
-
¸
)
$
-
5
1
1
¹
$
1
+
¸
$
¸
Ç
¸
"
-
$
!
+
)
¾
!
·
·
)
-
+
¸
!
$
5
-
¸
5
+
Å
5
)
1
$
¸
'
Ê
"
2
)
1
1
)
À
5
-
¹
É
$
6
¼
1
'
¶
6
)
-
+
¸
!
$
¸
+
¸
"
¼
!
)
)
2
2
)
!
¸
"
À
"
5
1
1
)
)
¼
Ç
¸
"
$
+
+
5
¹
-
6
-
¸
Ç
$
-
'
¸
"
'
+
5
¹
-
$
¸
)
!
Ê
"
"
#
&
;
<
> V
}
M &
M
X
<
"
K
¸
!
$
-
+
'
5
¸
R
5
O
)
O
U
-
!
G
¾
O
1
<
K
2
K
)
!
¸
"
À
"
5
1
1
)
)
¼
º
·
)
6
+
¶
W
n
}
g
m
u
£
h
g
;
P V
>
Þ
I
m
O
D
b
U
Ý
ß
ÿ
º
u
£
h
Á
h
Á
Ë
b
Ý
u
h
b
c
w
Ý
u
r
b
w
h
h
Ý
u
u
h
"
c
g
N
¸
!
$
-
h
+
5
¸
5
)
-
w
!
¾
1
h
2
)
!
¸
"
$
+
+
5
¹
-
6
-
¸
!
6
$
5
-
+
Ê
"
¶
'
+
¸
!
$
-
+
5
¸
5
)
-
!
¾
1
2
)
!
$
¶
5
¹
-
$
¸
)
!
6
$
n
g
m
¼
+
Å
$
!
5
$
º
1
+
$
+
2
)
1
1
)
À
+
Á
u £
c
b
Ý
h
N
;
P V
>
Þ
ß
Á
Ý
I
O
D
F
>
D
F
Þ
O V
I
;
þ V
Q
>
; V
U
U
Q
Þ
F
;
9
F
O
Q
O
I
Þ
ß
u
U
u
ß
ß
»
u
W
h
;
U
U
Q
h
ß Þ
Á
Ý
O V
I
;
þ V
Q
>
; V
U
U
Q
Þ
F
;
9
F
O
Q
O
I
ß
U
Þ
u u
v
ß
h
w
g
ß
u
W
h h
Á
h
w
g
Ý
u
u
h
d
v
$
h
¼
¼
5
-
¹
w
$
h
5
+
¼
!
)
Å
-
·
)
!
!
·
¸
º
»
+
¾
º
æ
·
$
+
5
-
¹
$
-
'
+
»
6
º
)
1
5
·
É
·
¾
¸
5
)
-
}
g
p
)
2
¸
"
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
+
Ê
}
)
!
$
1
1
+
¸
$
¸
+
$
-
'
¸
$
+
Ã
+
p
Â
Ý
Ý
Â
"
)
1
'
+
5
Þ
ß
Ý
u
u
u
u
h
Ý
Â
Ê
-
·
Ç
º
)
¸
"
$
º
+
¸
!
$
·
¸
+
¸
$
¸
6
$
·
"
5
-
+
É
·
¾
¸
¸
"
+
$
6
5
-
+
¸
!
¾
·
¸
5
)
-
Ê
4 u
h
p
¾
¾
¼
¼
)
+
Ý
Ý
Â
u
u
h
¸
´
Á
N
;
P V
>
Þ
I
O
D
U
ß
ÿ
º
Ê
"
-
$
2
¸
!
¸
"
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
)
2
¸
"
Ù
¾
d
Ù
¾
¶ u
h
w
p
$
º
+
¸
!
$
·
¸
+
¸
$
¸
6
$
·
"
5
-
Ç
Ü
Ý
Ý
Â
Ê
¾
5
-
·
F
Q
P
>
5
+
6
$
¼
¼
'
¸
)
$
¼
)
+
5
¸
5
Å
u
u
h
w
h
h
p
5
-
¸
¹
!
p
Ç
Ý
N
;
P V
>
Þ
I
O
D
U
ß
ÿ
º
5
Þ
ß
Ý
N
;
P V
>
Þ
I
O
D
U
ß
Ý
F
Q
P
>
Ê
-
·
Ç
º
»
4
u
u
u
u
h
w
h
w
p
¸
"
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
)
2
¸
"
d
Ù
¾
$
º
+
¸
!
$
·
¸
+
¸
$
¸
6
$
·
"
5
-
Ç
Þ
Ü
ß
Ý
Ý
Â
Ë Ê
1
1
u
u
h
)
¸
"
!
'
»
-
$
6
5
·
2
¾
-
·
¸
5
)
-
+
!
6
$
5
-
¾
-
·
"
$
-
¹
'
Ç
5
Ê
Ê
Ç
Þ
ß
Ñ
¡
£
Þ
Ü
u
¸
´
¥
Á
N
;
P V
>
Þ
I
O
D
U
ß
r
º
5
+
¼
!
)
Å
-
$
-
$
1
)
¹
)
¾
+
1
»
ß
w
h
h
Ê
u
Ê
u
h
d
$
¼
¼
5
-
¹
$
-
w
5
+
+
¸
!
$
5
¹
"
¸
2
)
!
À
$
!
'
¸
)
¼
!
)
Å
Ê
"
¼
!
)
)
2
5
+
º
$
+
'
)
-
¸
"
¸
¶
g
$
+
$
!
º
+
¾
6
¸
¼
¸
"
¸
À
5
+
)
-
$
¸
6
-
"
¹
1
$
Ê
)
¸
d
¸
º
$
1
"
$
¼
¼
$
-
'
$
5
-
'
'
¹
1
!
$
)
·
$
+
+
1
+
$
Å
$
5
!
5
!
+
$
6
6
º
)
1
$
!
+
¼
$
·
¼
-
)
'
6
'
·
¼
)
1
-
1
5
)
·
»
!
$
·
!
¸
)
·
¸
'
-
1
¸
+
5
»
$
)
'
¼
-
!
!
'
)
¸
¸
Å
"
"
Ê
1
Å
.
$
$
¸
¸
1
6
!
¾
¾
+
+
Ê
·
¸
"
)
'
5
6
+
-
¼
¸
¸
5
"
¾
-
¹
¾
¼
5
'
!
+
"
)
)
2
¶
!
1
5
+
)
-
¸
"
2
$
·
¸
¸
"
$
¸
2
)
!
$
1
)
·
$
1
Å
$
!
5
$
º
1
G L
D
U
Þ
¦
ß
5
+
6
$
¼
¼
'
)
-
¸
)
O V
I
;
þ V
v
Q
>
; V
U
U
Q
Þ
¦
ß
Ê
"
+
5
6
¾
1
$
¸
5
)
-
5
+
·
)
!
!
·
¸
5
2
¶
v
Q
>
; V
U
U
Q
Þ
¦
ß
Ý
Q
>
; V
U
U
Q
Þ
¦
ß
v
5
Ê
·
Ê
)
Ç
Q
6
>
¼
; V
5
1
U
U
!
Q
Ç
5
¼
!
+
)
5
¼
-
â
!
¸
·
¸
»
5
Þ
Å
»
2
ß
5
)
!
+
$
Å
¹
v
)
!
»
)
¼
'
!
·
)
$
·
-
'
5
'
¾
'
!
$
¸
¦
2
Ê
)
§
Ý
Þ
L
¾
5
!
»
ß
L
-
¼
·
!
)
Q
¹
!
>
$
;
U
V
6
U
·
Q
"
5
·
+
Ã
·
5
)
-
6
¹
¼
¾
¸
'
º
»
¸
"
Ê
"
-
É
¸
+
¸
¼
5
+
¸
)
¼
!
2
)
!
6
¸
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
+
Ë Ê
2
¸
!
·
)
-
+
¸
!
¾
·
¸
5
-
¹
¸
"
¶
Ù
¾
.
d
Ù
$
Ë
1
¾
+
)
¾
$
1
d
1
+
)
5
À
¸
d
5
Ù
¾
+
æ
¼
5
)
-
+
+
¸
!
+
¾
5
º
·
1
¸
5
¸
)
-
)
+
$
É
+
+
·
¸
¾
$
¸
¸
d
6
Ù
-
¸
¾
æ
+
5
-
+
Ê
¸
"
!
¾
!
·
¸
2
5
)
)
!
-
+
$
À
+
À
-
1
1
'
$
-
+
)
Ù
¸
¸
¾
æ
)
¸
·
$
"
+
$
Ã
-
+
Ê
¹
¶
¸
"
2
)
+
!
¸
6
$
$
¸
¸
5
+
)
-
¼
$
+
2
·
!
)
Ê
Ù
6
-
¸
¼
"
$
!
¸
¸
!
5
$
·
-
¾
+
1
2
$
)
!
!
Ç
6
¸
$
"
¸
5
!
)
-
5
+
+
-
2
)
)
!
-
5
-
¸
'
!
¸
6
)
'
'
5
5
$
¸
+
¸
5
·
-
¹
)
'
¾
5
+
"
¹
)
-
¼
!
¸
$
5
6
¸
5
5
)
t
5
-
-
¹
¸
Ê
)
!
$
À
-
Å
+
æ
!
5
Ç
4
-
¸
!
6
'
5
$
¸
5
-
+
¸
!
¾
·
¸
5
)
-
+
·
"
$
-
¹
5
-
¹
·
)
-
¸
!
)
1
-
'
¸
)
º
·
"
$
-
¹
'
Ç
+
5
-
·
6
u
h
º
¾
¼
'
$
¸
'
Ç
Ê
¹
Ê
¸
"
!
¾
1
2
)
!
·
)
-
'
5
¸
5
)
-
$
1
â
¾
6
¼
+
Þ
·
2
Ê
x
É
$
6
¼
1
»
ß
º
·
)
6
+
¾
+
¸
U
G
R
¡
<
B
R
M
K
M
F
M
O
R
A
U
G
X "
"
Z
n
g
m
u
£
h
g
U
g
G
c
b
Ý
Á
N
j
£
L
>
Q
O
Þ
9
Q
I
Þ
ß
m
ß
>
u
£
c
b
I
>
F
G
O
D
Á
Ý
¤
¥
¦
§
¨
©
ª
«
¬
®
¤
Ý
W
h
O
b
Ë
r
g
m
b
Ë
r
g
m
b
Ë
r
g
m
N
>
Q
¯
O
±
Þ
9
Q
I
Þ
ß
ß
>
u
£
c
b
I
>
F
G
O
D
Á
Ý
¤
²
¬
¦
³
´
µ
«
³
¦
¶
®
§
«
¬
·
¸
®
¹
¤
Ý
W
h
<
>
<
O
N
>
Q
¯
O
±
Þ
9
Q
I
Þ
ß
ß
>
u
£
c
b
I
>
F
G
O
D
Á
Ý
¤
µ
«
µ
®
¬
©
®
§
«
¬
·
¸
®
¹
¤
Ý
W
h
>
N
;
Þ V
9
Q
I
Þ
ß
ß
ÿ
º
u
h
Á
£
c
b
Ý
Ý
; V
> L
F
O
V
F
;
9
Þ
F
Q
P
>
F
;
Q
X
>
F
Þ
ß
u
h
Á
b
Ë
r
b
Ý
; V
> L
F V
O
F
;
9
Þ
7
;
9
>
V
F
;
Q
X
>
F
Þ
ß
u
Ù
¾
-
¹
6
º
-
!
)
!
$
2
ß
u
h
-
ß
u
h
h
1
$
Ç
¼
¸
¼
"
1
5
·
)
'
!
!
!
¾
1
·
¸
+
-
Ê
+
"
+
)
!
2
2
$
)
+
!
5
6
¾
À
1
$
)
¸
-
5
1
)
-
»
5
-
+
'
'
'
¸
¾
)
·
·
)
'
-
º
+
5
»
'
5
-
!
'
+
5
¾
-
·
¹
¸
1
5
)
-
¸
)
!
$
Å
-
+
2
!
¸
)
!
"
6
$
æ
¶
¸
5
)
5
$
-
+
;
$
-
'
<
>
)
ª
V
}
¸
+
¸
¾
.
'
»
¸
È
!
"
+
1
¸
·
)
)
·
-
$
+
1
5
'
!
·
¸
¸
"
+
Á
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
+
5
-
}
5
¹
Ê
B
Ê
B
¸
º
W
¸
1
+
¸
"
5
-
5
æ
u
¸
$
¸
)
2
}
Ç
¸
"
+
¸
$
¸
É
·
¾
¸
5
-
¹
¸
"
¸
$
+
Ã
Ç
«
¸
"
+
¸
$
¸
2
)
!
}
u
u
g
p
;
D
j
$
-
'
¸
"
5
-
5
¸
5
$
1
+
¸
$
¸
)
2
Ê
B
¸
Ü
º
¸
"
+
¸
$
¸
À
"
!
Ü
Ý Ý
u
u
u
h
u
h h
¾
¿
À
Þ
}
Ð
Ð
ß
Ê
.
'
È
-
¸
"
!
1
$
¸
5
)
-
+
¾
·
"
¸
"
$
¸
Ü
)
¸
"
!
À
5
+
v
b
q
q
u
-
'
5
'
-
¸
5
¸
»
u
v
O
y
$
«
d
`
Q
; V
G V
D
F
>
X
>
Q
9
z
¬
^
Á
p
p
Ý
>
N
;
Þ V
}
ß
Ý
z
Ý
N
;
P V
«
>
Þ
I
O
D
U
ß
Ý
z
u
u
u
O
y
b
q
q
d
]
Q
;
U
V
j
V
D
;
<
h
G
I
7
P
D
I
F
G
O
D
9
w
w
Î
>
I
>
F
;
^
D
U
; V
F
>
V
Q
<
9
1
Â
Â
Â
u
W
Á
±
M
G
I
M
U
O
D
O
h
F
I
O
D
F
;
G
D
v
w
w
w
v
v
¬
u
h
¯
p
p
Ý
Î
Þ
1
Â
Â
ß
Ý
Â
°
>
N
;
Þ
V
}
ß
ÿ
º
§
Ý
»
"
1
Þ
¼
)
2
¸
"
+
v
w
w
1
w
Â
v
6
6
$
+
$
-
'
+
¾
º
æ
·
$
+
5
-
¹
À
·
)
-
·
1
¾
'
5
'
-
¸
5
v
¸
¸
´
Á
w
w
»
p
1
Â
ß
Ý
Â
u
Î
«
u
w
)
v
2
+
¸
$
¸
+
Á
p
Ü
Ý
>
N
;
Þ V
}
ß
ÿ
º
Ê
"
«
-
º
»
'
È
-
5
¸
5
)
-
)
2
Ç
Ý
>
N
;
Þ V
}
¶
u
ß
ÿ
º
Ê
«
u
p
B
6
6
$
5
6
¼
1
5
+
¸
"
$
¸
Ý
Ý
Â
n
°
N
;
P V
}
>
Þ
I
u
O
D
U
ß
ÿ
º
Ê
»
¸
"
u
u
h
g
h
w
p
+
¸
$
¸
¸
!
$
-
+
5
¸
5
)
-
+
2
)
!
Ý
Ý
Â
Ê
}
¾
!
¸
"
!
6
)
!
2
!
)
6
1
6
6
$
»
À
} u
u
g
Ã
-
)
h
w
h
h
À
p
p
Ý
Î
Þ
1
Â
Â
ß
Ý
Â
°
>
N
;
Þ
V
}
ß
ÿ
º
§
Ý
Î
Þ
1
Â
Â
ß
Ý
Â
«
u
u
v
w
w
w
v
v
w
w
w
v
p
¾
-
'
!
¸
"
$
+
+
¾
6
¼
¸
5
)
-
+
)
2
¸
"
1
6
6
$
Ê
B
¸
Ü
º
¸
"
+
¸
$
¸
$
2
¸
!
Ü
Ê
"
-
Ü
Ý
¶
u
u
u
Ý
F
;
9
F
O
; V
Þ L
Ð
ß
Ý
Â
"
)
1
'
+
Ê
}
¾
!
¸
"
!
6
)
!
Ç
5
¸
5
+
$
+
»
¸
)
+
¸
"
$
¸
u
h
w
Ü
h
h
p
p
Ý
Î
Þ
Â
1 Â
ß
Ý
Â
°
>
N
;
Þ V
}
ß
ÿ
º
§
Ý
-
'
!
¸
Þ
Â
1 Â
ß
Ý
Â
u
¾
Î
«
u
"
$
+
+
¾
v
6
w
w
¼
¸
w
5
v
)
-
+
)
2
1
6
6
$
»
Ê
»
'
È
-
5
¸
5
)
-
)
2
5
¸
"
)
1
v
'
w
w
w
v
+
Ü p
p
Ý
Î
Þ
Â
Â
1
ß
Ý
Â
°
>
N
; V
Þ
}
ß
ÿ
º
Ý
-
·
Þ
Â
Â
1
ß
Ý
Â
u
Î
«
u
Ü
Ý
v
w
w
w
v
v
w
w
w
v
w
Ê
4
u
u
p
¸
´
¥
Á
Ü
Ý
>
N
;
Þ V
}
ß
r
º
5
+
¼
!
)
Å
-
$
-
$
1
)
¹
)
¾
+
1
»
Ê
«
u
á
)
-
+
5
'
!
-
)
À
¸
"
¼
!
)
)
2
2
)
!
¸
"
$
+
+
5
¹
-
6
-
¸
Ç
}
5
¹
º
Ê
B
¸
º
¸
"
5
-
5
¸
5
$
1
+
¸
$
¸
+
¸
$
¸
u
)
2
ú
Ç
¸
}
"
5
-
5
¸
5
$
1
+
¸
$
¸
)
2
}
Ç
¸
"
+
¸
$
¸
2
)
!
Â
n
Ç
u
u
¸
«
u
g
"
"
"
$
"
2
&
¸
!
Â
$
-
M &
'
M
X
Ü
<
¸
"
K
+
¸
$
¸
'
R
O
É
O
U
·
¾
G
¸
5
O
<
-
K
¹
K
¸
"
æ
5
-
+
¸
!
¾
·
¸
5
)
-
Ê
.
'
È
-
+
u
Ü
$
u
-
'
¸
"
!
À
5
+
5
'
-
¸
5
Ü B
¾
·
"
¸
"
$
¸
)
¸
»
)
-
$
1
1
'
»
-
$
6
5
·
2
¾
-
·
¸
5
)
-
+
É
·
¼
¸
N
;
P
>
V
$
-
'
;
U
U
Q
Ê
u
Ü
¸
º
¸
"
+
¸
$
¸
$
2
¸
Ü
!
Ê
u
.
"
$
Å
¸
)
+
"
)
À
¸
"
$
¸
Ý
u
u
É
·
¼
¸
2
)
!
N
;
P V
>
$
-
'
u
;
U
U
Q
Ê
.
+
¸
$
!
¸
À
5
¸
"
¸
"
2
)
1
1
)
À
5
-
¹
1
6
6
$
+
Á
p
O
y
b
q
q
d
Ú
Q
;
;
V
U
V
U
Q
>
9
9
>
9
p
¬
Ý
>
N
;
Þ V
ú
ß
Ý
§
Ý
u
M
>
Q
>
Â
G
9
F
b
q
q
U
U
Q
Þ
Â
ß
Ý
u
M
>
; V
9
d
6
F
F
;
9
O
7
ú
}
O
y
;
}
^
Á
±
Q
;
G
V
V
D
F
>
X
>
Q
N
;
P
>
V
9
z
¬
^
Á
p
p
Ý
>
N
;
Þ
V
}
ß
Ý
z
§
Ý
N
;
P V
«
>
Þ
9
Q
I
ß
Ý
z
u
u
u
G
y
b
q
q
d
F
D
F
>
Q
Q
>
F
9
;
U
V
j
V
D
;
<
G
I
7
P
h
D
I
F
G
O
D
9
;
9
w
>
w
I
>
F
;
^
W
u
q
q
d
[
D
F
>
Q
Q
>
F
9
;
U
V
j
V
D
;
<
G
I
7
P
D
I
F
G
O
D
9
;
9
>
!
+
5
6
¼
1
5
U
U
Q
I
>
F
;
D
U
N
;
P V
>
u
W
u
W
)
^
u
}
;
h
G
b
U
W
y
D
u
u
·
5
¸
»
À
)
6
5
¸
)
Å
!
*
)
À
+
Ê
"
+
¸
$
¸
¸
!
$
-
+
5
¸
5
h
)
-
2
)
!
+
"
)
À
+
¸
"
$
¸
¶
p
Ü
!
6
$
5
-
+
¾
-
·
"
$
-
¹
'
À
Ê
!
Ê
¸
Ê
Ü
u
É
·
¼
¸
¸
"
$
¸
-
)
À
Ü
u
Ý
I
O
D
F
>
D
F
Þ
ß
Ý
z
À
"
!
u
p
Ü
Ý
>
N
;
Þ V
ú
ß
Ý
°
>
N
;
Þ V
}
}
ß
Ý
z
Ê
}
!
)
6
¸
"
$
º
)
Å
1
6
6
$
+
$
-
'
¸
"
+
¸
$
¸
«
u
¸
!
$
-
+
5
¸
5
)
-
+
2
)
!
¸
"
+
$
6
2
)
1
1
)
À
+
2
)
!
Ê
-
·
Ç
Ü
Ê
4
u
g
u
u
"
¹
!
$
¼
"
æ
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
+
!
+
¾
1
¸
5
-
$
+
¸
)
2
'
5
!
·
¸
'
¼
$
¸
"
+
À
"
!
É
$
·
¸
1
»
¸
"
¶
È
!
+
¸
¸
$
+
Ã
5
+
1
$
º
1
'
Ê
x
$
·
"
)
2
¸
"
+
¼
$
¸
"
+
!
¼
!
+
-
¸
$
º
$
+
5
·
º
1
)
·
Ã
Ê
"
!
2
)
!
Ç
5
¸
5
+
¶
+
¸
!
$
5
¹
"
¸
2
)
!
À
$
!
'
¸
)
6
$
¼
¸
)
¸
"
¼
$
5
!
Þ
u
h
$
¹
-
Â
!
)
$
1
À
À
æ
æ
·
+
5
)
6
-
¾
+
5
1
'
$
¸
5
!
)
¸
-
"
Ë
ß
Ê
¹
$
5
-
Ç
5
¸
5
+
-
)
¸
"
$
!
'
¸
)
¼
!
)
Å
u
v
g
Ê
º
$
+
5
·
º
1
)
·
Ã
1
$
-
¹
¾
$
¹
û
Ê
}
)
!
·
)
-
+
¸
!
¾
·
¸
5
-
¹
º
$
+
5
·
æ
º
1
)
·
Ã
g
¹
!
$
¼
"
+
À
5
¸
"
R
x
á
Ë æ
1
¼
"
$
·
)
6
6
$
-
'
+
Ç
À
È
!
+
¸
6
$
¼
¸
"
¼
)
5
-
¸
!
+
O
I
V
;
$ V
-
'
F
O
O
7
M
>
;
W
¸
)
!
¹
5
+
¸
!
+
Ã
º
$
-
'
Ã
Þ
$
+
¼
!
)
¼
)
+
'
º
»
¸
"
R
x
á
Ë æ
1
¼
"
$
æ
d
$
-
¾
$
1
ß
Ê
W
"
º
$
+
5
·
¶
$
¼
2
¼
)
!
!
)
5
$
-
·
¸
"
!
2
)
6
!
¼
'
5
!
$
)
¸
Å
5
-
·
¹
)
¸
'
"
·
¹
)
-
!
!
!
$
·
¸
¸
5
-
)
-
+
+
)
Ê
2
)
¸
À
"
Å
·
!
)
'
Ç
¸
"
¹
!
-
$
!
!
$
¸
5
+
)
)
-
5
6
+
+
¼
5
!
6
5
)
º
1
1
$
!
¸
6
)
¸
+
À
"
5
¸
)
"
¸
-
"
4
'
·
)
;
6
¼
<
)
5
> V
}
+
¸
µ
5
)
-
¸
á
)
)
1
-
+
5
)
·
'
$
1
!
·
¸
)
"
!
!
2
)
·
1
¸
1
-
)
+
À
5
+
-
·
¹
)
5
-
-
'
+
5
¸
¸
!
5
¾
)
-
·
¸
+
5
Ê
)
-
)
2
$
º
$
+
5
·
º
1
)
·
Ã
Á
W
Þ
¶
¶
Þ
ß
·
¸
Þ
Þ
¶
¶
Þ
ß
ß
v
$
-
'
¸
"
¸
!
6
æ
!
À
!
5
¸
!
¾
1
Þ
¶
¶
Þ
ß
ß
ß
ß
+
v
Á
È
Þ
¶
¶
Þ
G
D
F
I
O
D
9
F
ß
ß
Ñ
¹
Ç
»
¹
Þ
Ã
º
ß
Þ
Ù
ß
Þ
ß
Þ
E
ß
ý
È
·
¸
Þ
¹
ß
v
Ñ
¾
Ç
À
»
»
¹
¾
½
½
È
Þ
¶
¶
Þ
G
D
F
I
O
D
9
F
ß
¹
ý
"
-
)
-
¸
!
6
5
-
$
1
+
¹
Ç
Ç
¾
+
¸
$
-
'
2
ß
Ñ
Ã
Ç
Å
Þ
Ã
º
ß
v
)
!
$
!
º
5
¸
!
$
!
»
!
¹
5
+
¸
!
+
Ê
Ù
¸
5
+
-
)
¸
"
$
!
'
¸
)
+
¶
½
¸
"
$
¸
¸
"
!
¾
1
+
$
!
1
)
·
$
1
1
»
·
)
!
!
·
¸
Ê
¾
¾
¼
¼
)
+
À
$
¼
¼
1
»
¸
"
!
¾
1
+
5
-
¸
"
2
)
1
1
)
À
5
-
¹
)
!
'
!
À
5
¸
"
¸
"
2
)
1
1
)
À
Þ
Ù
ß
)
-
Þ
¶
¶
Þ
Þ
Ù
ß
)
-
Þ
¶
¶
Þ
Þ
ß
)
-
5
-
¹
ß
!
¹
5
+
¸
ß
!
¹
»
5
1
$
Æ
'
+
Ã
+
+
5
¹
-
6
-
¸
+
U
G
R
¡
<
B
R
M
K
M
ß
ß
M
O
R
A
U
G
X "
¹
Æ
Ã
»
Þ
¹
Æ
Ã
»
»
¸
Þ
Ã
»
Ã
»
ß
Á
¶
¶
Þ
ß
·
¸
Þ
Ã
»
5
1
'
+
Þ
¶
¶
Þ
Æ
v
Ã
»
¾
Æ
Ã
ß
ß
ß
ß
v
Þ
¶
¶
Þ
ß
·
¸
Þ
Ã
»
Ã
v
·
"
»
v
F
»
ß
ß
v
»
½
»
5
1
'
+
Þ
¶
¶
Þ
ß
Ã
»
ß
v
Þ
E
ß
)
-
Þ
¶
¶
Þ
ß
Ã
»
ß
¹
Æ
Ã
»
v
"
-
¸
"
2
)
1
1
)
À
5
-
¹
·
)
'
5
+
¼
!
)
'
¾
·
'
Á
¶
»
Ã
»
»
Ã
»
À
»
»
Ã
Å
"
Þ
Þ
+
·
º
Þ
»
5
Ã
º
Ã
Ã
'
ß
»
º
)
ß
Ã
Ã
ß
»
Ã
5
»
+
)
º
Å
5
)
¾
+
1
»
À
!
)
-
¹
Á
$
Å
$
1
¾
5
+
À
!
5
¸
¸
-
¸
)
Ã
»
$
1
¸
"
)
¾
¹
"
Ã
»
·
)
-
¸
$
5
-
+
$
¶
Å
$
¸
1
"
¾
5
À
+
+
5
"
¸
5
¾
·
$
"
¸
5
5
)
+
+
-
¸
5
Ê
1
"
1
!
+
½
¾
·
5
)
!
-
'
'
Ê
5
¸
5
Ù
)
-
-
+
E
»
·
$
+
-
¾
º
·
·
5
"
-
·
¸
·
Ã
)
-
'
'
$
5
¸
¸
·
5
)
)
-
+
6
$
¼
5
1
!
æ
¹
¸
5
5
6
Å
-
2
)
!
$
Å
)
5
'
5
-
¹
Ê
¶
Ë
Ë 1
¼
2
"
¸
!
$
5
$
-
¼
+
¼
¸
!
1
¾
»
·
5
¸
-
5
¹
)
¸
-
+
!
6
æ
Ê
"
!
+
À
!
5
5
¸
-
5
+
-
¹
¸
!
Ç
¾
¸
·
"
¸
5
)
!
-
+
+
¾
·
1
$
¸
5
-
+
$
$
1
!
º
$
$
'
+
5
»
·
æ
º
º
1
)
·
º
5
Ã
-
¹
$
!
!
$
¼
»
"
-
À
·
5
)
'
¸
"
R
'
x
É
á
·
æ
¼
¸
¶
â
¾
6
¼
5
-
+
¸
!
¾
·
¸
5
)
-
+
Ê
"
$
+
+
6
º
1
»
¼
"
$
+
+
¸
)
!
+
¸
"
¼
!
)
¹
!
$
6
5
-
¸
)
¸
"
6
6
)
!
»
$
-
'
¶
-
·
)
'
+
â
¾
6
¼
5
-
+
¸
!
¾
·
¸
5
)
-
+
Þ
+
"
)
!
¸
â
¾
6
¼
+
Ç
1
)
-
¹
â
¾
6
¼
+
Ç
)
!
!
6
)
Å
$
1
)
2
â
¾
6
¼
+
ß
Ê
"
¶
+
5
6
¾
1
$
Ù
¸
2
5
¸
·
)
-
"
'
¼
5
!
È
-
!
¹
+
º
¸
"
¸
"
)
)
¸
1
5
)
1
2
-
·
$
!
+
Ã
+
½
¸
!
+
¸
¾
¾
-
+
+
!
·
¦
5
5
¸
¸
$
!
+
5
¸
)
5
¾
¸
-
+
·
"
)
2
¸
$
)
º
-
-
"
$
)
)
¸
2
»
5
¸
$
)
2
2
+
5
2
¦
¸
5
)
1
·
)
À
º
"
+
1
1
'
2
5
!
5
)
·
)
-
1
¸
·
Ã
1
·
¹
+
)
1
¸
À
-
$
5
»
)
!
-
º
'
¸
2
!
!
5
)
$
¼
)
¸
+
¹
5
-
¸
)
$
¼
5
+
'
+
'
!
¸
$
!
5
¸
5
+
+
+
È
+
'
Ç
Á
¸
"
-
$
1
1
¼
!
æ
Á
9
1
$
+
¸
5
-
+
¸
!
¾
·
¸
5
)
-
5
+
$
¸
$
'
'
!
+
+
Ü
$
-
'
¸
"
·
)
6
6
$
-
'
5
+
$
â
¾
6
¼
À
5
¸
"
9
!
¸
1
$
"
¸
5
1
Å
$
+
$
¸
'
5
'
-
!
+
¸
!
+
¾
+
·
¸
5
É
)
-
5
Ü
+
$
¸
$
'
'
!
+
+
Ü
$
-
'
¸
"
·
)
6
6
$
-
'
5
+
$
â
¾
6
¼
¾
+
5
-
¹
9
$
}
Ë ¹
Ù
[
¾
$
^
5
!
¸
-
¼
1
"
Ê
6
"
¸
]
!
5
¹
!
)
Ë
-
¸
¸
)
·
U
6
+
6
+
q
5
!
¸
5
)
1
¸
b
5
)
$
'
q
$
·
-
b
!
5
5
-
£
+
¸
1
)
Ý
-
-
+
g
¸
-
5
¸
·
£
2
5
-
+
d
)
$
!
!
·
-
¸
5
º
Ý
¹
¾
$
i
-
-
!
£
+
·
m
æ
)
i
6
Ê
"
c
À
)
·
5
$
Ã
b
!
2
Û
¸
º
'
+
¸
·
¸
U
+
5
5
q
»
+
À
i
$
"
g
1
¸
Ë
6
º
b
·
"
$
$
$
H
·
Ã
l
+
)
¼
U
-
¼
b
º
!
!
Ü
g
6
)
$
L
·
·
Ü
)
$
g
·
)
£
¸
¼
"
d
+
¼
2
i
)
'
·
¼
!
)
)
-
¹
+
!
$
·
¾
¸
6
5
·
Å
"
1
·
»
Ê
Ã
5
-
¹
Ê
Ý
-
¸
!
)
1
1
'
Ê
"
»
¾
+
·
)
6
æ
¶
¼
1
+
»
!
É
+
$
¸
1
¹
)
6
!
5
¸
"
Ë
6
¼
+
!
)
$
º
-
1
'
"
6
+
¾
$
!
!
5
+
5
¸
5
·
-
+
Ç
º
Â
·
$
Ë Ê
¾
'
+
'
5
Ë
¸
5
'
)
-
$
1
1
¼
»
Ç
-
2
'
)
5
!
-
¹
)
$
¼
-
!
¸
$
·
¸
"
5
·
·
$
1
1
$
+
·
+
)
)
6
2
¸
¼
5
1
"
!
!
À
À
!
-
5
¸
'
¿
¸
"
¸
5
¹
5
+
¸
¹
)
-
!
+
$
-
1
Ê
!
1
)
$
"
·
¸
$
)
¸
)
!
º
!
¸
$
·
+
"
$
Ã
$
æ
-
¸
'
¼
-
5
!
'
)
¸
-
+
'
)
¸
¾
)
!
·
¾
1
·
¸
+
¸
x
5
)
"
-
+
·
Ç
·
"
)
'
'
¾
Ç
+
¹
1
1
-
!
+
·
!
¸
À
$
)
"
5
¸
!
5
+
·
"
6
¸
$
¼
"
1
!
¾
6
·
)
+
-
'
¾
¸
$
$
+
1
¸
5
1
1
»
)
5
-
-
·
¸
2
¸
)
!
)
!
¹
!
$
2
6
¸
!
+
)
¼
'
6
5
·
$
5
+
-
¸
È
)
·
$
æ
¸
)
¸
2
¶
!
6
"
æ
5
!
À
6
!
¼
1
5
¸
6
!
-
¾
1
¸
$
+
¸
$
5
)
-
-
-
)
·
)
¸
$
-
¸
+
5
+
'
¸
À
+
5
)
¸
"
2
·
$
)
¸
!
+
¸
+
$
¼
-
$
'
¸
6
¸
$
!
¼
-
¼
6
5
$
-
¹
¸
·
+
¸
"
)
¼
¸
"
$
$
+
!
¹
Ç
¸
¸
6
"
$
$
¸
·
È
"
-
5
'
-
·
+
)
$
'
·
)
Ê
+
¸
¶
5
$
6
1
1
-
)
5
·
6
$
$
¸
1
5
)
·
-
)
Å
$
-
!
'
)
·
2
)
¸
'
"
¼
6
)
5
!
¸
¹
¸
!
5
-
$
6
¹
¸
¸
!
!
$
Å
À
!
+
Ê
$
1
!
+
Ê
¸
$
Ê
¸
!
"
5
-
!
5
¸
5
À
$
!
¸
5
'
¸
Ê
!
Ù
¾
¸
1
5
+
+
Ë Ê
¼
!
$
2
·
¸
¸
5
!
·
À
$
$
1
1
!
»
'
+
5
6
!
¼
)
¹
5
+
+
+
¸
5
º
!
1
"
"
¸
Ä
&
)
Å
Å
!
¹
-
5
!
2
5
»
2
5
»
¸
-
"
¹
"
·
M
¸
M &
X
¹
"
)
+
1
¼
K
-
!
6
<
!
$
¾
1
¸
¸
¸
'
+
2
)
R
O
á
)
·
'
æ
¸
'
O
·
"
U
)
'
+
1
5
K
Ã
¸
K
.
·
·
<
Ê
$
O
º
G
æ
)
$
-
Å
'
-
)
5
'
¸
"
5
+
º
»
$
¼
¼
1
»
5
-
¹
¼
!
)
¹
!
$
6
·
"
·
Ã
5
-
¹
2
)
!
Ê
¼
$
!
¸
À
5
¸
"
!
¹
5
+
¸
!
$
1
1
)
·
$
¸
5
)
-
$
-
'
+
·
"
'
¾
1
5
-
¹
¶
!
$
¸
'
º
»
¸
"
º
$
·
Ã
æ
-
'
·
$
-
º
-
·
$
¼
+
¾
1
$
¸
'
2
)
!
·
"
·
Ã
5
-
¹
Ê
"
·
)
!
!
·
¸
-
+
+
¶
!
¸
½
¾
"
º
!
$
$
+
!
5
Ë Þ
5
·
·
æ
6
"
5
º
1
-
¸
)
ß
+
·
·
¸
¸
¸
Ã
)
¾
æ
º
!
¹
!
)
$
¼
·
2
"
¸
"
"
Þ
·
Ã
·
"
'
$
·
ß
Ã
Ç
!
)
'
'
¾
º
¸
¼
!
$
¾
5
·
Å
Ã
¸
5
æ
+
'
2
-
$
!
'
-
)
Ê
$
6
Ù
-
¹
-
¼
-
1
¾
)
¸
)
¸
º
$
¸
¸
$
1
)
¸
'
·
"
¹
)
-
!
'
$
¼
5
¸
x
"
5
)
-
À
+
¹
5
¸
Ê
"
}
-
!
5
!
¹
$
À
¾
¸
!
5
!
¸
'
5
¼
-
Ù
$
¹
+
!
$
¸
"
¸
¸
)
5
!
5
À
+
+
¸
º
"
¾
¸
+
Ê
Code Select. Specification
BEG (generates)
Code Selection
BBG MIS
ABBG
ABBG Checker
Register Allocation
DECAlpha
Transformation
Instr. Schedul.
Check-Error!
Ë !
·
"
5
¸
·
¸
¾
!
·
"
·
Ã
'
º
$
·
Ã
æ
-
'
g
"
·
"
·
Ã
!
¼
$
+
+
p
^
+
`
¸
Ú
"
^
·
)
-
·
!
Ë
¸
$
¸
!
¾
-
¸
5
6
¸
)
¸
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
¶
¼
"
+
$
+
½
$
¾
!
+
·
)
-
¸
"
!
·
"
!
¾
}
1
5
¹
¸
¸
5
¸
1
5
¸
+
Í
¹
¸
"
Í
)
!
Þ
·
Ã
5
Ñ
1
º
¹
·
+
$
¸
À
"
$
'
$
¸
Í
5
¹
)
Ñ
"
È
+
'
¸
$
Ë
-
Ê
!
1
$
¸
-
1
¸
»
!
¼
'
5
º
$
¾
!
¸
-
2
)
)
!
+
!
6
¼
'
+
!
!
"
Ë
¸
-
¾
!
6
À
!
º
-
!
5
5
¸
)
-
¸
'
"
Ê
2
Ð
·
)
5
'
-
Ð
5
·
¸
Ó
"
ß
!
¾
$
¼
1
¾
¹
1
$
$
¸
Å
5
+
Ë æ
)
-
+
á
1
¸
Ð
x
$
+
Ï
6
R
¾
"
!
¸
6
·
!
Ç
!
'
"
-
$
!
¸
$
¸
¼
¸
"
¼
"
·
·
¸
"
$
¸
¼
À
5
+
"
À
¸
º
·
'
¸
5
5
5
6
"
Í
+
)
À
¶
¸
-
¶
·
'
1
5
!
â
-
¾
¾
$
'
!
)
!
¸
"
d
Ù
Í
¾
Ô
Ð
É
¼
!
+
+
5
)
-
Ð
$
!
5
+
5
-
¹
2
!
)
6
¸
"
+
)
¾
!
·
1
$
-
¹
¾
$
¹
¸
!
6
Þ
Ï
Õ
Ó
Ô
ß
Ë Ê
¸
»
¼
5
·
$
1
+
¸
)
2
·
)
'
+
1
·
¸
5
)
-
½
!
¾
1
$
'
+
'
5
5
¸
5
-
·
)
1
-
¾
'
$
1
1
+
»
$
)
¸
¼
¸
1
5
$
6
5
+
t
¸
5
)
-
-
¹
!
!
¾
1
¾
1
+
2
)
!
Å
!
»
5
-
¸
!
6
'
5
$
¸
1
$
-
¹
¾
$
¹
·
)
-
+
¸
!
¾
·
¸
$
-
'
Á
È
¦ Ö
Å
Ø
Ù
Å
Ø
Ù
À
Å
Ø
Ù
Å
Ø
Ù
À
Å
Ø
Ù
¶
¶
Þ
¹
ß
v
Ñ
¾
Ç
À
»
»
Ú
¹
Ú
¹
¾
½
v
½
v
È
Ö
Ö
Ö
¦
Ö
¸
·
Þ
¹
ß
v
Ñ
¾
Ç
Ü
Ç
Ç
Ü
Ø
¾
½
v
½
v
È
¦ Ö
Ô
Ñ
¹
»
À
¹
Ô
v
Þ
ß
©
ß
Þ
È
Ö
¦ à
¸
·
Þ
Ô
¹
ß
Ñ
v
Ø
Ú
¹
Ú
¹
Ô
½
v
Þ
v
Þ
v
½
v
½
È
¦ à
¶
¶
Þ
¹
Ô
ß
Ñ
Ç
v
"
¼
$
!
-
¸
"
+
5
t
'
À
»
»
Ô
½
!
5
¹
"
¸
·
)
1
¾
6
-
·
)
-
+
5
+
¸
+
)
2
·
)
-
·
!
¸
R
x
á
Ë æ
1
¼
"
$
6
$
·
"
5
-
5
-
æ
¶
+
¸
¸
!
¾
"
·
1
¸
5
2
)
-
¸
+
"
5
$
6
-
¼
'
1
+
5
6
'
-
¸
Ê
5
-
"
¹
¸
¼
"
)
¸
+
-
¸
6
5
$
$
-
1
)
¸
5
¼
·
¸
5
+
)
6
5
2
t
¸
$
"
¸
5
)
5
-
-
¸
+
$
!
!
6
5
+
'
2
5
!
$
)
¸
1
6
¸
$
-
"
¹
¾
'
$
5
¹
¼
!
$
-
¸
¸
¸
¼
!
)
+
-
)
+
5
-
º
5
1
æ
¶
5
¸
5
)
¾
+
¸
!
¸
!
)
É
·
$
+
)
6
Å
Ê
¼
æ
1
!
Ê
¸
¸
Ê
"
"
¸
·
$
-
)
!
'
'
Ç
$
+
æ
Ê
1
1
1
»
)
5
·
2
¸
-
5
+
¸
)
¸
"
-
$
¼
$
1
'
)
¹
+
)
)
!
2
+
$
5
5
¸
º
1
"
¼
·
6
¼
1
'
)
»
5
-
Å
¹
·
5
!
¸
'
+
"
$
!
'
¸
+
5
·
)
)
$
6
!
¼
¼
1
!
¼
1
!
·
!
»
¸
¸
!
¾
¾
1
!
1
$
-
+
+
+
á
á
2
æ
)
â
á
!
$
6
á
á
$
-
'
¸
5
â
Ù
-
)
-
¸
¸
)
"
ã
5
1 ©
[
R
X
U
ä
G
U
X
X
R
M
K
M
@
A
M
F
M
@
G
X
U
U
F
M
A
U
U
@
X
U
B
[
R
X
U
ä
<
O
A
U
F
M
G
X
R
O
A
R
R
B
ª
+
Ê
+
+
Ù
¾
·
-
º
$
æ
+
U
G
R
¡
<
B
R
M
K
M
F
M
O
R
A
U
G
X "
"
Í
Basic-Block-Graph
P1
Schedule
1
1
+ 1.1
1.2 c
* 1.1.1 c
1.1
+
1.1.2 c
1.1.1
1.1.2
Register á
"
·
Ã
5
-
¹
$
¸
¸
!
5
º
¾
¸
1.1.2 1.2 1.1.1 1.1 1
1.2
'
º
$
+
5
Rule
·
æ
º
1
)
·
Ã
æ
¹
!
$
¼
"
+
g
º
»
¸
"
5
+
'
·
5
+
5
)
-
2
p
^
`
À
6
^
!
5
-
+
¸
!
¾
·
¸
5
)
-
+
$
!
6
5
¸
¸
'
Ê
"
'
·
5
+
5
)
-
6
5
¹
"
¸
º
º
$
+
'
)
-
¶
·
)
º
6
¼
¾
¸
1
¸
"
5
¸
"
É
+
5
¼
·
+
!
)
'
)
+
·
¸
6
¼
+
-
+
5
'
$
+
+
+
¾
)
-
!
-
)
6
¸
¸
5
"
-
-
¸
·
¸
"
+
)
¸
-
"
·
+
$
·
!
¸
)
¸
¸
¼
$
Ã
º
$
)
5
·
2
Ã
)
-
æ
+
¾
¸
-
!
¾
'
·
!
¸
¹
À
)
5
!
)
-
Ã
-
+
!
$
Ê
·
¸
"
"
)
!
'
·
¾
¼
"
1
!
5
)
·
-
¹
Å
Ã
5
·
-
)
¹
!
+
¸
·
"
¸
"
+
5
·
-
)
Ã
¸
¼
)
+
¸
À
$
5
·
"
6
$
·
¸
)
1
"
5
¾
¸
-
¸
»
!
)
¸
2
"
¶
1
!
2
¸
¹
"
5
$
+
-
¸
'
+
!
À
5
!
'
5
¸
)
¸
2
$
-
'
!
)
¾
1
+
6
-
)
$
¸
¸
·
·
)
"
-
¸
+
$
5
¸
"
-
·
$
Å
)
$
!
1
!
¾
+
¼
)
À
"
-
5
'
·
5
-
"
5
¹
+
+
!
¾
º
$
¸
!
'
1
$
Ç
¸
$
!
-
'
Ê
À
"
"
1
$
¸
¸
"
¸
!
!
·
Å
$
!
-
»
º
¶
·
"
·
Ã
'
¾
+
5
-
¹
¸
"
!
¹
5
+
¸
!
$
+
+
5
¹
-
6
-
¸
$
-
'
¸
"
+
·
"
'
¾
1
Ê
å
M
é
Ù U &
K
U
G
<
B
M
G
ç
U &
ê
K
U
<
B
U
O
A
å
M
@
I
R
@
K
U
A
<
æ
<
A
<
M
M
U
Ù
Í
Z
7
U
A
U
B
R
M
U
>
U
Ü
G
<
B
[
U
G
á @
X
B
G
R
<
+
$
2
¾
)
!
º
d
5
â
Ê
6
·
¸
¼
Ë
æ
ì
b
1
)
`
!
ç
ª
B
R
K
<
G
U
ª
ç
è
ª
B
G
M
U
#
#
#
#
#
å "
ç
Z
å
ç
Z
Ä
#
Y #
ç Í
#
#
"
#
#
Y
ç
#
Y
ç
Ü è
#
ë
<
6
5
G
X
U
G
Ù
Y
#
Ü
#
[
U
>
Ù
U
#
G
å
#
Ü
I
A
í
;
B
M
Y
K
Ä
ç
#
ë
K
G
X
Ù
I
U
U
Í
[
[
I
B
Ü å
&
G
-
-
©
+
)
2
G
¼
Z
!
)
¹
!
$
6
·
Ä
#
)
'
#
#
#
¸
)
Å
!
5
2
»
2
)
å Ä
!
É
ç
$
6
¼
1
º
$
·
å
Ã
Í
æ
ç
-
'
^
5
î
-
¸
¸
$
'
¸
5
1
$
)
-
-
1
¹
¾
$
-
$
¹
¹
¾
$
Ç
¹
»
Ù
2
)
!
Ê
¸
" ¶
"
·
·
)
"
'
·
¹
Ã
-
!
5
!
+
$
¾
¸
$
)
!
¸
"
¹
!
-
æ
ä
!
Ç
$
¸
$
)
-
!
6
)
x
'
!
¼
-
!
¸
)
'
»
¼
¾
·
æ
+
"
"
$
á
Ù
&
5
E
Ê
º
6
¼
º
º
1
1
5
M
M
&
6
-
X
-
+
<
¸
)
$
K
2
¸
5
d
)
-
)
'
À
'
¾
5
1
$
R
¸
æ
O
O
"
U
»
·
G
)
Ê
'
O
º
<
º
K
K
º
1
Ê
$
5
-
º
1
+
)
2
·
·
)
)
'
6
¼
$
Ç
!
¸
"
+
1
¹
5
-
-
+
)
!
$
2
·
¸
)
)
!
'
¸
)
$
)
-
1
5
'
+
¼
À
!
)
!
¹
5
!
¸
$
¸
-
6
5
+
5
-
t
+
¶
2
)
!
¼
!
º
$
)
)
¾
¹
!
·
!
Ã
$
æ
|
É
»
-
'
1
·
Ã
5
¸
-
"
¹
Ê
!
»
º
1
$
¸
·
5
)
)
-
-
)
¸
$
5
2
-
+
¸
)
6
)
!
E
5
'
-
1
¸
5
$
-
5
1
+
+
¸
)
)
-
Å
$
!
¼
5
!
2
)
»
¹
+
!
"
$
)
À
6
+
·
¸
"
"
·
Ã
¾
+
!
2
2
)
¾
1
!
·
-
)
+
6
+
)
¼
5
1
2
!
Ê
1
Ê
¼
"
+
$
|
6
·
Ç
$
6
.
+
}
)
)
$
!
¼
'
¼
1
¸
5
$
5
1
'
)
+
Ç
¾
À
!
$
!
¼
2
¼
!
!
)
¸
$
·
)
"
»
¸
)
$
Ê
·
$
º
)
1
6
¼
»
5
+
1
"
!
)
2
À
!
)
+
¸
-
¸
"
æ
!
-
'
+
2
¾
1
)
¸
!
+
$
á
+
¾
º
+
¸
Ù
¾
Ç
Ê
¶
é
U
K
&
U
G
<
B
M
G
U &
X
K
U
G
ï
<
B
U
Y
©
I
M
é
R
Z
æ
K
U
Z
#
<
B
[
U
G
Y
ç
X
#
ç
#
ª
#
"
B
R
K
<
U
ª
è
ç
å
ç
Ä
G
ª
Z
G
B
M
U
å
ç
"
U
"
"
#
#
#
Y
#
#
ç
#
#
"
#
#
Y
ç
Y
ç
I
O
A
I
;
G
M
K
B
U
K
Ù Í
Ù
[
U
>
U
Ü
G
<
B
[
U
G
Ü è
#
<
#
ë Z
#
B
Ê
Ë
ð
b
]
5
-
+
)
2
¼
!
)
¹
!
$
6
·
)
U
G
'
M
O
Ù
¸
#
<
Å
G
ç
Ä
U
©
!
5
2
Y
ç
Ü
#
)
Y
Z
Ü
#
,
d
X
Ù
Y
ë
M
G
»
2
)
!
$
¼
!
Y #
)
¹
!
ç
$
6
æ
·
"
·
Ã
'
Ù
¾
2
!
)
-
¸
æ
-
'
^
ñ +
á
)
¸
5
!
)
!
·
-
8
¸
)
!
-
2
¯
$
+
!
+
²
+
5
¸
)
ò
"
2
·
6
±
)
6
¸
5
°
¼
·
G
5
1
É
!
¼
+
!
À
+
$
+
5
+
)
È
-
!
+
+
¸
·
Ê
"
)
-
!
+
5
$
'
2
¸
!
'
!
5
6
)
-
+
¸
Ù
»
¼
º
)
¾
¼
1
¸
2
)
·
É
¾
¼
+
1
)
!
'
)
-
'
¸
¸
"
"
·
¼
)
)
¸
6
¼
-
¸
5
5
$
1
$
æ
1
)
2
¶
'
-
E
)
Ç
6
|
Ç
)
+
+
"
1
+
Ç
$
1
E
Ç
Ê
2
Ç
+
º
6
$
Ê
"
'
+
»
¹
¸
+
-
Ç
-
)
)
¹
-
5
¸
5
5
¸
Ç
)
·
$
B
'
d
'
¸
Ù
Ç
¼
¸
!
-
Ù
+
$
Ù
·
Ç
¸
"
·
6
+
¸
â
¸
+
Ç
)
·
5
|
Ê
!
$
¸
$
!
¸
¹
¾
5
¾
¼
5
-
¸
$
'
"
Ê
·
!
+
·
Ê
Ù
!
¼
$
!
'
+
Ç
!
5
º
-
5
1
Ù
1
$
5
Ç
$
1
¼
)
+
5
6
Ç
¸
¼
)
B
¾
6
·
Ù
$
+
)
'
E
"
·
-
Ù
¼
·
¸
$
Ç
)
$
)
Ç
Ù
1
)
-
Ç
+
º
-
+
¸
'
2
Ç
B
¸
6
!
-
+
!
Ç
¸
-
¼
2
$
5
!
·
¸
"
)
5
+
·
¸
!
¸
¸
$
5
)
-
·
6
!
Ç
$
$
)
)
Ê
¸
-
¹
-
!
·
¹
+
6
$
$
Ê
6
1
È
!
5
$
2
¸
-
Ê
-
·
+
$
¾
$
Ù
+
1
'
Ç
Ê
$
-
+
"
·
$
¹
¸
-
"
¾
)
1
¹
¸
5
¹
$
+
¸
!
Ç
·
B
"
¸
Ê
5
Ç
¸
·
¹
$
|
Ç
$
Ê
º
'
!
Ç
Ê
º
1
Ê
»
6
$
æ
Ê
"
+
+
6
$
-
¸
5
·
+
æ
º
$
+
'
$
¼
¼
!
)
$
·
"
+
1
$
'
¸
)
6
)
-
)
1
5
¸
"
5
·
·
)
6
¼
5
1
!
+
Ç
·
2
Ê
B
Ç
|
Ê
¶
"
»
'
)
-
5
¸
"
!
$
1
1
)
À
2
)
!
!
¾
+
)
2
¸
!
$
'
5
¸
5
)
-
$
1
·
)
6
¼
5
1
!
¸
·
"
-
)
1
)
¹
»
-
)
!
'
)
¼
!
)
æ
¶
¹
!
1
$
6
Å
$
!
-
1
'
Ç
)
È
¸
!
¸
"
¹
5
$
-
-
¸
-
5
)
5
t
+
-
¸
$
¾
¸
·
!
5
)
-
"
¼
+
!
+
·
¸
Ç
"
$
+
6
'
-
)
+
-
·
Ê
x
$
+
+
Ê
+
¸
$
¹
!
Ê
$
·
»
Ç
2
Ã
É
)
¼
6
!
!
$
¹
·
+
1
+
"
)
5
5
º
)
-
$
-
1
+
)
$
¼
Ê
!
¸
"
5
6
¾
5
+
¾
t
$
$
·
¸
1
5
1
5
)
»
-
!
-
·
)
È
»
-
-
)
¸
2
"
'
¸
5
"
6
-
¸
$
)
¹
·
¼
-
"
)
5
+
!
-
¸
$
È
¸
·
É
)
2
'
'
)
·
!
6
)
'
¶
5
+
º
¼
!
$
»
¸
$
·
6
¸
'
5
·
$
6
$
¹
1
-
$
!
·
5
"
¸
¾
½
5
-
¾
'
5
!
1
+
À
$
6
-
)
¹
-
!
¾
¸
$
+
+
¸
¹
Ç
·
Ç
2
"
Ê
$
Ê
-
¹
¸
Ê
Ç
"
E
Ù
$
Ç
¸
|
Ê
)
Ç
Ù
x
2
É
Ç
)
·
Ù
¸
|
"
¼
Ç
¸
$
!
-
·
Ù
Ù
)
6
'
Ç
¼
!
Å
)
5
1
á
-
!
)
¼
+
$
+
!
-
Ç
)
»
â
'
·
¸
Ç
¸
"
+
¾
·
À
"
+
)
"
+
5
'
·
)
"
¸
!
+
"
-
$
¸
1
!
)
1
¸
$
»
6
-
¹
+
¼
-
¾
¸
¸
!
æ
!
5
Ç
¿
Ê
Ê
Ç
$
+
¸
$
·
Ã
6
$
·
"
5
-
Ç
$
+
¸
"
5
!
¸
$
!
¹
¸
Ê
Ù
Ù
'
5
+
·
¾
+
+
+
·
)
6
¼
5
1
$
¸
5
)
-
)
2
$
+
¸
$
·
Ã
æ
º
$
+
'
5
-
¸
!
6
'
5
$
¸
1
$
-
¹
¾
$
¹
G
F
O
D
5
-
¸
)
$
-
$
+
+
6
º
1
»
1
$
-
U
¹
G
¾
R
¡
$
¹
<
B
R
)
M
K
2
¸
M
"
F
!
M
¹
O
5
+
¸
R
A
!
U
G
æ
X
º
"
$
+
'
"
¼
,
!
)
æ
·
+
+
)
!
}
d
B
º
º
Ê
"
·
)
!
!
·
¸
-
+
+
¼
!
)
)
2
+
)
2
¸
"
¸
!
$
-
+
2
)
!
6
$
¸
5
)
-
+
$
+
À
1
1
$
+
¸
"
5
!
¶
5
6
¼
¼
!
+
1
)
¸
6
¾
!
!
-
Ê
·
Ù
¼
"
¸
$
¸
-
·
!
)
5
5
¹
-
-
!
'
)
)
Þ
¸
$
!
5
$
6
¸
+
$
)
Ë -
+
6
2
á
¸
¾
¼
!
B
)
+
)
»
)
¸
¹
¹
5
À
$
)
!
º
!
1
¾
¸
6
·
)
!
·
ß
!
5
!
Ç
6
"
$
Ã
·
¸
-
$
Ã
5
·
"
¸
-
"
·
5
-
·
)
¹
¹
!
À
Ã
6
$
'
¼
6
5
¹
1
¾
+
1
)
!
$
¸
$
5
!
¹
·
5
1
5
"
)
$
-
-
»
5
5
·
+
$
1
$
1
»
6
¾
$
+
·
!
5
-
)
¹
æ
¸
É
Ë
"
¼
$
-
á
+
5
B
)
»
-
5
$
-
-
¸
'
!
¸
æ
"
Ê
-
$
1
1
»
$
¼
¼
1
5
'
¸
)
$
1
¹
)
!
5
¸
"
6
+
5
-
¶
$
-
+
'
»
·
+
B
¸
¾
Þ
+
!
·
5
Ê
¹
Å
¾
$
!
·
¹
$
!
$
)
'
Å
+
5
!
¸
$
+
+
!
5
d
+
5
$
·
½
5
!
¸
¾
$
1
d
$
·
!
)
)
)
)
+
)
+
-
¹
$
$
-
+
º
¼
+
¾
¸
¸
)
¹
|
¸
¾
Ù
»
¸
B
Ç
2
)
5
!
6
æ
Ê
·
·
»
¸
'
$
$
Ë
1
+
!
Â
¾
Ã
!
-
6
Å
)
6
·
$
·
)
¸
ô
¹
À
"
$
Ç
)
'
·
+
Ç
-
Þ
1
)
+
¸
5
+
1
º
5
¸
$
¼
·
·
+
»
$
!
¾
$
-
'
!
!
¾
)
)
)
¸
¹
5
1
º
+
-
¸
¼
-
$
¼
"
)
)
1
6
¸
)
·
+
¾
1
)
¾
+
¼
5
!
¸
-
¾
-
$
"
5
!
1
¿
ã
"
¸
!
6
¸
5
»
$
$
1
1
2
·
·
"
¹
-
5
-
¸
-
)
·
1
»
Ç
)
+
Ç
¼
+
!
'
¼
¹
+
¸
B
-
Å
$
¾
º
$
5
2
¼
+
¸
À
)
¸
¸
$
)
¹
·
5
1
"
¾
+
-
-
)
Ë
+
5
)
'
.
+
+
+
¸
-
¾
6
+
·
¸
$
-
¹
+
)
!
¸
)
¸
¹
¾
º
1
5
$
)
¼
)
'
)
·
-
!
!
+
5
$
»
¼
6
Ç
»
5
æ
6
"
á
¹
Ê
"
)
!
+
¸
)
º
»
2
¹
E
¸
-
á
Ç
ß
!
)
Ù
1
+
¼
5
¾
Ç
¼
¸
¸
»
¼
$
·
-
!
-
Ç
-
"
¾
¾
$
»
·
)
2
E
5
+
1
»
Ç
¸
ß
»
'
$
$
-
á
¸
¸
$
Ê
-
¾
-
d
5
Ê
Ç
¸
6
¸
+
!
$
1
-
6
¸
¼
)
"
»
5
Ç
-
ô
+
$
Ç
Å
$
¶
½
"
5
-
º
Ç
Ç
E
Ë Ç
x
º
º
Ë
õ
Ç
d
»
»
B
Ç
R
x
Ë
á
æ
1
¼
"
$
»
Ç
R
B
ö
Ê
¿
÷
*
}
)
+
¾
+
)
!
±
Å
·
"
®
!
$
5
´
2
»
+
8
5
³
-
á
.
¹
Ç
µ
¼
!
¸
"
!
·
¹
1
6
·
-
)
!
'
)
¸
·
¼
-
¸
5
½
¾
6
-
¸
5
t
)
$
¸
+
!
$
1
-
Ç
5
1
»
$
)
"
6
¾
¸
5
5
-
+
Å
5
2
·
+
¾
1
)
Å
¸
¸
!
)
·
'
!
)
1
5
æ
»
5
6
·
¼
)
$
-
)
-
'
5
1
5
6
1
¼
1
)
!
5
!
-
1
»
+
2
!
$
)
+
+
!
2
5
5
!
)
!
$
ø
1
5
¸
É
)
+
¸
ù
+
¼
5
·
¸
·
¼
À
5
!
5
¼
1
)
¹
-
!
$
6
6
'
¸
5
-
)
¹
·
1
)
¼
$
-
¹
¾
À
5
$
¸
¹
"
+
!
!
5
5
$
)
·
·
2
¸
5
"
$
)
5
!
-
Ê
-
x
Ç
·
+
$
-
)
¼
'
'
·
¸
5
"
$
$
1
-
1
'
»
¸
¸
Ç
¸
·
)
"
"
!
-
5
¾
½
¾
æ
+
¾
+
)
+
2
2
)
!
Ê
¼
6
+
·
6
2
'
+
¸
)
)
$
·
5
'
!
"
1
¸
1
)
¼
¸
!
·
-
$
Å
!
5
·
¼
)
À
¸
)
'
¸
1
·
!
2
-
$
$
¼
'
$
!
1
-
¸
'
Ê
$
¹
$
)
$
'
+
¼
·
º
-
6
·
$
"
¸
À
¼
"
·
-
À
¼
+
!
2
)
$
"
-
1
!
!
-
$
1
5
1
$
À
¼
¼
)
6
¸
)
6
"
·
!
+
·
·
+
)
2
-
5
Å
5
)
5
$
·
½
¸
+
+
"
5