CharlesCNorton commited on
Commit ·
657864a
1
Parent(s): f3fd723
neural_ca: the collision is verified as a reversible interaction gate, not just AND. At step 4 three output cells carry A&B (deflected, (3,6)/(6,3)), A&~B ((6,6)), and ~A&B ((3,3)), checked over all four inputs. Analog robustness sweep on the matrix tile: exact under read noise through sigma 0.10 and conductance mismatch through sigma_G 0.10, matching neural_matrix8. README updated.
Browse files- README.md +9 -8
- src/ca.py +20 -9
- tools/build_ca.py +19 -0
README.md
CHANGED
|
@@ -683,20 +683,21 @@ partition sequence in reverse reconstructs any earlier configuration (verified
|
|
| 683 |
over random lattices), and particle number is conserved. The rule is expressed
|
| 684 |
in the family's Heaviside threshold gates (a diagonal-pair detector XORed onto
|
| 685 |
the rotated cells) and compiles to a 6-layer ternary matrix tile that is a
|
| 686 |
-
permutation with a 0.5 analog margin
|
| 687 |
-
|
|
|
|
| 688 |
|
| 689 |
The dynamics are the billiard-ball model's: a single particle moves ballistically
|
| 690 |
along a diagonal at one cell per step, and two particles collide and deflect
|
| 691 |
reversibly (verified as a genuine interaction, distinct from independent motion).
|
| 692 |
-
A collision computes logic directly: with input particles at (2,2) and (7,7),
|
| 693 |
-
|
| 694 |
-
|
| 695 |
-
|
| 696 |
-
(Margolus 1984).
|
| 697 |
|
| 698 |
```bash
|
| 699 |
-
python src/ca.py # rule bijection, lattice reversibility, ballistic motion,
|
| 700 |
python tools/build_ca.py # ship the block rule as a ternary matrix tile (permutation + 0.5 margin)
|
| 701 |
```
|
| 702 |
|
|
|
|
| 683 |
over random lattices), and particle number is conserved. The rule is expressed
|
| 684 |
in the family's Heaviside threshold gates (a diagonal-pair detector XORed onto
|
| 685 |
the rotated cells) and compiles to a 6-layer ternary matrix tile that is a
|
| 686 |
+
permutation with a 0.5 analog margin, bit-exact under read noise through
|
| 687 |
+
sigma ~ 0.10 and conductance mismatch through sigma_G ~ 0.10; that tile applied
|
| 688 |
+
to every block is one lattice step, stored as `variants/neural_ca.safetensors`.
|
| 689 |
|
| 690 |
The dynamics are the billiard-ball model's: a single particle moves ballistically
|
| 691 |
along a diagonal at one cell per step, and two particles collide and deflect
|
| 692 |
reversibly (verified as a genuine interaction, distinct from independent motion).
|
| 693 |
+
A collision computes logic directly: with input particles at (2,2) and (7,7),
|
| 694 |
+
three output cells at step 4 carry A AND B (the deflected paths (3,6) and (6,3)),
|
| 695 |
+
A AND NOT B ((6,6)), and NOT A AND B ((3,3)), the billiard-ball interaction
|
| 696 |
+
gate, verified over all four inputs. That gate with mirror routing is
|
| 697 |
+
functionally complete (Margolus 1984).
|
| 698 |
|
| 699 |
```bash
|
| 700 |
+
python src/ca.py # rule bijection, lattice reversibility, ballistic motion, interaction gate
|
| 701 |
python tools/build_ca.py # ship the block rule as a ternary matrix tile (permutation + 0.5 margin)
|
| 702 |
```
|
| 703 |
|
src/ca.py
CHANGED
|
@@ -160,24 +160,35 @@ def _test_ballistic():
|
|
| 160 |
return ok and steady
|
| 161 |
|
| 162 |
|
| 163 |
-
def
|
| 164 |
-
"""
|
| 165 |
-
moving SE
|
| 166 |
-
|
|
|
|
|
|
|
| 167 |
H = W = 12
|
| 168 |
g = [[0] * W for _ in range(H)]
|
| 169 |
if a:
|
| 170 |
g[2][2] = 1
|
| 171 |
if b:
|
| 172 |
g[7][7] = 1
|
| 173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
|
| 175 |
|
| 176 |
def _test_gate():
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
return ok
|
| 182 |
|
| 183 |
|
|
|
|
| 160 |
return ok and steady
|
| 161 |
|
| 162 |
|
| 163 |
+
def interaction_gate(a: int, b: int) -> dict:
|
| 164 |
+
"""One billiard-ball collision as a reversible interaction gate. Input
|
| 165 |
+
particle A enters at (2,2) moving SE and B at (7,7) moving NW; at step 4
|
| 166 |
+
three output cells carry A&B (the deflected paths), A&~B and ~A&B (the
|
| 167 |
+
straight-through paths). AND plus routing by mirrors is functionally
|
| 168 |
+
complete for the billiard-ball construction (Margolus 1984)."""
|
| 169 |
H = W = 12
|
| 170 |
g = [[0] * W for _ in range(H)]
|
| 171 |
if a:
|
| 172 |
g[2][2] = 1
|
| 173 |
if b:
|
| 174 |
g[7][7] = 1
|
| 175 |
+
g = run(g, 4)
|
| 176 |
+
return {"A_and_B": g[3][6], "A_and_notB": g[6][6], "notA_and_B": g[3][3]}
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def and_gate(a: int, b: int) -> int:
|
| 180 |
+
return interaction_gate(a, b)["A_and_B"]
|
| 181 |
|
| 182 |
|
| 183 |
def _test_gate():
|
| 184 |
+
ok = True
|
| 185 |
+
for a in (0, 1):
|
| 186 |
+
for b in (0, 1):
|
| 187 |
+
o = interaction_gate(a, b)
|
| 188 |
+
ok &= (o["A_and_B"] == (a & b) and o["A_and_notB"] == (a & (1 - b))
|
| 189 |
+
and o["notA_and_B"] == ((1 - a) & b))
|
| 190 |
+
print(f" billiard-ball interaction gate (A&B, A&~B, ~A&B) over all 4 inputs: "
|
| 191 |
+
f"{'OK' if ok else 'FAIL'}")
|
| 192 |
return ok
|
| 193 |
|
| 194 |
|
tools/build_ca.py
CHANGED
|
@@ -81,6 +81,25 @@ def main() -> int:
|
|
| 81 |
print(f" tile is a permutation (16 distinct outputs): {'OK' if perm else 'FAIL'}")
|
| 82 |
print(f" analog noise margin: {margin:.3f} (guarantee 0.5)")
|
| 83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
# the loaded tile, applied to every block, is one whole-lattice CA step
|
| 85 |
t = load_file(OUT)
|
| 86 |
n = 0
|
|
|
|
| 81 |
print(f" tile is a permutation (16 distinct outputs): {'OK' if perm else 'FAIL'}")
|
| 82 |
print(f" analog noise margin: {margin:.3f} (guarantee 0.5)")
|
| 83 |
|
| 84 |
+
# analog robustness: the tile must reproduce the rule under read noise and
|
| 85 |
+
# static conductance mismatch, as neural_matrix8 measures
|
| 86 |
+
states = torch.stack(vecs)
|
| 87 |
+
ref = [ca.rule(tuple((s >> k) & 1 for k in (3, 2, 1, 0))) for s in range(16)]
|
| 88 |
+
|
| 89 |
+
def outs(machine, **kw):
|
| 90 |
+
v = machine.step(states, **kw)
|
| 91 |
+
return [tuple(int(v[i][j]) for j in range(4)) for i in range(v.shape[0])]
|
| 92 |
+
|
| 93 |
+
print(" read-noise sweep (exact = tile matches the rule on all 16 states):")
|
| 94 |
+
for sigma in (0.05, 0.10, 0.15, 0.20):
|
| 95 |
+
okn = all(outs(mm, analog=True, noise_sigma=sigma,
|
| 96 |
+
gen=torch.Generator().manual_seed(s)) == ref for s in range(4))
|
| 97 |
+
print(f" sigma={sigma:.2f}: {'exact' if okn else 'errors appear'}")
|
| 98 |
+
print(" conductance-mismatch sweep:")
|
| 99 |
+
for sg in (0.05, 0.10, 0.15):
|
| 100 |
+
okg = outs(mm.perturbed(sg, seed=0), analog=True) == ref
|
| 101 |
+
print(f" sigma_G={sg:.2f}: {'exact' if okg else 'errors appear'}")
|
| 102 |
+
|
| 103 |
# the loaded tile, applied to every block, is one whole-lattice CA step
|
| 104 |
t = load_file(OUT)
|
| 105 |
n = 0
|