A LOOIC FOR COffi-P?CT PROGRA?? D?7EbCPY?ENT Josep? Lojis Rates Ph.D. Tbesis TR 79-3S8 Department of Computer Science Cornell University Ithaca, New York 14S53 Auqust 1979 A lOGlC FOR ceRKr.cT PROcfQ&N t?ffiVEL(?P'ffi??T A Thesis Presented to the Faculty of the Graduate School of Cornell Uni?ersity in Partial Fulfillinent for the Degree of Doctor of Philosophy by Joseph Louis Bates August 1979 BIOGRAPHICAL SXETCH Jcsepb Louis Bates was born on October 20, 1953 in Baltimore. Nar?lsnd. He began study at The Johns Hopkins University in September 1969 as the first early entrant of the later formalized Study of Itathenatically Precocious Youth. In January 1972 he was admitted to the Johns Hopkins Craduste School for concurrent study in Computer Science. He received the degree of Bachelor of Arta in Quantitative Studies in Nay 1973. and the degree of Master of Science and Engineering in Computer Science in August 1973, both from Johna Hopkins. He received Honorable Mention for tbe Clark Teaching Award (given for excellence in teaching) fros Cornell University in May 1973. --H`i--H To Paul. Louis. and Julian for making it posaibla. ACXNoWLEflO(ENTS Professor Alan Demers encouraged my research efforts from the beginning. His ready car and persistent interest in this work, though it was not squarely "in his area5. were vital to its completion. In addition. his technical assistance has significantly improved numerous aspects of this thesis. I as pleased to have worked with him the last few years. Professor lobert Constable provided critical insight and crucial smpnort during tbs later stages of mv studies. His arguments for constructive reasoning drove me to understand more deeply the application of logic to programming. Had he spoken less persuasively, I would still be struggling with "obviously valid5 classical reasoning. Xany individuals. in addition to the two above. took time to read and co-ent upon drafts of this document. William Appelbaum. Milton Hates. Professor Robert Cartwright. Merrick Furst. and Professor David Cries supplied suggestions on the style and presentation of the thesis. My special thanks go to Peter Vanderbilt for many fruitful discussions. for his careful technical readint of rough drafts. and for constantly encouraging is to ciplain o+yssl clearly and correctly. -jy- Dr. llerlan Kills planted the seed of this ?ork ions ago by a?guing that people can and should construct correct programs. A glance at aociety?e uses of computers convinced me of the lattert William Appelbeum and Fran Corredo concretely demonsttated the former. Finally. I would like to thank fly friends for aaking time here tolerable. especially during my self-imposed isolation this last year. I cannot adequately acknowledge the support of iy family when things were intolerable. TAilt OF CONTENTS 1, Introduction1 1.1 The software problemI 1.2 Toward a solutionA 1.3 Organization of the thesis6 2. Correct program development by formsl refinement8 2.1 Some existing approaches to correctness8 2.2 The formal refinement approach to correctness21 2.? The specification of imperative program segments31 2.4 gefinement rules and the semantic content of proofs38 3. PEL: A logic for correct program development48 3.1 Types and expressions49 3.2 Generators and iterators55 3.3 Transition specifications63 3.4 Propositions. environments, and justifications65 3.5 Refinement: logical rules70 3.6 Refinement: integers and sets--H81 3.7 Refinement: transition specifications87 3.8 Abstraction 97 3.9 Static analysis and type checking112 vi- ?. The extraction of prosrasa fros proofs126 4.1 Itefinement logic netatbeory126 4.2 The extraction procesa and extracted prograMs131 4.3 Extraction: logical rulea143 4.4 Extraction: integera and aeta139 4.3 Extraction: tranaition apecifications161 4.6 Extraction: definitions and leunna170 4.7 Example extractiona and optimization173 3. Conclusion18? 5.1 Summary187 3.2 Ideas for future research192 Bibliography200 Collected concepts. definitions. and syntax210 Index of refinement rules216 CIIAPTVM I INTRODUCTION 1.1 ?ialinu?? With the advent of the silicon integrated circuit in the early 1960's. the fundasental electrooics tecbnology that underlies modern coiputers began doubling in effectiveness every year (Siewiorek Ct. 51. 1978. Bhandarkar and Juliussen 19783. Prior to this technological achievement. sachines were limited, society's expectations modest. and potential applications of computers were adequately realized. liowever, as exponentially inproving hardware encouraged increasingly cornplex applications. the burden of producing correct. efficient. ever larger systeas case to rest on the programmer. Too often the programmer failed miserably. As hardware advances continued into the 1970's. the growing gap between the expectation and reality of software development prompted computer scientists to examine the programming task in depth. Dijkstra wrote the frequently mimicked 1COTO Statement Considered ilaruiful5 letter Dijkstra 1968a) advancing tha idea that the anro statement led to programs with 5intellectually unmanageable5 control flow. The term 5software engineering5 was coined to convey the notion that programs are structured objacts to be constructed according to sound anginesring --H1--H -2- principles [Randell and Naur 1968]. progra?ming language seeantics took on a new aignif:cance as Noare's axiomatic method provided an effective tool for analyzing both the complexity of languages and the properties of individual programs (Hoare 1969]. These ideas grew into several broad areas of research aimed at solving the software problem. Languages: Progra,ming language designers realized that languages must aid. not burden, the programmer (Hoare 1973. Wirth 1974). Languages were developed to support the major intellectual techniques for handling complexity -- abstraction, case analysis. induction. etc. -- without themselves becoming too complex to understand. Study of such areas as data abstraction, control abstraction, scoping. and modularity led to proposals for various supporting language constructs. Nethodology: After considerable debate. the 5code then debug5 philosophy gave way to the idea that programs could and should be constructed to function properly the cat time execute,: (Nilla 1973]. Top down design from well specified requirements became an accepted development technique. Progra?era recognized that testing alone could only mildly increase their confidence that a program was properly constructed; assured correctness had to be built in, it couldn't be tested in. Verification: The notion of program correctoess was formalized in various ways and techniques were developed to prove programs correct. (Correctoess means performing according to specifications. Assuring the aptnesa of specifications is an important, but distinct, problem.) These ideas affected programssing languages and methodology? they led to tha -3- suggestion that programs and their proofs be developed simultaneously. Systems `gere built to support program verification with varying degrees of automated aid. As of the late 1970'.. many of these advances in progran-ing languages and methodology have had an impact on the construction of real world software. Top down development and structured programming have been adopted by a wide variety of software producers. Articles proposing or analyzing other techniques appear constantly in the data processing industry's trade journals. Myriad introductory programming texts describe top down development in PVI subsets or PASCAL. 5Structured progra?ing5 preprocessors for FORTRAN, COBOL. and other old languages seem as common as the compilers themselves. In contrast, thougb the idea has been in the technical literature for over a decade. formal verification of programs has not had a direct impact on real world software production. That is, people almost never carry out complete formal verificatione of their programs. For interesting algorithes. existing formal proof techniques and their informal counterparts are adequate. These short programs. often published, are subject to the detailed scrutiny of many iod?viduale. Real programs, however. are often so dull that only the original programmer ever reads them. Existing techniques. though theoretically adequate, are exceedingly tedious in this domain, even if mechanical aid is supplied. Thus. one finds that enforced formal verification with current technology is unacceptable in practice; yet. because real world programs are too large to be fully tested and are produced by pr?gra?s?rs ?ith a ,,r,jst?nt t?n.;?n?y to err. f?'rma;?nR of ,uma -4- kind (checked by sachine) is exactly what is needed to guarantee the correctneaa of large programa. 1.2 Za??1??i? The work presented herein is based on the belief that current verification technology is inadequate largely because it fails to directly support effective methods of progras development. ?(oat verification techniques are analytic tools. applicable to arbitrary code segments divorced fron their development; simila?ly. soat verification systems analyze arbitrary programs and yield a set of lemmas (verification conditiona) that must he proven. In ny experience. however. careful. accurate prograusaera having low error rates develnp correct programa with informal reaaoniug -- they seldom verify completed programs with formal reasoning. Though formal techniques for analyzing code can help guide informal development .e.g. flijkstra?s uae of predicate tranaforuera (Dijkstra 1976). verification systems based on these techniques are code readers -- they can only insure correctoesa by anslyais performed after code is written. In contrast. this thesis claims the need for a habitable formal logic and associated support system for correct program cnn.tructinn A logic for program construction should formalize a particular development methodology. not just the semantics of a conventional programming language. The text produced by a programmer should contain the complete record of an idealized (l.e.. no backup) development of his program. including all reneoning needed to dt.monatrate i?a correctness. Prugr rs are y,e1?.'raI ly a?.? ?f a r..as?nje? Jur'?g devel??ment of -5 forrect code. Providing a fors?l notation for recording it peruits program and proof synthesis to be integrated into one unifled process5 with correctoess of the evolving program insured at all stages. This approach forsalizes the methodology advocated by many authore of structured proarsamaing texts (Wirth 1973. Conway and Cries 1975, Dljkstra 1976). ?stsbliahing program correctness is viewed differently from this vantage. Verification as a distinct activity no longer exists since incorrect progranLa cannot be produced. Executable code is obtained only by means of correct formal development. This change in viewpoint is of great psychological importance becauae it captures the idea of prograsnaing as a methodical process of discrete. manageable deci.ions in which the concepts of bugs, quick and dirty prograna, etc., never arise. When constructing programs to meet given specifications. I believe limiting one's thought in this way is not ?ust appropriate. but assentisl. A program development logic requires prograu?ners to manipulate substantially ,sore text than is usual. Also, formal reasoning has an advantage over rigorous reasoning only when it is mechanically checked for validity. Thus, an interactive system that assists and watches the prograsiser is sn indispensable part of this approach. The minimal version of such a system must provide clerical help in manipulating program developments sod should check the validity of reasoning used therein. Im addition, the system should take over the work of proving the less of trivial propositions found in developments. The constantly increasing ratio of software to hardware Costa bee ude any such -6- assistance ecoomically attractive. even at the expense of substantial dedicated computing power. The view of program development advocated here clearly contradicts the well known argument that 5programs should not be written at terminals5. The reasoning behind that claim applies to conventional (edit-run-dehug) systems. because they effectively support only the 5modify until.sll the test cases work5 methodology. Ny proposal is for a system supporting a more tenable methodology requiring and helping the programmer to reason about all possible executions. I envision construction proceeding via a man-machine dialogue. perhaps a variation of that suggested by Floyd (Floyd 1971]. The dialogue would emphasize correct reasoning in a style suited to expressing complete idealixed developments. 1.3 Oreanization ? the thesis The body of this thesis is the presentation and analysis of PRL. a logic for the top down development of programs. PRL an acronym for Proeram Refrinemeur ??. is a tormalism that provides for the specification and correct refinement of programs operating on integers, hooleans, and well typed. homogeneous finite sets. The logic is the result of my attempt at the 5habitable formal logic ... for program constructions called for in the previous section. Chapters 3 and 4 contain the major technical results of my work. Chapter 3 describes PRL in depth; it includes examples dispersed throughout the text. Chapter 4 presents a detailed account of a method --H7--H for aitractias (1.s.. compiling) programs from proofs. Inherent in this account is a desonstration of the logic's consistency. Though I have tried to limit the bulk of the thesis. chspters 3 and 4 have steadfastly resisted my efforts. In chapter 2. the 5casual5 reader will find the general ideas of refinement logics. motivated and developed from previous work on program correctnesa. Chapter 5 first sunnarizes the three fundamental ideas that underlie PaL. then enunerates a variety of areas subject to future study. Thus. chapters 2 and 5 provide an overview of refinenent logica in the context of past and suggested research. CWTKt 2 CORRECT PRoCRA?q DEVELOPMENT DV FODEL W1!wD(?ENT 2.1 Some existing annroacbea ? correermeas I shall now discuss a variety of methods aimed at belping people produce correct imperative programs. These methods range from the early work on formally defining correctness to automatic systems for synthesizing correct code from specifications. They roughly fall into three catagories: development methodologies, formal logic.. and computer based programming support systems. The fundamental idea in establishing correctnesa is that uecutable programs may be interpreted as defining classes of computations. One can analyze a given program to determine its leaning. that is. the claas of computations it performs. A program is said to be correct exactly when its determined meaning is consistent with a separate specification of its intended meaning. Early workers on program verification (Naur 1966. Floyd 19671 developt'd a method of assigning predicate.. called Inductive assertions. to various points In the control flow of a program so that every time execution reaches any particular point the corresponding sasertion is true. By choosing ss?ertions appiopriately and examining all ex??ution paths bi?twcnn an p?i r. l?prov?d norr.rt n that the -9 otitnut assertion will hold at termination whenever the innut assertion holds initially. The pair of input/output assertions forms a specification of the progreas. 7or exaxple consider the followin8 saerted prograi segIent to Cuss the first ? positive integers. (Mxl) s i; K It A S-sui of I up to KI MhLL' KxM ? jlxttit'g logic (e.g.. integer arit?rnetic). Since these proofs are -16- necessary to demonstrate the correctneas of the program. and often contain reasoning essential to understanding it. I believe they shoold be an integral part of the program text. As will be shown. PIL overcomes these technical problems of Hoare?s logic. yloyd?s early work on the inductive assertion method has been used aa the basis for nany verification syatema (ring 1969. Good 1970. Deutach 1973 Bledsoe and Bruell l97?. Waldinger and Levitt 1974. Igarashi et.al 1973. von Henke and Lorkham 1975. Good et.sl. 19753. These systens typically require only that the user provide invariants to cut every loop; they autonatically generate the necessary verification condition. (King 1976J which are sent to a theorem prover that attempts to conplete the verification. sonetinee with interactive user guidance. The fundanental approach to correctness here is 5after the fact5 verification in which completed programs are submitted for vC generation and proof. Thus. theae systems are completely independent of the methods used to construct input programs. Nany researchers interested in correctoess find existing verification systems lacking. Their objections divide them into two distinct groups. however. One group finds that the information users must supply to allow a posteriori verification is too great a burden; their gosi is to increase th power of mechanical vsrifiecs 5. much as possible so that all interral arsertions can bc automatically generated and proven frou the spoc iL IcatIons and code (??spss 1974. ?eca?n and Weghteit 1975. Xat? and ?anns 19763. The other group rejects a poateriori verification as a rana of achieving rrrctness: rather. they argue that p?ogrc?a si0 6 c?'? ? cuctt? :???, wi h )?ric proof. --H17--H in such a way that correetmess is assured at all stages cf development Enjikatra 1968h. Nills 1975. Dijkstrs l9?6. Cries 1976). Study of this constructive approach to correctness. generally considered programming nethodology. has yielded informal techniques as well as psychological attitudes that enable programmers to greatly increase their productivity (Nills 1975]. This thesis is based in part on the bel?ef that automated aids for insuring correct software should support these techniques for correct program development rather than after the fact verification. Dijkstrs'a calculus of guarded cotmands is a useful mathematical tool that aids in the formal development of correct programs EDi?kstrs 1975a). In his recent book each program is developed with an informal discussion that makes heavy use of formal techniques. but the correct programs that result are pure code with none of their correctoess proofs contained in the program text fDijkstra 1976]. I see this as a significant fault; since proof and program should he developed as a unit, so should they be presented. In contrast. PLfCf is a formal logic whose well?formed formulas are correct program/proofs (Constable and O?Donnell 1978. Constable and Johnson 1979). These combined objects are a variation of asserted programs in which all the reasoning needed to establish total correctoesa is combined with the program text in a relatively natural. rudable way. The formality of the logic allows reasoning to be checked sachanically. thus justifying a high degres of confidence in tha correctness of programs. -18- Pl?CV is a significant step in the solution of the software crisis. yet it too is only a step. Its major failing is the lack of a methodology for producing program/proofs in stages, as the constructive approach calls for. PRL is the result of an attempt to remedy this failing by formaliring a logic of program development, not juat programs. where each well formed formula describes a mechanically verifiable idealized top down development of a program. Such a logic should be a souod foundation from which to build automated interactive systems thst aid in the consteuction of programs. The interactive developmeot of correct programs is an attractive idea that has been discussed before, Floyd presents an imaginary dialogue between man and machine that leads to a search program similar to the example above (Floyd 1971]. Though quite brief. his discussion provides much worth conside?ieg and clearly demonstrates the potential benefits of the system he envisions. Moriconi has developed a system for incremental development that aids the user ir determining the effects of changes to specifications, code. and proofs when using the embedded vc generation based verifier (Moriconi 19773. A limited facility is provided for partially refined programs and top down development, but Moriconi is mostly concerned with an intelligent natural language interface and reducing verification effort by keeping intact any work still valid after given changes are made. A recent paper from MIT describes the theory and initial construction of a orozramner's anorentice that aids experts in the development of LISP programs (gich and Shrobe l9?83. The proposed system 5knows5 enough about the prograaamins task and specific Programs to watch development, --H19--H notice inconsistencies. suggest correction.. vrite programs by inatantiating abstract achena. and answer questions. Though still under devalonnent. the LISP apprentice appears to be an inportant step toward the reslixation of rloyd?s ideas. A somewhat different approach to correct program development is taken in work on correctness nreaerv.ne rrafl.tormnr?ons (?ernart l975s. Cerhart l975b. Surstall and Darlington 1975. Baizer et.sl. i??6. Wegbreit 1976. Schwarti 1977). Here much of the complexity of real programs is tbought to result from the need for efficient execution. Thus. a methodology is proposed whereby the program ia first written in as simple a form as possible. so that correctneas is eaeily shovn. and then correctneas preserving optinizing transformations are applied to produce an acceptably efficient equivalent. Cerhart further proposes that many conon program constructs. e.g.. search loops. could be abstracted. proven correct. and listed in a handbook of valid schema. Large segments of the initial (simple) program might then be formed by combining appropriate instances of these established achema. A catalog of program transformations has been developed to support this methodology (Standish et.al. 1976). In its pure form. the program transformation approach is limited by the ability of programmers to express short. clear solutions to real programming tasks. It seems to me that the approach would benefit from the introduction of a specification language of substantially greater power than the programming language. Creating a fully recorded transformation from initial specification to final code is similar to constructing a PRL program developm?nt. Thtrc arc two main differences -20--H Pint. PIL restricts tbe class of transformation rules to refinenenta of individual specifications. guaranteeins that each development is a simple hierarchy of transformations. Second. PIL specifications 157 be ststements of pure logic. rather thsn only progral specifications. These logical statements carry constructive (executable) leaning. thus. correctnees and execution are highly intertwined concepts (see section 2.4). The final area of correctness research that will be considered is automatic oroerammin?. The goal is to automate th? programmer. and possibly the analyst. out of existence. There are two overall phases in the use of an automatic programming system. though they nay overlap in time: problem ecquisition and progra synthesis. Some researchers. studying the simpler task. describe techniques for synthesis that start from some formal specification of the problem (Manna and Waldinger 1977. Long 1977. Nanna and Waldinger 1978). A few more ambitious researchers are attempting the construction of synthesis systems capable of acquiring the problem specifications directly from con?ersation in natural language with relatively naive users. much as would a programmer/analyst (Belter et.al. 1974. Green 1976). Though Dijkstra considers efforts at producing such systems 5a theme that recurs with the same regularity as influenza epidemics' and the likely result of using tiem `design specif lcati?na jruduc?d a. a kind of p5?l????n alobber11 (Dijkstra 1971b]. it seems probable that systems of this t?pe would be extremely useful in bringing th- power of computers to the public. In any case. ?any of t?e prohl-ma studied in automatic programeing re:e?e imila.us inrional programming -21- (e.g.. specification languages. program synthesis methods. insur?n correctuess) and the work being done is of interest. even if successful autometed systefla are far off. This completes my lengthy but necessarily incomplete review of existing work on the problem of producing correct imperative programs (ses (London 1972. gispas et.sl. 1972. London 1975. Greenspan end Homing 1977. Barnard 1977) for further references). The last decede has seen a tremendous volume of work done in this area with tha attendant publication of many hundreds of papers. I have tried to present enough background to enable the reader to understand and evaluate tbis thesis in the light of current knowledge; I will provide fly own comments and analysis in the following pages. 2.2 Zh formal efinenent A?? I have had the valuable opportunity to observe several programmers whose programs almost always ?ork properly the firat time executed. The most important aspect of tbeir rare ability seens to be an attitude of precision that might be phrased 5programming is a task in which I must carry out a series of discrete decisions and actions. each of which is simply acceptable or not; therefore. I can and will take care never to introduce a line of code whose correctness I am unsure of5. Given this attitude. the appropriate time for machine aid in avoiding coding errors is not during program etecution5 nor iC it during a post-development reading or verification. The appropriate time for machine aid is during program development. -22- In order to determine meciicatly whether the construction of a program is proceeding along an acceptable patb. one needs a formaliam for expressing both the stages of partial development and the reasoning that justifies their correctoess. The method of top down programming. in which problems are repeet?dly bro?cn down into a composition of smaller ones, has been proposed by many and found beneficial for constructing complex systems (Wirtb 1971. Nills 1971. tiskow 1972, Baker 1972a, Baker l972b). I have chosen to explore s?logic of formal top down development in which the well-formed formulas are correct partial refinements of progr?ms from their specifications. The remaining three sections of this chapter informally describes the fundamental features of PIL in preparation for the formal development of chapter 3. Consider the following top down description of the search program that vas presented in section 2.1. /a If x occurs in A1:N) then set t so that AXl--L otherwiae eet K to zero. Assume N?1 and Ail:N) is aorted in increasing order. a? var L,B: inte2er; ?* With the invsriant (1?1sH%N, A(ltN) is sorted in increasing order, and AfL:H) contains X if A(ltN] does), decrassa l1-L to asro, a? flila L