Chapter 4 Creating animated Turing gifs

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") 
}