Research source · python
verify_regular_history_restoration.py
site/public/research-artifacts/foundations/verify_regular_history_restoration.py
222 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 071e169e03081b5c2a969a8dd12aafe1a59a8ce5713ac6f28ee225a7c6207926
#!/usr/bin/env python3
"""Finite evidence for the classical reversible-cover construction in our contract.
No infinite-source or proof-assistant verification is performed. Capacities
are checked against bounded integer search on the small cases; explicit lifts
are checked by all local forward/inverse equations and reachability. The
binary-depth examples enumerate all legal histories, not just sampled traces.
"""
from collections import deque
from itertools import product
import json
from pathlib import Path
from verify_partial_restoration import PartialMoore, minimize, reachable
def components(machine):
"""Small-instance transitive closure, independent of a graph library."""
reach = {q: {q} for q in machine.states}
for (q, _), r in machine.delta.items():
reach[q].add(r)
for k in machine.states:
for q in machine.states:
if k in reach[q]:
reach[q].update(reach[k])
unseen = set(machine.states)
blocks = []
while unseen:
q = min(unseen)
block = {r for r in unseen if r in reach[q] and q in reach[r]}
blocks.append(block)
unseen -= block
owner = {q: i for i, block in enumerate(blocks) for q in block}
parents = {i: set() for i in range(len(blocks))}
for (q, _), r in machine.delta.items():
if owner[q] != owner[r]:
parents[owner[r]].add(owner[q])
order = []
while len(order) < len(blocks):
ready = sorted(i for i in parents if i not in order and parents[i] <= set(order))
assert ready, "component graph must be acyclic"
order.extend(ready)
return blocks, owner, order, reach
def solve(machine):
assert len(machine.starts) == 1
assert reachable(machine) == set(machine.states)
blocks, owner, order, reach = components(machine)
pred = {(r, a): sorted(q for q in machine.states if machine.delta.get((q, a)) == r)
for r in machine.states for a in machine.alphabet}
for (r, a), sources in pred.items():
if len(sources) > 1:
for q in sources:
if q in reach[r]:
p = next(p for p in sources if p != q)
return {"possible": False,
"witness": {"other_source": p, "cyclic_source": q,
"letter": a, "target": r}}
weights = {}
for i in order:
c = max([1] + [sum(weights[q] for q in pred[r, a] if owner[q] != i)
for r in blocks[i] for a in machine.alphabet])
weights.update({q: c for q in blocks[i]})
assert all(sum(weights[q] for q in sources) <= weights[r]
for (r, _), sources in pred.items())
states = {(q, i) for q in machine.states for i in range(weights[q])}
delta, inverse = {}, {}
for (r, a), sources in pred.items():
offset = 0
for q in sources:
for i in range(weights[q]):
source, target = (q, i), (r, offset + i)
assert (target, a) not in inverse
delta[source, a] = target
inverse[target, a] = source
offset += weights[q]
start = (machine.starts[0], 0)
seen, queue = {start}, deque([start])
while queue:
source = queue.popleft()
for a in machine.alphabet:
target = delta.get((source, a))
assert (target is not None) == ((source[0], a) in machine.delta)
if target is not None:
assert target[0] == machine.delta[source[0], a]
assert inverse[target, a] == source
if target not in seen:
seen.add(target)
queue.append(target)
assert seen == states
return {"possible": True, "weights": weights, "states": len(states),
"arrows": len(delta), "delta": delta, "inverse": inverse,
"start": start}
def integer_search(machine, bound):
"""Enumerate feasible capacities, not reversible transition tables."""
feasible = []
for values in product(range(1, bound + 1), repeat=len(machine.states)):
weights = dict(zip(machine.states, values))
if all(sum(weights[q] for q in machine.states
if machine.delta.get((q, a)) == r) <= weights[r]
for r in machine.states for a in machine.alphabet):
feasible.append(values)
return feasible
def moore(states, alphabet, output, edges, start="s"):
return PartialMoore(tuple(states), tuple(alphabet), (start,), output, edges)
def fork(loop=None):
edges = {("s", "0"): "p", ("s", "1"): "q",
("p", "a"): "r", ("q", "a"): "r"}
if loop:
edges["r", loop] = "r"
return moore("spqr", "01ab", {"s": "start", "p": 0, "q": 1, "r": 2}, edges)
def two_state_component():
return moore("spqrt", "01abc", dict(zip("spqrt", range(5))),
{("s", "0"): "p", ("s", "1"): "q",
("p", "a"): "r", ("q", "a"): "r",
("r", "b"): "t", ("t", "c"): "r"})
def bounded_binary(n):
states = ["e"] + [f"{d}:{b}" for d in range(1, n + 1) for b in "01"]
output = {q: ("empty" if q == "e" else q[-1]) for q in states}
edges = {}
for q in states:
d = 0 if q == "e" else int(q.split(":")[0])
if d < n:
edges.update({(q, b): f"{d+1}:{b}" for b in "01"})
return moore(states, "01", output, edges, "e")
def example_certificate(name, machine, expected, search_bound=None):
minimized, blocks = minimize(machine)
solution = solve(minimized)
assert solution["possible"] == (expected is not None)
if expected is not None:
assert solution["states"] == expected
certificate = {"name": name, "forward_residual_states": len(minimized.states),
"residual_blocks": blocks,
**{k: v for k, v in solution.items() if k not in {"delta", "inverse", "start"}}}
if search_bound is not None:
feasible = integer_search(minimized, search_bound)
if expected is None:
assert not feasible
else:
optimum = tuple(solution["weights"][q] for q in minimized.states)
assert optimum in feasible
assert all(all(x <= y for x, y in zip(optimum, candidate)) for candidate in feasible)
certificate["bounded_capacity_search"] = {
"coordinate_range": [1, search_bound],
"vectors_checked": search_bound ** len(minimized.states),
"feasible_vectors": len(feasible),
"scope": "corroboration within this box; not a proof outside it"}
return certificate
def main():
cases = [
example_certificate("fork", fork(), 5, 3),
example_certificate("merge_then_different_letter_loop", fork("b"), 5, 3),
example_certificate("merge_into_same_letter_loop", fork("a"), None, 3),
example_certificate("merge_into_two_state_component", two_state_component(), 7, 3),
example_certificate("parity_with_legal_pop_promise",
moore("st", "X", {"s": 0, "t": 1},
{("s", "X"): "t", ("t", "X"): "s"}), 2, 3),
example_certificate("a_star_b_star_constant_output",
moore("st", "ab", {"s": 0, "t": 0},
{("s", "a"): "s", ("s", "b"): "t", ("t", "b"): "t"}),
None, 6),
]
binary = []
for n in range(1, 9):
machine, blocks = minimize(bounded_binary(n))
solution = solve(machine)
assert len(machine.states) == 2*n + 1
assert solution["states"] == 2**(n+1) - 1
history_states = {"": solution["start"]}
for depth in range(n):
for word in [w for w in history_states if len(w) == depth]:
for bit in "01":
state = solution["delta"][history_states[word], bit]
history_states[word + bit] = state
assert solution["inverse"][state, bit] == history_states[word]
assert machine.output[state[0]] == bit
assert len(set(history_states.values())) == len(history_states)
binary.append({"depth": n, "forward_states": len(machine.states),
"restoration_states": solution["states"],
"all_legal_histories_checked": len(history_states),
"all_restoration_edges_checked": len(history_states) - 1})
# A single failing-edge mutation must be rejected by the local inverse invariant.
sample, _ = minimize(fork())
solution = solve(sample)
by_target = {}
for (source, a), target in solution["delta"].items():
by_target.setdefault((target[0], a), []).append((source, target))
pair = next(edges for edges in by_target.values() if len(edges) >= 2)
(left, target_left), (right, target_right) = pair[:2]
assert left != right and target_left != target_right
a = next(a for (source, a), target in solution["delta"].items()
if source == left and target == target_left)
assert solution["inverse"][target_left, a] != right
output = {
"scope": "Six finite controller cases; binary-depth family n=1..8; all lift edges and reachability; bounded capacity enumeration as specified. Not an infinite-source proof.",
"cases": cases, "binary_depth_family": binary,
"forced_merge_mutation_rejected": True,
}
target = Path(__file__).with_name("regular-history-restoration-output.json")
target.write_text(json.dumps(output, indent=2) + "\n")
print(json.dumps({"cases": len(cases), "binary_depths": len(binary),
"largest_lift": binary[-1]["restoration_states"],
"forced_merge_mutation_rejected": True}))
if __name__ == "__main__":
main()