serialize the host netlist unit by unit and instantiate each generation from the emitted bytes
0654a8d | """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()) | |