Research source · python
verify_stack_erasure.py
site/public/research-artifacts/foundations/verify_stack_erasure.py
346 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: e0222727036e647e1a09161e103aca718e85096134e25a9d1efa7017a3af3f76
#!/usr/bin/env python3
"""Regular-invariant certificates plus finite traces; not a proof assistant.
DFA language emptiness verifies invariant closure and realizable local
classes without a stack-depth cutoff. General pushdown post* is imported
in the note, not implemented here. Trace and persistence checks are finite.
"""
from collections import deque
from dataclasses import dataclass
import itertools
import json
from pathlib import Path
@dataclass
class DFA:
alphabet: tuple
start: int
final: frozenset
delta: dict
def advance(self, state, word):
for symbol in word:
state = self.delta[state, symbol]
return state
def accepts(self, word):
return self.advance(self.start, word) in self.final
def simple_dfa(kind):
alphabet = ("A", "X")
if kind == "A*":
return DFA(alphabet, 0, frozenset({0}),
{(0, "A"): 0, (0, "X"): 1, (1, "A"): 1, (1, "X"): 1})
if kind == "X*":
d = simple_dfa("A*")
d.delta = {(s, "X" if a == "A" else "A"): t for (s, a), t in d.delta.items()}
return d
delta = {(0, "X"): 0, (0, "A"): 1, (1, "A"): 1,
(1, "X"): 2, (2, "A"): 2, (2, "X"): 2}
if kind == "X*A*":
return DFA(alphabet, 0, frozenset({0, 1}), delta)
if kind == "X*A+":
return DFA(alphabet, 0, frozenset({1}), delta)
assert kind == "all"
return DFA(alphabet, 0, frozenset({0}), {(0, a): 0 for a in alphabet})
def singleton_dfa(word, alphabet):
sink = len(word) + 1
delta = {(s, a): s + 1 if s < len(word) and word[s] == a else sink
for s in range(sink + 1) for a in alphabet}
return DFA(alphabet, 0, frozenset({len(word)}), delta)
def inclusion_failure(left, left_start, right, right_start):
queue = deque([(left_start, right_start, ())])
seen = {(left_start, right_start)}
while queue:
x, y, word = queue.popleft()
if x in left.final and y not in right.final:
return word
for a in left.alphabet:
pair = (left.delta[x, a], right.delta[y, a])
if pair not in seen:
seen.add(pair)
queue.append((*pair, word + (a,)))
return None
def apply(word, operation):
if operation == "pop":
return word[1:] if word else word
if operation == "keep":
return word
assert operation.startswith("push:")
return (operation[5:],) + word
def invariant_check(machine, invariants):
for q in machine["initial"]:
assert invariants[q].accepts(())
obligations = 0
for (q, top, letter), rules in machine["rules"].items():
src = invariants[q]
for target, operation in rules:
dst = invariants[target]
if top is None:
if src.accepts(()):
assert dst.accepts(apply((), operation)), (q, letter, target)
else:
prefix = apply((top,), operation)
failure = inclusion_failure(src, src.delta[src.start, top],
dst, dst.advance(dst.start, prefix))
assert failure is None, (q, top, letter, target, failure)
obligations += 1
return obligations
def local_classes(dfa, projection):
queue = deque([(dfa.start, None, None, ())])
seen = {(dfa.start, None, None)}
classes = {}
while queue:
state, raw_top, projected_top, word = queue.popleft()
if state in dfa.final:
classes.setdefault((raw_top, projected_top), word)
for a in dfa.alphabet:
rt = a if raw_top is None else raw_top
pt = projection[a] if projected_top is None else projected_top
key = (dfa.delta[state, a], rt, pt)
if key not in seen:
seen.add(key)
queue.append((*key, word + (a,)))
return classes
def signatures(machine, q, top, letter, projection, controls):
out = set()
for target, operation in machine["rules"].get((q, top, letter), ()):
if operation.startswith("push:"):
image = projection[operation[5:]]
mapped = "keep" if image is None else "push:" + image
elif operation == "pop":
mapped = "pop" if top is not None and projection[top] is not None else "keep"
else:
mapped = "keep"
out.add((controls[target], mapped))
return frozenset(out)
def certificate(machine, invariants, projection, controls):
obligations = invariant_check(machine, invariants)
groups = {}
for q, invariant in invariants.items():
for (top, projected_top), witness in local_classes(invariant, projection).items():
groups.setdefault((controls[q], projected_top), []).append((q, top, witness))
failures, quotient_rules, quotient_obs = [], {}, {}
for (control, projected_top), cells in groups.items():
q0, top0, word0 = cells[0]
obs0 = machine["observe"](q0, top0)
quotient_obs[control, projected_top] = obs0
for q, top, word in cells:
if machine["observe"](q, top) != obs0:
failures.append({"kind": "observation", "control": control,
"top": projected_top, "witnesses": [word0, word]})
for a in machine["inputs"]:
s0 = signatures(machine, q0, top0, a, projection, controls)
quotient_rules[control, projected_top, a] = s0
for q, top, word in cells[1:]:
s = signatures(machine, q, top, a, projection, controls)
if s != s0:
failures.append({"kind": "signatures", "control": control,
"top": projected_top, "input": a,
"witnesses": [[q0, list(word0)], [q, list(word)]],
"signatures": [sorted(s0), sorted(s)]})
return {"failures": failures, "rules": quotient_rules, "observations": quotient_obs,
"groups": len(groups), "cells": sum(map(len, groups.values())),
"closure_obligations": obligations}
def logging_example():
states = ("grow", "fall", "yes", "no", "dead")
inputs = ("c", "r", "#", "p")
rules = {}
for q, g, a in itertools.product(states, (None, "A", "X"), inputs):
out = {("dead", "keep")}
if q == "dead":
out = {("dead", "keep")}
elif q in ("yes", "no") and a == "p":
out = {(q, "push:X"), (q, "keep")}
elif q in ("grow", "fall") and a == "#":
out = {("yes" if g is None else "no", "keep")}
elif q == "grow" and a == "c" and g != "X":
out = {("grow", "push:A")}
elif q in ("grow", "fall") and a == "r" and g == "A":
out = {("fall", "pop")}
rules[q, g, a] = out
machine = {"initial": ("grow",), "inputs": inputs, "rules": rules,
"observe": lambda q, top: q == "yes"}
invariants = {"grow": simple_dfa("A*"), "fall": simple_dfa("A*"),
"yes": simple_dfa("X*"), "no": simple_dfa("X*A+"),
"dead": simple_dfa("X*A*")}
return machine, invariants, {"A": "A", "X": None}, {q: q for q in states}
def projected(config, projection, controls):
q, word = config
return controls[q], tuple(projection[g] for g in word if projection[g] is not None)
def successors(configs, rules, letter):
return {(target, apply(word, op)) for q, word in configs
for target, op in rules.get((q, word[0] if word else None, letter), ())}
def logging_audit():
machine, invariants, pi, controls = logging_example()
cert = certificate(machine, invariants, pi, controls)
assert not cert["failures"]
invalid = dict(invariants)
invalid["yes"] = singleton_dfa((), ("A", "X"))
try:
invariant_check(machine, invalid)
except AssertionError:
invalid_rejected = True
else:
invalid_rejected = False
assert invalid_rejected # A log push must leave the proposed singleton.
frontier = [({("grow", ())}, {("grow", ())})]
checked_words = 0
for length in range(8):
following = []
for source, target in frontier:
assert {projected(c, pi, controls) for c in source} == target
assert any(q == "yes" for q, _ in source) == any(q == "yes" for q, _ in target)
for q, word in source:
assert invariants[q].accepts(word)
checked_words += 1
if length < 7:
for a in machine["inputs"]:
following.append((successors(source, machine["rules"], a),
successors(target, cert["rules"], a)))
frontier = following
source = successors({("grow", ())}, machine["rules"], "#")
for j in range(13):
assert {len(word) for _, word in source} == set(range(j + 1))
assert {len(projected(c, pi, controls)[1]) for c in source} == {0}
source = successors(source, machine["rules"], "p")
return {"regular_invariant": {"grow": "A*", "fall": "A*", "yes": "X*",
"no": "X*A+", "dead": "X*A*"},
"closure_obligations": cert["closure_obligations"],
"realizable_cells": cert["cells"], "abstract_groups": cert["groups"],
"certificate": "passed using DFA emptiness, without a depth cutoff",
"invalid_singleton_log_invariant": "rejected as required",
"trace_words_max_length": 7, "trace_words_checked": checked_words,
"raw_spread_example_j": [0, 12]}
def delayed_pop_audit():
states, inputs = ("q", "yes", "no"), ("a", "x", "r", "t")
rules = {}
for q, g, a in itertools.product(states, (None, "A", "X"), inputs):
if q != "q":
out = {(q, "keep")}
elif a in ("a", "x"):
out = {(q, "push:" + ("A" if a == "a" else "X"))}
elif a == "r":
out = {(q, "pop")}
else:
out = {("yes" if g is None else "no", "keep")}
rules[q, g, a] = out
machine = {"initial": ("q",), "inputs": inputs, "rules": rules,
"observe": lambda q, g: q == "yes"}
pi, controls = {"A": "A", "X": None}, {q: q for q in states}
cert = certificate(machine, {q: simple_dfa("all") for q in states}, pi, controls)
witness = next(f for f in cert["failures"] if f.get("input") == "r" and f["top"] == "A")
left, right = {("q", ("A",))}, {("q", ("X", "A"))}
assert {projected(c, pi, controls) for c in left} == {projected(c, pi, controls) for c in right}
for a in "rt":
left, right = successors(left, rules, a), successors(right, rules, a)
assert any(q == "yes" for q, _ in left)
assert not any(q == "yes" for q, _ in right)
return {"certificate": "rejected as required", "pop_witness": witness,
"distinguishing_suffix": "rt"}
def deeper_control_audit():
alphabet = ("A", "B0", "B1", "C0", "C1")
words = {"init": (), "s0": ("B0",), "s1": ("B1",),
"q0": ("A", "B0"), "q1": ("A", "B1"),
"e0": ("C0", "A", "B0"), "e1": ("C1", "A", "B1")}
rules = {("init", None, str(i)): {("s" + str(i), "push:B" + str(i))} for i in range(2)}
for i in range(2):
rules["s" + str(i), "B" + str(i), "a"] = {("q" + str(i), "push:A")}
rules["q" + str(i), "A", "z"] = {("e" + str(i), "push:C" + str(i))}
machine = {"initial": ("init",), "inputs": ("0", "1", "a", "z"),
"rules": rules, "observe": lambda q, g: False}
pi = {a: a for a in alphabet}
controls = {q: "q" if q in ("q0", "q1") else q for q in words}
cert = certificate(machine, {q: singleton_dfa(w, alphabet) for q, w in words.items()}, pi, controls)
assert len({projected((q, w), pi, controls) for q, w in words.items()}) == len(words)
witness = next(f for f in cert["failures"] if f.get("input") == "z")
return {"reachable_configurations": len(words), "projection_injective": True,
"one_top_certificate": "rejected as required", "witness": witness}
def shortcut_audit():
# Each record is an immutable (label, full_tail, saved_filtered_root) tuple.
heap, snapshots = [], []
pi = {"A": "a", "B": "b", "X": None}
def decode(root, field, filtered=False):
out = []
while root is not None:
label, tail, saved = heap[root]
out.append(pi[label] if filtered else label)
assert not filtered or pi[label] is not None
root = (tail, saved)[field]
return tuple(out)
def visit(R, E, word, remaining):
assert decode(R, 0) == word
assert decode(E, 1, True) == tuple(pi[g] for g in word if pi[g] is not None)
snapshots.append((R, E, word))
if not remaining:
return
for operation in ("push:A", "push:B", "push:X", "pop", "keep"):
before = len(heap)
if operation.startswith("push:"):
g = operation[5:]
new_R = len(heap)
heap.append((g, R, E))
new_E = E if pi[g] is None else new_R
elif operation == "pop" and R is not None:
_, new_R, new_E = heap[R]
else:
new_R, new_E = R, E
assert len(heap) - before <= 1
visit(new_R, new_E, apply(word, operation), remaining - 1)
visit(None, None, (), 7)
for R, E, word in snapshots:
assert decode(R, 0) == word
assert decode(E, 1, True) == tuple(pi[g] for g in word if pi[g] is not None)
return {"operation_alphabet": ["push A", "push B", "push X", "pop", "keep"],
"all_sequences_through_length": 7, "retained_snapshots": len(snapshots),
"allocations": len(heap), "max_allocations_per_update": 1,
"full_and_filtered_decoders": "passed before and after all branches"}
def main():
result = {"status": "passed", "regular_certificate": logging_audit(),
"delayed_pop_negative": delayed_pop_audit(),
"semantic_but_nonlocal_negative": deeper_control_audit(),
"persistent_filtered_access": shortcut_audit(),
"assurance": "Executable finite-automaton certificates and finite trace audits; no proof assistant.",
"not_implemented": ["general pushdown post* saturation", "VPA determinization",
"bounded-spread checker", "scaffold compiler"]}
Path(__file__).with_name("stack-erasure-output.json").write_text(json.dumps(result, indent=2) + "\n")
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()