Skip to main content

Multi-tape Turing Machine simulator in Python

Project description

mtm — Multi-tape Turing Machine simulator in Python

mtm is a small, reusable library for simulating multi-tape Turing Machines in Python.

It provides:

  • A core MultiTapeTuringMachine simulator.
  • A Tape abstraction with infinite tapes in both directions.
  • A Direction enum for head movements.
  • A TuringMachineDefinition class to encapsulate reusable machine definitions.
  • A console helper (animate_run) to visualize head movements as a terminal animation.
  • Ready-to-use example machines under mtm.examples.

The goal is to make it easy to experiment with Turing Machines, build examples for complexity theory courses, and integrate the simulator into other projects (GUIs, notebooks, etc.).


Installation

From PyPI:

pip install multitape-tm

From the project root (where pyproject.toml lives):

python -m venv .venv
source .venv/bin/activate   # on Windows: .venv\Scripts\activate
python -m pip install -e .

This installs mtm in editable mode, so changes to the source code are immediately reflected when you import the package.


Quick start

Basic 1-tape example

The smallest possible example: a 1-tape TM that moves right over a run of a’s and accepts when it hits blank.

from mtm import MultiTapeTuringMachine, Direction

# States and alphabets
states = {"q0", "q_accept"}
input_alphabet = {"a"}
tape_alphabet = {"a", "_"}
blank = "_"

start_state = "q0"
accept_states = {"q_accept"}

# Transition function:
# (state, (symbols_on_tapes, ...)) -> (new_state, (symbols_to_write, ...), (moves, ...))
transitions = {
    # While reading 'a', move right
    ("q0", ("a",)): ("q0", ("a",), (Direction.RIGHT,)),
    # When reaching blank, accept
    ("q0", ("_",)): ("q_accept", ("_",), (Direction.STAY,)),
}

tm = MultiTapeTuringMachine(
    states=states,
    input_alphabet=input_alphabet,
    tape_alphabet=tape_alphabet,
    blank=blank,
    transitions=transitions,
    start_state=start_state,
    accept_states=accept_states,
    reject_states=set(),
    num_tapes=1,
    initial_inputs=["aaa"],
)

result = tm.run()
print("Final status:", result)
print("Final configuration:", tm.get_configuration())

Animating the heads in the terminal

mtm.console.animate_run clears the screen every step and shows a live “animation” of the tape(s), with the head position indicated by [...].

from mtm import MultiTapeTuringMachine, Direction, animate_run

states = {"q0", "q_accept"}
input_alphabet = {"a"}
tape_alphabet = {"a", "_"}
blank = "_"
start_state = "q0"
accept_states = {"q_accept"}

transitions = {
    ("q0", ("a",)): ("q0", ("a",), (Direction.RIGHT,)),
    ("q0", ("_",)): ("q_accept", ("_",), (Direction.STAY,)),
}

tm = MultiTapeTuringMachine(
    states=states,
    input_alphabet=input_alphabet,
    tape_alphabet=tape_alphabet,
    blank=blank,
    transitions=transitions,
    start_state=start_state,
    accept_states=accept_states,
    reject_states=set(),
    num_tapes=1,
    initial_inputs=["aaa"],
)

animate_run(tm, max_steps=50, delay=0.2)

Output (sketch):

Multi-tape Turing Machine
========================================
Step : 3
State: q0

Tape 0:  a  a [a] _

(press Ctrl+C to stop)

Library overview

