phanerozoic commited on
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 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. An organism of 133 records on the member with 64
 
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 H_8 extracted from it against the netlist sigma(N_host) denotes |
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 N_host (`stored symbolic`), and three generations in C |
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": 303.5,
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
- "A": 8,
28
- "units": 17598,
29
- "identical": true,
30
- "sha256_sigma": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a",
31
- "sha256_rocq": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": 131.8
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": 1435999,
77
- "seconds": 3.6
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:c973871985a763cf000c4cfa9e8126aa37eb0efb94c99261d4289b10a39e1b10
3
- size 327298
 
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; a constructor of
83
- $133$ records does the same with every step proved in Rocq. Because every
 
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. Neural networks have been trained to output
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 running $P^\ast$ builds every
163
- image of its size into the idle bank and hands control to it, and started on a
164
- recipe for its own records it reproduces in every generation, weights included,
165
- a generation of $G$ records taking at most $\tfrac{25}{16}(8+3\alpha)G^2+29G$
166
- steps (Theorems~\ref{thm:storedconstruct} and~\ref{thm:storedrep}); three
167
- generations of the host, $36{,}074$ records and $7.9\times10^{10}$ steps each,
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))$ when the
181
- noise sits on every synapse (Theorem~\ref{thm:amplify},
182
- Corollary~\ref{cor:synapse}). The state read by majority fails only when two wrong
183
- copies meet, a second-order event whose bound certifies the complete run of the
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-mapped
312
- cells of the SUBLEQ memory at the addresses of Table~\ref{tab:device}, and
313
- $c_{\mathrm{halt}}$ is a state bit that latches the predicate $p=255$ on the
314
- program counter of the state produced by the step, so that a halted state is a
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}}$, and an emission appends the low byte of $R_{\mathrm{out}}$.
 
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$, the
632
- definition gives the netlist that $\sigma(\Nhost)$ denotes, unit for unit.
 
633
  \end{proof}
634
 
635
  \begin{remark}[Depth]\label{rem:fold}
636
- A ripple-carry datapath makes the depth grow linearly with $A$; for $A=8$ it has
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$. We do not know the least depth of a ternary SUBLEQ step; the
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. For the bounds,
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}$. With every programmed weight perturbed
1038
- uniformly in $[-\varepsilon,\varepsilon]$ or every zero entry in
1039
- $[-\gamma,\gamma]$, the first $10{,}000$ steps stayed exact up to
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$. The census of $\tau^\ast_3$ is $L=23{,}892$,
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: the record and
1498
- the cells under the heads are selected at depth $2$, the decode lines lie at
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
- For $\alpha=6$, $G=133$ and $L=2930$, the member that Section~\ref{sec:organism}
1511
- uses, $N^6_{G,L}$ has $45{,}891$ units, $99{,}602$ edges and $12{,}837$ state bits;
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 as a network of two-input records in a bank of $T^{12}_{G,L}$,
1528
- whose window of $4096$ cells holds the host's $2057$ state bits, with a device
1529
- that writes the bytes the host emits under the arm until the tape is rewound and
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
- Gate-level logic simulation engines evaluate one stored gate per step from
1553
- operand memory and rank-order the gates so that one pass
1554
- suffices~\cite{Denneau1982}, and Lemma~\ref{lem:feedback} is the fixed-order
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 $\alpha=12$. The window holds, after the eight cells of
1580
  Definition~\ref{def:twohead}, a cell $\mathrm{booted}$ at $8$, a counter
1581
- $\mathrm{cnt}$ of $20$ bits at $9$ to $28$, least significant first, a cell
1582
- $\mathrm{dest}$ at $29$, a limit $\mathrm{lim}$ of $20$ bits at $30$ to $49$, the
1583
- $2057$ state bits of $\Nhost$ at $50$ to $2106$ in the order of
1584
- Construction~\ref{con:host}, and temporaries from $2107$ on. The stored host $S$
1585
- lists the following $36{,}074$ records.
1586
  \begin{enumerate}[label=(\alph*),leftmargin=2em]
