Our goal is to build a Turing machine. First we need a smart encoding of our infinite tape, since R can only use positive indices. We assume that the starting position of our machine is at the left most 1 and let this be position 1. We let the even numbers represent the numbers to the left of our starting position, and the uneven numbers represent the numbers to the right of our starting position.
We define a function for determining the index of a new position, given the current position and the direction:
<- function(current_position, direction){
position_determiner <- current_position
position if(current_position == 2 & direction == "R"){position <- position -1 }
else if(current_position == 1 & direction == "L"){position <- position + 1 }
else if(current_position %% 2 != 0 & direction == "R"){position <- position + 2}
else if(current_position %% 2 == 0 & direction == "R"){position <- position -2 }
else if(current_position %% 2 == 0 & direction == "L"){position <- position + 2}
else{position <- position - 2}
position}
We can now define our universal turingmachine. The machine takes the program and an input as inputs. The browser argument allows that we can follow the machines course of action step by step, and the ‘numeric’ arguments allows that we get the output as the sum of ones on the tape instead of the tape itself.
<- function(program, input, browser = FALSE, numeric = FALSE){
turingmachine if(browser){browser()}
<- 1
position <- "1"
state <- input
input while(state != "0"){
if(is.na(input[position])){
<- program[[state]]$if_read_na$return
input[position] <- position_determiner(position, program[[state]]$if_read_na$direction)
position <- program[[state]]$if_read_na$state
state
}else {
<- program[[state]]$if_read_one$return
input[position] <- position_determiner(position, program[[state]]$if_read_one$direction)
position <- program[[state]]$if_read_one$state
state
}
}if(numeric){sum(as.numeric(input), na.rm = TRUE)} else {as.numeric(input)}
}
In order to ease the usability, we define some functions that can help putting programs and inputs into the correct form, so they are readable by the machine.
We first define a function specifically for creating programs on a correct form
such that it can be read by our Turing machine. The function takes a list of vectors and creates a nested list as needed by the machine:
<- function(list_of_states){
program_builder # function for creating a program that can be read by the turingmachine,
# given a list of vectors with the commands
<- list()
return_list for(vec in list_of_states){
<- list(if_read_na= list(return = vec[2],direction=vec[3],state=vec[4]),
loop_list if_read_one = list(return = vec[5], direction=vec[6], state=vec[7]))
1]]] <- loop_list
return_list[[vec[
}
return_list }
We define a function that can create 1d inputs that can be read by our Turing machines:
<- function(n){
input_builder_1d # function for creating a input that can be read by the turing machine
<- c()
output for(i in seq(1,n+1)){
<- c(output, 1, NA)
output
}
output }
We define a function that can create 2d inputs that can be read by our turing machines:
<- function(n,m){
input_builder_2d # function for creating an input that can be read by the turing machine
<- c()
output for(i in seq(1,n+1)){
<- c(output, 1, NA)
output
}<- c(output, NA,NA)
output for(i in seq(1,m+1)){
<- c(output,1, NA)
output
}
output }