Research source · python
check_one_counter_certificates.py
site/public/research-artifacts/foundations/check_one_counter_certificates.py
215 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 6a291ecdeccc20237d069873aa547b8f453b6078ef4b9bbf2d61a246144fe21e
#!/usr/bin/env python3
"""Exact finite certificate checker; see one-counter-certificates.md.
Run without arguments for examples and bounded implementation audits.
Run --check instance.json to check one source/clock/rows JSON instance.
No saturation, synthesis, determinization or scaffold generation is implemented.
"""
import argparse
from dataclasses import dataclass
from itertools import product
import json
from math import lcm
@dataclass(frozen=True)
class UP:
T: int
p: int
below: frozenset
residues: frozenset
def __post_init__(self):
if type(self.T) is not int or self.T < 0:
raise ValueError('threshold must be a nonnegative integer')
if type(self.p) is not int or self.p < 1:
raise ValueError('period must be a positive integer')
if any(type(x) is not int or not 0 <= x < self.T for x in self.below):
raise ValueError('invalid finite-prefix member')
if any(type(x) is not int or not 0 <= x < self.p for x in self.residues):
raise ValueError('invalid residue')
def has(self, z):
return z >= 0 and (z in self.below if z < self.T
else z % self.p in self.residues)
def nonempty(self):
return bool(self.below or self.residues)
EMPTY = UP(0, 1, frozenset(), frozenset())
ZERO = UP(1, 1, frozenset({0}), frozenset())
NAT = UP(0, 1, frozenset(), frozenset({0}))
def shifted_failure(A, t, target):
"""Least positive z violating (A intersect positive)+t subset target.
None means the infinite inclusion holds, by the finite-period proof.
"""
if t not in (-1, 0, 1):
raise ValueError('shift outside unit range')
M = max(1, A.T, target.T + 1)
L = lcm(A.p, target.p)
return next((z for z in range(1, M + L)
if A.has(z) and not target.has(z + t)), None)
def enabled(guard, h):
return guard == 'any' or (guard == 'zero' and h == 0) or (
guard == 'positive' and h > 0)
def boundary(e, d, c):
h = max(0, max(e, 0) + d)
H = max(0, max(-e, 0) + c)
return h - H, min(h, H)
def interior(e, d, c):
return e + d - c, min(max(e, 0) + d, max(-e, 0) + c)
def check(instance):
source, clock = instance['source'], instance['clock']
Q, R, alphabet = set(source['states']), set(clock['states']), set(source['alphabet'])
initial = set(source['initial'])
if not initial or not initial <= Q or clock['initial'] not in R:
raise ValueError('invalid initialization')
table = {}
for row in clock['table']:
r, a, nxt, c = row
if r not in R or nxt not in R or a not in alphabet or type(c) is not int or c not in (-1, 0, 1):
raise ValueError('invalid clock transition')
if (r, a) in table:
raise ValueError('duplicate clock transition')
table[r, a] = nxt, c
if set(table) != set(product(R, alphabet)):
raise ValueError('clock must be complete')
rules = source['rules']
for q, a, g, d, nxt in rules:
if q not in Q or nxt not in Q or a not in alphabet or g not in ('zero', 'positive', 'any') or type(d) is not int or d not in (-1, 0, 1):
raise ValueError('invalid source rule')
rows = {}
for row in instance['rows']:
q, r, e = row['q'], row['r'], row['e']
if q not in Q or r not in R or type(e) is not int or (q, r, e) in rows:
raise ValueError('invalid or duplicate certificate row')
rows[q, r, e] = UP(row['T'], row['p'], frozenset(row['below']), frozenset(row['residues']))
for q in sorted(initial):
if not rows.get((q, clock['initial'], 0), EMPTY).has(0):
return {'valid': False, 'reason': 'initialization', 'q': q}
for (q, r, e), A in sorted(rows.items()):
for index, (old, a, guard, d, nxt) in enumerate(rules):
if old != q:
continue
nr, c = table[r, a]
if A.has(0) and enabled(guard, max(e, 0)):
ne, nz = boundary(e, d, c)
if not rows.get((nxt, nr, ne), EMPTY).has(nz):
return {'valid': False, 'reason': 'boundary',
'mode': [q, r, e], 'z': 0, 'rule_index': index,
'target_mode': [nxt, nr, ne], 'target_z': nz}
if guard != 'zero':
ne, t = interior(e, d, c)
z = shifted_failure(A, t, rows.get((nxt, nr, ne), EMPTY))
if z is not None:
return {'valid': False, 'reason': 'interior',
'mode': [q, r, e], 'z': z, 'rule_index': index,
'target_mode': [nxt, nr, ne], 'target_z': z + t}
return {'valid': True, 'bound': max(abs(e) for (_, _, e), A in rows.items() if A.nonempty())}
def row(q, r, e, A):
return {'q': q, 'r': r, 'e': e, 'T': A.T, 'p': A.p,
'below': sorted(A.below), 'residues': sorted(A.residues)}
def one_state(rules, outputs, rows):
return {'source': {'states': [0], 'initial': [0], 'alphabet': list(outputs),
'rules': [[0, a, guard, d, 0] for a, guard, d in rules]},
'clock': {'states': [0], 'initial': 0,
'table': [[0, a, 0, c] for a, c in outputs.items()]},
'rows': [row(0, 0, e, A) for e, A in rows]}
def examples():
bottom = one_state([('x', 'any', -1), ('x', 'any', 0)], {'x': 0}, [(0, ZERO)])
once = one_state([('x', 'zero', 1), ('x', 'positive', 0)], {'x': 0}, [(0, ZERO), (1, ZERO)])
dyck = one_state([('a', 'any', 1), ('b', 'positive', -1),
('x', 'any', 0), ('x', 'zero', -1)],
{'a': 1, 'b': -1, 'x': 0}, [(0, NAT)])
parity = {'source': {'states': [0, 1], 'initial': [0], 'alphabet': ['a'],
'rules': [[0, 'a', 'any', 1, 1], [1, 'a', 'any', 1, 0]]},
'clock': {'states': [0], 'initial': 0, 'table': [[0, 'a', 0, 1]]},
'rows': [row(0, 0, 0, UP(0, 2, frozenset(), frozenset({0}))),
row(1, 0, 0, UP(0, 2, frozenset(), frozenset({1})))]}
clock_once = {'source': bottom['source'],
'clock': {'states': [0, 1], 'initial': 0,
'table': [[0, 'x', 1, 1], [1, 'x', 1, 0]]},
'rows': [row(0, 0, 0, ZERO), row(0, 1, -1, ZERO)]}
unbounded = one_state([('x', 'any', 1), ('x', 'any', 0)], {'x': 0}, [(0, ZERO), (1, ZERO)])
false_ray = one_state([('x', 'any', -1), ('x', 'any', 0)], {'x': 0}, [(0, NAT)])
bad_parity = json.loads(json.dumps(parity))
bad_parity['rows'][1]['residues'] = [0]
return [('bottom_pop_keep', bottom, True), ('guarded_push_once', once, True),
('dyck_with_bottom_noise', dyck, True), ('parity_rows', parity, True),
('clock_ahead_at_boundary', clock_once, True),
('unbounded_source_truncated_certificate', unbounded, False),
('unrestricted_ray_for_bottom_only_source', false_ray, False),
('corrupted_parity_row', bad_parity, False)]
def finite_audit():
# These are implementation corroboration, not unrestricted theorem proofs.
updates = 0
for e, z, d, c in product(range(-5, 6), range(9), (-1, 0, 1), (-1, 0, 1)):
h, H = z + max(e, 0), z + max(-e, 0)
u, v = max(0, h + d), max(0, H + c)
ne, nz = boundary(e, d, c) if z == 0 else interior(e, d, c)
if z:
nz += z
assert (ne, nz) == (u - v, min(u, v))
updates += 1
sets = []
for T, p in product(range(3), range(1, 4)):
for maskF, maskD in product(range(1 << T), range(1 << p)):
sets.append(UP(T, p, frozenset(i for i in range(T) if maskF >> i & 1),
frozenset(i for i in range(p) if maskD >> i & 1)))
inclusions = 0
for A, target, t in product(sets, sets, (-1, 0, 1)):
witness = shifted_failure(A, t, target)
oracle = next((z for z in range(1, 81) if A.has(z) and not target.has(z + t)), None)
assert witness == oracle
inclusions += 1
return {'coordinate_formula_cases': updates,
'coordinate_ranges': {'e': [-5, 5], 'z': [0, 8], 'd_and_c': [-1, 0, 1]},
'periodic_descriptions': len(sets), 'inclusion_cases': inclusions,
'periodic_ranges': {'threshold': [0, 2], 'period': [1, 3],
'prefix_and_residue_subsets': 'all', 'oracle_z': [1, 80]},
'status': 'bounded implementation audit passed'}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--check', metavar='JSON')
args = parser.parse_args()
if args.check:
with open(args.check, encoding='utf-8') as f:
result = check(json.load(f))
print(json.dumps(result, indent=2, sort_keys=True))
raise SystemExit(0 if result['valid'] else 1)
results = []
for name, instance, expected in examples():
result = check(instance)
assert result['valid'] == expected, (name, result)
results.append({'name': name, 'instance': instance, 'exact_check': result})
print(json.dumps({'note': 'one-counter-certificates.md',
'exact_scope': 'local inductive certificate obligations, including infinite periodic inclusions',
'not_implemented': ['saturation', 'certificate synthesis', 'VPA determinization',
'scaffold generation', 'proof-assistant verification'],
'examples': results, 'finite_audit': finite_audit()}, indent=2, sort_keys=True))
if __name__ == '__main__':
main()