CS201: HW3 - Turing Machines

The homework file is (https://zoo.cs.yale.edu/classes/cs201/Spring_2021/materials/hws/hw3.rkt)

Unless the problem specifies otherwise:

Turing Machines

Turing machines were described in the lectures; see also the lecture notes on the course web page. Here is a top-level procedure to simulate a Turing machine starting from a given configuration until either it halts or it has executed n steps. The procedure returns the list of the successive configurations of the computation, starting with the initial one. The length of the list of configurations is one more than the number of steps taken by the machine.

mach is a representation of a Turing machine config is a representation of a configuration of the machine n is the maximum number of steps to simulate

The procedures halted? and next-config will be written by you in the problems below; you will then have a complete Turing machine simulator.

The test solutions at the bottom specify a number of steps, n, that the simulation should run before stopping. Your code may in fact need more steps to solve the given problem. The auto-grade program will account for this, allowing roughly twice as many steps for your code to run. Still, there is a limit. We have yet to solve the halting problem.

(simulate-lite tm config n) is like simulate, but does not return the intermediate states - just the final tape contents. Thus, we can use simulate-lite in the public tests without revealing the Turing machine instructions.

Turing machine representation.

A Turing machine is represented as a list of instructions, where each instruction is a 5-tuple, represented as a struct defined as follows:

The fields represent the following components of an instruction: current state, current symbol, new state, new symbol, and move direction

The current state and new state are Racket symbols, the current symbol and new symbol are Racket symbols or non-negative integers and the move direction must be either the symbol 'L or the symbol 'R, representing a move to the left or right, respectively.

We discussed the struct special form in (https://zoo.cs.yale.edu/classes/cs201/Spring_2021/lectures/Structs.html)

Here is an example of an instruction struct.

creates an instruction with current state 'q1, current symbol 0, new state 'q3, new symbol 1, and move direction 'L, and names it i1.

Because we've made ins "transparent", its field values will be printed out.

We can access the components of i1 via the structure selectors:

Example (from lecture):

A Turing machine that when started in state 'q1 on the leftmost of a string of 0's and 1's changes all the 0's to 1's and all the 1's to 0's and then returns the head to the leftmost symbol and halts.

problem 1 (15 points)

Define (in the format just given) a Turing machine named

tm-reverse

that takes an input string of 0's and 1's and produces an output string equal to the reverse of the input string. When the machine halts, the head should be scanning the leftmost symbol of the output.

That is, when started in state q1 with the head on the leftmost of a string of 0's and 1's, it halts with the head on the leftmost of a string of 0's and 1's, and the output string is obtained from the input string by reversing it.

Your machine may use additional tape symbols but the output should contain no symbols other than 0, 1 and blank. When the machine halts, symbols other than the output should be blank.

Examples of the behavior of tm-reverse

1            =>  1
110          =>  011
0001         =>  1000
101011       =>  110101

(test 'tm-reverse (simulate-lite tm-reverse (conf 'q1 '() 1 '()) 20) '(() 1 ()))
(test 'tm-reverse (simulate-lite tm-reverse (conf 'q1 '() 1 '(1 0)) 200) '(() 0 (1 1)))
(test 'tm-reverse (simulate-lite tm-reverse (conf 'q1 '() 0 '(0 0 1)) 200) '(() 1 (0 0 0)))
(test 'tm-reverse (simulate-lite tm-reverse (conf 'q1 '() 1 '(0 1 0 1 1)) 200) '(() 1 (1 0 1 0 1)))

(It may help to review ideas from the machine to make a copy of its input, described in lectures and in the online lecture notes.)

The initial state of your machine should be q1 -- other states may be named with Racket symbols of your choice.

IMPORTANT: please describe how your Turing machine works. You'll be able to run it once you get the procedures for the simulator working. Or you can load the working simulator from the staff solution: hw3_rkt.zo

Problem 2 (10 points)

Write the following two procedures. Remember to use the instruction selectors: ins-c-state, ins-c-symbol, ins-n-state, ins-n-symbol, ins-dir

(i-match? state symbol inst)

returns #t if state and symbol are equal to the state and symbol of instruction inst otherwise returns #f

(i-lookup state symbol mach)

returns #f if no instruction of Turing machine mach has state and symbol equal to state and symbol otherwise returns the instruction in mach that matches. You may assume that at most one instruction will match.

The latter point is based on the requirement that Turing machines be deterministic, that is, there is only one way to execute a given program for a given input. The alternative is non-determinism, as mentioned in class.

For this assignment, when writing Turing machine programs (problems 1, 7, and 8) be certain that no two instructions have the same c-symbol and c-state (with possibly differing n-state, n-symbol, or dir).

Examples

