Cons-free Programs and Complexity Classes between LOGSPACE and PTIME
Neil D. Jones, Siddharth Bhaskar, Cynthia Kop, Jakob Grue Simonsen
LL. Fribourg and M. Heizmann (Eds.): VPT/HCVS 2020EPTCS 320, 2020, pp. 65–79, doi:10.4204/EPTCS.320.5 c (cid:13)
Jones, Bhaskar, Kop, SimonsenThis work is licensed under theCreative Commons Attribution License.
Cons-free Programs and Complexity Classes between
LOGSPACE and
PTIME
Neil D. Jones
Computer Science DepartmentUniversity of Copenhagen [email protected]
Siddharth Bhaskar
Computer Science DepartmentUniversity of Copenhagen [email protected]
Cynthia Kop
Department of Software ScienceRadboud University. Nijmegen
Jakob Grue Simonsen
Computer Science DepartmentUniversity of Copenhagen [email protected]
Programming language concepts are used to give some new perspectives on a long-standing openproblem: is
LOGSPACE = PTIME ? Introduction “P =? NP” is an archetypical question in computational complexity theory, unanswered since its formu-lation in the 1970s. The question: Is the computional power of polynomially time-bounded programsincreased by adding the ability to “guess” (i.e., nondeterminism) ? This is interesting because “polyno-mial time” is a plausible candidate for “feasibly solvable”.Perhaps the second most important question is “L =? P”: whether
LOGSPACE = PTIME . Here L is theset of problems solvable by cursor programs . These also run in polynomial time, but have no rewritablestorage . Both questions remain open since Cook and Savitch’s pathbreaking papers in the 1970s [3, 15].We investigate the question “L =? P” from the viewpoint of functional programming languages : adifferent viewpoint than Turing machines. The link is earlier characterisations of L and P by “cons-free”programs [6, 7, 8]. The net result: a deeper and finer-grained analysis, illuminated by perspectives bothfrom programming languages and complexity theory.Some new definitions and theorems give fresh perspectives on the question L =? P. We use programsto define and study complexity classes between the two. By [6, 7, 8] cursor programs exactly capturethe problem class L; and cursor programs with recursive function definitions exactly capture the problemclass P. A drawback though is that recursive cursor programs can run for exponential time , even thoughthey exactly capture the decision problems that can be solved in polynomial time by Turing machines. The goal of this paper is to better understand the problems in the interval between classes L and P.Problem class NL is already-studied in this interval, and it is the logspace analog of similar long-standingopen problems. Kuroda’s two “LBA problems” posed in 1964 [11]: (1) Is
DSPACE ( n ) =? NSPACE ( n )and (2) Is NSPACE ( n ) closed under complementation? After both stood unresolved for 23 years, (2)was finally answered ”yes” (independently in 1987) by Immerman and by Szelepcs´enyi [5, 16]: NL andlarger nondeterministic space classes (with constructive bounds) are closed under complementation. One take: a cursor program is a multihead two-way read-only finite automaton. A more classical but equivalent version: a2-tape Turing machine with n -bit read-only input tape 1, that uses at most O ( log n ) bits of storage space on read-write tape 2. Kuroda’s other LBA problem
DSPACE ( n ) =? NSPACE ( n ) is still open, as well as the question L =? NL. LOGSPACE and
PTIME
We study the problems solvable by an in-between class CFpoly: recursive cursor programs that run inpolynomial time . Recursion is in some sense orthogonal to the ability to make nondeterministic choices,i.e., to “guess”. The class CFpoly seems more natural than NL from a programming perspective.
Let X ⊆ { , } ∗ be a set of bit strings. The decision problem for X : given x ∈ { , } ∗ , to decide whetheror not x ∈ X . We say that X is in PTIME iff it is decidable by a 1-tape deterministic Turing machinethat runs within polynomial time O ( n k ) [here n = | x | is the length of its input x , and k is a constantindependent of x ]. Further, X is in LOGSPACE iff it is decidable by a 2-tape Turing machine that uses atmost O ( log n ) bits of storage space on tape 2, assuming its n -bit input is given on read-only tape 1. Bothproblem classes are of practical interest as they are decidable by programs with running times boundedby polynomial functions of their input lengths. The essential difference is the amount of allowed storagespace. These classes are invariant across a wide range of variations among computation models, and it iseasy to see that LOGSPACE ⊆ PTIME .However, the question: is
LOGSPACE ( PTIME ? has stood open for many years.
Programs and problem decision.
Semantics: a program computes a (partial!) function from bit stringsto bits: [[ p ]] : { , } ∗ → { , } ∪ {⊥} Program semantics is call-by-value; and [[ p ]]( x ) = ⊥ means: p does not terminate on input x .A set X ⊆ { , } ∗ is decided by a program p if p terminates on all inputs x ∈ { , } ∗ , and for any x , [[ p ]]( x ) = (cid:26) x ∈ X x / ∈ X Complexity by cons-free programs.
We use programming languages (several in this paper) to explorethe interesting boundary zone between the problem classes
LOGSPACE and
PTIME . Strong links wereestablished in [7, 8]: Each class was characterised by a small general recursive functional programminglanguage. The one language (called CF for “cons-free”) is limited to programs without data construc-tors. The other, named CFTR, is identical to CF but has restricted control, allowing only tail recursive calls to defined functions. From [8] we know:
Theorem 1
LOGSPACE = { X ⊆ { , } ∗ | some CFTR program decides X } Theorem 2
PTIME = { X ⊆ { , } ∗ | some CF program decides X } A compact notation relating programs and problemsDefinition 1 is the set of all problems (i.e., sets X ⊆ { , } ∗ ) that are decidable by L - programs : de f = { X ⊆ { , } ∗ | some L -program p decides X } Theorems 1 and 2 can thus be restated as:
LOGSPACE = ⊆ = PTIME “Cons-free” is not to be confused with “context-free”. TR stands for “tail recursive”. Data access is read-only in both ofour languages, so neither CF nor CFTR is Turing-complete. These ideas stem from S. A. Cook’s seminal work on complexity classes and pushdown machines [3]. Papers [7, 8] re-express and adapt Cook’s ideas to a cons-free programming context. Paper [8] extends [3], characterising decision powers ofhigher-order cons-free programs. CFTR is (yet another) version of the “cursor programs” mentioned in the Introduction. ones, Bhaskar, Kop,Simonsen 67
All programs are first-order in this paper, and deterministic to begin with (until nondeterminism isexpressly added in Section 5). First, a brief overview (details in [6, 7, 8]): Definition 2 Program syntax: a CF-program is a finite sequence of mutually recursive function defi-nitions. Write CF programs and fragments in teletype , e.g., program p or expression tail(f x y) .The first definition, of form f x = e f , defines the program entry function (with one argument, alwaysnamed x ). A context-free grammar for programs, definitions and expressions e : p ::= def | p def -- Program = sequence of function definitionsdef ::= f x1...xm = e -- (where m >= 0)e ::= True | False | [] | xi | base | if e then e else e | f e1...embase ::= not e | null e | head e | tail e -- Base function call Data types: bits and bit lists. Variable and expression values are elements of one of the value sets { , } or list { , } ∗ . A string x ∈ { , } ∗ is a bit list, and list can be written [1,0,1,1] as datavalue. [] is the empty list, and b:bs is the result of prepending bit b to list bs . We sometimes identify with False and
True , resp. e.g., in the test position e0 of an expression if e0 then e1 else e2 . Expressions:
Expression e may be a constant; a variable; a base function call ( not , null , head , or tail ); a conditional if e0 then e1 else e2 ; or a call f e1...er to some program-defined function f . A program contains no CONS function or other constructors (hence CF for cons-free). Thus CF doesnot have successor, + , ∗ or explicit storage allocators such as malloc in C, :: in ML, or : in Haskell. Function definition:
A program-defined definition has form f x1 x2...xm = e with m ≥ . Nofunction may be defined more than once, left-side variables must be distinct, and any variable appearingon the right side (in e ) must be one of x1 ,. . . , xm . Semantics:
The semantics of CF is given by the inference rules in Figure 1. Given a program p and input x, these rules define a (unique) computation tree that we call T p , x . The inference rules definestatements [[ p ]]( x ) = v (at the root of the computation tree) or p , ρ ⊢ e → v. The p in p , ρ ⊢ e → v isa CF program. The e is a subexpression of the right side of some function definition. Further, ρ is an environment that binds the current program variables to respective argument values v , . . . , v m ; and v isthe result value of e . Base or defined function calls are evaluated using call-by-value. The full inference rule set is given in Figure 1. It is essentially the first-order part of Fig. 1 in [8].
Example 1
The CF program parity decides membership in the set X = { x ∈ { , } ∗ | | x | is even } . entry x = even xeven z = if (null z) then True else not(even(tail z)) This satisfies [[ parity ]]( x ) = True if | x | is even, else False . For example, [[ parity ]]([ , , ]) = False . T p , x and an evaluation order Evaluation steps:
The computation tree T p , x can be built systematically, applying the rules of Figure 1bottom-up and left-to-right. Initially we are given a known program p and input ∈ { , } ∗ , and thecomputation goal is [[ p ]]( input ) = ?, where ? is to be filled in with the appropriate value v (if it exists).Intermediate goals are of form p , ρ ⊢ e → ?, where p , ρ and e are known, and ? is again to be filled in. The larger language described in [8] encompasses both first and higher-order programs.
LOGSPACE and
PTIME
Axioms: p , ρ ⊢ x → ρ ( x ) p , ρ ⊢ True → True p , ρ ⊢ False → False p , ρ ⊢ [] → [] Base functions: p , ρ ⊢ e → Falsep , ρ ⊢ not e → Truep , ρ ⊢ e → Truep , ρ ⊢ not e → False p , ρ ⊢ e → [] p , ρ ⊢ null e → Truep , ρ ⊢ e → v : v p , ρ ⊢ null e → False p , ρ ⊢ e → v : v p , ρ ⊢ head e → v p , ρ ⊢ e → v : v p , ρ ⊢ tail e → v Condition: p , ρ ⊢ e → True p , ρ ⊢ e → v p , ρ ⊢ if e then e else e → v p , ρ ⊢ e → False p , ρ ⊢ e → v p , ρ ⊢ if e then e else e → v Function call: p , ρ ⊢ e → w . . . p , ρ ⊢ e m → w m p , [ x1 w , . . . , xm w m ] ⊢ e f → v if f x1 . . . xm = e f ∈ pp , ρ ⊢ fe . . . e m → v Program running: p , [ x input ] ⊢ e f → v If f x = e f is the entry function definition of p [[ p ]]( input ) = v Figure 1: Inference rules for CFAxioms have no premises at all, and base function calls have exactly one premise, making their treeconstruction straightforward. The inference rules for conditional expressions have two premises, and acall to an m -ary function has m + if e then e else e → ?, there are two possibly applicable inference rules. However bothpossibilities begin by evaluating e : finding v such that e → v . Once v is known, only one of the two if rules can be applied. Claim. the evaluation order above for given p and input is general: if [[ p ]]( input ) = v is deducible byany finite proof at all, then the evaluation order will terminate with result [[ p ]]( input ) = v at the root.A consequence: tree T p , x is unique if it exists, so CF is a deterministic language. (Nondeterministicvariants of CF will considered later.) CF programs have no constructors. This implies that all values occurring in the tree T p , x must be booleanvalues, or suffixes of the input. Expressed more formally: Definition 3
For program p and input x ∈ { , } ∗ , define its range of variation and its reachable calls byV x = { , } ∪ suffixes ( x ) and Reach p ( x ) = { ( f , ρ ) | e f is called at least once with environment ρ while computing [[ p ]]( x ) } Lemma 1
The computation tree T p , x is finite iff p terminates on input x. Lemma 2 If T p , x contains p , ρ ⊢ e → v then v ∈ V x and ρ ( z ) ∈ V x for every z ∈ domain ( ρ ) . ones, Bhaskar, Kop,Simonsen 69Proof: a straightforward induction on the depth of computation trees. If the entry function definitionis f x = e f , then the root [[ p ]]( x ) = v has a parent of the form p , ρ ⊢ e f → v where the initial environmentis ρ = [ x x ] . Of course x is a suffix of x . At any non-root node in the computation tree, any new valuemust either be a Boolean constant or [] , or constructed by a base function not , head , tail , or null from a value already proven to be in V x .Consequence: a CF computation has at most polynomially many different function call arguments . Lemma 3
For any CF program p there is a polynomial π ( | x | ) that bounds Reach p ( x ) for all x ∈ { , } ∗ . Proof: By Lemma 2, any argument of any m -ary p function f has at most V x = + | x | possible values,so the number of reachable argument tuples for f can at most be ( + | x | ) m . Remark: this does not necessarily imply that p ’s running time is polynomial in | x | . We say more onthis in Section 2. A CFTR program is a CF program p such that every function call occurring on the right side of anydefined function is in tail form . This is a syntactic condition; the semantic purpose is to enable a no-stackCFTR implementation, as outlined in Section 2.1. The operational intention is that if a call f e1...em is in tail form then, after the call has been performed, control is immediately returned from the currentfunction: there is “nothing more to do” after the call. Definition 4
Define function α : Exp → { X , T , N } as follows, where the set of descriptions is ordered byX < T < N. The intention: if expression e contains no function calls then α ( e ) = X , else if all functioncalls in e are in tail form then α ( e ) = T , else if e contains a function call in one or more non-tail-callpositions then α ( e ) = N. α ( e ) = X if e is a constant α ( base e ) = X if α ( e ) = X α ( base e ) = N if α ( e ) = T or α ( e ) = N α ( f e1 ... em ) = T if α ( e1 ) = . . . = α ( em ) = X α ( f e1 ... em ) = N otherwise α ( if e0 then e1 else e2 ) = max ( α ( e1 ) , α ( e2 )) if α ( e0 ) = X α ( if e0 then e1 else e2 ) = N otherwise
Definition 5
CF program p is in CFTR iff α ( e ) ∈ { X , T } for all function definitions f x1...xm = e . Some instances in the program parity , to clarify the definition:1. α ( null z ) = α ( tail z ) = X . Neither calls any program-defined functions.2. Expression even x is a call, and is in tail form: α ( even x ) = T .3. The expression even(tail z) is in tail form: α ( even ( tail z )) = T .4. The expression not(even(tail z)) is not in tail form: α ( not ( even ( tail z ))) = N .By point 4, parity is not a CFTR program. However the set X it decides can be decided by the followingalternative program whose recursive calls are in tail form. Thus X is
CFTR decidable.0 Cons-free Programs and Complexity Classes between
LOGSPACE and
PTIME
Example 2
Program parity ′ entry ′ x = f x Truef x y = if (null x) then y else f (tail x) (not y) A very useful result from [1] is the following: we can assume, without loss of generality, that a CFprogram contains no nested function calls such as f x1...xm = ...g(h(e))... . Lemma 4
For any CF program p there is a CF program p ′ such that [[ p ]] = [[ p ′ ]] , and for each functiondefinition f x1 ... xm = e f in p ′ , either α ( e f ) ≤ T , or e f = if e then e else e and α ( e i ) ≤ T fori ∈ { , , } . An interesting step in the proof of Lemma 4 is to show that a function f : X → Y is CF-computableif and only if its graph G f = { ( x , y ) ∈ X × Y | f ( x ) = y } is CF-decidable (see [1] for details). In a CFTRprogram, no function calls are allowed to occur in the test part of a tail-recursive conditional expression(by the last line of the α definition). Thus Lemma 4 does not rule out a call nested in a conditional’s testpart, and so does not imply that p ′ is tail-recursive.An example that suggests that some call nesting is essential: the MCV program of Section 2.3 hasfunction calls inside if tests. It is well-known that the function that MCV computes can be computedtail-recursively if and only if
LOGSPACE = PTIME [14].
Theorems 1 and 2 relate computations by two rather different computation models: cons-free programsand Turing machines. We now focus on time and space relations between the two. We define the timeand space used to run given CF program p on input x ∈ { , } ∗ : Definition 6 • time p ( x ) is the number of evaluation steps to run program p on x (as in Section 1.3). • space p ( x ) is the number of bits required to run p on input x. Both time p ( x ) and space p ( x ) are non-negative integers (or ⊥ for nontermination). We call time p ( x ) the“ native time ” for CF or CFTR (in contrast to Turing machine time). For the example, time parity ( x ) = O ( | x | ) . It is reasonably simple to define running time as time p ( x ) = | T p , x | , i.e., the number of nodes inthe computation tree T p , x .A full definition of space p ( x ) requires a lower-level execution model than the abstract semanticsabove. (Section 2.1 will show a bit more detail.) Consider the parity example. The length of the callstack needed to implement the program is linear in the depth of the proof tree, and so O ( | x | ) . Moreover,each non-root node has an environment ρ that binds x or z to its value. By Lemma 2 any such value is asuffix of the input. Any suffix can be represented in O ( log | x | ) bits, so the total space that parity uses is space parity ( x ) = O ( | x | log | x | ) To more clearly define space usage and present the tail call optimisation, we use a finer, more operationallevel of detail based on traditional implementations . Programs are executed sequentially as in the proof-tree-building algorithm seen earlier. The expression on the right side of a function definition is evaluated Readers may think of machine-code run-time states, e.g., value stacks, stack frames,. . . ; or of tapes and state transitionrelations. Such implementation paraphernalia are well-known both to compiler writers and programming language theorists. ones, Bhaskar, Kop,Simonsen 71one step at a time as in Section 1.3; but with an extra data structure, a stack σ used to record some ofthe environments seen before. The stack’s topmost activation record corresponds closely to the currentenvironment ρ .Each defined function f x1...xm = e has an activation record format that contains the values v , . . . , v m of the arguments with which f has been called (plus shorter-lived “temporary results,” i.e.,as-yet-unused subexpression values). On any call to f , a new activation record is pushed onto the stack σ . This activation record will be popped when control returns from the call. Definition 7
The call history for CF program p and input x ∈ { , } ∗ is a sequence (finite or infinite)of configurations , each of form ( f , ρ ) ∈ Reach p ( x ) where f is a defined function name and ρ is anenvironment. The first configuration always has form ( p − entry , [ z x [) . How the syntactic CFTR condition in Definition 5 allows more efficient implementation:
The tail call optimisation
Claim: every CFTR program can be implemented using at most one stack frame at a time.Suppose CF program p has a definition f x1...xr = ...(g e1...es)... where the g call is atail call. If so, then after the call (g e1...es) has been started there can be no future references tothe current values of x1,...,xr . Informally, there is “nothing more to do” after a tail call has beencompleted. (One can review the parity’ and parity examples in this light.)The tail call optimisation: The new activation record for g overwrites f ’s current activation record.In a CFTR program every call will be a tail call. Thus there is never more than one frame at a time inthe runtime stack. One stack frame requires O ( log | x | ) bits. For example, this gives parity ′ a majorimprovement over the space used by parity : space parity ′ ( x ) = O ( log | x | ) bits. A relaxation of the tail call restriction.
Sketch (details in [1]): It is sufficient that the functions definedin p can be given a partial order < such that no call is to another that is earlier in the order, and recursivecalls must be tail calls. Under this lighter restriction there may be more than one frame at a time in theruntime stack; but these frames are properly ordered by < . Consequently every restricted program canbe implemented within a constant depth of stack frames . Theorem 3
Any terminating CFTR program runs in (native) time polynomial in | x | . Proof: in the call history of p on input x , all runtime configurations must be distinct (else the program isin an infinite loop). There is a constant bound on the number of stack frames. Thus, by Lemma 3 thereare only polynomially many distinct runtime configurations. Theorem 4
A terminating run of a CF program can take time exponential in its input length.
First, a trivial example with non-polynomial running time (from [8]):
Example 3 f x = if (null x) then True elseif f(tail x) then f(tail x) else False
It is easy to see that time q ( x ) = O ( | x | ) due to the repeated calls to tail x . Exponential time is notnecessary, though, since the computed function satisfies f(x) = True .2 Cons-free Programs and Complexity Classes between LOGSPACE and
PTIME
PTIME -complete
MCV is the
Monotone Circuit Value Problem . Technically it is the set of all straight-line Boolean pro-grams whose last computed value is
True , e.g., x : = False ; x : = True ; x : = x ∨ x ; x : = x ∧ x ; x : = x ∨ x ; x : = x ∨ x MCV is a well-known “hardest” problem for
PTIME [14]. In complexity theory, completeness means twothings: (1)
MCV ∈ PTIME ; and (2) if X ⊆ { , } ∗ is any problem in PTIME , then X is logspace-reducible to MCV . By transitivity of logspace-reduction,
MCV ∈ LOGSPACE if and only if
LOGSPACE = PTIME .Following is the core of a Haskell program to decide membership in
MCV , together with a samplerun. We chose a compact Boolean program representation, so the program above becomes a list: program = [ OR 5 4 3, OR 4 3 2, AND 3 2 0, OR 2 1 0 ]
Haskell encoding:
Assignment x i : = x j ∧ x k is represented by omitting : = , and coding ∧ as AND in prefixposition (and similarly for ∨ ). The program is presented in reverse order; and variables X0, X1 alwayshave predefined values
False, True resp., so their assignments are omitted in the representation. type Program = [Instruction]data Instruction = AND Int Int Int | OR Int Int Intmcv :: Program -> Boolvv :: (Int,Program) -> Boolmcv ((OR lhs x y):s) = if vv(x,s) then True else vv(y,s)mcv ((AND lhs x y):s) = if vv(x,s) then vv(y,s) else Falsevv(0,s) = False -- vv(v,s) = value of variable v at program suffix svv(1,s) = True --vv(v,s) = case s of((AND lhs x y):s’) -> if v==lhs then mcv(s) else vv(v,s’)((OR lhs x y):s’) -> if v==lhs then mcv(s) else vv(v,s’)
This works by recursive descent, beginning at the end of the program; and uses no storage at all (beyondthe implicit implementation stack). Following is a trace of nontrivial calls to vv , ended by the final resultof running p . Note that variable X2 is evaluated repeatedly. program = [X5:=X4 OR X3, X4:=X3 OR X2, X3:=X2 AND X0, X2:=X1 OR X0]vv(X4,[ X4 := X3 OR X2, X3 := X2 AND X0, X2 := X1 OR X0])vv(X3,[ X3 := X2 AND X0, X2 := X1 OR X0])vv(X2,[ X2 := X1 OR X0])vv(X2,[ X3 := X2 AND X0, X2 := X1 OR X0])vv(X2,[ X2 := X1 OR X0])True Details may be found in [6], Chapters 25, 26. ones, Bhaskar, Kop,Simonsen 73
Re-expressing the Boolean program as a bit string for CF input
Of course CF programs do not have data values of type
Int . However, any straight-line Boolean programcan be coded by a CF bit string. Example: the Boolean program above can be coded as a 44-bit string : [1,1,1,0, 1,0,1, 0, 1,0,0, 0,1,1, -- x5 := OR x4 x31,0,0, 0, 0,1,1, 0,1,0, -- x4 := OR x3 x20,1,1, 1, 0,1,0, 0,0,0, -- x3 := AND x2 x00,1,0, 0, 0,0,1, 0,0,0] -- x2 := OR x1 x0 Bag of tricks: The program has 5 variables. The index i of any variable xi can be coded by a 3-bitbinary sequence we denote by ˆ i , e.g., x3 is coded by ˆ = . This has length 3 since 3 = ⌈ log ⌉ .The beginning of the program code gives (in unary) the code block length, 3 for this pro-gram. A Boolean assignment xi := xj op xk is coded as ˆ i ˆ op ˆ j ˆ k , where the Boolean operators ∨ , ∧ are coded as , respectively.Using this encoding, it is not hard to transform the Haskell-like program to use if-then-else statementsrather than case; and then implement it in the true CF language. A dramatic contrast in running times • The CF program just sketched has repeated (and nested) function calls with the same argumentvalues. For example, Boolean variable X2 in program p is evaluated 3 times in the trace above.More generally, the running time bound is exponential: time mcv ( x ) = O ( | x | ) • On the other hand, one can show that
MCV can be decided by a Turing machine in polynomialtime: Execute the Boolean instructions from the beginning, store the values of left side variableswhen computed, and refer to stored variable values as needed.This major difference is due to data storage: the Turing machine tape can save already-computed values,to be looked up as needed. A CF program has no such storage, and must resort to recomputation . Is this contrast necessary?
It seems strange that the cost of strengthening tail recursive programs (inCFTR) by adding recursion (to get CF) is to raise run times from polynomial to exponential. The nextsections, abbreviated from [8], show that the problem is a general one of the relation between
LOGSPACE and
PTIME . Thus it is not peculiar to the MCV problem, nor to the way we have programmed its solution.
LOGSPACE = and PTIME = are proven LOGSPACE = • For ⊇ , we simulate a CFTR program p by a LOGSPACE
Turing machine (informal). Given an input x = a . . . a n ∈ { , } ∗ , by Lemma 2 any reachable configuration ( f , ρ ) satisfies 0 ≤ | ρ ( xi ) | ≤ max ( n , ) for i = , . . . , m . Each v i can be coded in O ( log n ) bits. Now f and the number of f ’sarguments are independent of x , so an entire configuration ( f , ρ ) can be coded into O ( log n ) bits. The -- parts delimit comments, and are not part of the Boolean program’s bit-string encoding. Duplicating CF variables does not suffice, since the number of variables is independent of the length of the input data.
LOGSPACE and
PTIME
The remaining task is to show that the operational semantics of running p on x can be simulatedby a LOGSPACE
Turing machine. The key: because p is tail recursive, there is no nesting of callsto program-defined functions. The construction can be described by cases:1. Expressions without calls to any defined function: Suppose p ’s current environment ρ isrepresented on the Turing machine work tape. Simulating this evaluation is straighforward.2. Evaluation of an expression f e1...em : Since p is tail recursive, none of e1,...,em con-tains a call, and there is “nothing more to do” after the call f e1...em has been simulated.Assume inductively that e1...em have all been evaluated. Given the definition f x1...xm =e of f , the remaining steps are to collect the values v , . . . , v m construct a new environment ρ ′ = [ x1 v , . . . , xm v m ] , and replace the current ρ by ρ ′ . • For ⊆ , we simulate a LOGSPACE
Turing machine by a CFTR program. This can be done usingLemma 2: represent a Tape 2 value by one or more suffixes of x . (A more general result is shownin [8] by “counting modules”.) Remark: given an input x , the number of times that a call ( f , ρ ) appears in the call history of [[ p ]]( x ) maybe much larger than the number of such calls with distinct argument values , even exponentially larger. PTIME = • For ⊆ , we simulate a PTIME
Turing machine Z by a CF program. (this is the core of Proposition Z = ( Q , { , } , δ , q ) is given and that it runs in time atmost n k for inputs x of length n . Consider an input x = a a . . . a n ∈ { , } ∗ .Idea: in the space-time diagram of Z ’s computation on x (e.g., Fig. 3 in [8]), data propagationis local; the information (control state q , symbol a , whether or not it is scanned) at time t andtape position i is a mathematical function of the same information at time t − i − , i , i +
1. This connection can be used to compute the contents of any tape cell at any time.Repeating for t = , , . . . , n k steps gives the final result of the computation ( x is accepted or notaccepted).The simulating CF program computes functions state ( t ) = the state q that Z is in at time t position ( t ) = the scanning position i ∈ { , , , . . . , n k } at time t symbol ( t , i ) = the tape symbol a found at time t and scanning position i Initially, at time t = ( q , , τ ) where τ ( i ) = a i for 1 ≤ i ≤ n , else τ ( i ) = B .Now suppose t > t − ( q , i , τ ) , and that δ ( q , a ) = ( q ′ , a ′ , d ) . Thenthe total state at time t will be ( q ′ , i + d , τ ′ ) where τ ′ ( i ) = a ′ and τ ′ ( j ) = τ ( j ) if j = i .Construction of a CF program z with definitions of state , position and symbol is straight-forward. Arguments t , i ∈ { , , , . . . , n k } can be uniquely encoded as tuples of suffixes of x = These steps are done using Turing machine representations of the environments as coded on Tape 2. As usual Q is a finite set with initial state q , and transition function of type δ : Q × { , , B } → Q × { , , B } × { , , − } .A total state is a triple ( q , i , τ ) where q ∈ Q , i ≥ τ : N → { , , B } . Scan positions are counted i = , ,... fromthe tape left end. Transition δ ( q , a ) = ( q ′ , a ′ , d ) means: if Z is in state q and a = τ ( i ) is the scanned tape symbol, then changethe state to q ′ , write a ′ in place of the scanned symbol, and move the read head from its current position i to position i + d . ones, Bhaskar, Kop,Simonsen 75 a a . . . a n ∈ { , } ∗ . It is not hard to see that such an encoding is possible; [8] works out detailsfor an imperative version of the Turing machine (cf. Fig. 5). • For ⊇ , we simulate an arbitrary CF program p by a PTIME
Turing machine (call it Z p ). We describethe Z p computation informally. Given an input x ∈ { , } ∗ , Z p will systematically build a cache containing Reach p ( x ) . By Lemma 3 its size is polynomially bounded.The cache (call it c ) at any time contains a set of triples ( f , ρ , v ′ ) where the simulator has completedevaluation of function f on argument values in environment ρ , and this f call has returned value v .Concretely, c is built “breadth-first”: when a p call f e1...em is encountered (initially c is empty): – First, arguments e1,...,em are evaluated to values v , . . . , v m ; and these are collected intoan environment ρ . – Second, cache c is searched. If it contains ( f , ρ , v ) , then simulation continues using the value v as the value of f e1...em . – If c contains no such triple, then p must contain a function definition f x1...xm = e f . Thenexpression e f is evaluated in environment ρ to yield some value v . After finishing, add thetriple ( f , ρ , v ) to c , and return the value v . An observation:
The CF program of Section 3.2 (simulating a polynomial time Turing machine) hasexponential runtime.
Paradoxically, as observed in Section 2.2: even though CF exactly characterises
PTIME , its programs donot run in polynomial time. The polynomial versus exponential contrast between the running times ofCFTR and CF programs is interesting since both program classes are natural; and the decision powers of CFTR and CF are exactly the complexity classes
LOGSPACE and
PTIME . Alas, we have found no CFalgorithm to simulate polynomial-time Turing machines. We explain how this happens in more detail.
Definition 8
Call overlap occurs if a CF program can call the same function more than once with thesame tuple of argument values.
How can this happen?
By Lemma 3, only polynomially many argument tuples are distinct. Conse-quently, superpolynomial running time implies that some simulation functions may be called repeatedlywith the same argument value tuples, even though only polynomially many of them are distinct.This can be seen in the proof that
PTIME ⊇ : the value of symbol ( t + , i ) may depend on thevalues of symbol ( t , i − ) , and symbol ( t , i ) , and symbol ( t , i + ) . In turn, the value of symbol ( t , i ) maydepend on the values of symbol ( t − , i − ) , and symbol ( t − , i ) , and symbol ( t − , i + ) .Net effect: a symbol a i on the final tape (with t = n k ) may depend many distinct function call se-quences that “bottom out” at t =
0. The number of call sequences may be exponential in n . Lemma 5
Call overlap will occur if the length of the call history for [[ p ]]( x ) is greater than Reach p ( x ) . Unfortunately, it is is hard to see which calls will overlap (it seems impossible without storage). Further-more, the “caching” technique used to prove Theorem 2 cannot be used because, in contrast with Turingmachines, CF programs do not have a memory that can accumulate previously computed values.
Viewed extensionally , the difference (if any) between CFTR and CF corresponds to the difference (ifany) between
LOGSPACE and
PTIME . Viewed intensionally , there seem to be significant differences, e.g.,in algorithm expressivity as well as in running time. A relevant early result:6 Cons-free Programs and Complexity Classes between
LOGSPACE and
PTIME
A program transformation by Greibach shows that programs whose calls (to defined functions) areall linear can be made tail recursive [4]. Using this transformation, a CF program p whose calls aretail calls or linear calls may be transformed into one containing only tail calls (and no CONS or otherconstructors), so it is in CFTR. Thus p decides a problem in LOGSPACE .There is a price to be paid, though: in general, the transformed program may run polynomiallyslower than the original , due to re-computation. For instance, the Greibach method can transform ourfirst “parity” program into CFTR form. The cost: to raise time complexity from linear to quadratic.Following is a new tool to investigate the problem. It is analogous to the set of programs for polynomial-time Turing machines, but adapted to the CF world. By Theorem 4, CFpoly ( CF.
Definition 9
The programming language CFpoly has the same semantics as CF; but CFpoly’s programsare restricted to be those CF programs that terminate in polynomial time . Immediate:
LOGSPACE = ⊆ {{
CFpoly }} ⊆ = PTIME
By Theorem 3, every terminating CFTR program is in CFpoly. One can see Greibach’s result as trans-forming a subset of CFpoly into CFTR.
Lemma 6
If a terminating CF program does not have call overlap, then it is in CFpoly.
The reason: by Lemma 3, such a CF program must run in polynomial time.
Remark:
On the other hand, it may have non-tail calls, and so not be in CFTR.
Lemma 7
Problem class is closed under ∪ , ∩ and complement. Nondeterministic programs allow expression evaluation and program runs to be relations ( ❀ ) rather thanfunctions. A nondeterministic version of Figure 1 would use [[ p ]]( x ) ❀ v and p , ρ ⊢ e ❀ v in place of [[ p ]]( x ) → v and p , ρ ⊢ e → v . Alas, the algorithm of Section 1.3 cannot be used if p is nondeterministic. Definition 10
A set X ⊆ { , } ∗ is decided by an NCF program p if for all inputs x ∈ { , } ∗ ,x ∈ X if and only if p has a computation [[ p ]]( x ) ❀ True
Remark: the reasoning used in Theorem 3 clearly extends to show that
NLOGSPACE = . Thefollowing is particularly interesting since the question LOGSPACE =? NLOGSPACE is still open.
Theorem 5 = A call is linear if it is not contained in a call to any defined function. An example with a linear call that is not a tail call: not(even(tail z)) in Section 1.5. ones, Bhaskar, Kop,Simonsen 77This was proven by Bonfante [2] by a technique that stems back to in Cook [3]. The implication isthat is closed under nondeterminism, since both problem classes are equal to PTIME . (This does not imply
PTIME = NPTIME , since it is not hard to see that any NCF program can be simulated by adeterministic polynomial-time Turing machine: Lemma 3 holds for NCF as well as for CF.)However it is not known whether is closed under nondeterminism, since Bonfante andCook’s reasoning does not seem to apply. Why? The memoisation used in [2] yields a Turing machine polynomial time algorithm. Consequently, the problem is decidable by some CF program; but we knowno way to reduce its time usage from exponential to polynomial.
A “devil’s advocate” remark: by Theorem 2 the classes and NLOGSPACE are both between
LOGSPACE and
PTIME : LOGSPACE = ⊆
NLOGSPACE ⊆ = PTIME
So why bother with yet another class? One answer: CFpoly seems more natural than NCFTR from aprogramming viewpoint; and intuitively seems to be a larger extension of LOGSPACE than
NLOGSPACE or the program class NCFTR. However we have no proof that
NLOGSPACE = ,and no solid reason to think that either class contains the other. Theorem 6 ⊆
NSPACE(log n)). Proof: If p ∈ CFPoly, there is a polynomial π such that for any input x ∈ { , } ∗ one can decide, in time π ( | x | ) , whether or not [[ p ]]( x ) → v . The question: can this be done in significantly less space? We answer“yes”. The proof uses a space-economical nondeterministic algorithm to find v at the root [[ p ]]( x ) = v oftree T p , x . First, observe that any reachable statement p , ρ ⊢ e → w can be represented in O ( log n ) bits. • To evaluate p on input x , we nondeterministically guess a value v such that [[ p ]]( x ) = v . Theremaining task is to confirm that this statement is true. If we cannot do that, the whole algorithmhas failed. • To confirm a statement such as p , ρ ⊢ f e → v , we must confirm the existence of an evaluation treeof the form: . . . p , ρ ⊢ e → w . . . p , [ x w ] ⊢ e f → v p , ρ ⊢ f e → v To do this, we now guess w ∈ V x , and now need to confirm two statements. We also guess whichof these two statements has the shortest evaluation tree.For example, suppose we guess that this is the case for p , [ x w ] ⊢ e f → v . Then we do a recursivecall to confirm this statement (which temporarily stores the current state on the algorithm’s stack).Afterwards, we tail-recursively confirm the other statement, p , ρ ⊢ e → w . Since this is a tail call,the algorithm’s stack size does not increase. • This extends naturally to multi-argument function calls. • To confirm a statement p , ρ ⊢ if e then e else e → v , we guess whether e reduces to True orFalse; for example, we guess that it reduces to False. Then it suffices to confirm that an evaluationtree of the following form exists:8 Cons-free Programs and Complexity Classes between LOGSPACE and
PTIME . . . p , ρ ⊢ e → False . . . p , ρ ⊢ e → v p , ρ ⊢ if e then e else e → v For this, we again have to confirm two statements. As before, we guess which of the two statementshas the shorter evaluation tree, evaluate that statement first, and then evaluate the other statementtail-recursively.If all guessed values are correct, then this algorithm returns the correct result. Furthermore, if we alwaysguessed correctly which statement has the shortest evaluation tree, it does so with an overall stack depththat is never more than log( | T p , x | ). The reason is that every time we do a non-tail recursive call, thisshortest subtree has size at most half of the previous subtree’s size. Since a statement p , ρ ⊢ e → w canbe represented in O ( log n ) bits we have the desired result.The idea of applying tail-recursion to the largest subtree to save space was also used to implementQuicksort [9]. However our problem is much more general; and we must use nondeterminism because itcannot be known in advance which subtree will be the largest.We expect that this construction can be extended to show ⊆
NSPACE ( log n ) as well. The following was shown by a subtle nondeterministic state-enumeration and state-counting algorithm.It was devised independently by Immerman and Szelepcs´enyi, and solved Kuroda’s second and long-standing open question [11, 5, 16]. It is still open whether
LOGSPACE ( NLOGSPACE . Theorem 7
NLOGSPACE is closed under complement.
We have probed the question
LOGSPACE =? PTIME from a programming language viewpoint. A startingpoint was that the “cons-free” programming language CF exactly captures the Turing complexity class
PTIME ; while its cons-free tail recursive subset CFTR exactly captures
LOGSPACE . Section 3 recapitu-lates the reasoning used in [8].In more detail: all CFTR programs run in polynomial time; but on the other hand, some CF programsrun for exponentially many steps. Further the sets decided by the two program classes have seeminglydifferent closure properties: the questions
LOGSPACE =? NLOGSPACE and
PTIME =? NPTIME andeven
LOGSPACE =? PTIME have been open for decades. Given this, it seems almost paradoxical that = (from [2]).Trying to understand these differences made it natural to consider CFpoly - the class of polynomiallytime-bounded CF programs since they have feasible running times (even though some CF programsmay have superpolynomial behavior=. One test of CFpoly was to see whether it contained any PTIME -complete problems. As a case study we wrote (Section 2.3) a CF-program for MCV (the monotone circuitvalue) problem to clarify where non-tail-recursion was necessary, and where superpolynomial runtimescame into the picture. (One key was nested recursion in function calls, clearly visible in function mcv inthe MCV code.) Another test was to see whether is perhaps a smaller complexity class than PTIME . Theorem 6 leads in this direction, with an interesting proof construction and the surprising upperbound
NSPACE ( log n ) .Many questions for CFpoly are still to be investigated. One is to see whether the Immerman-Szelepcsenyi algorithm can be adapted to NCFpoly.ones, Bhaskar, Kop,Simonsen 79 References [1] Siddharth Bhaskar & Jakob G. Simonsen (2020):
Implicit Complexity via Controlled Construction and De-struction . Technical Report, Department of Computer Science, University of Copenhagen.[2] Guillaume Bonfante (2006):
Some Programming Languages for Logspace and Ptime . In Michael Johnson& Varmo Vene, editors: Algebraic Methodology and Software Technology, 11th International Conference,AMAST 2006,Kuressaare,Estonia, July5-8,2006,Proceedings, LectureNotesin ComputerScience 4019,Springer, pp. 66–80, doi:10.1007/11784180 8.[3] Stephen A. Cook (1971):
Characterizations of Pushdown Machines in Terms of Time-Bounded Computers .J.ACM 18(1), pp. 4–18, doi:10.1145/321623.321625.[4] Sheila A. Greibach (1975):
Theory of Program Structures: Schemes, Semantics, Verification . LectureNotesinComputerScience 36, Springer, doi:10.1007/BFb0023017.[5] Neil Immerman (1988):
Nondeterministic Space is Closed Under Complementation . SIAMJ.Comput.17(5),pp. 935–938, doi:10.1137/0217058.[6] Neil D. Jones (1997):
Computability and complexity - from a programming perspective . Foundations ofcomputing series, MIT Press, doi:10.7551/mitpress/2003.001.0001.[7] Neil D. Jones (1999):
LOGSPACE and PTIME Characterized by Programming Languages . Theor.Comput.Sci. 228(1-2), pp. 151–174, doi:10.1016/S0304-3975(98)00357-0.[8] Neil D. Jones (2001):
The expressive power of higher-order types or, life without CONS .J. Funct. Program. 11(1), pp. 55–94, doi:10.1017/S0956796800003889. Available at http://journals.cambridge.org/action/displayAbstract?aid=68581 .[9] Donald E. Knuth (1973):
The Art of Computer Programming, Volume III: Sorting and Searching . Addison-Wesley.[10] Cynthia Kop & Jakob Grue Simonsen (2017):
The Power of Non-determinism in Higher-Order Implicit Com-plexity - Characterising Complexity Classes Using Non-deterministic Cons-Free Programming . In HongseokYang, editor: Programming Languages and Systems - 26th European Symposium on Programming, ESOP2017, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2017,Uppsala,Sweden,April22-29,2017,Proceedings, LectureNotesinComputerScience 10201, Springer, pp.668–695, doi:10.1007/978-3-662-54434-1 25.[11] Sige-Yuki Kuroda (1964):
Classes of languages and linear-bounded automata . Information and Control7(2), pp. 207–223, doi:10.1016/S0019-9958(64)90120-2.[12] John McCarthy (1960):
Recursive Functions of Symbolic Expressions and Their Computation by Machine,Part I . Commun.ACM 3(4), pp. 184–195, doi:10.1145/367177.367199.[13] Yiannis Moschovakis (2019):
Abstract Recursion and Intrinsic Complexity . Cambridge University Press(Lecture Notes in Logic), doi:10.1017/9781108234238.[14] Christos H. Papadimitriou (1994):
Computational complexity . Addison-Wesley.[15] Walter J. Savitch (1970):
Relationships Between Nondeterministic and Deterministic Tape Complexities . J.Comput.Syst.Sci. 4(2), pp. 177–192, doi:10.1016/S0022-0000(70)80006-X.[16] R´obert Szelepcs´enyi (1988):
The Method of Forced Enumeration for Nondeterministic Automata . Acta Inf.26(3), pp. 279–284, doi:10.1007/BF00299636.[17] Alan M. Turing (1936-7):