Research source · python
check_normalized_composition.py
tools/research/check_normalized_composition.py
126 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 9e3a2deec60df4db0d666fa14bbd8466ce305a080502cf4698cc30d676347960
"""Finite semantic model of paid target normalization; not native timing evidence."""
from itertools import product
import json
import check_pending_substitution as n
from check_frozen_row_composition import B, lookup
def key(word):
at = word.find('1')
return word[at+1:] if at >= 0 and at+1 < len(word) else None
def prepare(pairs, k=2, d=2, s=0):
targets, counts = {}, {}
lanes = (B,) * k
global_rows = B
for v,w in pairs:
z = key(w)
if z is None:
return None
global_candidate = n.add_right(global_rows, v, z, d, s)
if global_candidate is None:
return None
global_rows = global_candidate
# All lane builders consume the same actual record before slot discovery.
candidates = tuple(n.add_right(root, v, z, d, s) for root in lanes)
fresh = w not in targets
slot = counts.get(z, 0) if fresh else targets[w]
if slot >= k or candidates[slot] is None:
return None
targets = dict(targets); counts = dict(counts)
targets[w] = slot
if fresh:
counts[z] = slot + 1
lanes = tuple(candidates[i] if i == slot else root for i,root in enumerate(lanes))
return targets, lanes
def condition(pairs, k, d, s):
# Independent explicit sets, preserving the declared first-occurrence order.
fibres, rows = {}, {}
for v,w in pairs:
z = key(w)
if z is None or abs(n.cls(v)-n.cls(z)) > s:
return False
fibre = fibres.setdefault(z, [])
if w not in fibre:
fibre.append(w)
if len(fibre) > k:
return False
slot = fibre.index(w)
rows.setdefault(v, set()).add(z)
return all(len(row) <= d for row in rows.values())
def audit(pairs, queries, k=2, d=2):
packed = prepare(pairs,k,d)
assert (packed is not None) == condition(pairs,k,d,0)
if packed is None:
return 0,0
targets, frozen = packed
rows=(B,)*k; marks=set(); snapshots=[(rows,marks)]
names=sorted({v for v,w in pairs})
for i,v in enumerate(names+names[:1]):
u=str(i%2)
rows=tuple(n.add_left(root,f,u,v,d,0) for root,f in zip(rows,frozen))
marks=marks|{(u,v)}
snapshots.append((rows,marks))
checks=0
for old, marked in snapshots:
for u in ('0','1','00'):
for w in queries:
z=key(w)
answers=[n.index_contains(lookup(root,u) or {},z) for root in old] if z else [False]*k
got=w in targets and answers[targets[w]]
want=any((u,v) in marked and ww==w for v,ww in pairs)
assert got==want,(pairs,u,w,marked)
checks+=1
return len(snapshots),checks
def main():
edges=[('0','10'),('1','10'),('0','010'),('1','0010'),('0','11'),('1','011'),('00','100'),('01','0101'),('00','10')]
queries=['10','010','0010','00010','11','011','100','0101','0','1','111']
cases=versions=checks=0
for mask in range(1<<len(edges)):
pairs=[e for i,e in enumerate(edges) if mask>>i&1]
for k,d in ((1,1),(2,1),(2,2),(3,2)):
for ordered in (pairs,list(reversed(pairs))):
vv,qq=audit(ordered+ordered[:1],queries,k,d)
cases+=1;versions+=vv;checks+=qq
assert prepare([('0','0')]) is None # Outside normalizer domain.
assert prepare([('0','1')]) is None # Empty normalized key.
# Terminal guard and lane distinction cannot be dropped.
assert key('10')==key('010')
assert prepare([('0','10'),('1','010')],1) is None
packed=prepare([('0','10'),('1','010')],2)
assert packed[0]['10'] != packed[0]['010']
rectangle_cases = 0
for mask in range(1 << len(edges)):
relation = {e for i,e in enumerate(edges) if mask >> i & 1}
groups = {}
for v,w in relation:
groups.setdefault(key(w), set()).add((v,w))
rectangle = all(g == {(v,w) for v,_ in g for _,w in g} for g in groups.values())
safe = all(((v,w) in relation) == any(vv == v and key(ww) == key(w) for vv,ww in relation)
for v in {v for v,w in relation} for w in {w for v,w in relation})
assert rectangle == safe
rectangle_cases += 1
# Far-expanded reversal under one fixed erasing normalizer.
examples=[]
for h in range(2,9):
words=[''.join(x) for x in product('01',repeat=h)]
pairs=[(v,'0'*(h*h)+'1'+v[::-1]) for v in words]
vv,qq=audit(pairs,[pairs[0][1],pairs[-1][1],'0'*(h*h+1)+'1'+words[0]],1,1)
versions+=vv;checks+=qq
r=h//2
# A prefix fixing r reversed bits leaves all first h-r bits independent.
possible=[v for v in words if v[::-1].startswith('0'*r)]
for ticks in range(r,h+2):
width=len({(v+'P'*ticks)[:ticks] for v in possible})
assert width>=2**r
examples.append({'h':h,'target_length':h*h+1+h,'minimum_midpoint_width':2**r})
print(json.dumps({'contract_cases':cases,'retained_versions':versions,'query_comparisons':checks,'expanded_reversal':examples,'rectangle_equivalence_cases':rectangle_cases,'native_timing_evidence':False},indent=2))
if __name__=='__main__': main()