Research source · python
verify_local_fringe_certificates.py
site/public/research-artifacts/foundations/verify_local_fringe_certificates.py
222 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 2731394b61de433dc034c144d6ca4d3268a1d75da2162de2fe564b6cadf7ea46
#!/usr/bin/env python3
"""Check the authored constructor-rule IR, not OCaml or Rocq source.
The companion note proves soundness of this finite procedure. This program
does not prove its own soundness and is not a proof-assistant development.
No finite-word sampling is used to accept an equation.
"""
import hashlib
import itertools
import json
from pathlib import Path
class Rejected(Exception):
def __init__(self, stage, reason):
self.stage, self.reason = stage, reason
def require(ok, stage, reason):
if not ok:
raise Rejected(stage, reason)
def cat(parts):
return tuple(itertools.chain.from_iterable(parts))
class Checker:
def __init__(self, data):
self.alphabet = set(data["alphabet"])
self.sorts = data["sorts"]
self.cons = data["constructors"]
require(all(isinstance(n, int) and n > 0 for n in self.sorts.values()),
"signature", "component counts must be positive integers")
for name, c in self.cons.items():
require(c["sort"] in self.sorts and
all(s in self.sorts for s in c["children"]),
"signature", f"unknown sort in {name}")
require(len(c["meaning"]) == self.sorts[c["sort"]],
"signature", f"wrong component count in {name}")
# Validate interpretation references with distinct symbolic children.
xs = [tuple((("signature", i, j),) for j in range(self.sorts[s]))
for i, s in enumerate(c["children"])]
self.interpret(name, xs)
self.productive = set()
while True:
new = {c["sort"] for c in self.cons.values()
if all(s in self.productive for s in c["children"])}
if new <= self.productive:
break
self.productive |= new
self.q = max((len(c["children"]) for c in self.cons.values()), default=0)
def interpret(self, name, xs):
out = []
for expr in self.cons[name]["meaning"]:
pieces = []
for t in expr:
if isinstance(t, str):
require(t in self.alphabet, "signature", "unknown letter")
pieces.append((("letter", t),))
else:
require(isinstance(t, list) and len(t) == 2 and
all(type(i) is int and i >= 0 for i in t) and
t[0] < len(xs) and t[1] < len(xs[t[0]]),
"signature", "invalid child-component reference")
pieces.append(xs[t[0]][t[1]])
out.append(cat(pieces))
return tuple(out)
def pattern(self, p, sort, env, depth=0):
"""Return symbolic components, maximum old address, constructor height."""
require(sort in self.productive, "shape", f"uninhabited sort {sort}")
if "var" in p:
require(set(p) == {"var", "sort"} and p["sort"] == sort,
"shape", "ill-sorted frontier variable")
name = p["var"]
require(name not in env, "shape", "nonlinear/repeated variable")
v = tuple((("variable", name, j),) for j in range(self.sorts[sort]))
env[name] = (sort, v)
return v, depth, 0
require(set(p) <= {"ctor", "args", "as"} and
p.get("ctor") in self.cons, "shape", "unknown pattern constructor")
c = self.cons[p["ctor"]]
require(c["sort"] == sort and len(p.get("args", [])) == len(c["children"]),
"shape", "ill-sorted constructor pattern")
vals, radius, height = [], depth, 1
for child, s in zip(p["args"], c["children"]):
v, r, h = self.pattern(child, s, env, depth + 1)
vals.append(v)
radius, height = max(radius, r), max(height, h + 1)
v = self.interpret(p["ctor"], vals)
if "as" in p:
require(p["as"] not in env, "shape", "repeated internal-node binding")
env[p["as"]] = (sort, v)
return v, radius, height
def shapes(self, sort, height):
if height == 0:
return [("*", sort)]
ans = []
for name, c in self.cons.items():
if c["sort"] != sort or not all(s in self.productive for s in c["children"]):
continue
for children in itertools.product(
*(self.shapes(s, height - 1) for s in c["children"])):
ans.append((name, children))
return ans
def matches(self, p, shape):
if "var" in p:
return True
return (p["ctor"] == shape[0] and
all(self.matches(x, y) for x, y in zip(p["args"], shape[1])))
def spec_expr(self, expr, pre, post):
out = []
for t in expr:
if isinstance(t, str):
require(t in self.alphabet, "specification", "unknown letter")
out.append((("letter", t),))
continue
require(isinstance(t, dict) and len(t) == 1 and
next(iter(t)) in {"pre", "post"},
"specification", "invalid specification token")
kind, ij = next(iter(t.items()))
vals = pre if kind == "pre" else post
require(isinstance(ij, list) and len(ij) == 2 and
all(type(i) is int and i >= 0 for i in ij) and
ij[0] < len(vals) and ij[1] < len(vals[ij[0]]),
"specification", "invalid specification reference")
out.append(vals[ij[0]][ij[1]])
return cat(out)
def check(self, op):
require(all(s in self.productive for s in op["inputs"] + op["outputs"]),
"shape", "operation uses an uninhabited/unknown sort")
require(op["rules"], "shape", "no rules")
prepared, height, radius, allocation = [], 0, 0, 0
for rule in op["rules"]:
require(len(rule["patterns"]) == len(op["inputs"]),
"shape", "wrong number of input patterns")
env, pre = {}, []
for p, s in zip(rule["patterns"], op["inputs"]):
v, r, h = self.pattern(p, s, env)
pre.append(v)
radius, height = max(radius, r), max(height, h)
for slot in rule["fresh"]:
require(slot["id"] not in env and slot["ctor"] in self.cons,
"shape", "unknown constructor or reused fresh-slot name")
c = self.cons[slot["ctor"]]
require(len(slot["args"]) == len(c["children"]),
"shape", "wrong fresh arity")
for a, s in zip(slot["args"], c["children"]):
require(a in env and env[a][0] == s, "shape",
"ill-sorted, cyclic, or forward fresh reference")
env[slot["id"]] = (
c["sort"], self.interpret(slot["ctor"],
[env[a][1] for a in slot["args"]]))
require(len(rule["roots"]) == len(op["outputs"]),
"shape", "wrong output arity")
for root, s in zip(rule["roots"], op["outputs"]):
require(root in env and env[root][0] == s,
"shape", "ill-sorted/unknown output root")
require(rule["tag"] in op["contracts"],
"specification", "undeclared output tag")
post = [env[x][1] for x in rule["roots"]]
allocation = max(allocation, len(rule["fresh"]))
prepared.append((rule, pre, post))
cells = 0
for roots in itertools.product(*(self.shapes(s, height) for s in op["inputs"])):
matches = sum(all(self.matches(p, t) for p, t in zip(r["patterns"], roots))
for r in op["rules"])
require(matches == 1, "coverage",
f"truncated input cell matches {matches} rules")
cells += 1
for key, actual in (("r", radius), ("A", allocation)):
budget = op["budget"][key]
require(type(budget) is int and budget >= actual, "resource",
f"{key} needs {actual}, declared {budget}")
equations = []
for rule, pre, post in prepared:
for index, equation in enumerate(op["contracts"][rule["tag"]]):
require(len(equation) == 2, "specification", "not an equation pair")
lhs = self.spec_expr(equation[0], pre, post)
rhs = self.spec_expr(equation[1], pre, post)
require(lhs == rhs, "equation",
f'{rule["name"]} equation {index}: {lhs!r} != {rhs!r}')
equations.append({"rule": rule["name"], "index": index,
"normal_form": lhs})
return {"status": "accepted", "q_signature": self.q,
"r": radius, "A": allocation, "coverage_cells": cells,
"equations": equations}
def main():
path = Path(__file__).with_name("local-fringe-certificates.json")
data = json.loads(path.read_text())
checker = Checker(data)
reports = []
for op in data["operations"]:
try:
result = checker.check(op)
except Rejected as exc:
result = {"status": "rejected", "stage": exc.stage, "reason": exc.reason}
expected = op["expected"]
require(result["status"] == expected["status"] and
("stage" not in expected or result.get("stage") == expected["stage"]),
"regression", f'{op["name"]}: {result}, expected {expected}')
reports.append({"name": op["name"], **result})
print(json.dumps({
"scope": "Exact symbolic normalization and finite shape/resource checks "
"for the authored constructor-rule JSON only. No OCaml extraction, "
"Rocq proof, or complete catenable-deque certificate.",
"input_sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
"checker_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
"reports": reports
}, indent=2))
if __name__ == "__main__":
main()