Research source · python

verify_reversible_summary_congruence.py

site/public/research-artifacts/foundations/verify_reversible_summary_congruence.py

220 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: 6d996de8f92fbb9a94aa0f79a7c9b23c98ff96162d625c7273e533358e30404d

#!/usr/bin/env python3
"""Finite certificates for the reversible-summary residual theorem.

The script minimizes supplied deterministic Moore machines, checks whether
every generator acts as a permutation on the reachable minimal quotient, and
exhaustively corroborates the common-pop collapse for state sets of size at
most four. It does not prove the general theorem or analyze pushdown systems.
"""

from collections import deque
from dataclasses import dataclass
from itertools import permutations, product
import json
from pathlib import Path


@dataclass(frozen=True)
class Moore:
    states: tuple
    alphabet: tuple
    start: object
    output: dict
    delta: dict


def reachable(machine):
    seen = {machine.start}
    queue = deque([machine.start])
    while queue:
        state = queue.popleft()
        for letter in machine.alphabet:
            target = machine.delta[state, letter]
            if target not in seen:
                seen.add(target)
                queue.append(target)
    return seen


def minimize(machine):
    states = reachable(machine)
    blocks = {}
    for state in states:
        blocks.setdefault(machine.output[state], set()).add(state)
    partition = list(blocks.values())

    while True:
        owner = {state: index for index, block in enumerate(partition) for state in block}
        refined = {}
        for state in states:
            signature = (
                machine.output[state],
                tuple(owner[machine.delta[state, letter]] for letter in machine.alphabet),
            )
            refined.setdefault(signature, set()).add(state)
        next_partition = list(refined.values())
        if {frozenset(block) for block in next_partition} == {
            frozenset(block) for block in partition
        }:
            partition = next_partition
            break
        partition = next_partition

    owner = {state: index for index, block in enumerate(partition) for state in block}
    quotient_delta = {
        (index, letter): owner[machine.delta[next(iter(block)), letter]]
        for index, block in enumerate(partition)
        for letter in machine.alphabet
    }
    quotient_output = {
        index: machine.output[next(iter(block))]
        for index, block in enumerate(partition)
    }
    return Moore(
        tuple(range(len(partition))),
        machine.alphabet,
        owner[machine.start],
        quotient_output,
        quotient_delta,
    )


def analyze(name, machine):
    minimal = minimize(machine)
    transitions = {}
    failures = []
    for letter in minimal.alphabet:
        image = tuple(minimal.delta[state, letter] for state in minimal.states)
        injective = len(set(image)) == len(minimal.states)
        transitions[letter] = {"image": image, "injective": injective}
        if not injective:
            witness = None
            for left in minimal.states:
                for right in minimal.states:
                    if left < right and minimal.delta[left, letter] == minimal.delta[right, letter]:
                        witness = [left, right, minimal.delta[left, letter]]
                        break
                if witness:
                    break
            failures.append({"letter": letter, "merge": witness})
    return {
        "name": name,
        "minimal_states": len(minimal.states),
        "permutation_summary": not failures,
        "transitions": transitions,
        "failures": failures,
    }


def parity_machine():
    return Moore(
        (0, 1), ("X",), 0,
        {0: 0, 1: 1},
        {(0, "X"): 1, (1, "X"): 0},
    )


def mod_three_machine():
    return Moore(
        (0, 1, 2), ("A",), 0,
        {0: 0, 1: 1, 2: 2},
        {(0, "A"): 1, (1, "A"): 2, (2, "A"): 0},
    )


def presence_machine():
    return Moore(
        (0, 1), ("X", "A"), 0,
        {0: False, 1: True},
        {
            (0, "X"): 1, (1, "X"): 1,
            (0, "A"): 0, (1, "A"): 1,
        },
    )


def emptiness_machine():
    return Moore(
        (0, 1), ("X",), 0,
        {0: True, 1: False},
        {(0, "X"): 1, (1, "X"): 1},
    )


def rightmost_tag_machine():
    states = ("e", "0", "1")
    alphabet = ("B0", "B1", "A")
    delta = {}
    for state in states:
        delta[state, "A"] = state
        delta[state, "B0"] = "0" if state == "e" else state
        delta[state, "B1"] = "1" if state == "e" else state
    return Moore(states, alphabet, "e", {state: state for state in states}, delta)


def common_pop_exhaustive(max_size=4):
    records = []
    for size in range(1, max_size + 1):
        states = tuple(range(size))
        perms = tuple(permutations(states))
        functions = product(states, repeat=size)
        solutions = 0
        unequal_push_solutions = 0
        checked = 0
        for down in functions:
            left_inverses = []
            for up in perms:
                checked += 1
                if all(down[up[state]] == state for state in states):
                    left_inverses.append(up)
            solutions += len(left_inverses) ** 2
            unequal_push_solutions += sum(
                1 for first in left_inverses for second in left_inverses if first != second
            )
        assert unequal_push_solutions == 0
        records.append({
            "states": size,
            "down_tables_times_permutations_checked": checked,
            "ordered_two_push_solutions": solutions,
            "unequal_push_solutions": unequal_push_solutions,
        })
    return records


def main():
    cases = [
        analyze("parity of hidden height", parity_machine()),
        analyze("hidden height modulo three", mod_three_machine()),
        analyze("presence of X", presence_machine()),
        analyze("exact emptiness", emptiness_machine()),
        analyze("rightmost B0/B1 tag", rightmost_tag_machine()),
    ]
    assert cases[0]["permutation_summary"]
    assert cases[1]["permutation_summary"]
    assert not cases[2]["permutation_summary"]
    assert not cases[3]["permutation_summary"]
    assert not cases[4]["permutation_summary"]

    result = {
        "status": "passed",
        "residual_examples": cases,
        "common_untyped_pop": common_pop_exhaustive(),
        "assurance": (
            "Exact minimization and injectivity checks for the finite examples; "
            "bounded exhaustive corroboration of common-pop collapse through four states."
        ),
        "not_verified": [
            "the general residual theorem",
            "unrestricted pushdown reachability",
            "automatic synthesis from source programs",
            "scaffold generation",
            "proof assistant formalization",
        ],
    }
    output = Path(__file__).with_name("reversible-summary-congruence-output.json")
    output.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n")
    print(json.dumps(result, indent=2, sort_keys=True))


if __name__ == "__main__":
    main()