Research source · python
check_name_weighted_classes.py
tools/research/check_name_weighted_classes.py
159 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: d0830852f43b7d586bb8ddd1009571b70108d0b6c0137ccf05a24f25f7e7b9f7
#!/usr/bin/env python3
"""Finite semantic checks for assessment 177; not a native implementation."""
from collections import deque
from fractions import Fraction
from itertools import product
import json
def words(n):
return [''.join(bits) for bits in product('01', repeat=n)]
def weight(v):
return Fraction(1, 2 ** (2 * len(v) + 1))
def code(v):
return ''.join('00' if b == '0' else '01' for b in v) + '11'
def clause(v, w):
return f'(-01{v},+1{w});'
def gaps(rows):
occupied = sorted({len(ws) for ws in rows.values()})
nxt = dict(zip(occupied, occupied[1:]))
return {v: nxt.get(len(ws)) == len(ws) + 1 for v, ws in rows.items()}
def prefix_masks(n):
names = words(n)
return sorted({sum(1 << i for i, v in enumerate(names) if v.startswith(p))
for length in range(n + 1) for p in words(length)})
def shortest_costs(n):
"""Independent BFS over all answer vectors and one-prefix XOR edges."""
masks = prefix_masks(n)
dist = {0: 0}
todo = deque([0])
while todo:
x = todo.popleft()
for p in masks:
y = x ^ p
if y not in dist:
dist[y] = dist[x] + 1
todo.append(y)
return dist
def tree_cost(bits, inherited=0):
"""Optimize the root tag, then independently optimize its children."""
if len(bits) == 1:
return bits[0] ^ inherited
middle = len(bits) // 2
return min(t + tree_cost(bits[:middle], inherited ^ t)
+ tree_cost(bits[middle:], inherited ^ t) for t in (0, 1))
def main():
report = dict(relation_states=0, gap_queries=0, prefix_vectors=0,
monotone_histories=0, partitions=0, static_codes=0,
abandoned_classes=0)
targets = words(2)
for k in range(9):
h = 2 ** k
rows = {'0': set(targets[:2])}
stream = [clause('0', w) for w in targets[:2]]
for u in words(k):
rows['1' + u + '0'] = set(targets)
rows['1' + u + '1'] = {targets[0]}
stream += [clause('1' + u + '0', w) for w in targets]
stream.append(clause('1' + u + '1', targets[0]))
assert sum(map(len, stream)) == 5 * h * (k + 13) + 24
trigger = clause('0', '10')
assert len(trigger) == 12
before = {v: set(ws) for v, ws in rows.items()}
for z in (0, 1):
if z:
rows['0'].add('10')
answers = gaps(rows)
for v, ans in answers.items():
expected = bool(z) if v == '0' else v[-1] == '1' and not z
assert ans == expected
report['gap_queries'] += 1
completed = {v: ws | set(targets) for v, ws in rows.items()}
assert len({frozenset(ws) for ws in completed.values()}) == 1
report['relation_states'] += 1
old = gaps(before)
new = gaps(rows)
long_delta = [int(old['1' + u + b] != new['1' + u + b])
for u in words(k) for b in '01']
assert long_delta == [0, 1] * h
assert sum(long_delta[2 * i] ^ long_delta[2 * i + 1]
for i in range(h)) == h
if k <= 5:
assert tree_cost(long_delta) == h
rows['0'].add('10')
assert gaps(rows) == new # duplicate identity
assert gaps(before) == old # retained semantic version
for depth in range(4):
dist = shortest_costs(depth)
for mask, cost in dist.items():
bits = [(mask >> i) & 1 for i in range(2 ** depth)]
assert tree_cost(bits) == cost
report['prefix_vectors'] += 1
names = ['0', '10', '111']
for moves in product(range(3), repeat=6):
counts = [0] * 3
visits = {0: set(names)}
visited = {v: {0} for v in names}
for i in moves:
counts[i] += 1
c = counts[i]
assert c not in visited[names[i]]
visited[names[i]].add(c)
visits.setdefault(c, set()).add(names[i])
assert all(sum((weight(v) for v in vs), Fraction()) <= Fraction(1, 2)
for vs in visits.values())
report['monotone_histories'] += 1
names = ['0', '1', '00', '01', '10', '11']
for labels in product(range(3), repeat=len(names)):
blocks = {}
for v, label in zip(names, labels):
blocks.setdefault(label, []).append(v)
reps = [min(vs, key=lambda v: (len(v), v)) for vs in blocks.values()]
codes = list(map(code, reps))
assert all(not a.startswith(b) for a in codes for b in codes if a != b)
assert len(set(codes)) == len(codes)
total = Fraction()
for vs in blocks.values():
rep = min(vs, key=lambda v: (len(v), v))
mass = sum((weight(v) for v in vs), Fraction())
total += mass
for v in vs:
assert len(code(rep)) <= 2 * len(v) + 2
assert mass >= weight(v)
report['static_codes'] += 1
assert total <= Fraction(1, 2)
report['partitions'] += 1
for h in range(1, 33):
counts = {f'1{i:06b}': i for i in range(1, h + 1)}
counts['0'] = 0
abandoned = set()
for c in range(1, h + 2):
previous = counts['0']
counts['0'] = c
if previous:
assert previous in counts.values()
abandoned.add(previous)
assert len(abandoned) == h
assert sum((weight('0') for _ in abandoned), Fraction()) == Fraction(h, 8)
report['abandoned_classes'] += h
print(json.dumps(report, sort_keys=True))
if __name__ == '__main__':
main()