1587
- \item \emph{Startup}, $2099$ records: for each memory bit $c$,
1588
- $c\leftarrow c\vee\neg\mathrm{booted}$ if its value in $m^\ast$ is $1$ and
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}, $33{,}568$ records: the units of $\Nhost$ compiled by
1594
- Lemma~\ref{cor:compile}, in two stages. The first evaluates every unit that a
1595
- next value depends on, other than the units of the next values and the units read
1596
- by a single unit, each after its predecessors. The second takes the counter bits,
1597
- the halt bit and the memory bits in this order, and evaluates for each the unit of
1598
- its next value, with the units read by it alone just before it, its last record
1599
- writing the bit.
1600
- \item \emph{Device}, $402$ records: the device of Definition~\ref{def:ring} on the
1601
- state that~(b) leaves.
1602
- \item \emph{Hand-over}, five records: $\mathrm{booted}\leftarrow
1603
- \mathrm{booted}\wedge\neg h$, where $h$ is the halt bit; a record with both
1604
- weights $0$ that writes $0$ into the sink, which makes $S$ a whole number of bytes;
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, $789$ cells in all, so $S$ uses the window cells $0$ to
1609
- $2895$. The image of $S$, its records in order, has $1{,}587{,}256$ bits, read as
1610
- $198{,}407$ bytes most significant bit first, and $\tau_S=\describe(S)$ has
1611
- $199{,}971$ bytes.
 
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 the host after a step, the registers
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, $c_{\mathrm{eot}}$ is cleared and
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^{12}_{G,L}$ with $G=36{,}074$ hold $S$ in the active bank from
1674
- its first record, and in the window clear requests and a host state $x$. One pass
1675
- replaces $x$ by $x_0(m^\ast)$ and clears $\mathrm{cnt}$, $\mathrm{lim}$ and
1676
- $\mathrm{dest}$ if $\mathrm{booted}=0$; then carries out one step of $\Nhost$
1677
- followed by the device of Definition~\ref{def:ring}; then sets $\mathrm{booted}$
1678
- to the negation of the halt bit and, if the halt bit is $1$, changes $\kappa$ at
1679
- its last step. It leaves $S$ in the active bank from its first record and the
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^\ast$ and clear the other cells they name. The step block is $\Nhost$
1688
  compiled by Lemma~\ref{cor:compile}, in an order that Lemma~\ref{lem:feedback}
