Commit ·
dd2a421
1
Parent(s): 8cfe9fa
Prove self-reproduction by the dynamics for the stored host of every word width, with a sign-extending device read and the record count in closed form, check the stored hosts of widths 9 and 10 symbolically and on random states, check the extracted host family for widths 8 to 10, and remove the to-do note
Browse files- README.md +2 -1
- paper/README.md +2 -2
- paper/runs/paper_rocq.json +25 -6
- paper/runs/paper_stored_host.json +136 -4
- paper/universal_construction_ternary.pdf +2 -2
- paper/universal_construction_ternary.tex +256 -273
- src/host.py +49 -0
- src/paper.py +20 -15
- src/twohead.py +238 -162
- todo.md +0 -5
README.md
CHANGED
|
@@ -604,7 +604,8 @@ and stored in the member with 4096 cells, runs the 27-instruction program on a
|
|
| 604 |
recipe for its own records: it writes them into the idle bank, copies the recipe
|
| 605 |
and hands control to the copy, so that it reproduces itself, weights included,
|
| 606 |
by the dynamics alone; `src/stored_host_run.c` runs three generations of
|
| 607 |
-
79,464,240,088 steps each.
|
|
|
|
| 608 |
cells does the same with a description code of its own, every generation of it
|
| 609 |
proved in Rocq. Its robustness section gives the margin every orbit has
|
| 610 |
against perturbation, a certificate of the leakage an orbit tolerates from the
|
|
|
|
| 604 |
recipe for its own records: it writes them into the idle bank, copies the recipe
|
| 605 |
and hands control to the copy, so that it reproduces itself, weights included,
|
| 606 |
by the dynamics alone; `src/stored_host_run.c` runs three generations of
|
| 607 |
+
79,464,240,088 steps each. The paper proves that every member of the host family
|
| 608 |
+
with wider words does the same in a larger window. An organism of 133 records on the member with 64
|
| 609 |
cells does the same with a description code of its own, every generation of it
|
| 610 |
proved in Rocq. Its robustness section gives the margin every orbit has
|
| 611 |
against perturbation, a certificate of the leakage an orbit tolerates from the
|
paper/README.md
CHANGED
|
@@ -36,10 +36,10 @@ Each command is `python src/<file>.py <command>` and writes its record to `runs/
|
|
| 36 |
| `paper.py family-gate` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
|
| 37 |
| `paper.py c` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
|
| 38 |
| `paper.py throughput` | `paper_throughput.json` | the rate of each evaluator |
|
| 39 |
-
| `paper.py rocq` | `paper_rocq.json` | the Rocq development of `rocq/`, its assumptions, and the host
|
| 40 |
| `twohead.py organism` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
|
| 41 |
| `twohead.py net` | `paper_twohead_net.json` | the netlist N_{G,L} against the machine for windows of 64 and 4096 cells, its file, the organism on it in C, and the netlist extracted from Rocq |
|
| 42 |
-
| `twohead.py stored` | `paper_stored_host.json` | the host compiled into records of the two-head machine: one pass against the host's step and its device, the startup and step records on decision diagrams over the signals of
|
| 43 |
| `noise.py host` | `paper_noise_*.json` | the margin, the profile bound, read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
|
| 44 |
| `noise.py amplified` | `paper_redundant_*.json` | the amplified host N_3: one step on replicated states, the margin 3/2, exact self-reproduction in C, the run under noise, the deviation curve and its bound by layer, the failure rate of the state read by majority and the restoration bound, computed by `src/restore_bound.c` |
|
| 45 |
| `independent.py` | `independent_*.json` | code written from the paper's definitions alone: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma and the measurements of Section 6.1 and Appendix A with the noise simulator `src/nsim.c` |
|
|
|
|
| 36 |
| `paper.py family-gate` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
|
| 37 |
| `paper.py c` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
|
| 38 |
| `paper.py throughput` | `paper_throughput.json` | the rate of each evaluator |
|
| 39 |
+
| `paper.py rocq` | `paper_rocq.json` | the Rocq development of `rocq/`, its assumptions, and the host family extracted from it for A = 8, 9, 10 against sigma(N_host) and the generator |
|
| 40 |
| `twohead.py organism` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
|
| 41 |
| `twohead.py net` | `paper_twohead_net.json` | the netlist N_{G,L} against the machine for windows of 64 and 4096 cells, its file, the organism on it in C, and the netlist extracted from Rocq |
|
| 42 |
+
| `twohead.py stored` | `paper_stored_host.json` | the host compiled into records of the two-head machine: one pass against the host's step and its device, the startup and step records on decision diagrams over the signals of the host (`stored symbolic`), and three generations in C; `--width A` checks H_A in place of H_8, and `stored widths` tabulates A = 8 to 12 |
|
| 43 |
| `noise.py host` | `paper_noise_*.json` | the margin, the profile bound, read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
|
| 44 |
| `noise.py amplified` | `paper_redundant_*.json` | the amplified host N_3: one step on replicated states, the margin 3/2, exact self-reproduction in C, the run under noise, the deviation curve and its bound by layer, the failure rate of the state read by majority and the restoration bound, computed by `src/restore_bound.c` |
|
| 45 |
| `independent.py` | `independent_*.json` | code written from the paper's definitions alone: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma and the measurements of Section 6.1 and Appendix A with the noise simulator `src/nsim.c` |
|
paper/runs/paper_rocq.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
"rocq": "The Rocq Prover, version 9.1.1",
|
| 3 |
"files": 30,
|
| 4 |
-
"build_seconds":
|
| 5 |
"theorems": {
|
| 6 |
"PhysMain.netlist_step": "closed",
|
| 7 |
"PhysMain.netlist_step64": "closed",
|
|
@@ -24,10 +24,29 @@
|
|
| 24 |
"extraction_identical": true,
|
| 25 |
"lines": 5093,
|
| 26 |
"host_extraction": {
|
| 27 |
-
"
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
}
|
| 33 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"rocq": "The Rocq Prover, version 9.1.1",
|
| 3 |
"files": 30,
|
| 4 |
+
"build_seconds": 251.8,
|
| 5 |
"theorems": {
|
| 6 |
"PhysMain.netlist_step": "closed",
|
| 7 |
"PhysMain.netlist_step64": "closed",
|
|
|
|
| 24 |
"extraction_identical": true,
|
| 25 |
"lines": 5093,
|
| 26 |
"host_extraction": {
|
| 27 |
+
"members": [
|
| 28 |
+
{
|
| 29 |
+
"A": 8,
|
| 30 |
+
"units": 17598,
|
| 31 |
+
"identical": true,
|
| 32 |
+
"sha256_generator": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a",
|
| 33 |
+
"sha256_rocq": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a"
|
| 34 |
+
},
|
| 35 |
+
{
|
| 36 |
+
"A": 9,
|
| 37 |
+
"units": 39130,
|
| 38 |
+
"identical": true,
|
| 39 |
+
"sha256_generator": "0ff74a207964d69eaf8857eb39ca93a085ee1f59d680edd7a81dd9906a82e916",
|
| 40 |
+
"sha256_rocq": "0ff74a207964d69eaf8857eb39ca93a085ee1f59d680edd7a81dd9906a82e916"
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"A": 10,
|
| 44 |
+
"units": 86263,
|
| 45 |
+
"identical": true,
|
| 46 |
+
"sha256_generator": "9465daed0832b5942d120e685597e4db16a155dbd12adccb1b0ea18852a4a8a4",
|
| 47 |
+
"sha256_rocq": "9465daed0832b5942d120e685597e4db16a155dbd12adccb1b0ea18852a4a8a4"
|
| 48 |
+
}
|
| 49 |
+
],
|
| 50 |
+
"identical": true
|
| 51 |
}
|
| 52 |
}
|
paper/runs/paper_stored_host.json
CHANGED
|
@@ -65,15 +65,147 @@
|
|
| 65 |
"disagreements": 0,
|
| 66 |
"records": 36074,
|
| 67 |
"window_cells": 2896,
|
| 68 |
-
"seconds":
|
| 69 |
},
|
| 70 |
"symbolic": {
|
|
|
|
| 71 |
"startup_records": 2099,
|
| 72 |
"step_records": 33568,
|
| 73 |
"startup_exact": true,
|
| 74 |
"step_exact": true,
|
| 75 |
"sha256_image": "7a769aa264a89860149962d7e98f8b2a5cb34ceb7778e88bcbffdccdc0996154",
|
| 76 |
-
"nodes":
|
| 77 |
-
"seconds":
|
| 78 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
}
|
|
|
|
| 65 |
"disagreements": 0,
|
| 66 |
"records": 36074,
|
| 67 |
"window_cells": 2896,
|
| 68 |
+
"seconds": 75.0
|
| 69 |
},
|
| 70 |
"symbolic": {
|
| 71 |
+
"A": 8,
|
| 72 |
"startup_records": 2099,
|
| 73 |
"step_records": 33568,
|
| 74 |
"startup_exact": true,
|
| 75 |
"step_exact": true,
|
| 76 |
"sha256_image": "7a769aa264a89860149962d7e98f8b2a5cb34ceb7778e88bcbffdccdc0996154",
|
| 77 |
+
"nodes": 79870,
|
| 78 |
+
"seconds": 0.9
|
| 79 |
+
},
|
| 80 |
+
"symbolic_A9": {
|
| 81 |
+
"A": 9,
|
| 82 |
+
"startup_records": 4660,
|
| 83 |
+
"step_records": 75366,
|
| 84 |
+
"startup_exact": true,
|
| 85 |
+
"step_exact": true,
|
| 86 |
+
"sha256_image": "40affa80c17e09eddf8267b377ca48fb19ce1616366bf0f2020f0f574fb19aee",
|
| 87 |
+
"nodes": 177802,
|
| 88 |
+
"seconds": 1.7
|
| 89 |
+
},
|
| 90 |
+
"symbolic_A10": {
|
| 91 |
+
"A": 10,
|
| 92 |
+
"startup_records": 10297,
|
| 93 |
+
"step_records": 167351,
|
| 94 |
+
"startup_exact": true,
|
| 95 |
+
"step_exact": true,
|
| 96 |
+
"sha256_image": "a2e7bd1326e149fef968b232b35f4d9496022bbc706f59330994fbb8410498e0",
|
| 97 |
+
"nodes": 392233,
|
| 98 |
+
"seconds": 5.8
|
| 99 |
+
},
|
| 100 |
+
"pass_check_A9": {
|
| 101 |
+
"trials": 300,
|
| 102 |
+
"disagreements": 0,
|
| 103 |
+
"records": 80448,
|
| 104 |
+
"window_cells": 6228,
|
| 105 |
+
"seconds": 204.6
|
| 106 |
+
},
|
| 107 |
+
"pass_check_A10": {
|
| 108 |
+
"trials": 100,
|
| 109 |
+
"disagreements": 0,
|
| 110 |
+
"records": 178100,
|
| 111 |
+
"window_cells": 13404,
|
| 112 |
+
"seconds": 156.2
|
| 113 |
+
},
|
| 114 |
+
"widths": [
|
| 115 |
+
{
|
| 116 |
+
"A": 8,
|
| 117 |
+
"records": 36074,
|
| 118 |
+
"startup": 2099,
|
| 119 |
+
"step": 33568,
|
| 120 |
+
"device": 402,
|
| 121 |
+
"handover": 5,
|
| 122 |
+
"window_cells": 2896,
|
| 123 |
+
"alpha": 12,
|
| 124 |
+
"record_bits": 44,
|
| 125 |
+
"counter_bits": 20,
|
| 126 |
+
"image_bytes": 198407,
|
| 127 |
+
"tau_bytes": 199971,
|
| 128 |
+
"literal_tokens": 1563,
|
| 129 |
+
"repeat_tokens": 0,
|
| 130 |
+
"passes": 2202812,
|
| 131 |
+
"applications": 79464240088,
|
| 132 |
+
"seconds": 0.4
|
| 133 |
+
},
|
| 134 |
+
{
|
| 135 |
+
"A": 9,
|
| 136 |
+
"records": 80448,
|
| 137 |
+
"startup": 4660,
|
| 138 |
+
"step": 75366,
|
| 139 |
+
"device": 413,
|
| 140 |
+
"handover": 9,
|
| 141 |
+
"window_cells": 6228,
|
| 142 |
+
"alpha": 13,
|
| 143 |
+
"record_bits": 47,
|
| 144 |
+
"counter_bits": 20,
|
| 145 |
+
"image_bytes": 472632,
|
| 146 |
+
"tau_bytes": 476355,
|
| 147 |
+
"literal_tokens": 3722,
|
| 148 |
+
"repeat_tokens": 0,
|
| 149 |
+
"passes": 5247354,
|
| 150 |
+
"applications": 422139134592,
|
| 151 |
+
"seconds": 1.0
|
| 152 |
+
},
|
| 153 |
+
{
|
| 154 |
+
"A": 10,
|
| 155 |
+
"records": 178100,
|
| 156 |
+
"startup": 10297,
|
| 157 |
+
"step": 167351,
|
| 158 |
+
"device": 448,
|
| 159 |
+
"handover": 4,
|
| 160 |
+
"window_cells": 13404,
|
| 161 |
+
"alpha": 14,
|
| 162 |
+
"record_bits": 50,
|
| 163 |
+
"counter_bits": 22,
|
| 164 |
+
"image_bytes": 1113125,
|
| 165 |
+
"tau_bytes": 1121891,
|
| 166 |
+
"literal_tokens": 8765,
|
| 167 |
+
"repeat_tokens": 0,
|
| 168 |
+
"passes": 12358336,
|
| 169 |
+
"applications": 2201019641600,
|
| 170 |
+
"seconds": 3.7
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"A": 11,
|
| 174 |
+
"records": 391216,
|
| 175 |
+
"startup": 22588,
|
| 176 |
+
"step": 368148,
|
| 177 |
+
"device": 471,
|
| 178 |
+
"handover": 9,
|
| 179 |
+
"window_cells": 28770,
|
| 180 |
+
"alpha": 15,
|
| 181 |
+
"record_bits": 53,
|
| 182 |
+
"counter_bits": 23,
|
| 183 |
+
"image_bytes": 2591806,
|
| 184 |
+
"tau_bytes": 2612215,
|
| 185 |
+
"literal_tokens": 20408,
|
| 186 |
+
"repeat_tokens": 0,
|
| 187 |
+
"passes": 28775186,
|
| 188 |
+
"applications": 11257313166176,
|
| 189 |
+
"seconds": 9.9
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"A": 12,
|
| 193 |
+
"records": 853167,
|
| 194 |
+
"startup": 49215,
|
| 195 |
+
"step": 803454,
|
| 196 |
+
"device": 494,
|
| 197 |
+
"handover": 4,
|
| 198 |
+
"window_cells": 61544,
|
| 199 |
+
"alpha": 16,
|
| 200 |
+
"record_bits": 56,
|
| 201 |
+
"counter_bits": 24,
|
| 202 |
+
"image_bytes": 5972169,
|
| 203 |
+
"tau_bytes": 6019191,
|
| 204 |
+
"literal_tokens": 47025,
|
| 205 |
+
"repeat_tokens": 2,
|
| 206 |
+
"passes": 66305186,
|
| 207 |
+
"applications": 56569396624062,
|
| 208 |
+
"seconds": 26.0
|
| 209 |
+
}
|
| 210 |
+
]
|
| 211 |
}
|
paper/universal_construction_ternary.pdf
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:07d0ca48862fbcbbff532d926d57af98543fb0c3acf837dc3ecd5b8e38f6f0be
|
| 3 |
+
size 327765
|
paper/universal_construction_ternary.tex
CHANGED
|
@@ -79,8 +79,9 @@ step. Stored in it as $36{,}074$ records of two inputs, the SUBLEQ computer runs
|
|
| 79 |
the second program on a description of its own records: it writes them into the
|
| 80 |
idle bank, copies the description and hands control to the copy, which does the
|
| 81 |
same, so the fixed network rebuilds, exactly and in every generation, the weights
|
| 82 |
-
of the stored network that computes, with no map outside it
|
| 83 |
-
|
|
|
|
| 84 |
pre-activation is an integer, every orbit survives perturbations below $1/2$, and
|
| 85 |
a bound computed from the pre-activation profile is within $20\%$ of the measured
|
| 86 |
failure rate under Gaussian read noise. Replacing each unit by $r$ copies that read
|
|
@@ -106,9 +107,7 @@ copies the description, produces a copy of itself together with a copy of the
|
|
| 106 |
description~\cite{vonNeumann1966}. The self-reproducing automata that followed
|
| 107 |
\cite{Arbib1966,Codd1968,Langton1984,Pesavento1995,PerrierSipperZahnd1996},
|
| 108 |
surveyed in~\cite{Sipper1998}, reproduce configurations of a cellular space
|
| 109 |
-
under a fixed transition rule.
|
| 110 |
-
approximations of their own parameters
|
| 111 |
-
\cite{ChangLipson2018,Gabor2022,RandazzoVersariMordvintsev2021,ShvartzmanRam2024}.
|
| 112 |
|
| 113 |
This paper makes the parameters of a threshold network the object of exact
|
| 114 |
reproduction. The networks have weights in $\Tern$ and integer thresholds and
|
|
@@ -159,13 +158,12 @@ networks $N^\alpha_{G,L}$ whose state holds a stored network as records in two
|
|
| 159 |
banks, with two tapes and three heads, each step evaluating one record, proved in
|
| 160 |
Rocq to compute the step of this two-head machine from every state for every
|
| 161 |
window of $2^\alpha$ cells and every $G$ and $L$ (Theorem~\ref{thm:physnet}).
|
| 162 |
-
Stored in it as records of two inputs, the host
|
| 163 |
-
image of its size into the idle bank and hands
|
| 164 |
-
recipe for its own records
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
were run. A constructor of $133$ records with a description code of its own does
|
| 169 |
the same in the member with $64$ cells, every step of it proved in Rocq
|
| 170 |
(Section~\ref{sec:organism}).
|
| 171 |
\item \emph{Robustness.} Every orbit survives perturbations below $1/2$ per
|
|
@@ -177,12 +175,10 @@ copies of its inputs, Pierce's interwoven redundancy~\cite{Pierce1965} with
|
|
| 177 |
threshold units, multiplies every margin by $r$: the probability of leaving an
|
| 178 |
orbit within $T$ steps under read noise of deviation $s$ is at most
|
| 179 |
$T\,rM\erfc(r/2\sqrt2 s)$, so any noise level is survived with redundancy
|
| 180 |
-
$O(s\sqrt{\log(TM/\delta)})$, and $O(s_{\mathrm w}^2\log(TM/\delta))$
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
threefold host where the first-order bound exceeds one
|
| 185 |
-
(Proposition~\ref{prop:restore}).
|
| 186 |
\end{enumerate}
|
| 187 |
|
| 188 |
% =============================================================================
|
|
@@ -308,13 +304,10 @@ $\omega$, we write $\Out(x_0,\tau)=\omega$.
|
|
| 308 |
\end{definition}
|
| 309 |
|
| 310 |
\begin{remark}[Device realization]\label{rem:devices}
|
| 311 |
-
In the host the registers and the request and status bits are memory
|
| 312 |
-
|
| 313 |
-
$
|
| 314 |
-
|
| 315 |
-
fixed point. A request fires on the value held by its cell, so the device is a
|
| 316 |
-
function of the machine state, and the transition map $F$ treats the device
|
| 317 |
-
cells as ordinary memory.
|
| 318 |
\end{remark}
|
| 319 |
|
| 320 |
\begin{table}[ht]
|
|
@@ -426,7 +419,8 @@ bits, is at most $0$, and $p\leftarrow p+3$ otherwise~\cite{MavaddatParhami1988}
|
|
| 426 |
Indices are taken modulo $S$, and the machine halts when $p=S-1$. The device
|
| 427 |
cells of Definition~\ref{def:transducer} are the seven top words, in the order of
|
| 428 |
Table~\ref{tab:device}; a request fires on the value $1$, a read loads a tape byte
|
| 429 |
-
into $R_{\mathrm{in}}$,
|
|
|
|
| 430 |
We write $\mathrm{SUBLEQ}_A$ for this machine. The host is $A=8$: $256$ words of
|
| 431 |
one byte.
|
| 432 |
\end{definition}
|
|
@@ -628,14 +622,13 @@ $\mathrm{SUBLEQ}_A$ with the halt latch, from every state and for every $A\ge3$,
|
|
| 628 |
is proved in Rocq from a definition of $H_A$ block by block in the order of
|
| 629 |
Table~\ref{tab:blocks}: every unit is given its value in terms of the state,
|
| 630 |
the carries through the recurrence of Lemma~\ref{lem:sub}, and induction over the
|
| 631 |
-
units shows that the netlist computes these values. Extracted for $A=8$
|
| 632 |
-
definition gives the netlist that $\sigma(\Nhost)$ denotes
|
|
|
|
| 633 |
\end{proof}
|
| 634 |
|
| 635 |
\begin{remark}[Depth]\label{rem:fold}
|
| 636 |
-
|
| 637 |
-
depth $33$ and a levelization of $87{,}080$ rows, $79\%$ of them identity units,
|
| 638 |
-
against $58\%$ here. Writing every fetch conjunction $FA_{o,t,j}$, every read
|
| 639 |
conjunction $RX_{t,j}$, $RY_{t,j}$ and every write enable $W_j$ as a single unit
|
| 640 |
that reads the bits of its address directly, of fan-in $A+1$, removes the decode
|
| 641 |
lines of $a$ and $b$ and one level each from the fetch and from the operand reads,
|
|
@@ -643,8 +636,7 @@ so the step has depth $11$ for every $A$. For $A=8$ the folded netlist has
|
|
| 643 |
$17{,}086$ units and $120{,}508$ edges, against $17{,}598$ and $51{,}132$, and for
|
| 644 |
every $A$ from $3$ to $12$ one step of it agreed with $\mathrm{SUBLEQ}_A$ on
|
| 645 |
$2^{16}$ uniformly random full states for $A\le10$ and on $2^{15}$ and $2^{14}$
|
| 646 |
-
for $A=11$ and $12$.
|
| 647 |
-
constructions below use $H_8$.
|
| 648 |
\end{remark}
|
| 649 |
|
| 650 |
% =============================================================================
|
|
@@ -756,11 +748,7 @@ the output of an instance with host $\Nhost$ and memory image $m_P$. Writing $L$
|
|
| 756 |
and $R$ for the numbers of literal and repeat tokens of $r$ and
|
| 757 |
$f_{\mathrm{lit}}$, $f_{\mathrm{rep}}$ for the numbers of bytes each kind
|
| 758 |
contributes to $\delta(r)$, the run takes exactly
|
| 759 |
-
\
|
| 760 |
-
5f_{\mathrm{lit}}+4f_{\mathrm{rep}}+7L+9R+8
|
| 761 |
-
\]
|
| 762 |
-
steps, hence at most $5|\delta(r)|+9\bigl\lfloor(|r|-1)/2\bigr\rfloor+8$ and at
|
| 763 |
-
least $4|\delta(r)|+8$.
|
| 764 |
\end{theorem}
|
| 765 |
|
| 766 |
\begin{proof}
|
|
@@ -792,9 +780,7 @@ length $T$ then executes $6$, $T$ passes of $9$ to $12$ of which the first $T-1$
|
|
| 792 |
also execute $13$, and $14$: $5T+7$ steps. A repeat token of run length
|
| 793 |
$\ell=256-T$ executes $7$, $8$ and $15$, $\ell$ passes of $16$ to $18$ of which the
|
| 794 |
first $\ell-1$ also execute $19$, and $14$: $4\ell+9$ steps. The end token executes
|
| 795 |
-
$0$ to $5$, $7$ and $20$: eight steps.
|
| 796 |
-
$f_{\mathrm{lit}}+f_{\mathrm{rep}}=|\delta(r)|$, and every token occupies at least
|
| 797 |
-
two bytes of $r$, so $7L+9R\le9(L+R)\le9\lfloor(|r|-1)/2\rfloor$.
|
| 798 |
\end{proof}
|
| 799 |
|
| 800 |
\begin{corollary}[Self-description]\label{cor:selfdesc}
|
|
@@ -841,6 +827,48 @@ elsewhere, and let
|
|
| 841 |
\]
|
| 842 |
\end{construction}
|
| 843 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 844 |
\begin{theorem}[Exact self-reproduction]\label{thm:selfrep}
|
| 845 |
For every recipe $\tau$ the instance $(\Nhost,m^\ast,\tau)$ halts and
|
| 846 |
$\Out(\Nhost,m^\ast,\tau)=\delta(\tau)\cat\tau$; its run reads no byte at
|
|
@@ -901,6 +929,16 @@ $794{,}960$ steps in phase~(A), one in phase~(R) and $869{,}978$ in phase~(B),
|
|
| 901 |
$1{,}664{,}939$ in all.
|
| 902 |
\end{remark}
|
| 903 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 904 |
|
| 905 |
% =============================================================================
|
| 906 |
\section{Robustness under perturbation}\label{sec:robust}
|
|
@@ -989,11 +1027,6 @@ evaluation whose input is unperturbed and whose perturbation satisfies
|
|
| 989 |
$|e|\ge\tfrac12$. There are $TM$ evaluations up to time $T$.
|
| 990 |
\end{proof}
|
| 991 |
|
| 992 |
-
A row can change its output only when its noise crosses the comparator on the
|
| 993 |
-
side away from its pre-activation, with a probability that falls rapidly with the
|
| 994 |
-
distance from the comparator. The following bound counts each row by that
|
| 995 |
-
probability.
|
| 996 |
-
|
| 997 |
\begin{proposition}[Profile bound]\label{prop:profile}
|
| 998 |
Let the perturbations be independent centred Gaussians of standard deviation
|
| 999 |
$s$, let $(x_t)$ be the orbit of $F$ from $x_0$, and for $t\ge0$ and each row $i$
|
|
@@ -1034,11 +1067,9 @@ without leakage and for $\gamma<6.09\times10^{-5}$ with exact weights. Along the
|
|
| 1034 |
first $10{,}000$ steps of the self-describing instance $K^\ast=8$ and
|
| 1035 |
$A^\ast=349$, and (ii) certifies $\gamma<1.43\times10^{-3}$ and
|
| 1036 |
$\varepsilon<1/16$, each alone; along the self-reproducing run $A^\ast=441$,
|
| 1037 |
-
certifying $\gamma<1.13\times10^{-3}$.
|
| 1038 |
-
|
| 1039 |
-
$
|
| 1040 |
-
$\gamma=3.9\times10^{-3}$ and up to $\varepsilon=1/16$, and deviated at
|
| 1041 |
-
$\gamma=1.56\times10^{-2}$ and at $\varepsilon=1/4$.
|
| 1042 |
|
| 1043 |
For Gaussian read noise of deviation $s=0.05$, $p=1.52\times10^{-23}$, and over the
|
| 1044 |
$T=1{,}664{,}939$ steps of the self-reproducing run, $TM=6.99\times10^{10}$,
|
|
@@ -1272,9 +1303,7 @@ copies, which is their common value, and writes every copy, so the run of $N_r$
|
|
| 1272 |
from $\rho_r(x_0(m))$ visits the replications of the states $\Nhost$ visits from
|
| 1273 |
$x_0(m)$ on the same tape and emits the same bytes. The proofs of
|
| 1274 |
Theorems~\ref{thm:univ} and~\ref{thm:selfrep} use the transducer alone, so they
|
| 1275 |
-
hold with $N_r$ in place of $\Nhost$.
|
| 1276 |
-
$R=1{,}581$, $f_{\mathrm{lit}}=2{,}995{,}056$ and $f_{\mathrm{rep}}=126{,}755$, so
|
| 1277 |
-
phase~(A) takes $15{,}663{,}780$ steps and phase~(B) $18{,}132{,}668$.
|
| 1278 |
\end{proof}
|
| 1279 |
|
| 1280 |
One step of $N_3$ agreed with Definition~\ref{def:subleq} on $65{,}536$
|
|
@@ -1494,12 +1523,8 @@ $i+1\bmod N$ or bit $i$ of the bank after the arm's write, as cell $5$ after the
|
|
| 1494 |
write requests; the cell under the arm after the write is a multiplexer of $v$
|
| 1495 |
and the old cell on the decode line of $2$. The tapes are alike, with cells $4$
|
| 1496 |
and $6$ and the decode line of $3$. Counting the units and edges of the blocks
|
| 1497 |
-
gives the sizes. The depth of a unit depends only on its block
|
| 1498 |
-
the
|
| 1499 |
-
depth $3$, the operands at $5$, the products at $6$, the tests $p\ge c$ at $7$
|
| 1500 |
-
and $v$ at $9$, the written window cells, the requests among them, at $11$, the
|
| 1501 |
-
next bank bits at $14$, the signals that turn the tapes at $13$ and the next tape
|
| 1502 |
-
bits at $15$. That the next state is the encoding of the next state of $x$, for
|
| 1503 |
all $\alpha$, $G$, $L$ and $x$, is proved in Rocq with the number of units and the
|
| 1504 |
weights: every unit is given a value in terms of $x$ and fires to it on the values
|
| 1505 |
of the units it reads, and induction over the units shows that the netlist
|
|
@@ -1507,11 +1532,8 @@ computes these values.
|
|
| 1507 |
\end{proof}
|
| 1508 |
|
| 1509 |
\begin{remark}[Corroboration]\label{rem:physcheck}
|
| 1510 |
-
|
| 1511 |
-
|
| 1512 |
-
for $\alpha=12$, $G=36{,}074$ and $L=1{,}599{,}768$, the member that
|
| 1513 |
-
Section~\ref{sec:storedhost} uses, it has $22{,}329{,}613$ units,
|
| 1514 |
-
$47{,}964{,}818$ edges and $6{,}378{,}141$ state bits. For $N^6_{133,2930}$ and
|
| 1515 |
$N^{12}_{5,40}$ the generator's file is byte for byte the netlist extracted from
|
| 1516 |
the Rocq definition, and three generations of the organism, $2{,}762{,}676$ steps,
|
| 1517 |
were run on $N^6_{133,2930}$ in C beside a transcription of
|
|
@@ -1524,10 +1546,10 @@ Definition~\ref{def:twohead}, the full state compared after every step.
|
|
| 1524 |
|
| 1525 |
Inside the two-head machine the instantiation step of Section~\ref{sec:selfrep}
|
| 1526 |
is a write into the idle bank followed by a change of $\kappa$. This section
|
| 1527 |
-
stores the host
|
| 1528 |
-
|
| 1529 |
-
|
| 1530 |
-
under the copy head after it. Run on a recipe for its own records, $P^\ast$ then
|
| 1531 |
writes the host into the idle bank, copies the recipe and hands control to the
|
| 1532 |
copy (Figure~\ref{fig:generation}).
|
| 1533 |
|
|
@@ -1549,10 +1571,9 @@ its predecessors on the current state, a state bit being unchanged until the
|
|
| 1549 |
record of its next value, which follows its last reader.
|
| 1550 |
\end{proof}
|
| 1551 |
|
| 1552 |
-
|
| 1553 |
-
|
| 1554 |
-
|
| 1555 |
-
sequential schedule of automata networks~\cite{RiosWilsonTheyssier2024c}.
|
| 1556 |
|
| 1557 |
\begin{lemma}[Compilation]\label{cor:compile}
|
| 1558 |
A ternary threshold unit $\Hv(\sum_{i\in P}x_i-\sum_{i\in N}x_i+b)$ is $1$
|
|
@@ -1576,55 +1597,54 @@ others are, and its base cases are the chains and the constants.
|
|
| 1576 |
\end{proof}
|
| 1577 |
|
| 1578 |
\begin{construction}[The stored host]\label{con:stored}
|
| 1579 |
-
Let $\
|
| 1580 |
Definition~\ref{def:twohead}, a cell $\mathrm{booted}$ at $8$, a counter
|
| 1581 |
-
$\mathrm{cnt}$ of $
|
| 1582 |
-
$\mathrm{dest}$
|
| 1583 |
-
$
|
| 1584 |
-
|
| 1585 |
-
lists the following $36{,}074$ records.
|
| 1586 |
\begin{enumerate}[label=(\alph*),leftmargin=2em]
|
| 1587 |
-
\item \emph{Startup}, $
|
| 1588 |
-
$c\leftarrow c\vee\neg\mathrm{booted}$ if its value in $m^\
|
| 1589 |
$c\leftarrow c\wedge\mathrm{booted}$ if it is $0$; then
|
| 1590 |
$c\leftarrow c\wedge\mathrm{booted}$ for the bits of the counter, the halt bit and
|
| 1591 |
the bits of $\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$; then
|
| 1592 |
$\mathrm{booted}\leftarrow1$.
|
| 1593 |
-
\item \emph{Step}
|
| 1594 |
-
|
| 1595 |
-
|
| 1596 |
-
|
| 1597 |
-
|
| 1598 |
-
|
| 1599 |
-
|
| 1600 |
-
|
| 1601 |
-
|
| 1602 |
-
|
| 1603 |
-
|
| 1604 |
-
|
| 1605 |
-
and $\kappa\leftarrow\kappa\oplus h$ in three records.
|
| 1606 |
\end{enumerate}
|
| 1607 |
Temporaries whose live intervals, from the first write to the last read, are
|
| 1608 |
-
disjoint share a cell,
|
| 1609 |
-
|
| 1610 |
-
|
| 1611 |
-
$
|
|
|
|
| 1612 |
\end{construction}
|
| 1613 |
|
| 1614 |
\begin{definition}[The device of the stored host]\label{def:ring}
|
| 1615 |
-
The device acts on the state $y$ of
|
| 1616 |
$\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$, the read tape, the idle bank
|
| 1617 |
and the copy tape, each request firing on the value $1$:
|
| 1618 |
\begin{enumerate}[label=(\roman*)]
|
| 1619 |
-
\item if $y_{c_{\mathrm{wr}}}=1$, the eight bits of $y_{R_{\mathrm{out}}}$, most
|
| 1620 |
significant first, are written under the arm if $\mathrm{dest}=0$ and under the
|
| 1621 |
copy head if $\mathrm{dest}=1$, that head turning after each, and
|
| 1622 |
$R_{\mathrm{out}}$ is cleared;
|
| 1623 |
\item if $y_{c_{\mathrm{rd}}}=1$, then $c_{\mathrm{eot}}$ is set if
|
| 1624 |
$\mathrm{dest}=1$ and $\mathrm{cnt}=\mathrm{lim}$, and otherwise the eight bits
|
| 1625 |
-
under the read head, the head turning after each, are loaded into
|
| 1626 |
-
$R_{\mathrm{in}}$ most significant first,
|
| 1627 |
-
$\mathrm{cnt}$ is incremented;
|
| 1628 |
\item if $y_{c_{\mathrm{rw}}}=1$, then $\mathrm{lim}\leftarrow\mathrm{cnt}$,
|
| 1629 |
$\mathrm{cnt}\leftarrow0$ and $\mathrm{dest}\leftarrow1$;
|
| 1630 |
\item the request cells are cleared.
|
|
@@ -1670,13 +1690,13 @@ loads $m^\ast$ and runs the copy.}
|
|
| 1670 |
\end{figure}
|
| 1671 |
|
| 1672 |
\begin{proposition}[One pass]\label{prop:storedpass}
|
| 1673 |
-
Let a state of $T^{
|
| 1674 |
-
its first record, and in the window clear requests and a
|
| 1675 |
-
replaces $x$ by $x_0(m^\
|
| 1676 |
-
$\mathrm{dest}$ if $\mathrm{booted}=0$; then carries out one step of $
|
| 1677 |
-
followed by the device of Definition~\ref{def:ring}; then sets $\mathrm{booted}$
|
| 1678 |
-
|
| 1679 |
-
|
| 1680 |
requests clear, whatever the temporaries held.
|
| 1681 |
\end{proposition}
|
| 1682 |
|
|
@@ -1684,40 +1704,44 @@ requests clear, whatever the temporaries held.
|
|
| 1684 |
By Lemma~\ref{lem:feedback} the pass evaluates the blocks of
|
| 1685 |
Construction~\ref{con:stored} in order. The startup records leave every cell
|
| 1686 |
unchanged when $\mathrm{booted}=1$; otherwise they set each memory bit to its value
|
| 1687 |
-
in $m^\
|
| 1688 |
compiled by Lemma~\ref{cor:compile}, in an order that Lemma~\ref{lem:feedback}
|
| 1689 |
-
admits: the first stage writes temporaries only, and
|
| 1690 |
-
|
| 1691 |
-
|
| 1692 |
-
|
| 1693 |
-
|
| 1694 |
-
|
| 1695 |
-
|
| 1696 |
-
|
| 1697 |
-
|
| 1698 |
-
|
| 1699 |
-
|
| 1700 |
-
|
| 1701 |
-
|
| 1702 |
-
|
| 1703 |
-
|
| 1704 |
-
|
| 1705 |
-
|
| 1706 |
-
$
|
|
|
|
|
|
|
|
|
|
| 1707 |
\end{proof}
|
| 1708 |
|
| 1709 |
The theorems below hold for every image $S'$ of $G$ records of which a pass of
|
| 1710 |
-
$T^\alpha_{G,L}$
|
| 1711 |
-
|
| 1712 |
-
|
| 1713 |
-
|
| 1714 |
-
|
| 1715 |
-
compile any netlist whose step is that of $
|
| 1716 |
-
$\alpha=12$, $G=36{,}074$ and
|
|
|
|
| 1717 |
|
| 1718 |
\begin{theorem}[Universal construction by the dynamics]\label{thm:storedconstruct}
|
| 1719 |
-
Let $S'$ be a stored host of $G$ records and $B<2^
|
| 1720 |
-
of $G$ records, let $r$ be a recipe with $\delta(r)=X$, and let $L=8|r|$. Let $x$
|
| 1721 |
be a state of $T^\alpha_{G,L}$ with $S'$ in the active bank from its first record,
|
| 1722 |
$r$ on the read tape from its head, and in the window $\mathrm{booted}=0$ and clear
|
| 1723 |
requests, whatever the idle bank, the copy tape and the other cells hold. After as
|
|
@@ -1730,15 +1754,15 @@ $T^\alpha_{G,L}$ evaluates the records of $X$.
|
|
| 1730 |
|
| 1731 |
\begin{proof}
|
| 1732 |
By the conclusion of Proposition~\ref{prop:storedpass} the first pass loads
|
| 1733 |
-
$x_0(m^\
|
| 1734 |
more step, with the device of Definition~\ref{def:ring}, up to the pass in which
|
| 1735 |
the halt bit is set, which clears $\mathrm{booted}$ and changes $\kappa$ at its
|
| 1736 |
-
last step. By Theorem~\ref{thm:selfrep}, $P^\ast$ on
|
| 1737 |
-
Definition~\ref{def:transducer} halts after the steps of
|
| 1738 |
Proposition~\ref{prop:steps} with output $\delta(r)\cat r$, reads no byte at
|
| 1739 |
$h=|r|$ before it requests the rewind, and requests it at $h=|r|$. On this run the
|
| 1740 |
two devices agree. A token covers at least one byte in at most two, so
|
| 1741 |
-
$|r|\le2B+1<2^
|
| 1742 |
$\mathrm{dest}=0$ and each read loads the next
|
| 1743 |
byte of $r$ and increments $\mathrm{cnt}$, so $\mathrm{cnt}=h$; at the rewind the
|
| 1744 |
read head has turned $8|r|=L$ cells and is back at its start, and $\mathrm{lim}$
|
|
@@ -1756,8 +1780,8 @@ By Lemma~\ref{lem:complete} every image of $G$ records has a recipe, so a stored
|
|
| 1756 |
host builds every image of its own size, itself among them.
|
| 1757 |
|
| 1758 |
\begin{theorem}[Self-reproduction of the host by the dynamics]\label{thm:storedrep}
|
| 1759 |
-
Let $S'$ be a stored host of $G$ records and $B
|
| 1760 |
-
and $L=8|\tau'|$, and let $x_0$ be the state of $T^\alpha_{G,L}$ with $S'$ in $Q_0$,
|
| 1761 |
$\tau'$ on $D_0$, and $Q_1$, $D_1$ and the window clear. For every $g\ge1$, the
|
| 1762 |
state after $g$ generations of $P$ passes, $GP$ applications of $T^\alpha_{G,L}$
|
| 1763 |
each, holds $S'$ in both banks and $\tau'$ on both tapes, each from its head, with
|
|
@@ -1795,6 +1819,42 @@ address are never written. So the two generations perform the same steps and end
|
|
| 1795 |
in the same state. Theorem~\ref{thm:physnet} carries the statement to the network.
|
| 1796 |
\end{proof}
|
| 1797 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1798 |
\begin{corollary}[Self-reproduction under noise]\label{cor:storednoise}
|
| 1799 |
$\Lev(N^{12}_{G,L})$ has depth $15$ and $110{,}775+58N+32L$ rows, $M=143{,}364{,}199$
|
| 1800 |
for the member that holds $S$. Under independent centred Gaussian perturbations of
|
|
@@ -1814,25 +1874,23 @@ coefficients.
|
|
| 1814 |
\end{proof}
|
| 1815 |
|
| 1816 |
\begin{remark}[Corroboration]\label{rem:storedcheck}
|
| 1817 |
-
Three generations from $x_0$ were run on a transcription of
|
| 1818 |
-
Definition~\ref{def:twohead} in C
|
| 1819 |
-
|
| 1820 |
-
|
| 1821 |
-
after the
|
| 1822 |
-
Python agreed with the C program on the full state after three passes and
|
| 1823 |
-
$12{,}345$ further steps. One pass was compared with the startup, one step of
|
| 1824 |
$\Nhost$ and the device of Definition~\ref{def:ring} from $300$ random states, a
|
| 1825 |
-
fifth of them not booted and a third with requests holding random
|
| 1826 |
-
random tapes, idle bank, registers and temporaries, and
|
| 1827 |
-
|
| 1828 |
-
|
| 1829 |
-
|
| 1830 |
-
|
| 1831 |
-
|
| 1832 |
-
|
| 1833 |
-
|
| 1834 |
-
|
| 1835 |
-
|
| 1836 |
\end{remark}
|
| 1837 |
|
| 1838 |
% =============================================================================
|
|
@@ -1840,11 +1898,10 @@ holding the variable of the unit of its next value.
|
|
| 1840 |
% =============================================================================
|
| 1841 |
|
| 1842 |
Theorem~\ref{thm:storedrep} is proved on paper over the Rocq proofs of
|
| 1843 |
-
Proposition~\ref{prop:host} and Theorem~\ref{thm:physnet}
|
| 1844 |
-
|
| 1845 |
-
|
| 1846 |
-
|
| 1847 |
-
proved in Rocq.
|
| 1848 |
|
| 1849 |
\begin{definition}[The description code]\label{def:code}
|
| 1850 |
A \emph{gate} is a record that computes the conjunction or the disjunction of
|
|
@@ -1944,10 +2001,8 @@ last pass; from then on $T_{133,L}$ evaluates the records of $X$.
|
|
| 1944 |
|
| 1945 |
\begin{proof}
|
| 1946 |
By Proposition~\ref{prop:pass} it suffices to follow the decoder over whole
|
| 1947 |
-
tapes. In construct mode a gate codon
|
| 1948 |
-
|
| 1949 |
-
arm; an escape costs as many and writes the $26$ bits that follow it; the end
|
| 1950 |
-
codon costs $4$ passes and switches to copy mode. Every consumed bit turns the
|
| 1951 |
read tape, so after the end codon it has turned $L$ cells and holds $d$ from its
|
| 1952 |
start again, and the arm has written the $26\cdot133$ bits of $X$ in order and
|
| 1953 |
turned once per bit, so the idle bank holds $X$. In copy mode every pass consumes
|
|
@@ -1986,11 +2041,9 @@ $T$ evaluated in the Rocq kernel, are equal, so the orbit is periodic.
|
|
| 1986 |
\begin{remark}\label{rem:organismcheck}
|
| 1987 |
The description of $\rho$ has $2930$ bits against $3458$ for the bank: a gate is
|
| 1988 |
named by four bits and its eight bits are written by the organism. Three
|
| 1989 |
-
generations
|
| 1990 |
-
|
| 1991 |
-
|
| 1992 |
-
states of the Rocq definition and of the transcription agree after $1000$ and
|
| 1993 |
-
$20{,}000$ steps.
|
| 1994 |
\end{remark}
|
| 1995 |
|
| 1996 |
% =============================================================================
|
|
@@ -2027,14 +2080,11 @@ simulated one, while here the simulating network is fixed.
|
|
| 2027 |
|
| 2028 |
\emph{Finiteness and noise.} Every network here is a finite
|
| 2029 |
automaton~\cite{Kleene1956,Minsky1967,SimaWiedermann1998}; power beyond finite
|
| 2030 |
-
automata comes from
|
| 2031 |
-
numbers of units
|
| 2032 |
-
|
| 2033 |
-
|
| 2034 |
-
|
| 2035 |
-
models to finite automata~\cite{MaassOrponen1998}; here bounded perturbations
|
| 2036 |
-
preserve every orbit for all time, and the failure probability under unbounded ones
|
| 2037 |
-
grows linearly with the run and falls with the margin at every noise level.
|
| 2038 |
|
| 2039 |
\emph{Self-reproduction.} Von Neumann's universal constructor uses a description
|
| 2040 |
once as instructions for construction and once as data to be
|
|
@@ -2059,14 +2109,12 @@ constructor is a configuration of a fixed threshold network that holds the weigh
|
|
| 2059 |
of the network that computes.
|
| 2060 |
|
| 2061 |
\emph{Networks that produce their own parameters.} Neural networks have been
|
| 2062 |
-
trained to output their own weights~\cite{ChangLipson2018}, to
|
| 2063 |
-
|
| 2064 |
-
|
| 2065 |
-
|
| 2066 |
-
|
| 2067 |
-
|
| 2068 |
-
themselves~\cite{Schmidhuber1993,IrieEtAl2022}. In each case the relation between a
|
| 2069 |
-
network and its parameters is learned and approximate.
|
| 2070 |
|
| 2071 |
\appendix
|
| 2072 |
% =============================================================================
|
|
@@ -2079,9 +2127,8 @@ and~\ref{sec:amplify} summarize; every run is recorded in the artifact.
|
|
| 2079 |
\subsection{The host}
|
| 2080 |
|
| 2081 |
Along the first $4000$ steps of the self-describing instance on $\Lev(\Nhost)$,
|
| 2082 |
-
an average of $26{,}825$ rows per step sit at pre-activation $-1$
|
| 2083 |
-
$0$
|
| 2084 |
-
above. Table~\ref{tab:curve} compares the per-step rate at which $256$ noisy
|
| 2085 |
copies first leave the exact orbit with the bound of
|
| 2086 |
Proposition~\ref{prop:profile}, evaluated on the same orbit and weighted by the
|
| 2087 |
steps each copy ran, and with the bound $Mp$ of Proposition~\ref{prop:random};
|
|
@@ -2170,13 +2217,11 @@ $0.36$ & 64/64 & 2{,}188 & $2.93\times10^{-2}$ & $4.30\times10^{-2}$ & $3.89$\\
|
|
| 2170 |
\section{Verification}\label{sec:verification}
|
| 2171 |
% =============================================================================
|
| 2172 |
|
| 2173 |
-
Four evaluators of the host transition were used
|
| 2174 |
-
representation: (a) an integer reference implementing
|
| 2175 |
Definitions~\ref{def:subleq} and~\ref{def:transducer}; (b) the netlist that
|
| 2176 |
-
$\sigma(\Nhost)$ denotes,
|
| 2177 |
-
|
| 2178 |
-
|
| 2179 |
-
levelization. Evaluators (b)--(d) are built from $\sigma(\Nhost)$. The
|
| 2180 |
self-describing instance ran to completion on (a), (b) and (d) in lockstep,
|
| 2181 |
$793{,}709$ steps emitting $\sigma(\Nhost)$; $\Omega^\ast$ for three generations on
|
| 2182 |
(a), (b) and (d) and for one on (c), each of $1{,}664{,}939$ steps emitting
|
|
@@ -2210,10 +2255,10 @@ computation; it proves Lemma~\ref{lem:code}, Proposition~\ref{prop:pass},
|
|
| 2210 |
Theorem~\ref{thm:construct} for images of any number of records with an idle bank
|
| 2211 |
of their length, and Theorem~\ref{thm:organism}. The file that defines the
|
| 2212 |
organism and its description is written by \texttt{src/twohead.py}, and the
|
| 2213 |
-
netlist definitions, extracted to OCaml, write for $H_8$ the netlist
|
| 2214 |
-
|
| 2215 |
-
$N^{12}_{5,40}$ files byte for byte equal to
|
| 2216 |
-
\texttt{src/twohead.py} writes.
|
| 2217 |
|
| 2218 |
The encoder satisfies $\delta(\describe(f))=f$ within the bound of
|
| 2219 |
Lemma~\ref{lem:describe} on the $29$ serialized machines of the artifact,
|
|
@@ -2225,15 +2270,12 @@ $137{,}781$ ternary units on eight inputs with biases in $[-10,10]$ computes the
|
|
| 2225 |
branch predicate; $\inst(\ser(\Omega))=\Omega$ on $310$ instances; the constructor,
|
| 2226 |
run on the $29$ recipes on the reference and on four of them on the netlist of
|
| 2227 |
$\sigma(\Nhost)$, emitted every target in the number of steps the reference took;
|
| 2228 |
-
|
| 2229 |
-
|
| 2230 |
-
Every run of $\Omega^\ast$ produced the same output,
|
| 2231 |
-
|
| 2232 |
-
|
| 2233 |
-
|
| 2234 |
-
the organism's record image and its description written as $3458$ and $2930$
|
| 2235 |
-
bytes of value $0$ or $1$, and of the image of the stored host and $\tau_S$ as
|
| 2236 |
-
bytes:
|
| 2237 |
\begin{center}\ttfamily\small
|
| 2238 |
\begin{tabular}{@{}l@{\quad}l@{}}
|
| 2239 |
\normalfont $\ser(\Omega^\ast)$ & c5950d3fec6bcf70e8111586a030d21b2dfa55bd69a1c7fe5f016cb06e7fb523\\
|
|
@@ -2281,65 +2323,6 @@ safetensors 0.8.0 and GCC 13.3.0 on Ubuntu 24.04, on an Intel Core i9-12900H
|
|
| 2281 |
with $20$ hardware threads and $31$ GiB of memory and an NVIDIA GeForce RTX 3070
|
| 2282 |
Ti Laptop GPU with $8$ GiB of memory.
|
| 2283 |
|
| 2284 |
-
% =============================================================================
|
| 2285 |
-
\section{Program listings}\label{app:listings}
|
| 2286 |
-
% =============================================================================
|
| 2287 |
-
|
| 2288 |
-
An instruction $A\;B\;C$ assigns $M[B]\leftarrow M[B]-M[A]$ and branches to $C$
|
| 2289 |
-
when the result is at most $0$ (Definition~\ref{def:subleq}); the device cells are
|
| 2290 |
-
those of Table~\ref{tab:device} and the variables those of
|
| 2291 |
-
Construction~\ref{con:P}, with $\cell{EOK}=\cell{0xF5}$ holding $1$. Writing $b$ for
|
| 2292 |
-
the tape byte just read, $\nu(b)$ is the value the program emits for it.
|
| 2293 |
-
|
| 2294 |
-
\begin{table}[ht]\centering\small
|
| 2295 |
-
\begin{tabular}{@{}rlllll@{}}
|
| 2296 |
-
\toprule
|
| 2297 |
-
$k$ & addr & $A$ & $B$ & $C$ & effect\\
|
| 2298 |
-
\midrule
|
| 2299 |
-
0 & \cell{0x00} & \cell{T2} & \cell{T2} & \cell{0x03} & $M[\cell{T2}]\leftarrow 0$\\
|
| 2300 |
-
1 & \cell{0x03} & \cell{T1} & \cell{T1} & \cell{0x06} & $M[\cell{T1}]\leftarrow 0$\\
|
| 2301 |
-
2 & \cell{0x06} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x09} & read request\\
|
| 2302 |
-
3 & \cell{0x09} & $R_{\mathrm{in}}$ & \cell{T1} & \cell{0x0C} & $M[\cell{T1}]\leftarrow\nu(T)$\\
|
| 2303 |
-
4 & \cell{0x0C} & \cell{T1} & \cell{T2} & \cell{0x0F} & $M[\cell{T2}]\leftarrow T$\\
|
| 2304 |
-
5 & \cell{0x0F} & \cell{Z} & \cell{T2} & \cell{0x15} & branch if $T=0$ or $T\ge128$\\
|
| 2305 |
-
6 & \cell{0x12} & \cell{Z} & \cell{Z} & \cell{0x1B} & goto \textsc{lit}\\
|
| 2306 |
-
7 & \cell{0x15} & \cell{Z} & \cell{T1} & \cell{0x3C} & branch to \textsc{end} if $\nu(T)\le0$\\
|
| 2307 |
-
8 & \cell{0x18} & \cell{Z} & \cell{Z} & \cell{0x2D} & goto \textsc{rep}\\
|
| 2308 |
-
9 & \cell{0x1B} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x1E} & \textsc{lit}: read request\\
|
| 2309 |
-
10 & \cell{0x1E} & $R_{\mathrm{in}}$ & $R_{\mathrm{out}}$ & \cell{0x21} & $M[R_{\mathrm{out}}]\leftarrow\nu(b)$\\
|
| 2310 |
-
11 & \cell{0x21} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x24} & write request\\
|
| 2311 |
-
12 & \cell{0x24} & \cell{ONE} & \cell{T2} & \cell{0x2A} & $M[\cell{T2}]\mathrel{-}=1$; done $\to$ 14\\
|
| 2312 |
-
13 & \cell{0x27} & \cell{Z} & \cell{Z} & \cell{0x1B} & next literal byte\\
|
| 2313 |
-
14 & \cell{0x2A} & \cell{Z} & \cell{Z} & \cell{0x00} & goto 0\\
|
| 2314 |
-
15 & \cell{0x2D} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x30} & \textsc{rep}: read request\\
|
| 2315 |
-
16 & \cell{0x30} & $R_{\mathrm{in}}$ & $R_{\mathrm{out}}$ & \cell{0x33} & $M[R_{\mathrm{out}}]\leftarrow\nu(b)$\\
|
| 2316 |
-
17 & \cell{0x33} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x36} & write request\\
|
| 2317 |
-
18 & \cell{0x36} & \cell{ONE} & \cell{T1} & \cell{0x2A} & $M[\cell{T1}]\mathrel{-}=1$; done $\to$ 14\\
|
| 2318 |
-
19 & \cell{0x39} & \cell{Z} & \cell{Z} & \cell{0x30} & emit again\\
|
| 2319 |
-
20 ($P$) & \cell{0x3C} & \cell{Z} & \cell{Z} & \cell{0xFF} & \textsc{end}: halt\\
|
| 2320 |
-
20 ($P^\ast$) & \cell{0x3C} & \cell{NEG1} & $c_{\mathrm{rw}}$ & \cell{0x3F} & \textsc{r}: rewind request\\
|
| 2321 |
-
21 & \cell{0x3F} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x42} & \textsc{b}: read request\\
|
| 2322 |
-
22 & \cell{0x42} & $c_{\mathrm{eot}}$ & \cell{EOK} & \cell{0xFF} & $M[\cell{EOK}]\leftarrow1-c_{\mathrm{eot}}$; halt if $\le0$\\
|
| 2323 |
-
23 & \cell{0x45} & $R_{\mathrm{in}}$ & \cell{Z} & \cell{0x48} & $M[\cell{Z}]\leftarrow\nu(b)$\\
|
| 2324 |
-
24 & \cell{0x48} & \cell{Z} & $R_{\mathrm{out}}$ & \cell{0x4B} & $M[R_{\mathrm{out}}]\leftarrow b$\\
|
| 2325 |
-
25 & \cell{0x4B} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x4E} & write request\\
|
| 2326 |
-
26 & \cell{0x4E} & \cell{Z} & \cell{Z} & \cell{0x3F} & $M[\cell{Z}]\leftarrow0$; goto \textsc{b}\\
|
| 2327 |
-
\bottomrule
|
| 2328 |
-
\end{tabular}
|
| 2329 |
-
\caption{The constructor $P$ of Construction~\ref{con:P}, instructions $0$ to $20$ at
|
| 2330 |
-
\cell{0x00}--\cell{0x3E}, and the self-reproducing program $P^\ast$ of
|
| 2331 |
-
Construction~\ref{con:selfrep}, instructions $0$ to $19$ of $P$ followed by $20$ to $26$ at
|
| 2332 |
-
\cell{0x3C}--\cell{0x50}.}
|
| 2333 |
-
\label{tab:P}\label{tab:Pstar}\end{table}
|
| 2334 |
-
|
| 2335 |
-
|
| 2336 |
-
\noindent The memory image $m^\ast$ is zero except for the $81$ program bytes at
|
| 2337 |
-
\cell{0x00}--\cell{0x50} and the constants $M[\cell{ONE}]=1$,
|
| 2338 |
-
$M[\cell{NEG1}]=255$, $M[\cell{EOK}]=1$; $m_P$ carries the same constants with the
|
| 2339 |
-
$63$ bytes of $P$.
|
| 2340 |
-
|
| 2341 |
-
|
| 2342 |
-
|
| 2343 |
% =============================================================================
|
| 2344 |
\begin{thebibliography}{99}
|
| 2345 |
\setlength{\itemsep}{0pt}
|
|
|
|
| 79 |
the second program on a description of its own records: it writes them into the
|
| 80 |
idle bank, copies the description and hands control to the copy, which does the
|
| 81 |
same, so the fixed network rebuilds, exactly and in every generation, the weights
|
| 82 |
+
of the stored network that computes, with no map outside it, and so does every
|
| 83 |
+
member of the family with wider words; a constructor of $133$ records does the same
|
| 84 |
+
with every step proved in Rocq. Because every
|
| 85 |
pre-activation is an integer, every orbit survives perturbations below $1/2$, and
|
| 86 |
a bound computed from the pre-activation profile is within $20\%$ of the measured
|
| 87 |
failure rate under Gaussian read noise. Replacing each unit by $r$ copies that read
|
|
|
|
| 107 |
description~\cite{vonNeumann1966}. The self-reproducing automata that followed
|
| 108 |
\cite{Arbib1966,Codd1968,Langton1984,Pesavento1995,PerrierSipperZahnd1996},
|
| 109 |
surveyed in~\cite{Sipper1998}, reproduce configurations of a cellular space
|
| 110 |
+
under a fixed transition rule.
|
|
|
|
|
|
|
| 111 |
|
| 112 |
This paper makes the parameters of a threshold network the object of exact
|
| 113 |
reproduction. The networks have weights in $\Tern$ and integer thresholds and
|
|
|
|
| 158 |
banks, with two tapes and three heads, each step evaluating one record, proved in
|
| 159 |
Rocq to compute the step of this two-head machine from every state for every
|
| 160 |
window of $2^\alpha$ cells and every $G$ and $L$ (Theorem~\ref{thm:physnet}).
|
| 161 |
+
Stored in it as records of two inputs, the host $H_A$ of every word width $A\ge8$
|
| 162 |
+
running $P^\ast$ builds every image of its size into the idle bank and hands
|
| 163 |
+
control to it, and started on a recipe for its own records reproduces in every
|
| 164 |
+
generation, weights included, in $\Theta(A^34^A)$ steps
|
| 165 |
+
(Theorems~\ref{thm:storedconstruct} to~\ref{thm:widths}); three generations of
|
| 166 |
+
$H_8$, $36{,}074$ records and $7.9\times10^{10}$ steps each, were run. A constructor of $133$ records with a description code of its own does
|
|
|
|
| 167 |
the same in the member with $64$ cells, every step of it proved in Rocq
|
| 168 |
(Section~\ref{sec:organism}).
|
| 169 |
\item \emph{Robustness.} Every orbit survives perturbations below $1/2$ per
|
|
|
|
| 175 |
threshold units, multiplies every margin by $r$: the probability of leaving an
|
| 176 |
orbit within $T$ steps under read noise of deviation $s$ is at most
|
| 177 |
$T\,rM\erfc(r/2\sqrt2 s)$, so any noise level is survived with redundancy
|
| 178 |
+
$O(s\sqrt{\log(TM/\delta)})$, and $O(s_{\mathrm w}^2\log(TM/\delta))$ with noise on
|
| 179 |
+
every synapse (Theorem~\ref{thm:amplify}, Corollary~\ref{cor:synapse}); a
|
| 180 |
+
second-order bound certifies the complete run of the threefold host where the
|
| 181 |
+
first-order bound exceeds one (Proposition~\ref{prop:restore}).
|
|
|
|
|
|
|
| 182 |
\end{enumerate}
|
| 183 |
|
| 184 |
% =============================================================================
|
|
|
|
| 304 |
\end{definition}
|
| 305 |
|
| 306 |
\begin{remark}[Device realization]\label{rem:devices}
|
| 307 |
+
In the host the registers and the request and status bits are memory cells at
|
| 308 |
+
the addresses of Table~\ref{tab:device}, and $c_{\mathrm{halt}}$ is a state bit
|
| 309 |
+
latching $p=255$ for the state the step produces, so that a halted state is a fixed
|
| 310 |
+
point; $F$ treats the device cells as ordinary memory.
|
|
|
|
|
|
|
|
|
|
| 311 |
\end{remark}
|
| 312 |
|
| 313 |
\begin{table}[ht]
|
|
|
|
| 419 |
Indices are taken modulo $S$, and the machine halts when $p=S-1$. The device
|
| 420 |
cells of Definition~\ref{def:transducer} are the seven top words, in the order of
|
| 421 |
Table~\ref{tab:device}; a request fires on the value $1$, a read loads a tape byte
|
| 422 |
+
into $R_{\mathrm{in}}$, its sign bit copied into the bits above the eighth, and an
|
| 423 |
+
emission appends the low byte of $R_{\mathrm{out}}$.
|
| 424 |
We write $\mathrm{SUBLEQ}_A$ for this machine. The host is $A=8$: $256$ words of
|
| 425 |
one byte.
|
| 426 |
\end{definition}
|
|
|
|
| 622 |
is proved in Rocq from a definition of $H_A$ block by block in the order of
|
| 623 |
Table~\ref{tab:blocks}: every unit is given its value in terms of the state,
|
| 624 |
the carries through the recurrence of Lemma~\ref{lem:sub}, and induction over the
|
| 625 |
+
units shows that the netlist computes these values. Extracted for $A=8$ to $10$,
|
| 626 |
+
the definition gives the netlist that $\sigma(\Nhost)$ denotes and those of the
|
| 627 |
+
generator, unit for unit.
|
| 628 |
\end{proof}
|
| 629 |
|
| 630 |
\begin{remark}[Depth]\label{rem:fold}
|
| 631 |
+
Writing every fetch conjunction $FA_{o,t,j}$, every read
|
|
|
|
|
|
|
| 632 |
conjunction $RX_{t,j}$, $RY_{t,j}$ and every write enable $W_j$ as a single unit
|
| 633 |
that reads the bits of its address directly, of fan-in $A+1$, removes the decode
|
| 634 |
lines of $a$ and $b$ and one level each from the fetch and from the operand reads,
|
|
|
|
| 636 |
$17{,}086$ units and $120{,}508$ edges, against $17{,}598$ and $51{,}132$, and for
|
| 637 |
every $A$ from $3$ to $12$ one step of it agreed with $\mathrm{SUBLEQ}_A$ on
|
| 638 |
$2^{16}$ uniformly random full states for $A\le10$ and on $2^{15}$ and $2^{14}$
|
| 639 |
+
for $A=11$ and $12$. The least depth of a ternary SUBLEQ step is open.
|
|
|
|
| 640 |
\end{remark}
|
| 641 |
|
| 642 |
% =============================================================================
|
|
|
|
| 748 |
and $R$ for the numbers of literal and repeat tokens of $r$ and
|
| 749 |
$f_{\mathrm{lit}}$, $f_{\mathrm{rep}}$ for the numbers of bytes each kind
|
| 750 |
contributes to $\delta(r)$, the run takes exactly
|
| 751 |
+
$5f_{\mathrm{lit}}+4f_{\mathrm{rep}}+7L+9R+8$ steps.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 752 |
\end{theorem}
|
| 753 |
|
| 754 |
\begin{proof}
|
|
|
|
| 780 |
also execute $13$, and $14$: $5T+7$ steps. A repeat token of run length
|
| 781 |
$\ell=256-T$ executes $7$, $8$ and $15$, $\ell$ passes of $16$ to $18$ of which the
|
| 782 |
first $\ell-1$ also execute $19$, and $14$: $4\ell+9$ steps. The end token executes
|
| 783 |
+
$0$ to $5$, $7$ and $20$: eight steps.
|
|
|
|
|
|
|
| 784 |
\end{proof}
|
| 785 |
|
| 786 |
\begin{corollary}[Self-description]\label{cor:selfdesc}
|
|
|
|
| 827 |
\]
|
| 828 |
\end{construction}
|
| 829 |
|
| 830 |
+
\begin{table}[t]\centering\small
|
| 831 |
+
\begin{tabular}{@{}rlllll@{}}
|
| 832 |
+
\toprule
|
| 833 |
+
$k$ & addr & $A$ & $B$ & $C$ & effect\\
|
| 834 |
+
\midrule
|
| 835 |
+
0 & \cell{0x00} & \cell{T2} & \cell{T2} & \cell{0x03} & $M[\cell{T2}]\leftarrow 0$\\
|
| 836 |
+
1 & \cell{0x03} & \cell{T1} & \cell{T1} & \cell{0x06} & $M[\cell{T1}]\leftarrow 0$\\
|
| 837 |
+
2 & \cell{0x06} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x09} & read request\\
|
| 838 |
+
3 & \cell{0x09} & $R_{\mathrm{in}}$ & \cell{T1} & \cell{0x0C} & $M[\cell{T1}]\leftarrow\nu(T)$\\
|
| 839 |
+
4 & \cell{0x0C} & \cell{T1} & \cell{T2} & \cell{0x0F} & $M[\cell{T2}]\leftarrow T$\\
|
| 840 |
+
5 & \cell{0x0F} & \cell{Z} & \cell{T2} & \cell{0x15} & branch if $T=0$ or $T\ge128$\\
|
| 841 |
+
6 & \cell{0x12} & \cell{Z} & \cell{Z} & \cell{0x1B} & goto \textsc{lit}\\
|
| 842 |
+
7 & \cell{0x15} & \cell{Z} & \cell{T1} & \cell{0x3C} & branch to \textsc{end} if $\nu(T)\le0$\\
|
| 843 |
+
8 & \cell{0x18} & \cell{Z} & \cell{Z} & \cell{0x2D} & goto \textsc{rep}\\
|
| 844 |
+
9 & \cell{0x1B} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x1E} & \textsc{lit}: read request\\
|
| 845 |
+
10 & \cell{0x1E} & $R_{\mathrm{in}}$ & $R_{\mathrm{out}}$ & \cell{0x21} & $M[R_{\mathrm{out}}]\leftarrow\nu(b)$\\
|
| 846 |
+
11 & \cell{0x21} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x24} & write request\\
|
| 847 |
+
12 & \cell{0x24} & \cell{ONE} & \cell{T2} & \cell{0x2A} & $M[\cell{T2}]\mathrel{-}=1$; done $\to$ 14\\
|
| 848 |
+
13 & \cell{0x27} & \cell{Z} & \cell{Z} & \cell{0x1B} & next literal byte\\
|
| 849 |
+
14 & \cell{0x2A} & \cell{Z} & \cell{Z} & \cell{0x00} & goto 0\\
|
| 850 |
+
15 & \cell{0x2D} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x30} & \textsc{rep}: read request\\
|
| 851 |
+
16 & \cell{0x30} & $R_{\mathrm{in}}$ & $R_{\mathrm{out}}$ & \cell{0x33} & $M[R_{\mathrm{out}}]\leftarrow\nu(b)$\\
|
| 852 |
+
17 & \cell{0x33} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x36} & write request\\
|
| 853 |
+
18 & \cell{0x36} & \cell{ONE} & \cell{T1} & \cell{0x2A} & $M[\cell{T1}]\mathrel{-}=1$; done $\to$ 14\\
|
| 854 |
+
19 & \cell{0x39} & \cell{Z} & \cell{Z} & \cell{0x30} & emit again\\
|
| 855 |
+
20 ($P$) & \cell{0x3C} & \cell{Z} & \cell{Z} & \cell{0xFF} & \textsc{end}: halt\\
|
| 856 |
+
20 ($P^\ast$) & \cell{0x3C} & \cell{NEG1} & $c_{\mathrm{rw}}$ & \cell{0x3F} & \textsc{r}: rewind request\\
|
| 857 |
+
21 & \cell{0x3F} & \cell{NEG1} & $c_{\mathrm{rd}}$ & \cell{0x42} & \textsc{b}: read request\\
|
| 858 |
+
22 & \cell{0x42} & $c_{\mathrm{eot}}$ & \cell{EOK} & \cell{0xFF} & $M[\cell{EOK}]\leftarrow1-c_{\mathrm{eot}}$; halt if $\le0$\\
|
| 859 |
+
23 & \cell{0x45} & $R_{\mathrm{in}}$ & \cell{Z} & \cell{0x48} & $M[\cell{Z}]\leftarrow\nu(b)$\\
|
| 860 |
+
24 & \cell{0x48} & \cell{Z} & $R_{\mathrm{out}}$ & \cell{0x4B} & $M[R_{\mathrm{out}}]\leftarrow b$\\
|
| 861 |
+
25 & \cell{0x4B} & \cell{NEG1} & $c_{\mathrm{wr}}$ & \cell{0x4E} & write request\\
|
| 862 |
+
26 & \cell{0x4E} & \cell{Z} & \cell{Z} & \cell{0x3F} & $M[\cell{Z}]\leftarrow0$; goto \textsc{b}\\
|
| 863 |
+
\bottomrule
|
| 864 |
+
\end{tabular}
|
| 865 |
+
\caption{The constructor $P$ of Construction~\ref{con:P}, instructions $0$ to $20$ at
|
| 866 |
+
\cell{0x00}--\cell{0x3E}, and the self-reproducing program $P^\ast$ of
|
| 867 |
+
Construction~\ref{con:selfrep}, instructions $0$ to $19$ of $P$ followed by $20$ to $26$ at
|
| 868 |
+
\cell{0x3C}--\cell{0x50}. An instruction $A\;B\;C$ assigns $M[B]\leftarrow M[B]-M[A]$ and
|
| 869 |
+
branches to $C$ when the result is at most $0$; $b$ is the tape byte just read.}
|
| 870 |
+
\label{tab:P}\label{tab:Pstar}\end{table}
|
| 871 |
+
|
| 872 |
\begin{theorem}[Exact self-reproduction]\label{thm:selfrep}
|
| 873 |
For every recipe $\tau$ the instance $(\Nhost,m^\ast,\tau)$ halts and
|
| 874 |
$\Out(\Nhost,m^\ast,\tau)=\delta(\tau)\cat\tau$; its run reads no byte at
|
|
|
|
| 929 |
$1{,}664{,}939$ in all.
|
| 930 |
\end{remark}
|
| 931 |
|
| 932 |
+
\begin{remark}[Wider words]\label{rem:wider}
|
| 933 |
+
For $A\ge8$ let $m^\ast_A$ hold $P^\ast$ in $2^A$ words, the cells $\cell{0xF0}$ to
|
| 934 |
+
$\cell{0xFF}$ and the addresses naming them moved to the top sixteen words, with
|
| 935 |
+
$M[\cell{ONE}]=M[\cell{EOK}]=1$ and $M[\cell{NEG1}]=2^A-1$, so that $m^\ast_8=m^\ast$.
|
| 936 |
+
Theorem~\ref{thm:selfrep} and Proposition~\ref{prop:steps} hold for $H_A$ and
|
| 937 |
+
$m^\ast_A$ with the same proofs: a byte read with its sign bit copied has the same
|
| 938 |
+
value in two's complement on $A$ bits as on eight, and the low byte of
|
| 939 |
+
$R_{\mathrm{out}}$ is again $\nu(b)$ or $b$, since $256$ divides $2^A$.
|
| 940 |
+
\end{remark}
|
| 941 |
+
|
| 942 |
|
| 943 |
% =============================================================================
|
| 944 |
\section{Robustness under perturbation}\label{sec:robust}
|
|
|
|
| 1027 |
$|e|\ge\tfrac12$. There are $TM$ evaluations up to time $T$.
|
| 1028 |
\end{proof}
|
| 1029 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1030 |
\begin{proposition}[Profile bound]\label{prop:profile}
|
| 1031 |
Let the perturbations be independent centred Gaussians of standard deviation
|
| 1032 |
$s$, let $(x_t)$ be the orbit of $F$ from $x_0$, and for $t\ge0$ and each row $i$
|
|
|
|
| 1067 |
first $10{,}000$ steps of the self-describing instance $K^\ast=8$ and
|
| 1068 |
$A^\ast=349$, and (ii) certifies $\gamma<1.43\times10^{-3}$ and
|
| 1069 |
$\varepsilon<1/16$, each alone; along the self-reproducing run $A^\ast=441$,
|
| 1070 |
+
certifying $\gamma<1.13\times10^{-3}$. Under uniform random errors the first
|
| 1071 |
+
$10{,}000$ steps stayed exact up to $\gamma=3.9\times10^{-3}$ and up to
|
| 1072 |
+
$\varepsilon=1/16$.
|
|
|
|
|
|
|
| 1073 |
|
| 1074 |
For Gaussian read noise of deviation $s=0.05$, $p=1.52\times10^{-23}$, and over the
|
| 1075 |
$T=1{,}664{,}939$ steps of the self-reproducing run, $TM=6.99\times10^{10}$,
|
|
|
|
| 1303 |
from $\rho_r(x_0(m))$ visits the replications of the states $\Nhost$ visits from
|
| 1304 |
$x_0(m)$ on the same tape and emits the same bytes. The proofs of
|
| 1305 |
Theorems~\ref{thm:univ} and~\ref{thm:selfrep} use the transducer alone, so they
|
| 1306 |
+
hold with $N_r$ in place of $\Nhost$.
|
|
|
|
|
|
|
| 1307 |
\end{proof}
|
| 1308 |
|
| 1309 |
One step of $N_3$ agreed with Definition~\ref{def:subleq} on $65{,}536$
|
|
|
|
| 1523 |
write requests; the cell under the arm after the write is a multiplexer of $v$
|
| 1524 |
and the old cell on the decode line of $2$. The tapes are alike, with cells $4$
|
| 1525 |
and $6$ and the decode line of $3$. Counting the units and edges of the blocks
|
| 1526 |
+
gives the sizes. The depth of a unit depends only on its block, from $2$ for the
|
| 1527 |
+
selected record to $15$ for the next tape bits. That the next state is the encoding of the next state of $x$, for
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1528 |
all $\alpha$, $G$, $L$ and $x$, is proved in Rocq with the number of units and the
|
| 1529 |
weights: every unit is given a value in terms of $x$ and fires to it on the values
|
| 1530 |
of the units it reads, and induction over the units shows that the netlist
|
|
|
|
| 1532 |
\end{proof}
|
| 1533 |
|
| 1534 |
\begin{remark}[Corroboration]\label{rem:physcheck}
|
| 1535 |
+
The member $N^6_{133,2930}$ of Section~\ref{sec:organism} has $45{,}891$ units and
|
| 1536 |
+
the member of Section~\ref{sec:storedhost} $22{,}329{,}613$. For $N^6_{133,2930}$ and
|
|
|
|
|
|
|
|
|
|
| 1537 |
$N^{12}_{5,40}$ the generator's file is byte for byte the netlist extracted from
|
| 1538 |
the Rocq definition, and three generations of the organism, $2{,}762{,}676$ steps,
|
| 1539 |
were run on $N^6_{133,2930}$ in C beside a transcription of
|
|
|
|
| 1546 |
|
| 1547 |
Inside the two-head machine the instantiation step of Section~\ref{sec:selfrep}
|
| 1548 |
is a write into the idle bank followed by a change of $\kappa$. This section
|
| 1549 |
+
stores the host, and every member of its family with wider words, as a network of
|
| 1550 |
+
two-input records in a bank of a two-head machine whose window holds its state
|
| 1551 |
+
bits, $4096$ cells for $\Nhost$, with a device that writes the bytes the host emits
|
| 1552 |
+
under the arm until the tape is rewound and under the copy head after it. Run on a recipe for its own records, $P^\ast$ then
|
| 1553 |
writes the host into the idle bank, copies the recipe and hands control to the
|
| 1554 |
copy (Figure~\ref{fig:generation}).
|
| 1555 |
|
|
|
|
| 1571 |
record of its next value, which follows its last reader.
|
| 1572 |
\end{proof}
|
| 1573 |
|
| 1574 |
+
Lemma~\ref{lem:feedback} is the rank-ordered schedule of gate-level simulation
|
| 1575 |
+
engines~\cite{Denneau1982} and the fixed-order sequential schedule of automata
|
| 1576 |
+
networks~\cite{RiosWilsonTheyssier2024c}.
|
|
|
|
| 1577 |
|
| 1578 |
\begin{lemma}[Compilation]\label{cor:compile}
|
| 1579 |
A ternary threshold unit $\Hv(\sum_{i\in P}x_i-\sum_{i\in N}x_i+b)$ is $1$
|
|
|
|
| 1597 |
\end{proof}
|
| 1598 |
|
| 1599 |
\begin{construction}[The stored host]\label{con:stored}
|
| 1600 |
+
Let $A\ge8$ and $w\ge20$. The window holds, after the eight cells of
|
| 1601 |
Definition~\ref{def:twohead}, a cell $\mathrm{booted}$ at $8$, a counter
|
| 1602 |
+
$\mathrm{cnt}$ of $w$ bits from $9$ on, least significant first, a cell
|
| 1603 |
+
$\mathrm{dest}$, a limit $\mathrm{lim}$ of $w$ bits, the $n=A+1+A2^A$ state bits of
|
| 1604 |
+
$H_A$ in the order of Construction~\ref{con:host}, and temporaries. The stored host
|
| 1605 |
+
$S_{A,w}$ lists the following records.
|
|
|
|
| 1606 |
\begin{enumerate}[label=(\alph*),leftmargin=2em]
|
| 1607 |
+
\item \emph{Startup}, $A2^A+A+2w+3$ records: for each memory bit $c$,
|
| 1608 |
+
$c\leftarrow c\vee\neg\mathrm{booted}$ if its value in $m^\ast_A$ is $1$ and
|
| 1609 |
$c\leftarrow c\wedge\mathrm{booted}$ if it is $0$; then
|
| 1610 |
$c\leftarrow c\wedge\mathrm{booted}$ for the bits of the counter, the halt bit and
|
| 1611 |
the bits of $\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$; then
|
| 1612 |
$\mathrm{booted}\leftarrow1$.
|
| 1613 |
+
\item \emph{Step}: the units of $H_A$ compiled by Lemma~\ref{cor:compile}, in two
|
| 1614 |
+
stages. The first evaluates every unit that a next value depends on, other than the
|
| 1615 |
+
units of the next values and the units read by a single unit, each after its
|
| 1616 |
+
predecessors. The second takes the counter bits, the halt bit and the memory bits
|
| 1617 |
+
in this order, and evaluates for each the unit of its next value, with the units
|
| 1618 |
+
read by it alone just before it, its last record writing the bit.
|
| 1619 |
+
\item \emph{Device}, $11A+12w+74$ records: the device of Definition~\ref{def:ring}
|
| 1620 |
+
on the state that~(b) leaves.
|
| 1621 |
+
\item \emph{Hand-over}: $\mathrm{booted}\leftarrow\mathrm{booted}\wedge\neg h$, where
|
| 1622 |
+
$h$ is the halt bit; the fewest records with both weights $0$ writing $0$ into the
|
| 1623 |
+
sink, at most seven, that make the image a whole number of bytes; and
|
| 1624 |
+
$\kappa\leftarrow\kappa\oplus h$ in three records.
|
|
|
|
| 1625 |
\end{enumerate}
|
| 1626 |
Temporaries whose live intervals, from the first write to the last read, are
|
| 1627 |
+
disjoint share a cell, and the window is the least $2^\alpha$ that holds the cells
|
| 1628 |
+
used. The host $S=S_{8,20}$ has its state bits at $50$ to $2106$ and $789$ cells of
|
| 1629 |
+
temporaries after them, so $\alpha=12$; its image, its records in order, has
|
| 1630 |
+
$1{,}587{,}256$ bits, read as $198{,}407$ bytes most significant bit first, and
|
| 1631 |
+
$\tau_S=\describe(S)$ has $199{,}971$ bytes.
|
| 1632 |
\end{construction}
|
| 1633 |
|
| 1634 |
\begin{definition}[The device of the stored host]\label{def:ring}
|
| 1635 |
+
The device acts on the state $y$ of $H_A$ after a step, the registers
|
| 1636 |
$\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$, the read tape, the idle bank
|
| 1637 |
and the copy tape, each request firing on the value $1$:
|
| 1638 |
\begin{enumerate}[label=(\roman*)]
|
| 1639 |
+
\item if $y_{c_{\mathrm{wr}}}=1$, the low eight bits of $y_{R_{\mathrm{out}}}$, most
|
| 1640 |
significant first, are written under the arm if $\mathrm{dest}=0$ and under the
|
| 1641 |
copy head if $\mathrm{dest}=1$, that head turning after each, and
|
| 1642 |
$R_{\mathrm{out}}$ is cleared;
|
| 1643 |
\item if $y_{c_{\mathrm{rd}}}=1$, then $c_{\mathrm{eot}}$ is set if
|
| 1644 |
$\mathrm{dest}=1$ and $\mathrm{cnt}=\mathrm{lim}$, and otherwise the eight bits
|
| 1645 |
+
under the read head, the head turning after each, are loaded into the low byte of
|
| 1646 |
+
$R_{\mathrm{in}}$ most significant first, their sign bit is copied into the bits
|
| 1647 |
+
above them, $c_{\mathrm{eot}}$ is cleared and $\mathrm{cnt}$ is incremented;
|
| 1648 |
\item if $y_{c_{\mathrm{rw}}}=1$, then $\mathrm{lim}\leftarrow\mathrm{cnt}$,
|
| 1649 |
$\mathrm{cnt}\leftarrow0$ and $\mathrm{dest}\leftarrow1$;
|
| 1650 |
\item the request cells are cleared.
|
|
|
|
| 1690 |
\end{figure}
|
| 1691 |
|
| 1692 |
\begin{proposition}[One pass]\label{prop:storedpass}
|
| 1693 |
+
Let a state of $T^\alpha_{G,L}$ hold $S_{A,w}$, of $G$ records, in the active bank
|
| 1694 |
+
from its first record, and in the window clear requests and a state $x$ of $H_A$.
|
| 1695 |
+
One pass replaces $x$ by $x_0(m^\ast_A)$ and clears $\mathrm{cnt}$, $\mathrm{lim}$
|
| 1696 |
+
and $\mathrm{dest}$ if $\mathrm{booted}=0$; then carries out one step of $H_A$
|
| 1697 |
+
followed by the device of Definition~\ref{def:ring}; then sets $\mathrm{booted}$ to
|
| 1698 |
+
the negation of the halt bit and, if the halt bit is $1$, changes $\kappa$ at its
|
| 1699 |
+
last step. It leaves $S_{A,w}$ in the active bank from its first record and the
|
| 1700 |
requests clear, whatever the temporaries held.
|
| 1701 |
\end{proposition}
|
| 1702 |
|
|
|
|
| 1704 |
By Lemma~\ref{lem:feedback} the pass evaluates the blocks of
|
| 1705 |
Construction~\ref{con:stored} in order. The startup records leave every cell
|
| 1706 |
unchanged when $\mathrm{booted}=1$; otherwise they set each memory bit to its value
|
| 1707 |
+
in $m^\ast_A$ and clear the other cells they name. The step block is $H_A$
|
| 1708 |
compiled by Lemma~\ref{cor:compile}, in an order that Lemma~\ref{lem:feedback}
|
| 1709 |
+
admits: the first stage writes temporaries only, and in the second the group of a
|
| 1710 |
+
state bit evaluates with its unit only units read by that unit alone, $HP_i$,
|
| 1711 |
+
$Q_i$, $TA_i$ and $TB_i$ for a counter bit, $AC$, $HA$ and $HB$ for the halt bit,
|
| 1712 |
+
$KP_{j,t}$ and $WR_{j,t}$ for a memory bit (Table~\ref{tab:blocks}), which read,
|
| 1713 |
+
besides temporaries, only that bit and, for a counter bit, the halt bit, whose
|
| 1714 |
+
group comes later. So after the block the state bits hold the next state of
|
| 1715 |
+
$H_A$, which Remark~\ref{rem:storedcheck} also checks on every window for
|
| 1716 |
+
$A\le10$. The device records form the requests $[y_c=1]$ as conjunctions of $A$
|
| 1717 |
+
literals, the bit $[\mathrm{cnt}=\mathrm{lim}]$ as a conjunction of $w$
|
| 1718 |
+
equivalences, and its conjunction with $\mathrm{dest}$. They then write each bit of
|
| 1719 |
+
the low byte of $R_{\mathrm{out}}$ under the arm or the copy head by a multiplexer,
|
| 1720 |
+
followed by the request that turns that head, and clear $R_{\mathrm{out}}$ on a
|
| 1721 |
+
write; load each bit under the read head into $R_{\mathrm{in}}$ by a multiplexer on
|
| 1722 |
+
the condition of a read, followed by the request that turns the read tape, and copy
|
| 1723 |
+
the sign bit above them; set $c_{\mathrm{eot}}$; increment $\mathrm{cnt}$ by carries
|
| 1724 |
+
formed before any of its bits changes; carry out the rewind; and clear the
|
| 1725 |
+
requests: these are clauses (i) to (iv) of Definition~\ref{def:ring}. The hand-over
|
| 1726 |
+
records set $\mathrm{booted}$ and, last, $\kappa$. Every temporary is written in the
|
| 1727 |
+
pass before it is read and is not written after its last read, so a cell shared by
|
| 1728 |
+
temporaries holds, at each read, the value of the temporary read. No record writes
|
| 1729 |
+
the active bank, which turns by $G$ records.
|
| 1730 |
\end{proof}
|
| 1731 |
|
| 1732 |
The theorems below hold for every image $S'$ of $G$ records of which a pass of
|
| 1733 |
+
$T^\alpha_{G,L}$ does what Proposition~\ref{prop:storedpass} states for some
|
| 1734 |
+
$S_{A,w}$, on the window cells of Construction~\ref{con:stored}, every cell that a
|
| 1735 |
+
record after the startup records reads, other than $\kappa$, the cells under the
|
| 1736 |
+
heads and the sink, being written earlier in the pass; we call such an image a
|
| 1737 |
+
\emph{stored host}, of $B=bG/8$ bytes with $b=8+3\alpha$, and $w$ the width of its
|
| 1738 |
+
counters. Its step block may compile any netlist whose step is that of $H_A$; every
|
| 1739 |
+
$S_{A,w}$ is a stored host, and $S$ one with $\alpha=12$, $G=36{,}074$ and
|
| 1740 |
+
$B=198{,}407$.
|
| 1741 |
|
| 1742 |
\begin{theorem}[Universal construction by the dynamics]\label{thm:storedconstruct}
|
| 1743 |
+
Let $S'$ be a stored host of $G$ records and $B$ bytes with $2B+1<2^w$, let $X$ be
|
| 1744 |
+
an image of $G$ records, let $r$ be a recipe with $\delta(r)=X$, and let $L=8|r|$. Let $x$
|
| 1745 |
be a state of $T^\alpha_{G,L}$ with $S'$ in the active bank from its first record,
|
| 1746 |
$r$ on the read tape from its head, and in the window $\mathrm{booted}=0$ and clear
|
| 1747 |
requests, whatever the idle bank, the copy tape and the other cells hold. After as
|
|
|
|
| 1754 |
|
| 1755 |
\begin{proof}
|
| 1756 |
By the conclusion of Proposition~\ref{prop:storedpass} the first pass loads
|
| 1757 |
+
$x_0(m^\ast_A)$ and carries out the first step of the host, and each later pass one
|
| 1758 |
more step, with the device of Definition~\ref{def:ring}, up to the pass in which
|
| 1759 |
the halt bit is set, which clears $\mathrm{booted}$ and changes $\kappa$ at its
|
| 1760 |
+
last step. By Theorem~\ref{thm:selfrep} and Remark~\ref{rem:wider}, $P^\ast$ on
|
| 1761 |
+
$r$ with the device of Definition~\ref{def:transducer} halts after the steps of
|
| 1762 |
Proposition~\ref{prop:steps} with output $\delta(r)\cat r$, reads no byte at
|
| 1763 |
$h=|r|$ before it requests the rewind, and requests it at $h=|r|$. On this run the
|
| 1764 |
two devices agree. A token covers at least one byte in at most two, so
|
| 1765 |
+
$|r|\le2B+1<2^w$ and $\mathrm{cnt}$ does not wrap. Before the rewind
|
| 1766 |
$\mathrm{dest}=0$ and each read loads the next
|
| 1767 |
byte of $r$ and increments $\mathrm{cnt}$, so $\mathrm{cnt}=h$; at the rewind the
|
| 1768 |
read head has turned $8|r|=L$ cells and is back at its start, and $\mathrm{lim}$
|
|
|
|
| 1780 |
host builds every image of its own size, itself among them.
|
| 1781 |
|
| 1782 |
\begin{theorem}[Self-reproduction of the host by the dynamics]\label{thm:storedrep}
|
| 1783 |
+
Let $S'$ be a stored host of $G$ records and $B$ bytes with $2B+1<2^w$,
|
| 1784 |
+
$\tau'=\describe(S')$ and $L=8|\tau'|$, and let $x_0$ be the state of $T^\alpha_{G,L}$ with $S'$ in $Q_0$,
|
| 1785 |
$\tau'$ on $D_0$, and $Q_1$, $D_1$ and the window clear. For every $g\ge1$, the
|
| 1786 |
state after $g$ generations of $P$ passes, $GP$ applications of $T^\alpha_{G,L}$
|
| 1787 |
each, holds $S'$ in both banks and $\tau'$ on both tapes, each from its head, with
|
|
|
|
| 1819 |
in the same state. Theorem~\ref{thm:physnet} carries the statement to the network.
|
| 1820 |
\end{proof}
|
| 1821 |
|
| 1822 |
+
\begin{theorem}[Every word width]\label{thm:widths}
|
| 1823 |
+
For every $A\ge8$ there is a least $w_A\ge20$ for which $S_A=S_{A,w_A}$ has
|
| 1824 |
+
$2B+1<2^{w_A}$. The stored host $S_A$ builds every image of its size and
|
| 1825 |
+
reproduces itself by the dynamics of $N^{\alpha_A}_{G_A,L_A}$ as
|
| 1826 |
+
Theorems~\ref{thm:storedconstruct} and~\ref{thm:storedrep} state, with
|
| 1827 |
+
\[
|
| 1828 |
+
G_A=35A2^{A-1}-2^{A+1}+\tfrac16(A^3-A)+A^2+29A+14w_A+85+\pi_A
|
| 1829 |
+
\]
|
| 1830 |
+
records, $\pi_A\le7$ the sink records of its hand-over, a window of $2^{\alpha_A}$
|
| 1831 |
+
cells with $\alpha_A=A+\Theta(\log A)$, and generations of $\Theta(A^34^A)$
|
| 1832 |
+
applications of $T^{\alpha_A}_{G_A,L_A}$.
|
| 1833 |
+
\end{theorem}
|
| 1834 |
+
|
| 1835 |
+
\begin{proof}
|
| 1836 |
+
A pass of $S_A$ does what Proposition~\ref{prop:storedpass} states, and every cell
|
| 1837 |
+
a record after the startup reads, other than $\kappa$, the cells under the heads and
|
| 1838 |
+
the sink, is written earlier in the pass, so $S_A$ is a stored host; $w_A$ exists
|
| 1839 |
+
since $B$ grows with $w$ far slower than $2^w$. The startup and device records are counted in Construction~\ref{con:stored} and the
|
| 1840 |
+
hand-over has $4+\pi_A$. Lemma~\ref{cor:compile} compiles a conjunction or a
|
| 1841 |
+
disjunction of $k\ge2$ literals into $k-1$ records and a unit of threshold $2$ on
|
| 1842 |
+
three or four literals into four or eight, and summing over the blocks of
|
| 1843 |
+
Table~\ref{tab:blocks} gives
|
| 1844 |
+
$\tfrac{33}{2}A2^A-2^{A+1}+\tfrac16(A^3-A)+A^2+17A+4$ step records, the cubic term
|
| 1845 |
+
from the carry terms. The window holds the $A2^A+A+1$ state bits and at most $G_A$
|
| 1846 |
+
temporaries, so $\alpha_A=A+\Theta(\log A)$; then $b=8+3\alpha_A=\Theta(A)$,
|
| 1847 |
+
$B=bG_A/8=\Theta(A^22^A)$, and Theorem~\ref{thm:storedrep} gives a generation of
|
| 1848 |
+
$\Theta(B)$ passes of $G_A$ steps.
|
| 1849 |
+
\end{proof}
|
| 1850 |
+
|
| 1851 |
+
For $A=8$ to $12$, $S_A$ has $36{,}074$, $80{,}448$, $178{,}100$, $391{,}216$ and
|
| 1852 |
+
$853{,}167$ records, windows of $2^{12}$ to $2^{16}$ cells, counters of $20$, $20$,
|
| 1853 |
+
$22$, $23$ and $24$ bits and images of $198{,}407$ to $5{,}972{,}169$ bytes, and a
|
| 1854 |
+
generation takes $2{,}202{,}812$, $5{,}247{,}354$, $12{,}358{,}336$,
|
| 1855 |
+
$28{,}775{,}186$ and $66{,}305{,}186$ passes, $7.95\times10^{10}$ to
|
| 1856 |
+
$5.66\times10^{13}$ applications of $T$.
|
| 1857 |
+
|
| 1858 |
\begin{corollary}[Self-reproduction under noise]\label{cor:storednoise}
|
| 1859 |
$\Lev(N^{12}_{G,L})$ has depth $15$ and $110{,}775+58N+32L$ rows, $M=143{,}364{,}199$
|
| 1860 |
for the member that holds $S$. Under independent centred Gaussian perturbations of
|
|
|
|
| 1874 |
\end{proof}
|
| 1875 |
|
| 1876 |
\begin{remark}[Corroboration]\label{rem:storedcheck}
|
| 1877 |
+
Three generations of $S$ from $x_0$ were run on a transcription of
|
| 1878 |
+
Definition~\ref{def:twohead} in C: after each the new active bank held $S$ and the
|
| 1879 |
+
new read tape $\tau_S$, each from its head, the other bank and tape still held them,
|
| 1880 |
+
$\kappa$ alternated, and the full state after the third generation equalled the
|
| 1881 |
+
state after the first. One pass of $S$ agreed with the startup, one step of
|
|
|
|
|
|
|
| 1882 |
$\Nhost$ and the device of Definition~\ref{def:ring} from $300$ random states, a
|
| 1883 |
+
fifth of them not booted and a third with requests holding random words, with
|
| 1884 |
+
random tapes, idle bank, registers and temporaries, and so did one pass of $S_9$
|
| 1885 |
+
from $300$ and of $S_{10}$ from $100$. The startup and step records of $S_8$ to
|
| 1886 |
+
$S_{10}$ were also evaluated on reduced ordered decision diagrams over variables for
|
| 1887 |
+
the state bits and the units of $H_A$, the variable of a unit replacing, at the
|
| 1888 |
+
record the compiler names as writing its value, a diagram checked to equal the
|
| 1889 |
+
unit's function of the variables of its predecessors: from every window the startup
|
| 1890 |
+
records leave $x_0(m^\ast_A)$ or the state as $\mathrm{booted}$ is $0$ or $1$, and the
|
| 1891 |
+
step records leave every state bit holding the variable of the unit of its next
|
| 1892 |
+
value. The counts of Theorem~\ref{thm:widths} agree with the construction for $A=8$
|
| 1893 |
+
to $12$.
|
| 1894 |
\end{remark}
|
| 1895 |
|
| 1896 |
% =============================================================================
|
|
|
|
| 1898 |
% =============================================================================
|
| 1899 |
|
| 1900 |
Theorem~\ref{thm:storedrep} is proved on paper over the Rocq proofs of
|
| 1901 |
+
Proposition~\ref{prop:host} and Theorem~\ref{thm:physnet}. This section gives a
|
| 1902 |
+
smaller stored network, the organism, that performs von Neumann's cycle in
|
| 1903 |
+
$T_{G,L}$, the machine of $64$ cells, with a description code of its own; every step
|
| 1904 |
+
of its reproduction is proved in Rocq.
|
|
|
|
| 1905 |
|
| 1906 |
\begin{definition}[The description code]\label{def:code}
|
| 1907 |
A \emph{gate} is a record that computes the conjunction or the disjunction of
|
|
|
|
| 2001 |
|
| 2002 |
\begin{proof}
|
| 2003 |
By Proposition~\ref{prop:pass} it suffices to follow the decoder over whole
|
| 2004 |
+
tapes. In construct mode a gate codon or an escape costs $30$ passes and writes a
|
| 2005 |
+
record under the arm, and the end codon $4$ passes, switching to copy mode. Every consumed bit turns the
|
|
|
|
|
|
|
| 2006 |
read tape, so after the end codon it has turned $L$ cells and holds $d$ from its
|
| 2007 |
start again, and the arm has written the $26\cdot133$ bits of $X$ in order and
|
| 2008 |
turned once per bit, so the idle bank holds $X$. In copy mode every pass consumes
|
|
|
|
| 2041 |
\begin{remark}\label{rem:organismcheck}
|
| 2042 |
The description of $\rho$ has $2930$ bits against $3458$ for the bank: a gate is
|
| 2043 |
named by four bits and its eight bits are written by the organism. Three
|
| 2044 |
+
generations were also run on the transcription of Definition~\ref{def:twohead} and
|
| 2045 |
+
on the netlist beside it (Remark~\ref{rem:physcheck}), with the outcome the theorem
|
| 2046 |
+
states.
|
|
|
|
|
|
|
| 2047 |
\end{remark}
|
| 2048 |
|
| 2049 |
% =============================================================================
|
|
|
|
| 2080 |
|
| 2081 |
\emph{Finiteness and noise.} Every network here is a finite
|
| 2082 |
automaton~\cite{Kleene1956,Minsky1967,SimaWiedermann1998}; power beyond finite
|
| 2083 |
+
automata comes from unbounded precision~\cite{SiegelmannSontag1995}, growing
|
| 2084 |
+
numbers of units~\cite{ChungSiegelmann2021} or changing
|
| 2085 |
+
weights~\cite{CabessaSiegelmann2014}, and von Neumann's cellular automaton is
|
| 2086 |
+
universal because its tape can be extended~\cite{vonNeumann1966,Burks1970}. Analog
|
| 2087 |
+
noise reduces discrete-time analog models to finite automata~\cite{MaassOrponen1998}.
|
|
|
|
|
|
|
|
|
|
| 2088 |
|
| 2089 |
\emph{Self-reproduction.} Von Neumann's universal constructor uses a description
|
| 2090 |
once as instructions for construction and once as data to be
|
|
|
|
| 2109 |
of the network that computes.
|
| 2110 |
|
| 2111 |
\emph{Networks that produce their own parameters.} Neural networks have been
|
| 2112 |
+
trained to output their own weights~\cite{ChangLipson2018,Gabor2022}, to reproduce
|
| 2113 |
+
over generations~\cite{RandazzoVersariMordvintsev2021,ShvartzmanRam2024} and to
|
| 2114 |
+
emit the program text that trains them~\cite{Schmidgall2021}; hypernetworks and
|
| 2115 |
+
self-referential weight matrices generate or modify
|
| 2116 |
+
weights~\cite{HaDaiLe2017,Schmidhuber1993,IrieEtAl2022}. In each case the relation
|
| 2117 |
+
between a network and its parameters is learned and approximate.
|
|
|
|
|
|
|
| 2118 |
|
| 2119 |
\appendix
|
| 2120 |
% =============================================================================
|
|
|
|
| 2127 |
\subsection{The host}
|
| 2128 |
|
| 2129 |
Along the first $4000$ steps of the self-describing instance on $\Lev(\Nhost)$,
|
| 2130 |
+
an average of $26{,}825$ rows per step sit at pre-activation $-1$ and $4{,}066$ at
|
| 2131 |
+
$0$. Table~\ref{tab:curve} compares the per-step rate at which $256$ noisy
|
|
|
|
| 2132 |
copies first leave the exact orbit with the bound of
|
| 2133 |
Proposition~\ref{prop:profile}, evaluated on the same orbit and weighted by the
|
| 2134 |
steps each copy ran, and with the bound $Mp$ of Proposition~\ref{prop:random};
|
|
|
|
| 2217 |
\section{Verification}\label{sec:verification}
|
| 2218 |
% =============================================================================
|
| 2219 |
|
| 2220 |
+
Four evaluators of the host transition were used: (a) an integer reference of
|
|
|
|
| 2221 |
Definitions~\ref{def:subleq} and~\ref{def:transducer}; (b) the netlist that
|
| 2222 |
+
$\sigma(\Nhost)$ denotes, unit by unit; (c) $\Lev(\Nhost)$, dense or sparse; and
|
| 2223 |
+
(d) \texttt{src/netlist\_eval.c}, with its own reference, device, parser and
|
| 2224 |
+
levelization; (b)--(d) are built from $\sigma(\Nhost)$. The
|
|
|
|
| 2225 |
self-describing instance ran to completion on (a), (b) and (d) in lockstep,
|
| 2226 |
$793{,}709$ steps emitting $\sigma(\Nhost)$; $\Omega^\ast$ for three generations on
|
| 2227 |
(a), (b) and (d) and for one on (c), each of $1{,}664{,}939$ steps emitting
|
|
|
|
| 2255 |
Theorem~\ref{thm:construct} for images of any number of records with an idle bank
|
| 2256 |
of their length, and Theorem~\ref{thm:organism}. The file that defines the
|
| 2257 |
organism and its description is written by \texttt{src/twohead.py}, and the
|
| 2258 |
+
netlist definitions, extracted to OCaml, write for $H_8$ the netlist that
|
| 2259 |
+
$\sigma(\Nhost)$ denotes, for $H_9$ and $H_{10}$ those that \texttt{src/host.py}
|
| 2260 |
+
generates, and for $N^6_{133,2930}$ and $N^{12}_{5,40}$ files byte for byte equal to
|
| 2261 |
+
those that \texttt{src/twohead.py} writes.
|
| 2262 |
|
| 2263 |
The encoder satisfies $\delta(\describe(f))=f$ within the bound of
|
| 2264 |
Lemma~\ref{lem:describe} on the $29$ serialized machines of the artifact,
|
|
|
|
| 2270 |
branch predicate; $\inst(\ser(\Omega))=\Omega$ on $310$ instances; the constructor,
|
| 2271 |
run on the $29$ recipes on the reference and on four of them on the netlist of
|
| 2272 |
$\sigma(\Nhost)$, emitted every target in the number of steps the reference took;
|
| 2273 |
+
rebuilding the host from source reproduces its serialization byte for byte.
|
| 2274 |
+
|
| 2275 |
+
Every run of $\Omega^\ast$ produced the same output, and the
|
| 2276 |
+
artifact~\cite{Norton2026} is identified by the following SHA-256 digests, the
|
| 2277 |
+
organism's image and description taken as $3458$ and $2930$ bytes of value $0$ or
|
| 2278 |
+
$1$:
|
|
|
|
|
|
|
|
|
|
| 2279 |
\begin{center}\ttfamily\small
|
| 2280 |
\begin{tabular}{@{}l@{\quad}l@{}}
|
| 2281 |
\normalfont $\ser(\Omega^\ast)$ & c5950d3fec6bcf70e8111586a030d21b2dfa55bd69a1c7fe5f016cb06e7fb523\\
|
|
|
|
| 2323 |
with $20$ hardware threads and $31$ GiB of memory and an NVIDIA GeForce RTX 3070
|
| 2324 |
Ti Laptop GPU with $8$ GiB of memory.
|
| 2325 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2326 |
% =============================================================================
|
| 2327 |
\begin{thebibliography}{99}
|
| 2328 |
\setlength{\itemsep}{0pt}
|
src/host.py
CHANGED
|
@@ -887,6 +887,24 @@ M_P = memory_image(P)
|
|
| 887 |
M_STAR = memory_image(P_STAR)
|
| 888 |
|
| 889 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 890 |
# =============================================================================
|
| 891 |
# Device
|
| 892 |
# =============================================================================
|
|
@@ -944,6 +962,37 @@ def run_reference(mem0: List[int], tau: bytes, max_steps: int = 1 << 34,
|
|
| 944 |
steps += 1
|
| 945 |
return bytes(dev.out), steps
|
| 946 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 947 |
# =============================================================================
|
| 948 |
# The host netlist and its canonical serialization
|
| 949 |
# =============================================================================
|
|
|
|
| 887 |
M_STAR = memory_image(P_STAR)
|
| 888 |
|
| 889 |
|
| 890 |
+
def program_a(prog: List[Tuple[int, int, int]], A: int) -> List[Tuple[int, int, int]]:
|
| 891 |
+
"""A program moved to 2^A words: the cells from 0xF0 up name the top sixteen words."""
|
| 892 |
+
top = (1 << A) - 256
|
| 893 |
+
return [tuple(x + top if x >= 0xF0 else x for x in ins) for ins in prog]
|
| 894 |
+
|
| 895 |
+
|
| 896 |
+
def memory_image_a(prog: List[Tuple[int, int, int]], A: int) -> List[int]:
|
| 897 |
+
"""The initial memory of 2^A words holding a program moved there and its constants."""
|
| 898 |
+
S = 1 << A
|
| 899 |
+
top = S - 256
|
| 900 |
+
mem = [0] * S
|
| 901 |
+
for addr, val in _emit(program_a(prog, A)).items():
|
| 902 |
+
mem[addr] = val
|
| 903 |
+
for cell, val in ((Z, 0), (ONE, 1), (T1, 0), (T2, 0), (NEG1, S - 1), (EOK, 1)):
|
| 904 |
+
mem[cell + top] = val
|
| 905 |
+
return mem
|
| 906 |
+
|
| 907 |
+
|
| 908 |
# =============================================================================
|
| 909 |
# Device
|
| 910 |
# =============================================================================
|
|
|
|
| 962 |
steps += 1
|
| 963 |
return bytes(dev.out), steps
|
| 964 |
|
| 965 |
+
|
| 966 |
+
def run_reference_a(mem0: List[int], tau: bytes, A: int, max_steps: int = 1 << 40) -> Tuple[bytes, int]:
|
| 967 |
+
"""SUBLEQ_A with the device on its top words, a read extending the byte by its sign."""
|
| 968 |
+
S, half = 1 << A, 1 << (A - 1)
|
| 969 |
+
io = io_cells(A)
|
| 970 |
+
wr, eot, rw, rd, rin, rout, halt = (io[k] for k in ('c_wr', 'c_eot', 'c_rw', 'c_rd', 'r_in', 'r_out',
|
| 971 |
+
'halt_pc'))
|
| 972 |
+
mem, out = list(mem0), bytearray()
|
| 973 |
+
pc = h = steps = 0
|
| 974 |
+
while pc != halt and steps < max_steps:
|
| 975 |
+
a, b, c = mem[pc], mem[(pc + 1) % S], mem[(pc + 2) % S]
|
| 976 |
+
r = (mem[b] - mem[a]) % S
|
| 977 |
+
mem[b] = r
|
| 978 |
+
pc = c if r == 0 or r >= half else (pc + 3) % S
|
| 979 |
+
if mem[wr] == 1:
|
| 980 |
+
out.append(mem[rout] & 0xFF)
|
| 981 |
+
mem[rout] = 0
|
| 982 |
+
if mem[rd] == 1:
|
| 983 |
+
if h < len(tau):
|
| 984 |
+
v = tau[h]
|
| 985 |
+
mem[rin] = v if v < 128 else v + S - 256
|
| 986 |
+
mem[eot] = 0
|
| 987 |
+
h += 1
|
| 988 |
+
else:
|
| 989 |
+
mem[eot] = 1
|
| 990 |
+
if mem[rw] == 1:
|
| 991 |
+
h = 0
|
| 992 |
+
mem[wr] = mem[rd] = mem[rw] = 0
|
| 993 |
+
steps += 1
|
| 994 |
+
return bytes(out), steps
|
| 995 |
+
|
| 996 |
# =============================================================================
|
| 997 |
# The host netlist and its canonical serialization
|
| 998 |
# =============================================================================
|
src/paper.py
CHANGED
|
@@ -1048,28 +1048,33 @@ ROCQ = os.path.join(REPO, 'rocq')
|
|
| 1048 |
RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_rocq.json')
|
| 1049 |
|
| 1050 |
|
| 1051 |
-
def host_extraction():
|
| 1052 |
-
"""The host
|
|
|
|
| 1053 |
ex = os.path.join(ROCQ, 'extract')
|
| 1054 |
subprocess.run(['ocamlfind', 'ocamlopt', '-package', 'stdlib', 'hostnet.mli', 'hostnet.ml', 'dumphost.ml',
|
| 1055 |
'-o', 'dumphost'], cwd=ex, check=True)
|
| 1056 |
out = os.path.join(ex, 'host_rocq.bin')
|
| 1057 |
-
|
| 1058 |
-
|
| 1059 |
-
|
| 1060 |
-
|
| 1061 |
-
|
| 1062 |
-
|
| 1063 |
-
|
| 1064 |
-
|
| 1065 |
-
|
| 1066 |
-
words.
|
| 1067 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
for f in os.listdir(ex):
|
| 1069 |
if not f.endswith(('.ml', '.mli')):
|
| 1070 |
os.remove(os.path.join(ex, f))
|
| 1071 |
-
return dict(
|
| 1072 |
-
sha256_sigma=hashlib.sha256(ours).hexdigest(), sha256_rocq=hashlib.sha256(theirs).hexdigest())
|
| 1073 |
|
| 1074 |
|
| 1075 |
def main_rocq():
|
|
|
|
| 1048 |
RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_rocq.json')
|
| 1049 |
|
| 1050 |
|
| 1051 |
+
def host_extraction(widths=(8, 9, 10)):
|
| 1052 |
+
"""The host family of rocq/Host.v, extracted to OCaml, against sigma(N_host) and the generator's H_A."""
|
| 1053 |
+
from host import sigma as sigma_family
|
| 1054 |
ex = os.path.join(ROCQ, 'extract')
|
| 1055 |
subprocess.run(['ocamlfind', 'ocamlopt', '-package', 'stdlib', 'hostnet.mli', 'hostnet.ml', 'dumphost.ml',
|
| 1056 |
'-o', 'dumphost'], cwd=ex, check=True)
|
| 1057 |
out = os.path.join(ex, 'host_rocq.bin')
|
| 1058 |
+
members = []
|
| 1059 |
+
for A in widths:
|
| 1060 |
+
subprocess.run([os.path.join(ex, 'dumphost'), str(A), out], check=True)
|
| 1061 |
+
theirs = open(out, 'rb').read()
|
| 1062 |
+
n, units, nxt = parse_sigma(read_host() if A == 8 else sigma_family(A))
|
| 1063 |
+
words = array('i', [n, len(units), sum(len(ins) for _, ins in units)])
|
| 1064 |
+
words.extend(b for b, _ in units)
|
| 1065 |
+
words.extend(len(ins) for _, ins in units)
|
| 1066 |
+
words.extend(w * (k + 1) for _, ins in units for k, w in ins)
|
| 1067 |
+
words.extend(nxt)
|
| 1068 |
+
if sys.byteorder != 'little':
|
| 1069 |
+
words.byteswap()
|
| 1070 |
+
ours = words.tobytes()
|
| 1071 |
+
members.append(dict(A=A, units=len(units), identical=ours == theirs,
|
| 1072 |
+
sha256_generator=hashlib.sha256(ours).hexdigest(),
|
| 1073 |
+
sha256_rocq=hashlib.sha256(theirs).hexdigest()))
|
| 1074 |
for f in os.listdir(ex):
|
| 1075 |
if not f.endswith(('.ml', '.mli')):
|
| 1076 |
os.remove(os.path.join(ex, f))
|
| 1077 |
+
return dict(members=members, identical=all(m['identical'] for m in members))
|
|
|
|
| 1078 |
|
| 1079 |
|
| 1080 |
def main_rocq():
|
src/twohead.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
"""The two-head machine: the organism, the netlist N_{G,L}, and the host stored in it."""
|
| 2 |
import argparse
|
| 3 |
import hashlib
|
|
|
|
| 4 |
import json
|
| 5 |
import os
|
| 6 |
import random
|
|
@@ -661,21 +662,15 @@ def main_net():
|
|
| 661 |
|
| 662 |
STORED_RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_stored_host.json')
|
| 663 |
|
| 664 |
-
|
| 665 |
-
|
| 666 |
-
SH_W = 1 << SH_ALPHA
|
| 667 |
-
|
| 668 |
-
SH_B = 8 + 3 * SH_ALPHA
|
| 669 |
-
|
| 670 |
-
CW = 20 # width of the device's byte counters
|
| 671 |
|
| 672 |
|
| 673 |
# ---------------------------------------------------------------------------
|
| 674 |
# the host netlist from its serialization
|
| 675 |
# ---------------------------------------------------------------------------
|
| 676 |
|
| 677 |
-
def host_units():
|
| 678 |
-
data = SR.read_host()
|
| 679 |
hlen = struct.unpack('<Q', data[:8])[0]
|
| 680 |
head = json.loads(data[8:8 + hlen])
|
| 681 |
T = {}
|
|
@@ -695,16 +690,16 @@ def host_units():
|
|
| 695 |
return len(nxt), units, nxt
|
| 696 |
|
| 697 |
|
| 698 |
-
# state layout of sigma:
|
| 699 |
-
# k = 0 the most significant
|
| 700 |
-
def mem_bit(j, t):
|
| 701 |
-
"""State index of bit t (value 2^t) of memory
|
| 702 |
-
return
|
| 703 |
|
| 704 |
|
| 705 |
-
|
| 706 |
-
|
| 707 |
-
|
| 708 |
|
| 709 |
|
| 710 |
# ---------------------------------------------------------------------------
|
|
@@ -795,9 +790,9 @@ class Prog:
|
|
| 795 |
self.OR((a, True), (c, True), dst)
|
| 796 |
|
| 797 |
|
| 798 |
-
def compile_host(P):
|
| 799 |
-
"""The records of one step of
|
| 800 |
-
n, units, nxt = host_units()
|
| 801 |
cons = {}
|
| 802 |
for u, (_, ins) in enumerate(units):
|
| 803 |
for s, _w in ins:
|
|
@@ -856,8 +851,8 @@ def compile_host(P):
|
|
| 856 |
_chain_lazy(P, 'and' if t == k else 'or', lits, dst, before)
|
| 857 |
P.ends[len(P.recs) - 1] = u
|
| 858 |
|
| 859 |
-
order_next = [nxt[
|
| 860 |
-
[nxt[mem_bit(j, t)] - n for j in range(
|
| 861 |
for u in order_next: # stage A: everything the next values read
|
| 862 |
ensure_ancestors(u)
|
| 863 |
for u in order_next: # stage B: the next values, in place
|
|
@@ -888,27 +883,30 @@ def _chain_lazy(P, kind, lits, dst, before):
|
|
| 888 |
# the device, the startup block and the hand-over
|
| 889 |
# ---------------------------------------------------------------------------
|
| 890 |
|
| 891 |
-
def mem_cell(j, t):
|
| 892 |
-
return ('s', mem_bit(j, t))
|
| 893 |
|
| 894 |
|
| 895 |
-
def
|
| 896 |
-
"""[memory
|
| 897 |
dst = P.tmp()
|
| 898 |
-
lits = [(mem_cell(j, 0), True)] + [(mem_cell(j, t), False) for t in range(1,
|
| 899 |
P.chain('and', lits, dst)
|
| 900 |
return dst
|
| 901 |
|
| 902 |
|
| 903 |
-
def compile_device(P):
|
| 904 |
-
|
| 905 |
-
|
|
|
|
| 906 |
dest = ('d', 'dest')
|
| 907 |
-
wr
|
|
|
|
|
|
|
| 908 |
# [cnt == lim]
|
| 909 |
eq = P.tmp()
|
| 910 |
xs = []
|
| 911 |
-
for i in range(
|
| 912 |
e = P.tmp()
|
| 913 |
a1, a0 = P.tmp(), P.tmp()
|
| 914 |
P.AND((cnt[i], True), (lim[i], True), a1)
|
|
@@ -918,69 +916,73 @@ def compile_device(P):
|
|
| 918 |
P.chain('and', xs, eq)
|
| 919 |
eot = P.tmp() # the end of the tape is known after the rewind
|
| 920 |
P.AND((eq, True), (dest, True), eot)
|
| 921 |
-
# (i) R_out, most significant bit first, under the arm or under the copy head
|
| 922 |
ca, cc = P.tmp(), P.tmp()
|
| 923 |
P.AND((wr, True), (dest, False), ca)
|
| 924 |
P.AND((wr, True), (dest, True), cc)
|
|
|
|
| 925 |
for t in range(7, -1, -1):
|
| 926 |
-
P.MUX(ca, (mem_cell(
|
| 927 |
P.COPY((ca, True), ('c', AA))
|
| 928 |
-
P.MUX(cc, (mem_cell(
|
| 929 |
P.COPY((cc, True), ('c', AC))
|
| 930 |
-
for t in range(
|
| 931 |
-
P.AND((mem_cell(
|
| 932 |
g = P.tmp()
|
| 933 |
P.AND((rd, True), (eot, False), g)
|
| 934 |
-
# (ii) the byte under the read head into R_in, most significant bit first, each bit turning the tape
|
|
|
|
| 935 |
for t in range(7, -1, -1):
|
| 936 |
-
P.MUX(g, (('c', RD), True), (mem_cell(
|
| 937 |
P.COPY((g, True), ('c', AR))
|
|
|
|
|
|
|
| 938 |
# c_eot: bit 0 <- [cnt == lim] on a read, the other bits cleared on a read
|
| 939 |
-
P.MUX(rd, (eot, True), (mem_cell(
|
| 940 |
-
for t in range(1,
|
| 941 |
-
P.AND((mem_cell(
|
| 942 |
# the counter of bytes read: carries first, then the sum bits
|
| 943 |
car = [g]
|
| 944 |
-
for i in range(
|
| 945 |
c = P.tmp()
|
| 946 |
P.AND((car[-1], True), (cnt[i], True), c)
|
| 947 |
car.append(c)
|
| 948 |
-
for i in range(
|
| 949 |
P.XOR((cnt[i], True), (car[i], True), cnt[i])
|
| 950 |
# (iii) a rewind: the limit takes the count, the count returns to 0, the writes go to the copy tape
|
| 951 |
-
for i in range(
|
| 952 |
P.MUX(rw, (cnt[i], True), (lim[i], True), lim[i])
|
| 953 |
P.AND((cnt[i], True), (rw, False), cnt[i])
|
| 954 |
P.OR((dest, True), (rw, True), dest)
|
| 955 |
# (iv) the request cells cleared
|
| 956 |
-
for
|
| 957 |
-
for t in range(
|
| 958 |
-
P.CONST(0, mem_cell(
|
| 959 |
|
| 960 |
|
| 961 |
-
def compile_startup(P, mem_image):
|
| 962 |
-
"""The startup records: while booted is 0, load
|
| 963 |
b = ('d', 'booted')
|
| 964 |
-
for j in range(
|
| 965 |
-
for t in range(
|
| 966 |
-
c = mem_cell(j, t)
|
| 967 |
if (mem_image[j] >> t) & 1:
|
| 968 |
P.OR((c, True), (b, False), c) # b ? c : 1
|
| 969 |
else:
|
| 970 |
P.AND((c, True), (b, True), c) # b ? c : 0
|
| 971 |
-
for t in range(
|
| 972 |
-
P.AND((('s',
|
| 973 |
-
P.AND((('s',
|
| 974 |
-
for i in range(
|
| 975 |
P.AND((('d', 'cnt', i), True), (b, True), ('d', 'cnt', i))
|
| 976 |
P.AND((('d', 'lim', i), True), (b, True), ('d', 'lim', i))
|
| 977 |
P.AND((('d', 'dest'), True), (b, True), ('d', 'dest'))
|
| 978 |
P.CONST(1, b)
|
| 979 |
|
| 980 |
|
| 981 |
-
def compile_handover(P):
|
| 982 |
"""The hand-over records: at the halt, clear booted and flip the bank bit at the end of the pass."""
|
| 983 |
-
h = ('s',
|
| 984 |
P.AND((('d', 'booted'), True), (h, False), ('d', 'booted'))
|
| 985 |
P.XOR((('c', KAPPA), True), (h, True), ('c', KAPPA))
|
| 986 |
|
|
@@ -1011,16 +1013,18 @@ def allocate(recs):
|
|
| 1011 |
if ao[0] == 't':
|
| 1012 |
first_w.setdefault(ao, i)
|
| 1013 |
base = nxt_addr
|
| 1014 |
-
|
| 1015 |
addr = dict(fixed)
|
| 1016 |
for name in sorted(first_w, key=lambda x: first_w[x]):
|
| 1017 |
start, end = first_w[name], last_r.get(name, first_w[name])
|
| 1018 |
-
|
| 1019 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1020 |
addr[name] = c
|
| 1021 |
-
|
| 1022 |
-
top = base + len(free_at)
|
| 1023 |
-
assert top <= SH_W, ('window too small', top)
|
| 1024 |
|
| 1025 |
def res(a):
|
| 1026 |
if a is None:
|
|
@@ -1067,24 +1071,34 @@ def check_schedule(recs, lo, hi, n):
|
|
| 1067 |
return dict(state_bits_written=len(written))
|
| 1068 |
|
| 1069 |
|
| 1070 |
-
def build_stored():
|
| 1071 |
-
|
| 1072 |
-
|
| 1073 |
-
|
| 1074 |
-
|
| 1075 |
-
|
| 1076 |
-
|
| 1077 |
-
|
| 1078 |
-
|
| 1079 |
-
|
| 1080 |
-
|
| 1081 |
-
|
| 1082 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1083 |
image = bits_to_bytes(image_bits)
|
| 1084 |
tau = SR.describe(image)
|
| 1085 |
assert SR.decode(tau) == image
|
| 1086 |
-
return dict(recs=recs, addr=addr, top=top, image=image, image_bits=image_bits,
|
| 1087 |
-
|
|
|
|
| 1088 |
|
| 1089 |
|
| 1090 |
# ---------------------------------------------------------------------------
|
|
@@ -1093,12 +1107,13 @@ def build_stored():
|
|
| 1093 |
|
| 1094 |
class HeadMachine:
|
| 1095 |
"""T_{G,L} with a window of W cells; banks and tapes listed from their heads."""
|
| 1096 |
-
def __init__(self, Q0, Q1, D0, D1, window):
|
| 1097 |
self.Q = [list(Q0), list(Q1)]
|
| 1098 |
self.D = [list(D0), list(D1)]
|
| 1099 |
self.h = [[0, 0], [0, 0]] # heads of the banks and of the tapes
|
| 1100 |
self.w = list(window)
|
| 1101 |
self.N, self.L = len(Q0), len(D0)
|
|
|
|
| 1102 |
|
| 1103 |
def cell(self, a):
|
| 1104 |
k = self.w[KAPPA]
|
|
@@ -1114,7 +1129,7 @@ class HeadMachine:
|
|
| 1114 |
k = self.w[KAPPA]
|
| 1115 |
if rec is None:
|
| 1116 |
hq = self.h[0][k]
|
| 1117 |
-
rec = decode_record([self.Q[k][(hq + i) % self.N] for i in range(
|
| 1118 |
a0, w0, a1, w1, beta, ao = rec
|
| 1119 |
v = 1 if w0 * self.cell(a0) + w1 * self.cell(a1) + beta >= 0 else 0
|
| 1120 |
if ao == ARM:
|
|
@@ -1123,7 +1138,7 @@ class HeadMachine:
|
|
| 1123 |
self.D[1 - k][self.h[1][1 - k]] = v
|
| 1124 |
elif ao != RD:
|
| 1125 |
self.w[ao] = v
|
| 1126 |
-
self.h[0][k] = (self.h[0][k] +
|
| 1127 |
if self.w[AA]:
|
| 1128 |
self.h[0][1 - k] = (self.h[0][1 - k] + 1) % self.N
|
| 1129 |
if self.w[AR]:
|
|
@@ -1144,36 +1159,38 @@ def host_step(n, units, nxt, x):
|
|
| 1144 |
return [sig[v] for v in nxt]
|
| 1145 |
|
| 1146 |
|
| 1147 |
-
def check_stored(trials=40, seed=3, verbose=False):
|
| 1148 |
-
S = build_stored()
|
| 1149 |
-
recs, addr = S['recs'], S['addr']
|
| 1150 |
n, units, nxt = S['host']
|
|
|
|
| 1151 |
G = len(recs)
|
| 1152 |
rng = random.Random(seed)
|
| 1153 |
bad = 0
|
| 1154 |
-
image_bits = [
|
|
|
|
| 1155 |
x0 = [0] * n # the state x_0(m*)
|
| 1156 |
-
for j in range(
|
| 1157 |
-
for t in range(
|
| 1158 |
-
x0[mem_bit(j, t)] = (
|
| 1159 |
for trial in range(trials):
|
| 1160 |
# a random host state with random device registers, temporaries and tapes; every fifth
|
| 1161 |
-
# state not yet booted, and in every third the requests hold random
|
| 1162 |
x = [rng.randrange(2) for _ in range(n)]
|
| 1163 |
-
x[
|
| 1164 |
booted = 0 if trial % 5 == 0 else 1
|
| 1165 |
-
for
|
| 1166 |
-
v = rng.randrange(
|
| 1167 |
-
for t in range(
|
| 1168 |
-
x[mem_bit(
|
| 1169 |
L = 64
|
| 1170 |
cnt, lim = rng.randrange(8), rng.randrange(8)
|
| 1171 |
dest = rng.randrange(2)
|
| 1172 |
-
win = [rng.randrange(2) for _ in range(
|
| 1173 |
win[KAPPA] = 0
|
| 1174 |
for i in range(n):
|
| 1175 |
win[addr[('s', i)]] = x[i]
|
| 1176 |
-
for i in range(
|
| 1177 |
win[addr[('d', 'cnt', i)]] = (cnt >> i) & 1
|
| 1178 |
win[addr[('d', 'lim', i)]] = (lim >> i) & 1
|
| 1179 |
win[addr[('d', 'dest')]] = dest
|
|
@@ -1182,55 +1199,57 @@ def check_stored(trials=40, seed=3, verbose=False):
|
|
| 1182 |
D0 = [rng.randrange(2) for _ in range(L)]
|
| 1183 |
Q1 = [rng.randrange(2) for _ in range(len(image_bits))]
|
| 1184 |
D1 = [rng.randrange(2) for _ in range(L)]
|
| 1185 |
-
M = HeadMachine(image_bits, Q1, D0, D1, win)
|
| 1186 |
for g in range(G):
|
| 1187 |
M.step(recs[g])
|
| 1188 |
-
# expected: the startup if not booted, one step of
|
| 1189 |
if not booted:
|
| 1190 |
x, cnt, lim, dest = list(x0), 0, 0, 0
|
| 1191 |
y = host_step(n, units, nxt, x)
|
| 1192 |
-
get = lambda j: sum(y[mem_bit(j, t)] << t for t in range(
|
| 1193 |
|
| 1194 |
def put(j, v):
|
| 1195 |
-
for t in range(
|
| 1196 |
-
y[mem_bit(j, t)] = (v >> t) & 1
|
| 1197 |
e_q1, e_d1, hq1, hd0, hd1 = list(Q1), list(D1), 0, 0, 0
|
| 1198 |
e_cnt, e_lim, e_dest = cnt, lim, dest
|
| 1199 |
-
if get(
|
| 1200 |
-
byte = get(
|
| 1201 |
for kk in range(8):
|
| 1202 |
bit = (byte >> (7 - kk)) & 1
|
| 1203 |
if e_dest:
|
| 1204 |
e_d1[hd1] = bit; hd1 += 1
|
| 1205 |
else:
|
| 1206 |
e_q1[hq1] = bit; hq1 += 1
|
| 1207 |
-
put(
|
| 1208 |
-
if get(
|
| 1209 |
if not (e_dest and e_cnt == e_lim):
|
| 1210 |
-
|
|
|
|
| 1211 |
hd0 += 8
|
| 1212 |
-
put(
|
| 1213 |
-
e_cnt = (e_cnt + 1) % (1 <<
|
| 1214 |
else:
|
| 1215 |
-
put(
|
| 1216 |
-
if get(
|
| 1217 |
e_lim, e_cnt, e_dest = e_cnt, 0, 1
|
| 1218 |
-
|
| 1219 |
-
|
|
|
|
| 1220 |
got = [M.w[addr[('s', i)]] for i in range(n)]
|
| 1221 |
-
g_cnt = sum(M.w[addr[('d', 'cnt', i)]] << i for i in range(
|
| 1222 |
-
g_lim = sum(M.w[addr[('d', 'lim', i)]] << i for i in range(
|
| 1223 |
parts = dict(state=got == y, cnt=g_cnt == e_cnt, lim=g_lim == e_lim,
|
| 1224 |
dest=M.w[addr[('d', 'dest')]] == e_dest, bank=M.Q[1] == e_q1, copy=M.D[1] == e_d1,
|
| 1225 |
arm=M.h[0][1] == hq1, read=M.h[1][0] == hd0, copyhead=M.h[1][1] == hd1,
|
| 1226 |
kappa=M.w[KAPPA] == e_kappa, tape=M.D[0] == D0,
|
| 1227 |
-
booted=M.w[addr[('d', 'booted')]] == 1 - y[
|
| 1228 |
requests=M.w[AR] == M.w[AA] == M.w[AC] == 0, active=M.Q[0] == image_bits)
|
| 1229 |
ok = all(parts.values())
|
| 1230 |
if not ok and verbose:
|
| 1231 |
print(trial, [k for k, v in parts.items() if not v], 'reqs',
|
| 1232 |
-
[get(
|
| 1233 |
-
'halt', x[
|
| 1234 |
bad += not ok
|
| 1235 |
return dict(trials=trials, disagreements=bad, records=G, window_cells=S['top'])
|
| 1236 |
|
|
@@ -1285,34 +1304,39 @@ class BDD:
|
|
| 1285 |
return row[t]
|
| 1286 |
|
| 1287 |
|
| 1288 |
-
def symbolic_check():
|
| 1289 |
-
"""The startup and step records of the image of
|
| 1290 |
sys.setrecursionlimit(100000)
|
| 1291 |
t0 = time.time()
|
| 1292 |
-
S = build_stored()
|
| 1293 |
-
n, units, nxt = host_units()
|
|
|
|
| 1294 |
bits = bytes_to_bits(S['image'])
|
| 1295 |
-
recs = [decode_record(bits[k *
|
| 1296 |
-
lo
|
|
|
|
| 1297 |
addr = S['addr']
|
| 1298 |
D = BDD()
|
| 1299 |
# the value of every signal on the current state: a unit that is a constant or a literal is that,
|
| 1300 |
# and the units of one function share the variable of the first; fn[u] is the function of unit u
|
| 1301 |
-
# of the values of its predecessors
|
| 1302 |
-
|
| 1303 |
-
|
| 1304 |
-
|
|
|
|
|
|
|
|
|
|
| 1305 |
fn.append(f)
|
| 1306 |
-
val.append(
|
| 1307 |
unknown = lambda c: D.var(1 << 30 | c)
|
| 1308 |
state = [addr[('s', i)] for i in range(n)]
|
| 1309 |
ends = S['ends']
|
| 1310 |
agree = [True]
|
| 1311 |
|
| 1312 |
-
def run(window, a,
|
| 1313 |
# at the record that the compiler names as writing the value of unit u, the cell must hold
|
| 1314 |
# the function of u, and from then on it holds the value of u
|
| 1315 |
-
for k in range(a,
|
| 1316 |
a0, w0, a1, w1, beta, ao = recs[k]
|
| 1317 |
assert ao >= 7, ('a record writes a head or a request', k)
|
| 1318 |
g = D.record(w0, window[a0], w1, window[a1], beta)
|
|
@@ -1324,25 +1348,26 @@ def symbolic_check():
|
|
| 1324 |
|
| 1325 |
# the startup: x_0(m*) when booted is 0, the window unchanged when it is 1
|
| 1326 |
boot = addr[('d', 'booted')]
|
| 1327 |
-
window = [unknown(c) for c in range(
|
| 1328 |
-
regs = [addr[('d', 'cnt', i)] for i in range(
|
| 1329 |
[addr[('d', 'dest')]]
|
| 1330 |
before = list(window)
|
| 1331 |
run(window, 0, lo)
|
| 1332 |
B0 = before[boot]
|
|
|
|
| 1333 |
x0 = [0] * n
|
| 1334 |
-
for j in range(
|
| 1335 |
-
for t in range(
|
| 1336 |
-
x0[mem_bit(j, t)] = (
|
| 1337 |
startup = window[boot] == 1 and all(window[c] == D.ite(B0, before[c], 0) for c in regs) and \
|
| 1338 |
all(window[state[i]] == D.ite(B0, before[state[i]], x0[i]) for i in range(n))
|
| 1339 |
-
# the step: from every window, the state bits end holding the next state of
|
| 1340 |
-
window = [unknown(c) for c in range(
|
| 1341 |
for i in range(n):
|
| 1342 |
window[state[i]] = val[i]
|
| 1343 |
run(window, lo, hi)
|
| 1344 |
step = agree[0] and len(ends) == len(units) and all(window[state[i]] == val[nxt[i]] for i in range(n))
|
| 1345 |
-
return dict(startup_records=lo, step_records=hi - lo, startup_exact=startup, step_exact=step,
|
| 1346 |
sha256_image=hashlib.sha256(S['image']).hexdigest(), nodes=len(D.node),
|
| 1347 |
seconds=round(time.time() - t0, 1))
|
| 1348 |
|
|
@@ -1353,27 +1378,49 @@ def stored_update_record(key, value):
|
|
| 1353 |
json.dump(rec, open(STORED_RECORD, 'w'), indent=1)
|
| 1354 |
|
| 1355 |
|
| 1356 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1357 |
"""Generations of the stored host on the machine in C, against the reference run of P*."""
|
| 1358 |
-
S = build_stored()
|
| 1359 |
-
recs, image_bits, tau = S['recs'], S['image_bits'], S['tau']
|
| 1360 |
G = len(recs)
|
| 1361 |
-
out, steps = SR.
|
| 1362 |
-
assert out == S['image'] + tau
|
| 1363 |
tau_bits = bytes_to_bits(tau)
|
| 1364 |
work = os.path.join(REPO, 'variants')
|
| 1365 |
-
inp, exe = os.path.join(work, '.
|
| 1366 |
with open(inp, 'wb') as f:
|
| 1367 |
-
f.write(struct.pack('<4i',
|
| 1368 |
-
f.write(bytes(image_bits) + bytes(tau_bits) + bytes(
|
| 1369 |
subprocess.run(['gcc', '-O3', '-march=native', '-o', exe, os.path.join(REPO, 'src', 'stored_host_run.c')], check=True)
|
| 1370 |
t0 = time.time()
|
| 1371 |
p = subprocess.run([exe, inp, str(generations)], capture_output=True, text=True)
|
| 1372 |
os.remove(inp); os.remove(exe)
|
| 1373 |
lines = [json.loads(l) for l in p.stdout.split('\n') if l.strip()]
|
| 1374 |
gens = [l for l in lines if 'generation' in l]
|
| 1375 |
-
res = dict(records=G, window_cells=S['top'], record_bits=
|
| 1376 |
-
image_bytes=len(S['image']), tau_bytes=len(tau), passes_expected=steps,
|
| 1377 |
generations=gens, seconds=round(time.time() - t0, 1),
|
| 1378 |
sha256_image=hashlib.sha256(S['image']).hexdigest(),
|
| 1379 |
sha256_tau=hashlib.sha256(tau).hexdigest())
|
|
@@ -1382,36 +1429,65 @@ def run_stored(generations):
|
|
| 1382 |
res['state_after_3_equals_after_1'] = l['state_after_3_equals_after_1']
|
| 1383 |
res['every_generation_exact'] = all(g['passes'] == steps and g['steps'] == steps * G and g['bank_holds_image']
|
| 1384 |
and g['tape_holds_tau'] for g in gens) and len(gens) == generations
|
| 1385 |
-
stored_update_record('run', res)
|
| 1386 |
return res
|
| 1387 |
|
| 1388 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1389 |
def cmd_stored():
|
| 1390 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1391 |
if cmd == 'check':
|
| 1392 |
t0 = time.time()
|
| 1393 |
-
res = check_stored(int(
|
| 1394 |
res['seconds'] = round(time.time() - t0, 1)
|
| 1395 |
-
stored_update_record('pass_check', res)
|
| 1396 |
print(json.dumps(res))
|
| 1397 |
sys.exit(0 if res['disagreements'] == 0 else 1)
|
| 1398 |
elif cmd == 'symbolic':
|
| 1399 |
-
res = symbolic_check()
|
| 1400 |
-
stored_update_record('symbolic', res)
|
| 1401 |
print(json.dumps(res))
|
| 1402 |
sys.exit(0 if res['startup_exact'] and res['step_exact'] else 1)
|
| 1403 |
elif cmd == 'run':
|
| 1404 |
-
gens = int(
|
| 1405 |
-
res = run_stored(gens)
|
| 1406 |
print(json.dumps(res, indent=1))
|
| 1407 |
sys.exit(0 if res['every_generation_exact'] and (gens < 3 or res.get('state_after_3_equals_after_1') == 1)
|
| 1408 |
else 1)
|
|
|
|
|
|
|
| 1409 |
elif cmd == 'build':
|
| 1410 |
t0 = time.time()
|
| 1411 |
-
S = build_stored()
|
| 1412 |
-
print(json.dumps(dict(records=len(S['recs']), host_records=S['n_host_records'],
|
| 1413 |
-
window_cells=S['top'], record_bits=
|
| 1414 |
-
image_bytes=len(S['image']), tau_bytes=len(S['tau']),
|
|
|
|
| 1415 |
seconds=round(time.time() - t0, 1))))
|
| 1416 |
|
| 1417 |
|
|
|
|
| 1 |
"""The two-head machine: the organism, the netlist N_{G,L}, and the host stored in it."""
|
| 2 |
import argparse
|
| 3 |
import hashlib
|
| 4 |
+
import heapq
|
| 5 |
import json
|
| 6 |
import os
|
| 7 |
import random
|
|
|
|
| 662 |
|
| 663 |
STORED_RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_stored_host.json')
|
| 664 |
|
| 665 |
+
CW = 20 # the least width of the device's byte counters
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 666 |
|
| 667 |
|
| 668 |
# ---------------------------------------------------------------------------
|
| 669 |
# the host netlist from its serialization
|
| 670 |
# ---------------------------------------------------------------------------
|
| 671 |
|
| 672 |
+
def host_units(A=8):
|
| 673 |
+
data = SR.read_host() if A == 8 else SR.sigma(A)
|
| 674 |
hlen = struct.unpack('<Q', data[:8])[0]
|
| 675 |
head = json.loads(data[8:8 + hlen])
|
| 676 |
T = {}
|
|
|
|
| 690 |
return len(nxt), units, nxt
|
| 691 |
|
| 692 |
|
| 693 |
+
# state layout of sigma: the A counter bits most significant first, the halt bit at A, and bit k of
|
| 694 |
+
# word j at A + 1 + A j + k, k = 0 the most significant
|
| 695 |
+
def mem_bit(j, t, A=8):
|
| 696 |
+
"""State index of bit t (value 2^t) of memory word j."""
|
| 697 |
+
return A + 1 + A * j + (A - 1 - t)
|
| 698 |
|
| 699 |
|
| 700 |
+
def pc_bit(t, A=8):
|
| 701 |
+
"""State index of bit t of the counter."""
|
| 702 |
+
return A - 1 - t
|
| 703 |
|
| 704 |
|
| 705 |
# ---------------------------------------------------------------------------
|
|
|
|
| 790 |
self.OR((a, True), (c, True), dst)
|
| 791 |
|
| 792 |
|
| 793 |
+
def compile_host(P, A=8):
|
| 794 |
+
"""The records of one step of H_A; state bits are cells ('s', i)."""
|
| 795 |
+
n, units, nxt = host_units(A)
|
| 796 |
cons = {}
|
| 797 |
for u, (_, ins) in enumerate(units):
|
| 798 |
for s, _w in ins:
|
|
|
|
| 851 |
_chain_lazy(P, 'and' if t == k else 'or', lits, dst, before)
|
| 852 |
P.ends[len(P.recs) - 1] = u
|
| 853 |
|
| 854 |
+
order_next = [nxt[pc_bit(t, A)] - n for t in range(A)] + [nxt[A] - n] + \
|
| 855 |
+
[nxt[mem_bit(j, t, A)] - n for j in range(1 << A) for t in range(A)]
|
| 856 |
for u in order_next: # stage A: everything the next values read
|
| 857 |
ensure_ancestors(u)
|
| 858 |
for u in order_next: # stage B: the next values, in place
|
|
|
|
| 883 |
# the device, the startup block and the hand-over
|
| 884 |
# ---------------------------------------------------------------------------
|
| 885 |
|
| 886 |
+
def mem_cell(j, t, A=8):
|
| 887 |
+
return ('s', mem_bit(j, t, A))
|
| 888 |
|
| 889 |
|
| 890 |
+
def word_is_one(P, j, A=8):
|
| 891 |
+
"""[memory word j == 1]"""
|
| 892 |
dst = P.tmp()
|
| 893 |
+
lits = [(mem_cell(j, 0, A), True)] + [(mem_cell(j, t, A), False) for t in range(1, A)]
|
| 894 |
P.chain('and', lits, dst)
|
| 895 |
return dst
|
| 896 |
|
| 897 |
|
| 898 |
+
def compile_device(P, A=8, w=CW):
|
| 899 |
+
io = SR.io_cells(A)
|
| 900 |
+
cnt = [('d', 'cnt', i) for i in range(w)]
|
| 901 |
+
lim = [('d', 'lim', i) for i in range(w)]
|
| 902 |
dest = ('d', 'dest')
|
| 903 |
+
wr = word_is_one(P, io['c_wr'], A)
|
| 904 |
+
rd = word_is_one(P, io['c_rd'], A)
|
| 905 |
+
rw = word_is_one(P, io['c_rw'], A)
|
| 906 |
# [cnt == lim]
|
| 907 |
eq = P.tmp()
|
| 908 |
xs = []
|
| 909 |
+
for i in range(w):
|
| 910 |
e = P.tmp()
|
| 911 |
a1, a0 = P.tmp(), P.tmp()
|
| 912 |
P.AND((cnt[i], True), (lim[i], True), a1)
|
|
|
|
| 916 |
P.chain('and', xs, eq)
|
| 917 |
eot = P.tmp() # the end of the tape is known after the rewind
|
| 918 |
P.AND((eq, True), (dest, True), eot)
|
| 919 |
+
# (i) the low byte of R_out, most significant bit first, under the arm or under the copy head
|
| 920 |
ca, cc = P.tmp(), P.tmp()
|
| 921 |
P.AND((wr, True), (dest, False), ca)
|
| 922 |
P.AND((wr, True), (dest, True), cc)
|
| 923 |
+
out, inp, ceot = io['r_out'], io['r_in'], io['c_eot']
|
| 924 |
for t in range(7, -1, -1):
|
| 925 |
+
P.MUX(ca, (mem_cell(out, t, A), True), (('c', ARM), True), ('c', ARM))
|
| 926 |
P.COPY((ca, True), ('c', AA))
|
| 927 |
+
P.MUX(cc, (mem_cell(out, t, A), True), (('c', CPY), True), ('c', CPY))
|
| 928 |
P.COPY((cc, True), ('c', AC))
|
| 929 |
+
for t in range(A):
|
| 930 |
+
P.AND((mem_cell(out, t, A), True), (wr, False), mem_cell(out, t, A))
|
| 931 |
g = P.tmp()
|
| 932 |
P.AND((rd, True), (eot, False), g)
|
| 933 |
+
# (ii) the byte under the read head into R_in, most significant bit first, each bit turning the tape,
|
| 934 |
+
# and its sign bit into the bits above it
|
| 935 |
for t in range(7, -1, -1):
|
| 936 |
+
P.MUX(g, (('c', RD), True), (mem_cell(inp, t, A), True), mem_cell(inp, t, A))
|
| 937 |
P.COPY((g, True), ('c', AR))
|
| 938 |
+
for t in range(8, A):
|
| 939 |
+
P.MUX(g, (mem_cell(inp, 7, A), True), (mem_cell(inp, t, A), True), mem_cell(inp, t, A))
|
| 940 |
# c_eot: bit 0 <- [cnt == lim] on a read, the other bits cleared on a read
|
| 941 |
+
P.MUX(rd, (eot, True), (mem_cell(ceot, 0, A), True), mem_cell(ceot, 0, A))
|
| 942 |
+
for t in range(1, A):
|
| 943 |
+
P.AND((mem_cell(ceot, t, A), True), (rd, False), mem_cell(ceot, t, A))
|
| 944 |
# the counter of bytes read: carries first, then the sum bits
|
| 945 |
car = [g]
|
| 946 |
+
for i in range(w - 1):
|
| 947 |
c = P.tmp()
|
| 948 |
P.AND((car[-1], True), (cnt[i], True), c)
|
| 949 |
car.append(c)
|
| 950 |
+
for i in range(w):
|
| 951 |
P.XOR((cnt[i], True), (car[i], True), cnt[i])
|
| 952 |
# (iii) a rewind: the limit takes the count, the count returns to 0, the writes go to the copy tape
|
| 953 |
+
for i in range(w):
|
| 954 |
P.MUX(rw, (cnt[i], True), (lim[i], True), lim[i])
|
| 955 |
P.AND((cnt[i], True), (rw, False), cnt[i])
|
| 956 |
P.OR((dest, True), (rw, True), dest)
|
| 957 |
# (iv) the request cells cleared
|
| 958 |
+
for c in ('c_wr', 'c_rd', 'c_rw'):
|
| 959 |
+
for t in range(A):
|
| 960 |
+
P.CONST(0, mem_cell(io[c], t, A))
|
| 961 |
|
| 962 |
|
| 963 |
+
def compile_startup(P, mem_image, A=8, w=CW):
|
| 964 |
+
"""The startup records: while booted is 0, load the memory image and clear the counter, halt bit and registers."""
|
| 965 |
b = ('d', 'booted')
|
| 966 |
+
for j in range(1 << A):
|
| 967 |
+
for t in range(A):
|
| 968 |
+
c = mem_cell(j, t, A)
|
| 969 |
if (mem_image[j] >> t) & 1:
|
| 970 |
P.OR((c, True), (b, False), c) # b ? c : 1
|
| 971 |
else:
|
| 972 |
P.AND((c, True), (b, True), c) # b ? c : 0
|
| 973 |
+
for t in range(A):
|
| 974 |
+
P.AND((('s', pc_bit(t, A)), True), (b, True), ('s', pc_bit(t, A)))
|
| 975 |
+
P.AND((('s', A), True), (b, True), ('s', A))
|
| 976 |
+
for i in range(w):
|
| 977 |
P.AND((('d', 'cnt', i), True), (b, True), ('d', 'cnt', i))
|
| 978 |
P.AND((('d', 'lim', i), True), (b, True), ('d', 'lim', i))
|
| 979 |
P.AND((('d', 'dest'), True), (b, True), ('d', 'dest'))
|
| 980 |
P.CONST(1, b)
|
| 981 |
|
| 982 |
|
| 983 |
+
def compile_handover(P, A=8):
|
| 984 |
"""The hand-over records: at the halt, clear booted and flip the bank bit at the end of the pass."""
|
| 985 |
+
h = ('s', A)
|
| 986 |
P.AND((('d', 'booted'), True), (h, False), ('d', 'booted'))
|
| 987 |
P.XOR((('c', KAPPA), True), (h, True), ('c', KAPPA))
|
| 988 |
|
|
|
|
| 1013 |
if ao[0] == 't':
|
| 1014 |
first_w.setdefault(ao, i)
|
| 1015 |
base = nxt_addr
|
| 1016 |
+
busy, free, top = [], [], base # (index after which it is free, cell); free cells
|
| 1017 |
addr = dict(fixed)
|
| 1018 |
for name in sorted(first_w, key=lambda x: first_w[x]):
|
| 1019 |
start, end = first_w[name], last_r.get(name, first_w[name])
|
| 1020 |
+
while busy and busy[0][0] < start:
|
| 1021 |
+
heapq.heappush(free, heapq.heappop(busy)[1])
|
| 1022 |
+
if free:
|
| 1023 |
+
c = heapq.heappop(free)
|
| 1024 |
+
else:
|
| 1025 |
+
c, top = top, top + 1
|
| 1026 |
addr[name] = c
|
| 1027 |
+
heapq.heappush(busy, (end, c))
|
|
|
|
|
|
|
| 1028 |
|
| 1029 |
def res(a):
|
| 1030 |
if a is None:
|
|
|
|
| 1071 |
return dict(state_bits_written=len(written))
|
| 1072 |
|
| 1073 |
|
| 1074 |
+
def build_stored(A=8):
|
| 1075 |
+
"""The stored host of H_A, with the least counters from CW bits on and the least window that hold it."""
|
| 1076 |
+
w = CW
|
| 1077 |
+
while True:
|
| 1078 |
+
P = Prog()
|
| 1079 |
+
compile_startup(P, SR.memory_image_a(SR.P_STAR, A), A, w)
|
| 1080 |
+
lo = len(P.recs)
|
| 1081 |
+
n, units, nxt = compile_host(P, A)
|
| 1082 |
+
n_host = len(P.recs) - lo
|
| 1083 |
+
check_schedule(P.recs, lo, len(P.recs), n)
|
| 1084 |
+
compile_device(P, A, w)
|
| 1085 |
+
n_device = len(P.recs) - lo - n_host
|
| 1086 |
+
compile_handover(P, A)
|
| 1087 |
+
recs, addr, top = allocate(P.recs)
|
| 1088 |
+
alpha = (top - 1).bit_length()
|
| 1089 |
+
b = 8 + 3 * alpha
|
| 1090 |
+
while b * len(recs) % 8: # an image of whole bytes
|
| 1091 |
+
recs.insert(len(recs) - 3, (SINK, 0, SINK, 0, -1, SINK))
|
| 1092 |
+
if 2 * (b * len(recs) // 8) + 1 < 1 << w:
|
| 1093 |
+
break
|
| 1094 |
+
w += 1
|
| 1095 |
+
image_bits = [x for r in recs for x in encode_record(r, alpha)]
|
| 1096 |
image = bits_to_bytes(image_bits)
|
| 1097 |
tau = SR.describe(image)
|
| 1098 |
assert SR.decode(tau) == image
|
| 1099 |
+
return dict(A=A, w=w, alpha=alpha, b=b, recs=recs, addr=addr, top=top, image=image, image_bits=image_bits,
|
| 1100 |
+
tau=tau, startup_records=lo, n_host_records=n_host, device_records=n_device,
|
| 1101 |
+
host=(n, units, nxt), ends=P.ends)
|
| 1102 |
|
| 1103 |
|
| 1104 |
# ---------------------------------------------------------------------------
|
|
|
|
| 1107 |
|
| 1108 |
class HeadMachine:
|
| 1109 |
"""T_{G,L} with a window of W cells; banks and tapes listed from their heads."""
|
| 1110 |
+
def __init__(self, Q0, Q1, D0, D1, window, alpha=12):
|
| 1111 |
self.Q = [list(Q0), list(Q1)]
|
| 1112 |
self.D = [list(D0), list(D1)]
|
| 1113 |
self.h = [[0, 0], [0, 0]] # heads of the banks and of the tapes
|
| 1114 |
self.w = list(window)
|
| 1115 |
self.N, self.L = len(Q0), len(D0)
|
| 1116 |
+
self.alpha, self.b = alpha, 8 + 3 * alpha
|
| 1117 |
|
| 1118 |
def cell(self, a):
|
| 1119 |
k = self.w[KAPPA]
|
|
|
|
| 1129 |
k = self.w[KAPPA]
|
| 1130 |
if rec is None:
|
| 1131 |
hq = self.h[0][k]
|
| 1132 |
+
rec = decode_record([self.Q[k][(hq + i) % self.N] for i in range(self.b)], self.alpha)
|
| 1133 |
a0, w0, a1, w1, beta, ao = rec
|
| 1134 |
v = 1 if w0 * self.cell(a0) + w1 * self.cell(a1) + beta >= 0 else 0
|
| 1135 |
if ao == ARM:
|
|
|
|
| 1138 |
self.D[1 - k][self.h[1][1 - k]] = v
|
| 1139 |
elif ao != RD:
|
| 1140 |
self.w[ao] = v
|
| 1141 |
+
self.h[0][k] = (self.h[0][k] + self.b) % self.N
|
| 1142 |
if self.w[AA]:
|
| 1143 |
self.h[0][1 - k] = (self.h[0][1 - k] + 1) % self.N
|
| 1144 |
if self.w[AR]:
|
|
|
|
| 1159 |
return [sig[v] for v in nxt]
|
| 1160 |
|
| 1161 |
|
| 1162 |
+
def check_stored(trials=40, seed=3, verbose=False, A=8):
|
| 1163 |
+
S = build_stored(A)
|
| 1164 |
+
recs, addr, w, alpha = S['recs'], S['addr'], S['w'], S['alpha']
|
| 1165 |
n, units, nxt = S['host']
|
| 1166 |
+
io = SR.io_cells(A)
|
| 1167 |
G = len(recs)
|
| 1168 |
rng = random.Random(seed)
|
| 1169 |
bad = 0
|
| 1170 |
+
image_bits = S['image_bits']
|
| 1171 |
+
m0 = SR.memory_image_a(SR.P_STAR, A)
|
| 1172 |
x0 = [0] * n # the state x_0(m*)
|
| 1173 |
+
for j in range(1 << A):
|
| 1174 |
+
for t in range(A):
|
| 1175 |
+
x0[mem_bit(j, t, A)] = (m0[j] >> t) & 1
|
| 1176 |
for trial in range(trials):
|
| 1177 |
# a random host state with random device registers, temporaries and tapes; every fifth
|
| 1178 |
+
# state not yet booted, and in every third the requests hold random words
|
| 1179 |
x = [rng.randrange(2) for _ in range(n)]
|
| 1180 |
+
x[A] = 0 if trial % 4 else 1
|
| 1181 |
booted = 0 if trial % 5 == 0 else 1
|
| 1182 |
+
for c in ('c_wr', 'c_rd', 'c_rw'):
|
| 1183 |
+
v = rng.randrange(1 << A) if trial % 3 == 0 else rng.choice((0, 1))
|
| 1184 |
+
for t in range(A):
|
| 1185 |
+
x[mem_bit(io[c], t, A)] = (v >> t) & 1
|
| 1186 |
L = 64
|
| 1187 |
cnt, lim = rng.randrange(8), rng.randrange(8)
|
| 1188 |
dest = rng.randrange(2)
|
| 1189 |
+
win = [rng.randrange(2) for _ in range(1 << alpha)]
|
| 1190 |
win[KAPPA] = 0
|
| 1191 |
for i in range(n):
|
| 1192 |
win[addr[('s', i)]] = x[i]
|
| 1193 |
+
for i in range(w):
|
| 1194 |
win[addr[('d', 'cnt', i)]] = (cnt >> i) & 1
|
| 1195 |
win[addr[('d', 'lim', i)]] = (lim >> i) & 1
|
| 1196 |
win[addr[('d', 'dest')]] = dest
|
|
|
|
| 1199 |
D0 = [rng.randrange(2) for _ in range(L)]
|
| 1200 |
Q1 = [rng.randrange(2) for _ in range(len(image_bits))]
|
| 1201 |
D1 = [rng.randrange(2) for _ in range(L)]
|
| 1202 |
+
M = HeadMachine(image_bits, Q1, D0, D1, win, alpha)
|
| 1203 |
for g in range(G):
|
| 1204 |
M.step(recs[g])
|
| 1205 |
+
# expected: the startup if not booted, one step of H_A, then the device on the ring tapes
|
| 1206 |
if not booted:
|
| 1207 |
x, cnt, lim, dest = list(x0), 0, 0, 0
|
| 1208 |
y = host_step(n, units, nxt, x)
|
| 1209 |
+
get = lambda j: sum(y[mem_bit(j, t, A)] << t for t in range(A))
|
| 1210 |
|
| 1211 |
def put(j, v):
|
| 1212 |
+
for t in range(A):
|
| 1213 |
+
y[mem_bit(j, t, A)] = (v >> t) & 1
|
| 1214 |
e_q1, e_d1, hq1, hd0, hd1 = list(Q1), list(D1), 0, 0, 0
|
| 1215 |
e_cnt, e_lim, e_dest = cnt, lim, dest
|
| 1216 |
+
if get(io['c_wr']) == 1:
|
| 1217 |
+
byte = get(io['r_out']) & 0xFF
|
| 1218 |
for kk in range(8):
|
| 1219 |
bit = (byte >> (7 - kk)) & 1
|
| 1220 |
if e_dest:
|
| 1221 |
e_d1[hd1] = bit; hd1 += 1
|
| 1222 |
else:
|
| 1223 |
e_q1[hq1] = bit; hq1 += 1
|
| 1224 |
+
put(io['r_out'], 0)
|
| 1225 |
+
if get(io['c_rd']) == 1:
|
| 1226 |
if not (e_dest and e_cnt == e_lim):
|
| 1227 |
+
byte = sum(D0[hd0 + kk] << (7 - kk) for kk in range(8))
|
| 1228 |
+
put(io['r_in'], byte if byte < 128 else byte + (1 << A) - 256)
|
| 1229 |
hd0 += 8
|
| 1230 |
+
put(io['c_eot'], 0)
|
| 1231 |
+
e_cnt = (e_cnt + 1) % (1 << w)
|
| 1232 |
else:
|
| 1233 |
+
put(io['c_eot'], 1)
|
| 1234 |
+
if get(io['c_rw']) == 1:
|
| 1235 |
e_lim, e_cnt, e_dest = e_cnt, 0, 1
|
| 1236 |
+
for c in ('c_wr', 'c_rd', 'c_rw'):
|
| 1237 |
+
put(io[c], 0)
|
| 1238 |
+
e_kappa = 1 if y[A] else 0
|
| 1239 |
got = [M.w[addr[('s', i)]] for i in range(n)]
|
| 1240 |
+
g_cnt = sum(M.w[addr[('d', 'cnt', i)]] << i for i in range(w))
|
| 1241 |
+
g_lim = sum(M.w[addr[('d', 'lim', i)]] << i for i in range(w))
|
| 1242 |
parts = dict(state=got == y, cnt=g_cnt == e_cnt, lim=g_lim == e_lim,
|
| 1243 |
dest=M.w[addr[('d', 'dest')]] == e_dest, bank=M.Q[1] == e_q1, copy=M.D[1] == e_d1,
|
| 1244 |
arm=M.h[0][1] == hq1, read=M.h[1][0] == hd0, copyhead=M.h[1][1] == hd1,
|
| 1245 |
kappa=M.w[KAPPA] == e_kappa, tape=M.D[0] == D0,
|
| 1246 |
+
booted=M.w[addr[('d', 'booted')]] == 1 - y[A],
|
| 1247 |
requests=M.w[AR] == M.w[AA] == M.w[AC] == 0, active=M.Q[0] == image_bits)
|
| 1248 |
ok = all(parts.values())
|
| 1249 |
if not ok and verbose:
|
| 1250 |
print(trial, [k for k, v in parts.items() if not v], 'reqs',
|
| 1251 |
+
[get(io[c]) for c in ('c_wr', 'c_rd', 'c_rw')], 'dest', dest, 'cnt', cnt, 'lim', lim,
|
| 1252 |
+
'halt', x[A], [i for i in range(n) if got[i] != y[i]][:10])
|
| 1253 |
bad += not ok
|
| 1254 |
return dict(trials=trials, disagreements=bad, records=G, window_cells=S['top'])
|
| 1255 |
|
|
|
|
| 1304 |
return row[t]
|
| 1305 |
|
| 1306 |
|
| 1307 |
+
def symbolic_check(A=8):
|
| 1308 |
+
"""The startup and step records of the image of S_A on decision diagrams over the signals of H_A."""
|
| 1309 |
sys.setrecursionlimit(100000)
|
| 1310 |
t0 = time.time()
|
| 1311 |
+
S = build_stored(A)
|
| 1312 |
+
n, units, nxt = host_units(A)
|
| 1313 |
+
b, alpha = S['b'], S['alpha']
|
| 1314 |
bits = bytes_to_bits(S['image'])
|
| 1315 |
+
recs = [decode_record(bits[k * b:(k + 1) * b], alpha) for k in range(len(bits) // b)]
|
| 1316 |
+
lo = S['startup_records']
|
| 1317 |
+
hi = lo + S['n_host_records']
|
| 1318 |
addr = S['addr']
|
| 1319 |
D = BDD()
|
| 1320 |
# the value of every signal on the current state: a unit that is a constant or a literal is that,
|
| 1321 |
# and the units of one function share the variable of the first; fn[u] is the function of unit u
|
| 1322 |
+
# of the values of its predecessors; later signals lie nearer the root
|
| 1323 |
+
var = lambda s: D.var((1 << 29) - s)
|
| 1324 |
+
top = lambda x: D.node[x][0] if x > 1 else 1 << 31
|
| 1325 |
+
val, first, fn = [var(s) for s in range(n)], {}, []
|
| 1326 |
+
for u, (bias, ins) in enumerate(units):
|
| 1327 |
+
lits = sorted(((val[s], wt > 0) for s, wt in ins), key=lambda l: top(l[0]))
|
| 1328 |
+
f = D.atleast(sum(1 for _, wt in ins if wt < 0) - bias, lits)
|
| 1329 |
fn.append(f)
|
| 1330 |
+
val.append(var(first.setdefault(f, n + u)) if f > 1 and D.node[f][1:] not in ((0, 1), (1, 0)) else f)
|
| 1331 |
unknown = lambda c: D.var(1 << 30 | c)
|
| 1332 |
state = [addr[('s', i)] for i in range(n)]
|
| 1333 |
ends = S['ends']
|
| 1334 |
agree = [True]
|
| 1335 |
|
| 1336 |
+
def run(window, a, z):
|
| 1337 |
# at the record that the compiler names as writing the value of unit u, the cell must hold
|
| 1338 |
# the function of u, and from then on it holds the value of u
|
| 1339 |
+
for k in range(a, z):
|
| 1340 |
a0, w0, a1, w1, beta, ao = recs[k]
|
| 1341 |
assert ao >= 7, ('a record writes a head or a request', k)
|
| 1342 |
g = D.record(w0, window[a0], w1, window[a1], beta)
|
|
|
|
| 1348 |
|
| 1349 |
# the startup: x_0(m*) when booted is 0, the window unchanged when it is 1
|
| 1350 |
boot = addr[('d', 'booted')]
|
| 1351 |
+
window = [unknown(c) for c in range(1 << alpha)]
|
| 1352 |
+
regs = [addr[('d', 'cnt', i)] for i in range(S['w'])] + [addr[('d', 'lim', i)] for i in range(S['w'])] + \
|
| 1353 |
[addr[('d', 'dest')]]
|
| 1354 |
before = list(window)
|
| 1355 |
run(window, 0, lo)
|
| 1356 |
B0 = before[boot]
|
| 1357 |
+
m0 = SR.memory_image_a(SR.P_STAR, A)
|
| 1358 |
x0 = [0] * n
|
| 1359 |
+
for j in range(1 << A):
|
| 1360 |
+
for t in range(A):
|
| 1361 |
+
x0[mem_bit(j, t, A)] = (m0[j] >> t) & 1
|
| 1362 |
startup = window[boot] == 1 and all(window[c] == D.ite(B0, before[c], 0) for c in regs) and \
|
| 1363 |
all(window[state[i]] == D.ite(B0, before[state[i]], x0[i]) for i in range(n))
|
| 1364 |
+
# the step: from every window, the state bits end holding the next state of H_A
|
| 1365 |
+
window = [unknown(c) for c in range(1 << alpha)]
|
| 1366 |
for i in range(n):
|
| 1367 |
window[state[i]] = val[i]
|
| 1368 |
run(window, lo, hi)
|
| 1369 |
step = agree[0] and len(ends) == len(units) and all(window[state[i]] == val[nxt[i]] for i in range(n))
|
| 1370 |
+
return dict(A=A, startup_records=lo, step_records=hi - lo, startup_exact=startup, step_exact=step,
|
| 1371 |
sha256_image=hashlib.sha256(S['image']).hexdigest(), nodes=len(D.node),
|
| 1372 |
seconds=round(time.time() - t0, 1))
|
| 1373 |
|
|
|
|
| 1378 |
json.dump(rec, open(STORED_RECORD, 'w'), indent=1)
|
| 1379 |
|
| 1380 |
|
| 1381 |
+
def census(tau):
|
| 1382 |
+
"""The literal and repeat tokens of a recipe and the bytes each kind gives."""
|
| 1383 |
+
i = lit = rep = flit = frep = 0
|
| 1384 |
+
while tau[i]:
|
| 1385 |
+
t = tau[i]
|
| 1386 |
+
if t < 128:
|
| 1387 |
+
lit, flit, i = lit + 1, flit + t, i + 1 + t
|
| 1388 |
+
else:
|
| 1389 |
+
rep, frep, i = rep + 1, frep + 256 - t, i + 2
|
| 1390 |
+
return lit, rep, flit, frep
|
| 1391 |
+
|
| 1392 |
+
|
| 1393 |
+
def passes(tau):
|
| 1394 |
+
"""The steps of P* on a recipe, Proposition 5.4."""
|
| 1395 |
+
lit, rep, flit, frep = census(tau)
|
| 1396 |
+
return 5 * flit + 4 * frep + 7 * lit + 9 * rep + 7 + 1 + 6 * len(tau) + 2
|
| 1397 |
+
|
| 1398 |
+
|
| 1399 |
+
def stored_key(name, A):
|
| 1400 |
+
return name if A == 8 else f'{name}_A{A}'
|
| 1401 |
+
|
| 1402 |
+
|
| 1403 |
+
def run_stored(generations, A=8):
|
| 1404 |
"""Generations of the stored host on the machine in C, against the reference run of P*."""
|
| 1405 |
+
S = build_stored(A)
|
| 1406 |
+
recs, image_bits, tau, alpha = S['recs'], S['image_bits'], S['tau'], S['alpha']
|
| 1407 |
G = len(recs)
|
| 1408 |
+
out, steps = SR.run_reference_a(SR.memory_image_a(SR.P_STAR, A), tau, A)
|
| 1409 |
+
assert out == S['image'] + tau and steps == passes(tau)
|
| 1410 |
tau_bits = bytes_to_bits(tau)
|
| 1411 |
work = os.path.join(REPO, 'variants')
|
| 1412 |
+
inp, exe = os.path.join(work, f'.stored_host_{A}.bin'), os.path.join(work, f'.stored_host_run_{A}')
|
| 1413 |
with open(inp, 'wb') as f:
|
| 1414 |
+
f.write(struct.pack('<4i', 1 << alpha, alpha, G, len(tau_bits)))
|
| 1415 |
+
f.write(bytes(image_bits) + bytes(tau_bits) + bytes(1 << alpha))
|
| 1416 |
subprocess.run(['gcc', '-O3', '-march=native', '-o', exe, os.path.join(REPO, 'src', 'stored_host_run.c')], check=True)
|
| 1417 |
t0 = time.time()
|
| 1418 |
p = subprocess.run([exe, inp, str(generations)], capture_output=True, text=True)
|
| 1419 |
os.remove(inp); os.remove(exe)
|
| 1420 |
lines = [json.loads(l) for l in p.stdout.split('\n') if l.strip()]
|
| 1421 |
gens = [l for l in lines if 'generation' in l]
|
| 1422 |
+
res = dict(A=A, records=G, window_cells=S['top'], record_bits=S['b'], counter_bits=S['w'],
|
| 1423 |
+
bank_bits=len(image_bits), image_bytes=len(S['image']), tau_bytes=len(tau), passes_expected=steps,
|
| 1424 |
generations=gens, seconds=round(time.time() - t0, 1),
|
| 1425 |
sha256_image=hashlib.sha256(S['image']).hexdigest(),
|
| 1426 |
sha256_tau=hashlib.sha256(tau).hexdigest())
|
|
|
|
| 1429 |
res['state_after_3_equals_after_1'] = l['state_after_3_equals_after_1']
|
| 1430 |
res['every_generation_exact'] = all(g['passes'] == steps and g['steps'] == steps * G and g['bank_holds_image']
|
| 1431 |
and g['tape_holds_tau'] for g in gens) and len(gens) == generations
|
| 1432 |
+
stored_update_record(stored_key('run', A), res)
|
| 1433 |
return res
|
| 1434 |
|
| 1435 |
|
| 1436 |
+
def stored_widths(widths):
|
| 1437 |
+
"""The stored host of every word width: its records, window, counters, image and generation."""
|
| 1438 |
+
rows = []
|
| 1439 |
+
for A in widths:
|
| 1440 |
+
t0 = time.time()
|
| 1441 |
+
S = build_stored(A)
|
| 1442 |
+
G, tau = len(S['recs']), S['tau']
|
| 1443 |
+
lit, rep, flit, frep = census(tau)
|
| 1444 |
+
P = passes(tau)
|
| 1445 |
+
rows.append(dict(A=A, records=G, startup=S['startup_records'], step=S['n_host_records'],
|
| 1446 |
+
device=S['device_records'],
|
| 1447 |
+
handover=G - S['startup_records'] - S['n_host_records'] - S['device_records'],
|
| 1448 |
+
window_cells=S['top'], alpha=S['alpha'], record_bits=S['b'], counter_bits=S['w'],
|
| 1449 |
+
image_bytes=len(S['image']), tau_bytes=len(tau), literal_tokens=lit, repeat_tokens=rep,
|
| 1450 |
+
passes=P, applications=P * G, seconds=round(time.time() - t0, 1)))
|
| 1451 |
+
print(json.dumps(rows[-1]), flush=True)
|
| 1452 |
+
stored_update_record('widths', rows)
|
| 1453 |
+
return rows
|
| 1454 |
+
|
| 1455 |
+
|
| 1456 |
def cmd_stored():
|
| 1457 |
+
args = sys.argv[1:]
|
| 1458 |
+
A = 8
|
| 1459 |
+
if '--width' in args:
|
| 1460 |
+
i = args.index('--width')
|
| 1461 |
+
A = int(args[i + 1])
|
| 1462 |
+
del args[i:i + 2]
|
| 1463 |
+
cmd = args[0] if args else 'build'
|
| 1464 |
if cmd == 'check':
|
| 1465 |
t0 = time.time()
|
| 1466 |
+
res = check_stored(int(args[1]) if len(args) > 1 else 40, A=A)
|
| 1467 |
res['seconds'] = round(time.time() - t0, 1)
|
| 1468 |
+
stored_update_record(stored_key('pass_check', A), res)
|
| 1469 |
print(json.dumps(res))
|
| 1470 |
sys.exit(0 if res['disagreements'] == 0 else 1)
|
| 1471 |
elif cmd == 'symbolic':
|
| 1472 |
+
res = symbolic_check(A)
|
| 1473 |
+
stored_update_record(stored_key('symbolic', A), res)
|
| 1474 |
print(json.dumps(res))
|
| 1475 |
sys.exit(0 if res['startup_exact'] and res['step_exact'] else 1)
|
| 1476 |
elif cmd == 'run':
|
| 1477 |
+
gens = int(args[1]) if len(args) > 1 else 3
|
| 1478 |
+
res = run_stored(gens, A)
|
| 1479 |
print(json.dumps(res, indent=1))
|
| 1480 |
sys.exit(0 if res['every_generation_exact'] and (gens < 3 or res.get('state_after_3_equals_after_1') == 1)
|
| 1481 |
else 1)
|
| 1482 |
+
elif cmd == 'widths':
|
| 1483 |
+
stored_widths([int(a) for a in args[1:]] or list(range(8, 13)))
|
| 1484 |
elif cmd == 'build':
|
| 1485 |
t0 = time.time()
|
| 1486 |
+
S = build_stored(A)
|
| 1487 |
+
print(json.dumps(dict(A=A, records=len(S['recs']), host_records=S['n_host_records'],
|
| 1488 |
+
window_cells=S['top'], record_bits=S['b'], counter_bits=S['w'],
|
| 1489 |
+
bank_bits=len(S['image_bits']), image_bytes=len(S['image']), tau_bytes=len(S['tau']),
|
| 1490 |
+
sha256_image=hashlib.sha256(S['image']).hexdigest(),
|
| 1491 |
seconds=round(time.time() - t0, 1))))
|
| 1492 |
|
| 1493 |
|
todo.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 1 |
-
# todo
|
| 2 |
-
|
| 3 |
-
Unfinished work.
|
| 4 |
-
|
| 5 |
-
1. A machine-checked correctness proof relates the shipped weights to the ISA.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|