Research source · python
check_indexed_plans.py
site/public/research-artifacts/foundations/check_indexed_plans.py
359 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 621a02c8794336ecc0469e0bdb978052ee909942648eef560a63b80dd6a63011
#!/usr/bin/env python3
"""Finite affine plan checking, conditional on named primitive contracts.
This is a handwritten contract checker, not OCaml extraction or Rocq proof.
Run with --source PATH to pin the inspected upstream files as well.
"""
from dataclasses import dataclass
from pathlib import Path
import argparse
import hashlib
import json
from itertools import product
PARAMETERS = ('n', 'p', 'r', 's')
class Rejected(ValueError):
pass
def require(ok, message):
if not ok:
raise Rejected(message)
@dataclass(frozen=True)
class Affine:
coefficients: tuple
@staticmethod
def read(x):
if isinstance(x, int):
return Affine((x, 0, 0, 0, 0))
require(isinstance(x, dict) and set(x) <= {'const', *PARAMETERS},
'unknown affine parameter')
require(all(type(v) is int for v in x.values()), 'noninteger coefficient')
return Affine(tuple(x.get(k, 0) for k in ('const', *PARAMETERS)))
def __add__(self, other):
if isinstance(other, int):
other = Affine.read(other)
return Affine(tuple(a + b for a, b in zip(self.coefficients, other.coefficients)))
def __sub__(self, other):
if isinstance(other, int):
other = Affine.read(other)
return Affine(tuple(a - b for a, b in zip(self.coefficients, other.coefficients)))
def nonnegative(self):
return all(c >= 0 for c in self.coefficients)
def at(self, values):
return self.coefficients[0] + sum(c * v for c, v in zip(self.coefficients[1:], values))
@dataclass(frozen=True)
class Type:
sort: str
level: Affine
size: Affine | None = None
arity: int | None = None
kind: str | None = None
left: int | None = None
right: int | None = None
def read_type(t):
require(t['sort'] in ('Stored', 'Buf', 'Chain', 'Semi'), 'unknown sort')
level = Affine.read(t['level'])
require(level.nonnegative(), 'level is not uniformly natural')
if t['sort'] == 'Buf':
size = Affine.read(t['size'])
require(size.nonnegative(), 'occupancy is not uniformly natural')
return Type('Buf', level, size)
if t['sort'] == 'Chain':
require(t['arity'] in (0, 1, 2), 'invalid arity')
require(t['kind'] in ('only', 'left', 'right'), 'invalid kind')
require(type(t['left']) is int and 0 <= t['left'] < 16, 'invalid left color')
require(type(t['right']) is int and 0 <= t['right'] < 16, 'invalid right color')
return Type('Chain', level, arity=t['arity'], kind=t['kind'],
left=t['left'], right=t['right'])
return Type(t['sort'], level)
@dataclass(frozen=True)
class Value:
type: Type
word: tuple
class Checker:
def __init__(self, plan):
self.values = {}
self.substitution = {}
self.module_calls = 0
self.fresh_records = 0
self.depth = 0
for name, root in plan['inputs'].items():
self.values[name] = Value(read_type(root['type']), tuple(root['word']))
require(type(root.get('path_depth', 0)) is int and root.get('path_depth', 0) >= 0,
'invalid declared access path')
self.depth = max(self.depth, root.get('path_depth', 0))
def take(self, name, sort=None):
require(name in self.values, 'unavailable or forward reference')
v = self.values[name]
if sort:
require(v.type.sort == sort, f'expected {sort}, got {v.type.sort}')
return v
def put(self, name, t, word):
require(name not in self.values, 'duplicate binding')
self.values[name] = Value(t, tuple(word))
def normalize(self, word):
answer = ()
for atom in word:
answer += self.normalize(self.substitution[atom]) if atom in self.substitution else (atom,)
return answer
def instruction(self, i):
op = i['op']
if op == 'empty':
t = read_type({'sort': 'Chain', 'level': i['level'], 'arity': 0,
'kind': i['kind'], 'left': i['left'], 'right': i['right']})
self.put(i['out'], t, ())
self.fresh_records += 1
elif op == 'ground':
require(i['letter'] in ('a', 'b'), 'unknown payload letter')
self.put(i['out'], Type('Stored', Affine.read(0)), (i['letter'],))
self.fresh_records += 1
elif op == 'small':
b = self.take(i['buffer'], 'Buf')
require((b.type.size - 3).nonnegative(), 'Small needs at least 3 entries')
self.put(i['out'], Type('Stored', b.type.level + 1), b.word)
self.fresh_records += 1
elif op == 'big':
p, c, s = self.take(i['prefix'], 'Buf'), self.take(i['child'], 'Chain'), self.take(i['suffix'], 'Buf')
require(p.type.level == s.type.level, 'Big buffer level mismatch')
require(c.type.level == p.type.level + 1, 'Big child level mismatch')
require(c.type.kind == 'only', 'Big requires only-kind child')
require((p.type.size - 3).nonnegative() and (s.type.size - 3).nonnegative(),
'Big needs buffers of at least 3 entries')
self.put(i['out'], Type('Stored', p.type.level + 1), p.word + c.word + s.word)
self.fresh_records += 1
elif op == 'pack':
c = self.take(i['chain'], 'Chain')
require(c.type.kind == 'only', 'Semi requires only-kind chain')
self.put(i['out'], Type('Semi', c.type.level), c.word)
self.fresh_records += 1
elif op in ('push', 'concat'):
if op == 'push':
x, c = self.take(i['stored'], 'Stored'), self.take(i['child'], 'Semi')
else:
x, c = self.take(i['left'], 'Semi'), self.take(i['right'], 'Semi')
require(x.type.level == c.type.level, 'chain operation level mismatch')
self.put(i['out'], Type('Semi', c.type.level), x.word + c.word)
self.module_calls += 1
elif op in ('inject3', 'inject_vector'):
p, v = self.take(i['prefix'], 'Buf'), self.take(i['items'], 'Buf')
require(p.type.level == v.type.level, 'injection level mismatch')
if op == 'inject3':
require(v.type.size == Affine.read(3), 'inject3 requires exactly 3 entries')
else:
require(v.type.size in tuple(Affine.read(k) for k in range(3)),
'inject_vector requires fixed 0, 1, or 2 entries')
self.put(i['out'], Type('Buf', p.type.level, p.type.size + v.type.size), p.word + v.word)
self.module_calls += 1
elif op == 'split3':
b = self.take(i['buffer'], 'Buf')
require(len(b.word) == 1 and b.word[0] not in self.substitution,
'split requires fresh opaque buffer word')
if i['case'] == 'short':
require(i['remainder'] in (0, 1, 2), 'invalid short case')
size = Affine.read(i['remainder'])
else:
require(i['case'] == 'long', 'unknown split case')
size = Affine.read(i['remainder'])
require((size - 3).nonnegative(), 'long remainder needs at least 3 entries')
require(b.type.size == size + 3, 'split occupancy equation fails')
uword = (i['three'],)
rword = () if size == Affine.read(0) else (i['rest'],)
used_atoms = {'a', 'b'} | {a for v in self.values.values() for a in v.word}
used_atoms |= {a for w in self.substitution.values() for a in w}
require(b.word[0] not in ('a', 'b') and i['three'] != i['rest']
and i['three'] not in used_atoms and i['rest'] not in used_atoms,
'split word-name collision')
self.substitution[b.word[0]] = uword + rword
self.put(i['three'], Type('Buf', b.type.level, Affine.read(3)), uword)
self.put(i['rest'], Type('Buf', b.type.level, size), rword)
self.module_calls += 1
else:
raise Rejected('unknown operation')
def check(self, plan):
for instruction in plan['instructions']:
self.instruction(instruction)
outputs = []
for spec in plan['outputs']:
v = self.take(spec['value'])
if 'type' in spec:
require(v.type == read_type(spec['type']), 'output type mismatch')
if 'min_size' in spec:
require(v.type.sort == 'Buf' and (v.type.size - spec['min_size']).nonnegative(),
'output occupancy refinement fails')
outputs.append(v.word)
if 'target_word' in plan:
require(self.normalize(sum(outputs, ())) == self.normalize(tuple(plan['target_word'])),
'word identity fails')
return {'module_calls': self.module_calls, 'fresh_records': self.fresh_records,
'declared_old_path_depth': self.depth}
def certify(plan):
return Checker(plan).check(plan)
def buffer(size, word, depth=0, level=None):
return {'type': {'sort': 'Buf', 'level': level or {'n': 1}, 'size': size},
'word': [word], 'path_depth': depth}
def repair_plan(kind, short):
rest = short if short is not None else {'const': 3, 'r': 1}
head_size = short + 3 if short is not None else {'const': 6, 'r': 1}
roots = {'P': buffer({'const': 5, 'p': 1}, 'P'), 'H': buffer(head_size, 'H', 1),
'D': {'type': {'sort': 'Semi', 'level': {'const': 1, 'n': 1}}, 'word': ['D']}}
code = []
target = ['P', 'H', 'D']
child = 'D'
if kind == 'Big':
roots['S'] = buffer({'const': 3, 's': 1}, 'S', 1)
roots['T'] = {'type': {'sort': 'Chain', 'level': {'const': 1, 'n': 1},
'arity': 2, 'kind': 'only', 'left': 1, 'right': 8},
'word': ['T'], 'path_depth': 1}
code += [{'op': 'small', 'buffer': 'S', 'out': 's1'},
{'op': 'push', 'stored': 's1', 'child': 'D', 'out': 'd1'},
{'op': 'pack', 'chain': 'T', 'out': 't1'},
{'op': 'concat', 'left': 't1', 'right': 'd1', 'out': 'd2'}]
child = 'd2'
target = ['P', 'H', 'T', 'S', 'D']
code += [{'op': 'split3', 'buffer': 'H', 'case': 'short' if short is not None else 'long',
'remainder': rest, 'three': 'U', 'rest': 'V'},
{'op': 'inject3', 'prefix': 'P', 'items': 'U', 'out': 'p1'}]
prefix = 'p1'
if short is not None:
code += [{'op': 'inject_vector', 'prefix': 'p1', 'items': 'V', 'out': 'p2'}]
prefix = 'p2'
else:
code += [{'op': 'small', 'buffer': 'V', 'out': 'v1'},
{'op': 'push', 'stored': 'v1', 'child': child, 'out': 'd3'}]
child = 'd3'
return {'inputs': roots, 'instructions': code,
'outputs': [{'value': prefix, 'min_size': 8},
{'value': child, 'type': {'sort': 'Semi', 'level': {'const': 1, 'n': 1}}}],
'target_word': target}
SOURCE_HASHES = {
'theory/Cadeque/Types.v': '4beb995bd9634c6cc275aa053e009065a7ff699e2ad7b04fd2821df97bcd9e23',
'theory/Cadeque/Models.v': 'd19612a21f4e506aedb31657393c437a07d1f2f8e5ed4ebcea4e408d6b05402f',
'lib/cadeque_core.ml': '2a7e36a50e9cec5f3cc06226922ab26e039e1fa0dc1188e879e594f320ae003e',
}
def run():
import copy
accepted = {f'{kind}/{k if k is not None else "long"}': certify(repair_plan(kind, k))
for kind in ('Small', 'Big') for k in (0, 1, 2, None)}
failures = {}
def rejects(name, plan):
try:
certify(plan)
except Rejected as e:
failures[name] = str(e)
else:
raise AssertionError(f'negative control accepted: {name}')
bad = repair_plan('Small', 2)
bad['instructions'][-1:] = [{'op': 'small', 'buffer': 'V', 'out': 'badsmall'},
{'op': 'push', 'stored': 'badsmall', 'child': 'D', 'out': 'badchild'}]
bad['outputs'][0]['value'] = 'p1'
bad['outputs'][1]['value'] = 'badchild'
rejects('two-entry-Small-word-correct', bad)
bad = repair_plan('Small', None)
bad['instructions'][-2:] = [{'op': 'push', 'stored': 'V', 'child': 'D', 'out': 'd3'}]
rejects('omitted-Small-word-correct', bad)
bad = repair_plan('Big', None)
bad['inputs']['S']['type']['level'] = {'const': 1, 'n': 1}
rejects('wrong-suffix-level', bad)
bad = repair_plan('Big', None)
bad['inputs']['T']['type']['kind'] = 'left'
rejects('wrong-child-kind', bad)
bad = repair_plan('Big', None)
bad['inputs']['T']['type']['left'] = 16
rejects('invalid-color', bad)
bad = repair_plan('Big', None)
bad['inputs']['T']['type']['arity'] = 3
rejects('invalid-arity', bad)
bad = repair_plan('Small', 1)
bad['inputs']['P']['type']['size'] = {'const': 5, 'p': -1}
rejects('eventually-negative-occupancy', bad)
bad = repair_plan('Small', None)
bad['instructions'][-1]['child'] = 'd3'
rejects('forward-reference', bad)
bad = repair_plan('Big', None)
bad['instructions'][3]['left'], bad['instructions'][3]['right'] = 'd1', 't1'
rejects('reversed-concat', bad)
# Empty is specialized at each explicit use, independently of stored rank.
empty_samples = 0
for level in (0, {'n': 1}, {'const': 100, 'n': 1}):
for kind, lc, rc in product(('only', 'left', 'right'), range(16), range(16)):
certify({'inputs': {}, 'instructions': [{'op': 'empty', 'out': 'e',
'level': level, 'kind': kind, 'left': lc, 'right': rc}],
'outputs': [{'value': 'e'}], 'target_word': []})
empty_samples += 1
poly = {'inputs': {'P': buffer({'const': 3, 'p': 1}, 'P'),
'S': buffer({'const': 3, 's': 1}, 'S')},
'instructions': [{'op': 'empty', 'out': 'e', 'level': {'const': 1, 'n': 1},
'kind': 'only', 'left': 0, 'right': 15},
{'op': 'big', 'prefix': 'P', 'child': 'e', 'suffix': 'S', 'out': 'b'}],
'outputs': [{'value': 'b', 'type': {'sort': 'Stored', 'level': {'const': 1, 'n': 1}}}],
'target_word': ['P', 'S']}
certify(poly)
bad = copy.deepcopy(poly)
bad['instructions'][0]['kind'] = 'left'
rejects('Big-empty-wrong-kind', bad)
bad = copy.deepcopy(poly)
bad['instructions'][0]['level'] = {'n': 1}
rejects('Big-empty-wrong-level', bad)
# Finite differential corroboration for affine obligation rejection.
arithmetic_cases = 0
for coeffs in product(range(-2, 3), repeat=3):
a = Affine((coeffs[0], coeffs[1], coeffs[2], 0, 0))
brute = all(a.at((n, p, 0, 0)) >= 0 for n, p in product(range(9), repeat=2))
assert a.nonnegative() == brute
arithmetic_cases += 1
return {'scope': 'Generic annotated straight-line contract-plan checker with independent natural affine parameters. Eight finite source-clause subcases checked symbolically; finite Empty/metadata/arithmetic samples and mutation rejection. No OCaml execution/refinement, Rocq build, proof-assistant verification, general type inference, unrestricted plan synthesis, primitive implementation certificate, or iterative closure proof.',
'accepted_repair_plans': accepted, 'rejected_controls': failures,
'Empty_specializations_sampled': empty_samples,
'finite_arithmetic_differential_cases': arithmetic_cases,
'polymorphic_Empty_Big_plan': 'accepted',
'closure_witness': 'P has five entries, z=Small(U) with three entries, green singleton child holding z. Pop leaves Empty; short repair0 leaves Empty, outside the original nonempty-green-child input view.',
'source_commit': '503c5d3ff7f9a20bad1cd7a8f8d7abf4e635d3a0',
'source_hashes': SOURCE_HASHES}
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--source', type=Path)
parser.add_argument('--plan', type=Path, help='check one supplied JSON plan')
args = parser.parse_args()
if args.source:
for path, expected in SOURCE_HASHES.items():
require(hashlib.sha256((args.source / path).read_bytes()).hexdigest() == expected,
f'source hash mismatch: {path}')
if args.plan:
print(json.dumps(certify(json.loads(args.plan.read_text())), indent=2))
else:
print(json.dumps(run(), indent=2))