1689
- admits: the first stage writes temporaries only, and no record reads a state bit
1690
- after the record that writes its next value, a condition checked over the records.
1691
- So after the block the state bits hold the next state of $\Nhost$, which
1692
- Remark~\ref{rem:storedcheck} also checks on every window. The device
1693
- records form the requests $[y_c=1]$ as conjunctions of eight literals, the bit
1694
- $[\mathrm{cnt}=\mathrm{lim}]$ as a conjunction of twenty equivalences, and its
1695
- conjunction with $\mathrm{dest}$. They then write each bit of $R_{\mathrm{out}}$
1696
- under the arm or the copy head by a multiplexer, followed by the request that turns
1697
- that head, and clear $R_{\mathrm{out}}$ on a write; load each bit under the read
1698
- head into $R_{\mathrm{in}}$ by a multiplexer on the condition of a read, followed
1699
- by the request that turns the read tape; set $c_{\mathrm{eot}}$; increment
1700
- $\mathrm{cnt}$ by carries formed before any of its bits changes; carry out the
1701
- rewind; and clear the requests: these are clauses (i) to (iv) of
1702
- Definition~\ref{def:ring}. The hand-over records set $\mathrm{booted}$ and,
1703
- last, $\kappa$. Every temporary is written in the pass before it is read and is not
1704
- written after its last read, so a cell shared by temporaries holds, at each read,
1705
- the value of the temporary read. No record writes the active bank, which turns by
1706
- $G$ records.
 
 
 
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}$, $\alpha\ge12$, does what Proposition~\ref{prop:storedpass}
1711
- states for $S$, on the window cells of Construction~\ref{con:stored}, every cell
1712
- that a record after the startup records reads, other than $\kappa$, the cells
1713
- under the heads and the sink, being written earlier in the pass; we call such an
1714
- image a \emph{stored host}, of $B=bG/8$ bytes with $b=8+3\alpha$. Its step block may
1715
- compile any netlist whose step is that of $\Nhost$, and $S$ is a stored host with
1716
- $\alpha=12$, $G=36{,}074$ and $B=198{,}407$.
 
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^{19}$ bytes, let $X$ be an image
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^\ast)$ and carries out the first step of the host, and each later pass one
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 $r$ with the device of
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^{20}$ and $\mathrm{cnt}$ does not wrap. Before the rewind
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<2^{19}$ bytes, $\tau'=\describe(S')$
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, $79{,}464{,}240{,}088$ steps each: after each
1819
- the new active bank held $S$ and the new read tape $\tau_S$, each from its head,
1820
- the other bank and tape still held them, $\kappa$ alternated, and the full state
1821
- after the third generation equalled the state after the first. A transcription in
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 bytes, with
1826
- random tapes, idle bank, registers and temporaries, and agreed in every case; that no
1827
- record of the step block reads a state bit after the record of its next value, and
1828
- that no temporary is written after its last read, was checked over the records.
1829
- The startup and step records of the image were also evaluated on reduced ordered
1830
- decision diagrams over variables for the state bits and the units of $\Nhost$, the
1831
- variable of a unit replacing, at the record the compiler names as writing its
1832
- value, a diagram checked to equal the unit's function of the variables of its
1833
- predecessors: from every window the startup records leave $x_0(m^\ast)$ or the
1834
- state as $\mathrm{booted}$ is $0$ or $1$, and the step records leave every state bit
1835
- holding the variable of the unit of its next value.
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}, and was run for three
1844
- generations. This section gives a smaller stored network, the
1845
- organism, that performs von Neumann's cycle in $T_{G,L}$, the machine of $64$
1846
- cells, with a description code of its own; every step of its reproduction is
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 costs $4$ passes in phase C, $8$ in G and
1948
- $18$ in A, and writes the gate's eight bits and the $18$ address bits under the
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 from $x_0$ were also run on the transcription of
1990
- Definition~\ref{def:twohead} and on the netlist in C beside it
1991
- (Remark~\ref{rem:physcheck}), with the outcome the theorem states, and the full
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 weights of unbounded precision~\cite{SiegelmannSontag1995},
2031
- numbers of units that grow with the computation~\cite{ChungSiegelmann2021}
2032
- or weights that change over time~\cite{CabessaSiegelmann2014}, and von Neumann's
2033
- cellular automaton is universal because its tape can be
2034
- extended~\cite{vonNeumann1966,Burks1970}. Analog noise reduces discrete-time analog
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 reach approximate
2063
- fixed points of self-application~\cite{Gabor2022}, to reproduce over
2064
- generations~\cite{RandazzoVersariMordvintsev2021}, to emit the program text that
2065
- trains them~\cite{Schmidgall2021} and to copy a genotype with
2066
- errors~\cite{ShvartzmanRam2024}; hypernetworks generate the weights of other
2067
- networks~\cite{HaDaiLe2017}, and self-referential weight matrices modify
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$, $4{,}066$ at
2083
- $0$, $10{,}396$ at $-2$, $176$ at $-3$, $499$ at $-4$ and below, and $5$ at $1$ and
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, each built from a different
2174
- representation: (a) an integer reference implementing
2175
  Definitions~\ref{def:subleq} and~\ref{def:transducer}; (b) the netlist that
2176
- $\sigma(\Nhost)$ denotes, evaluated unit by unit; (c) $\Lev(\Nhost)$, as $13$ dense
2177
- ternary matrices or from its $75{,}501$ nonzero entries; and (d) an evaluator in C,
2178
- \texttt{src/netlist\_eval.c}, with its own SUBLEQ reference, device, parser and
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 file of the
2214
- netlist that $\sigma(\Nhost)$ denotes and for $N^6_{133,2930}$ and
2215
- $N^{12}_{5,40}$ files byte for byte equal to those that
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
- and rebuilding the host from source reproduces its serialization byte for byte.
2229
-
2230
- Every run of $\Omega^\ast$ produced the same output, of SHA-256 digest
2231
- \texttt{c5950d3f\ldots6e7fb523}, and the artifact~\cite{Norton2026} is identified by
2232
- the digests of $\ser(\Omega^\ast)$, of the host serialization, of the serialization
2233
- of $N_3$, of $\ser(\Omega^\ast_3)$, of the netlist file of $N^6_{133,2930}$, of
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 netlist of rocq/Host.v for A = 8, extracted to OCaml, against the netlist sigma(N_host) denotes."""
 
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
- subprocess.run([os.path.join(ex, 'dumphost'), '8', out], check=True)
1058
- theirs = open(out, 'rb').read()
1059
- n, units, nxt = parse_sigma(read_host())
1060
- words = array('i', [n, len(units), sum(len(ins) for _, ins in units)])
1061
- words.extend(b for b, _ in units)
1062
- words.extend(len(ins) for _, ins in units)
1063
- words.extend(w * (k + 1) for _, ins in units for k, w in ins)
1064
- words.extend(nxt)
1065
- if sys.byteorder != 'little':
1066
- words.byteswap()
1067
- ours = words.tobytes()
 
 
 
 
 
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(A=8, units=len(units), identical=ours == theirs,
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
- SH_ALPHA = 12
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: pc bits 0..7 most significant first, halt 8, memory byte j bit k at 9 + 8 j + k,
699
- # k = 0 the most significant
700
- def mem_bit(j, t):
701
- """State index of bit t (value 2^t) of memory byte j."""
702
- return 9 + 8 * j + (7 - t)
703
 
704
 
705
- PC_BIT = lambda t: 7 - t # bit t of the counter
706
-
707
- HALT = 8
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 H_8; state bits are cells ('s', i)."""
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[PC_BIT(t)] - n for t in range(8)] + [nxt[HALT] - n] + \
860
- [nxt[mem_bit(j, t)] - n for j in range(256) for t in range(8)]
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 byte_is_one(P, j):
896
- """[memory byte j == 1]"""
897
  dst = P.tmp()