(i-match? 'q1 'b (ins 'q1 'b 'q3 'b 'L)) => #t
(i-match? 'q1  0  (ins 'q1 1 'q4 1 'L)) => #f
(i-match? 'q2 1 (ins 'q2 1 'q2 1 'L)) => #t
(equal? (i-lookup 'q1 1 tm1) (ins 'q1 1 'q1 0 'R)) => #t
(equal? (i-lookup 'q2 'b tm1) (ins 'q2 'b 'q3 'b 'R)) => #t
(i-lookup 'q3 1 tm1) => #f

Representation of a Turing machine configuration.

We represent a Turing machine configuration using the following structure:

where

We reserve the symbol 'b for the blank.

For example, we define the following two configurations:

Note that the selectors are conf-state, conf-ltape, conf-symbol, conf-rtape

config1 represents the Turing machine configuration


   --------------------------
   .. | 0 | 0 | 1 | 1 |  | ..
   --------------------------
                ^
                q3

in which the non-blank symbols on the tape are 0011, and the machine is in state q3 with the read/write head scanning the leftmost 1.

config2 represents the Turing machine configuration


   ------------------------------
   .. |   | 1 |  | 0 |   |   | ..
   ------------------------------
                   ^
                   q6

in which the symbols 1, blank, 0, are on the tape, surrounded by blanks, and the machine is in state q6 with the read/write head scanning the 0.

A configuration is normalized if neither the first symbol of ltape nor the last symbol of rtape is the symbol 'b. Of the two configurations above, config1 is normalized, but config2 is not (the last element of its rtape list is 'b.)

Note that tape squares not explicitly represented are assumed to contain blanks. A normalized configuration to represent the machine in state q1 with all tape squares blank is thus (conf 'q1 '() 'b '())).

Problem 3 (9 points)

Write the following three procedures.

(halted? mach config) returns #t if the Turing machine mach is halted in machine configuration config (ie, no instruction of the machine matches the current state and symbol in configuration config) and returns #f otherwise.

(change-state new-state config) takes a configuration config and returns a configuration in which the state of the machine is changed to new-state.

(write-symbol new-symbol config) takes a configuration config and returns a configuration in which the symbol scanned by the read/write head has been replaced by new-symbol.

Examples

(halted? tm1 (conf 'q1 '(1 1 0) 'b '())) => #f
(halted? (list (ins 'q1 'b 'q2 'b 'R)) (conf 'q2 '() 'b '())) => #t
(change-state 'q2 (conf 'q1 '(0) 1 '())) => (conf 'q2 '(0) 1 '())
(change-state 'q13 (conf 'q4 '(0 1 1) 'b '())) => (conf 'q13 '(0 1 1) 'b '())
(write-symbol 1 (conf 'q5 '(0) 0 '(1 1))) => (conf 'q5 '(0) 1 '(1 1))
(write-symbol 'c (conf 'q2 '(0 0 1) 1 '(1 1))) => (conf 'q2 '(0 0 1) 'c '(1 1))
(write-symbol 'b (conf 'q3 '(1) 0 '())) => (conf 'q3 '(1) 'b '())

Problem 4 ** (10 points)

Write one procedure

(normalize config) takes a Turing machine configuration config and returns an equivalent normalized configuration. That is, the same Turing machine configuration is represented by the input configuration and the output configuration, and the output configuration does not have a 'b as the first element of its ltape list or the last element of its rtape list.

Examples

(normalize config1) => (conf 'q3 '(0 0) 1 '(1))
(normalize config2) => (conf 'q6 '(1 b) 0 '())
(normalize (conf 'q3 '(b 0) 'b '(1 1 0 b b))) => (conf 'q3 '(0) 'b '(1 1 0))
(normalize (conf 'q6 '(b 0 b 0) 1 '(0 b 0 b))) => (conf 'q6 '(0 b 0) 1 '(0 b 0))
(normalize (conf 'q4 '(b b) 'b '(b b b))) => (conf 'q4 '() 'b '())

Problem 5 ** (10 points)

Write two procedures

(shift-head-left config) takes a normalized configuration config and returns a normalized configuration in which the position of the read/write head has been moved one tape square to the left.

(shift-head-right config) takes a normalized configuration config and returns a normalized configuration in which the position of the read/write head has been moved one tape square to the right.

Examples

(shift-head-left (conf 'q5 '() 'b '())) => (conf 'q5 '() 'b '())
(shift-head-left (conf 'q6 '(0 0) 1 '(1 1))) => (conf 'q6 '(0) 0 '(1 1 1))
(shift-head-left (conf 'q7 '() 0 '(1 1 0))) => (conf 'q7 '() 'b '(0 1 1 0))
(shift-head-right (conf 'q2 '() 'b '())) => (conf 'q2 '() 'b '())
(shift-head-right (conf 'q9 '() 0 '(1 1 1))) => (conf 'q9 '(0) 1 '(1 1))
(shift-head-right (conf 'q8 '(1 0 1 1) 'b '())) => (conf 'q8 '(1 0 1 1 b) 'b '())

Hint:

last element of a list is built in to Racket (last lst)

all but last element of a list -- uses Racket's drop-right

Problem 6 ** (15 points)

Write a procedure

(next-config mach config) takes a Turing machine mach and a normalized configuration config and returns the normalized next configuration for the Turing machine mach in the configuration config. If there is no applicable instruction, the configuration returned should be just the input configuration.

Hint: get your procedures halted?, i-lookup, write-symbol, shift-head-left, shift-head-right working and combine them appropriately.

Examples

(next-config tm1 (conf 'q1 '() 0 '(0 1))) => (conf 'q1 '(1) 0 '(1))
(next-config tm1 (conf 'q1 '(1) 0 '(1))) => (conf 'q1 '(1 1) 1 '())
(next-config tm1 (conf 'q1 '(1 1 0) 'b '())) => (conf 'q2 '(1 1) 0 '())
(next-config tm1 (conf 'q2 '() 'b '(1 1 0))) => (conf 'q3 '() 1 '(1 0))
(next-config tm1 (conf 'q3 '() 1 '(1 0))) => (conf 'q3 '() 1 '(1 0))

If your procedures are working, then you should be able to run the following example, which shows the successive normalized configurations of Turing machine tm1 when run from the given configuration.

> (simulate tm1 (conf 'q1 '() 1 '(1 0 1 0)) 20)
(list
 (conf 'q1 '() 1 '(1 0 1 0))
 (conf 'q1 '(0) 1 '(0 1 0))
 (conf 'q1 '(0 0) 0 '(1 0))
 (conf 'q1 '(0 0 1) 1 '(0))
 (conf 'q1 '(0 0 1 0) 0 '())
 (conf 'q1 '(0 0 1 0 1) 'b '())
 (conf 'q2 '(0 0 1 0) 1 '())
 (conf 'q2 '(0 0 1) 0 '(1))
 (conf 'q2 '(0 0) 1 '(0 1))
 (conf 'q2 '(0) 0 '(1 0 1))
 (conf 'q2 '() 0 '(0 1 0 1))
 (conf 'q2 '() 'b '(0 0 1 0 1))
 (conf 'q3 '() 0 '(0 1 0 1)))

Problem 7 ** (15 points)

Define (in the given representation) a Turing machine named

tm-parity

that takes as input a positive integer n represented in binary and produces as output a 1 if the number has an odd number of 1's, else

  1. When the machine halts, the read/write head should be positioned over the leftmost b to the right of the binary digit in the output string. The start state should be named q1 -- other states may be named by any other Racket symbols.

You may use additional tape symbols. When the machine halts, there should be just a single binary digit, 0 or 1, surrounded by blanks, on the tape.

IMPORTANT: Give a clear overview description of how your Turing machine works.

NOTE: you can still do this problem if your simulator is not working, assuming you understand Turing machines and the representation of them defined above.

A parity bit is often used for error checking in data transmission. See https://en.wikipedia.org/wiki/Parity_bit

Examples of the behavior of tm-convert

1            => 1
11           => 0
110          => 0
1111         => 0
1110110      => 1

(test 'tm-parity (simulate-lite tm-parity (conf 'q1 '() 1 '()) 20) '((1) b ()))
(test 'tm-parity (simulate-lite tm-parity (conf 'q1 '() 1 '(1)) 200) '((0) b ()))
(test 'tm-parity (simulate-lite tm-parity (conf 'q1 '() 1 '(1 0)) 200) '((0) b ()))
(test 'tm-parity (simulate-lite tm-parity (conf 'q1 '() 1 '(1 1 1)) 400) '((0) b ()))
(test 'tm-parity (simulate-lite tm-parity (conf 'q1 '() 1 '(1 1 0 1 1 0)) 400) '((1) b ()))

Problem 8 (15 points)

Define (in the given representation) a Turing machine named

tm-sort

that takes as input a non-empty string of 0's and 1's and produces as output a string of 0's and 1's equal to the input string rearranged to have all the 0's before all the 1's. When the machine halts, the read/write head should be positioned over the leftmost 0 or 1 in the output string. The start state should be named q1 -- other states may be named by any other Racket symbols.

You may use additional tape symbols. When the machine halts, the only non-blank symbols on the tape should be the output string.

IMPORTANT: Give a clear overview description of how your Turing machine works.

NOTE: you can still do this problem if your simulator is not working, assuming you understand Turing machines and the representation of them defined above.

Examples of the behavior of tm-sort

0          => 0  
1          => 1
00         => 00
110        => 011
1011011    => 0011111

(test 'tm-sort (simulate-lite tm-sort (conf 'q1 '() 0 '()) 20) '(() 0 ()))
(test 'tm-sort (simulate-lite tm-sort (conf 'q1 '() 1 '()) 20) '(() 1 ()))
(test 'tm-sort (simulate-lite tm-sort (conf 'q1 '() 0 '(0)) 200) '(() 0 (0)))
(test 'tm-sort (simulate-lite tm-sort (conf 'q1 '() 1 '(1 0)) 200) '(() 0 (1 1)))
(test 'tm-sort (simulate-lite tm-sort (conf 'q1 '() 1 '(0 1 1 0 1 1)) 200) '(() 0 (0 1 1 1 1 1)))

Here are some input configurations if you want to simulate your tm-sort on these inputs.