phanerozoic commited on
Commit
c1f23de
·
1 Parent(s): 79ed4eb

Add the restoration bound for the amplified host with its proof, the batched failure-rate runs that test it, and the per-step table

Browse files
README.md CHANGED
@@ -583,9 +583,10 @@ interpreter's state. Its robustness section gives the margin every orbit has
583
  against perturbation, a certificate of the leakage an orbit tolerates from the
584
  inputs active along it, and the amplified host of `src/redundant.py`: every row
585
  of the levelized host replaced by r rows reading all r copies of its inputs,
586
- which multiplies every margin by r, reproduces itself exactly, and completes the
587
- self-reproducing run under read noise at levels where the host fails within its
588
- first bytes.
 
589
 
590
  `python src/verify.py` audits every statement of the paper, and `--tier 2` adds
591
  every construction end to end; the checks of a tier run concurrently. `--tier 3` runs
 
583
  against perturbation, a certificate of the leakage an orbit tolerates from the
584
  inputs active along it, and the amplified host of `src/redundant.py`: every row
585
  of the levelized host replaced by r rows reading all r copies of its inputs,
586
+ which multiplies every margin by r, reproduces itself exactly, fails only when two
587
+ wrong copies meet, with a probability of second order that the paper bounds, and
588
+ completes the self-reproducing run under read noise at levels where the host
589
+ fails within its first bytes.
590
 
591
  `python src/verify.py` audits every statement of the paper, and `--tier 2` adds
592
  every construction end to end; the checks of a tier run concurrently. `--tier 3` runs
paper/README.md CHANGED
@@ -72,7 +72,7 @@ the cost of any one run is a multiplication.
72
  | `src/hosted_constructor.py` | `paper_hosted.json` | the constructor as a netlist stored in the interpreter |
73
  | `src/throughput.py` | `paper_throughput.json` | the rate of each evaluator |
74
  | `src/noise.py` | `paper_noise_*.json` | read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
75
- | `src/redundant.py` | `paper_redundant_*.json` | the amplified host N_3: one step against SUBLEQ on replicated states, the margin 3/2, exact self-reproduction in C, the run under noise, the deviation curve and its bound by layer, wrong copies and the state read by majority |
76
  | `src/neuromorphic.py` | `paper_neuromorphic.json` | the datapath on the Loihi and Akida neuron models |
77
 
78
  `src/neuromorphic.py run` needs Lava, which requires Python 3.10; everything
 
72
  | `src/hosted_constructor.py` | `paper_hosted.json` | the constructor as a netlist stored in the interpreter |
73
  | `src/throughput.py` | `paper_throughput.json` | the rate of each evaluator |
74
  | `src/noise.py` | `paper_noise_*.json` | read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
75
+ | `src/redundant.py` | `paper_redundant_*.json` | the amplified host N_3: one step against SUBLEQ 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 |
76
  | `src/neuromorphic.py` | `paper_neuromorphic.json` | the datapath on the Loihi and Akida neuron models |
77
 
78
  `src/neuromorphic.py run` needs Lava, which requires Python 3.10; everything
paper/runs/paper_redundant_bound_r3.json ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "r": 3,
3
+ "rows": [
4
+ {
5
+ "sigma": 0.1,
6
+ "p": 3.6709661993128594e-51,
7
+ "sigma_link": 2.866515718791946e-07,
8
+ "converged": true,
9
+ "second_term_uncapped": 2.13025075311841e-57,
10
+ "a_max": 3.671774358064498e-51,
11
+ "a_state_max": 3.670975669925945e-51,
12
+ "first_term": 1.657595730962774e-94,
13
+ "second_term": 2.130250753116143e-57,
14
+ "per_step": 2.130250753116143e-57,
15
+ "one_step_map_norm": 1.1207102716990636e-69,
16
+ "G_max": 2.177572163092903e-08,
17
+ "first_order_per_step": 9.243566309193767e-46,
18
+ "seconds": 44.994851198003744
19
+ },
20
+ {
21
+ "sigma": 0.15,
22
+ "p": 7.619853024160593e-24,
23
+ "sigma_link": 0.00042906033319683735,
24
+ "converged": true,
25
+ "second_term_uncapped": 9.96281774740883e-24,
26
+ "a_max": 1.0137246671296701e-23,
27
+ "a_state_max": 7.649365999909047e-24,
28
+ "first_term": 7.1820241657899036e-40,
29
+ "second_term": 9.962793936252263e-24,
30
+ "per_step": 9.962793936252263e-24,
31
+ "one_step_map_norm": 2.121416036030206e-28,
32
+ "G_max": 0.048788884933895625,
33
+ "first_order_per_step": 1.9186942311896616e-18,
34
+ "seconds": 44.644577098995796
35
+ },
36
+ {
37
+ "sigma": 0.2,
38
+ "p": 3.19089167291092e-14,
39
+ "sigma_link": 0.006209665325776139,
40
+ "converged": true,
41
+ "second_term_uncapped": 9.84392269671024e-12,
42
+ "a_max": 1.9232583156861574e-13,
43
+ "a_state_max": 3.3772509678220235e-14,
44
+ "first_term": 1.3839563909399713e-20,
45
+ "second_term": 2.284341310002908e-12,
46
+ "per_step": 2.284341323842472e-12,
47
+ "one_step_map_norm": 2.5928274635601137e-13,
48
+ "G_max": 10.318938219834262,
49
+ "first_order_per_step": 8.034729050223154e-09,
50
+ "seconds": 44.76692351400561
51
+ },
52
+ {
53
+ "sigma": 0.22,
54
+ "p": 4.6099955192965596e-12,
55
+ "sigma_link": 0.011521310043880927,
56
+ "converged": true,
57
+ "second_term_uncapped": 6.1655968721159675e-09,
58
+ "a_max": 5.2390139649676e-11,
59
+ "a_state_max": 5.1292274254447534e-12,
60
+ "first_term": 3.3417127781326887e-16,
61
+ "second_term": 1.7924312135933292e-09,
62
+ "per_step": 1.7924315477646071e-09,
63
+ "one_step_map_norm": 8.005921428622896e-10,
64
+ "G_max": 36.378198953846095,
65
+ "first_order_per_step": 1.1608060917499123e-06,
66
+ "seconds": 44.5916818560072
67
+ },
68
+ {
69
+ "sigma": 0.25,
70
+ "p": 9.865876450377012e-10,
71
+ "sigma_link": 0.02275013194817922,
72
+ "converged": true,
73
+ "second_term_uncapped": 1.2221903683727557e-05,
74
+ "a_max": 3.464062637574069e-08,
75
+ "a_state_max": 1.2256411202374905e-09,
76
+ "first_term": 2.955875675535229e-11,
77
+ "second_term": 2.101305150682518e-06,
78
+ "per_step": 2.101334709439273e-06,
79
+ "one_step_map_norm": 5.554923106754895e-06,
80
+ "G_max": 160.96107083907205,
81
+ "first_order_per_step": 0.00024842474219578326,
82
+ "seconds": 44.780106067002635
83
+ },
84
+ {
85
+ "sigma": 0.27,
86
+ "p": 1.3836508957768842e-08,
87
+ "sigma_link": 0.03202354974072154,
88
+ "converged": true,
89
+ "second_term_uncapped": 0.0008325628286829023,
90
+ "a_max": 1.2542660971875762e-06,
91
+ "a_state_max": 1.896662835974905e-08,
92
+ "first_term": 1.5422649474591534e-08,
93
+ "second_term": 9.280154361716902e-05,
94
+ "per_step": 9.28169662666436e-05,
95
+ "one_step_map_norm": 0.0004731405980891133,
96
+ "G_max": 502.241185749977,
97
+ "first_order_per_step": 0.00348406062858411,
98
+ "seconds": 44.378902162992745
99
+ },
100
+ {
101
+ "sigma": 0.3,
102
+ "p": 2.866515718791946e-07,
103
+ "sigma_link": 0.0477903522728147,
104
+ "converged": true,
105
+ "second_term_uncapped": 0.26158463232188245,
106
+ "a_max": 0.00011903221609335197,
107
+ "a_state_max": 5.40858095381371e-07,
108
+ "first_term": 5.502587076206081e-05,
109
+ "second_term": 0.01129871498942794,
110
+ "per_step": 0.011353740860190002,
111
+ "one_step_map_norm": 0.08616087624087705,
112
+ "G_max": 9637.91625882214,
113
+ "first_order_per_step": 0.07217943910232472,
114
+ "seconds": 45.34780544799287
115
+ },
116
+ {
117
+ "sigma": 0.33,
118
+ "p": 2.740841326345048e-06,
119
+ "sigma_link": 0.06486701914733445,
120
+ "converged": false,
121
+ "first_order_per_step": 0.6901493276563357,
122
+ "seconds": 0.13191196900152136
123
+ },
124
+ {
125
+ "sigma": 0.36,
126
+ "p": 1.5454296882296004e-05,
127
+ "sigma_link": 0.08243326987395455,
128
+ "converged": false,
129
+ "one_step_map_norm": 103.09080918475902,
130
+ "first_order_per_step": 3.8914228635558983,
131
+ "seconds": 45.01266609299637
132
+ }
133
+ ]
134
+ }
paper/runs/paper_redundant_r3.json CHANGED
@@ -25,7 +25,7 @@
25
  "bias_min": -23,