898
- lits = [(mem_cell(j, 0), True)] + [(mem_cell(j, t), False) for t in range(1, 8)]
899
  P.chain('and', lits, dst)
900
  return dst
901
 
902
 
903
- def compile_device(P):
904
- cnt = [('d', 'cnt', i) for i in range(CW)]
905
- lim = [('d', 'lim', i) for i in range(CW)]
 
906
  dest = ('d', 'dest')
907
- wr, rd, rw = byte_is_one(P, SR.C_WR), byte_is_one(P, SR.C_RD), byte_is_one(P, SR.C_RW)
 
 
908
  # [cnt == lim]
909
  eq = P.tmp()
910
  xs = []
911
- for i in range(CW):
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(SR.R_OUT, t), True), (('c', ARM), True), ('c', ARM))
927
  P.COPY((ca, True), ('c', AA))
928
- P.MUX(cc, (mem_cell(SR.R_OUT, t), True), (('c', CPY), True), ('c', CPY))
929
  P.COPY((cc, True), ('c', AC))
930
- for t in range(8):
931
- P.AND((mem_cell(SR.R_OUT, t), True), (wr, False), mem_cell(SR.R_OUT, t))
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(SR.R_IN, t), True), mem_cell(SR.R_IN, t))
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(SR.C_EOT, 0), True), mem_cell(SR.C_EOT, 0))
940
- for t in range(1, 8):
941
- P.AND((mem_cell(SR.C_EOT, t), True), (rd, False), mem_cell(SR.C_EOT, t))
942
  # the counter of bytes read: carries first, then the sum bits
943
  car = [g]
944
- for i in range(CW - 1):
945
  c = P.tmp()
946
  P.AND((car[-1], True), (cnt[i], True), c)
947
  car.append(c)
948
- for i in range(CW):
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(CW):
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 j in (SR.C_WR, SR.C_RD, SR.C_RW):
957
- for t in range(8):
958
- P.CONST(0, mem_cell(j, t))
959
 
960
 
961
- def compile_startup(P, mem_image):
962
- """The startup records: while booted is 0, load m* and clear the counter, halt bit and registers."""
963
  b = ('d', 'booted')
964
- for j in range(256):
965
- for t in range(8):
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(8):
972
- P.AND((('s', PC_BIT(t)), True), (b, True), ('s', PC_BIT(t)))
973
- P.AND((('s', HALT), True), (b, True), ('s', HALT))
974
- for i in range(CW):
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', HALT)
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
- free_at = {} # cell -> index after which it is free
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
- cand = [c for c, f in free_at.items() if f < start]
1019
- c = min(cand) if cand else base + len(free_at)
 
 
 
 
1020
  addr[name] = c
1021
- free_at[c] = end
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
- P = Prog()
1072
- compile_startup(P, SR.M_STAR)
1073
- lo = len(P.recs)
1074
- n, units, nxt = compile_host(P)
1075
- n_host = len(P.recs) - lo
1076
- check_schedule(P.recs, lo, len(P.recs), n)
1077
- compile_device(P)
1078
- compile_handover(P)
1079
- recs, addr, top = allocate(P.recs)
1080
- if len(recs) % 2: # an image of whole bytes
1081
- recs.insert(len(recs) - 3, (SINK, 0, SINK, 0, -1, SINK))
1082
- image_bits = [b for r in recs for b in encode_record(r, SH_ALPHA)]
 
 
 
 
 
 
 
 
 
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, tau=tau,
1087
- n_host_records=n_host, host=(n, units, nxt), ends=P.ends)
 
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(SH_B)], SH_ALPHA)
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] + SH_B) % self.N
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 = [b for r in recs for b in encode_record(r, SH_ALPHA)]
 
