From 9b19fcf08a18c44fa89a75c4b4804964e3e1652e Mon Sep 17 00:00:00 2001 From: tfburns Date: Wed, 24 Jul 2019 21:02:55 +0900 Subject: [PATCH] Working example of program to compute if binary numbers divisible by 3 --- example.jl | 15 ++++- example_input_1.txt | 2 +- example_program_1.txt | 12 ++-- simulator.jl | 135 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 140 insertions(+), 24 deletions(-) diff --git a/example.jl b/example.jl index fa9365e..7b960e0 100644 --- a/example.jl +++ b/example.jl @@ -6,4 +6,17 @@ program_file = "example_program_1.txt" input = load_input(input_file) program, init_state, halt_state = load_program(program_file) -tape_left, tape_right = set_up(input) +state, tape_left, tape_right = set_up(init_state, input) + +# run simulation step-by-step until we reach the halting state +while true + try + global state, tape_left, tape_right = simulate(state, program, tape_left, tape_right) + println(state) + state ==("qAccept") && break + catch err + global state = "qReject" + println(state) + state ==("qReject") && break + end +end diff --git a/example_input_1.txt b/example_input_1.txt index ca0a713..5381c73 100644 --- a/example_input_1.txt +++ b/example_input_1.txt @@ -1 +1 @@ -01100101 +1101101 diff --git a/example_program_1.txt b/example_program_1.txt index da4f1d9..6e5809c 100644 --- a/example_program_1.txt +++ b/example_program_1.txt @@ -5,14 +5,14 @@ // Example: accepts 110 (=6) // ------- States -----------| -// q0 - mod3 == 0 | -// q1 - mod3 == 1 | -// q2 - mod3 == 2 | -// qHalt - halting state | +// q0 : mod3 == 0 | +// q1 : mod3 == 1 | +// q2 : mod3 == 2 | +// qAccept : halting state | // --------------------------| init: q0 -halt: qHalt +halt: qAccept q0,0,q0,0,> @@ -26,4 +26,4 @@ q2,0,q1,0,> q2,1,q2,1,> -q0,_,qHalt,_,- +q0,_,qAccept,_,- diff --git a/simulator.jl b/simulator.jl index 3dae691..ef7fce6 100644 --- a/simulator.jl +++ b/simulator.jl @@ -1,10 +1,6 @@ using DataStructures using DelimitedFiles -# Read Input / Change value of current input (or do nothing), Move L or R or do nothing -# e.g. 1/0, L = if current cell value is 1, change it to 0, then move left -# e.g. 0/1, . = if current cell value is 0, change it to 1, then don't move - """ load_input(file_name) @@ -28,23 +24,27 @@ end Takes a text file containing a Turing program. Please see docs for how to write such a program. Input +- `file_name`::string : path of text file containing the Turing program to simulate + +Output +- `program`::Dict{Any,Any} with `m` entries: dictionary with keys of [states,read_cells] and values of [next_state,write_cell,movement] """ function load_program(file_name) - program_file = readdlm("example_program_1.txt") - rows, cols = size(program_file) + program_raw = readdlm(file_name) + rows, cols = size(program_raw) program = Dict{Any,Any}() init_state = [] halt_state = [] for i = 1:rows - if program_file[i,1] == "//" + if program_raw[i,1] == "//" continue else - if program_file[i,1] == "init:" - push!(init_state, program_file[i,2]) - elseif program_file[i,1] == "halt:" - push!(halt_state, program_file[i,2]) + if program_raw[i,1] == "init:" + push!(init_state, program_raw[i,2]) + elseif program_raw[i,1] == "halt:" + push!(halt_state, program_raw[i,2]) else - card = split(program_file[i,1], r",") + card = split(program_raw[i,1], r",") state_read = (String(card[1]),String(card[2])) instruction = (String(card[3]),String(card[4]),String(card[5])) program[state_read] = instruction @@ -55,26 +55,129 @@ function load_program(file_name) end """ - set_up(input) + set_up(init_state, input) Performs initial set-up for the simulation of single tape. The `length(input)` must be equal of greater than 1. The input will be placed on tape to the right of the head. Input - `input`::`n`-element Array{Char, 1} : initial data to insert to the right of the head +- `init_state`::String : string label for initial/starting state of the Turing machine -Output +Outputs - `tape_left`::Deque{Int} : initial values for the stack to the left of the head - `tape_right`::Deque{Int} : initial values for the stack to the right of the head """ -function set_up(input) +function set_up(init_state, input) # set up two stacks to simulate a single tape tape_left = Deque{Int}() # simulates tape lying to the left of the head tape_right = Deque{Int}() # simulates tape lying to the right of the head - for i = 1:length(input) push!(tape_right, parse(Int, input[i])) end + state = init_state + return state, tape_left, tape_right +end + +""" + read_tape(tape_right) + +Reads a tape and returns the current value. + +Input +- `tape_right`::Deque{Int}() : values for the stack to the right of the head + +Output +- `read_cell`::String : value for the current cell being read by the head +""" +function read_tape(tape_right) + read_cell = front(tape_right) + return read_cell +end + +""" + get_instruction(state, read_cell, program) + +Inputs +- `state`::String : curent state of the Turing machine +- `read_cell`::String : value for the current cell being read by the head +- `program`::Dict{Any,Any} with `m` entries: dictionary with keys of [states,read_cells] and values of [next_state,write_cell,movement] + +Outputs +- `next_state`::String : next state for the Turing machine to move to +- `write_cell`::String : value for the head to write on the current cell +- `movement`::String : movement instruction for the head (left="<", right=">", any other symbol doesn't move) +""" +function get_instruction(state, read_cell, program) + instruction = program[(string(state), string(read_cell))] + next_state = instruction[1] + write_cell = instruction[2] + movement = instruction[3] + return next_state, write_cell, movement +end + +""" + write_move!(movement, write_cell, tape_left, tape_right) + +Performs the operations of writing at the current position then moving the head left or right. + +Inputs +- `movement`::String : movement instruction for the head (left="<", right=">", any other symbol doesn't move) +- `write_cell`::String : value for the head to write on the current cell +- `tape_left`::Deque{Int} : values for the stack to the left of the head +- `tape_right`::Deque{Int} : values for the stack to the right of the head +Outputs +- `tape_left`::Deque{Int} : updated values for the stack to the left of the head (after writing/movement) +- `tape_right`::Deque{Int} : updated values for the stack to the right of the head (after writing/movement) +""" +function write_move!(movement, write_cell, tape_left, tape_right) + if isempty(tape_right) + return tape_left, tape_right + end + popfirst!(tape_right) + pushfirst!(tape_right, parse(Int, write_cell)) + if movement == "<" + if isempty(tape_left) + pushfirst!(tape_right, "_") + else + carry = pop!(tape_left) + pushfirst!(tape_right, carry) + end + elseif movement == ">" + if isempty(tape_right) + push!(tape_left, "_") + else + carry = popfirst!(tape_right) + push!(tape_left, carry) + end + end return tape_left, tape_right end + +""" + simulate(state, program, tape_left, tape_right) + +Simulates one step of the Turing machine: reading, writing, and moving the head. + +Inputs +- `state`::String : curent state of the Turing machine +- `program`::Dict{Any,Any} with `m` entries: dictionary with keys of [states,read_cells] and values of [next_state,write_cell,movement] +- `tape_left`::Deque{Int} : values for the stack to the left of the head +- `tape_right`::Deque{Int} : values for the stack to the right of the head + +Outputs +- `state`::String : updated state of the Turing machine after one simulation step +- `tape_left`::Deque{Int} : updated values for the stack to the left of the head after one simulation step +- `tape_right`::Deque{Int} : updated values for the stack to the right of the head after one simulation step +""" +function simulate(state, program, tape_left, tape_right) + if isempty(tape_right) + read_cell = "_" + else + read_cell = read_tape(tape_right) + end + state, write_cell, movement = get_instruction(state, read_cell, program) + tape_left, tape_right = write_move!(movement, write_cell, tape_left, tape_right) + return state, tape_left, tape_right +end