A Linear-Time Self-Interpreter of a Reversible Imperative Language
Information and Media Technologies 11: 160-180 (2016) reprinted from: Computer Software 33(3): 108-128 (2016) © Japan Society for Software Science and Technology
推薦論文● PPL 2015
A Linear-Time Self-Interpreter of a Reversible Imperative Language
Robert Gl¨uck Tetsuo Yokoyama
A linear-time reversible self-interpreter in an r-Turing complete reversible imperative language is presented. The proposed imperative language has reversible structured control flow operators and symbolic tree- structured data (S-expressions). The latter data structures are dynamically allocated and enable reversible simulation of programs of arbitrary size and space consumption. As self-interpreters are used to show a number of fundamental properties in classic computability and complexity theory, the present study of an efficient reversible self-interpreter is intended as a basis for future work on reversible computability and com- plexity theory as well as programming language theory for reversible computing. Although the proposed reversible interpreter consumes superlinear space, the restriction of the number of variables in the source language leads to linear-time reversible simulation.
Examples of recently shown properties include the 1 Introduction structured program theorem [32] and the universal- Reversible computing is a relatively young area of ity of Turing machines [2]. computer science that studies the theory and prac- This paper deals with the question of the exis- tice of forward and backward computation on all tence of linear-time self-interpretation in reversible levels of the computation stack ranging from logic computing (i.e., efficient interpretation in the sense circuits and computer architectures to program- of Jones [16]). Linear-time interpreters are used ming languages and algorithms (e.g. [8][29][34]). in computability and complexity theory. Among Reversible programming languages compute only others, they are used to show the existence of a injective functions [2] owing to the forward and linear-time complexity hierarchy along the lines backward determinism of the underlying compu- of Jones [16][17] and of Levin’s optimal univer- tation model. This means that there is a unique sal search [18][13]. Although linear-time self- relation between the input and the output of a re- interpretation is a good property to have in any versible program. The validity of several funda- computation model, no such self-interpreter is mental programming language theories, whose ir- known in some models (cf. a universal Turing ma- reversible counterparts are often taken for granted, chine as fast as that with a logarithmic-time over- has not yet been examined in reversible computing. head is known [19]), whereas it is for the pure un- typed lambda calculus [21] and for Jones’ imper- ative I language [16]. However, the existence of 可逆命令型言語の線形時間自己解釈系 linear-time self-interpreters in irreversible comput- ロバート・グリュック , コペンハーゲン大学計算機科学 ing does not imply the corresponding result for re- 部, DIKU, Department of Computer Science, Uni- versity of Copenhagen. versible computing. 横山哲郎, 南山大学理工学部ソフトウェア工学科 , Depart- We begin by introducing the language R-WHILE, ment of Software Engineering, Nanzan University. a reversible version of Jones’ WHILE language. The コンピュータソフトウェア ,Vol.33, No.3 (2016),pp.108–128. language has structured control flow operators [研究論文] 2015 年 7 月 30 日受付. and symbolic tree-structured data (S-expressions
160 Information and Media Technologies 11: 160-180 (2016) reprinted from: Computer Software 33(3): 108-128 (2016) © Japan Society for Software Science and Technology known from Lisp). The latter allows for the mod- and their input and output are written in type- eling of many familiar data structures in a simple writer font. If p is a program written in the lan- way, which is more difficult in existing reversible guage S,then[[p]] S denotes the meaning of p, i.e., imperative languages such as Janus, which only the input–output function that p computes. Thus, provide integers, arrays, and stacks. It was only the output d =[[p]] S(d) results from running p on recently shown how to represent and manipulate bi- the input d. It is undefined if the program does not nary trees in the heap of a reversible random-access terminate. machine [3]. We shall see that a linear-time self- We assume that programs compute with trees interpreter exists in R-WHILE-M,anr-Turingcom- built from a finite set of atoms. The data domain D plete subset of the language R-WHILE in which the of a program is the smallest set that contains the fi- number of variables is bounded. nite set of atoms and all of the pairs (d1.d2),where
The reversible structured control flow operators d1, d2 ∈ D. of the reversible imperative reversible language R-WHILE-M are instances of those of the reversible 2. 1 Standard Interpreter flowchart language [34]. There are other r-Turing An L-program int is an interpreter of a language complete languages with reversible structured con- S in the language L iff for any S-program p and S- †1 trol flow operators such as Janus and R [9].How- data d and d , ever, none of these languages have tree-structured [[ int]] L(p.d)=d ⇐⇒ [[ p]] S(d)=d . (1) data, and they explicitly limit the number of vari- Following the convention [17], whenever a program ables and constants. is an input into another program, we regard it as Moreover, the reversibility of R-WHILE will be the corresponding data representation. For exam- shown from a new viewpoint, namely by using its ple, p on the right-hand side is an S-program text, denotational semantics. This simplifies the proof whereas p on the left-hand side is a representation of this defining property as compared to the pre- of the text as L-data (e.g., as tree-structured data). vious approach used for the reversible language The language S is the source language,andL is Janus [35]. the implementation language of int. If the source The work presented here is part of a larger ef- language and the implementation language are the fort on advancing reversible computing systems on same, S = L; then, int is a self-interpreter. all levels, including the design and physical realiza- tion of reversible logic circuits [8][29][25], reversible 2. 2 Reversible Interpreter computer architectures [4][28], and programming The usual definition of an interpreter in Eq. (1) languages and abstract machines [1][20][22]. does not carry over to interpreters written in a re- To demonstrate our results, a complete online versible language. Let us look at this surprising interpreter for R-WHILE, an implementation of the and important point more closely. Suppose that linear-time reversible self-interpreter in R-WHILE-M, the implementation language L is a reversible lan- and the program inverter are available from http: guage, which means that all L-programs compute //tetsuo.jp/rwhile-playground/. injective functions. Thus, for all L-programs p and
data d1, d2,wehave L L ⇒ . 2 Standard vs. Reversible Interpreters [[ p]] (d1)=[[p]] (d2)= d1 = d2 (2) That is, whenever the output of two applications We define the notion of a reversible interpreter of the same program is identical, so must be their and its efficiency. We find the fundamental differ- input. In particular, consider the L-program int, ences between standard and reversible interpreters which computes an injective function because of the already on this abstract level and even more when reversibility of L. For all S-programs p , p and data we later consider the actual construction of re- 1 2 versible interpreters. We begin by recalling the standard definition of an interpreter and then dis- †1 Following the notational convention [17], we omit cuss the properties of reversible interpreters. the outermost brackets of data if it appears as the argument of a semantic functions, e.g., we write We use the notation presented in [17]: Programs [[ int]] L(p.d) instead of [[int]] L((p.d)).
161 Information and Media Technologies 11: 160-180 (2016) reprinted from: Computer Software 33(3): 108-128 (2016) © Japan Society for Software Science and Technology d,wehave A reversible interpreter that does not require any L L ⇒ . [[ int]] (p1.d)=[[int]] (p2.d)= (p1.d) = (p2.d) output in addition to the representation of the pro- (3) gram and its output is said to be functionally clean. This implies that the program representation of the Thus, an interpreter that returns an extra trace is two S-programs is textually identical: p1 = p2.Us- not functionally clean. S ing this implication and Eq. (1), we get [[p1]] (d)= S ⇒ [[ p2]] (d)= p1 = p2 from Eq. (3). That is, S- 2. 3 Running Time Function programs that compute the same result for some In analogy to the standard terminology, the effi- d must have the same program representation as ciency of programs written in a reversible language the L-data argument for int. However, source lan- L is defined by a running time function L guages that do satisfy this condition are too re- time : L-programs → (L-data → N⊥), (5) L strictive and not very expressive. For example, where timep(d) is the number of steps to compute p either the injective function f1(x)=(x.nil) or with the input d, provided the computation termi- f2(x)=(nil.x) cannot be computed in such a lan- nates; otherwise, undefined ⊥.WedenoteN ∪{⊥} guage since f1(nil)=f2(nil), and the programs by N⊥ (see Sect. 3. 3). implementing f1 and f2 will not be syntactically Finally, the definition of an efficient (i.e., linear- equivalent. time) reversible interpreter in the sense of Jones co- The issue described above cannot be avoided incides with the standard case [17]. The constant c when a universal reversible Turing machine (RTM) in the definition may depend on the reversible in- is considered, i.e., a self-interpreter for a reversible terpreter rint but not on the source program p or language [2]. A universal RTM needs to preserve data d. the machine it simulates in the output [19].These Definition 2. A reversible interpreter rint of the considerations lead to the following definition of a language S in the language L is linear-time if there reversible interpreter. exists a constant c such that for any S-program p Definition 1. Let L be a reversible language. and S-data d, L S Then, an L-program rint is a reversible interpreter timerint(p.d) ≤ c · timep(d) . (6) of the language S in L iff for any S-program p and S-data d and d , 3 A Structured Reversible Language [[ rint]] L(p.d)=(p.d ) ⇐⇒ [[ p]] S(d)=d . (4) This section presents the concise reversible lan- The reversible interpreter pairs p and d in the out- guage R-WHILE, a structured imperative language put, and it becomes symmetric: the input and out- with tree-structured data. We define its syntax put formats of the interpreter are the same. (Fig. 1), denotational semantics (Fig. 2), and a The definition also implies that every S-program syntax-directed program inverter (Fig. 4), which computes an injective function. Otherwise, an S- we will use later for the construction of the self- program p and the data d , d exist s.t. [[p]] S(d )= 1 2 1 interpreter. The language is based on Jones’ ir- [[ p]] S(d )andd = d . By Eq. (4), we have 2 1 2 reversible language WHILE [17]. We adopt denota- [[ rint]] L(p.d )=(p.[[ p]] S(d )) 1 1 tional semantics for ease of comparison, as the se- = (p.[[ p]] S(d )) 2 mantics of WHILE is defined in a denotational man- =[[rint]] L(p.d ) . 2 ner. We assume that the reader is familiar with the However, (p.d ) = (p.d ) because d = d . There- 1 2 1 2 basic notions of denotational semantics (e.g., [30]). fore, [[rint]] L is not an injective function, and L can- not be reversible, which contradicts the assumption 3. 1 Example Program: List Reversal that L is reversible. Thus, the source language S S S A short example program reverse for list rever- must have a semantic function [[·]] such that [[p]] is †2 sal illustrates several language features . injective for any S-program p. Simulating irrevers- read X; (* reverse list X *) ible languages in reversible languages requires an from (=? Y nil) injectivization of the semantic function of the irre- versible language. For example, this can be done by †2 Here, we omit the do branch of the loop. See adding a trace to the output of the interpreter [24]. Sect. 3. 2.
162 Information and Media Technologies 11: 160-180 (2016) reprinted from: Computer Software 33(3): 108-128 (2016) © Japan Society for Software Science and Technology
Expressions E, F ::= X | d | cons E F | hd E | tl E | =?EF Patterns Q, R ::= X | d | cons Q R Commands C, D ::= X^=E | Q<=R | C; D | if E then C else D fi F | from E do C loop D until F Programs P ::= read X; C; write Y Fig. 1 Syntax of R-WHILE.
loop (Z.X) <= X; d, e, f,... ∈ D and X, Y, Z,... ∈ Vars.Forthe Y <= (Z.Y) sake of readability, we will use more than one atom until (=? X nil); in the programs. For example, the three atoms write Y ’a, ’b, ’c can be encoded in D as nil, (nil.nil), The input of the program is read into the vari- (nil.(nil.nil)). able X, and the output is written from the vari- An expression is either a variable X,aconstant able Y. All variables are initially set to nil.The d,ortheapplicationofanoperator(theselectors reversible loop from ...until is entered by assert- hd and tl, constructor cons, and equality test =?). ing that Y is nil and exited when X is nil.The Patterns are a subset of expressions: a variable X,a commands in the loop body are repeated as long data element d, or a pair of patterns cons Q R.For as the entry assertion and the exit test are false. the sake of readability, we denote a pair of patterns The first command in the loop, a reversible re- cons Q R by (Q.R). Patterns must be linear, i.e., placement, deconstructs the value of X into its head not contain repeated variables. The language has and tail components; the second reversible replace- no local variables. ment constructs a value by pairing the values of In a reversible assignment X^=E,thevariable Z and Y. A reversible replacement sets the vari- X on the left-hand side must not occur in the ex- ables on the right-hand side to nil before bind- pression E on the right-hand side. A reversible re- ing the original value of the right-hand side to the placement Q<=Rupdates the variables in Q using variables on the left-hand side (e.g., Z is nil af- the values of the variables in R. In contrast to an ter the replacement Y <= (Z.Y)). All variables ex- assignment, a variable can appear on both sides of cept the output variable Y must finally be nil. a replacement in the linear patterns Q and R (e.g., The application of the program to reverse a list is the variable Y in the replacement Y <= (Z.Y)). denoted by [[reverse]] R-WHILE(’a.(’b.(’c.nil)))= The two structured control-flow operators of the (’c.(’b.(’a.nil))), where the list elements ’a, language are conditional if E then C else D fi ’b,and’c are atoms. Because of the entry as- F and loop from E do C loop D until F.Loops sertion and reversible replacements, the program is have an additional entry assertion E, and condi- reversible. tionals have an additional exit assertion F.Tests and assertions have the same syntax, and both are 3. 2 Syntax evaluated at run time. For readability, we often The syntax of the language is simple (Fig. 1). A omit the branches of conditionals and loops that program P has a unique entry and exit point (read, contain only skip commands (e.g., nil <= nil). write) and a command C as its body. The input As usual, we write the list and output of a program is read into and written (d1 d2 ··· dn) from the variables in the entry and exit points. for (d1.(d2.(···.(dn.nil)···))), and the im- The data domain D of a program is the small- proper list est set that contains the atom nil and all pairs (d1 ··· dn-1.dn)
(d1.d2) ∈ D if d1, d2 ∈ D. Vars is an infinite for (d1.(···.(dn-1.dn)···)). set of variable names. We use the conventions Similar to the notation for lists, we write the pat-
163 Information and Media Technologies 11: 160-180 (2016) reprinted from: Computer Software 33(3): 108-128 (2016) © Japan Society for Software Science and Technology
E σ E σ E σ E σ [[ d]] = d [[ cons E F]] = ( [[ E]] . [[ F]] ) E[[ X]] σ = σ(X) true if E[[ E]] σ = E[[ F]] σ E σ E σ E[[ =? E F]] σ = [[ hd E]] = e if [[ E]] = (e.f) false otherwise E[[ tl E]] σ = f if E[[ E]] σ = (e.f)
Q[[ d]] σ =(d,σ) Q[[ X]] ( σ {X → d})=(d,σ {X → nil})
Q[[ cons Q R]] σ =((d1.d2),σ2) where (d1,σ1)=Q[[ Q]] σ ∧ (d2,σ2)=Q[[ R]] σ1
C[[ X^=E]] ( σ {X → d})=σ {X → d E[[ E]] σ} −1 C[[ Q<=R]] σ = Q[[ Q]] (Q[[ R]] σ) C σ C C σ [[ C; D]] = [[ D]] ( [[ C]] ) if E then C σ if E[[ E]] σ = true ∧ σ = C[[ C]] σ ∧E[[ F]] σ = true C σ = elseDfiF σ if E[[ E]] σ = false ∧ σ = C[[ D]] σ ∧E[[ F]] σ = false fromEdoC C σ = σ if E[[ E]] σ = true ∧ σ = fix(F )(σ) loop D until F where F (ϕ)={ (σ, σ1) | σ1 = C[[ C]] σ ∧E[[ F]] σ1 = true }∪ { (σ, σ3) | σ1 = C[[ C]] σ ∧E[[ F]] σ1 = false ∧ σ2 = C[[ D]] σ1 ∧E[[ E]] σ2 = false ∧ σ3 = ϕ(σ2) }