Languages and Models of Computation

Similar documents
14.1 Encoding for different models of computation

Theory of Programming Languages COMP360

Chapter 11 :: Functional Languages

Lexical Analysis. Lexical analysis is the first phase of compilation: The file is converted from ASCII to tokens. It must be fast!

Turing Machines. A transducer is a finite state machine (FST) whose output is a string and not just accept or reject.

Languages and Compilers

Optimizing Finite Automata

Limitations of Algorithmic Solvability In this Chapter we investigate the power of algorithms to solve problems Some can be solved algorithmically and

Finite Automata. Dr. Nadeem Akhtar. Assistant Professor Department of Computer Science & IT The Islamia University of Bahawalpur

Variants of Turing Machines

Introduction to Computers & Programming

Chapter 3: Lexing and Parsing

ECS 120 Lesson 16 Turing Machines, Pt. 2

Theory of Languages and Automata

Automata & languages. A primer on the Theory of Computation. The imitation game (2014) Benedict Cumberbatch Alan Turing ( ) Laurent Vanbever

Computer Sciences Department

Turing Machine Languages

Programming Languages Third Edition

Alternation. Kleene Closure. Definition of Regular Expressions

ECS 120 Lesson 7 Regular Expressions, Pt. 1

1. Draw the state graphs for the finite automata which accept sets of strings composed of zeros and ones which:

CS 125 Section #4 RAMs and TMs 9/27/16

Finite Automata Theory and Formal Languages TMV027/DIT321 LP4 2016

1 Lexical Considerations

DEMO A Language for Practice Implementation Comp 506, Spring 2018

Chapter 3. Describing Syntax and Semantics

CT32 COMPUTER NETWORKS DEC 2015

Decidable Problems. We examine the problems for which there is an algorithm.

4/19/2018. Chapter 11 :: Functional Languages

Lexical Analysis. COMP 524, Spring 2014 Bryan Ward

This is already grossly inconvenient in present formalisms. Why do we want to make this convenient? GENERAL GOALS

CSE 105 THEORY OF COMPUTATION

The SPL Programming Language Reference Manual

6.080 / Great Ideas in Theoretical Computer Science Spring 2008