Core types

  • Tape

    • Represents an infinite tape in both directions.

    • Stores only non-blank cells in a dictionary index -> symbol.

    • Key methods:

      • read() -> str
      • write(symbol: str) -> None
      • move(direction: int) -> None
      • __str__() gives a human-readable view with the head wrapped in [...].
  • Direction (enum)

    • Direction.LEFT = -1
    • Direction.RIGHT = 1
    • Direction.STAY = 0
  • MultiTapeTuringMachine

    • Simulates a TM with k tapes.

    • Constructor parameters:

      • states: iterable of states (typically strings).

      • input_alphabet: symbols that may appear in the input.

      • tape_alphabet: symbols that may appear on the tapes (must include input_alphabet and blank).

      • blank: blank symbol.

      • transitions: dict with keys and values:

        • Key: (state, (s1, ..., sk))

        • Value: (new_state, (w1, ..., wk), (m1, ..., mk))

          • wi are symbols to write.
          • mi are movements (Direction.LEFT, Direction.RIGHT, Direction.STAY, or -1, 0, 1).
      • start_state

      • accept_states

      • reject_states

      • num_tapes

      • initial_inputs: list of strings, one per tape.

    • Main methods:

      • step() -> str

        • Executes one step.
        • Returns "RUNNING", "ACCEPT", "REJECT" or "HALT".
      • run(max_steps: int = 10_000) -> str

        • Runs until halting, accepting/rejecting, or reaching max_steps.
      • reset(initial_inputs: Optional[Sequence[str]] = None) -> None

      • get_configuration() -> dict

        • Returns { "state": ..., "tapes": [...], "step": ... }.
  • TuringMachineDefinition

    • A dataclass that stores a reusable definition of a machine:

      • states
      • input_alphabet
      • tape_alphabet
      • blank
      • transitions
      • start_state
      • accept_states
      • reject_states
      • num_tapes
    • Method:

      • create_machine(initial_inputs: Optional[Sequence[str]] = None) -> MultiTapeTuringMachine

    This is intended for building reusable models: you define the structure once, and then create many instances with different inputs.


Using the built-in examples

The package includes several predefined Turing Machine definitions under mtm.examples.

All examples accept an input string and return a MultiTapeTuringMachine instance ready to run or animate.

1. Binary palindrome (2 tapes)

mtm.examples.palindrome_2tape implements a 2-tape TM that checks if a binary string is a palindrome.

from mtm.examples import build_palindrome_2tape_machine
from mtm import animate_run

tm = build_palindrome_2tape_machine("0110")
status = animate_run(tm, max_steps=200, delay=0.3)
print("Final status:", status)
  • Tape 1: input.
  • Tape 2: used for marks.
  • Accepts if the string is a palindrome, rejects by lack of transitions.

2. Language aⁿ bⁿ cⁿ (1 tape)

mtm.examples.abc_equal implements a 1-tape TM for the language:

L = { aⁿ bⁿ cⁿ | n ≥ 1 }

from mtm.examples import build_abc_equal_machine
from mtm import animate_run

tm = build_abc_equal_machine("aabbcc")  # n = 2
status = animate_run(tm, max_steps=200, delay=0.3)
print("Final status:", status)

The machine:

  1. Searches for the next unmarked a, marks it as X.
  2. Searches for the next unmarked b, marks it as Y.
  3. Searches for the next unmarked c, marks it as Z.
  4. Returns to the left end and repeats.
  5. Accepts if no a remain and there are no extra b or c.

3. Language w%w (1 tape)

mtm.examples.ww_delimiter implements a 1-tape TM for:

L = { w % w | w ∈ {a, b}* }

from mtm.examples import build_ww_delimiter_machine
from mtm import animate_run

tm = build_ww_delimiter_machine("abba%abba")
status = animate_run(tm, max_steps=400, delay=0.3)
print("Final status:", status)

The machine:

  1. Scans the first w, marking letters as X or Y.
  2. For each marked letter before %, it looks for a matching unmarked letter after %.
  3. When there are no unmarked letters before %, it checks that no unmarked letters remain after %.
  4. Accepts if and only if the two halves are identical.

Defining your own machines

You have two main options:

Option A: Use MultiTapeTuringMachine directly

This is the most direct, flexible way.

from mtm import MultiTapeTuringMachine, Direction

states = {"q0", "q_accept"}
input_alphabet = {"0", "1"}
tape_alphabet = {"0", "1", "_"}
blank = "_"

transitions = {
    # Toy example: move right while reading 0/1, accept on blank
    ("q0", ("0",)): ("q0", ("0",), (Direction.RIGHT,)),
    ("q0", ("1",)): ("q0", ("1",), (Direction.RIGHT,)),
    ("q0", ("_",)): ("q_accept", ("_",), (Direction.STAY,)),
}

tm = MultiTapeTuringMachine(
    states=states,
    input_alphabet=input_alphabet,
    tape_alphabet=tape_alphabet,
    blank=blank,
    transitions=transitions,
    start_state="q0",
    accept_states={"q_accept"},
    reject_states=set(),
    num_tapes=1,
    initial_inputs=["0101"],
)

Option B: Subclass TuringMachineDefinition

