threshold-computers / src /check_device.py
phanerozoic's picture
serialize the host netlist unit by unit and instantiate each generation from the emitted bytes
0654a8d
Raw
History Blame Contribute Delete
4.7 kB
"""The device against Definition 2.8 of the paper.
Definition 2.8 specifies one device application on the
post-instruction state (x, tau, h, omega):
(i) if y[c_wr] = 1 then omega' = omega . y[R_out] and x'[R_out] = 0,
otherwise omega' = omega;
(ii) if y[c_rd] = 1 and h < |tau| then x'[R_in] = tau[h], x'[c_eot] = 0,
h' = h + 1; if y[c_rd] = 1 and h = |tau| then x'[c_eot] = 1 and h' = h;
if y[c_rd] = 0 then h' = h;
(iii) if y[c_rw] = 1 then h' = 0;
(iv) finally x'[c_rd] = x'[c_rw] = x'[c_wr] = 0.
The clauses are transcribed here independently of selfrep.Tape and the two are
compared over the whole cross product of request values, head positions and
tapes. The sweep covers non-unit values, so it also decides whether a request
fires on the value 1 alone.
"""
import itertools
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from selfrep import Tape, C_WR, C_EOT, C_RW, C_RD, R_IN, R_OUT
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def runs_path(name: str) -> str:
d = os.path.join(REPO, "paper", "runs")
os.makedirs(d, exist_ok=True)
return os.path.join(d, name)
def spec(mem, tau, h, omega):
"""Definition 2.8, clause by clause, on (mem, h, omega)."""
m = list(mem)
w = list(omega)
if m[C_WR] == 1: # (i)
w.append(m[R_OUT])
m[R_OUT] = 0
hp = h
if m[C_RD] == 1: # (ii)
if h < len(tau):
m[R_IN] = tau[h]
m[C_EOT] = 0
hp = h + 1
else:
m[C_EOT] = 1
if m[C_RW] == 1: # (iii)
hp = 0
m[C_WR] = m[C_RD] = m[C_RW] = 0 # (iv)
return m, hp, w
def main() -> int:
tapes = [b"", b"\x07", b"\x01\x02", bytes(range(5)), bytes(range(64))]
vals = (0, 1, 2, 3, 127, 128, 255)
bad, n = [], 0
for tau in tapes:
heads = sorted({0, 1, max(0, len(tau) - 1), len(tau)})
for h in heads:
for wr, rd, rw in itertools.product(vals, repeat=3):
for eot, rin, rout in ((0, 0, 0), (1, 9, 200), (0, 255, 1), (1, 1, 255)):
mem = [0] * 256
mem[C_WR], mem[C_RD], mem[C_RW] = wr, rd, rw
mem[C_EOT], mem[R_IN], mem[R_OUT] = eot, rin, rout
mem[0x10] = 0xAB # an ordinary cell, must not move
want_mem, want_h, want_out = spec(mem, tau, h, b"")
dev = Tape(tau)
dev.h = h
got_mem = list(mem)
dev.apply(got_mem)
n += 1
if (got_mem != want_mem or dev.h != want_h
or bytes(dev.out) != bytes(want_out)):
bad.append({"tau": len(tau), "h": h, "wr": wr, "rd": rd,
"rw": rw, "eot": eot,
"spec": (want_mem[C_EOT], want_mem[R_IN],
want_mem[R_OUT], want_h, list(want_out)),
"impl": (got_mem[C_EOT], got_mem[R_IN],
got_mem[R_OUT], dev.h, list(dev.out))})
print(f" device applications compared: {n:,}")
print(f" implementation agrees with Definition 2.8 on every one: "
f"{'yes' if not bad else f'NO ({len(bad)} disagreements)'}")
for b in bad[:5]:
print(" ", b)
# A request fires on the value 1 and on no other value. The head starts off
# zero so that a rewind is observable; without that a rewind of a head
# already at 0 changes nothing and the test would not see it fire.
fires = []
for cell in (C_WR, C_RD, C_RW):
for v in range(256):
mem = [0] * 256
mem[cell] = v
mem[R_OUT] = 0x5A
dev = Tape(b"\x11\x22")
dev.h = 1
before = (dev.h, len(dev.out))
dev.apply(mem)
acted = (dev.h, len(dev.out)) != before or mem[R_IN] != 0 or mem[C_EOT] != 0
if acted != (v == 1):
fires.append((cell, v, acted))
print(f" each request fires exactly on the value 1, over all 256 cell values: "
f"{'yes' if not fires else f'NO {fires[:5]}'}")
ok = not bad and not fires
json.dump({"applications": n, "disagreements": len(bad),
"value_trigger_failures": len(fires)},
open(runs_path("paper_device.json"), "w"), indent=1)
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())