for (i=1; i<=100000; i++) { x = sqrt (y); // square root function cout << x+i << endl; }

Functional Languages. Hwansoo Han

Handout 9: Imperative Programs and State

Theory of Computations Spring 2016 Practice Final Exam Solutions

Lec-5-HW-1, TM basics

Theory Bridge Exam Example Questions Version of June 6, 2008


Programming Language Pragmatics

Material from Recitation 1

Regular Expressions. Agenda for Today. Grammar for a Tiny Language. Programming Language Specifications

Properties of Regular Expressions and Finite Automata

for (i=1; i<=100000; i++) { x = sqrt (y); // square root function cout << x+i << endl; }

Lecture 4: Syntax Specification

This book is licensed under a Creative Commons Attribution 3.0 License

1. [5 points each] True or False. If the question is currently open, write O or Open.

Formal Languages and Compilers Lecture IV: Regular Languages and Finite. Finite Automata

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

MIT Specifying Languages with Regular Expressions and Context-Free Grammars. Martin Rinard Massachusetts Institute of Technology

MIT Specifying Languages with Regular Expressions and Context-Free Grammars

CISC 4090 Theory of Computation

Ambiguous Grammars and Compactification

CS5371 Theory of Computation. Lecture 8: Automata Theory VI (PDA, PDA = CFG)

CMSC 132: Object-Oriented Programming II

CS402 - Theory of Automata Glossary By

Formal Languages and Compilers Lecture VI: Lexical Analysis

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 5

Regular Expressions & Automata

COMP Logic for Computer Scientists. Lecture 25

1 Parsing (25 pts, 5 each)

Part 5 Program Analysis Principles and Techniques

Full file at

Last lecture CMSC330. This lecture. Finite Automata: States. Finite Automata. Implementing Regular Expressions. Languages. Regular expressions

CS402 Theory of Automata Solved Subjective From Midterm Papers. MIDTERM SPRING 2012 CS402 Theory of Automata

Lexical Considerations

Lecture 2 Finite Automata

Recursively Enumerable Languages, Turing Machines, and Decidability

TAFL 1 (ECS-403) Unit- V. 5.1 Turing Machine. 5.2 TM as computer of Integer Function

1. Lexical Analysis Phase

Regular Languages and Regular Expressions

CPS122 Lecture: From Python to Java last revised January 4, Objectives:

Chapter 3: CONTEXT-FREE GRAMMARS AND PARSING Part2 3.3 Parse Trees and Abstract Syntax Trees

CSE 105 THEORY OF COMPUTATION

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Compiler Design

Definition: A context-free grammar (CFG) is a 4- tuple. variables = nonterminals, terminals, rules = productions,,

6.001 Notes: Section 8.1

Formal languages and computation models

Theory and Compiling COMP360

CSE 105 THEORY OF COMPUTATION

CS21 Decidability and Tractability

CS 275 Automata and Formal Language Theory. First Problem of URMs. (a) Definition of the Turing Machine. III.3 (a) Definition of the Turing Machine

2 nd Week Lecture Notes

Concepts Introduced in Chapter 3. Lexical Analysis. Lexical Analysis Terms. Attributes for Tokens

CSEP 501 Compilers. Languages, Automata, Regular Expressions & Scanners Hal Perkins Winter /8/ Hal Perkins & UW CSE B-1

University of Nevada, Las Vegas Computer Science 456/656 Fall 2016

Lexical Analyzer Scanner

Lecture 5: The Halting Problem. Michael Beeson

Midterm Exam II CIS 341: Foundations of Computer Science II Spring 2006, day section Prof. Marvin K. Nakayama

(a) R=01[((10)*+111)*+0]*1 (b) ((01+10)*00)*. [8+8] 4. (a) Find the left most and right most derivations for the word abba in the grammar

Specifying Syntax COMP360

PS3 - Comments. Describe precisely the language accepted by this nondeterministic PDA.

Lexical Considerations

Lexical Analyzer Scanner

COMP 382: Reasoning about algorithms

Midterm Exam. CSCI 3136: Principles of Programming Languages. February 20, Group 2

Structure of Programming Languages Lecture 3

UNIT -2 LEXICAL ANALYSIS

Transcription:

Computer Science 52 Languages and Models of Computation Spring Semester, 2018 Computer scientists use languages in (at least) two ways. They design and use programming languages, and they study formal languages tolerant about the nature of computation. In these notes, we look at both kinds of languages. We will see how programming languages are specified and processed, and we will see models of computation that operate on languages and give us information about computations. Contents I EBNF Notation 1 II Deterministic finite automata 4 III Nondeterministic automata 5 IV Regular and non-regular languages 6 V Operations on Languages 7 VI Regular Expressions 8 VII Context-free Grammars 9 VIII Turing Machines 9 IX The Church-Turing Thesis 11 X Self-reproducing Programs 12 XI Universal Turing Machines 13 XII The Halting Problem 14 2018 Everett L. Bull, Jr. All rights reserved

computer science 52, languages and models of computation 1 I EBNF Notation Extended Bachus-Naur Notation, abbreviated EBNF, is a compact way to specify the precise syntax of a programming language. Here is a simple example that shows how we write integers. A number, denoted N here, is a sequence of symbols, optionally starting with a plus or minus sign. Then there is a digit, followed optionally by zero or more digits. N ::= [+ ] D{D} D ::= 0 1 2... 9 The square brackets [ ] indicate optional material. The vertical bar stands for or. The curly braces { } mean repeated zero or more times. In this example, the variable N is eventually replaced by a (correctly-formed) string of symbols chosen from +,, and the ten digits. More completely, an EBNF specification is composed from the following components. Variables for substitution. We normally use single uppercase letters or short words enclosed in angle brackets. Final values. For us, they will be ordinary letters, words, digits, and punctuation marks. The symbol, denoting or. The square brackets [ ], surrounding optional material. The curly brackets { }, surrounding material that is repeated zero or more times. Parentheses ( ), used for grouping. Single quotation marks, used to indicate material that should be taken as final and not interpreted as part of the EBNF specification. An EBNF specification is a collection of clauses of the form variable ::= expression with symbols above The idea is that one can repeatedly substitute expressions into variables until there are no variables left. The process is called derivation, and it produces a string of symbols that obeys the EBNF specification for the language. Here is a simple example that derives the string +253 using the specification given above for numbers. N [+ ] D{D} + D{D} + 2{D} + 253 substitute for N choose an optional plus sign specify a digit for D specify two more digits for the repeated D

computer science 52, languages and models of computation 2 Here is an example of a more realistic EBNF specification. It describes statements in a rudimentary programming language. A statement can have one of five types: empty, assignment, compound, loop, or conditional. stmt ::= empty asgt comp loop cond empty ::= ; asgt ::= vbl = arith ; comp ::= { { stmt } } loop ::= while ( test ) stmt cond ::= if ( test ) stmt [else stmt ] vbl ::=... arith ::=... test ::=... We see that the empty statement is simply a lone semicolon. An assignment statement is a variable, followed by an equal sign, then an arithmetic expression, and finally a semicolon. A compound statement is a sequence of zero or more statements surrounded by curly braces. Notice in that specification that we are using curly braces in two ways: one to indicate repetition and another (with the single quotation marks) to indicate the delimiters that are part of the compound statement itself. The loop and conditional statement begin with the keywords while and if, and the conditional statement has an optional else part. We do not specify here what a variable, an arithmetic expression, or boolean test is, but it would not be hard to fill in the details. If we chose to, we could extend these clauses to form a complete specification for a Java method. We would need clauses to specify variable declarations. The final specification would have some header material followed by a compound statement. As another example, here is a specification for a version of the language of boolean expressions we used in an earlier assignment. boolexp ::= false true prop ( boolexp ) ( boolexp & boolexp ) ( boolexp boolexp ) ( boolexp boolexp ) ( boolexp boolexp ) ( boolexp boolexp ) prop ::= P digit { digit } digit ::= 0 1 2... 9 One difficulty with this specification is that it insists formulas be fully parenthesized, with one pair of parentheses for each operator. There is no ambiguity in evaluating such a formula, but formulas can be very hard to read. Compare (( (p 0 & p 1 )) (( p 0 ) ( p 1 ))) with (p 0 & p 1 ) p 0 p 1.

computer science 52, languages and models of computation 3 We can specify our hierarchy of operations by increasing the number of clauses. boolexp ::= impl { impl } impl ::= xor [ impl ] xor ::= disj { disj } disj ::= conj { conj } conj ::= neg {& neg } neg ::= [ ] neg postneg postneg ::= false true prop ( boolexp ) prop ::= P digit { digit } digit ::= 0 1 2... 9 Each connective appears in this grammar exactly once. The specifications are mutually recursive, and they allow us to create a mutually recursive collection of functions to process the strings in the language. Notice that the clause for implication has a structure that differs from the clauses for the other binary connectives. The reason for that is that we consider implication to be right associative. The formula A B C means A (B C) and not (A B) C. All the other binary boolean connectives are left associative. The EBNF specification allows us to derive boolean formulas. Starting with boolexp, we can derive the formula (p 0 & p 1 ) p 0 p 1 in a sequence of steps, each one relying on one of the EBNF clauses. The sequence on the right gives an approximation to the first half of the derivation. By the end of that sequence we have produced the symbols in the formula up to and including. The derivation can also be considered as a tree. A portion of the derivation tree for (p 0 & p 1 ) p 0 p 1 appears on the left in Figure 1. The derivation tree contains lots of extraneous substitutions and can be refined into a syntax tree like the ones we saw in a previous assignment. The complete, simpler tree appears on the right in Figure 1. The tree representation makes it easy to write code to manipulate and evaluate boolean expressions. The process of producing the derivation from the formula is called parsing. Having an EBNF specification that respects the hierarchy of operations and the associativity conventions makes it possible to parse a formula as we read it from left to right. With a carefully-constructed EBNF specification, there is never any doubt about which clause to use next. The syntax tree is easily recovered from the derivation and is the valuable result of the parse. You will investigate parsing in one of our assignments. boolexp impl { impl } xor { impl } disj { impl } conj { impl } neg { impl } neg { impl } postneg { impl } ( boolexp ) { impl } ( impl ) { impl } ( xor ) { impl } ( disj ) { impl } ( conj ) { impl } ( neg & neg ) { impl } ( prop & neg ) { impl } ( P0 & neg ) { impl } ( P0 & prop ) { impl } ( P0 & P1 ) { impl } ( P0 & P1 ) impl

computer science 52, languages and models of computation 4 boolexp impl... xor disj conj neg neg postneg ( boolexp ). (p 0 & p 1 ) p 0 p 1 6 6 6 & 6 6 6 6 6 6 6 p 0 p 1 p 0 p 1 Figure 1: Two trees arising from a formula. The one on the left is part of the derivation tree from the EBNF specification. It can be refined into the complete syntax tree on the right. II Deterministic finite automata We now turn to a more abstract context with simpler languages. We start with a finite alphabet, A. In examples, we often use an alphabet with only two symbols, like a and b or 0 and 1. In real life, the alphabet is the full alphabet or a computer system s character set. A deterministic finite automaton, abbreviated DFA, consists of a finite set Q of states, one of which is designated as the start state q 0 ; a subset F of Q of final states; and a transition function δ : Q A Q. The idea is that our automaton processes a string of alphabet symbols, one at a time. It begins in the start state, and each time it processes a character, it moves to a (possibly different) state as determined by the transition function. The deterministic part is that the new state is determined solely by the current state and the symbol. A string is accepted if, after processing the string, the machine is in a state in F. Otherwise, the string is rejected. The language accepted by the DFA is the set of all accepted strings. We can represent a DFA by a diagram with arrows labeled by alphabet letters, like the one in Figure 2. Starting in the start state, the one with a triangle, we process a string of characters from left to right. At each

computer science 52, languages and models of computation 5 step, we follow the arrow labeled by the current character. If, after following an arrow for each character, we end up in a final state, we accept the string. The diagram shows a DFA which accepts the strings that start and end with a. a b q0 a b q1 b a b a q2 Figure 2: A DFA over the two-letter alphabet accepting strings that begin and end with a. The start state is q 0 ; the only final state is q 1. q3 More formally, let A be the set of all strings composed of letters from the alphabet A. It includes the empty string, denoted λ. The transition function δ takes states and characters into states. We can define a new function δ from states and strings into states using recursion; it is easy to imagine transforming this definition into an SML function. Consider a string to be empty or to consist of a first character c and a rest of string s. δ (q, λ) = q δ (q, c s) = δ (δ(q, c), s) A language over the alphabet A is a set of strings composed of letters from A. In other words, it is a subset of A. The language accepted by the DFA with transition function δ is { t A δ (q 0, t) F }. III Nondeterministic automata A nondeterministic finite automaton, abbreviated NFA, is one that may make guesses as it processes characters. More precisely, its transition function gives not a single new state but a set of possibilities. There may be several arrows out of a state, all labeled with the same character. Or there may be a state with no outward arrow labeled with a particular character. Let P(Q) be the set of subsets of Q, and consider a transition function of the form δ : Q A P(Q). If the automaton is in state q and encounters a symbol c, then δ(q, c) is the set of possible next states. One can think of the new state

computer science 52, languages and models of computation 6 as being chosen randomly from the set. The set may have just one element, in which case there is no choice; or the set may even be empty, in which case there is no new state and the automaton freezes up. We can define a function that gives us the set of possible states of the automaton after processing a string. It is a function that takes a set of states and a string and produces a set of states. δ (R, λ) = R δ (R, c s) = q R δ (δ(q, c), s) An NFA accepts the string t if δ ({q 0 }, t) contains an element of F. A string is accepted if there is one sequence of guesses that results in a final state. It is rejected if there is no way to get into a final state after processing the string. Nondeterministic automata are useful because they are often simpler and more compact. The NFA in Figure 3 accepts the language of all strings that end with bbb. b a q0 b b q1 q2 q3 b Figure 3: An NFA over the two-letter alphabet accepting strings that end with bbb. A DFA accepting the same language would have more states or more transitions. A DFA is a special kind of NFA, so a language that can be accepted by a DFA is also accepted by a DFA. It is also true that a language that is accepted by a NFA is accepted by a DFA. To see that, transform transform a nondeterministic automaton into a deterministic one that accepts the same states. Given an NFA, construct a DFA whose states are sets of the NFA s states, and define a transition function similar to the one above. IV Regular and non-regular languages A language (that is, a set of strings over some alphabet) is regular if it is accepted by some finite automaton. We have seen that a language accepted by an NFA is also accepted by a DFA, so we can say that a language is regular if it is accepted by a DFA. Are there languages that are not regular? Yes. A common example is the language of balanced parentheses. The string ()((())()) is in that language, while )() is not. Most programming languages are not regular because they insist, among other things, that parentheses be balanced. Another example of a non-regular language is given in one of the assignments.

computer science 52, languages and models of computation 7 To see how one might determine that a language is not regular, suppose that we have a language and a DFA that accepts it. Consider how the DFA processes strings. If two strings, t and u, end up in the same state and we append the same suffix x to each of them, then the new strings tx and ux are also in the same state. We know that the two strings t and u are in different states if we can find a suffix x such that one of tx and ux is accepted and the other is rejected. When this occurs, we say that we can distinguish between t and u. Notice that distinguishing depends only on the language being accepted and is independent of the particular DFA. Given a language L, we say that a pair of strings t and u is distinguishable if there is another string x such that tx is in L and ux is not, or vice versa. We have the following theorem. Regular Language Theorem. A language L is regular if and only if there is no infinite set of pairwise distinguishable strings. Here is a sketch of one direction of the proof: If a language is regular, it is accepted by some DFA with n states. Suppose that we have a set of strings with more than n elements. Each string is processed by the DFA into some state, and since there are more strings than states, two strings must end up in the same state. (This is an application of the famous Pigeon Hole Principle.) Those two strings are indistinguishable. Therefore, any pairwise indistinguishable set can have at most n elements and must be finite. The proof of the converse requires equivalence relations, which are covered in another class. We can now see why the language of balanced parentheses is not regular. Let p j be the string consisting of exactly j left parentheses. If j k, then p j and p k are distinguishable because, when r is the string of j right parentheses, p j r is in the language and p k r is not. The set of all p j s is an infinite pairwise distinguishable set. V Operations on Languages Keep in mind that a language is a set of strings over some alphabet. If L 0 and L 1 are languages over the same alphabet A, then their concatenation L 0 L 1 is the set of all strings that can be formed by joining an element of L 0 and an element of L 1. In symbols, L 0 L 1 = { st s is in L 0 and t is in L 1 }. As a simple example, suppose that A has two letters, a and b. Let L a be the language of strings that consist of one or more a s, and let L b be the language of strings that consist of one or more b s. Then L a L b is

computer science 52, languages and models of computation 8 the language of strings that have a block of a s followed by a block of b s. The strings ab and aabbbb are in L a L b, but λ, b, and aaba are not. The union L 0 L 1 of two languages is the language that contains all the strings from L 0 together with all the strings from L 1. L 0 L 1 = { s s is in L 0 or s is in L 1 } Following our simple example above, L a L b is the set of non-empty strings that have only one of the letters. If L is a language, then we can concatenate it with itself repeatedly. L 0 = {λ} L k+1 = LL k Then the Kleene closure L is the language formed by joining elements of L zero or more times. L = L 0 L 1 L 2... The Kleene closure is named after Stephen Kleene, the mathematician who first studied regular languages. If L unit is the language of strings of length one over an alphabet, then L unit is the language of all strings over the alphabet. If L 0 and L 1 are regular languages, one can show using NFA s that L 0 L 1, L 0 L 1, and L 0 are regular as well. VI Regular Expressions We can create a language to describe regular sets. Given an alphabet A, create a new alphabet with these symbols: a new letter, a new letter λ, a new letter a for each letter a in A, the symbols and, and parentheses ( and ). A regular expression is a string of these new letters that can be derived from the following EBNF specification. R ::= λ a (RR) (R R) (R ) It turns out that this language is itself a regular language. Each string in the language denotes a regular set over the original alphabet A. denotes the empty language. λ denotes the language whose only member is the empty string λ. a denotes the language whose only member is the one-element string a. If r and s are regular expressions, then (r s) denotes the concatenation of the two languages denoted by r and s. Now you see the reason for the distinction between the original alphabet letter a and its counterpart a in regular expressions.

computer science 52, languages and models of computation 9 If r and s are regular expressions, then (r s) denotes the union of the two languages denoted by r and s. If r is a regular expression, then (r ) denotes the Kleene closure of the language denoted by r. Inn the absence of parentheses, we carry out the Kleene closure operation first and then concatenation. The union operation is last. It turns out that every language denoted by a regular expression is a regular language, and every regular language is denoted by some regular expression. The regular expression a((a b)a) denotes the language of strings that start and end with a. The expression (a b)bbb denotes the language of strings that end with (at least) three b s. VII Context-free Grammars Earlier, we saw the EBNF formalism for defining languages. It is equivalent to context-free grammars, a topic that some of you may have encountered in a linguistics course. The language of balanced parentheses is described by a context-free grammar, as are most programming languages. Context-free languages are intermediate in complexity between regular languages and the computable languages presented in the next section. In a later course, you will study context-free grammars and discover that they can be recognized by a more powerful machine model called a push down automaton. VIII Turing Machines Turing machines are the ultimate computing machines. Anything that can be computed can be computed on a Turing machine. The machines were invented by Alan Turing in the 1930 s to study the nature of computation. A Turing machine is like a DFA, except that it has a memory in the form of a paper tape. Here is a quick summary of the structure of the machine. A Turing machine consists of the following components: a finite input alphabet A; a finite tape alphabet T which contains all the symbols in A plus (at least) a blank symbol ; a finite set of states Q with three especially-designated states a start state q 0, an accepting state q A, and a rejecting state q R ; a tape, divided into cells, each holding exactly one character;

computer science 52, languages and models of computation 10 a head that scans one cell of the tape; and a finite set of possible transitions of the form (a, q ; b, D, r ). The tape is potentially infinite in both directions. By potentially we mean that we only use finitely much of it at any given time, but we can always extend the tape in either direction when we need to. All tape cells, except the ones that have been explicitly changed, contain the blank symbol. When the machine begins, it is in the start state, there is a string of symbols from the input alphabet on the tape, and the tape head is scanning the leftmost symbol of the input string. A transition specifies one step in the computation. It is determined by the current state of the machine and the contents of the cell under the head. The transition (a, q ; b, D, r ) applies when the tape head is scanning a character a and the machine is in state q. The action of the transition is to replace the character by b (which may be the same as a), to move the head as specified by D, and to enter state r. The machine is then ready for the next step in the computation. The head movement D is either L, R, or S, standing for move left one square, move right one square, or stay put. A string is accepted if the Turing machine enters its accepting state at some point along the computation. A string is rejected if it is not accepted. For simplicity, it is best to design the machine so that it enters the explicit rejecting state whenever possible, but this requirement cannot always be enforced. There may be situations in which no transition is applicable; the machine freezes and implicitly rejects its input in those cases. Unlike a DFA or NFA, a Turing machine need not examine its entire input string. It may also go backwards over its input, or replace part of the input with other characters. 1 ; 1, L 0 ; 0, L 1 ; 1, R 0 ; 0, R 1 ; 0, L 0 ; 1, L q2 ;, R Figure 4: A Turing machine that adds one in binary. q0 ;, L q1 ; 1, S q3 Turing machines are not limited to accepting and rejecting strings. They can also carry out computations to produce results. The Turing machine in Figure 4 adds one to a binary number. The labels on the arrows are old-character ; new-character, direction The idea is that the machine (in its start state q 0 ) moves to the right of its input. It then enters its carry state q 1 and moves to the left,

computer science 52, languages and models of computation 11 changing 1 s to 0 s. When it encounters a 0, it exits the carry state and preserves the input until it halts on the left bit of the result. Turing machines can be non-deterministic. That is, there may be situations in which two or more transitions are applicable. You can think of the Turing machine as making a random choice of which transition to apply in those cases. A string is accepted if some legal sequence of steps leads to an accepting state. Perhaps surprisingly, the class of languages accepted by non-deterministic Turing machines is the same as the class of languages accepted by deterministic ones. As already mentioned, Turing machines are thought to be universal in the sense that any computable process can be carried out on a Turing machine. It would not be difficult to write in your favorite programming language a program that simulates a Turing machine. It is equally possible, but tedious, to design a Turing machine that simulates an ordinary computer program. Turing machines are valuable because they capture the nature of computation in a simple model and can therefore be used to study the limits of computation. IX The Church-Turing Thesis The value of a Turing machine is not that we actually carry out computations on them, but that we use them to study computation. In this course you will design a few Turing machines to do simple computational tasks. If you had more time (as perhaps you will in a later course), you will create Turing machines with more complicated behavior. You might, for example, build a Turing machine that executed SML programs. After some experience with Turing machines, people often come to a conclusion: Any computable process can be carried out on a Turing machine. This assertion is known as the Church-Turing Thesis, or more simply, Church s Thesis. It is named for the mathematicians Alonzo Church and Alan Turing, both pioneers in the theory of computation. The Church-Turing Thesis is a statement of confidence. It cannot ever be proved, because we do not have a clear definition of computable process. One might, in principle at least, discover a process that everyone agrees is computable but cannot be carried out on a Turing machine. It is highly unlikely that anyone will do that, and the Church-Turing Thesis is usually taken as the definition of a computable process.

computer science 52, languages and models of computation 12 X Self-reproducing Programs To see an unusual example of a computable process, we take a short digression into self-reproducing programs. We seek a program that takes no input and produces its own code as its output. Here is an example in SML. val q="\""; val s=";"; (fn x => x^q^x^q^s)"(fn x => x^q^x^q^s)"; This program is unsatisfying because the declarations of the values q and s are outside the program. We can put it inside by complicating the function a bit. The code below generates a self-reproducing expression in SML. We use ASCII values for the characters to avoid having to quote the quotation mark. val q=str(chr 34); val s=str(chr 59); (fn x => x^q^x^q^s) "val q=str(chr 34);val s=str(chr 59);(fn x => x^q^x^q^s)"; This program is still not quite self-reproducing, because the code above contains line breaks and spaces that do not appear in the output. But the output itself is exactly a self-reproducing program! The Java program below is another example of a self-reproduction. It comes from www.nyx.net/~gthompso/self_java.txt where it is attributed to Bertram Felgenhauer. A cursory web search will uncover literally hundreds of self-reproducing programs in all possible programming languages. class S { } public static void main(string[]a){ } String s="class S{public static void main(string[]a){ char c=34; String s=;char c=34; System.out.println(s.substring(0,52)+ c+s+c+s.substring(52));}}"; System.out.println(s.substring(0,52)+c+s+c+s.substring(52)); Running these programs is a computational process. Therefore, if we accept the Church-Turing Thesis, there must be a Turing machine that does the same thing. By the same thing, we might mean the trivial act of printing the above SML code or Java code, but in fact one can design a Turing machine that will print its own description. Try it before reading further! A computer virus is a slightly more sophisticated version of a selfreproducing program. Instead of merely writing its own source code, the virus makes a copy of itself and sends it on to another computer.

computer science 52, languages and models of computation 13 If we accept the Church-Turing Thesis, then we have an appealing shortcut to designing Turing machines. We can informally describe a computational process and then use the Church-Turing Thesis to assert that a corresponding Turing machine must exist. It is only a shortcut, however. If we were pressed, we would have to verify an instance of the thesis by specifying the Turing machine down to the last transition. It is usually not a difficult task, but it is tedious and distracting. For our purposes now, we will rely on the Church-Turing Thesis and be satisfied with the higher-level descriptions. XI Universal Turing Machines If someone gives you a description of a Turing machine and an input string appropriate for that machine, you can step through the computation. With pencil and paper, you can keep track of the contents of the tape, the position of the head, and the state of the machine. It is a simple mechanical or computational process to move from one configuration to the next. It follows that simulating the behavior of a Turing machine is itself a computational process. By the Church-Turing thesis, therefore, there must be a Turing machine that simulates other Turing machines. More precisely, there is a Turing machine U, called a universal Turing machine. Suppose that M is the description of a Turing machine M (suitably translated into the input alphabet of U) and w is an input string for M. When presented with a tape containing M and w, U does the same thing (accepts, rejects explicitly, or runs forever) as M does on input w. We have a programmable computer! The idea that a program, M in this case, is just another form of data was a crucial observation in the development of computers. The mathematician John von Neumann is usually credited with that insight. The indistinguishability of program and data leads to interesting cases of self-reference. One such example is the self-reproducing computer. Let C w be the Turing machine that erases its input, prints w on the tape, and then halts. Creating C w from w is a computational process, so there is a Turing machine D that on input w prints a description of C w. Now let E be the Turing machine that behaves as follows. On input w, E begins by making a second copy of w. It simulates D on one copy to obtain C w. It then treats the second copy of w as a Turing machine description and composes it with C w : first C w, then w. The Turing machine E prints a description of the composite machine and then halts.

computer science 52, languages and models of computation 14 Notice that E halts on all inputs, because it is only manipulating the descriptions of Turing machines. Let e be a description of E, and let s be the Turing machine description produced by running E with input e. Let S be the Turing machine described by s. What does S do? It runs C e and writes e on the tape. It passes that input to E, which in turn produces s. Therefore, S writes its own description. XII The Halting Problem Here is a problem that programmers confront frequently: Given a program and an input, does the program with the given input halt? It is a question that can be asked in our ordinary language about computation. And it can often have an easy answer. All of us have found, and corrected, infinite loops in our code. But is there a general algorithm that will always answer the question? Simulating the program on the input will give us only one possible answer. If the simulation halts, then we can say Yes, the program halts. But if the simulation does not halt, we will never get to the point where we can say No, the program runs for ever. It turns out that there is no algorithm to decide whether a program halts on a given input value. In our language of Turing machines, there is no Turing machine H with the following properties. An input for H is a pair ( M, w) consisting of a Turing machine description and an input. If M with input w halts, then H with input ( M, w) halts in an accepting state. If M with input w fails to halt, then H with input ( M, w) halts in an rejecting state. The result is troubling. We have a simple question about computation that has no computable answer. The proof that there is no Turing machine H is similar to the construction of a self-reproducing program. Suppose that we have a Turing machine H that halts on all inputs. We will find a Turing machine M and an input w for which H gives the wrong answer for ( M, w). Let D be a Turing machine that, on input x, does the following. i. creates the pair (x, x), ii. simulates H on (x, x), and iii. accepts x if H rejects and loops forever if H accepts. This is a symbolic activity that follows explicit rules and uses a bounded amount of resource. Therefore, by the Church-Turing Thesis,

computer science 52, languages and models of computation 15 it can be carried out on a Turing machine. Let D be a description of this machine. What does D do on input D? If H accepts ( D, D ), then D loops forever on D. If H rejects ( D, D ), then D accepts D and halts. Either way, H gives the wrong answer for ( D, D ), and H is not the halting checker that we were seeking. The problem of finding an algorithm that will tell us whether M halts on input w is called the Halting Problem. The proof just sketched shows that there is no computable solution to the Halting problem. It is an example of a problem that has no computable solution. There is, of course, a non-computable solution to the Halting Problem. The definition H ( M, w ) 0 if M halts on w, and = 1 otherwise is a perfectly well-defined mathematical function. It is just not a computable function. The negative solution to the Halting Problem has important consequences. For example, we cannot decide in a computational manner if a Turing-machine-and-input pair enters a specific state, because if we could, we could apply that ability to the halting state and determine whether another computation halts. Translated to programs, we cannot decide in an algorithmic manner whether a program enters a particular block of code. This limits the ability of a compiler to eliminate dead code. There are many similar impossibility results.