200 lines
6.6 KiB
Python
200 lines
6.6 KiB
Python
# Improved TuringMachine class with debug output and updated transition table per your fix.
|
|
from dataclasses import dataclass
|
|
from typing import Dict, Tuple, List, TypeAlias, Literal
|
|
|
|
# === Type Aliases ===
|
|
State: TypeAlias = str
|
|
Symbol: TypeAlias = str
|
|
Direction: TypeAlias = Literal["L", "R"] # precise directions only
|
|
|
|
TransitionKey: TypeAlias = Tuple[State, Symbol]
|
|
TransitionValue: TypeAlias = Tuple[State, Symbol, Direction]
|
|
TransitionFunction: TypeAlias = Dict[TransitionKey, TransitionValue]
|
|
Tape: TypeAlias = List[Symbol]
|
|
|
|
|
|
@dataclass
|
|
class TuringMachine:
|
|
transition_function: TransitionFunction
|
|
start_state: State
|
|
accept_state: State
|
|
reject_state: State
|
|
blank_symbol: Symbol = " "
|
|
|
|
def run(
|
|
self,
|
|
tape_input: str,
|
|
head: int = 0,
|
|
max_steps: int = 10_000,
|
|
verbose: bool = True,
|
|
) -> Tuple[State, Tape]:
|
|
tape: Tape = list(tape_input) + [self.blank_symbol] * 20
|
|
state = self.start_state
|
|
steps = 0
|
|
|
|
# normalize head position
|
|
if head < 0:
|
|
tape = [self.blank_symbol] * (-head) + tape
|
|
head = 0
|
|
elif head >= len(tape):
|
|
tape += [self.blank_symbol] * (head - len(tape) + 1)
|
|
|
|
def debug_print():
|
|
tape_view = "".join(tape).replace(self.blank_symbol, "_")
|
|
head_marker = " " * head + "^"
|
|
print(
|
|
f"[{steps:04}] State: {state} | Head: {head} | Tape:\n{tape_view}\n{head_marker}"
|
|
)
|
|
|
|
debug_print()
|
|
while (
|
|
state != self.accept_state
|
|
and state != self.reject_state
|
|
and steps < max_steps
|
|
):
|
|
if verbose:
|
|
debug_print()
|
|
read = tape[head]
|
|
key = (state, read)
|
|
if key not in self.transition_function:
|
|
print(f"No transition for ({state}, '{read}') — rejecting.")
|
|
state = self.reject_state
|
|
break
|
|
|
|
next_state, write, move = self.transition_function[key]
|
|
tape[head] = write
|
|
head += 1 if move == "R" else -1
|
|
if head < 0:
|
|
tape.insert(0, self.blank_symbol)
|
|
head = 0
|
|
state = next_state
|
|
steps += 1
|
|
|
|
debug_print()
|
|
return state, tape
|
|
|
|
|
|
# Updated transitions
|
|
transitions_cleaned: TransitionFunction = {}
|
|
|
|
# Scan phase: 1 → X, 0 → Y
|
|
transitions_cleaned[("scan", "1")] = ("scan", "X", "R")
|
|
transitions_cleaned[("scan", "0")] = ("scan", "Y", "R")
|
|
|
|
transitions_cleaned[("scan", " ")] = ("back", " ", "L")
|
|
|
|
# Back phase: move left over 0/1/X/Y and turn forward on ' ', 'M', 'N'
|
|
for sym in ["0", "1", "X", "Y"]:
|
|
transitions_cleaned[("back", sym)] = ("back", sym, "L")
|
|
transitions_cleaned[("back", " ")] = ("forward", " ", "R")
|
|
transitions_cleaned[("back", "M")] = ("forward", "M", "R")
|
|
transitions_cleaned[("back", "N")] = ("forward", "N", "R")
|
|
|
|
# Forward: if blank, done; if digit → sweep; if mark → prepare copy
|
|
transitions_cleaned[("forward", " ")] = ("accept", " ", "R")
|
|
transitions_cleaned[("forward", "0")] = ("sweep", "0", "L")
|
|
transitions_cleaned[("forward", "1")] = ("sweep", "1", "L")
|
|
transitions_cleaned[("forward", "X")] = ("fw1", "M", "R") # 1 → M
|
|
transitions_cleaned[("forward", "Y")] = ("fw0", "N", "R") # 0 → N
|
|
|
|
# Copy phases
|
|
for sym in ["0", "1", "X", "Y"]: # ts wont ever meet M N
|
|
transitions_cleaned[("fw1", sym)] = ("fw1", sym, "R")
|
|
transitions_cleaned[("fw0", sym)] = ("fw0", sym, "R")
|
|
transitions_cleaned[("fw1", " ")] = ("back", "1", "L")
|
|
transitions_cleaned[("fw0", " ")] = ("back", "0", "L")
|
|
|
|
# Sweep phase: M → 1, N → 0
|
|
transitions_cleaned[("sweep", "M")] = ("sweep", "1", "L")
|
|
transitions_cleaned[("sweep", "N")] = ("sweep", "0", "L")
|
|
transitions_cleaned[("sweep", "0")] = ("sweep", "0", "L")
|
|
transitions_cleaned[("sweep", "1")] = ("sweep", "1", "L")
|
|
transitions_cleaned[("sweep", " ")] = ("accept", " ", "R")
|
|
|
|
# Build and run the machine with debug output
|
|
tm = TuringMachine(
|
|
transition_function=transitions_cleaned,
|
|
start_state="scan",
|
|
accept_state="accept",
|
|
reject_state="reject",
|
|
)
|
|
|
|
tape_input = "00110"
|
|
final_state, final_tape = tm.run(tape_input)
|
|
print("Final State:", final_state)
|
|
final_tape_str = "".join(final_tape).strip()
|
|
print("Final Tape:", final_tape_str)
|
|
|
|
classic: TransitionFunction = {}
|
|
|
|
# ok idk
|
|
|
|
classic[("want_copy", "1")] = ("past_og_1", "X", "R")
|
|
classic[("want_copy", "0")] = ("past_og_0", "Y", "R")
|
|
|
|
for sym in ["0", "1"]:
|
|
classic[("past_og_1", sym)] = ("past_og_1", sym, "R")
|
|
classic[("past_og_0", sym)] = ("past_og_0", sym, "R")
|
|
|
|
classic[("past_og_1", " ")] = ("copy_1", " ", "R")
|
|
classic[("past_og_0", " ")] = ("copy_0", " ", "R")
|
|
|
|
for sym in ["0", "1"]:
|
|
classic[("copy_1", sym)] = ("copy_1", sym, "R")
|
|
classic[("copy_0", sym)] = ("copy_0", sym, "R")
|
|
|
|
classic[("copy_1", " ")] = ("back", "1", "L")
|
|
classic[("copy_0", " ")] = ("back", "0", "L")
|
|
|
|
for sym in ["0", "1", " "]:
|
|
classic[("back", sym)] = ("back", sym, "L")
|
|
|
|
for sym, target in [("X", "1"), ("Y", "0")]:
|
|
classic[("back", sym)] = ("want_copy", target, "R")
|
|
|
|
classic[("want_copy", " ")] = ("accept", " ", "R")
|
|
|
|
tm_classic = TuringMachine(
|
|
transition_function=classic,
|
|
start_state="want_copy",
|
|
accept_state="accept",
|
|
reject_state="reject",
|
|
)
|
|
|
|
final_state, final_tape = tm_classic.run(tape_input)
|
|
print("Final State (Classic):", final_state)
|
|
final_tape_str = "".join(final_tape).strip()
|
|
print("Final Tape (Classic):", final_tape_str)
|
|
|
|
# for now it will copy with a blank in between. so 00110 → 00110 00110, not 0011000110. but it works. and the other one works too. so that's good enough for now.
|
|
|
|
left_shift_1: TransitionFunction = {}
|
|
|
|
left_shift_1[("want_copy", "1")] = ("copy_1", " ", "L")
|
|
left_shift_1[("want_copy", "0")] = ("copy_0", " ", "L")
|
|
left_shift_1[("want_copy", " ")] = ("accept", " ", "R")
|
|
|
|
for sym, target in [("copy_0", "0"), ("copy_1", "1")]:
|
|
# override for now, i can make a wrapping one but i wont
|
|
left_shift_1[(sym, "1")] = ("going_balls", target, "R")
|
|
left_shift_1[(sym, "0")] = ("going_balls", target, "R")
|
|
left_shift_1[(sym, " ")] = ("going_balls", target, "R")
|
|
|
|
left_shift_1[("going_balls", " ")] = ("want_copy", " ", "R")
|
|
|
|
left_shift_machine = TuringMachine(
|
|
transition_function=left_shift_1,
|
|
start_state="want_copy",
|
|
accept_state="accept",
|
|
reject_state="reject",
|
|
)
|
|
|
|
left_shift_input = "101010"
|
|
|
|
left_shift_final_state, left_shift_final_tape = left_shift_machine.run(
|
|
left_shift_input, head=1
|
|
)
|
|
print("Final State (Left Shift):", left_shift_final_state)
|
|
left_shift_final_tape_str = "".join(left_shift_final_tape).strip()
|
|
print("Final Tape (Left Shift):", left_shift_final_tape_str)
|