Research source · python
check_hybrid_composition.py
tools/research/check_hybrid_composition.py
132 lines. Source is displayed for inspection; it is not executed by this page.
File fingerprint
SHA-256: 5a330ed237efccea5ecf64923129ab7394aa931689462cb5d252f218a3b43326
"""Assessment129: finite transactional semantics, not native timing evidence."""
from itertools import product, permutations
import json
import check_prefix_decoding as p
import check_pending_substitution as n
from check_frozen_row_composition import B, lookup, insert
def provisional(joint, counts, v, w, k, clock):
j, q = ((), joint), ((), counts)
queue, state, bad = tuple(v), False, False
for bit in w:
state, emit = p.tick(state, bit, clock)
label = 'E'
if emit:
label = queue[0] if queue else 'P'
queue = queue[1:]
for c in p.code(bit, label):
j = p.step(j, c)
old = p.view(j[1])[0] or (False, False)
j = p.setvalue(j, (True, old[1]))
q = p.step(q, bit)
count = min(k + 1, (p.view(q[1])[0] or 0) + (not old[0]))
bad |= count > k
q = p.setvalue(q, count)
bad |= bool(queue)
j = p.setvalue(j, (True, True))
return p.finish(j), p.finish(q), bad
def prepare(pairs, d=1, s=0, k=1, clock='all'):
near = joint = counts = B
for v, w in pairs:
# Both alternatives start from committed roots. Classification is late.
candidate = n.add_right(near, v, w, d, s)
jj, cc, bad = provisional(joint, counts, v, w, k, clock)
if abs(n.cls(v) - n.cls(w)) <= s:
if candidate is None:
return None
near = candidate
else:
if bad:
return None
joint, counts = jj, cc
return near, joint, counts
def valid(pairs, d, s, k, clock):
rows, far = {}, []
for v, w in set(pairs):
if abs(n.cls(v) - n.cls(w)) <= s:
rows.setdefault(v, set()).add(w)
else:
far.append((v, w))
width = p.oracle(far, clock)
return all(len(row) <= d for row in rows.values()) and width is not None and max(width.values(), default=0) <= k
def audit(pairs, probes, d=1, s=0, k=1, clock='all'):
packed = prepare(pairs, d, s, k, clock)
assert (packed is not None) == valid(pairs, d, s, k, clock)
if packed is None:
return 0, 0
frozen, joint, counts = packed
far = [(v,w) for v,w in pairs if abs(n.cls(v)-n.cls(w)) > s]
for prefix, count in p.oracle(far, clock).items():
assert lookup(counts, prefix) == count
names = sorted({v for v,w in pairs})
near_rows = direct_rows = B
snapshots = [(near_rows, direct_rows, set())]
marked = set()
for i, v in enumerate(names + names[:1]):
u = str(i % 2)
near_rows = n.add_left(near_rows, frozen, u, v, d, s)
row = lookup(direct_rows, u) or B
direct_rows = insert(direct_rows, u, insert(row, v, True))
marked = marked | {(u, v)}
snapshots.append((near_rows, direct_rows, marked))
comparisons = 0
for oldnear, olddirect, oldmarks in snapshots:
for u in ('0','1','00'):
index = lookup(oldnear, u) or {}
row = lookup(olddirect, u) or B
for w in probes:
got = n.index_contains(index, w) or p.query(joint, row, w, k, clock)
want = any((u,v) in oldmarks and ww == w for v,ww in pairs)
assert got == want, (pairs, u, w, oldmarks)
comparisons += 1
return len(snapshots), comparisons
def main():
# Includes ignored near width overflow, far near-degree overflow, contraction,
# duplicate rows, late class choice, and invalid far source exhaustion.
edges = [('0','0'),('1','0'),('0','1'),('0','0000'),('1','0000'),
('0','1000'),('00','0'),('00','01'),('00','0000'),('01','1000')]
probes = ['0','1','00','01','0000','1000','000','1111']
cases = versions = queries = 0
for mask in range(1 << len(edges)):
pairs = [e for i,e in enumerate(edges) if mask >> i & 1]
for d,k in ((1,1),(2,1),(1,2)):
for ordered in (pairs, list(reversed(pairs))):
vv, qq = audit(ordered + ordered[:1], probes, d=d, k=k)
cases += 1; versions += vv; queries += qq
# A near contraction can violate the far length test and must still commit.
for pairs in ([('000','00')], [('0','0'),('1','0')],
[('0','0'),('0','0000'),('0','1000')]):
vv,qq = audit(pairs, probes + ['00']); cases += 1; versions += vv; queries += qq
# Non-ticking clock and far rejection are checked independently.
for pairs in ([('0','00010'),('1','00011'),('0','1')], [('00','0000')]):
vv,qq = audit(pairs, probes+['00010','00011'], clock='skip'); cases += 1; versions += vv; queries += qq
# Functional family: near reversal and far expansion in disjoint name lanes.
mixtures = []
for h in range(2,7):
bits = [''.join(x) for x in product('01', repeat=h)]
pairs = [('0'+x, '0'+x[::-1]) for x in bits]
pairs += [('1'+x, '1'+x+'0'*(8*h*h)) for x in bits]
assert len({v for v,w in pairs}) == len(pairs)
assert prepare(pairs) is not None
width = max(p.oracle(pairs, 'all').values())
span = max(abs(n.cls(v)-n.cls(w)) for v,w in pairs)
assert width >= 2**(h//2) and span > 0
# Sparse query set, every retained version: both alternatives and misses.
vv,qq = audit(pairs, [pairs[0][1], pairs[-1][1], '111'])
versions += vv; queries += qq
mixtures.append({'h':h,'whole_width':width,'whole_class_span':span})
print(json.dumps({'contract_cases':cases,'retained_versions':versions,
'queries':queries,'functional_mixtures':mixtures,
'native_timing_evidence':False}, indent=2))
if __name__ == '__main__':
main()