1155
  x0 = [0] * n # the state x_0(m*)
1156
- for j in range(256):
1157
- for t in range(8):
1158
- x0[mem_bit(j, t)] = (SR.M_STAR[j] >> t) & 1
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 bytes
1162
  x = [rng.randrange(2) for _ in range(n)]
1163
- x[HALT] = 0 if trial % 4 else 1
1164
  booted = 0 if trial % 5 == 0 else 1
1165
- for j in (SR.C_WR, SR.C_RD, SR.C_RW):
1166
- v = rng.randrange(256) if trial % 3 == 0 else rng.choice((0, 1))
1167
- for t in range(8):
1168
- x[mem_bit(j, t)] = (v >> t) & 1
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(SH_W)]
1173
  win[KAPPA] = 0
1174
  for i in range(n):
1175
  win[addr[('s', i)]] = x[i]
1176
- for i in range(CW):
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 H_8, then the device on the ring tapes
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(8))
1193
 
1194
  def put(j, v):
1195
- for t in range(8):
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(SR.C_WR) == 1:
1200
- byte = get(SR.R_OUT)
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(SR.R_OUT, 0)
1208
- if get(SR.C_RD) == 1:
1209
  if not (e_dest and e_cnt == e_lim):
1210
- put(SR.R_IN, sum(D0[hd0 + kk] << (7 - kk) for kk in range(8)))
 
1211
  hd0 += 8
1212
- put(SR.C_EOT, 0)
1213
- e_cnt = (e_cnt + 1) % (1 << CW)
1214
  else:
1215
- put(SR.C_EOT, 1)
1216
- if get(SR.C_RW) == 1:
1217
  e_lim, e_cnt, e_dest = e_cnt, 0, 1
1218
- put(SR.C_WR, 0); put(SR.C_RD, 0); put(SR.C_RW, 0)
1219
- e_kappa = 1 if y[HALT] else 0
 
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(CW))
1222
- g_lim = sum(M.w[addr[('d', 'lim', i)]] << i for i in range(CW))
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[HALT],
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(j) for j in (SR.C_WR, SR.C_RD, SR.C_RW)], 'dest', dest, 'cnt', cnt, 'lim', lim,
1233
- 'halt', x[HALT], [i for i in range(n) if got[i] != y[i]][:10])
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 S on decision diagrams over the signals of N_host."""
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 * SH_B:(k + 1) * SH_B], SH_ALPHA) for k in range(len(bits) // SH_B)]
1296
- lo, hi = 2099, 2099 + S['n_host_records']
 
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
- val, first, fn = [D.var(s) for s in range(n)], {}, []
1303
- for u, (b, ins) in enumerate(units):
1304
- f = D.atleast(sum(1 for _, w in ins if w < 0) - b, [(val[s], w > 0) for s, w in ins])
 
 
 
1305
  fn.append(f)
1306
- val.append(D.var(first.setdefault(f, n + u)) if f > 1 and D.node[f][1:] not in ((0, 1), (1, 0)) else f)
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, b):
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, b):
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(SH_W)]
1328
- regs = [addr[('d', 'cnt', i)] for i in range(CW)] + [addr[('d', 'lim', i)] for i in range(CW)] + \
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(256):
1335
- for t in range(8):
1336
- x0[mem_bit(j, t)] = (SR.M_STAR[j] >> t) & 1
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 N_host
1340
- window = [unknown(c) for c in range(SH_W)]
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 run_stored(generations):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.run_reference(SR.M_STAR, tau)
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, '.stored_host.bin'), os.path.join(work, '.stored_host_run')
1366
  with open(inp, 'wb') as f:
1367
- f.write(struct.pack('<4i', SH_W, SH_ALPHA, G, len(tau_bits)))
1368
- f.write(bytes(image_bits) + bytes(tau_bits) + bytes(SH_W))
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=SH_B, bank_bits=len(image_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
- cmd = sys.argv[1] if len(sys.argv) > 1 else 'build'
 
 
 
 
 
 
1391
  if cmd == 'check':
1392
  t0 = time.time()
1393
- res = check_stored(int(sys.argv[2]) if len(sys.argv) > 2 else 40)
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(sys.argv[2]) if len(sys.argv) > 2 else 3
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=SH_B, bank_bits=len(S['image_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.