We first load the needed packages:
library(tidyverse)
library(ggplot2)
library(gganimate)We define a function that can create 1d inputs that can be read by our Turing machine:
input_builder_1d_animated <- function(n){
output <- c(rep(1,n+1))
output
}We define a function that can create 2d inputs that can be read by our Turing machine:
input_builder_2d_animated <- function(n,m){
output <- c(rep(1,n+1), NA, rep(1,m+1))
output
}We now define a function that will return a data set we can be use to make an animated plot of a turing program. As in our original implementation, it takes a program and an input (build by one of the input generators above) as arguments. If the browser arguments is TRUE in a call to the function, we enter the function environment and can follow along every step of the way. Since R cannot use negative indices, and we want our infinite tape to be intuitive, the n_na argument allow us to add some NA to the left of the first 1 on the input tape, such that the machine can go to the left of the starting position.
turingmachine_animated_data <- function(program, input, browser = FALSE, numeric = FALSE, n_na=0){
#if(browser){browser()} we have to comment out the browser function for publishing. Uncomment if you want to use the browser argument.
position <- n_na+1
state <- "1"
input <- c(rep(NA, n_na),input)
position_animate <- c(n_na+1)
input_animate <- list(input)
state_animate <- c("1")
s <- 1
while(state != "0"){
if(is.na(input[position])){
input[position] <- program[[state]]$if_read_na$return
input_animate <- append(input_animate, list(input))
s <- s+1
if(program[[state]]$if_read_na$direction == "R"){position <- position + 1
position_animate <- c(position_animate, position)
s <- s+1
} else {
position <- position -1
position_animate <- c(position_animate, position)
s <- s+1
}
state <- program[[state]]$if_read_na$state
state_animate <- c(state_animate,state)
}
else {
input[position] <- program[[state]]$if_read_one$return
input_animate <- append(input_animate, list(input))
s <- s+1
if(program[[state]]$if_read_one$direction == "R"){
position <- position + 1
position_animate <- c(position_animate, position)
s <- s+1
} else {
position <- position -1
position_animate <- c(position_animate, position)
s <- s+1
}
state <- program[[state]]$if_read_one$state
state_animate <- c(state_animate,state)
}
}
# collect variables to make the data from
animate_list <-
list(position=position_animate,
input=input_animate,
state=state_animate,
steps=s)
position_out <- c()
input_out <- c()
state_out <- c()
input_x <- c()
step_out <- c()
for(i in c(1:length(animate_list$state))){
l <- length(animate_list$input[[i]])
input_out <- c(input_out,as.numeric(animate_list$input[[i]]))
input_x <- c(input_x, 1:l)
state_out <- c(state_out,rep(as.numeric(animate_list$state[i]),l))
step_out <- c(step_out, rep(i,l))
position_out <- c(position_out, rep(animate_list$position[i],l))
}
#return the collected data
tibble(position_out,input_out,state_out,input_x,step_out)
}We define a function for creating animated plots of turingmachines. The function call the turing_animated_data() function we defined above with the program, input and n_na specified in the arguments. The title argument is the plot title. After having created the data, the function creates and return a ggplot object, ready to be rendered into a gif.
animated_turingmachine_plot <- function(program, input, title, n_na =0){
# create the data
data_anim <- turingmachine_animated_data(program, input, n_na = n_na) %>%
mutate(label_text= paste("state: ", as.character(state_out)))
# create an object which can be rendered using animate()
ggplot(data=data_anim, aes(input_x, input_out))+
geom_point(size=3, colour = "magenta") +
geom_point(aes(x=position_out, y = 2),size = 5,shape = 25, fill = "orange", colour = "orange")+
theme_minimal()+
ylim(0,3.5)+
transition_states(step_out, transition_length = 1 , state_length = 1, wrap = FALSE)+
theme(axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.position="none",
text = element_text(family = "Times New Roman", size = 15))+
ggtitle(title) +
geom_text(aes(x=1.5,y=0.3,label=label_text),size = 6, check_overlap=TRUE,
family = "Times New Roman")
}