Use this if you want a reusable library model that you can instantiate many times with different inputs (similar to the examples).

from __future__ import annotations
from typing import Dict, Set

from mtm import TuringMachineDefinition, MultiTapeTuringMachine, Direction
from mtm.machine import State, Symbol, TransitionKey, TransitionValue


class MyToyDefinition(TuringMachineDefinition):
    """
    Example of a custom 1-tape TM definition.
    Accepts any string of 0/1 that ends in 1.
    """

    def __init__(self) -> None:
        states: Set[State] = {"q0", "q_accept", "q_reject"}
        input_alphabet: Set[Symbol] = {"0", "1"}
        tape_alphabet: Set[Symbol] = {"0", "1", "_"}
        blank: Symbol = "_"

        transitions: Dict[TransitionKey, TransitionValue] = {
            ("q0", ("0",)): ("q0", ("0",), (Direction.RIGHT,)),
            ("q0", ("1",)): ("q0", ("1",), (Direction.RIGHT,)),
            # On blank, last symbol was 1 if the head is to the right of a 1
            # (here, for simplicity, we just accept on blank)
            ("q0", ("_",)): ("q_accept", ("_",), (Direction.STAY,)),
        }

        super().__init__(
            states=states,
            input_alphabet=input_alphabet,
            tape_alphabet=tape_alphabet,
            blank=blank,
            transitions=transitions,
            start_state="q0",
            accept_states={"q_accept"},
            reject_states={"q_reject"},
            num_tapes=1,
        )


# Helper function, similar to the ones in mtm.examples
def build_my_toy_machine(input_string: str) -> MultiTapeTuringMachine:
    definition = MyToyDefinition()
    return definition.create_machine(initial_inputs=[input_string])

Usage:

from my_module import build_my_toy_machine
from mtm import animate_run

tm = build_my_toy_machine("0101")
animate_run(tm)

This pattern is recommended if you are building a collection of Turing Machines for a course, a paper, or a larger project.


Project structure (for contributors)

src/
  mtm/
    __init__.py
    tape.py               # Tape + Direction
    machine.py            # MultiTapeTuringMachine
    console.py            # animate_run for terminal animation
    definition.py         # TuringMachineDefinition
    examples/
      __init__.py
      palindrome_2tape.py # binary palindrome with 2 tapes
      abc_equal.py        # a^n b^n c^n
      ww_delimiter.py     # w%w

Local top-level demo scripts used for manual testing (not published) are kept outside src/ and ignored by git (see .gitignore).


License

This project is licensed under the Apache License 2.0.

You are free to use, modify, and distribute this code (including in commercial and closed-source projects) as long as you keep the copyright and license notices, and respect the terms of the Apache 2.0 license.

Roadmap / Ideas

  • More built-in examples (unary addition, multiplication, etc.).
  • Ready-made GUIs for step-by-step visualization.
  • Export/import Turing Machines from JSON or YAML.
  • Jupyter notebook helpers.

Contributions and suggestions are very welcome 🚀

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multitape_tm-1.0.4.tar.gz (17.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multitape_tm-1.0.4-py3-none-any.whl (17.8 kB view details)

Uploaded Python 3

File details

Details for the file multitape_tm-1.0.4.tar.gz.

File metadata

  • Download URL: multitape_tm-1.0.4.tar.gz
  • Upload date:
  • Size: 17.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for multitape_tm-1.0.4.tar.gz
Algorithm Hash digest
SHA256 47a6e4bc91a3c29f7c8622b9477b377612b97f2d3a12c66e4ea3006c8b397c48
MD5 61e781b7bc75f612f656cb7d6dbb5d30
BLAKE2b-256 82ec7ae65c1aa4f23438b214c91b7102c37c8c9f75d37eaa021a3e969f98a6a4

See more details on using hashes here.

File details

Details for the file multitape_tm-1.0.4-py3-none-any.whl.

File metadata

  • Download URL: multitape_tm-1.0.4-py3-none-any.whl
  • Upload date:
  • Size: 17.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for multitape_tm-1.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 75ca2482903f94ce1a3edb4e9d72f2ebba6f1c5b1be8cef9c7787813f63560c0
MD5 13c32d4d50db238558109688db8fe779
BLAKE2b-256 3c606dec68c1b43c4b423b90be0d9128b93bd1ab48aeba09d88f7ca0024f79f1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page