Research source · python
verify_substitution_stable_restoration.py
site/public/research-artifacts/foundations/verify_substitution_stable_restoration.py
229 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 412fa04e4267e52d6f8d140d2530be9352cd686be7e7b8a58ed7f47c5b48c55a
#!/usr/bin/env python3
"""Construct selected finite stable summaries; no proof-assistant claim."""
from collections import deque
from itertools import permutations, product
from pathlib import Path
import json
class Group:
def __init__(self, elements, identity, multiplication):
self.elements = tuple(elements)
self.identity = identity
self.mul = multiplication
self.inverse = {x: next(y for y in self.elements
if multiplication(x, y) == identity
and multiplication(y, x) == identity)
for x in self.elements}
def construct(group, alphabet, initial_evaluation, transforms, word_bound):
positions = {a: i for i, a in enumerate(alphabet)}
def evaluate(phi, word):
value = group.identity
for a in word:
value = group.mul(value, phi[positions[a]])
return value
def substitute(word, h):
return ''.join(h[a] for a in word)
evaluations = [initial_evaluation]
evaluation_set = {initial_evaluation}
queue = deque(evaluations)
while queue:
phi = queue.popleft()
for _, h, _ in transforms.values():
child = tuple(evaluate(phi, h[a]) for a in alphabet)
if child not in evaluation_set:
evaluation_set.add(child)
evaluations.append(child)
queue.append(child)
assert len(evaluations) <= len(group.elements) ** len(alphabet)
evaluation_index = {phi: i for i, phi in enumerate(evaluations)}
def summary(word):
return tuple(evaluate(phi, word) for phi in evaluations)
def push(state, a):
return tuple(group.mul(value, phi[positions[a]])
for value, phi in zip(state, evaluations))
def pop(state, a):
return tuple(group.mul(value, group.inverse[phi[positions[a]]])
for value, phi in zip(state, evaluations))
def boundary(state, data):
u, h, v = data
result = []
for phi in evaluations:
child = tuple(evaluate(phi, h[a]) for a in alphabet)
index = evaluation_index[child]
result.append(group.mul(group.mul(evaluate(phi, u), state[index]),
evaluate(phi, v)))
return tuple(result)
initial = summary('')
representatives = {initial: ''}
queue = deque([initial])
while queue:
state = queue.popleft()
for a in alphabet:
nxt = push(state, a)
if nxt not in representatives:
representatives[nxt] = representatives[state] + a
queue.append(nxt)
inverse_entries = boundary_entries = 0
for state, word in representatives.items():
assert state == summary(word)
for a in alphabet:
assert pop(push(state, a), a) == state
assert push(pop(state, a), a) == state
assert pop(state, a) in representatives
inverse_entries += 1
for data in transforms.values():
u, h, v = data
nxt = boundary(state, data)
assert nxt in representatives
assert nxt == summary(u + substitute(word, h) + v)
boundary_entries += 1
# Independent word interpreter also checks collisions and legal undo.
word_cases = 0
for length in range(word_bound + 1):
for letters in product(alphabet, repeat=length):
word = ''.join(letters)
state = summary(word)
assert state in representatives
if word:
assert pop(state, word[-1]) == summary(word[:-1])
for data in transforms.values():
u, h, v = data
assert boundary(state, data) == summary(u + substitute(word, h) + v)
word_cases += 1
return {
'group_order': len(group.elements),
'evaluation_orbit_size': len(evaluations),
'reachable_summary_states': len(representatives),
'all_push_inverse_entries_checked': inverse_entries,
'all_boundary_entries_checked': boundary_entries,
'transform_names': list(transforms),
'raw_word_max_length': word_bound,
'raw_words_checked': word_cases,
}, summary
def horizon_check(r, word_bound, witness_max):
modulus = 2 ** r
def update(state, letter):
n, bits = state
bits = list(bits)
if letter == 'a':
for k in range(r + 1):
if n % (2 ** k) == 0:
bits[k] ^= 1
return ((n + 1) % modulus, tuple(bits))
def undo(state, letter):
n, bits = state
n = (n - 1) % modulus
bits = list(bits)
if letter == 'a':
for k in range(r + 1):
if n % (2 ** k) == 0:
bits[k] ^= 1
return (n, tuple(bits))
table_entries = words = 0
for n in range(modulus):
for bits in product((0, 1), repeat=r + 1):
state = (n, bits)
for a in 'ab':
assert undo(update(state, a), a) == state
table_entries += 1
for length in range(word_bound + 1):
for letters in product('ab', repeat=length):
word = ''.join(letters)
state = (0, (0,) * (r + 1))
for a in word:
state = update(state, a)
raw = word
for k in range(r + 1):
assert state[1][k] == raw.count('a') % 2
raw = raw[::2]
words += 1
rows = []
for j in range(witness_max + 1):
raw = 'b' * (2 ** j) + 'a'
observations = []
for k in range(witness_max + 2):
observations.append(raw.count('a') % 2)
assert observations[-1] == int(k <= j)
raw = raw[::2]
rows.append(observations)
return {'horizon': r, 'state_bound': modulus * 2 ** (r + 1),
'all_append_inverse_entries': table_entries,
'raw_word_max_length': word_bound, 'raw_words': words,
'separating_family_max_j': witness_max,
'separating_family_observations': rows,
'scope': 'Finite corroboration only; no all-state-size impossibility proof.'}
def main():
c2 = Group((0, 1), 0, lambda x, y: (x + y) % 2)
identity = {'a': 'a', 'b': 'b'}
swap = {'a': 'b', 'b': 'a'}
fibonacci = {'a': 'ab', 'b': 'a'}
erase_b = {'a': 'a', 'b': ''}
transforms = {
'swap': ('', swap, ''),
'fibonacci': ('', fibonacci, ''),
'erase_b': ('', erase_b, ''),
'surround': ('ab', identity, 'a'),
}
minimal, _ = construct(c2, 'ab', (1, 0), {}, 6)
refined, summary = construct(c2, 'ab', (1, 0), {'swap': transforms['swap']}, 9)
expanded, _ = construct(c2, 'ab', (1, 0), transforms, 9)
assert minimal['reachable_summary_states'] == 2
assert refined['evaluation_orbit_size'] == 2
assert refined['reachable_summary_states'] == 4
assert len({summary(w) for w in ('', 'a', 'b', 'ab')}) == 4
elements = tuple(permutations(range(3)))
# Product is in reading order: first x, then y.
s3 = Group(elements, (0, 1, 2), lambda x, y: tuple(y[x[i]] for i in range(3)))
noncommutative, noncomm_summary = construct(
s3, 'ab', ((1, 0, 2), (1, 2, 0)), transforms, 7)
assert noncomm_summary('ab') != noncomm_summary('ba')
# A minimal forward machine for ends-in-b fails the necessary test.
last_b_updates = {'a': (0, 0), 'b': (1, 1)}
assert any(len(set(update)) != 2 for update in last_b_updates.values())
# Parity alone merges epsilon and b but swap separates their observations.
assert ''.count('a') % 2 == 'b'.count('a') % 2
assert ''.count('b') % 2 != 'b'.count('b') % 2
result = {
'scope': ('Finite evaluation-orbit construction and exhaustive checks of every '
'reachable table entry in the listed examples; independent raw-word '
'evaluation through the stated lengths. No proof assistant, infinite '
'word enumeration, nested-trace or scaffold generator is claimed.'),
'parity_before_refinement': minimal,
'parity_swap': refined,
'parity_multiple_transforms': expanded,
'noncommutative_S3': noncommutative,
'four_observation_pairs_force_four_states': True,
'last_b_minimal_machine_rejected': True,
'decimation_horizons': horizon_check(3, 9, 9),
'general_proof': 'Written finite-orbit and permutation argument in companion note.',
}
Path(__file__).with_name('substitution-stable-restoration-output.json').write_text(
json.dumps(result, indent=2) + '\n')
print(json.dumps(result, indent=2))
if __name__ == '__main__':
main()