26
  "bias_max": 4,
27
  "max_fanin": 768,
28
- "build_seconds": 0.6454255809949245,
29
  "sigma_roundtrip": true,
30
  "c_random": "random states: 65536 tested, 0 disagree with SUBLEQ, 0 halt-latch mismatches, 0 halted batches not fixed",
31
  "c_random_ok": true,
 
25
  "bias_min": -23,
26
  "bias_max": 4,
27
  "max_fanin": 768,
28
+ "build_seconds": 0.3552343150076922,
29
  "sigma_roundtrip": true,
30
  "c_random": "random states: 65536 tested, 0 disagree with SUBLEQ, 0 halt-latch mismatches, 0 halted batches not fixed",
31
  "c_random_ok": true,
paper/runs/paper_redundant_restore_r3.json CHANGED
@@ -1,66 +1,323 @@
1
  {
2
  "r": 3,
3
- "steps": 20000,
 
4
  "rows": [
5
- {
6
- "sigma": 0.24,
7
- "steps": 20000,
8
- "copy_errors": 0,
9
- "steps_with_copy_errors": 0,
10
- "max_copy_errors_in_a_step": 0,
11
- "copy_errors_carried_to_next_step": 0,
12
- "decoded_first_deviation": null,
13
- "bytes": 3950,
14
- "bytes_equal": true,
15
- "seconds": 54.976982238003984
16
- },
17
  {
18
  "sigma": 0.27,
 
19
  "steps": 20000,
20
- "copy_errors": 2,
21
- "steps_with_copy_errors": 2,
22
- "max_copy_errors_in_a_step": 1,
23
- "copy_errors_carried_to_next_step": 0,
24
- "decoded_first_deviation": null,
25
- "bytes": 3950,
26
- "bytes_equal": true,
27
- "seconds": 80.73841675600852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  },
29
  {
30
  "sigma": 0.3,
31
- "steps": 288,
32
- "copy_errors": 6,
33
- "steps_with_copy_errors": 4,
34
- "max_copy_errors_in_a_step": 3,
35
- "copy_errors_carried_to_next_step": 1,
36
- "decoded_first_deviation": 288,
37
- "bytes": 54,
38
- "bytes_equal": true,
39
- "seconds": 1.0162241850048304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  },
41
  {
42
  "sigma": 0.33,
43
- "steps": 110,
44
- "copy_errors": 5,
45
- "steps_with_copy_errors": 3,
46
- "max_copy_errors_in_a_step": 3,
47
- "copy_errors_carried_to_next_step": 0,
48
- "decoded_first_deviation": 110,
49
- "bytes": 18,
50
- "bytes_equal": true,
51
- "seconds": 0.3773938849917613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  },
53
  {
54
  "sigma": 0.36,
55
- "steps": 38,
56
- "copy_errors": 5,
57
- "steps_with_copy_errors": 3,
58
- "max_copy_errors_in_a_step": 3,
59
- "copy_errors_carried_to_next_step": 0,
60
- "decoded_first_deviation": 38,
61
- "bytes": 5,
62
- "bytes_equal": true,
63
- "seconds": 0.13369095901725814
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
  ]
66
  }
 
1
  {
2
  "r": 3,
3
+ "copies": 64,
4
+ "cap": 20000,
5
  "rows": [
 
 
 
 
 
 
 
 
 
 
 
 
6
  {
7
  "sigma": 0.27,
8
+ "copies": 64,
9
  "steps": 20000,
10
+ "failed": 5,
11
+ "median_first_failure": 11406,
12
+ "exposure": 1237505,
13
+ "failure_rate_per_step": 4.04038771560519e-06,
14
+ "steps_with_wrong_copies": 126,
15
+ "wrong_copies": 136,
16
+ "max_wrong_copies_in_a_step": 3,
17
+ "first_failure": [
18
+ null,
19
+ null,
20
+ null,
21
+ null,
22
+ null,
23
+ null,
24
+ null,
25
+ null,
26
+ null,
27
+ null,
28
+ null,
29
+ null,
30
+ null,
31
+ null,
32
+ null,
33
+ null,
34
+ 11406,
35
+ null,
36
+ null,
37
+ null,
38
+ null,
39
+ null,
40
+ null,
41
+ null,
42
+ null,
43
+ null,
44
+ 16645,
45
+ null,
46
+ 12976,
47
+ null,
48
+ null,
49
+ null,
50
+ null,
51
+ null,
52
+ null,
53
+ null,
54
+ null,
55
+ null,
56
+ null,
57
+ null,
58
+ null,
59
+ null,
60
+ 10094,
61
+ null,
62
+ null,
63
+ null,
64
+ 6384,
65
+ null,
66
+ null,
67
+ null,
68
+ null,
69
+ null,
70
+ null,
71
+ null,
72
+ null,
73
+ null,
74
+ null,
75
+ null,
76
+ null,
77
+ null,
78
+ null,
79
+ null,
80
+ null,
81
+ null
82
+ ],
83
+ "seconds": 207.45457119197818
84
  },
85
  {
86
  "sigma": 0.3,
87
+ "copies": 64,
88
+ "steps": 20000,
89
+ "failed": 63,
90
+ "median_first_failure": 2915,
91
+ "exposure": 295163,
92
+ "failure_rate_per_step": 0.00021344138662366218,
93
+ "steps_with_wrong_copies": 662,
94
+ "wrong_copies": 795,
95
+ "max_wrong_copies_in_a_step": 15,
96
+ "first_failure": [
97
+ 1289,
98
+ 1699,
99
+ 1009,
100
+ 13088,
101
+ 8295,
102
+ 8217,
103
+ 865,
104
+ 887,
105
+ 4749,
106
+ 376,
107
+ 332,
108
+ 2307,
109
+ 2054,
110
+ 2915,
111
+ 3220,
112
+ 410,
113
+ 10239,
114
+ 10535,
115
+ 5621,
116
+ 8143,
117
+ 18583,
118
+ 2592,
119
+ 15730,
120
+ 6922,
121
+ 6739,
122
+ 3364,
123
+ 2861,
124
+ 711,
125
+ 701,
126
+ 11579,
127
+ 755,
128
+ 3925,
129
+ 1298,
130
+ 5957,
131
+ 4032,
132
+ null,
133
+ 259,
134
+ 261,
135
+ 2632,
136
+ 3171,
137
+ 12493,
138
+ 11725,
139
+ 7126,
140
+ 5570,
141
+ 7546,
142
+ 3554,
143
+ 494,
144
+ 1364,
145
+ 4900,
146
+ 2511,
147
+ 5602,
148
+ 1506,
149
+ 362,
150
+ 11745,
151
+ 7285,
152
+ 4452,
153
+ 413,
154
+ 2186,
155
+ 339,
156
+ 76,
157
+ 1551,
158
+ 684,
159
+ 3044,
160
+ 313
161
+ ],
162
+ "seconds": 381.3582687800226
163
  },
164
  {
165
  "sigma": 0.33,
166
+ "copies": 64,
167
+ "steps": 1280,
168
+ "failed": 64,
169
+ "median_first_failure": 198,
170
+ "exposure": 17472,
171
+ "failure_rate_per_step": 0.003663003663003663,
172
+ "steps_with_wrong_copies": 450,
173
+ "wrong_copies": 574,
174
+ "max_wrong_copies_in_a_step": 3,
175
+ "first_failure": [
176
+ 153,
177
+ 73,
178
+ 68,
179
+ 129,
180
+ 391,
181
+ 48,
182
+ 198,
183
+ 535,
184
+ 92,
185
+ 261,
186
+ 210,
187
+ 912,
188
+ 597,
189
+ 65,
190
+ 315,
191
+ 29,
192
+ 140,
193
+ 172,
194
+ 685,
195
+ 199,
196
+ 62,
197
+ 53,
198
+ 396,
199
+ 97,
200
+ 1,
201
+ 264,
202
+ 59,
203
+ 707,
204
+ 82,
205
+ 175,
206
+ 51,
207
+ 544,
208
+ 498,
209
+ 787,
210
+ 293,
211
+ 230,
212
+ 258,
213
+ 146,
214
+ 45,
215
+ 130,
216
+ 355,
217
+ 280,
218
+ 238,
219
+ 153,
220
+ 422,
221
+ 60,
222
+ 186,
223
+ 228,
224
+ 64,
225
+ 146,
226
+ 290,
227
+ 34,
228
+ 1280,
229
+ 241,
230
+ 27,
231
+ 178,
232
+ 332,
233
+ 78,
234
+ 39,
235
+ 74,
236
+ 226,
237
+ 1046,
238
+ 747,
239
+ 598
240
+ ],
241
+ "seconds": 25.771730831998866
242
  },
243
  {
244
  "sigma": 0.36,
245
+ "copies": 64,
246
+ "steps": 166,
247
+ "failed": 64,
248
+ "median_first_failure": 25,
249
+ "exposure": 2188,
250
+ "failure_rate_per_step": 0.029250457038391225,
251
+ "steps_with_wrong_copies": 301,
252
+ "wrong_copies": 453,
253
+ "max_wrong_copies_in_a_step": 9,
254
+ "first_failure": [
255
+ 10,
256
+ 96,
257
+ 22,
258
+ 14,
259
+ 32,
260
+ 2,
261
+ 166,
262
+ 27,
263
+ 8,
264
+ 14,
265
+ 10,
266
+ 39,
267
+ 17,
268
+ 14,
269
+ 21,
270
+ 26,
271
+ 61,
272
+ 54,
273
+ 2,
274
+ 16,
275
+ 40,
276
+ 36,
277
+ 11,
278
+ 29,
279
+ 18,
280
+ 19,
281
+ 58,
282
+ 23,
283
+ 55,
284
+ 7,
285
+ 54,
286
+ 1,
287
+ 8,
288
+ 82,
289
+ 11,
290
+ 3,
291
+ 40,
292
+ 34,
293
+ 39,
294
+ 12,
295
+ 84,
296
+ 4,
297
+ 38,
298
+ 19,
299
+ 94,
300
+ 7,
301
+ 32,
302
+ 58,
303
+ 45,
304
+ 10,
305
+ 3,
306
+ 84,
307
+ 106,
308
+ 45,
309
+ 16,
310
+ 24,
311
+ 47,
312
+ 16,
313
+ 89,
314
+ 40,
315
+ 25,
316
+ 2,
317
+ 57,
318
+ 12
319
+ ],
320
+ "seconds": 3.35292315701372
321
  }
322
  ]
323
  }
paper/universal_construction_ternary.pdf CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:b7d5d0db83aea194995f36ddcbb899845b6a449a4fee151b585480f5d3a9b154
3
- size 342177
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:65149cc8b925e0925a8d0ffd77a3d607204e0f41545b6c4c1a926cc32310a581
3
+ size 350216
paper/universal_construction_ternary.tex CHANGED
@@ -165,7 +165,10 @@ and its probability of leaving an orbit within $T$ steps under read noise of
165
  deviation $s$ is at most $T\,rM\erfc(r/2\sqrt2 s)$, so any noise level is
166
  survived with redundancy $O(s\sqrt{\log(TM/\delta)})$, and with
167
  $O(\sigma^2\log(TM/\delta))$ when the noise sits on every synapse
168
- (Theorem~\ref{thm:amplify}, Corollary~\ref{cor:synapse}). The threefold host
 
 
 
169
  completes the self-reproducing run at noise levels at which the host fails within
170
  its first bytes (Section~\ref{sec:amplify}).
171
  \end{enumerate}
@@ -1527,12 +1530,69 @@ self-reproducing instance $\Omega^\ast$ of the host emits the whole instance at
1527
  $s=0.10$, $0.15$, $0.20$ and $0.25$, where the host itself fails at $s=0.10$
1528
  after $143$ bytes and at $s=0.15$ and $0.20$ before emitting one
1529
  (Table~\ref{tab:noise3}). The replicated state leaves its orbit far more often
1530
- than the computation fails. A single wrong copy is outvoted in the next layer,
1531
  so the measured rate at which the state deviates is close to the bound of
1532
  Theorem~\ref{thm:amplify}(ii) restricted to the last layer, between a tenth and
1533
- a twentieth of the whole bound (Table~\ref{tab:curve3}), and the computation
1534
- fails only when two copies of one signal are wrong together, which in runs of
1535
- $20{,}000$ steps first happened at $s=0.30$ (Appendix~\ref{app:measure}).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1536
 
1537
 
1538
  % =============================================================================
@@ -2354,19 +2414,37 @@ by at most a factor of $1.6$ up to $s=0.36$, where errors meeting in the last tw
2354
  layers add to it.
2355
 
2356
  A copy of the state that deviates is not a failure of the computation, since a
2357
- single wrong copy of a state bit is outvoted at the next step. One exact and one
2358
- noisy copy of $N_3$ were stepped together from the initial state of the
2359
- self-describing instance for up to $20{,}000$ steps, every copy of every state
2360
- bit of the noisy run compared with the exact run after each step. At $s=0.24$ no
2361
- copy was wrong; at $s=0.27$ one copy of one bit was wrong at each of two steps
2362
- and right again at the next, and the state read by majority was exact
2363
- throughout; at $s=0.30$, $0.33$ and $0.36$ the state read by majority was first
2364
- wrong at steps $288$, $110$ and $38$. The computation fails when a flip halves the
2365
- margin of the rows reading it and two copies of one of those rows then fail
2366
- together, an event of second order in the probability of a flip, which is why
2367
- the complete run survives $s=0.25$ although the replicated state leaves its
2368
- orbit there at about $6\times10^{-6}$ per step, the last-layer rate, some ten
2369
- times over the run.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2370
 
2371
  \begin{table}[ht]
2372
  \centering\small
 
165
  deviation $s$ is at most $T\,rM\erfc(r/2\sqrt2 s)$, so any noise level is
166
  survived with redundancy $O(s\sqrt{\log(TM/\delta)})$, and with
167
  $O(\sigma^2\log(TM/\delta))$ when the noise sits on every synapse
168
+ (Theorem~\ref{thm:amplify}, Corollary~\ref{cor:synapse}). The state read by
169
+ majority fails only when two wrong copies meet, an event of second order whose
170
+ probability certifies the complete run of the threefold host where the
171
+ first-order bound exceeds one (Proposition~\ref{prop:restore}), and that host
172
  completes the self-reproducing run at noise levels at which the host fails within
173
  its first bytes (Section~\ref{sec:amplify}).
174
  \end{enumerate}
 
1530
  $s=0.10$, $0.15$, $0.20$ and $0.25$, where the host itself fails at $s=0.10$
1531
  after $143$ bytes and at $s=0.15$ and $0.20$ before emitting one
1532
  (Table~\ref{tab:noise3}). The replicated state leaves its orbit far more often
1533
+ than the computation fails: a single wrong copy is outvoted in the next layer,
1534
  so the measured rate at which the state deviates is close to the bound of
1535
  Theorem~\ref{thm:amplify}(ii) restricted to the last layer, between a tenth and
1536
+ a twentieth of the whole bound (Table~\ref{tab:curve3}), while the computation
1537
+ fails only when two wrong copies meet. The probability of that event is of
1538
+ second order in the probability of a flip.
1539
+
1540
+ \begin{proposition}[Restoration]\label{prop:restore}
1541
+ Let the perturbations of $N_3$ be independent centred Gaussians of standard
1542
+ deviation $s$ on every pre-activation, and put $p=Q(3/(2s))$ and
1543
+ $\sigma=Q(1/(2s))$. Unroll $\Lev(\Nhost)$ over the steps, the rows of layer~$1$ of
1544
+ each step reading the rows of layer~$L$ of the step before, and write $u\to v$
1545
+ when row $v$ reads row $u$. For values $x$ on the rows of a layer, every copy of a
1546
+ row $w$ carrying $x_w$, let $\pi(x)$ be the sum of $x_wx_{w'}$ over the unordered
1547
+ pairs of distinct copies that some row of the next layer reads, together with
1548
+ the pairs of copies of one row when the layer is the last. Let $a$ be the least
1549
+ solution of $a_v=p+3\sigma\sum_{u\to v}a_u$; for a row $u$ let $V^u$ be the least
1550
+ solution of $V^u_v=\sigma[u\to v]+3\sigma\sum_{w\to v}V^u_w$, let $G_u$ be the sum of
1551
+ $\pi(V^u)$ over the layers after $u$, and let $X_u=G_u-3\sigma^2\sum_{u\to v}G_v$.
1552
+ Then the probability that the state of $N_3$ read by majority differs from the
1553
+ orbit at some step $t\le T$ is at most
1554
+ \[
1555
+ T\Bigl(\sum_{\ell}\pi(a)+3\sum_{u}a_u\min(1,X_u)\Bigr),
1556
+ \]
1557
+ the sums over the layers and the rows of one step.
1558
+ \end{proposition}
1559
+
1560
+ \begin{proof}
1561
+ Call a copy wrong when its output differs from the replicated orbit. By
1562
+ Proposition~\ref{prop:amplify}(ii) and~(iii), a copy that reads no wrong copy is
1563
+ wrong only if its perturbation carries it across its distance
1564
+ $3|z+\tfrac12|\ge\tfrac32$ from the comparator, and a copy that reads one wrong
1565
+ copy only if its perturbation carries it across a distance of at least $\tfrac12$;
1566
+ the first event has probability at most $p$, the second at most $\sigma$, and each
1567
+ depends on the perturbation of that copy alone. Call two wrong copies that some
1568
+ row reads, or two wrong copies of one row of the last layer, a \emph{collision};
1569
+ the device reads and writes every register by majority, so the state read by
1570
+ majority is wrong only after a collision. Before the first collision every row
1571
+ reads at most one wrong copy, so a wrong copy either reads none, and its first
1572
+ event occurred, or reads exactly one, its parent, and its second event occurred;
1573
+ following parents gives a chain from a copy of the first kind. The two copies of
1574
+ the first collision therefore end two chains that are disjoint or share an
1575
+ initial segment up to a last common copy $z$, after which they continue as two
1576
+ paths through distinct copies. Distinct copies have independent perturbations,
1577
+ so such a configuration occurs with probability at most the product of $p$ for
1578
+ the first copy of each chain and $\sigma$ for every other copy.
1579
+
1580
+ The sum of these products over the chains ending at a copy of $v$ is $a_v$, and
1581
+ over the paths from one copy of $u$ to a copy of $v$ it is $V^u_v$, every copy of a
1582
+ row reading all three copies of its inputs. Pairs of disjoint chains whose ends
1583
+ collide in one step therefore contribute at most $\sum_\ell\pi(a)$. For a
1584
+ configuration parting at a copy $z$ of $u$, the chain to $z$ and the paths after
1585
+ it involve disjoint copies, so its probability is at most $a_u$ times the
1586
+ probability that two paths leaving $z$ through distinct copies reach a collision.
1587
+ The pairs of paths from $z$ that reach a collision number $G_u$ in expectation,
1588
+ and those that leave $z$ through the same copy of a consumer $v$ number
1589
+ $\sigma^2G_v$ for each of its three copies, so the pairs that part at $z$ number at
1590
+ most $X_u$ in expectation and occur with probability at most $\min(1,X_u)$.
1591
+ Summing over the three copies of every row and over the $T$ steps at which the
1592
+ first collision can occur gives the bound.
1593
+ \end{proof}
1594
+
1595
+ For the self-reproducing run, $T=1{,}664{,}939$, the bound of Proposition~\ref{prop:restore} is $3.80\times10^{-6}$ at $s=0.20$, where Theorem~\ref{thm:amplify}(ii) gives $1.34\times10^{-2}$, and $2.98\times10^{-3}$ at $s=0.22$, where that bound exceeds one; from $s=0.25$ on it exceeds one as well, and from $s=0.33$ its sums diverge (Table~\ref{tab:bound3}). Along the orbit, over $64$ noisy copies, the state read by majority failed at $4.04\times10^{-6}$ per step at $s=0.27$ and $2.13\times10^{-4}$ at $s=0.30$, below the bound by factors of $23$ and $53$, and $21$ and $12$ times less often than the replicated state left its orbit.
1596
 
1597
 
1598
  % =============================================================================
 
2414
  layers add to it.
2415
 
2416
  A copy of the state that deviates is not a failure of the computation, since a
2417
+ single wrong copy of a state bit is outvoted at the next step.
2418
+ Table~\ref{tab:bound3} measures the failure itself: one exact and $64$ noisy
2419
+ copies of $N_3$ were stepped together from the initial state of the
2420
+ self-describing instance for up to $20{,}000$ steps, the state of each noisy copy
2421
+ read by majority and compared with the exact state after every step, and each
2422
+ noisy copy stopped at its first wrong majority-read state. The restoration bound
2423
+ of Proposition~\ref{prop:restore} is computed with the worst margins, every row
2424
+ at distance $\tfrac12$ from the comparator, so it holds along every orbit; along
2425
+ this one most rows of the decoders sit at distance at least $\tfrac32$, which is
2426
+ why it lies one to two orders of magnitude above the measured rate.
2427
+
2428
+ \begin{table}[ht]
2429
+ \centering\small
2430
+ \begin{tabular}{@{}lrrlll@{}}
2431
+ \toprule
2432
+ $s$ & Failed & Exposure & Measured rate & Restoration bound & $rM\erfc(r/2\sqrt2s)$\\
2433
+ \midrule
2434
+ $0.10$ & --- & --- & --- & $2.13\times10^{-57}$ & $9.24\times10^{-46}$\\
2435
+ $0.15$ & --- & --- & --- & $9.96\times10^{-24}$ & $1.92\times10^{-18}$\\
2436
+ $0.20$ & --- & --- & --- & $2.28\times10^{-12}$ & $8.03\times10^{-9}$\\
2437
+ $0.22$ & --- & --- & --- & $1.79\times10^{-9}$ & $1.16\times10^{-6}$\\
2438
+ $0.25$ & --- & --- & --- & $2.10\times10^{-6}$ & $2.48\times10^{-4}$\\
2439
+ $0.27$ & 5/64 & 1{,}237{,}505 & $4.04\times10^{-6}$ & $9.28\times10^{-5}$ & $3.48\times10^{-3}$\\
2440
+ $0.30$ & 63/64 & 295{,}163 & $2.13\times10^{-4}$ & $1.14\times10^{-2}$ & $7.22\times10^{-2}$\\
2441
+ $0.33$ & 64/64 & 17{,}472 & $3.66\times10^{-3}$ & diverges & $6.90\times10^{-1}$\\
2442
+ $0.36$ & 64/64 & 2{,}188 & $2.93\times10^{-2}$ & diverges & $3.89$\\
2443
+ \bottomrule
2444
+ \end{tabular}
2445
+ \caption{The per-step probability that the state of $N_3$ read by majority leaves the orbit under read noise of standard deviation $s$: $64$ noisy copies stepped beside an exact one from the initial state of the self-describing instance for up to $20{,}000$ steps, each stopped at its first wrong majority-read state, against the bound of Proposition~\ref{prop:restore} per step and the first-order bound of Theorem~\ref{thm:amplify}(ii). From $s=0.33$ the sums defining the restoration bound diverge.}
2446
+ \label{tab:bound3}
2447
+ \end{table}
2448
 
2449
  \begin{table}[ht]
2450
  \centering\small
src/redundant.py CHANGED
@@ -129,7 +129,7 @@ class Amplified:
129
  if ell == 1:
130
  idx = [c * n + k for k, w in ins for c in range(r)]
131
  else:
132
- idx = [r * (k - base[ell - 1]) + c for k, w in ins for c in range(r)]
133
  w = [wt for k, wt in ins for c in range(r)]
134
  for c in range(r):
135
  rows_of.append((m * r + c, idx, w, r * b + (r - 1) // 2))
@@ -590,31 +590,35 @@ def cmd_curve(args) -> int:
590
 
591
 
592
  def cmd_restore(args) -> int:
593
- """Restoration along the orbit: one exact and one noisy copy of N_r from the
594
- initial state of the self-describing instance. After every step the copies
595
- of every state bit of the noisy run are compared with the exact run: a
596
- wrong copy is counted, and the state read by majority over the r copies is
597
- compared with the exact state. The run stops at the first step whose
598
- majority-read state is wrong, or after the given number of steps."""
 
599
  import torch
600
  amp = build_amplified(args.r)
601
  sigma = read_host()
602
  r_H = describe(sigma)
603
  E = Evaluator(amp, device=args.device, pad=False)
604
  n, r = amp.n, args.r
 
605
  grid = [float(x) for x in args.grid.split(",")]
606
  rows = []
607
- print(f"[restore] N_{r}: {args.steps:,} steps per level", flush=True)
608
  for s in grid:
609
  gen = torch.Generator(device=args.device).manual_seed(31 + int(1000 * s))
610
- v = E.vec(0, M_P, copies=2)
611
- tapes = [Tape(r_H) for _ in range(2)]
612
- shadow = [[0] * 256 for _ in range(2)]
613
- copy_errors = steps_with = worst = 0
614
- carried = 0
615
- prev = None
616
- decoded_first = None
 
617
  t0 = time.perf_counter()
 
618
  for t in range(args.steps):
619
  x = v
620
  for width, groups in E.plan:
@@ -626,38 +630,234 @@ def cmd_restore(args) -> int:
626
  y[:, rws] = ((pre + noise) >= -0.5).float()
627
  x = y
628
  v = x[:, E.perm]
629
- wrong = (v[1] != v[0]).reshape(r, n)
630
- k = int(wrong.sum())
631
- if k:
632
- copy_errors += k
633
- steps_with += 1
634
- worst = max(worst, k)
635
- if prev is not None:
636
- carried += int((wrong & prev).sum())
637
- prev = wrong
638
- maj = (v[1].reshape(r, n).sum(0) * 2 > r)
639
- if bool((maj != (v[0, :n] > 0.5)).any()):
640
- decoded_first = t + 1
 
 
 
 
641
  break
642
  E.device_step(v, tapes, shadow)
643
  dt = time.perf_counter() - t0
644
- ran = decoded_first or args.steps
645
- rows.append({"sigma": s, "steps": ran, "copy_errors": copy_errors,
646
- "steps_with_copy_errors": steps_with, "max_copy_errors_in_a_step": worst,
647
- "copy_errors_carried_to_next_step": carried,
648
- "decoded_first_deviation": decoded_first,
649
- "bytes": len(tapes[1].out), "bytes_equal": tapes[1].out == tapes[0].out,
650
- "seconds": dt})
651
- print(f" s={s:.2f}: {ran:,} steps; {steps_with:,} steps with a wrong copy, "
652
- f"{copy_errors:,} wrong copies in all, at most {worst} in one step, {carried} still "
653
- f"wrong a step later; majority-read state "
654
- f"{'exact throughout' if decoded_first is None else f'wrong at step {decoded_first:,}'} "
655
- f"({dt / 60:.1f} min)", flush=True)
656
- json.dump({"r": r, "steps": args.steps, "rows": rows},
657
  open(runs_path(f"paper_redundant_restore_r{r}.json"), "w"), indent=1)
658
  return 0
659
 
660
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
661
  def cmd_layers(args) -> int:
662
  """The profile bound of N_r split by layer.
663
 
@@ -720,7 +920,7 @@ def cmd_layers(args) -> int:
720
 
721
  def main() -> int:
722
  ap = argparse.ArgumentParser()
723
- ap.add_argument("mode", choices=["build", "selfrep", "omega", "curve", "restore", "layers"])
724
  ap.add_argument("--r", type=int, default=3)
725
  ap.add_argument("--cc", default="gcc")
726
  ap.add_argument("--device", default="cuda")
@@ -735,10 +935,12 @@ def main() -> int:
735
  if args.grid is None:
736
  args.grid = {"omega": "0.10,0.15,0.20,0.25",
737
  "curve": "0.06,0.12,0.18,0.24,0.27,0.30,0.33,0.36,0.45,0.60",
738
- "restore": "0.24,0.27,0.30,0.33,0.36",
739
- "layers": "0.06,0.12,0.18,0.24,0.27,0.30,0.33,0.36,0.45,0.60"}.get(args.mode, "")
 
740
  return {"build": cmd_build, "selfrep": cmd_selfrep, "omega": cmd_omega,
741
- "curve": cmd_curve, "restore": cmd_restore, "layers": cmd_layers}[args.mode](args)
 
742
 
743
 
744
  if __name__ == "__main__":
 
129
  if ell == 1:
130
  idx = [c * n + k for k, w in ins for c in range(r)]
131
  else:
132
+ idx = [r * (k - base[ell - 2]) + c for k, w in ins for c in range(r)]
133
  w = [wt for k, wt in ins for c in range(r)]
134
  for c in range(r):
135
  rows_of.append((m * r + c, idx, w, r * b + (r - 1) // 2))
 
590
 
591
 
592
  def cmd_restore(args) -> int:
593
+ """Restoration along the orbit: one exact and B noisy copies of N_r stepped
594
+ together from the initial state of the self-describing instance. After every
595
+ step the copies of every state bit of each noisy run are compared with the
596
+ exact run, and the state read by majority over the r copies is compared with
597
+ the exact state; a run is stopped at its first step whose majority-read state
598
+ is wrong, and the rate of that event per step of exposure is recorded with
599
+ the counts of wrong copies seen before it."""
600
  import torch
601
  amp = build_amplified(args.r)
602
  sigma = read_host()
603
  r_H = describe(sigma)
604
  E = Evaluator(amp, device=args.device, pad=False)
605
  n, r = amp.n, args.r
606
+ B = args.batch
607
  grid = [float(x) for x in args.grid.split(",")]
608
  rows = []
609
+ print(f"[restore] N_{r}: {B} noisy copies, up to {args.steps:,} steps per level", flush=True)
610
  for s in grid:
611
  gen = torch.Generator(device=args.device).manual_seed(31 + int(1000 * s))
612
+ v = E.vec(0, M_P, copies=B + 1)
613
+ tapes = [Tape(r_H) for _ in range(B + 1)]
614
+ shadow = [[0] * 256 for _ in range(B + 1)]
615
+ first = [None] * B
616
+ wrong_copy_steps = 0
617
+ wrong_copies = 0
618
+ worst = 0
619
+ live = torch.ones(B, dtype=torch.bool)
620
  t0 = time.perf_counter()
621
+ ran = args.steps
622
  for t in range(args.steps):
623
  x = v
624
  for width, groups in E.plan:
 
630
  y[:, rws] = ((pre + noise) >= -0.5).float()
631
  x = y
632
  v = x[:, E.perm]
633
+ ex = v[0].reshape(r, n)
634
+ wrong = (v[1:].reshape(B, r, n) != ex.unsqueeze(0))
635
+ k = wrong.sum(dim=(1, 2)).cpu()
636
+ maj = (v[1:].reshape(B, r, n).sum(1) * 2 > r)
637
+ bad = (maj != (ex[0] > 0.5).unsqueeze(0)).any(1).cpu()
638
+ for i in range(B):
639
+ if live[i]:
640
+ if int(k[i]):
641
+ wrong_copy_steps += 1
642
+ wrong_copies += int(k[i])
643
+ worst = max(worst, int(k[i]))
644
+ if bool(bad[i]):
645
+ first[i] = t + 1
646
+ live[i] = False
647
+ if not bool(live.any()):
648
+ ran = t + 1
649
  break
650
  E.device_step(v, tapes, shadow)
651
  dt = time.perf_counter() - t0
652
+ failed = [f for f in first if f is not None]
653
+ exposure = sum(f if f is not None else ran for f in first)
654
+ rows.append({"sigma": s, "copies": B, "steps": ran, "failed": len(failed),
655
+ "median_first_failure": sorted(failed)[len(failed) // 2] if failed else None,
656
+ "exposure": exposure, "failure_rate_per_step": len(failed) / exposure,
657
+ "steps_with_wrong_copies": wrong_copy_steps, "wrong_copies": wrong_copies,
658
+ "max_wrong_copies_in_a_step": worst, "first_failure": first, "seconds": dt})
659
+ print(f" s={s:.2f}: {len(failed)}/{B} majority-read failures within {ran:,} steps, "
660
+ f"exposure {exposure:,}, rate {len(failed) / exposure:.3e} per step; "
661
+ f"{wrong_copies:,} wrong copies in {wrong_copy_steps:,} copy-steps before the "
662
+ f"failures ({dt / 60:.1f} min)", flush=True)
663
+ json.dump({"r": r, "copies": B, "cap": args.steps, "rows": rows},
 
664
  open(runs_path(f"paper_redundant_restore_r{r}.json"), "w"), indent=1)
665
  return 0
666
 
667
 
668
+ class _Inc:
669
+ """The 0/1 incidence of one layer, applied by gathering and adding."""
670
+
671
+ def __init__(self, rows, cols, shape, device):
672
+ import torch
673
+ self.rows = torch.tensor(rows, dtype=torch.long, device=device)
674
+ self.cols = torch.tensor(cols, dtype=torch.long, device=device)
675
+ self.shape = shape
676
+
677
+ def mm(self, V):
678
+ import torch
679
+ out = torch.zeros((self.shape[0],) + tuple(V.shape[1:]), dtype=V.dtype, device=V.device)
680
+ out.index_add_(0, self.rows, V[self.cols])
681
+ return out
682
+
683
+ def column_block(self, cols):
684
+ """The dense block of the columns `cols`, as a matrix."""
685
+ import torch
686
+ pos = torch.full((self.shape[1],), -1, dtype=torch.long, device=self.rows.device)
687
+ pos[cols] = torch.arange(len(cols), device=self.rows.device)
688
+ keep = pos[self.cols] >= 0
689
+ out = torch.zeros(self.shape[0], len(cols), dtype=torch.float64, device=self.rows.device)
690
+ out[self.rows[keep], pos[self.cols[keep]]] = 1.0
691
+ return out
692
+
693
+
694
+ def incidence(amp: "Amplified", device: str):
695
+ """The 0/1 incidence of every layer of Lev(N_host): entry (i, j) of layer l
696
+ is 1 when row i of layer l reads row j of layer l-1, layer 0 being the
697
+ state."""
698
+ n = amp.n
699
+ base = [n]
700
+ for L in amp.layers:
701
+ base.append(base[-1] + L)
702
+ mats, j0 = [], 0
703
+ for ell, L in enumerate(amp.layers, start=1):
704
+ rows, cols = [], []
705
+ for m in range(L):
706
+ _, ins = amp.lev_units[j0 + m]
707
+ for k, w in ins:
708
+ rows.append(m)
709
+ cols.append(k if ell == 1 else k - base[ell - 2])
710
+ j0 += L
711
+ width_prev = n if ell == 1 else amp.layers[ell - 2]
712
+ mats.append(_Inc(rows, cols, (L, width_prev), device))
713
+ return mats
714
+
715
+
716
+ def consumer_sharing(mats, device):
717
+ """For every layer l, the indicator B_l over the rows of layer l-1 of
718
+ reading by a common row of layer l: B_l[j, k] = 1 when some row of layer l
719
+ reads both j and k, B_l[j, j] = 1 when row j has a consumer. Stored as
720
+ booleans."""
721
+ import torch
722
+ out = []
723
+ for A in mats:
724
+ D = A.column_block(torch.arange(A.shape[1], device=device)).float()
725
+ out.append((D.T @ D) > 0)
726
+ del D
727
+ return out
728
+
729
+
730
+ def restoration_bound(mats, shares, n: int, s: float, device: str, chunk: int = 1024):
731
+ """The bound of Proposition 6.14 on the per-step probability that the state
732
+ of N_3 read by majority leaves the orbit, for Gaussian perturbations of
733
+ deviation s on every pre-activation.
734
+
735
+ p bounds the probability that a copy with exact inputs fails and sigma the
736
+ probability that a copy with one wrong input copy fails. a_i is the sum over
737
+ chains of perturbations ending at one copy of row i, stationary over the
738
+ steps. A failure needs two wrong copies that one row reads or that one
739
+ bundle of the last layer holds; each such pair of copies is counted once.
740
+ The first term takes the two copies from separate chains, and the second,
741
+ for every copy z at which two chains part, weighs by a_z the number of such
742
+ pairs its cascade reaches, the cascade continued into later steps through
743
+ the quadratic form of one step."""
744
+ import torch
745
+ q = lambda u: 0.5 * math.erfc(u / math.sqrt(2.0))
746
+ p, sg = q(1.5 / s), q(0.5 / s)
747
+ L = len(mats)
748
+
749
+ def pairs(ell, V):
750
+ """Pairs of distinct copies among the values V on the rows of layer
751
+ ell-1 that some row of layer ell reads, counted once: three per row with
752
+ a consumer, nine per pair of rows with a common consumer."""
753
+ B = shares[ell - 1].to(torch.float64)
754
+ d = torch.diagonal(B).unsqueeze(1) if V.dim() == 2 else torch.diagonal(B)
755
+ return 4.5 * (V * (B @ V)).sum(0) - 1.5 * (d * V ** 2).sum(0)
756
+
757
+ a_state = torch.zeros(n, dtype=torch.float64, device=device)
758
+ for it in range(400):
759
+ a = [a_state]
760
+ for A in mats:
761
+ a.append(p + 3 * sg * A.mm(a[-1]))
762
+ change = float((a[-1] - a_state).abs().max())
763
+ a_state = a[-1]
764
+ if change <= 1e-13 * float(a_state.abs().max()) + 1e-300:
765
+ break
766
+ else:
767
+ return {"sigma": s, "p": p, "sigma_link": sg, "converged": False}
768
+ first = sum(float(pairs(ell, a[ell - 1])) for ell in range(1, L + 1)) + 3 * float((a[L] ** 2).sum())
769
+
770
+ def through(V, start):
771
+ """Collisions of per-copy values V held at layer start-1, carried
772
+ through layers start..L, and the values reaching the last layer."""
773
+ G = torch.zeros(V.shape[1], dtype=torch.float64, device=device)
774
+ for ell in range(start, L + 1):
775
+ G += pairs(ell, V)
776
+ V = 3 * sg * mats[ell - 1].mm(V)
777
+ return G + 3 * (V ** 2).sum(0), V
778
+
779
+ # the quadratic form of one step entered with per-copy values x on the state
780
+ V = torch.eye(n, dtype=torch.float64, device=device)
781
+ Qm = torch.zeros(n, n, dtype=torch.float64, device=device)
782
+ for ell in range(1, L + 1):
783
+ B = shares[ell - 1].to(torch.float64)
784
+ dg = torch.diagonal(B)
785
+ Qm += 4.5 * V.T @ (B @ V) - 1.5 * V.T @ (dg.unsqueeze(1) * V)
786
+ del B
787
+ V = 3 * sg * mats[ell - 1].mm(V)
788
+ Qm += 3 * V.T @ V
789
+ T = V
790
+ Qtot, M = Qm.clone(), T.clone()
791
+ for k in range(200):
792
+ add = M.T @ Qm @ M
793
+ Qtot += add
794
+ if float(add.abs().max()) <= 1e-14 * float(Qtot.abs().max()):
795
+ break
796
+ M = T @ M
797
+ rho = float(torch.linalg.matrix_norm(T, ord=2))
798
+ if not (rho < 1.0 and math.isfinite(float(Qtot.abs().max())) and math.isfinite(float(a_state.max()))):
799
+ return {"sigma": s, "p": p, "sigma_link": sg, "converged": False, "one_step_map_norm": rho}
800
+
801
+ # G[ell][u]: colliding pairs reached from one copy of row u of layer ell
802
+ Gs = [None] * (L + 1)
803
+ for ell in range(1, L + 1):
804
+ width = mats[ell - 1].shape[0]
805
+ out = torch.empty(width, dtype=torch.float64, device=device)
806
+ for c0 in range(0, width, chunk):
807
+ cols = torch.arange(c0, min(width, c0 + chunk), device=device)
808
+ if ell < L:
809
+ V = sg * mats[ell].column_block(cols) # consumers of one copy
810
+ G, V = through(V, ell + 2)
811
+ else:
812
+ V = sg * mats[0].column_block(cols) # the next step's first layer
813
+ G, V = through(V, 2)
814
+ out[cols] = G + (V * (Qtot @ V)).sum(0)
815
+ Gs[ell] = out
816
+ # X[ell][u]: the pairs whose two paths part at the copy itself, which is
817
+ # G less the pairs whose paths leave through one child c, sigma^2 G(c)
818
+ second, second_uncapped = 0.0, 0.0
819
+ for ell in range(1, L + 1):
820
+ nxt = mats[ell] if ell < L else mats[0]
821
+ Gc = Gs[ell + 1] if ell < L else Gs[1]
822
+ child = torch.zeros(Gs[ell].shape[0], dtype=torch.float64, device=device)
823
+ child.index_add_(0, nxt.cols, Gc[nxt.rows])
824
+ X = (Gs[ell] - 3 * sg ** 2 * child).clamp(min=0.0)
825
+ second += float((3 * a[ell] * X.clamp(max=1.0)).sum())
826
+ second_uncapped += float((3 * a[ell] * Gs[ell]).sum())
827
+ return {"sigma": s, "p": p, "sigma_link": sg, "converged": True,
828
+ "second_term_uncapped": second_uncapped,
829
+ "a_max": float(max(float(x.max()) for x in a[1:])),
830
+ "a_state_max": float(a_state.max()),
831
+ "first_term": first, "second_term": second, "per_step": first + second,
832
+ "one_step_map_norm": rho, "G_max": float(max(float(g.max()) for g in Gs[1:]))}
833
+
834
+
835
+ def cmd_bound(args) -> int:
836
+ """The restoration bound of Proposition 6.14 over a grid of noise levels,
837
+ beside the first-order bound of Theorem 6.9(ii)."""
838
+ import torch
839
+ amp = build_amplified(3)
840
+ mats = incidence(amp, args.device)
841
+ shares = consumer_sharing(mats, args.device)
842
+ M3 = 3 * sum(amp.layers)
843
+ rows = []
844
+ for s in [float(x) for x in args.grid.split(",")]:
845
+ t0 = time.perf_counter()
846
+ b = restoration_bound(mats, shares, amp.n, s, args.device)
847
+ b["first_order_per_step"] = M3 * math.erfc(3 / (2 * math.sqrt(2) * s))
848
+ b["seconds"] = time.perf_counter() - t0
849
+ rows.append(b)
850
+ if b["converged"]:
851
+ print(f" s={s:.2f}: p {b['p']:.3e}, sigma {b['sigma_link']:.3e}; restoration bound "
852
+ f"{b['per_step']:.3e} per step ({b['first_term']:.2e} + {b['second_term']:.2e}), "
853
+ f"first-order {b['first_order_per_step']:.3e}; one-step map norm "
854
+ f"{b['one_step_map_norm']:.3f} ({b['seconds']:.0f} s)", flush=True)
855
+ else:
856
+ print(f" s={s:.2f}: the chain sums do not converge", flush=True)
857
+ json.dump({"r": 3, "rows": rows}, open(runs_path("paper_redundant_bound_r3.json"), "w"), indent=1)
858
+ return 0
859
+
860
+
861
  def cmd_layers(args) -> int:
862
  """The profile bound of N_r split by layer.
863
 
 
920
 
921
  def main() -> int:
922
  ap = argparse.ArgumentParser()
923
+ ap.add_argument("mode", choices=["build", "selfrep", "omega", "curve", "restore", "layers", "bound"])
924
  ap.add_argument("--r", type=int, default=3)
925
  ap.add_argument("--cc", default="gcc")
926
  ap.add_argument("--device", default="cuda")
 
935
  if args.grid is None:
936
  args.grid = {"omega": "0.10,0.15,0.20,0.25",
937
  "curve": "0.06,0.12,0.18,0.24,0.27,0.30,0.33,0.36,0.45,0.60",
938
+ "restore": "0.27,0.30,0.33,0.36",
939
+ "layers": "0.06,0.12,0.18,0.24,0.27,0.30,0.33,0.36,0.45,0.60",
940
+ "bound": "0.10,0.15,0.20,0.22,0.25,0.27,0.30,0.33,0.36"}.get(args.mode, "")
941
  return {"build": cmd_build, "selfrep": cmd_selfrep, "omega": cmd_omega,
942
+ "curve": cmd_curve, "restore": cmd_restore, "layers": cmd_layers,
943
+ "bound": cmd_bound}[args.mode](args)
944
 
945
 
946
  if __name__ == "__main__":
src/verify.py CHANGED
@@ -91,7 +91,9 @@ TIER3 = [
91
  ("redundant.py", ["selfrep"], "exact self-reproduction of N_3 on the evaluator in C"),
92
  ("redundant.py", ["omega"], "Omega* on N_3 under read noise, to completion"),
93
  ("redundant.py", ["curve"], "the deviation rate of N_3 against the bounds"),
94
- ("redundant.py", ["restore"], "wrong copies of N_3 under noise, and the state read by majority"),
 
 
95
  ("redundant.py", ["layers"], "the profile bound of N_3 split by layer"),
96
  ]
97
 
 
91
  ("redundant.py", ["selfrep"], "exact self-reproduction of N_3 on the evaluator in C"),
92
  ("redundant.py", ["omega"], "Omega* on N_3 under read noise, to completion"),
93
  ("redundant.py", ["curve"], "the deviation rate of N_3 against the bounds"),
94
+ ("redundant.py", ["restore", "--batch", "64", "--steps", "20000"],
95
+ "the failure rate of the state of N_3 read by majority"),
96
+ ("redundant.py", ["bound"], "the restoration bound of N_3"),
97
  ("redundant.py", ["layers"], "the profile bound of N_3 split by layer"),
98
  ]
99