Skip to main content

Post Canonical Systems - A Python implementation of Emil Post's formal string rewriting systems

Project description

Post Canonical Systems

A Python implementation of Emil Post's formal string rewriting systems for computation and formal language exploration.

Python 3.12+ License: MIT

What is this?

Post Canonical Systems are a foundational model of computation developed by mathematician Emil Post in the 1920s. They define formal languages through string rewriting: starting from initial words (axioms) and repeatedly applying production rules to generate new strings. Despite their simplicity, Post systems are Turing-complete and serve as an elegant framework for exploring computability, formal grammars, and proof derivations.

Features

Feature Description
Pattern Matching Variable kinds: ANY (empty or more), NON_EMPTY (1+), SINGLE (exactly 1)
Multi-Antecedent Rules Combine multiple words in a single production
Derivation Tracking Full proof traces showing how each word was derived
Visualization Exports DOT/GraphViz, LaTeX, Mermaid diagrams, ASCII trees
Interactive CLI REPL interface via the pcs command
JSON Serialization Save and load system definitions
SystemBuilder DSL Ergonomic fluent API for system construction
Preset Systems MU Puzzle, Binary Doubler, Palindrome Generator

Installation

pip install post-canonical

Or with uv:

uv add post-canonical

Quick Start

from post_canonical.builder import SystemBuilder

# Build the MU puzzle from Godel, Escher, Bach
system = (SystemBuilder("MIU")
    .var("x")
    .var("y")
    .axiom("MI")
    .rule("$xI -> $xIU", name="add_U")
    .rule("M$x -> M$x$x", name="double")
    .rule("$x III $y -> $x U $y", name="III_to_U")
    .rule("$x UU $y -> $x$y", name="delete_UU")
    .build())

# Generate all derivable words up to 3 steps
words = system.generate_words(max_steps=3)
print(sorted(words, key=lambda w: (len(w), w)))
# ['MI', 'MII', 'MIU', 'MIII', 'MIIU', 'MIIII', 'MIIIU', 'MIUIU']

# Check if a word is reachable
from post_canonical.query import ReachabilityQuery

query = ReachabilityQuery(system)
print(query.is_derivable("MU", max_words=10000))
# 'MU' NOT_FOUND after exploring 10000 words

Variables use $ prefix in patterns ($x, ${x}). Whitespace is ignored, so $x III $y reads cleanly. Three variable kinds are available:

builder = (SystemBuilder("abc")
    .var("x")                      # ANY: matches "" or "a" or "abc"...
    .var("y", kind="non_empty")    # NON_EMPTY: matches "a" or "abc"...
    .var("z", kind="single")       # SINGLE: matches exactly one symbol
)

CLI

The package includes an interactive REPL for exploring systems without writing code:

$ pcs
Post Canonical Systems REPL v2.0.0
Type 'help' for commands.

pcs> alphabet MIU
Alphabet set: {I, M, U}

pcs> axiom MI
Axiom added: MI

pcs> var x
Variable added: x (ANY)

pcs> rule "$xI -> $xIU"
Rule added: $xI -> $xIU

pcs> rule "M$x -> M$x$x"
Rule added: M$x -> M$x$x

pcs> generate 3
Generated 8 words:
  MI, MII, MIU, MIII, MIIU, MIIII, MIIIU, MIUIU

pcs> query "MU"
'MU' NOT_FOUND after exploring 10000 words

pcs> exit
Goodbye.

Visualization

Export derivations as DOT/GraphViz, LaTeX, Mermaid, or ASCII trees:

from post_canonical import create_mu_puzzle
from post_canonical.visualization import to_ascii_tree

system = create_mu_puzzle()
for dw in system.generate(max_steps=3):
    if dw.word == "MIIII":
        print(to_ascii_tree(dw.derivation))
        break
MIIII
+-- MII (double)
    +-- MI (axiom)

Preset Systems

System Import Description
MU Puzzle create_mu_puzzle() Hofstadter's famous puzzle from GEB
Binary Doubler create_binary_doubler() Doubles binary strings: 1 -> 11 -> 1111
Palindrome Generator create_palindrome_generator() Generates all binary palindromes

Requirements

  • Python 3.12+
  • No external dependencies

License

MIT

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

post_canonical-2.2.0.tar.gz (61.4 kB view details)

Uploaded Source

Built Distribution

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

post_canonical-2.2.0-py3-none-any.whl (37.0 kB view details)

Uploaded Python 3

File details

Details for the file post_canonical-2.2.0.tar.gz.

File metadata

  • Download URL: post_canonical-2.2.0.tar.gz
  • Upload date:
  • Size: 61.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for post_canonical-2.2.0.tar.gz
Algorithm Hash digest
SHA256 b28ca1e93efc0ea67c8a43606268279820fefddccb40162b9c27d319938ab251
MD5 372951e7a08b605cb5358afcdbeef862
BLAKE2b-256 dd5d0ef8954edf61296e71616cd541addae13e9a9f015a5c28bf6f868bb222ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for post_canonical-2.2.0.tar.gz:

Publisher: publish.yml on niarenaw/post-canonical

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file post_canonical-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: post_canonical-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 37.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for post_canonical-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1e25395178adc624b0303c53eb13b35990e4e11996b5b244aa3c0a79d455c61a
MD5 51c88fcbab6bf995a655ca2f4c52e29a
BLAKE2b-256 0260a6c8650cbb7cedcf0472247da64586e803f9737aa46bcd11ac63d5e3e527

See more details on using hashes here.

Provenance

The following attestation bundles were made for post_canonical-2.2.0-py3-none-any.whl:

Publisher: publish.yml on niarenaw/post-canonical

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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