Research source · python
check_banded_interval_reuse.py
tools/research/check_banded_interval_reuse.py
337 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: f863e087ea9bcf642c2b5805de3a974815e015f07db98e08e418ae1b88fef8de
#!/usr/bin/env python3
"""Immutable finite model of banded interval reuse.
Tuple band deques and a query-local collections.deque output FIFO model
imported strict persistent primitives, not their
native running time. Explicit digit, height and continuation records model
worker steps. Integers occur in preparation and independent audit oracles.
"""
from dataclasses import dataclass, replace
from random import Random
from collections import deque
import json
@dataclass(frozen=True)
class Link:
head: object
tail: object = None
def digits(n):
p = None
for c in bin(n)[2:]:
p = Link(int(c), p)
return p
def units(n):
p = None
for _ in range(n):
p = Link(None, p)
return p
@dataclass(frozen=True)
class Branch:
left: object
right: object
# Finite EMPTY/FULL labels; no pointer identity observation.
EMPTY, FULL = False, True
def join(a, b):
return FULL if a is FULL and b is FULL else Branch(a, b)
@dataclass(frozen=True)
class Task:
node: object
lo: object
hi: object
height: object
@dataclass(frozen=True)
class Frame:
phase: str
node: object = None
hi: object = None
height: object = None
side: int = 0
tail: object = None
@dataclass(frozen=True)
class Insert:
phase: str
old: object
height: object
lo_cur: object
hi_cur: object
lo_rev: object = None
hi_rev: object = None
task: object = None
stack: object = None
result: object = None
def start_insert(old, height, lo, hi):
return Insert('reverse', old, height, lo, hi)
def insert_step(s):
if s.phase == 'reverse':
if s.lo_cur is not None:
return replace(s, lo_cur=s.lo_cur.tail,
lo_rev=Link(s.lo_cur.head, s.lo_rev))
if s.hi_cur is not None:
return replace(s, hi_cur=s.hi_cur.tail,
hi_rev=Link(s.hi_cur.head, s.hi_rev))
lo = None if s.lo_rev is None else s.lo_rev.tail
hi = None if s.hi_rev is None else s.hi_rev.tail
return replace(s, phase='descend', task=Task(s.old, lo, hi, s.height))
if s.phase == 'descend':
t = s.task
if t.node is FULL or (t.lo is None and t.hi is None) or t.height is None:
return replace(s, phase='return', task=None, result=FULL)
left = t.node.left if isinstance(t.node, Branch) else EMPTY
right = t.node.right if isinstance(t.node, Branch) else EMPTY
lb = 0 if t.lo is None else t.lo.head
hb = 1 if t.hi is None else t.hi.head
lo = None if t.lo is None else t.lo.tail
hi = None if t.hi is None else t.hi.tail
if lb == hb:
frame = Frame('single', right if lb == 0 else left,
side=lb, tail=s.stack)
task = Task(left if lb == 0 else right, lo, hi, t.height.tail)
else:
frame = Frame('right', right, hi, t.height.tail, tail=s.stack)
task = Task(left, lo, None, t.height.tail)
return replace(s, task=task, stack=frame)
if s.phase == 'return':
f = s.stack
if f is None:
return replace(s, phase='done')
if f.phase == 'single':
result = join(s.result, f.node) if f.side == 0 else join(f.node, s.result)
return replace(s, result=result, stack=f.tail)
if f.phase == 'right':
return replace(s, phase='descend', task=Task(f.node, None, f.hi, f.height),
stack=Frame('join', s.result, tail=f.tail), result=None)
return replace(s, result=join(f.node, s.result), stack=f.tail)
return s
@dataclass(frozen=True)
class Job:
lower: object
upper: object
lo_cur: object
hi_cur: object
started: bool = False
@dataclass(frozen=True)
class Bucket:
height: object = None
tree: object = EMPTY
jobs: object = None
insertion: object = None
continuation: object = None
@dataclass(frozen=True)
class Worker:
prefix: tuple = ()
suffix: tuple = ()
def release(w, lower, upper):
seq = w.prefix + w.suffix # Imported persistent catenation in native proof.
b = seq[0] if seq else Bucket()
job = Job(lower, upper, lower, upper)
b = replace(b, jobs=Link(job, b.jobs))
return Worker((), (b,) + seq[1:])
def finish(w, b, cont):
tail = w.suffix[1:]
if cont is not None:
nxt = tail[0] if tail else Bucket(Link(None, b.height))
nxt = replace(nxt, jobs=Link(cont, nxt.jobs))
tail = (nxt,) + tail[1:]
return Worker(w.prefix, (b,) + tail)
def service(w):
if not w.suffix:
return w
b = w.suffix[0]
if b.insertion is not None:
ins = insert_step(b.insertion)
if ins.phase == 'done':
new = replace(b, tree=ins.result, insertion=None, continuation=None)
return finish(w, new, b.continuation)
return Worker(w.prefix, (replace(b, insertion=ins),) + w.suffix[1:])
if b.jobs is None:
return Worker(w.prefix + (b,), w.suffix[1:])
job, rest = b.jobs.head, b.jobs.tail
lo = None if job.lo_cur is None else job.lo_cur.tail
hi = job.hi_cur.tail
began = job.started or lo is None
cont = None if hi is None else replace(job, lo_cur=lo, hi_cur=hi, started=began)
new = replace(b, jobs=rest)
if not began:
return finish(w, new, cont)
lower = job.lower if not job.started else None
upper = job.upper if hi is None else None
if b.tree is FULL or (lower is None and upper is None):
return finish(w, replace(new, tree=FULL), cont)
ins = start_insert(b.tree, b.height, lower, upper)
return Worker(w.prefix, (replace(new, insertion=ins, continuation=cont),) + w.suffix[1:])
def settled(w, k):
# Whole-state audit only. Native query consumes the emitted prefix FIFO.
return len(w.prefix) >= k or not w.suffix
def drain_to(w, k):
count = 0
while not settled(w, k):
w = service(w)
count += 1
assert count < 1000000
return w, count
def tree_bits(node, height):
# Independent whole-tree audit, outside the worker.
if isinstance(node, bool):
return [node] * (1 << height)
return tree_bits(node.left, height-1) + tree_bits(node.right, height-1)
@dataclass(frozen=True)
class Reader:
stack: object = None
emission: object = None
def read_step(r):
if r.stack is None:
return r
(node, height), tail = r.stack.head, r.stack.tail
if height is None:
return Reader(tail, node is FULL)
left = node.left if isinstance(node, Branch) else node
right = node.right if isinstance(node, Branch) else node
stack = Link((left, height.tail), Link((right, height.tail), tail))
return Reader(stack)
def query(w, count, worker_rate=262144, reader_rate=1024):
ready, pending = w.prefix, Worker((), w.suffix)
reader, answers, output = Reader(), [], deque()
# Actual native service uses fixed batches. Stopping an idle worker early
# below only omits no-ops, and does not transfer unused credit.
for _ in range(count):
for _ in range(worker_rate):
if not pending.suffix:
break
pending = service(pending)
if pending.prefix:
ready += pending.prefix
pending = Worker((), pending.suffix)
for _ in range(reader_rate):
if reader.stack is None:
if not ready:
break
b, ready = ready[0], ready[1:]
reader = replace(reader, stack=Link((b.tree, b.height)))
reader = read_step(reader)
if reader.emission is not None:
output.append(reader.emission)
if output:
answers.append(output.popleft())
else:
assert not ready and not pending.suffix and reader.stack is None
answers.append(False)
return answers
def oracle(rows, n):
return any(b <= n <= h for b, h in rows)
def main():
rng = Random(198)
cases = queries = forks = release_bounds = insertions = step_states = 0
# Every interval in small bands, retaining old coverage after each insert.
for k in range(1, 6):
a, z = 1 << (k-1), (1 << k)-1
tree, covered = EMPTY, set()
intervals = [(b,h) for b in range(a,z+1) for h in range(b,z+1)]
rng.shuffle(intervals)
for b,h in intervals:
ins = start_insert(tree, units(k-1), digits(b), digits(h)); cost=0
while ins.phase != 'done':
ins=insert_step(ins);cost+=1
assert cost <= 16*k+16
tree=ins.result;covered.update(range(b,h+1));insertions+=1
assert tree_bits(tree,k-1)==[n in covered for n in range(a,z+1)]
for trial in range(150):
w, rows, retained = Worker(), [], []
for j in range(rng.randrange(3,16)):
# Interleaving includes gaps, nested intervals, equal endpoints,
# short late rows and enormous unresolved upper numerals.
b=rng.randrange(1,85);h=b+rng.randrange(0,90)
if j%7==0:h=(1<<rng.randrange(150,600))+h
if j%5==4:b=h=rng.randrange(1,8)
for _ in range(rng.randrange(0,50)):w=service(w);step_states+=1
k=rng.randrange(1,9)
_,before=drain_to(w,k)
nxt=release(w,digits(b),digits(h))
_,after=drain_to(nxt,k)
assert after <= before+256*k
release_bounds+=1
if j%3==0:retained.append((w,tuple(rows)))
w=nxt;rows.append((b,h))
if j%4==0:
out=query(w,96);queries+=len(out)
assert out==[oracle(rows,n) for n in range(1,97)]
cases+=1
for old,oldrows in retained:
out=query(old,96);queries+=len(out);forks+=1
assert out==[oracle(oldrows,n) for n in range(1,97)]
# Interrupt each phase of an actual large boundary insertion with a short
# disjoint row; resume and check every retained predecessor independently.
w=release(Worker(),digits(71),digits(119));rows=[(71,119)]
interrupted=0
while w.suffix:
if w.suffix[0].insertion is not None:
new=release(w,digits(2),digits(2))
assert query(new,128)==[oracle(rows+[(2,2)],n) for n in range(1,129)]
assert query(w,128)==[oracle(rows,n) for n in range(1,129)]
interrupted+=1;queries+=256
w=service(w)
# Many separated components survive, unlike minimum-only cancellation.
rows=[(2*i,2*i) for i in range(1,65)];rng.shuffle(rows);w=Worker()
for b,h in rows:w=release(w,digits(b),digits(h))
out=query(w,140);assert out==[oracle(rows,n) for n in range(1,141)];queries+=140
assert oracle([(1,1),(4,4)],4) and not oracle([(1,1)],4)
# Exact integer checks of fixed-rate deadline bounds; no float oracle.
for k in range(4,513):
C,q,Q=256*k,16384,262144
B=C+sum((1<<d)*(C-q*d) for d in range(1,(C-1)//q+1))
assert B<Q*(1<<(k-4))
print(json.dumps(dict(interval_insertions=insertions,releases=cases,
release_increase_checks=release_bounds,retained_query_forks=forks,
query_prefixes=queries,boundary_phase_interruptions=interrupted,
random_service_states=step_states,deadline_inequalities=509)))
if __name__=='__main__':main()