Research source · python
check_born_hole_lanes.py
tools/research/check_born_hole_lanes.py
238 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 77ce75eac9944a1025f79fe529446dd5eca6d2696b5adee66f7f25d34ebb8966
#!/usr/bin/env python3
"""Finite semantic/scheduling audit for name-funded-ball-reuse section 16.
Python integers, tuples and replacement are oracle machinery, not native
primitives. Jobs use the proof's worst-case duration, normalized to a=1.
Each query iteration is one actual target bit; no jump-to-deadline operation.
"""
from dataclasses import dataclass, replace
from itertools import combinations, product
import json
import random
@dataclass(frozen=True)
class Row:
maximum: int
holes: tuple[int, ...]
def contains(self, n):
return 1 <= n <= self.maximum and n not in self.holes
def cost(n):
# 1 + ceil(log2(n+1)), for positive integer n.
return 1 + n.bit_length()
@dataclass(frozen=True)
class Hole:
position: int
queue: tuple[Row, ...] = ()
debt: int = 0
deleted: bool = False
def work(self, steps):
lane = self
while steps and lane.queue and not lane.deleted:
debt = lane.debt or cost(lane.position)
amount = min(debt, steps)
steps -= amount
debt -= amount
if debt:
lane = replace(lane, debt=debt)
elif lane.queue[0].contains(lane.position):
lane = replace(lane, queue=(), debt=0, deleted=True)
else:
lane = replace(lane, queue=lane.queue[1:], debt=0)
return lane
def append(self, row):
return self if self.deleted else replace(self, queue=self.queue + (row,))
def residual(self):
if not self.queue or self.deleted:
return 0
return (self.debt or cost(self.position)) + (len(self.queue)-1)*cost(self.position)
@dataclass(frozen=True)
class Receipt:
maximum: int = 0
queue: tuple[Row, ...] = ()
debt: int = 0
holes: tuple[Hole, ...] = ()
seen: frozenset[str] = frozenset()
selected: tuple[Row, ...] = ()
births: tuple[tuple[int, int, int], ...] = ()
def global_work(self, steps):
s = self
while steps and s.queue:
debt = s.debt or cost(s.maximum)
amount = min(debt, steps)
steps -= amount
debt -= amount
if debt:
s = replace(s, debt=debt)
continue
row, tail = s.queue[0], s.queue[1:]
holes, births = s.holes, s.births
if row.maximum > s.maximum:
for m in row.holes:
if m > s.maximum:
# Entire tail is new work; no inherited partial debt.
holes += (Hole(m, tail),)
births += ((s.maximum, m, len(tail)),)
assert len(tail)**4 <= 4096*(s.maximum+1)
assert len(tail)*cost(m) <= 64*m
s = replace(s, maximum=row.maximum)
s = replace(s, queue=tail, debt=0, holes=holes, births=births)
return s
def tick(self, global_steps=4, hole_steps=4):
s = self.global_work(global_steps)
return replace(s, holes=tuple(h.work(hole_steps) for h in s.holes))
def select(self, name, row):
assert name and set(name) <= {'0', '1'}
s = self
for _ in name:
s = s.tick()
if name in s.seen:
return s
s = replace(s, seen=s.seen | {name}, selected=s.selected+(row,))
if not s.maximum:
return replace(s, maximum=row.maximum,
holes=tuple(Hole(m) for m in row.holes))
return replace(s, queue=s.queue+(row,),
holes=tuple(h.append(row) for h in s.holes))
@dataclass
class Reader:
length: int
cursor: int = 0
debt: int = 0
def tick(self, newborn=False, position=0):
if newborn:
self.debt = position
elif self.debt:
self.debt += 1
else:
self.cursor += 1
return
take = min(4, self.debt)
self.cursor += take
self.debt -= take
def query_prefixes(saved, count, stats):
original = repr(saved)
s = saved
envelopes = [Reader(s.maximum)] if s.maximum else []
readers = [Reader(h.position) for h in s.holes]
for h in s.holes:
assert h.residual() <= 96*h.position
for n in range(1, count+1):
before_h = len(s.holes)
# Expose each promotion separately to capture every envelope lane.
remaining = 128
while remaining:
old = s.maximum
s = s.global_work(1)
if s.maximum > old:
envelopes.append(Reader(s.maximum, debt=n))
stats['query_promotions'] += 1
remaining -= 1
for reader in envelopes:
# Newly created readers carry exactly n debt before first repair.
fresh = reader.cursor == 0 and reader.debt == n
reader.tick(newborn=fresh, position=n)
for idx, h in enumerate(s.holes):
fresh = idx >= before_h
if fresh:
readers.append(Reader(h.position))
stats['query_hole_births'] += 1
readers[idx].tick(newborn=fresh, position=n)
if readers[idx].debt:
assert n < h.position
s = replace(s, holes=tuple(h.work(384) for h in s.holes))
envelope = any(not x.debt and n <= x.length for x in envelopes)
missing = False
for h, reader in zip(s.holes, readers):
if n == h.position:
assert not reader.debt
assert h.deleted or not h.queue
missing |= not h.deleted
got = envelope and not missing
want = any(row.contains(n) for row in saved.selected)
assert got == want, (saved, n, got, want)
stats['query_prefixes'] += 1
assert repr(saved) == original # Every query preserves its starting version.
stats['retained_query_forks'] += 1
def main():
stats = dict(query_prefixes=0, retained_query_forks=0,
query_promotions=0, query_hole_births=0, selected_prefixes=0,
seed_births=0, nonempty_seed_births=0, deadline_checks=0)
rows = []
for h in range(1, 7):
for r in range(min(2, h-1)+1):
rows += [Row(h, e) for e in combinations(range(1, h), r)]
# Exhaustive pairs with every order, including equal and different maxima.
for first, second in product(rows, repeat=2):
s = Receipt().select('0', first).select('1', second)
query_prefixes(s, 8, stats)
stats['selected_prefixes'] += 2
rng = random.Random(186)
for trial in range(180):
maxima = rng.sample(range(2, 65), rng.randint(1, 4))
dictionary = {}
s = Receipt()
retained = []
for i in range(35):
name = bin(rng.randrange(1, 24))[2:]
if name not in dictionary:
h = rng.choice(maxima)
e = tuple(sorted(rng.sample(range(1, h), rng.randrange(min(2, h-1)+1))))
dictionary[name] = Row(h, e)
retained.append(s)
s = s.select(name, dictionary[name])
assert len(s.holes) <= 2*len(maxima)
stats['selected_prefixes'] += 1
if i % 7 == 0:
query_prefixes(s, 66, stats)
for old in rng.sample(retained, 3):
query_prefixes(old, 66, stats)
for _, _, size in s.births:
stats['seed_births'] += 1
stats['nonempty_seed_births'] += bool(size)
# Long numerals force unfinished global jobs and copied queues at birth.
for exponent in (200, 800, 2000, 4000):
m = 1 << exponent
dictionary = [Row(m, (1, 3)), Row(2*m, (m+1, m+3)),
Row(m, (2, 3)), Row(2*m, (m+1, m+4))]
for count in (3, 12, 40):
s = Receipt().select('0', dictionary[0])
for i in range(1, count+1):
s = s.select(bin(i+1)[2:], dictionary[1+(i-1)%3])
query_prefixes(s, 64, stats)
final = s.global_work(10**7)
for _, _, size in final.births:
stats['seed_births'] += 1
stats['nonempty_seed_births'] += bool(size)
for m in range(2, 2000):
for old in {1, m//2, m-1}:
tau = (old+3)//4
assert tau+(m+5)//6 <= m
assert tau + (max(tau-4, 0)+2)//3 <= old
stats['deadline_checks'] += 1
assert stats['query_hole_births'] and stats['nonempty_seed_births']
print(json.dumps(stats, indent=2))
if __name__ == '__main__':
main()