Commit ·
60d3c95
1
Parent(s): fb69925
Store the host in a two-head machine of 4096 cells so that it reproduces itself by the dynamics, prove the machine's netlist for every window size, add figures and the layouts behind the digests, and remove the interpreter tower and the verification tiers
Browse files- README.md +28 -30
- paper/README.md +7 -36
- paper/runs/independent_interpreter.json +0 -40
- paper/runs/paper_fanin2.json +0 -27
- paper/runs/paper_hierarchy.json +0 -33
- paper/runs/paper_hosted.json +0 -27
- paper/runs/paper_interp.json +0 -20
- paper/runs/paper_lev.json +1 -4
- paper/runs/paper_rocq.json +3 -1
- paper/runs/paper_stats.json +0 -100
- paper/runs/paper_stored_host.json +70 -0
- paper/runs/paper_twohead_net.json +33 -6
- paper/runs/paper_verify.json +1 -15
- paper/runs/paper_verify_times.json +0 -75
- paper/universal_construction_ternary.pdf +2 -2
- paper/universal_construction_ternary.tex +624 -607
- rocq/Assumptions.v +2 -0
- rocq/NetMain.v +36 -25
- rocq/Phys.v +22 -18
- rocq/PhysFacts.v +12 -8
- rocq/PhysMain.v +64 -47
- rocq/PhysSem.v +219 -156
- rocq/PhysWF.v +72 -10
- rocq/TwoHead.v +54 -0
- rocq/extract/dump.ml +5 -5
- src/check_interp.py +0 -117
- src/check_lev.py +2 -19
- src/fanin2.py +0 -220
- src/hierarchy.py +0 -148
- src/hosted_constructor.py +0 -653
- src/independent/interpreter.py +0 -495
- src/paper_stats.py +1 -28
- src/paper_verify.py +3 -59
- src/stored_host.py +694 -0
- src/stored_host_run.c +130 -0
- src/twohead.py +12 -10
- src/twohead_net.py +55 -27
- src/verify.py +0 -161
README.md
CHANGED
|
@@ -574,14 +574,18 @@ host, its initial memory and its own description tape; each generation is
|
|
| 574 |
instantiated from the bytes the last one emitted, by parsing that output,
|
| 575 |
rebuilding the netlist from its first field, and building the evaluator from
|
| 576 |
that netlist. It also shows where the restriction to {-1, 0, 1} is paid for,
|
| 577 |
-
that a fixed ternary network
|
| 578 |
`src/twohead_net.py`, holds a stored network in its state and evaluates one
|
| 579 |
-
record per step,
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
against perturbation, a certificate of the leakage an orbit tolerates from the
|
| 586 |
inputs active along it, and the amplified host of `src/redundant.py`: every row
|
| 587 |
of the levelized host replaced by r rows reading all r copies of its inputs,
|
|
@@ -590,17 +594,11 @@ wrong copies meet, with a probability of second order that the paper bounds, and
|
|
| 590 |
completes the self-reproducing run under read noise at levels where the host
|
| 591 |
fails within its first bytes.
|
| 592 |
|
| 593 |
-
|
| 594 |
-
every construction end to end; the checks of a tier run concurrently. `--tier 3` runs
|
| 595 |
-
the self-reproducing instance on the threshold evaluators, the perturbation
|
| 596 |
-
experiments and the amplified host, whose cost belongs to the object: one
|
| 597 |
-
generation is 1,664,939 steps of a map of 41,967 units, and the amplified host
|
| 598 |
-
reproduces itself in 33,796,449 steps of 125,901 units. The scripts that produce
|
| 599 |
-
every figure are `src/selfrep.py`, `src/netlist_io.py`, `src/host_family.py`,
|
| 600 |
`src/paper_stats.py`, `src/paper_verify.py`, `src/paper_runs.py`,
|
| 601 |
-
`src/twohead.py`, `src/twohead_net.py`, `src/
|
| 602 |
-
`src/
|
| 603 |
-
`src/redundant.py`, `src/
|
| 604 |
`src/check_*.py` set, and their records are in `paper/runs/`; `rocq/` holds the
|
| 605 |
Rocq development, which `src/check_rocq.py` builds.
|
| 606 |
|
|
@@ -995,7 +993,7 @@ src/ the library (run scripts as `python src/<nam
|
|
| 995 |
│ program P*, the framing maps, and three evaluators
|
| 996 |
├── canonical.py deterministic safetensors writer (pinned key and tensor order)
|
| 997 |
├── paper_stats.py unit counts, levelization sizes, effective fan-in
|
| 998 |
-
├── paper_verify.py codec, framing, serialization, datapath,
|
| 999 |
├── paper_runs.py self-description, three generations, lockstep
|
| 1000 |
├── host_family.py the host family H_A: a constant-depth SUBLEQ step for
|
| 1001 |
│ every word width, and its serialization in build order
|
|
@@ -1004,23 +1002,22 @@ src/ the library (run scripts as `python src/<nam
|
|
| 1004 |
├── check_c.py the host on the evaluator in C
|
| 1005 |
├── twohead.py the two-head machine, transcribed, the description code
|
| 1006 |
│ and the translating organism; writes rocq/Organism.v
|
| 1007 |
-
├── twohead_net.py the two-head machine as a ternary netlist N_{G,L}
|
| 1008 |
-
│ check, its file, the organism on it in C,
|
| 1009 |
-
│ comparison with the netlist extracted from rocq/
|
| 1010 |
├── twohead_lockstep.c the organism on N_{G,L} beside the transcription, in C
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1011 |
├── restore_bound.c the restoration bound of the amplified host along the orbit
|
| 1012 |
├── check_rocq.py builds rocq/ and prints the assumptions of its theorems
|
| 1013 |
├── independent/ separate code written from the paper's definitions: the host
|
| 1014 |
-
│ family, the levelization,
|
| 1015 |
-
│
|
| 1016 |
├── redundant.py the amplified host N_r: r-fold redundancy with the restoring
|
| 1017 |
│ organ inside every unit, its self-reproduction, its runs
|
| 1018 |
│ under read noise
|
| 1019 |
-
├── fanin2.py rewrites a netlist to effective fan-in two
|
| 1020 |
-
├── hierarchy.py a larger interpreter interpreting a netlist realizing a
|
| 1021 |
-
│ smaller one
|
| 1022 |
-
├── hosted_constructor.py the universal constructor as a netlist stored in the
|
| 1023 |
-
│ interpreter, with tape, output word and device in signals
|
| 1024 |
├── noise.py read noise on the self-reproducing run, the deviation curve
|
| 1025 |
│ against the bounds, weight error with zero-entry leakage, the
|
| 1026 |
│ active-input counts that certify an orbit
|
|
@@ -1030,8 +1027,9 @@ src/ the library (run scripts as `python src/<nam
|
|
| 1030 |
framing, serialization, all 29 machines
|
| 1031 |
paper/ the manuscript, and the record of every run it reports
|
| 1032 |
rocq/ Rocq proofs: the netlist of the two-head machine computes its
|
| 1033 |
-
step, the organism builds every
|
| 1034 |
-
of it and reproduces in every
|
|
|
|
| 1035 |
tools/ build_all.py (build + quantize + verify every profile),
|
| 1036 |
cpu_programs.py (assembler + CPU program suite), test_cpu.py
|
| 1037 |
(program suite vs a variant), play.py (interactive demo),
|
|
|
|
| 574 |
instantiated from the bytes the last one emitted, by parsing that output,
|
| 575 |
rebuilding the netlist from its first field, and building the evaluator from
|
| 576 |
that netlist. It also shows where the restriction to {-1, 0, 1} is paid for,
|
| 577 |
+
and that a fixed ternary network, the two-head machine of
|
| 578 |
`src/twohead_net.py`, holds a stored network in its state and evaluates one
|
| 579 |
+
record per step, which `rocq/` proves for every window of 2^α cells, bank and
|
| 580 |
+
tape. The host itself, compiled by `src/stored_host.py` into 36,074 records of
|
| 581 |
+
two inputs with records that load its memory, its tape device and a hand-over,
|
| 582 |
+
and stored in the member with 4096 cells, runs the 27-instruction program on a
|
| 583 |
+
recipe for its own records: it writes them into the idle bank, copies the recipe
|
| 584 |
+
and hands control to the copy, so that it reproduces itself, weights included,
|
| 585 |
+
by the dynamics alone; `src/stored_host_run.c` runs three generations of
|
| 586 |
+
79,464,240,088 steps each. An organism of 133 records on the member with 64
|
| 587 |
+
cells does the same with a description code of its own, every generation of it
|
| 588 |
+
proved in Rocq. Its robustness section gives the margin every orbit has
|
| 589 |
against perturbation, a certificate of the leakage an orbit tolerates from the
|
| 590 |
inputs active along it, and the amplified host of `src/redundant.py`: every row
|
| 591 |
of the levelized host replaced by r rows reading all r copies of its inputs,
|
|
|
|
| 594 |
completes the self-reproducing run under read noise at levels where the host
|
| 595 |
fails within its first bytes.
|
| 596 |
|
| 597 |
+
The scripts that produce every figure are `src/selfrep.py`, `src/netlist_io.py`, `src/host_family.py`,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 598 |
`src/paper_stats.py`, `src/paper_verify.py`, `src/paper_runs.py`,
|
| 599 |
+
`src/twohead.py`, `src/twohead_net.py`, `src/stored_host.py`,
|
| 600 |
+
`src/stored_host_run.c`, `src/check_c.py`, `src/throughput.py`, `src/noise.py`,
|
| 601 |
+
`src/redundant.py`, `src/neuromorphic.py` and the
|
| 602 |
`src/check_*.py` set, and their records are in `paper/runs/`; `rocq/` holds the
|
| 603 |
Rocq development, which `src/check_rocq.py` builds.
|
| 604 |
|
|
|
|
| 993 |
│ program P*, the framing maps, and three evaluators
|
| 994 |
├── canonical.py deterministic safetensors writer (pinned key and tensor order)
|
| 995 |
├── paper_stats.py unit counts, levelization sizes, effective fan-in
|
| 996 |
+
├── paper_verify.py codec, framing, serialization, datapath, levelization
|
| 997 |
├── paper_runs.py self-description, three generations, lockstep
|
| 998 |
├── host_family.py the host family H_A: a constant-depth SUBLEQ step for
|
| 999 |
│ every word width, and its serialization in build order
|
|
|
|
| 1002 |
├── check_c.py the host on the evaluator in C
|
| 1003 |
├── twohead.py the two-head machine, transcribed, the description code
|
| 1004 |
│ and the translating organism; writes rocq/Organism.v
|
| 1005 |
+
├── twohead_net.py the two-head machine as a ternary netlist N_{G,L} for a window
|
| 1006 |
+
│ of 2^α cells: its check, its file, the organism on it in C,
|
| 1007 |
+
│ and the comparison with the netlist extracted from rocq/
|
| 1008 |
├── twohead_lockstep.c the organism on N_{G,L} beside the transcription, in C
|
| 1009 |
+
├── stored_host.py the host compiled into 36,074 records of the two-head machine
|
| 1010 |
+
│ with 4096 cells: one pass against the host's step and device,
|
| 1011 |
+
│ the image and its recipe, and its generations
|
| 1012 |
+
├── stored_host_run.c the stored host's generations on the two-head machine, in C
|
| 1013 |
├── restore_bound.c the restoration bound of the amplified host along the orbit
|
| 1014 |
├── check_rocq.py builds rocq/ and prints the assumptions of its theorems
|
| 1015 |
├── independent/ separate code written from the paper's definitions: the host
|
| 1016 |
+
│ family, the levelization, a noise simulator in C, weight
|
| 1017 |
+
│ error, and the neuromorphic datapath
|
| 1018 |
├── redundant.py the amplified host N_r: r-fold redundancy with the restoring
|
| 1019 |
│ organ inside every unit, its self-reproduction, its runs
|
| 1020 |
│ under read noise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1021 |
├── noise.py read noise on the self-reproducing run, the deviation curve
|
| 1022 |
│ against the bounds, weight error with zero-entry leakage, the
|
| 1023 |
│ active-input counts that certify an orbit
|
|
|
|
| 1027 |
framing, serialization, all 29 machines
|
| 1028 |
paper/ the manuscript, and the record of every run it reports
|
| 1029 |
rocq/ Rocq proofs: the netlist of the two-head machine computes its
|
| 1030 |
+
step for every window of 2^α cells, the organism builds every
|
| 1031 |
+
image from any description of it and reproduces in every
|
| 1032 |
+
generation
|
| 1033 |
tools/ build_all.py (build + quantize + verify every profile),
|
| 1034 |
cpu_programs.py (assembler + CPU program suite), test_cpu.py
|
| 1035 |
(program suite vs a variant), play.py (interactive demo),
|
paper/README.md
CHANGED
|
@@ -9,37 +9,11 @@ universal_construction_ternary.pdf typeset
|
|
| 9 |
runs/ the record written by each script
|
| 10 |
```
|
| 11 |
|
| 12 |
-
##
|
| 13 |
-
|
| 14 |
-
```bash
|
| 15 |
-
python src/verify.py # the statements
|
| 16 |
-
python src/verify.py --tier 2 # and every construction, end to end
|
| 17 |
-
python src/verify.py --tier 3 # and the full-scale runs
|
| 18 |
-
```
|
| 19 |
-
|
| 20 |
-
Tier one is an exhaustive or near-exhaustive audit of every definition, lemma,
|
| 21 |
-
proposition and theorem, and none of its checks runs the full instance. Tier two
|
| 22 |
-
executes every construction end to end: the self-describing instance and three
|
| 23 |
-
generations of the self-reproducing instance on the integer reference, the
|
| 24 |
-
constructor on four machines of the family through the netlist that
|
| 25 |
-
`variants/neural_subleq8io_netlist.safetensors` denotes, the record interpreters
|
| 26 |
-
of Section 9, the translating organism on the two-head machine and on its
|
| 27 |
-
netlist in C, and the Rocq development of Sections 7 and 8, which needs Rocq 9.1
|
| 28 |
-
and ocamlfind on the PATH. The two together take about forty minutes and cover
|
| 29 |
-
every claim the paper makes.
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
carries out the perturbation experiments and the orbit certificate, and runs
|
| 34 |
-
the amplified host: its exact self-reproduction on the evaluator in C, the
|
| 35 |
-
self-reproducing instance of the host on it under read noise, its deviation
|
| 36 |
-
curve, and the correction of single wrong copies. Its cost belongs to the object and not to the implementation: one
|
| 37 |
-
generation is 1,664,939 steps of a map of 41,967 units, that is 6.99e10 unit
|
| 38 |
-
evaluations, and the amplified host reproduces itself in 33,796,449 steps of
|
| 39 |
-
125,901 units. `runs/paper_throughput.json` holds the rate of each evaluator, so
|
| 40 |
-
the cost of any one run is a multiplication.
|
| 41 |
|
| 42 |
-
## What each script establishes
|
| 43 |
|
| 44 |
| Script | Record | Establishes |
|
| 45 |
|---|---|---|
|
|
@@ -61,22 +35,19 @@ the cost of any one run is a multiplication.
|
|
| 61 |
| `src/check_ternarity.py` | `paper_ternarity.json` | no ternary unit computes the branch predicate |
|
| 62 |
| `src/check_environment.py` | `paper_environment.json` | the cost of the environment against the cost of the network |
|
| 63 |
| `src/check_sigma.py` | — | sigma is a function, injective, and inverted by the parser |
|
| 64 |
-
| `src/fanin2.py` | `paper_fanin2.json` | the fan-in-two rewriting, on the host, the interpreter and every small ternary unit |
|
| 65 |
| `src/check_family.py` | `paper_runs_family.json` | the constructor emits all 29 machines |
|
| 66 |
| `src/check_family_gate.py` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
|
| 67 |
-
| `src/check_interp.py` | `paper_interp.json` | the record interpreter's netlist against its definition |
|
| 68 |
| `src/check_c.py` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
|
| 69 |
| `src/check_host_fold.py` | `paper_host_fold.json` | the folded host family, depth 11, against SUBLEQ_A for A = 3 to 12 |
|
| 70 |
| `src/twohead.py` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
|
| 71 |
-
| `src/twohead_net.py` | `paper_twohead_net.json` | the netlist N_{G,L} against the machine, its file, the organism on it in C, and the netlist extracted from Rocq |
|
| 72 |
-
| `src/
|
| 73 |
-
| `src/
|
| 74 |
-
| `src/hosted_constructor.py` | `paper_hosted.json` | the constructor as a netlist stored in the interpreter |
|
| 75 |
| `src/throughput.py` | `paper_throughput.json` | the rate of each evaluator |
|
| 76 |
| `src/noise.py` | `paper_noise_*.json` | read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
|
| 77 |
| `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, computed by `src/restore_bound.c` |
|
| 78 |
| `src/neuromorphic.py` | `paper_neuromorphic.json` | the datapath on the Loihi and Akida neuron models |
|
| 79 |
-
| `src/independent/*.py`, `nsim.c` | `independent_*.json` | separate code written from the paper's definitions: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma,
|
| 80 |
|
| 81 |
`src/neuromorphic.py run` needs Lava, which requires Python 3.10; everything
|
| 82 |
else runs in the environment of the repository.
|
|
|
|
| 9 |
runs/ the record written by each script
|
| 10 |
```
|
| 11 |
|
| 12 |
+
## What each script establishes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
+
Each script runs on its own and writes its record to `runs/`; `src/check_rocq.py`
|
| 15 |
+
needs Rocq 9.1 and ocamlfind on the PATH.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
|
|
|
| 17 |
|
| 18 |
| Script | Record | Establishes |
|
| 19 |
|---|---|---|
|
|
|
|
| 35 |
| `src/check_ternarity.py` | `paper_ternarity.json` | no ternary unit computes the branch predicate |
|
| 36 |
| `src/check_environment.py` | `paper_environment.json` | the cost of the environment against the cost of the network |
|
| 37 |
| `src/check_sigma.py` | — | sigma is a function, injective, and inverted by the parser |
|
|
|
|
| 38 |
| `src/check_family.py` | `paper_runs_family.json` | the constructor emits all 29 machines |
|
| 39 |
| `src/check_family_gate.py` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
|
|
|
|
| 40 |
| `src/check_c.py` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
|
| 41 |
| `src/check_host_fold.py` | `paper_host_fold.json` | the folded host family, depth 11, against SUBLEQ_A for A = 3 to 12 |
|
| 42 |
| `src/twohead.py` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
|
| 43 |
+
| `src/twohead_net.py` | `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 |
|
| 44 |
+
| `src/stored_host.py`, `src/stored_host_run.c` | `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 image and its recipe, three generations in C |
|
| 45 |
+
| `src/check_rocq.py` | `paper_rocq.json` | the Rocq development of `rocq/`: the netlist computes the step for every window, construction and self-reproduction by the organism |
|
|
|
|
| 46 |
| `src/throughput.py` | `paper_throughput.json` | the rate of each evaluator |
|
| 47 |
| `src/noise.py` | `paper_noise_*.json` | read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
|
| 48 |
| `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, computed by `src/restore_bound.c` |
|
| 49 |
| `src/neuromorphic.py` | `paper_neuromorphic.json` | the datapath on the Loihi and Akida neuron models |
|
| 50 |
+
| `src/independent/*.py`, `nsim.c` | `independent_*.json` | separate code written from the paper's definitions: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma, Tables 3 to 6 with a separate noise simulator, and the datapath on Loihi and Akida |
|
| 51 |
|
| 52 |
`src/neuromorphic.py run` needs Lava, which requires Python 3.10; everything
|
| 53 |
else runs in the environment of the repository.
|
paper/runs/independent_interpreter.json
DELETED
|
@@ -1,40 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"hierarchy": {
|
| 3 |
-
"small_units": 816,
|
| 4 |
-
"small_state_bits": 131,
|
| 5 |
-
"fanin2_units": 1403,
|
| 6 |
-
"signals": 1534,
|
| 7 |
-
"changed": 35,
|
| 8 |
-
"records": 1438,
|
| 9 |
-
"big": {
|
| 10 |
-
"A": 17,
|
| 11 |
-
"G": 2088,
|
| 12 |
-
"b": 62,
|
| 13 |
-
"span": 1616
|
| 14 |
-
},
|
| 15 |
-
"states": 48,
|
| 16 |
-
"passes": 4,
|
| 17 |
-
"disagree": 0,
|
| 18 |
-
"seconds": 5.6
|
| 19 |
-
},
|
| 20 |
-
"hosted": {
|
| 21 |
-
"records": 494,
|
| 22 |
-
"noops": 41,
|
| 23 |
-
"tail_noops": true,
|
| 24 |
-
"decode_matches": true,
|
| 25 |
-
"recipes": 41,
|
| 26 |
-
"recipes_ok": 41,
|
| 27 |
-
"first": {
|
| 28 |
-
"recipe_len": 9,
|
| 29 |
-
"out_len": 12,
|
| 30 |
-
"steps": 83,
|
| 31 |
-
"passes": 83,
|
| 32 |
-
"applications": 44358,
|
| 33 |
-
"ok": true
|
| 34 |
-
},
|
| 35 |
-
"random_states": 2000,
|
| 36 |
-
"random_halting_steps": 297,
|
| 37 |
-
"random_disagree": 0,
|
| 38 |
-
"seconds": 20.4
|
| 39 |
-
}
|
| 40 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/runs/paper_fanin2.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"small_units": 664,
|
| 3 |
-
"small_unit_failures": 0,
|
| 4 |
-
"netlists": {
|
| 5 |
-
"N_host": {
|
| 6 |
-
"units": 17598,
|
| 7 |
-
"units_fanin2": 33568,
|
| 8 |
-
"shapes_above_two": {
|
| 9 |
-
"and": 821,
|
| 10 |
-
"or": 70,
|
| 11 |
-
"threshold": 15
|
| 12 |
-
},
|
| 13 |
-
"agrees_on_random_inputs": true
|
| 14 |
-
},
|
| 15 |
-
"N_U": {
|
| 16 |
-
"units": 13034,
|
| 17 |
-
"units_fanin2": 40081,
|
| 18 |
-
"shapes_above_two": {
|
| 19 |
-
"and": 3091,
|
| 20 |
-
"or": 43
|
| 21 |
-
},
|
| 22 |
-
"agrees_on_random_inputs": true
|
| 23 |
-
}
|
| 24 |
-
},
|
| 25 |
-
"seconds": 7.610988596003153,
|
| 26 |
-
"ok": true
|
| 27 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/runs/paper_hierarchy.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"small": {
|
| 3 |
-
"S": 128,
|
| 4 |
-
"G": 3,
|
| 5 |
-
"units": 816,
|
| 6 |
-
"units_fanin2": 1403,
|
| 7 |
-
"signals": 1534,
|
| 8 |
-
"state_bits": 131
|
| 9 |
-
},
|
| 10 |
-
"big": {
|
| 11 |
-
"S": 131072,
|
| 12 |
-
"G": 2088,
|
| 13 |
-
"b": 62,
|
| 14 |
-
"span": 1616,
|
| 15 |
-
"units": 148571,
|
| 16 |
-
"layers": 65,
|
| 17 |
-
"Q_bits": 129456
|
| 18 |
-
},
|
| 19 |
-
"records": 1438,
|
| 20 |
-
"copy_records": 35,
|
| 21 |
-
"states": 48,
|
| 22 |
-
"pass_steps": 2088,
|
| 23 |
-
"transitions": 4,
|
| 24 |
-
"mismatches_per_transition": [
|
| 25 |
-
0,
|
| 26 |
-
0,
|
| 27 |
-
0,
|
| 28 |
-
0
|
| 29 |
-
],
|
| 30 |
-
"exact": true,
|
| 31 |
-
"mismatched_coordinates": 0,
|
| 32 |
-
"seconds": 62.78045246200054
|
| 33 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/runs/paper_hosted.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"records": 494,
|
| 3 |
-
"record_semantics_ok": true,
|
| 4 |
-
"S": 32768,
|
| 5 |
-
"G": 535,
|
| 6 |
-
"b": 56,
|
| 7 |
-
"span": 2808,
|
| 8 |
-
"units": 59348,
|
| 9 |
-
"layers": 61,
|
| 10 |
-
"memory_bytes": 128,
|
| 11 |
-
"tape_bytes": 9,
|
| 12 |
-
"target_bytes": 12,
|
| 13 |
-
"target": "ABCCCCCCCCDE",
|
| 14 |
-
"instructions": 83,
|
| 15 |
-
"reference_instructions": 83,
|
| 16 |
-
"interpreter_steps": 44405,
|
| 17 |
-
"emitted": "ABCCCCCCCCDE",
|
| 18 |
-
"exact": true,
|
| 19 |
-
"memory_matches_reference": true,
|
| 20 |
-
"head": 9,
|
| 21 |
-
"random_states_records": 2000,
|
| 22 |
-
"random_states_records_wrong": 0,
|
| 23 |
-
"random_states_netlist": 256,
|
| 24 |
-
"random_states_netlist_wrong": 0,
|
| 25 |
-
"seconds": 157.594675832981,
|
| 26 |
-
"ok": true
|
| 27 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/runs/paper_interp.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"members": [
|
| 3 |
-
{
|
| 4 |
-
"A": 10,
|
| 5 |
-
"S": 1024,
|
| 6 |
-
"G": 11,
|
| 7 |
-
"banks": 2,
|
| 8 |
-
"units": 13034,
|
| 9 |
-
"fields": 576,
|
| 10 |
-
"fields_wrong": 0,
|
| 11 |
-
"random": 4096,
|
| 12 |
-
"random_wrong": 0,
|
| 13 |
-
"halted_not_fixed": 0,
|
| 14 |
-
"counter_wrong": 0,
|
| 15 |
-
"ok": true,
|
| 16 |
-
"seconds": 7.045043751000776
|
| 17 |
-
}
|
| 18 |
-
],
|
| 19 |
-
"ok": true
|
| 20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/runs/paper_lev.json
CHANGED
|
@@ -7,8 +7,5 @@
|
|
| 7 |
"nonternary_layers": 0,
|
| 8 |
"noninteger_bias_layers": 0,
|
| 9 |
"min_margin": 0.5,
|
| 10 |
-
"max_noninteger": 0.0
|
| 11 |
-
"u_states": 64,
|
| 12 |
-
"u_gates": 13034,
|
| 13 |
-
"u_agree": true
|
| 14 |
}
|
|
|
|
| 7 |
"nonternary_layers": 0,
|
| 8 |
"noninteger_bias_layers": 0,
|
| 9 |
"min_margin": 0.5,
|
| 10 |
+
"max_noninteger": 0.0
|
|
|
|
|
|
|
|
|
|
| 11 |
}
|
paper/runs/paper_rocq.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
{
|
| 2 |
"rocq": "The Rocq Prover, version 9.1.1",
|
| 3 |
"files": 25,
|
| 4 |
-
"build_seconds":
|
| 5 |
"theorems": {
|
| 6 |
"PhysMain.netlist_step": "closed",
|
|
|
|
| 7 |
"PhysFacts.phys_size": "closed",
|
|
|
|
| 8 |
"PhysFacts.phys_ternary": "closed",
|
| 9 |
"NetMain.network_orbit": "closed",
|
| 10 |
"NetMain.network_reproduces": "closed",
|
|
|
|
| 1 |
{
|
| 2 |
"rocq": "The Rocq Prover, version 9.1.1",
|
| 3 |
"files": 25,
|
| 4 |
+
"build_seconds": 233.8,
|
| 5 |
"theorems": {
|
| 6 |
"PhysMain.netlist_step": "closed",
|
| 7 |
+
"PhysMain.netlist_step64": "closed",
|
| 8 |
"PhysFacts.phys_size": "closed",
|
| 9 |
+
"PhysFacts.phys_size64": "closed",
|
| 10 |
"PhysFacts.phys_ternary": "closed",
|
| 11 |
"NetMain.network_orbit": "closed",
|
| 12 |
"NetMain.network_reproduces": "closed",
|
paper/runs/paper_stats.json
CHANGED
|
@@ -128,105 +128,5 @@
|
|
| 128 |
"128": 8,
|
| 129 |
"256": 40
|
| 130 |
}
|
| 131 |
-
},
|
| 132 |
-
"lev_U": {
|
| 133 |
-
"depth": 53,
|
| 134 |
-
"gates": 13002,
|
| 135 |
-
"netlist_gates": 13034,
|
| 136 |
-
"state_bits": 1029,
|
| 137 |
-
"widths": [
|
| 138 |
-
1029,
|
| 139 |
-
1948,
|
| 140 |
-
1957,
|
| 141 |
-
1500,
|
| 142 |
-
1487,
|
| 143 |
-
1074,
|
| 144 |
-
1104,
|
| 145 |
-
1126,
|
| 146 |
-
1096,
|
| 147 |
-
1099,
|
| 148 |
-
1093,
|
| 149 |
-
1096,
|
| 150 |
-
1090,
|
| 151 |
-
1093,
|
| 152 |
-
1087,
|
| 153 |
-
1090,
|
| 154 |
-
1084,
|
| 155 |
-
1087,
|
| 156 |
-
1081,
|
| 157 |
-
1084,
|
| 158 |
-
1078,
|
| 159 |
-
1081,
|
| 160 |
-
1075,
|
| 161 |
-
1078,
|
| 162 |
-
1072,
|
| 163 |
-
1072,
|
| 164 |
-
1069,
|
| 165 |
-
4111,
|
| 166 |
-
4111,
|
| 167 |
-
3089,
|
| 168 |
-
2065,
|
| 169 |
-
2075,
|
| 170 |
-
2071,
|
| 171 |
-
2071,
|
| 172 |
-
2069,
|
| 173 |
-
2070,
|
| 174 |
-
2067,
|
| 175 |
-
2068,
|
| 176 |
-
2064,
|
| 177 |
-
2066,
|
| 178 |
-
2062,
|
| 179 |
-
2063,
|
| 180 |
-
2060,
|
| 181 |
-
2059,
|
| 182 |
-
2057,
|
| 183 |
-
2057,
|
| 184 |
-
2056,
|
| 185 |
-
2056,
|
| 186 |
-
2055,
|
| 187 |
-
1031,
|
| 188 |
-
1030,
|
| 189 |
-
1039,
|
| 190 |
-
1038,
|
| 191 |
-
1029
|
| 192 |
-
],
|
| 193 |
-
"M": 86490,
|
| 194 |
-
"dense_entries": 160865677,
|
| 195 |
-
"identity_units": 73488,
|
| 196 |
-
"new_units": 13002,
|
| 197 |
-
"max_fanin_netlist": 1024,
|
| 198 |
-
"nonzero_weights_netlist": 51557,
|
| 199 |
-
"bias_min": -10,
|
| 200 |
-
"bias_max": 1,
|
| 201 |
-
"fanin_hist": {
|
| 202 |
-
"1": 1494,
|
| 203 |
-
"2": 8374,
|
| 204 |
-
"3": 1,
|
| 205 |
-
"4": 12,
|
| 206 |
-
"5": 1,
|
| 207 |
-
"6": 1,
|
| 208 |
-
"7": 1,
|
| 209 |
-
"8": 1,
|
| 210 |
-
"9": 1,
|
| 211 |
-
"10": 3073,
|
| 212 |
-
"11": 41,
|
| 213 |
-
"1024": 2
|
| 214 |
-
}
|
| 215 |
-
},
|
| 216 |
-
"U_cfg": {
|
| 217 |
-
"S": 1024,
|
| 218 |
-
"G": 11,
|
| 219 |
-
"F": 2,
|
| 220 |
-
"BB": 4,
|
| 221 |
-
"banks": 2,
|
| 222 |
-
"R": 41,
|
| 223 |
-
"ACC": 6,
|
| 224 |
-
"SLOT": 13,
|
| 225 |
-
"A": 10,
|
| 226 |
-
"NET0": 122,
|
| 227 |
-
"NET1": 573,
|
| 228 |
-
"WORK_BASE": 16,
|
| 229 |
-
"span": 1024,
|
| 230 |
-
"STATE_BITS": 1029
|
| 231 |
}
|
| 232 |
}
|
|
|
|
| 128 |
"128": 8,
|
| 129 |
"256": 40
|
| 130 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
}
|
| 132 |
}
|
paper/runs/paper_stored_host.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"run": {
|
| 3 |
+
"records": 36074,
|
| 4 |
+
"window_cells": 2896,
|
| 5 |
+
"record_bits": 44,
|
| 6 |
+
"bank_bits": 1587256,
|
| 7 |
+
"image_bytes": 198407,
|
| 8 |
+
"tau_bytes": 199971,
|
| 9 |
+
"passes_expected": 2202812,
|
| 10 |
+
"generations": [
|
| 11 |
+
{
|
| 12 |
+
"generation": 1,
|
| 13 |
+
"steps": 79464240088,
|
| 14 |
+
"passes": 2202812,
|
| 15 |
+
"kappa": 1,
|
| 16 |
+
"bank_holds_image": 1,
|
| 17 |
+
"tape_holds_tau": 1,
|
| 18 |
+
"heads": [
|
| 19 |
+
0,
|
| 20 |
+
0,
|
| 21 |
+
0,
|
| 22 |
+
0
|
| 23 |
+
],
|
| 24 |
+
"window_fnv": "d17d72606006fc62"
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"generation": 2,
|
| 28 |
+
"steps": 79464240088,
|
| 29 |
+
"passes": 2202812,
|
| 30 |
+
"kappa": 0,
|
| 31 |
+
"bank_holds_image": 1,
|
| 32 |
+
"tape_holds_tau": 1,
|
| 33 |
+
"heads": [
|
| 34 |
+
0,
|
| 35 |
+
0,
|
| 36 |
+
0,
|
| 37 |
+
0
|
| 38 |
+
],
|
| 39 |
+
"window_fnv": "e3a2c10c6eddcef2"
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"generation": 3,
|
| 43 |
+
"steps": 79464240088,
|
| 44 |
+
"passes": 2202812,
|
| 45 |
+
"kappa": 1,
|
| 46 |
+
"bank_holds_image": 1,
|
| 47 |
+
"tape_holds_tau": 1,
|
| 48 |
+
"heads": [
|
| 49 |
+
0,
|
| 50 |
+
0,
|
| 51 |
+
0,
|
| 52 |
+
0
|
| 53 |
+
],
|
| 54 |
+
"window_fnv": "d17d72606006fc62"
|
| 55 |
+
}
|
| 56 |
+
],
|
| 57 |
+
"seconds": 534.3,
|
| 58 |
+
"sha256_image": "7a769aa264a89860149962d7e98f8b2a5cb34ceb7778e88bcbffdccdc0996154",
|
| 59 |
+
"sha256_tau": "fb23d9b4b41cd5d0576bce37d0cd53a0f63f33de6d4895f2e784eb1148387185",
|
| 60 |
+
"state_after_3_equals_after_1": 1,
|
| 61 |
+
"every_generation_exact": true
|
| 62 |
+
},
|
| 63 |
+
"pass_check": {
|
| 64 |
+
"trials": 300,
|
| 65 |
+
"disagreements": 0,
|
| 66 |
+
"records": 36074,
|
| 67 |
+
"window_cells": 2896,
|
| 68 |
+
"seconds": 131.8
|
| 69 |
+
}
|
| 70 |
+
}
|
paper/runs/paper_twohead_net.json
CHANGED
|
@@ -12,13 +12,26 @@
|
|
| 12 |
"states": 20,
|
| 13 |
"disagreements": 0
|
| 14 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
"netlist": {
|
| 16 |
"units": 45891,
|
| 17 |
"edges": 99602,
|
| 18 |
"depth": 15,
|
| 19 |
"state_bits": 12837
|
| 20 |
},
|
| 21 |
-
"seconds":
|
| 22 |
},
|
| 23 |
"netlist": {
|
| 24 |
"path": "variants/twohead_physics.bin",
|
|
@@ -42,10 +55,24 @@
|
|
| 42 |
"seconds": 322.4
|
| 43 |
},
|
| 44 |
"extraction": {
|
| 45 |
-
"
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
}
|
| 51 |
}
|
|
|
|
| 12 |
"states": 20,
|
| 13 |
"disagreements": 0
|
| 14 |
},
|
| 15 |
+
"wide": {
|
| 16 |
+
"alpha": 12,
|
| 17 |
+
"G": 5,
|
| 18 |
+
"L": 40,
|
| 19 |
+
"states": 40,
|
| 20 |
+
"disagreements": 0,
|
| 21 |
+
"netlist": {
|
| 22 |
+
"units": 34957,
|
| 23 |
+
"edges": 201434,
|
| 24 |
+
"depth": 15,
|
| 25 |
+
"state_bits": 4613
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
"netlist": {
|
| 29 |
"units": 45891,
|
| 30 |
"edges": 99602,
|
| 31 |
"depth": 15,
|
| 32 |
"state_bits": 12837
|
| 33 |
},
|
| 34 |
+
"seconds": 2.3
|
| 35 |
},
|
| 36 |
"netlist": {
|
| 37 |
"path": "variants/twohead_physics.bin",
|
|
|
|
| 55 |
"seconds": 322.4
|
| 56 |
},
|
| 57 |
"extraction": {
|
| 58 |
+
"members": [
|
| 59 |
+
{
|
| 60 |
+
"alpha": 6,
|
| 61 |
+
"N": 3458,
|
| 62 |
+
"L": 2930,
|
| 63 |
+
"identical": true,
|
| 64 |
+
"sha256_generator": "0b86fbe2da1d67beafb252a445738794f4eb35ad4aa8987030c65d3612aa50fe",
|
| 65 |
+
"sha256_rocq": "0b86fbe2da1d67beafb252a445738794f4eb35ad4aa8987030c65d3612aa50fe"
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"alpha": 12,
|
| 69 |
+
"N": 220,
|
| 70 |
+
"L": 40,
|
| 71 |
+
"identical": true,
|
| 72 |
+
"sha256_generator": "dc3b111811b5f3708641883c2313ff2d40387e4e288cb4a790a7289a0d8fcf4d",
|
| 73 |
+
"sha256_rocq": "dc3b111811b5f3708641883c2313ff2d40387e4e288cb4a790a7289a0d8fcf4d"
|
| 74 |
+
}
|
| 75 |
+
],
|
| 76 |
+
"identical": true
|
| 77 |
}
|
| 78 |
}
|
paper/runs/paper_verify.json
CHANGED
|
@@ -39,25 +39,11 @@
|
|
| 39 |
"counter_pairs": 65536,
|
| 40 |
"counter_failures": 0
|
| 41 |
},
|
| 42 |
-
"interpreter": {
|
| 43 |
-
"onerecord_cases": 576,
|
| 44 |
-
"onerecord_failures": 0,
|
| 45 |
-
"counter_failures": 0,
|
| 46 |
-
"Q_bits": 451,
|
| 47 |
-
"influencing": 451,
|
| 48 |
-
"S": 1024,
|
| 49 |
-
"G": 11,
|
| 50 |
-
"R": 41,
|
| 51 |
-
"b": 41,
|
| 52 |
-
"Q_size": 451,
|
| 53 |
-
"records_max": 11,
|
| 54 |
-
"units_lower_bound": 226
|
| 55 |
-
},
|
| 56 |
"lev": {
|
| 57 |
"sparse_dense_agree": true,
|
| 58 |
"layers": 13,
|
| 59 |
"max_width": 8210,
|
| 60 |
"total_weights": 124165940
|
| 61 |
},
|
| 62 |
-
"seconds":
|
| 63 |
}
|
|
|
|
| 39 |
"counter_pairs": 65536,
|
| 40 |
"counter_failures": 0
|
| 41 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
"lev": {
|
| 43 |
"sparse_dense_agree": true,
|
| 44 |
"layers": 13,
|
| 45 |
"max_width": 8210,
|
| 46 |
"total_weights": 124165940
|
| 47 |
},
|
| 48 |
+
"seconds": 190.45070967001084
|
| 49 |
}
|
paper/runs/paper_verify_times.json
DELETED
|
@@ -1,75 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"tier": 1,
|
| 3 |
-
"total_seconds": 214.8219217349979,
|
| 4 |
-
"failures": 0,
|
| 5 |
-
"checks": {
|
| 6 |
-
"check_device.py": {
|
| 7 |
-
"ok": true,
|
| 8 |
-
"seconds": 0.14191210998978931
|
| 9 |
-
},
|
| 10 |
-
"check_framing.py": {
|
| 11 |
-
"ok": true,
|
| 12 |
-
"seconds": 0.5073039440030698
|
| 13 |
-
},
|
| 14 |
-
"twohead_net.py check": {
|
| 15 |
-
"ok": true,
|
| 16 |
-
"seconds": 5.247474653995596
|
| 17 |
-
},
|
| 18 |
-
"check_steps.py": {
|
| 19 |
-
"ok": true,
|
| 20 |
-
"seconds": 5.269182780990377
|
| 21 |
-
},
|
| 22 |
-
"check_optimal.py": {
|
| 23 |
-
"ok": true,
|
| 24 |
-
"seconds": 7.710004391003167
|
| 25 |
-
},
|
| 26 |
-
"check_codec.py": {
|
| 27 |
-
"ok": true,
|
| 28 |
-
"seconds": 7.851285790995462
|
| 29 |
-
},
|
| 30 |
-
"check_sigma.py": {
|
| 31 |
-
"ok": true,
|
| 32 |
-
"seconds": 11.03636751799786
|
| 33 |
-
},
|
| 34 |
-
"fanin2.py": {
|
| 35 |
-
"ok": true,
|
| 36 |
-
"seconds": 12.635428726993268
|
| 37 |
-
},
|
| 38 |
-
"check_environment.py": {
|
| 39 |
-
"ok": true,
|
| 40 |
-
"seconds": 12.856029444010346
|
| 41 |
-
},
|
| 42 |
-
"check_interp.py": {
|
| 43 |
-
"ok": true,
|
| 44 |
-
"seconds": 13.257643950011698
|
| 45 |
-
},
|
| 46 |
-
"check_host.py": {
|
| 47 |
-
"ok": true,
|
| 48 |
-
"seconds": 14.019029688002774
|
| 49 |
-
},
|
| 50 |
-
"check_ternarity.py": {
|
| 51 |
-
"ok": true,
|
| 52 |
-
"seconds": 15.632652968997718
|
| 53 |
-
},
|
| 54 |
-
"check_host_family.py": {
|
| 55 |
-
"ok": true,
|
| 56 |
-
"seconds": 26.31405289299437
|
| 57 |
-
},
|
| 58 |
-
"check_lev.py": {
|
| 59 |
-
"ok": true,
|
| 60 |
-
"seconds": 32.38079876700067
|
| 61 |
-
},
|
| 62 |
-
"check_host_fold.py": {
|
| 63 |
-
"ok": true,
|
| 64 |
-
"seconds": 51.92139666900039
|
| 65 |
-
},
|
| 66 |
-
"check_total.py": {
|
| 67 |
-
"ok": true,
|
| 68 |
-
"seconds": 205.5435071989923
|
| 69 |
-
},
|
| 70 |
-
"redundant.py build": {
|
| 71 |
-
"ok": true,
|
| 72 |
-
"seconds": 214.77837346300657
|
| 73 |
-
}
|
| 74 |
-
}
|
| 75 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
paper/universal_construction_ternary.pdf
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:29a8e26ce2577a85810fc815acc5eeaef1925cbaadb629aee163c64bf7cfdcf4
|
| 3 |
+
size 364771
|
paper/universal_construction_ternary.tex
CHANGED
|
@@ -7,7 +7,12 @@
|
|
| 7 |
\usepackage{booktabs,tabularx,array}
|
| 8 |
\usepackage{cite}
|
| 9 |
\usepackage{enumitem}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
\usepackage[margin=1in]{geometry}
|
|
|
|
| 11 |
\usepackage[colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref}
|
| 12 |
|
| 13 |
% ---- theorem environments ---------------------------------------------------
|
|
@@ -62,30 +67,28 @@ We study recurrent networks of McCulloch--Pitts threshold units with weights in
|
|
| 62 |
$\{-1,0,1\}$ and integer thresholds, iterated as a fixed composition of ternary
|
| 63 |
matrix--vector products and Heaviside steps, and construct networks of this kind
|
| 64 |
that carry out von Neumann's scheme of universal construction and
|
| 65 |
-
self-reproduction exactly. A SUBLEQ computer of
|
| 66 |
-
family whose step has depth $13$ at every word
|
| 67 |
-
instructions that emits any byte string from a
|
| 68 |
-
of $27$ instructions
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
description of
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
an integer, every orbit survives perturbations below $1/2$
|
| 81 |
-
the pre-activation profile is within $20\%$ of the measured
|
| 82 |
-
Gaussian read noise
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
the self-reproducing run at noise levels at which the host fails within its
|
| 88 |
-
first bytes.
|
| 89 |
\end{abstract}
|
| 90 |
|
| 91 |
\maketitle
|
|
@@ -115,15 +118,17 @@ $F\colon\B^n\to\B^n$ built from ternary matrices and the Heaviside step, and its
|
|
| 115 |
behaviour is the orbit of an initial state. The paper treats two questions.
|
| 116 |
The first is whether such an orbit can emit, exactly, a serialization of the
|
| 117 |
weights that define $F$ together with the rest of the initial data, so that
|
| 118 |
-
loading the emitted data yields a process that emits the same data.
|
| 119 |
-
is whether the offspring can be built by the dynamics: whether a fixed network
|
| 120 |
-
can hold threshold networks in its state as data, and whether a network so held
|
| 121 |
-
can construct another from a description, copy the description, and hand over
|
| 122 |
-
control to what it built. The first is the
|
| 123 |
setting of program replicators, which rely on an execution environment to
|
| 124 |
-
instantiate what they emit~\cite{CotlerHonglerHudcova2025}
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
Integer weights make the reproduction exact. A trained network that outputs an
|
| 129 |
approximation of its weights loses information in every generation, while a
|
|
@@ -155,24 +160,26 @@ every string $f$ has a description of length at most
|
|
| 155 |
$|f|+\lceil|f|/127\rceil+1$, and none shorter when $f$ has no two equal adjacent
|
| 156 |
bytes (Section~\ref{sec:univ}).
|
| 157 |
\item \emph{Exact self-reproduction of the host.} A program of $27$
|
| 158 |
-
instructions, separating construction from copying as von Neumann did,
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
(Section~\ref{sec:selfrep}).
|
| 164 |
\item \emph{Self-reproduction by the dynamics.} A family of ternary threshold
|
| 165 |
-
networks $
|
| 166 |
-
with two tapes and three heads, each step evaluating one record; the
|
| 167 |
-
computes the step of this two-head machine from every state, for every
|
| 168 |
-
$
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
(
|
|
|
|
|
|
|
|
|
|
| 176 |
\item \emph{Robustness.} Every orbit survives perturbations below $1/2$ per
|
| 177 |
pre-activation. The tolerances for weight and leakage errors are given by
|
| 178 |
fan-in and layer width and, along an orbit, by its active inputs, and a bound
|
|
@@ -198,11 +205,12 @@ its first bytes (Section~\ref{sec:amplify}).
|
|
| 198 |
|
| 199 |
Sections~\ref{sec:prelim} to~\ref{sec:robust} define the networks, build the
|
| 200 |
host, carry out construction and self-reproduction on it and treat
|
| 201 |
-
perturbations
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
|
|
|
| 206 |
|
| 207 |
% =============================================================================
|
| 208 |
\section{Threshold maps, transducers, and reproduction}\label{sec:prelim}
|
|
@@ -448,8 +456,9 @@ second statement follows by induction on $k$.
|
|
| 448 |
The maps $\inst$ and $\Lev$ together with the device of
|
| 449 |
Definition~\ref{def:transducer} are the \emph{instantiation map}: the network
|
| 450 |
emits a description, and $\inst$, $\sigma^{-1}$ and $\Lev$ turn it into the next
|
| 451 |
-
running network. Section~\ref{sec:
|
| 452 |
-
|
|
|
|
| 453 |
|
| 454 |
\begin{proposition}[Cost of instantiation]\label{prop:envcost}
|
| 455 |
Let $\Omega=(N,m,\tau)$ be an instance whose run halts after $T$ steps, and let
|
|
@@ -624,8 +633,11 @@ $(0,1,1,0)$.
|
|
| 624 |
|
| 625 |
\begin{construction}[The host family]\label{con:host}
|
| 626 |
For $A\ge3$ the netlist $H_A$ has the blocks of Table~\ref{tab:blocks}, in that
|
| 627 |
-
order, each unit after its predecessors. Its state is the $A$
|
| 628 |
-
halt bit and the $A\cdot2^A$ memory bits
|
|
|
|
|
|
|
|
|
|
| 629 |
of $p$ give the three operands by reindexing, $M[p+o]_t=\bigvee_j(\mu_{j+o,t}\wedge
|
| 630 |
P_j)$, and the bits of $p+3$ as disjunctions of the lines $P_j$ for which the
|
| 631 |
corresponding bit of $j+3\bmod 2^A$ is $1$. The decode lines of $a$ and $b$ give
|
|
@@ -943,41 +955,44 @@ elsewhere, and let
|
|
| 943 |
\end{construction}
|
| 944 |
|
| 945 |
\begin{theorem}[Exact self-reproduction]\label{thm:selfrep}
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
|
|
|
|
|
|
|
| 949 |
$\Omega_{k+1}=\inst(\Out(\Omega_k))$ starting from $\Omega^\ast$ are constant.
|
| 950 |
\end{theorem}
|
| 951 |
|
| 952 |
\begin{proof}
|
| 953 |
Phase~(A) consists of the instructions of $P$ with the same memory layout, and
|
| 954 |
the cells $\cell{EOK}$ and $c_{\mathrm{eot}}$ are not addressed by them, so the
|
| 955 |
-
proof of Theorem~\ref{thm:univ} applies: every token of $\tau
|
| 956 |
-
|
| 957 |
-
$\delta(\tau
|
| 958 |
-
$
|
| 959 |
-
|
| 960 |
-
the
|
| 961 |
-
$c_{\mathrm{rw}}$.
|
| 962 |
|
| 963 |
For phase~(B) consider the assertion
|
| 964 |
\[
|
| 965 |
J_i:\quad
|
| 966 |
\begin{minipage}{0.78\textwidth}
|
| 967 |
control reaches the head of phase~(B) with head position $i$, output word
|
| 968 |
-
$\omega=\delta(\tau
|
| 969 |
$M[\cell{Z}]=0$, $M[\cell{EOK}]=1$, $M[R_{\mathrm{out}}]=0$, all request bits $0$.
|
| 970 |
\end{minipage}
|
| 971 |
\]
|
| 972 |
$J_0$ holds. Assume $J_i$; the first instruction requests a read. If
|
| 973 |
-
$i<|\tau
|
| 974 |
advances the head; the second instruction leaves $\cell{EOK}=1$, positive; the
|
| 975 |
-
third and fourth assign $M[\cell{Z}]\leftarrow\nu(\
|
| 976 |
-
$M[R_{\mathrm{out}}]\leftarrow\
|
| 977 |
sixth restores $M[\cell{Z}]=0$ and branches back, so $J_{i+1}$ holds. If
|
| 978 |
-
$i=|\tau
|
| 979 |
assigns $M[\cell{EOK}]\leftarrow0$ and transfers control to $\cell{0xFF}$, and the
|
| 980 |
-
output word is $\delta(\tau
|
|
|
|
|
|
|
| 981 |
statement is Lemma~\ref{lem:generations}.
|
| 982 |
\end{proof}
|
| 983 |
|
|
@@ -1208,7 +1223,7 @@ At $s=0.09$, $0.10$ and $0.11$, where most of the $256$ noisy copies leave the
|
|
| 1208 |
exact orbit, the profile bound of Proposition~\ref{prop:profile} lies $2\%$ to
|
| 1209 |
$19\%$ above the measured per-step rate, in the run of Table~\ref{tab:curve} and
|
| 1210 |
in a repetition with a separate simulator, and $Mp$ exceeds the bound by a factor
|
| 1211 |
-
of $2.7$. Under read noise on every
|
| 1212 |
pre-activation the complete self-reproducing run emits the whole instance at
|
| 1213 |
$s=0.05$ and has its halt bit set after $143$ bytes at $s=0.10$
|
| 1214 |
(Table~\ref{tab:noise}). Under static weight error the orbit stays exact up to a
|
|
@@ -1216,6 +1231,55 @@ leakage of $3.9\times10^{-3}$ and a programmed-weight error of $1/16$; of the
|
|
| 1216 |
thirteen settings of Table~\ref{tab:leak}, Corollary~\ref{cor:mismatch}
|
| 1217 |
certifies three and Proposition~\ref{prop:orbit} nine.
|
| 1218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1219 |
\subsection{Fault tolerance by amplification}\label{sec:amplify}
|
| 1220 |
|
| 1221 |
Theorem~\ref{thm:margin} tolerates perturbations below $\tfrac12$ because every
|
|
@@ -1535,7 +1599,8 @@ $3.11\times10^{-4}$ at $s=0.22$ and $0.271$ at $s=0.25$, where that bound exceed
|
|
| 1535 |
one, and it exceeds one from $s=0.27$. Along the first $20{,}000$ steps of the
|
| 1536 |
self-describing instance, weighted by the steps each of the $64$ noisy copies
|
| 1537 |
ran, $b(t)$ lies $1.06$ to $1.47$ times above the measured failure rates
|
| 1538 |
-
(Table~\ref{tab:bound3}), which are $21$ and $12$ times
|
|
|
|
| 1539 |
the replicated state left its orbit at $s=0.27$ and $0.30$.
|
| 1540 |
|
| 1541 |
|
|
@@ -1546,32 +1611,71 @@ the replicated state left its orbit at $s=0.27$ and $0.30$.
|
|
| 1546 |
This section gives a fixed network whose state holds a threshold network as
|
| 1547 |
data: a program bank lists the units of the stored network as records, the step
|
| 1548 |
evaluates the record in front of the bank and turns the bank by one record, and
|
| 1549 |
-
three heads read and write a second bank and two tapes
|
|
|
|
| 1550 |
|
| 1551 |
\begin{definition}[The two-head machine]\label{def:twohead}
|
| 1552 |
-
Let $G,L\ge1$ and $N=
|
| 1553 |
-
$
|
| 1554 |
-
|
| 1555 |
-
|
| 1556 |
-
|
| 1557 |
-
|
| 1558 |
-
$
|
| 1559 |
-
and
|
| 1560 |
-
|
|
|
|
| 1561 |
$w=1$ for $01$, $w=-1$ for $10$ and $w=0$ otherwise, a bias $\beta\in[-8,7]$ in
|
| 1562 |
-
two's complement on four bits, and three window addresses of
|
| 1563 |
-
significant first. One step reads the record $Q_\kappa[0..
|
| 1564 |
$x_a$ of the cells it names, and
|
| 1565 |
\begin{enumerate}[label=(\roman*)]
|
| 1566 |
\item computes $v=\Hv(w_0x_{a_0}+w_1x_{a_1}+\beta)$;
|
| 1567 |
\item writes $v$ into window cell $a_o$ if $a_o=0$ or $a_o\ge4$, under the arm if
|
| 1568 |
$a_o=2$, under the copy head if $a_o=3$, and nowhere if $a_o=1$;
|
| 1569 |
-
\item turns $Q_\kappa$ by $
|
| 1570 |
tape by one cell each when cell $4$, $5$ or $6$ holds $1$ after the write;
|
| 1571 |
\item clears cells $4$, $5$ and $6$.
|
| 1572 |
\end{enumerate}
|
|
|
|
|
|
|
| 1573 |
\end{definition}
|
| 1574 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1575 |
A \emph{pass} is $G$ steps. The active bank comes back to the record it started
|
| 1576 |
with, so a pass evaluates the $G$ records of the bank once each, in order, each
|
| 1577 |
on the values the records before it left. The bank bit is read at the start of a
|
|
@@ -1579,64 +1683,355 @@ step, so a record that writes $\kappa$ passes control to the other bank from
|
|
| 1579 |
the next step on.
|
| 1580 |
|
| 1581 |
\begin{theorem}[The machine as a ternary threshold network]\label{thm:physnet}
|
| 1582 |
-
For all $G,L\ge1$ there is a clocked ternary threshold netlist
|
| 1583 |
-
$
|
| 1584 |
-
$
|
| 1585 |
-
|
| 1586 |
-
|
|
|
|
|
|
|
|
|
|
| 1587 |
\end{theorem}
|
| 1588 |
|
| 1589 |
\begin{proof}
|
| 1590 |
The netlist has twenty-eight blocks. A multiplexer on $\kappa$ selects each bit
|
| 1591 |
of the record in front of the active bank and the cell under each head. Three
|
| 1592 |
-
blocks of $
|
| 1593 |
-
disjunction of the conjunctions of each decode line with the cell it names
|
| 1594 |
-
$x_{a_0}$ and $x_{a_1}$, cells $1$ to $3$ through the head multiplexers.
|
| 1595 |
-
weight codes, units for $[w_k=1]\wedge x_{a_k}$ and $[w_k=-1]\wedge
|
| 1596 |
-
$p=w_0x_{a_0}+w_1x_{a_1}\in[-2,2]$; five units test $p\ge c$ for
|
| 1597 |
-
and five test $\beta\ge-c$ on the four bits of $\beta$, and $v$ is
|
| 1598 |
-
of the five conjunctions, since $p+\beta\ge0$ exactly when some
|
| 1599 |
-
$c=p$, has $p\ge c$ and $\beta\ge-c$. A multiplexer on the decode line
|
| 1600 |
-
stored window cell writes $v$ into it, and the three request cells read a
|
| 1601 |
-
that never fires. Bit $i$ of a bank is the disjunction of three
|
| 1602 |
-
with the bank active, its bit $i+
|
| 1603 |
-
bit $i$ of the bank after the arm's write, as cell $5$ after the
|
| 1604 |
-
the cell under the arm after the write is a multiplexer of $v$
|
| 1605 |
-
on the decode line of $2$. The tapes are alike, with cells $4$
|
| 1606 |
-
decode line of $3$. Counting the units and edges of the blocks
|
| 1607 |
-
The depth of a unit depends only on its block: the record and
|
| 1608 |
-
the heads are selected at depth $2$, the decode lines lie at
|
| 1609 |
-
operands at $5$, the products at $6$, the tests $p\ge c$ at $7$
|
| 1610 |
-
the written window cells, the requests among them, at $11$, the
|
| 1611 |
-
at $14$, the signals that turn the tapes at $13$ and the next tape
|
| 1612 |
-
$15$. That the next state is the encoding of the next state of $x$, for
|
| 1613 |
-
$G$, $L$ and $x$, is proved in Rocq, with the number of units and
|
| 1614 |
-
every unit is given a value in terms of $x$, every unit fires to its
|
| 1615 |
-
on the values of the units it reads, and induction over the units in
|
| 1616 |
-
shows that the netlist computes these values, among them the next
|
|
|
|
|
|
|
| 1617 |
\end{proof}
|
| 1618 |
|
| 1619 |
\begin{remark}[Corroboration]\label{rem:physcheck}
|
| 1620 |
-
For $G=133$ and $L=2930$, the member that Section~\ref{sec:organism}
|
| 1621 |
-
$
|
| 1622 |
-
|
| 1623 |
-
|
| 1624 |
-
|
| 1625 |
-
|
| 1626 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1627 |
C beside the transcription, the full state compared after every step.
|
| 1628 |
\end{remark}
|
| 1629 |
|
| 1630 |
% =============================================================================
|
| 1631 |
-
\section{
|
| 1632 |
% =============================================================================
|
| 1633 |
|
| 1634 |
-
Inside the two-head machine the instantiation step of
|
| 1635 |
-
|
| 1636 |
-
|
| 1637 |
-
|
| 1638 |
-
|
| 1639 |
-
the
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1640 |
|
| 1641 |
\begin{definition}[The description code]\label{def:code}
|
| 1642 |
A \emph{gate} is a record that computes the conjunction or the disjunction of
|
|
@@ -1658,8 +2053,8 @@ having read the whole word.
|
|
| 1658 |
\end{definition}
|
| 1659 |
|
| 1660 |
An image of $n$ records of which $e$ are not gates has a description of
|
| 1661 |
-
$22n+8e+4$ bits, and the gates include every unit
|
| 1662 |
-
|
| 1663 |
|
| 1664 |
\begin{lemma}[Completeness of the code]\label{lem:code}
|
| 1665 |
For every image $X$ of whole records, $\describe(X)$ is a description of $X$.
|
|
@@ -1675,12 +2070,13 @@ the end codon closes the induction. The proof is checked in Rocq.
|
|
| 1675 |
\begin{construction}[The organism]\label{con:organism}
|
| 1676 |
The organism $\rho$ is the image of the $133$ records listed in
|
| 1677 |
Appendix~\ref{app:listings}, $3458$ bits. It uses $36$ window cells: the bank bit,
|
| 1678 |
-
the six head and request cells,
|
| 1679 |
-
decoder, and fifteen temporaries
|
| 1680 |
-
that pass. The decoder's state is a mode $m$,
|
| 1681 |
-
|
| 1682 |
-
|
| 1683 |
-
|
|
|
|
| 1684 |
\begin{enumerate}[label=(\roman*),leftmargin=2em]
|
| 1685 |
\item in phase C, $r$ is consumed and shifted into the codon register, and in copy
|
| 1686 |
mode copied under the copy head; at $z=0$ the codon decides: at end the mode
|
|
@@ -1721,7 +2117,7 @@ record. The refinement, the independence from the temporaries and the evaluation
|
|
| 1721 |
are checked in Rocq.
|
| 1722 |
\end{proof}
|
| 1723 |
|
| 1724 |
-
\begin{theorem}[Universal construction by the
|
| 1725 |
Let $X$ be an image of $133$ records and $d$ a description of $X$ of $L$ bits. Let
|
| 1726 |
$x$ be a state of $T_{133,L}$ with $\rho$ in the active bank $Q_\kappa$ from its
|
| 1727 |
first record, $d$ on the read tape from its head, and in the window clear
|
|
@@ -1752,13 +2148,13 @@ By Lemma~\ref{lem:code} every image of $133$ gates has a description of $2930$
|
|
| 1752 |
bits, so in $T_{133,2930}$ the organism builds every image of $133$ gates, and in
|
| 1753 |
$T_{133,2930+8e}$ every image of $133$ records of which $e$ are not gates.
|
| 1754 |
|
| 1755 |
-
\begin{theorem}[Self-reproduction
|
| 1756 |
Let $x_0$ be the state of $T_{133,2930}$ with $\rho$ in $Q_0$, $\describe(\rho)$
|
| 1757 |
on $D_0$, $Q_1$ and $D_1$ clear, $\kappa=0$, and in the window clear requests and
|
| 1758 |
the decoder in phase C with $z=3$ in construct mode. For every $g\ge1$, the state
|
| 1759 |
after $g$ generations of $6924$ passes, $920{,}892$ applications of $T$ each,
|
| 1760 |
holds $\rho$ in both banks and $\describe(\rho)$ on both tapes, with
|
| 1761 |
-
$\kappa=g\bmod2$. The network $
|
| 1762 |
their bits at the same steps. Its orbit is periodic from the first generation
|
| 1763 |
on, with a period of two generations.
|
| 1764 |
\end{theorem}
|
|
@@ -1776,281 +2172,16 @@ generations, $2{,}762{,}676$ applications of $T$, in the Rocq kernel, and are
|
|
| 1776 |
equal, so the orbit is periodic from the first generation on.
|
| 1777 |
\end{proof}
|
| 1778 |
|
| 1779 |
-
\begin{remark}\label{rem:
|
| 1780 |
-
The
|
| 1781 |
-
|
| 1782 |
-
|
| 1783 |
-
is named by four bits and its eight bits are written by the organism, so the
|
| 1784 |
-
description of $\rho$ has $2930$ bits against $3458$ for the bank. What is
|
| 1785 |
-
reproduced is the weight set of the network that runs, since the records are
|
| 1786 |
-
the units of the stored network, weights and biases included.
|
| 1787 |
-
\end{remark}
|
| 1788 |
-
|
| 1789 |
-
\begin{remark}[Corroboration]\label{rem:organismcheck}
|
| 1790 |
-
Three generations from $x_0$ were run on the transcription of
|
| 1791 |
Definition~\ref{def:twohead}, each of $920{,}892$ steps, and on the netlist in C
|
| 1792 |
beside it (Remark~\ref{rem:physcheck}); after each both banks held $\rho$ and
|
| 1793 |
both tapes $\describe(\rho)$, and the full state after the third generation
|
| 1794 |
-
equalled the state after the first. The
|
| 1795 |
-
|
| 1796 |
-
|
| 1797 |
-
transcription, and so do the full states of $T$ after $1000$ and $20{,}000$
|
| 1798 |
-
steps.
|
| 1799 |
-
\end{remark}
|
| 1800 |
-
|
| 1801 |
-
% =============================================================================
|
| 1802 |
-
\section{Interpreters running interpreters}\label{sec:tower}
|
| 1803 |
-
% =============================================================================
|
| 1804 |
-
|
| 1805 |
-
The records of the two-head machine name window cells. The record interpreters
|
| 1806 |
-
of this section address a state of $2^A$ coordinates through addresses of $A$
|
| 1807 |
-
bits and an index register, so that a member of their family can run another
|
| 1808 |
-
member, and the constructor of Section~\ref{sec:univ}, as stored netlists. A
|
| 1809 |
-
member is fixed by an address width $A$, with state width $S=2^A$, a record
|
| 1810 |
-
count $G$, a bias width of $4$ bits, a number of record banks, one or two, and
|
| 1811 |
-
an addressed span, the number of coordinates a record may read or write. The
|
| 1812 |
-
state $x\in\B^S$ holds, in this order from coordinate $0$: a pointer register
|
| 1813 |
-
$\mathrm{PTR}$ of $A$ bits, most significant first; the signals
|
| 1814 |
-
$\mathrm{OUT\_DATA}$, $\mathrm{OUT\_STROBE}$, $\mathrm{ADV}$, $\kappa$ (the bank
|
| 1815 |
-
bit), $\mathrm{HALT}$ and a sink that no record reads; a data region; and, at the
|
| 1816 |
-
top of the state, the record regions $Q_0$ and, for a two-bank member, $Q_1$, of
|
| 1817 |
-
$Gb$ bits each, $b$ the record width of Definition~\ref{def:records}. Further
|
| 1818 |
-
state bits outside $\B^S$ hold the record counter $g$, on $\lceil\log_2G\rceil$
|
| 1819 |
-
bits, and a halt bit. The members used are those of Table~\ref{tab:cfg}; $U$
|
| 1820 |
-
denotes the first, a map on $\B^{1029}$.
|
| 1821 |
-
|
| 1822 |
-
\begin{table}[ht]
|
| 1823 |
-
\centering\small
|
| 1824 |
-
\begin{tabular}{@{}lrrrrrrrl@{}}
|
| 1825 |
-
\toprule
|
| 1826 |
-
Member & $A$ & $S$ & $G$ & $b$ & banks & span & units & Used in\\
|
| 1827 |
-
\midrule
|
| 1828 |
-
$U$ & $10$ & $1024$ & $11$ & $41$ & 2 & $1024$ & $13{,}034$
|
| 1829 |
-
& Constr.~\ref{con:interp}, Rem.~\ref{rem:fanin2}\\
|
| 1830 |
-
$U_{128}$ & $7$ & $128$ & $3$ & $32$ & 1 & $32$ & $816$
|
| 1831 |
-
& Prop.~\ref{prop:hierarchy}, run\\
|
| 1832 |
-
$U_{2^{17}}$ & $17$ & $131{,}072$ & $2088$ & $62$ & 1 & $1616$ & $148{,}571$
|
| 1833 |
-
& Prop.~\ref{prop:hierarchy}, running\\
|
| 1834 |
-
$U_{2^{15}}$ & $15$ & $32{,}768$ & $535$ & $56$ & 1 & $2808$ & $59{,}348$
|
| 1835 |
-
& Thm.~\ref{thm:hosted}\\
|
| 1836 |
-
\bottomrule
|
| 1837 |
-
\end{tabular}
|
| 1838 |
-
\caption{The members of the interpreter family used here. Where the span is
|
| 1839 |
-
smaller than $S$ the record regions are read by index only and are not
|
| 1840 |
-
themselves addressable.}
|
| 1841 |
-
\label{tab:cfg}
|
| 1842 |
-
\end{table}
|
| 1843 |
-
|
| 1844 |
-
\begin{definition}[Stored netlists]\label{def:records}
|
| 1845 |
-
A \emph{record} is a tuple
|
| 1846 |
-
$\rho=(a_0,w_0,i_0,\,a_1,w_1,i_1,\,\beta,\,a_o,i_o)$ with addresses
|
| 1847 |
-
$a\in\{0,\dots,S-1\}$ on $A$ bits, weights $w\in\Tern$ encoded in two bits by
|
| 1848 |
-
$1\mapsto(0,1)$, $-1\mapsto(1,0)$ and $0\mapsto(0,0)$ or $(1,1)$, index flags
|
| 1849 |
-
$i\in\B$, and a bias $\beta\in[-8,7]$ in two's complement on four bits, so a
|
| 1850 |
-
record occupies $b=2(A+3)+4+(A+1)=3A+11$ bits. For a value of $\mathrm{PTR}$ the
|
| 1851 |
-
effective address is $\eff(a,i)=(a+i\cdot\mathrm{PTR})\bmod S$, and a read
|
| 1852 |
-
outside the span returns $0$. \emph{Evaluating} $\rho$ on a state $x$ with halt
|
| 1853 |
-
bit $0$ produces $x'$ in two stages. First
|
| 1854 |
-
\[
|
| 1855 |
-
x'_{\eff(a_o,i_o)}\leftarrow
|
| 1856 |
-
\Hv\bigl(w_0\,x_{\eff(a_0,i_0)}+w_1\,x_{\eff(a_1,i_1)}+\beta\bigr),
|
| 1857 |
-
\]
|
| 1858 |
-
all other coordinates being unchanged. Then the \emph{pointer clause}: if
|
| 1859 |
-
$x'_{\mathrm{ADV}}=1$, $\mathrm{PTR}$ is incremented modulo $S$ and
|
| 1860 |
-
$\mathrm{ADV}$ is cleared. The next halt bit is the disjunction of the halt bit
|
| 1861 |
-
with $x_{\mathrm{HALT}}$, and a state with halt bit $1$ is left unchanged. A
|
| 1862 |
-
\emph{stored netlist} of length $G$ is a sequence $\rho_0,\dots,\rho_{G-1}$
|
| 1863 |
-
encoded in the active record region, $Q_\kappa$. The interpreter applied to a
|
| 1864 |
-
state with halt bit $0$ and record counter $g$ evaluates $\rho_g$ and sets the
|
| 1865 |
-
counter to $g+1\bmod G$. The output clause is carried out by the runtime: when
|
| 1866 |
-
$x'_{\mathrm{OUT\_STROBE}}=1$ the runtime appends $x'_{\mathrm{OUT\_DATA}}$ to an
|
| 1867 |
-
output word and clears the strobe.
|
| 1868 |
-
\end{definition}
|
| 1869 |
-
|
| 1870 |
-
\begin{construction}[The interpreter netlist]\label{con:interp}
|
| 1871 |
-
The clocked ternary threshold netlist $N_U$ on $1029$ state bits has $13{,}034$
|
| 1872 |
-
units, and $\Lev(N_U)$ has depth $53$; the same blocks give every member of the
|
| 1873 |
-
family. A one-hot decoding of the counter by units of the form of
|
| 1874 |
-
Lemma~\ref{lem:mem} and, for each record position, a multiplexer on $\kappa$ and
|
| 1875 |
-
a disjunction over the records select the bits of $\rho_g$. For each slot the
|
| 1876 |
-
conjunctions of the pointer bits with the index flag and an $A$-bit ripple-carry
|
| 1877 |
-
chain of full adders form the effective address, which the
|
| 1878 |
-
units of Lemma~\ref{lem:mem} decode, and a disjunction of conjunctions reads the
|
| 1879 |
-
addressed coordinate. The units $\mathrm{AND}(\overline h,l)$ and
|
| 1880 |
-
$\mathrm{AND}(h,\overline l)$ decode a weight code $(h,l)$, and with the read
|
| 1881 |
-
value $v$ give $w\cdot v$ in two's complement on six bits, which hold
|
| 1882 |
-
$|w_0v_0+w_1v_1+\beta|\le10$; two ripple-carry chains form that sum, and the
|
| 1883 |
-
negation of its sign bit is $\Hv$ of the sum. The decoded output address drives a
|
| 1884 |
-
multiplexer for each coordinate of the span, which writes the value when the
|
| 1885 |
-
halt bit is $0$. The pointer clause adds
|
| 1886 |
-
$\mathrm{AND}(\hat x_{\mathrm{ADV}},\overline{\mathrm{halt}})$ to the written
|
| 1887 |
-
pointer, the carry into bit $j$ one unit of fan-in $j+1$, and clears
|
| 1888 |
-
$\mathrm{ADV}$; the counter is incremented by a ripple-carry chain, reset on the
|
| 1889 |
-
one-hot line of $G-1$ and held when the halt bit is $1$, and the next halt bit is
|
| 1890 |
-
the disjunction of the halt bit with $x_{\mathrm{HALT}}$. These blocks carry out
|
| 1891 |
-
the interpreter of Definition~\ref{def:records} on states whose halt bit is $0$
|
| 1892 |
-
and hold a state with halt bit $1$ fixed.
|
| 1893 |
-
\end{construction}
|
| 1894 |
-
|
| 1895 |
-
\begin{remark}[Corroboration]\label{rem:interpcheck}
|
| 1896 |
-
The netlist of $U$ was compared with a transcription of
|
| 1897 |
-
Definition~\ref{def:records} on all $576$ configurations of
|
| 1898 |
-
$(w_0,w_1,\beta,x_{a_0},x_{a_1})$ and on $4096$ uniformly random full states,
|
| 1899 |
-
stored records, pointer, $\mathrm{ADV}$ and counter included; halted states were
|
| 1900 |
-
checked to be fixed points and the counter to advance modulo $G$ from every
|
| 1901 |
-
value. The netlists of $U_{2^{17}}$ and $U_{2^{15}}$ ran the passes of
|
| 1902 |
-
Remarks~\ref{rem:hierarchycheck} and~\ref{rem:hostedcheck}.
|
| 1903 |
-
\end{remark}
|
| 1904 |
-
|
| 1905 |
-
\begin{definition}[Pass]\label{def:pass}
|
| 1906 |
-
A \emph{pass} consists of $G$ consecutive applications of the interpreter
|
| 1907 |
-
starting with record counter $0$.
|
| 1908 |
-
\end{definition}
|
| 1909 |
-
|
| 1910 |
-
\begin{lemma}[Netlists with feedback]\label{lem:feedback}
|
| 1911 |
-
Let $\rho_0,\dots,\rho_{G-1}$ be any stored netlist with $\mathrm{PTR}$ constant and
|
| 1912 |
-
let $\theta_g\colon\B^S\to\B^S$ evaluate $\rho_g$. Then one pass computes
|
| 1913 |
-
$\theta_{G-1}\circ\dots\circ\theta_0$, the sequential update of the automata
|
| 1914 |
-
network in record order, and $k$ passes compute its $k$-th iterate.
|
| 1915 |
-
\end{lemma}
|
| 1916 |
-
|
| 1917 |
-
\begin{proof}
|
| 1918 |
-
Definitions~\ref{def:records} and~\ref{def:pass}.
|
| 1919 |
-
\end{proof}
|
| 1920 |
-
|
| 1921 |
-
Gate-level logic simulation engines evaluate one stored gate per step from
|
| 1922 |
-
operand memory and rank-order the gates so that one pass
|
| 1923 |
-
suffices~\cite{Denneau1982}, and Lemma~\ref{lem:feedback} is the fixed-order
|
| 1924 |
-
sequential schedule of automata networks~\cite{RiosWilsonTheyssier2024c}.
|
| 1925 |
-
|
| 1926 |
-
\begin{corollary}[Compilation]\label{cor:compile}
|
| 1927 |
-
Every ternary threshold unit $\Hv(\sum_{i\in P}x_i-\sum_{i\in N}x_i+b)$ is a
|
| 1928 |
-
threshold over its literals: it is $1$ exactly when at least $t=|N|-b$ of the
|
| 1929 |
-
literals $x_i$ ($i\in P$), $\neg x_i$ ($i\in N$) are true. A disjunction
|
| 1930 |
-
($t=1$) or a conjunction ($t=k$) of $k>2$ literals is computed by a balanced
|
| 1931 |
-
binary tree of $k-1$ two-input units, negated literals being carried by the signs
|
| 1932 |
-
of the weights, and a threshold $1<t<k$ by the recursion
|
| 1933 |
-
$T_t(x_1,\dots,x_k)=T_t(x_2,\dots,x_k)\vee(x_1\wedge T_{t-1}(x_2,\dots,x_k))$.
|
| 1934 |
-
An acyclic netlist of fan-in at most $2$ whose signals and records fit in the
|
| 1935 |
-
data region and the record region, compiled one record per unit in topological
|
| 1936 |
-
order, is evaluated by one pass.
|
| 1937 |
-
\end{corollary}
|
| 1938 |
-
|
| 1939 |
-
\begin{proof}
|
| 1940 |
-
For the trees pair the literals at the leaves: $\Hv(\pm x\pm y+c)$ with
|
| 1941 |
-
$c\in\{0,-1,-2\}$ is the conjunction of any two literals and with
|
| 1942 |
-
$c\in\{-1,0,1\}$ their disjunction; each level of the tree halves the number of
|
| 1943 |
-
signals, and a signal left over at a level is carried to the next. The recursion
|
| 1944 |
-
holds because at least $t$ of $x_1,\dots,x_k$ are true exactly when at least $t$
|
| 1945 |
-
of $x_2,\dots,x_k$ are, or $x_1$ is and at least $t-1$ of the others are; its
|
| 1946 |
-
two base cases are the trees. A record carries the addresses of the unit's
|
| 1947 |
-
predecessors with index flag $0$, its weights and its bias, and writes a fresh
|
| 1948 |
-
data address, so by Lemma~\ref{lem:feedback} each record reads values already
|
| 1949 |
-
computed in the pass.
|
| 1950 |
-
\end{proof}
|
| 1951 |
-
|
| 1952 |
-
\begin{remark}\label{rem:fanin2}
|
| 1953 |
-
Every unit of fan-in greater than two in $N_U$ is a disjunction or a conjunction
|
| 1954 |
-
of literals, and in $\Nhost$ so is every one except the fifteen units of the sum
|
| 1955 |
-
bits and the branch, for which the recursion of Corollary~\ref{cor:compile}
|
| 1956 |
-
gives four and eight units; the $17{,}598$ units of $\Nhost$ become $33{,}568$
|
| 1957 |
-
and the $13{,}034$ of $N_U$ become $40{,}081$, and the rewriting agrees with the
|
| 1958 |
-
original netlists on random states. Records may read and write record fields,
|
| 1959 |
-
their own included, inside the span: stored netlists of $U$ were run that emit
|
| 1960 |
-
their own records, rewrite a weight of their own record between passes, switch
|
| 1961 |
-
the active bank, and hold a two-bit counter through feedback.
|
| 1962 |
-
\end{remark}
|
| 1963 |
-
|
| 1964 |
-
\begin{proposition}[A larger member runs a smaller one]\label{prop:hierarchy}
|
| 1965 |
-
For an address width $A$ let $N_2$ be the netlist of fan-in at most $2$ obtained
|
| 1966 |
-
from the netlist of $U_{2^A}$ by Corollary~\ref{cor:compile}, with $n_2(A)$
|
| 1967 |
-
units, let $c(A)$ be the number of state coordinates of $U_{2^A}$ whose next value
|
| 1968 |
-
is not the coordinate itself, and let $m(A)$ be the number of state bits of
|
| 1969 |
-
$U_{2^A}$ plus $n_2(A)$. If a one-bank member $U_{S'}$, $S'=2^{A'}$, has
|
| 1970 |
-
$G'\ge n_2(A)+c(A)$ records and addressed span at least $m(A)$, then the stored
|
| 1971 |
-
netlist consisting of the records of $N_2$ in topological order followed by one
|
| 1972 |
-
copy record for each of the $c(A)$ coordinates satisfies: for every state $y$ of
|
| 1973 |
-
$U_{2^A}$ held in the input coordinates, one pass of $U_{S'}$ replaces $y$ by
|
| 1974 |
-
$U_{2^A}(y)$ there. So $k$ passes carry out $k$ transitions, and $U_{S'}$ runs
|
| 1975 |
-
$U_{2^A}$, stored netlist and all. Such $A'$ exist for every $A$, and
|
| 1976 |
-
$S'=O(2^AA^2)$ suffices.
|
| 1977 |
-
\end{proposition}
|
| 1978 |
-
|
| 1979 |
-
\begin{proof}
|
| 1980 |
-
By Lemma~\ref{lem:feedback} a pass evaluates the records in order. The records of
|
| 1981 |
-
$N_2$ come in topological order and write fresh coordinates, so each reads its
|
| 1982 |
-
predecessors after they have been evaluated on $y$, the input coordinates being
|
| 1983 |
-
unmodified until the copy records; after them every unit signal holds its value on
|
| 1984 |
-
$y$. Each copy record reads a unit signal, which no copy record writes, and writes
|
| 1985 |
-
a distinct input coordinate, so after all of them the input coordinates hold
|
| 1986 |
-
$U_{2^A}(y)$, those not copied keeping their values, which are their next values.
|
| 1987 |
-
No next value of $U_{2^A}$ is another input coordinate, since every next value is
|
| 1988 |
-
a multiplexer output, a disjunction, or the coordinate itself. A record of
|
| 1989 |
-
$U_{S'}$ occupies $3A'+11$ bits, so the conditions say that the records fit in
|
| 1990 |
-
$G'(3A'+11)$ bits and the signals in $S'-G'(3A'+11)$. Since $U_{2^A}$ has
|
| 1991 |
-
$O(2^A)$ units of total fan-in $O(2^AA)$, $n_2(A)=O(2^AA)$, and
|
| 1992 |
-
$2^{A'}\ge c\,2^AA\,A'$ holds for $A'=A+O(\log A)$.
|
| 1993 |
-
\end{proof}
|
| 1994 |
-
|
| 1995 |
-
\begin{remark}\label{rem:hierarchycheck}
|
| 1996 |
-
For $A=7$ the netlist of $U_{128}$ has $816$ units and its fan-in-two form $1403$
|
| 1997 |
-
units on $1534$ signals, and $35$ of its $131$ state coordinates change in a
|
| 1998 |
-
transition. The member with $A'=17$ and $G'=2088$ records of $62$ bits has
|
| 1999 |
-
$148{,}571$ units and span $1616$. From $48$ uniformly random states of $U_{128}$,
|
| 2000 |
-
stored records included, four passes of $2088$ applications each reproduced four
|
| 2001 |
-
transitions of $U_{128}$ in every one of its $131$ coordinates.
|
| 2002 |
-
\end{remark}
|
| 2003 |
-
|
| 2004 |
-
The host's constructor runs inside the family as a stored netlist. Let $P^{128}$
|
| 2005 |
-
be the program $P$ with its variable and device cells placed at the same offsets
|
| 2006 |
-
from the top of a $128$-byte memory, so that $\cell{0xF0}$ to $\cell{0xFF}$
|
| 2007 |
-
become $\cell{0x70}$ to $\cell{0x7F}$; $P$ occupies $\cell{0x00}$ to $\cell{0x3E}$
|
| 2008 |
-
and its branch targets are unchanged. The hosted transducer is that of
|
| 2009 |
-
Definitions~\ref{def:transducer} and~\ref{def:subleq} with addresses modulo
|
| 2010 |
-
$128$, halting at $\cell{0x7F}$, whose tape is the content of a $64$-byte tape
|
| 2011 |
-
region and whose output word is held in a $64$-byte output region.
|
| 2012 |
-
|
| 2013 |
-
\begin{theorem}[The constructor as a stored netlist]\label{thm:hosted}
|
| 2014 |
-
In the member $U_{2^{15}}$ of Table~\ref{tab:cfg} there is a stored netlist of
|
| 2015 |
-
$494$ records, holding in data coordinates a $128$-byte memory as eight bit
|
| 2016 |
-
planes, the tape region, the output region, the program counter, the head and
|
| 2017 |
-
the write pointer, such that one pass carries out one step of the hosted
|
| 2018 |
-
transducer from every state in which the head is at most $64$, the write pointer
|
| 2019 |
-
at most $63$, the output region clear from the write pointer on and the
|
| 2020 |
-
pointer-advance, strobe and halt signals clear; at a step that reaches the halt
|
| 2021 |
-
address the interpreter halts within the pass, with the memory, the head and
|
| 2022 |
-
the output as the step leaves them. Consequently, for every recipe $r$ with
|
| 2023 |
-
$|r|\le64$ and $|\delta(r)|\le63$, the interpreter started from the state holding
|
| 2024 |
-
$P^{128}$ and $r$ halts after exactly as many passes as Theorem~\ref{thm:univ}
|
| 2025 |
-
gives steps, with the output region holding $\delta(r)$.
|
| 2026 |
-
\end{theorem}
|
| 2027 |
-
|
| 2028 |
-
\begin{proof}
|
| 2029 |
-
A pass evaluates the records in order (Lemma~\ref{lem:feedback}). The records
|
| 2030 |
-
form cells, each a fixed sequence of records computing a Boolean function of the
|
| 2031 |
-
current values of its sources into a destination through temporaries written
|
| 2032 |
-
once: copies, negations, conjunctions and disjunctions of two literals, exclusive
|
| 2033 |
-
ors, multiplexers, conjunctions of literals as balanced trees, the addition of a
|
| 2034 |
-
constant and an increment gated by a bit; an indexed read or write is a single
|
| 2035 |
-
record. In order, the pass forms $p+1$, $p+2$, $p+3$; fetches the three operands
|
| 2036 |
-
and the two words they address through the index register; subtracts and tests
|
| 2037 |
-
the result; writes it back; applies the device to the memory so updated; and
|
| 2038 |
-
replaces the counter by the branch target, raising the halt signal at the halt
|
| 2039 |
-
address. Appendix~\ref{app:hosted} proves each cell and each stage, the
|
| 2040 |
-
invariants of the run, and the halt.
|
| 2041 |
-
\end{proof}
|
| 2042 |
-
|
| 2043 |
-
\begin{remark}\label{rem:hostedcheck}
|
| 2044 |
-
$U_{2^{15}}$ has $59{,}348$ units in $61$ levels. On the recipe for
|
| 2045 |
-
\texttt{ABCCCCCCCCDE}, which exercises a literal token, a repeat token and the end
|
| 2046 |
-
token, the interpreter halted in pass $83$, as Theorem~\ref{thm:univ} predicts,
|
| 2047 |
-
at application $44{,}358$, with the output region holding the target byte
|
| 2048 |
-
for byte, the head at the end of the recipe, and all $128$ memory bytes equal to
|
| 2049 |
-
those of the reference machine. One pass was compared with one step of the hosted
|
| 2050 |
-
transducer from $2000$ random states on a transcription of
|
| 2051 |
-
Definition~\ref{def:records} and from $256$ random states on the netlist, the
|
| 2052 |
-
memory, counter, tape, head, write pointer and output below it random, and agreed
|
| 2053 |
-
in every case.
|
| 2054 |
\end{remark}
|
| 2055 |
|
| 2056 |
% =============================================================================
|
|
@@ -2094,7 +2225,8 @@ looped transformer whose state tensor holds the program~\cite{Turkcan2026}. Thes
|
|
| 2094 |
constructions use real-valued weights, and Loom includes a layer that restores
|
| 2095 |
persistent state to $\pm1$ after numerical drift. The two-head machine of
|
| 2096 |
Section~\ref{sec:interp} is a fixed ternary network of the same kind, which
|
| 2097 |
-
evaluates any network stored in its own state
|
|
|
|
| 2098 |
Valiant's universal circuits are combinational circuits of size
|
| 2099 |
$\Theta(n\log n)$ that simulate any circuit of size $n$ given its program bits as
|
| 2100 |
input~\cite{Valiant1976}; intrinsic simulation between families of automata
|
|
@@ -2166,9 +2298,11 @@ not imply it, and require that the maps mediating between symbolic computation a
|
|
| 2166 |
the dynamics be simpler than the computation attributed to the
|
| 2167 |
system~\cite{CotlerHonglerHudcova2025}. In those terms Section~\ref{sec:selfrep}
|
| 2168 |
is a replicator relative to an instantiation map whose cost
|
| 2169 |
-
Proposition~\ref{prop:envcost} counts, and
|
| 2170 |
-
|
| 2171 |
-
|
|
|
|
|
|
|
| 2172 |
|
| 2173 |
\subsection{Networks that produce their own parameters}
|
| 2174 |
|
|
@@ -2377,35 +2511,39 @@ or from its $75{,}501$ nonzero entries; and (d) an evaluator in C,
|
|
| 2377 |
\texttt{src/netlist\_eval.c}, with its own SUBLEQ reference, device, parser and
|
| 2378 |
levelization, sharing no code with (a)--(c). Evaluators (b)--(d) are built from
|
| 2379 |
$\sigma(\Nhost)$, and every generation of every run instantiated its evaluator
|
| 2380 |
-
afresh from the bytes the previous generation emitted. The
|
| 2381 |
-
|
| 2382 |
-
|
| 2383 |
-
|
| 2384 |
-
|
| 2385 |
-
|
| 2386 |
-
|
| 2387 |
-
|
| 2388 |
-
|
|
|
|
|
|
|
| 2389 |
with a simulator in C and on the accelerator, and maps the datapath onto Loihi
|
| 2390 |
and Akida; its sizes, depths and exact runs are those stated here, and its noisy
|
| 2391 |
runs agree with Appendix~\ref{app:measure} within sampling error.
|
| 2392 |
|
| 2393 |
The Rocq development, \texttt{rocq/} in the artifact, has $25$ files and
|
| 2394 |
-
$
|
| 2395 |
-
below, most of it in the kernel's evaluations of the first three generations
|
| 2396 |
-
defines the two-head machine
|
| 2397 |
-
description code and the decoder, and
|
| 2398 |
-
|
| 2399 |
-
and
|
| 2400 |
-
|
| 2401 |
-
|
|
|
|
|
|
|
| 2402 |
organism and its description is written by \texttt{src/twohead.py}, and the
|
| 2403 |
-
netlist definition, extracted to OCaml, writes
|
| 2404 |
-
|
| 2405 |
\texttt{src/twohead\_net.py} writes.
|
| 2406 |
|
| 2407 |
Besides the runs recorded in the remarks of Sections~\ref{sec:host}
|
| 2408 |
-
to~\ref{sec:
|
| 2409 |
checked. The encoder satisfies $\delta(\describe(f))=f$ within the bound of
|
| 2410 |
Lemma~\ref{lem:describe} on the $29$ serialized machines of the artifact,
|
| 2411 |
$971{,}266{,}155$ bytes, and on $68{,}061$ further strings chosen to straddle
|
|
@@ -2419,9 +2557,8 @@ $16{,}320$ steps and the device with its four clauses on $20{,}580$ applications
|
|
| 2419 |
$\inst(\ser(\Omega))=\Omega$ on $310$ instances; and rebuilding the host from
|
| 2420 |
source reproduces its serialization byte for byte. Evaluator~(d) agrees with its
|
| 2421 |
own reference on $2^{20}$ random full states of the netlist and of its
|
| 2422 |
-
levelization, and $\Lev(\Nhost)$
|
| 2423 |
-
|
| 2424 |
-
integer.
|
| 2425 |
|
| 2426 |
The constructor was run on the $29$ recipes of the artifact's machines on the
|
| 2427 |
integer reference, emitting $971{,}266{,}155$ bytes in $4{,}714{,}592{,}952$ steps,
|
|
@@ -2458,179 +2595,57 @@ generations on~(d) ran in lockstep.}
|
|
| 2458 |
Every run of $\Omega^\ast$ produced the same output, of SHA-256 digest
|
| 2459 |
\texttt{c5950d3f\ldots6e7fb523}, and the artifact~\cite{Norton2026} is identified by
|
| 2460 |
the digests of $\ser(\Omega^\ast)$, of the host serialization, of the serialization
|
| 2461 |
-
of $N_3$, of $\ser(\Omega^\ast_3)$, of the netlist file of $
|
| 2462 |
the organism's record image and its description written as $3458$ and $2930$
|
| 2463 |
-
bytes of value $0$ or $1$
|
|
|
|
| 2464 |
\begin{center}\ttfamily\small
|
| 2465 |
\begin{tabular}{@{}l@{\quad}l@{}}
|
| 2466 |
\normalfont $\ser(\Omega^\ast)$ & c5950d3fec6bcf70e8111586a030d21b2dfa55bd69a1c7fe5f016cb06e7fb523\\
|
| 2467 |
\normalfont $\sigma(\Nhost)$ & 55c555bd64302190d5bde57ee0cd41b36dac5cf65066d0ed3468567a57e85fa3\\
|
| 2468 |
\normalfont $\sigma(N_3)$ & 111bb202e6f2728449c6b0761f57a059bc0fb38e3e5ba8447bac6613ec7ce313\\
|
| 2469 |
\normalfont $\ser(\Omega^\ast_3)$ & 05005d59c373fb4998576ac098093de6df046355348e00370dbdccb1d458e3de\\
|
| 2470 |
-
\normalfont $
|
| 2471 |
\normalfont organism $\rho$ & e798ce81da252d6717b0f99321aa401924637b48fe09558a6590006de2e2ffe1\\
|
| 2472 |
-
\normalfont $\describe(\rho)$ & 59c917d4b2602b253bbae19d9866869587abea197730197fee8054acc8781d54
|
|
|
|
|
|
|
| 2473 |
\end{tabular}
|
| 2474 |
\end{center}
|
| 2475 |
-
The
|
| 2476 |
-
|
| 2477 |
-
|
| 2478 |
-
|
| 2479 |
-
|
| 2480 |
-
|
| 2481 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2482 |
produced with Python 3.12.3, PyTorch 2.14.0 with CUDA 12.6, NumPy 2.5.3,
|
| 2483 |
safetensors 0.8.0 and GCC 13.3.0 on Ubuntu 24.04, on an Intel Core i9-12900H
|
| 2484 |
with $20$ hardware threads and $31$ GiB of memory and an NVIDIA GeForce RTX 3070
|
| 2485 |
Ti Laptop GPU with $8$ GiB of memory.
|
| 2486 |
|
| 2487 |
-
% =============================================================================
|
| 2488 |
-
\section{Proof of Theorem~\ref{thm:hosted}}\label{app:hosted}
|
| 2489 |
-
% =============================================================================
|
| 2490 |
-
|
| 2491 |
-
Throughout, $U'=U_{2^{15}}$: $A=15$, one bank of $G=535$ records of $b=56$ bits
|
| 2492 |
-
at the coordinates from $2808$ on, and the addressed span the coordinates $0$ to
|
| 2493 |
-
$2807$. Coordinates $0$ to $14$ hold $\mathrm{PTR}$, most significant first,
|
| 2494 |
-
$15$ to $19$ hold $\mathrm{OUT\_DATA}$, $\mathrm{OUT\_STROBE}$, $\mathrm{ADV}$,
|
| 2495 |
-
$\kappa$ and $\mathrm{HALT}$, and $20$ is the sink. The stored netlist is the
|
| 2496 |
-
$494$ records described below, followed by $41$ records with both weights $0$
|
| 2497 |
-
and bias $-1$ that write $0$ into the sink, which no record reads. Its signals
|
| 2498 |
-
are the work region, coordinates $21$ to $720$, holding the registers
|
| 2499 |
-
$\mathrm{PC}$, $P_1$, $P_2$, $P_3$, $\mathrm{NPC}$, $\mathrm{head}$ and $\mathrm{wp}$
|
| 2500 |
-
of seven bits and $A$, $B$, $C$, $X$, $Y$, $R$ of eight bits, least significant
|
| 2501 |
-
bit first, and the temporaries; the memory, bit $t$ of byte $j$ at $721+128t+j$;
|
| 2502 |
-
the tape region, bit $t$ of byte $i$ at $1745+64t+i$; and the output region, bit
|
| 2503 |
-
$t$ of byte $i$ at $2257+64t+i$, bit $0$ being the least significant.
|
| 2504 |
-
|
| 2505 |
-
A hosted state $(M,p,\tau,h,\omega)$, with $M\in\Sigma^{128}$, $p<128$,
|
| 2506 |
-
$\tau\in\Sigma^{64}$, $h\le64$ and an output word $\omega$ of $w\le63$ bytes, is
|
| 2507 |
-
\emph{held} by a state $x$ of $U'$ when the memory, the tape region and the
|
| 2508 |
-
first $w$ bytes of the output region hold $M$, $\tau$ and $\omega$, the bytes
|
| 2509 |
-
from $w$ on of the output region are $0$, the registers $\mathrm{PC}$,
|
| 2510 |
-
$\mathrm{head}$ and $\mathrm{wp}$ hold $p$, $h$ and $w$, the signals
|
| 2511 |
-
$\mathrm{ADV}$, $\mathrm{OUT\_STROBE}$ and $\mathrm{HALT}$ are $0$, and the record
|
| 2512 |
-
counter and the halt bit are $0$.
|
| 2513 |
-
|
| 2514 |
-
\subsection*{Records}
|
| 2515 |
-
A pass evaluates the records in order, each on the state the records before it
|
| 2516 |
-
left (Lemma~\ref{lem:feedback}). The first eight records clear the bits $7$ to
|
| 2517 |
-
$14$ of $\mathrm{PTR}$, and the pass writes the low seven bits only by copying a
|
| 2518 |
-
register into them, so every indexed slot names a coordinate $\mathrm{base}+p'$
|
| 2519 |
-
with $p'\le127$; the bases and offsets used below keep every named coordinate in
|
| 2520 |
-
the work, memory, tape or output region or at most one coordinate past the tape
|
| 2521 |
-
region, all inside the span, so no read returns the default $0$ in place of a
|
| 2522 |
-
stored value. No record writes $\mathrm{ADV}$, $\mathrm{OUT\_STROBE}$, $\kappa$ or
|
| 2523 |
-
the bank, so the pointer and output clauses never fire and the stored netlist
|
| 2524 |
-
does not change.
|
| 2525 |
-
|
| 2526 |
-
\subsection*{Cells}
|
| 2527 |
-
Each temporary is the destination of one record, which precedes every record
|
| 2528 |
-
that reads it. A record with weights $w_0,w_1$ and bias $\beta$ writes
|
| 2529 |
-
$\Hv(w_0x_0+w_1x_1+\beta)$, so the following single records are correct on
|
| 2530 |
-
$\B$: a constant, bias $0$ or $-1$ and no input; a copy $\Hv(x-1)$; a negation
|
| 2531 |
-
$\Hv(-x)$; a conjunction of two literals, weights $\pm1$ by polarity and bias
|
| 2532 |
-
minus the number of positive literals; a disjunction $\Hv(x+y-1)$; an indexed
|
| 2533 |
-
read $y\leftarrow x_{\mathrm{base}+\mathrm{PTR}}$, a copy whose input slot carries
|
| 2534 |
-
the index flag; an indexed write $x_{\mathrm{base}+\mathrm{PTR}}\leftarrow y$, a
|
| 2535 |
-
copy whose output carries the index flag; and the indexed write of $y\wedge g$, a
|
| 2536 |
-
conjunction whose output carries the flag. The cells of several records are the
|
| 2537 |
-
following, each changing its destination and its temporaries and nothing else.
|
| 2538 |
-
\begin{enumerate}[label=(\roman*),leftmargin=2em]
|
| 2539 |
-
\item The exclusive or of $a$ and $b$ writes $t_1=a\vee b$, then
|
| 2540 |
-
$t_2=\Hv(1-a-b)=\neg(a\wedge b)$, then $t_1\wedge t_2=a\oplus b$. Its last record
|
| 2541 |
-
reads only $t_1$ and $t_2$, so the cell is correct when its destination is $a$ or
|
| 2542 |
-
$b$.
|
| 2543 |
-
\item The multiplexer $d\leftarrow s\,?\,x_1:x_0$ writes $\neg s$, $x_1\wedge s$,
|
| 2544 |
-
$x_0\wedge\neg s$ and their disjunction; its last record reads only the two
|
| 2545 |
-
conjunctions, so it is correct when $d$ is $x_0$.
|
| 2546 |
-
\item The conjunction of $k$ literals pairs them at the leaves of a balanced tree,
|
| 2547 |
-
a single literal left over being copied or negated, and conjoins the results
|
| 2548 |
-
level by level; the root writes the destination.
|
| 2549 |
-
\item The addition of a constant $c$ to a register $s$ on seven bits treats the bit
|
| 2550 |
-
positions from the least significant up, with no carry before the first position
|
| 2551 |
-
at which $c$ has a $1$: such a position $k$ writes $d_k=\neg s_k$ and starts the
|
| 2552 |
-
carry $s_k$; a later position with a $1$ writes $d_k=\neg(s_k\oplus\gamma)$ and the
|
| 2553 |
-
carry $s_k\vee\gamma$; a position with a $0$ writes $d_k=s_k\oplus\gamma$ and the carry
|
| 2554 |
-
$s_k\wedge\gamma$, or copies $s_k$ while there is no carry. These are the sum and the
|
| 2555 |
-
carry of $s_k+c_k+\gamma$, so $d=(s+c)\bmod128$.
|
| 2556 |
-
\item The increment of a seven-bit register $s$ by a bit $g$ first forms the carries
|
| 2557 |
-
$\gamma_0=g$ and $\gamma_{k+1}=s_k\wedge\gamma_k$ for $k<6$, and then replaces each
|
| 2558 |
-
$s_k$ by $s_k\oplus\gamma_k$, by~(i); the carries are formed before any bit
|
| 2559 |
-
changes, so $s$ becomes $(s+g)\bmod128$.
|
| 2560 |
-
\end{enumerate}
|
| 2561 |
-
|
| 2562 |
-
\subsection*{The pass}
|
| 2563 |
-
Let $x$ hold $(M,p,\tau,h,\omega)$ with $p\ne\cell{0x7F}$ as the start of a pass,
|
| 2564 |
-
let $(M',p',h',\omega')$ be the result of one step of the hosted transducer, and
|
| 2565 |
-
write $\pi(v)$ for the copies of the seven low bits of a register $v$ into the
|
| 2566 |
-
low bits of $\mathrm{PTR}$, which set $\mathrm{PTR}$ to $v\bmod128$.
|
| 2567 |
-
\begin{enumerate}[label=(\alph*),leftmargin=2em]
|
| 2568 |
-
\item Eight constants clear the high bits of $\mathrm{PTR}$, and three additions of
|
| 2569 |
-
a constant set $P_1$, $P_2$, $P_3$ to $p+1$, $p+2$ and $p+3$ modulo $128$.
|
| 2570 |
-
\item $\pi(\mathrm{PC})$ and eight indexed reads at the bases of the eight memory
|
| 2571 |
-
planes set $A=M[p]$, bit $t$ from plane $t$; likewise $\pi(P_1)$ and $\pi(P_2)$
|
| 2572 |
-
set $B=M[p+1]$ and $C=M[p+2]$, and $\pi(A)$ and $\pi(B)$ set $X=M[a]$ and $Y=M[b]$,
|
| 2573 |
-
where $a$ and $b$ are $A$ and $B$ modulo $128$.
|
| 2574 |
-
\item Eight negations form the bits of $\neg X$. Position $0$ forms
|
| 2575 |
-
$u=y_0\oplus\neg x_0$, $R_0=\neg u$ and the carry $y_0\vee\neg x_0$, the sum and carry
|
| 2576 |
-
of $y_0+\neg x_0+1$; each position $k\ge1$ forms $u=y_k\oplus\neg x_k$,
|
| 2577 |
-
$R_k=u\oplus\gamma$ and the carry $(y_k\wedge\neg x_k)\vee(u\wedge\gamma)$, the sum and
|
| 2578 |
-
carry of $y_k+\neg x_k+\gamma$. Hence $R=Y+\bar X+1=(Y-X)\bmod256$. A chain of
|
| 2579 |
-
disjunctions and a negation form $[R=0]$, and its disjunction with $R_7$ is
|
| 2580 |
-
$[R\le0]$ in two's complement, as in Lemma~\ref{lem:branch}.
|
| 2581 |
-
\item $\pi(B)$ and eight indexed writes store $R$ at $M[b]$. The memory is now the
|
| 2582 |
-
memory after the instruction of Definition~\ref{def:subleq}, which we call $N$.
|
| 2583 |
-
\item The device acts on $N$. Three conjunctions of eight literals, bit $0$
|
| 2584 |
-
positive and bits $1$ to $7$ negated, form the requests
|
| 2585 |
-
$\mathrm{wr}=[N[c_{\mathrm{wr}}]=1]$, $\mathrm{rd}$ and $\mathrm{rw}$; a conjunction of
|
| 2586 |
-
the literals of $\mathrm{head}$ against the bits of $64$ forms $[h=64]$, which for
|
| 2587 |
-
$h\le64$ is $[h\ge64]$, and $g=\mathrm{rd}\wedge\neg[h=64]$. Then $\pi(\mathrm{head})$
|
| 2588 |
-
and eight indexed reads of the tape planes give $\tau_h$ when $h<64$; eight
|
| 2589 |
-
multiplexers on $g$ load it into $R_{\mathrm{in}}$; a multiplexer on $\mathrm{rd}$
|
| 2590 |
-
sets bit $0$ of $c_{\mathrm{eot}}$ to $[h=64]$ and seven conjunctions clear its
|
| 2591 |
-
other bits when $\mathrm{rd}=1$; an increment adds $g$ to $\mathrm{head}$, which
|
| 2592 |
-
stays at most $64$, and seven conjunctions with $\neg\mathrm{rw}$ clear it on a
|
| 2593 |
-
rewind. Then $\pi(\mathrm{wp})$ and eight indexed writes store
|
| 2594 |
-
$R_{\mathrm{out}}\wedge\mathrm{wr}$ at byte $w$ of the output region, eight
|
| 2595 |
-
conjunctions with $\neg\mathrm{wr}$ clear $R_{\mathrm{out}}$ when it was emitted, an
|
| 2596 |
-
increment adds $\mathrm{wr}$ to $\mathrm{wp}$, and twenty-four constants clear the
|
| 2597 |
-
three request cells. These are the clauses of Definition~\ref{def:transducer} on
|
| 2598 |
-
$N$: a read at $h<64$ loads $\tau_h$, clears $c_{\mathrm{eot}}$ and advances the
|
| 2599 |
-
head, a read at $h=64$ sets $c_{\mathrm{eot}}$ and leaves $R_{\mathrm{in}}$ and the
|
| 2600 |
-
head, the rewind follows the read, and a write appends $R_{\mathrm{out}}$ to the
|
| 2601 |
-
output word and clears it. The clauses touch disjoint cells apart from the head,
|
| 2602 |
-
which the read changes before the rewind, as the definition orders them. When
|
| 2603 |
-
$\mathrm{wr}=0$ the indexed writes store $0$ at byte $w$, which was $0$. So the
|
| 2604 |
-
memory, the head, the output region and $\mathrm{wp}$ now hold $M'$, $h'$,
|
| 2605 |
-
$\omega'$ and the length of $\omega'$.
|
| 2606 |
-
\item Seven multiplexers on $[R\le0]$ set $\mathrm{NPC}$ to $C\bmod128$ or to $P_3$,
|
| 2607 |
-
which is the counter $p'$ of Definition~\ref{def:subleq} modulo $128$; a
|
| 2608 |
-
conjunction of the literals of $\mathrm{NPC}$ against the bits of $\cell{0x7F}$
|
| 2609 |
-
writes $[p'=\cell{0x7F}]$ into $\mathrm{HALT}$; and seven copies set $\mathrm{PC}$ to
|
| 2610 |
-
$\mathrm{NPC}$.
|
| 2611 |
-
\end{enumerate}
|
| 2612 |
-
If $p'\ne\cell{0x7F}$ the state after the pass holds $(M',p',\tau,h',\omega')$,
|
| 2613 |
-
with $\mathrm{HALT}=0$ and the record counter back at $0$ after the no-op records.
|
| 2614 |
-
If $p'=\cell{0x7F}$, the record that writes $\mathrm{HALT}$ is followed by one more
|
| 2615 |
-
application, which evaluates the first copy into $\mathrm{PC}$ and sets the halt
|
| 2616 |
-
bit, the next halt bit being the disjunction with $x_{\mathrm{HALT}}$; after it the
|
| 2617 |
-
state is fixed, with the memory, the head and the output as the step leaves
|
| 2618 |
-
them. This proves the first statement of the theorem.
|
| 2619 |
-
|
| 2620 |
-
\subsection*{The run}
|
| 2621 |
-
Let $r$ be a recipe with $|r|\le64$ and $|\delta(r)|\le63$, and let $\tau$ be $r$
|
| 2622 |
-
followed by $64-|r|$ bytes $0$. The program $P^{128}$ is $P$ with the cells it
|
| 2623 |
-
names moved to the same offsets from the top of the memory, and the proof of
|
| 2624 |
-
Theorem~\ref{thm:univ} uses only the transducer, so it holds for $P^{128}$ on
|
| 2625 |
-
$\tau$: the run halts after the number of steps the theorem gives, with output
|
| 2626 |
-
$\delta(r)$, and it never reads past the end token, so the bytes after $r$ are
|
| 2627 |
-
never read and the head stays at most $|r|\le64$. Its output word is a prefix of
|
| 2628 |
-
$\delta(r)$ at every step, so it has at most $63$ bytes. The state holding $P^{128}$
|
| 2629 |
-
and $r$ holds the initial hosted state, so by induction over the steps, the
|
| 2630 |
-
hypothesis of the first statement holding at each, every pass but the last
|
| 2631 |
-
carries out a step and the last carries out the halting step and halts, with the
|
| 2632 |
-
output region holding $\delta(r)$.
|
| 2633 |
-
|
| 2634 |
% =============================================================================
|
| 2635 |
\section{Program listings and the organism}\label{app:listings}
|
| 2636 |
% =============================================================================
|
|
@@ -2702,12 +2717,14 @@ $63$ bytes of $P$.
|
|
| 2702 |
consists of the $133$ records below, in the order a pass evaluates them; record
|
| 2703 |
$k$ is written $k{:}\;{\pm}a\,{\pm}b\;\beta{\to}o$, reading window cells $a$ and $b$
|
| 2704 |
with weights $\pm1$ and writing cell $o$, and a record with one slot has weight
|
| 2705 |
-
$0$ in the other
|
| 2706 |
-
$\mathrm{cpy}$ are the cells
|
| 2707 |
-
$
|
| 2708 |
-
|
| 2709 |
-
|
| 2710 |
-
$
|
|
|
|
|
|
|
| 2711 |
|
| 2712 |
{\scriptsize\raggedright\noindent \mbox{$0{:}\;{-}z_0\,{-}z_1\;0{\to}t_{21}$}\hspace{0.7em plus 0.5em}
|
| 2713 |
\mbox{$1{:}\;{+}t_{21}\,{-}z_2\;{-}1{\to}t_{21}$}\hspace{0.7em plus 0.5em}
|
|
|
|
| 7 |
\usepackage{booktabs,tabularx,array}
|
| 8 |
\usepackage{cite}
|
| 9 |
\usepackage{enumitem}
|
| 10 |
+
\usepackage{tikz}
|
| 11 |
+
\usetikzlibrary{arrows.meta,calc}
|
| 12 |
+
\usepackage{pgfplots}
|
| 13 |
+
\pgfplotsset{compat=1.18}
|
| 14 |
\usepackage[margin=1in]{geometry}
|
| 15 |
+
\setlength{\emergencystretch}{2em}
|
| 16 |
\usepackage[colorlinks=true,linkcolor=blue,citecolor=blue,urlcolor=blue]{hyperref}
|
| 17 |
|
| 18 |
% ---- theorem environments ---------------------------------------------------
|
|
|
|
| 67 |
$\{-1,0,1\}$ and integer thresholds, iterated as a fixed composition of ternary
|
| 68 |
matrix--vector products and Heaviside steps, and construct networks of this kind
|
| 69 |
that carry out von Neumann's scheme of universal construction and
|
| 70 |
+
self-reproduction exactly, by their dynamics alone. A SUBLEQ computer of
|
| 71 |
+
$17{,}598$ units, one member of a family whose step has depth $13$ at every word
|
| 72 |
+
width, runs a program of $21$ instructions that emits any byte string from a
|
| 73 |
+
run-length description, and one of $27$ instructions that decodes a description
|
| 74 |
+
and then copies it, with which the computer emits the serialization of every bias
|
| 75 |
+
and edge of itself, its memory and its tape. A fixed network holds a stored
|
| 76 |
+
network in its state, as records in two banks with two tapes under three heads,
|
| 77 |
+
and evaluates one record per step; proofs checked in Rocq show that it computes
|
| 78 |
+
the step of this machine from every state at every size. Stored in it as
|
| 79 |
+
$36{,}074$ records of two inputs, the SUBLEQ computer runs the program of $27$
|
| 80 |
+
instructions on a description of its own records: it writes them into the idle
|
| 81 |
+
bank, copies the description and hands control to the copy, which does the same.
|
| 82 |
+
The fixed network thus rebuilds, exactly and in every generation, the weights of
|
| 83 |
+
the stored network that computes, with no map outside it; a constructor of $133$
|
| 84 |
+
records does the same 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
|
| 88 |
+
read every copy of their inputs multiplies every margin by $r$, so any noise level
|
| 89 |
+
is survived with redundancy $O(s\sqrt{\log(TM/\delta)})$, and the threefold host
|
| 90 |
+
completes the self-reproducing run at noise levels at which the host fails within
|
| 91 |
+
its first bytes.
|
|
|
|
|
|
|
| 92 |
\end{abstract}
|
| 93 |
|
| 94 |
\maketitle
|
|
|
|
| 118 |
behaviour is the orbit of an initial state. The paper treats two questions.
|
| 119 |
The first is whether such an orbit can emit, exactly, a serialization of the
|
| 120 |
weights that define $F$ together with the rest of the initial data, so that
|
| 121 |
+
loading the emitted data yields a process that emits the same data. This is the
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
setting of program replicators, which rely on an execution environment to
|
| 123 |
+
instantiate what they emit~\cite{CotlerHonglerHudcova2025}. The second removes
|
| 124 |
+
the environment: whether a fixed network can hold threshold networks in its state
|
| 125 |
+
as data, and whether a universal computer so held can construct its own records
|
| 126 |
+
from a description, copy the description and hand over control to what it built,
|
| 127 |
+
so that the dynamics alone rebuilds the weights of the network that computes.
|
| 128 |
+
This is the setting of von Neumann's cellular constructions, with a threshold
|
| 129 |
+
network as the transition rule and threshold netlists as the configurations: the
|
| 130 |
+
network that reproduces is held as state, and the fixed network that holds it
|
| 131 |
+
plays the part of the cellular rule.
|
| 132 |
|
| 133 |
Integer weights make the reproduction exact. A trained network that outputs an
|
| 134 |
approximation of its weights loses information in every generation, while a
|
|
|
|
| 160 |
$|f|+\lceil|f|/127\rceil+1$, and none shorter when $f$ has no two equal adjacent
|
| 161 |
bytes (Section~\ref{sec:univ}).
|
| 162 |
\item \emph{Exact self-reproduction of the host.} A program of $27$
|
| 163 |
+
instructions, separating construction from copying as von Neumann did, that
|
| 164 |
+
decodes a recipe and then copies it, so that the host emits the serialization of
|
| 165 |
+
itself, its memory and its tape. This is the standard quine scheme run on a
|
| 166 |
+
universal machine; a fixed instantiation map of linear cost, outside the network,
|
| 167 |
+
turns the output into the next running instance (Section~\ref{sec:selfrep}).
|
|
|
|
| 168 |
\item \emph{Self-reproduction by the dynamics.} A family of ternary threshold
|
| 169 |
+
networks $N^\alpha_{G,L}$ whose state holds a stored network as records in two
|
| 170 |
+
banks, with two tapes and three heads, each step evaluating one record; the
|
| 171 |
+
network computes the step of this two-head machine from every state, for every
|
| 172 |
+
window of $2^\alpha$ cells and every $G$ and $L$, a proof checked in Rocq
|
| 173 |
+
(Theorem~\ref{thm:physnet}). Stored in the member with $4096$ cells as
|
| 174 |
+
$36{,}074$ records of two inputs, the units of the host with records that load its
|
| 175 |
+
memory, its tape device and a hand-over, the host running $P^\ast$ builds every
|
| 176 |
+
image of its size from any recipe for it into the idle bank and hands control to
|
| 177 |
+
it, and started on a recipe for its own records it reproduces in every
|
| 178 |
+
generation, weights included, the orbit of the network being periodic
|
| 179 |
+
(Theorems~\ref{thm:storedconstruct} and~\ref{thm:storedrep}); three generations
|
| 180 |
+
of $7.9\times10^{10}$ steps each were run. A constructor of $133$ records with a
|
| 181 |
+
description code of its own does the same in the member with $64$ cells, every
|
| 182 |
+
step of it proved in Rocq (Section~\ref{sec:organism}).
|
| 183 |
\item \emph{Robustness.} Every orbit survives perturbations below $1/2$ per
|
| 184 |
pre-activation. The tolerances for weight and leakage errors are given by
|
| 185 |
fan-in and layer width and, along an orbit, by its active inputs, and a bound
|
|
|
|
| 205 |
|
| 206 |
Sections~\ref{sec:prelim} to~\ref{sec:robust} define the networks, build the
|
| 207 |
host, carry out construction and self-reproduction on it and treat
|
| 208 |
+
perturbations. Section~\ref{sec:interp} gives the two-head machine,
|
| 209 |
+
Section~\ref{sec:storedhost} stores the host in it and shows that it reproduces
|
| 210 |
+
itself by the dynamics, Section~\ref{sec:organism} gives the constructor proved in
|
| 211 |
+
Rocq, and Section~\ref{sec:related} related work. The appendices give the
|
| 212 |
+
measurements in full, what was executed and checked in Rocq with what reproduces
|
| 213 |
+
each published digest, and the listings.
|
| 214 |
|
| 215 |
% =============================================================================
|
| 216 |
\section{Threshold maps, transducers, and reproduction}\label{sec:prelim}
|
|
|
|
| 456 |
The maps $\inst$ and $\Lev$ together with the device of
|
| 457 |
Definition~\ref{def:transducer} are the \emph{instantiation map}: the network
|
| 458 |
emits a description, and $\inst$, $\sigma^{-1}$ and $\Lev$ turn it into the next
|
| 459 |
+
running network. Section~\ref{sec:storedhost} removes the map: the host, held as
|
| 460 |
+
records in the state of a fixed network, carries out the same step by the
|
| 461 |
+
dynamics. With the map, the cost for the host is the following.
|
| 462 |
|
| 463 |
\begin{proposition}[Cost of instantiation]\label{prop:envcost}
|
| 464 |
Let $\Omega=(N,m,\tau)$ be an instance whose run halts after $T$ steps, and let
|
|
|
|
| 633 |
|
| 634 |
\begin{construction}[The host family]\label{con:host}
|
| 635 |
For $A\ge3$ the netlist $H_A$ has the blocks of Table~\ref{tab:blocks}, in that
|
| 636 |
+
order, each unit after its predecessors. Its state is, in this order, the $A$
|
| 637 |
+
counter bits, a halt bit and the $A\cdot2^A$ memory bits word by word, the counter
|
| 638 |
+
and each word most significant bit first, so $n=A+1+A2^A$; for $A=8$ the counter
|
| 639 |
+
occupies coordinates $0$ to $7$, the halt bit $8$, and bit $k$ of word $j$, $k=0$
|
| 640 |
+
the most significant, coordinate $9+8j+k$. The decode lines $P_j$
|
| 641 |
of $p$ give the three operands by reindexing, $M[p+o]_t=\bigvee_j(\mu_{j+o,t}\wedge
|
| 642 |
P_j)$, and the bits of $p+3$ as disjunctions of the lines $P_j$ for which the
|
| 643 |
corresponding bit of $j+3\bmod 2^A$ is $1$. The decode lines of $a$ and $b$ give
|
|
|
|
| 955 |
\end{construction}
|
| 956 |
|
| 957 |
\begin{theorem}[Exact self-reproduction]\label{thm:selfrep}
|
| 958 |
+
For every recipe $\tau$ the instance $(\Nhost,m^\ast,\tau)$ halts and
|
| 959 |
+
$\Out(\Nhost,m^\ast,\tau)=\delta(\tau)\cat\tau$; its run reads no byte at
|
| 960 |
+
$h=|\tau|$ before it requests the rewind, and requests it at $h=|\tau|$. In
|
| 961 |
+
particular $\Omega^\ast=(\Nhost,m^\ast,\tau^\ast)$ is exactly self-reproducing,
|
| 962 |
+
$\Out(\Omega^\ast)=\ser(\Omega^\ast)$, and the generations
|
| 963 |
$\Omega_{k+1}=\inst(\Out(\Omega_k))$ starting from $\Omega^\ast$ are constant.
|
| 964 |
\end{theorem}
|
| 965 |
|
| 966 |
\begin{proof}
|
| 967 |
Phase~(A) consists of the instructions of $P$ with the same memory layout, and
|
| 968 |
the cells $\cell{EOK}$ and $c_{\mathrm{eot}}$ are not addressed by them, so the
|
| 969 |
+
proof of Theorem~\ref{thm:univ} applies: every token of $\tau$ is consumed in
|
| 970 |
+
order, no byte is read after the end token, and when the end token is read the
|
| 971 |
+
output word is $\delta(\tau)$, the head is at $|\tau|$, $M[\cell{Z}]=0$,
|
| 972 |
+
$M[R_{\mathrm{out}}]=0$, $M[\cell{EOK}]=1$, and all request bits are $0$.
|
| 973 |
+
Phase~(R) assigns $M[c_{\mathrm{rw}}]\leftarrow 1$, the result being positive, and
|
| 974 |
+
the device sets $h=0$ and clears $c_{\mathrm{rw}}$.
|
|
|
|
| 975 |
|
| 976 |
For phase~(B) consider the assertion
|
| 977 |
\[
|
| 978 |
J_i:\quad
|
| 979 |
\begin{minipage}{0.78\textwidth}
|
| 980 |
control reaches the head of phase~(B) with head position $i$, output word
|
| 981 |
+
$\omega=\delta(\tau)\cat\tau_0\cdots\tau_{i-1}$,
|
| 982 |
$M[\cell{Z}]=0$, $M[\cell{EOK}]=1$, $M[R_{\mathrm{out}}]=0$, all request bits $0$.
|
| 983 |
\end{minipage}
|
| 984 |
\]
|
| 985 |
$J_0$ holds. Assume $J_i$; the first instruction requests a read. If
|
| 986 |
+
$i<|\tau|$, the device loads $\tau_i$, clears $c_{\mathrm{eot}}$ and
|
| 987 |
advances the head; the second instruction leaves $\cell{EOK}=1$, positive; the
|
| 988 |
+
third and fourth assign $M[\cell{Z}]\leftarrow\nu(\tau_i)$ and
|
| 989 |
+
$M[R_{\mathrm{out}}]\leftarrow\tau_i$; the fifth emits $\tau_i$; the
|
| 990 |
sixth restores $M[\cell{Z}]=0$ and branches back, so $J_{i+1}$ holds. If
|
| 991 |
+
$i=|\tau|$, the device sets $c_{\mathrm{eot}}=1$, the second instruction
|
| 992 |
assigns $M[\cell{EOK}]\leftarrow0$ and transfers control to $\cell{0xFF}$, and the
|
| 993 |
+
output word is $\delta(\tau)\cat\tau$. For $\tau=\tau^\ast$,
|
| 994 |
+
$\delta(\tau^\ast)=\field{\sigma(\Nhost)}\cat\field{m^\ast}$ by
|
| 995 |
+
Lemma~\ref{lem:describe}, so the output is $\ser(\Omega^\ast)$, and the last
|
| 996 |
statement is Lemma~\ref{lem:generations}.
|
| 997 |
\end{proof}
|
| 998 |
|
|
|
|
| 1223 |
exact orbit, the profile bound of Proposition~\ref{prop:profile} lies $2\%$ to
|
| 1224 |
$19\%$ above the measured per-step rate, in the run of Table~\ref{tab:curve} and
|
| 1225 |
in a repetition with a separate simulator, and $Mp$ exceeds the bound by a factor
|
| 1226 |
+
of $2.7$ (Figure~\ref{fig:noise}(a)). Under read noise on every
|
| 1227 |
pre-activation the complete self-reproducing run emits the whole instance at
|
| 1228 |
$s=0.05$ and has its halt bit set after $143$ bytes at $s=0.10$
|
| 1229 |
(Table~\ref{tab:noise}). Under static weight error the orbit stays exact up to a
|
|
|
|
| 1231 |
thirteen settings of Table~\ref{tab:leak}, Corollary~\ref{cor:mismatch}
|
| 1232 |
certifies three and Proposition~\ref{prop:orbit} nine.
|
| 1233 |
|
| 1234 |
+
\begin{figure}[t]
|
| 1235 |
+
\centering
|
| 1236 |
+
\begin{tikzpicture}
|
| 1237 |
+
\begin{semilogyaxis}[name=a,width=7.4cm,height=5.8cm,font=\footnotesize,
|
| 1238 |
+
xlabel={noise deviation $s$},ylabel={per-step probability},
|
| 1239 |
+
xmin=0.055,xmax=0.155,ymin=1e-13,ymax=1e2,
|
| 1240 |
+
xtick={0.06,0.08,0.10,0.12,0.14},
|
| 1241 |
+
xticklabel style={/pgf/number format/fixed,/pgf/number format/fixed zerofill,/pgf/number format/precision=2},
|
| 1242 |
+
ytick={1e-12,1e-9,1e-6,1e-3,1},
|
| 1243 |
+
legend style={font=\scriptsize,at={(0.97,0.03)},anchor=south east,draw=none,fill=white,fill opacity=0.8,text opacity=1},
|
| 1244 |
+
legend cell align=left,title={(a) $\Lev(\Nhost)$},title style={font=\footnotesize}]
|
| 1245 |
+
\addplot[densely dashed,thick,black!55] coordinates {(0.06,3.30e-12) (0.08,1.72e-5) (0.09,1.16e-3) (0.10,2.41e-2) (0.11,2.30e-1) (0.12,1.30) (0.15,3.60e1)};
|
| 1246 |
+
\addlegendentry{$Mp$}
|
| 1247 |
+
\addplot[thick,black] coordinates {(0.06,1.21e-12) (0.08,6.34e-6) (0.09,4.27e-4) (0.10,8.85e-3) (0.11,8.42e-2) (0.12,4.73e-1) (0.15,1.30e1)};
|
| 1248 |
+
\addlegendentry{profile bound}
|
| 1249 |
+
\addplot[only marks,mark=*,mark size=1.6pt] coordinates {(0.08,6.94e-6) (0.09,4.07e-4) (0.10,8.71e-3) (0.11,7.70e-2) (0.12,3.59e-1) (0.15,1.00)};
|
| 1250 |
+
\addlegendentry{measured}
|
| 1251 |
+
\end{semilogyaxis}
|
| 1252 |
+
\begin{semilogyaxis}[at={(a.east)},anchor=west,xshift=1.0cm,width=7.4cm,height=5.8cm,font=\footnotesize,
|
| 1253 |
+
xlabel={noise deviation $s$},
|
| 1254 |
+
xmin=0.19,xmax=0.37,ymin=1e-13,ymax=1e2,
|
| 1255 |
+
xtick={0.20,0.25,0.30,0.35},
|
| 1256 |
+
xticklabel style={/pgf/number format/fixed,/pgf/number format/fixed zerofill,/pgf/number format/precision=2},
|
| 1257 |
+
ytick={1e-12,1e-9,1e-6,1e-3,1},
|
| 1258 |
+
legend style={font=\scriptsize,at={(0.97,0.03)},anchor=south east,draw=none,fill=white,fill opacity=0.8,text opacity=1},
|
| 1259 |
+
legend cell align=left,title={(b) $N_3$, read by majority},title style={font=\footnotesize}]
|
| 1260 |
+
\addplot[densely dashed,thick,black!55] coordinates {(0.20,8.03e-9) (0.22,1.16e-6) (0.25,2.48e-4) (0.27,3.48e-3) (0.30,7.22e-2) (0.33,6.90e-1) (0.36,3.89)};
|
| 1261 |
+
\addlegendentry{first order}
|
| 1262 |
+
\addplot[thick,black] coordinates {(0.20,3.59e-13) (0.22,1.82e-10) (0.25,1.58e-7) (0.27,4.57e-6) (0.30,2.26e-4) (0.33,4.34e-3) (0.36,4.30e-2)};
|
| 1263 |
+
\addlegendentry{restoration bound}
|
| 1264 |
+
\addplot[only marks,mark=*,mark size=1.6pt] coordinates {(0.27,4.04e-6) (0.30,2.13e-4) (0.33,3.66e-3) (0.36,2.93e-2)};
|
| 1265 |
+
\addlegendentry{measured}
|
| 1266 |
+
\addplot[only marks,mark=o,mark size=1.8pt] coordinates {(0.24,9.79e-7) (0.27,8.47e-5) (0.30,2.46e-3) (0.33,2.58e-2)};
|
| 1267 |
+
\addlegendentry{a copy deviates}
|
| 1268 |
+
\end{semilogyaxis}
|
| 1269 |
+
\end{tikzpicture}
|
| 1270 |
+
\caption{The per-step probability of leaving the orbit under Gaussian read noise
|
| 1271 |
+
of deviation $s$, against the bounds of Section~\ref{sec:robust}; the lines join
|
| 1272 |
+
the values computed at the deviations of Tables~\ref{tab:curve}
|
| 1273 |
+
and~\ref{tab:bound3}. (a)~$\Lev(\Nhost)$: the rate at which noisy copies first
|
| 1274 |
+
leave the exact orbit, the profile bound of Proposition~\ref{prop:profile} and
|
| 1275 |
+
the bound $Mp$ of Proposition~\ref{prop:random}. (b)~$N_3$: the rate at which the
|
| 1276 |
+
state read by majority first leaves the orbit, the restoration bound of
|
| 1277 |
+
Proposition~\ref{prop:restore} and the first-order bound of
|
| 1278 |
+
Theorem~\ref{thm:amplify}(ii), with the rate at which some copy of some state bit
|
| 1279 |
+
first deviates.}
|
| 1280 |
+
\label{fig:noise}
|
| 1281 |
+
\end{figure}
|
| 1282 |
+
|
| 1283 |
\subsection{Fault tolerance by amplification}\label{sec:amplify}
|
| 1284 |
|
| 1285 |
Theorem~\ref{thm:margin} tolerates perturbations below $\tfrac12$ because every
|
|
|
|
| 1599 |
one, and it exceeds one from $s=0.27$. Along the first $20{,}000$ steps of the
|
| 1600 |
self-describing instance, weighted by the steps each of the $64$ noisy copies
|
| 1601 |
ran, $b(t)$ lies $1.06$ to $1.47$ times above the measured failure rates
|
| 1602 |
+
(Table~\ref{tab:bound3}, Figure~\ref{fig:noise}(b)), which are $21$ and $12$ times
|
| 1603 |
+
below the rates at which
|
| 1604 |
the replicated state left its orbit at $s=0.27$ and $0.30$.
|
| 1605 |
|
| 1606 |
|
|
|
|
| 1611 |
This section gives a fixed network whose state holds a threshold network as
|
| 1612 |
data: a program bank lists the units of the stored network as records, the step
|
| 1613 |
evaluates the record in front of the bank and turns the bank by one record, and
|
| 1614 |
+
three heads read and write a second bank and two tapes
|
| 1615 |
+
(Figure~\ref{fig:machine}).
|
| 1616 |
|
| 1617 |
\begin{definition}[The two-head machine]\label{def:twohead}
|
| 1618 |
+
Let $\alpha\ge3$ and $G,L\ge1$, and put $b=8+3\alpha$ and $N=bG$. A state of the
|
| 1619 |
+
machine $T^\alpha_{G,L}$ consists of a window $w\in\B^{2^\alpha}$, two banks
|
| 1620 |
+
$Q_0,Q_1\in\B^N$ and two tapes $D_0,D_1\in\B^L$, each bank and tape circular and
|
| 1621 |
+
listed from its head. Window cell $0$ is the bank bit $\kappa$; $Q_\kappa$ is the
|
| 1622 |
+
active bank and $Q_{1-\kappa}$ the idle one, $D_\kappa$ the read tape and
|
| 1623 |
+
$D_{1-\kappa}$ the copy tape. Window cells $1$, $2$ and $3$ are not stored: they
|
| 1624 |
+
name the cell under the read head $D_\kappa[0]$, under the arm $Q_{1-\kappa}[0]$
|
| 1625 |
+
and under the copy head $D_{1-\kappa}[0]$, and cells $4$, $5$ and $6$ are the
|
| 1626 |
+
requests that move these three heads. A \emph{record} is a word
|
| 1627 |
+
$(c_0,c_1,\beta,a_0,a_1,a_o)\in\B^{b}$: two weight codes of two bits, read as
|
| 1628 |
$w=1$ for $01$, $w=-1$ for $10$ and $w=0$ otherwise, a bias $\beta\in[-8,7]$ in
|
| 1629 |
+
two's complement on four bits, and three window addresses of $\alpha$ bits, most
|
| 1630 |
+
significant first. One step reads the record $Q_\kappa[0..b)$ and the values
|
| 1631 |
$x_a$ of the cells it names, and
|
| 1632 |
\begin{enumerate}[label=(\roman*)]
|
| 1633 |
\item computes $v=\Hv(w_0x_{a_0}+w_1x_{a_1}+\beta)$;
|
| 1634 |
\item writes $v$ into window cell $a_o$ if $a_o=0$ or $a_o\ge4$, under the arm if
|
| 1635 |
$a_o=2$, under the copy head if $a_o=3$, and nowhere if $a_o=1$;
|
| 1636 |
+
\item turns $Q_\kappa$ by $b$ cells, and the read tape, the idle bank and the copy
|
| 1637 |
tape by one cell each when cell $4$, $5$ or $6$ holds $1$ after the write;
|
| 1638 |
\item clears cells $4$, $5$ and $6$.
|
| 1639 |
\end{enumerate}
|
| 1640 |
+
We write $T_{G,L}$ for $T^6_{G,L}$, whose window has $64$ cells and whose records
|
| 1641 |
+
have $26$ bits.
|
| 1642 |
\end{definition}
|
| 1643 |
|
| 1644 |
+
\begin{figure}[t]
|
| 1645 |
+
\centering
|
| 1646 |
+
\begin{tikzpicture}[font=\footnotesize,>=Stealth,
|
| 1647 |
+
c/.style={draw,minimum height=5.5mm,minimum width=9mm,inner sep=0pt,anchor=west,text height=1.5ex,text depth=0.3ex},
|
| 1648 |
+
s/.style={draw,minimum height=5.5mm,inner sep=0pt,anchor=west,text height=1.5ex,text depth=0.3ex},
|
| 1649 |
+
lab/.style={anchor=east},
|
| 1650 |
+
note/.style={font=\scriptsize,text=black!70}]
|
| 1651 |
+
\node[lab] at (0,0) {window $w$};
|
| 1652 |
+
\foreach \i/\t in {0/{$\kappa$},1/{rd},2/{arm},3/{cpy},4/{AR},5/{AA},6/{AC},7/{sink}} {
|
| 1653 |
+
\node[c] (w\i) at (0.15+0.9*\i,0) {\t};
|
| 1654 |
+
\node[font=\tiny,text=black!60] at ($(w\i.north)+(0,0.13)$) {\i};
|
| 1655 |
+
}
|
| 1656 |
+
\node[c,minimum width=40mm] (wr) at (0.15+0.9*8,0) {cells $8,\dots,2^\alpha-1$};
|
| 1657 |
+
\node[lab] at (0,-1.45) {active bank $Q_\kappa$};
|
| 1658 |
+
\node[s,fill=black!10,minimum width=40mm] (r0) at (0.15,-1.45) {record $(c_0,c_1,\beta,a_0,a_1,a_o)$};
|
| 1659 |
+
\node[s,minimum width=24mm] (r1) at (r0.east) {next record};
|
| 1660 |
+
\node[s,minimum width=48mm] (r2) at (r1.east) {};
|
| 1661 |
+
\node[note,anchor=east] at ($(r2.east)+(-0.1,0)$) {turns one record per step};
|
| 1662 |
+
\draw[->,rounded corners=3pt] (r0.north) -- ++(0,0.42) -| node[pos=0.25,fill=white,inner sep=2pt]
|
| 1663 |
+
{$v=\Hv(w_0x_{a_0}+w_1x_{a_1}+\beta)$ into cell $a_o$} (wr.south);
|
| 1664 |
+
\foreach \y/\n/\l/\k/\q in {-2.35/rt/{read tape $D_\kappa$}/rd/AR, -3.05/ib/{idle bank $Q_{1-\kappa}$}/arm/AA, -3.75/ct/{copy tape $D_{1-\kappa}$}/cpy/AC} {
|
| 1665 |
+
\node[lab] at (0,\y) {\l};
|
| 1666 |
+
\node[s,fill=black!10,minimum width=9mm] (\n0) at (0.15,\y) {\k};
|
| 1667 |
+
\node[s,minimum width=103mm] (\n1) at (\n0.east) {};
|
| 1668 |
+
\node[note,anchor=east] at ($(\n1.east)+(-0.1,0)$) {turns one cell when \q\ holds $1$};
|
| 1669 |
+
}
|
| 1670 |
+
\end{tikzpicture}
|
| 1671 |
+
\caption{The two-head machine $T^\alpha_{G,L}$. A step evaluates the record in
|
| 1672 |
+
front of the active bank on the cells $a_0$ and $a_1$ and writes the result into
|
| 1673 |
+
cell $a_o$. Window cells $1$, $2$ and $3$ are the cells under the read head, the
|
| 1674 |
+
arm and the copy head, shaded, and cells $4$, $5$ and $6$ turn them. The banks
|
| 1675 |
+
and the tapes are circular.}
|
| 1676 |
+
\label{fig:machine}
|
| 1677 |
+
\end{figure}
|
| 1678 |
+
|
| 1679 |
A \emph{pass} is $G$ steps. The active bank comes back to the record it started
|
| 1680 |
with, so a pass evaluates the $G$ records of the bank once each, in order, each
|
| 1681 |
on the values the records before it left. The bank bit is read at the start of a
|
|
|
|
| 1683 |
the next step on.
|
| 1684 |
|
| 1685 |
\begin{theorem}[The machine as a ternary threshold network]\label{thm:physnet}
|
| 1686 |
+
For all $\alpha\ge3$ and $G,L\ge1$ there is a clocked ternary threshold netlist
|
| 1687 |
+
$N^\alpha_{G,L}$ on the $2^\alpha-3+2N+2L$ bits of the stored window cells
|
| 1688 |
+
$0,4,5,\dots,2^\alpha-1$ and of $Q_0$, $Q_1$, $D_0$ and $D_1$, in this order and
|
| 1689 |
+
each from its head, with $8\cdot2^\alpha+9\alpha+81+8N+6L$ units,
|
| 1690 |
+
$(3\alpha+12)2^\alpha+18\alpha+170+18N+12L$ edges, every weight $\pm1$ and depth
|
| 1691 |
+
$15$, such that for every state $x$ of $T^\alpha_{G,L}$ the next state
|
| 1692 |
+
$N^\alpha_{G,L}$ computes from the bits of $x$ is the encoding of the next state
|
| 1693 |
+
of $x$.
|
| 1694 |
\end{theorem}
|
| 1695 |
|
| 1696 |
\begin{proof}
|
| 1697 |
The netlist has twenty-eight blocks. A multiplexer on $\kappa$ selects each bit
|
| 1698 |
of the record in front of the active bank and the cell under each head. Three
|
| 1699 |
+
blocks of $2^\alpha$ units decode $a_0$, $a_1$ and $a_o$ (Lemma~\ref{lem:mem}),
|
| 1700 |
+
and a disjunction of the conjunctions of each decode line with the cell it names
|
| 1701 |
+
reads $x_{a_0}$ and $x_{a_1}$, cells $1$ to $3$ through the head multiplexers.
|
| 1702 |
+
From the weight codes, units for $[w_k=1]\wedge x_{a_k}$ and $[w_k=-1]\wedge
|
| 1703 |
+
x_{a_k}$ give $p=w_0x_{a_0}+w_1x_{a_1}\in[-2,2]$; five units test $p\ge c$ for
|
| 1704 |
+
$c=-2,\dots,2$ and five test $\beta\ge-c$ on the four bits of $\beta$, and $v$ is
|
| 1705 |
+
the disjunction of the five conjunctions, since $p+\beta\ge0$ exactly when some
|
| 1706 |
+
$c$, namely $c=p$, has $p\ge c$ and $\beta\ge-c$. A multiplexer on the decode line
|
| 1707 |
+
of each stored window cell writes $v$ into it, and the three request cells read a
|
| 1708 |
+
unit that never fires. Bit $i$ of a bank is the disjunction of three
|
| 1709 |
+
conjunctions: with the bank active, its bit $i+b\bmod N$; with it idle, bit
|
| 1710 |
+
$i+1\bmod N$ or bit $i$ of the bank after the arm's write, as cell $5$ after the
|
| 1711 |
+
write requests; the cell under the arm after the write is a multiplexer of $v$
|
| 1712 |
+
and the old cell on the decode line of $2$. The tapes are alike, with cells $4$
|
| 1713 |
+
and $6$ and the decode line of $3$. Counting the units and edges of the blocks
|
| 1714 |
+
gives the sizes. The depth of a unit depends only on its block: the record and
|
| 1715 |
+
the cells under the heads are selected at depth $2$, the decode lines lie at
|
| 1716 |
+
depth $3$, the operands at $5$, the products at $6$, the tests $p\ge c$ at $7$
|
| 1717 |
+
and $v$ at $9$, the written window cells, the requests among them, at $11$, the
|
| 1718 |
+
next bank bits at $14$, the signals that turn the tapes at $13$ and the next tape
|
| 1719 |
+
bits at $15$. That the next state is the encoding of the next state of $x$, for
|
| 1720 |
+
all $\alpha$, $G$, $L$ and $x$, is proved in Rocq, with the number of units and
|
| 1721 |
+
the weights: every unit is given a value in terms of $x$, every unit fires to its
|
| 1722 |
+
own value on the values of the units it reads, and induction over the units in
|
| 1723 |
+
their order shows that the netlist computes these values, among them the next
|
| 1724 |
+
state. A decode line is proved for every width through the binary value of an
|
| 1725 |
+
address of $\alpha$ bits.
|
| 1726 |
\end{proof}
|
| 1727 |
|
| 1728 |
\begin{remark}[Corroboration]\label{rem:physcheck}
|
| 1729 |
+
For $\alpha=6$, $G=133$ and $L=2930$, the member that Section~\ref{sec:organism}
|
| 1730 |
+
uses, $N^6_{G,L}$ has $45{,}891$ units, $99{,}602$ edges and $12{,}837$ state bits;
|
| 1731 |
+
for $\alpha=12$, $G=36{,}074$ and $L=1{,}599{,}768$, the member that
|
| 1732 |
+
Section~\ref{sec:storedhost} uses, it has $22{,}329{,}613$ units,
|
| 1733 |
+
$47{,}964{,}818$ edges and $6{,}378{,}141$ state bits. The generator writes the
|
| 1734 |
+
netlist unit by unit in the order of the Rocq definition, and for $N^6_{133,2930}$
|
| 1735 |
+
and $N^{12}_{5,40}$ its file is byte for byte the netlist extracted from that
|
| 1736 |
+
definition. One step of the netlist agreed with a transcription of
|
| 1737 |
+
Definition~\ref{def:twohead} on $300$ random full states for $N^6_{5,40}$, $20$ for
|
| 1738 |
+
$N^6_{133,2930}$ and $40$ for $N^{12}_{5,40}$, and three generations of the organism
|
| 1739 |
+
of Section~\ref{sec:organism}, $2{,}762{,}676$ steps, were run on $N^6_{133,2930}$ in
|
| 1740 |
C beside the transcription, the full state compared after every step.
|
| 1741 |
\end{remark}
|
| 1742 |
|
| 1743 |
% =============================================================================
|
| 1744 |
+
\section{The host reproduces itself by the dynamics}\label{sec:storedhost}
|
| 1745 |
% =============================================================================
|
| 1746 |
|
| 1747 |
+
Inside the two-head machine the instantiation step of Section~\ref{sec:selfrep}
|
| 1748 |
+
is a write into the idle bank followed by a change of $\kappa$. This section
|
| 1749 |
+
stores the host as a network of two-input records in a bank of $T^{12}_{G,L}$,
|
| 1750 |
+
whose window of $4096$ cells holds the host's $2057$ state bits, with a device
|
| 1751 |
+
that writes the bytes the host emits under the arm until the tape is rewound and
|
| 1752 |
+
under the copy head after it. Run on a recipe for its own records, $P^\ast$ then
|
| 1753 |
+
writes the host into the idle bank, copies the recipe and hands control to the
|
| 1754 |
+
copy (Figure~\ref{fig:generation}).
|
| 1755 |
+
|
| 1756 |
+
\begin{lemma}[Stored netlists]\label{lem:feedback}
|
| 1757 |
+
If no record but the last of the active bank writes $\kappa$, a pass evaluates the
|
| 1758 |
+
records in order, each on the window and the cells under the heads as the records
|
| 1759 |
+
before it left them. A clocked netlist whose units have at most two predecessors
|
| 1760 |
+
and whose state bits are window cells is therefore evaluated by one pass of
|
| 1761 |
+
records that list its units in an order in which every unit follows its
|
| 1762 |
+
predecessors, each record writing a cell that holds the unit's value until the
|
| 1763 |
+
last record that reads it, and the record of the next value of each state bit
|
| 1764 |
+
writing that bit after every record that reads it.
|
| 1765 |
+
\end{lemma}
|
| 1766 |
+
|
| 1767 |
+
\begin{proof}
|
| 1768 |
+
The active bank turns by one record per step, and $\kappa$, read at the start of a
|
| 1769 |
+
step, selects it. Induction over the records shows that each reads the values of
|
| 1770 |
+
its predecessors on the current state, a state bit being unchanged until the
|
| 1771 |
+
record of its next value, which follows its last reader.
|
| 1772 |
+
\end{proof}
|
| 1773 |
+
|
| 1774 |
+
Gate-level logic simulation engines evaluate one stored gate per step from
|
| 1775 |
+
operand memory and rank-order the gates so that one pass
|
| 1776 |
+
suffices~\cite{Denneau1982}, and Lemma~\ref{lem:feedback} is the fixed-order
|
| 1777 |
+
sequential schedule of automata networks~\cite{RiosWilsonTheyssier2024c}.
|
| 1778 |
+
|
| 1779 |
+
\begin{lemma}[Compilation]\label{cor:compile}
|
| 1780 |
+
A ternary threshold unit $\Hv(\sum_{i\in P}x_i-\sum_{i\in N}x_i+b)$ is $1$
|
| 1781 |
+
exactly when at least $t=|N|-b$ of its $k$ literals $x_i$ ($i\in P$) and $\neg x_i$
|
| 1782 |
+
($i\in N$) are true. It is a constant for $t\le0$ and for $t>k$, a disjunction
|
| 1783 |
+
for $t=1$ and a conjunction for $t=k$, each a copy of the literal when $k=1$ and a
|
| 1784 |
+
chain of $k-1$ two-input units otherwise, and for $1<t<k$ it satisfies
|
| 1785 |
+
$T_t(x_1,\dots,x_k)=T_t(x_2,\dots,x_k)\vee(x_1\wedge T_{t-1}(x_2,\dots,x_k))$.
|
| 1786 |
+
Every unit so obtained is a record.
|
| 1787 |
+
\end{lemma}
|
| 1788 |
+
|
| 1789 |
+
\begin{proof}
|
| 1790 |
+
The pre-activation is the number of true literals minus $t$. The unit
|
| 1791 |
+
$\Hv(\pm x\pm y+c)$ with $c\in\{0,-1,-2\}$ is the conjunction of any two literals
|
| 1792 |
+
and with $c\in\{-1,0,1\}$ their disjunction, a copy is $\Hv(x-1)$ or $\Hv(-x)$, and
|
| 1793 |
+
the constants are the disjunction and the conjunction of a literal and its
|
| 1794 |
+
negation; a chain conjoins or disjoins each further literal with the result so
|
| 1795 |
+
far. The recursion holds because at least $t$ of $x_1,\dots,x_k$ are true exactly
|
| 1796 |
+
when at least $t$ of $x_2,\dots,x_k$ are, or $x_1$ is and at least $t-1$ of the
|
| 1797 |
+
others are, and its base cases are the chains and the constants.
|
| 1798 |
+
\end{proof}
|
| 1799 |
+
|
| 1800 |
+
\begin{construction}[The stored host]\label{con:stored}
|
| 1801 |
+
Let $\alpha=12$. The window holds, after the eight cells of
|
| 1802 |
+
Definition~\ref{def:twohead}, a cell $\mathrm{booted}$ at $8$, a counter
|
| 1803 |
+
$\mathrm{cnt}$ of $20$ bits at $9$ to $28$, least significant first, a cell
|
| 1804 |
+
$\mathrm{dest}$ at $29$, a limit $\mathrm{lim}$ of $20$ bits at $30$ to $49$, the
|
| 1805 |
+
$2057$ state bits of $\Nhost$ at $50$ to $2106$ in the order of
|
| 1806 |
+
Construction~\ref{con:host}, and temporaries from $2107$ on. The stored host $S$
|
| 1807 |
+
lists the following $36{,}074$ records.
|
| 1808 |
+
\begin{enumerate}[label=(\alph*),leftmargin=2em]
|
| 1809 |
+
\item \emph{Startup}, $2099$ records: for each memory bit $c$,
|
| 1810 |
+
$c\leftarrow c\vee\neg\mathrm{booted}$ if its value in $m^\ast$ is $1$ and
|
| 1811 |
+
$c\leftarrow c\wedge\mathrm{booted}$ if it is $0$; then
|
| 1812 |
+
$c\leftarrow c\wedge\mathrm{booted}$ for the bits of the counter, the halt bit and
|
| 1813 |
+
the bits of $\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$; then
|
| 1814 |
+
$\mathrm{booted}\leftarrow1$.
|
| 1815 |
+
\item \emph{Step}, $33{,}568$ records: the units of $\Nhost$ compiled by
|
| 1816 |
+
Lemma~\ref{cor:compile}, in two stages. The first evaluates every unit that a
|
| 1817 |
+
next value depends on, other than the units of the next values and the units read
|
| 1818 |
+
by a single unit, each after its predecessors. The second takes the counter bits,
|
| 1819 |
+
the halt bit and the memory bits in this order, and evaluates for each the unit of
|
| 1820 |
+
its next value, with the units read by it alone just before it, its last record
|
| 1821 |
+
writing the bit.
|
| 1822 |
+
\item \emph{Device}, $402$ records: the device of Definition~\ref{def:ring} on the
|
| 1823 |
+
state that~(b) leaves.
|
| 1824 |
+
\item \emph{Hand-over}, five records: $\mathrm{booted}\leftarrow
|
| 1825 |
+
\mathrm{booted}\wedge\neg h$, where $h$ is the halt bit; a record with both
|
| 1826 |
+
weights $0$ that writes $0$ into the sink, which makes $S$ a whole number of bytes;
|
| 1827 |
+
and $\kappa\leftarrow\kappa\oplus h$ in three records.
|
| 1828 |
+
\end{enumerate}
|
| 1829 |
+
Temporaries whose live intervals, from the first write to the last read, are
|
| 1830 |
+
disjoint share a cell, $789$ cells in all, so $S$ uses the window cells $0$ to
|
| 1831 |
+
$2895$. The image of $S$, its records in order, has $1{,}587{,}256$ bits, read as
|
| 1832 |
+
$198{,}407$ bytes most significant bit first, and $\tau_S=\describe(S)$ has
|
| 1833 |
+
$199{,}971$ bytes.
|
| 1834 |
+
\end{construction}
|
| 1835 |
+
|
| 1836 |
+
\begin{definition}[The device of the stored host]\label{def:ring}
|
| 1837 |
+
The device acts on the state $y$ of the host after a step, the registers
|
| 1838 |
+
$\mathrm{cnt}$, $\mathrm{lim}$ and $\mathrm{dest}$, the read tape, the idle bank
|
| 1839 |
+
and the copy tape, each request firing on the value $1$:
|
| 1840 |
+
\begin{enumerate}[label=(\roman*)]
|
| 1841 |
+
\item if $y_{c_{\mathrm{wr}}}=1$, the eight bits of $y_{R_{\mathrm{out}}}$, most
|
| 1842 |
+
significant first, are written under the arm if $\mathrm{dest}=0$ and under the
|
| 1843 |
+
copy head if $\mathrm{dest}=1$, that head turning after each, and
|
| 1844 |
+
$R_{\mathrm{out}}$ is cleared;
|
| 1845 |
+
\item if $y_{c_{\mathrm{rd}}}=1$, then $c_{\mathrm{eot}}$ is set if
|
| 1846 |
+
$\mathrm{dest}=1$ and $\mathrm{cnt}=\mathrm{lim}$, and otherwise the eight bits
|
| 1847 |
+
under the read head, the head turning after each, are loaded into
|
| 1848 |
+
$R_{\mathrm{in}}$ most significant first, $c_{\mathrm{eot}}$ is cleared and
|
| 1849 |
+
$\mathrm{cnt}$ is incremented;
|
| 1850 |
+
\item if $y_{c_{\mathrm{rw}}}=1$, then $\mathrm{lim}\leftarrow\mathrm{cnt}$,
|
| 1851 |
+
$\mathrm{cnt}\leftarrow0$ and $\mathrm{dest}\leftarrow1$;
|
| 1852 |
+
\item the request cells are cleared.
|
| 1853 |
+
\end{enumerate}
|
| 1854 |
+
\end{definition}
|
| 1855 |
+
|
| 1856 |
+
\begin{figure}[t]
|
| 1857 |
+
\centering
|
| 1858 |
+
\begin{tikzpicture}[font=\footnotesize,>=Stealth,
|
| 1859 |
+
s/.style={draw,minimum height=6mm,inner sep=1pt,anchor=west,text height=1.5ex,text depth=0.3ex},
|
| 1860 |
+
lab/.style={anchor=east},
|
| 1861 |
+
note/.style={font=\scriptsize,text=black!70}]
|
| 1862 |
+
\node[lab] at (0,0) {active bank $Q_\kappa$};
|
| 1863 |
+
\node[s,fill=black!10,minimum width=13mm] (a1) at (0.15,0) {startup};
|
| 1864 |
+
\node[s,fill=black!10,minimum width=35mm] (a2) at (a1.east) {step of $\Nhost$};
|
| 1865 |
+
\node[s,fill=black!10,minimum width=13mm] (a3) at (a2.east) {device};
|
| 1866 |
+
\node[s,fill=black!10,minimum width=15mm] (a4) at (a3.east) {hand-over};
|
| 1867 |
+
\node[note,anchor=south] at (a1.north) {$2099$};
|
| 1868 |
+
\node[note,anchor=south] at (a2.north) {$33{,}568$ records};
|
| 1869 |
+
\node[note,anchor=south] at (a3.north) {$402$};
|
| 1870 |
+
\node[note,anchor=south] at (a4.north) {$5$};
|
| 1871 |
+
\node[lab] at (0,-1.1) {read tape $D_\kappa$};
|
| 1872 |
+
\node[s,minimum width=76mm] (d0) at (0.15,-1.1) {$\tau_S=\describe(S)$, $199{,}971$ bytes};
|
| 1873 |
+
\node[lab] at (0,-2.2) {idle bank $Q_{1-\kappa}$};
|
| 1874 |
+
\node[s,densely dashed,minimum width=76mm] (q1) at (0.15,-2.2) {$S$, written under the arm in phase~(A)};
|
| 1875 |
+
\node[lab] at (0,-3.3) {copy tape $D_{1-\kappa}$};
|
| 1876 |
+
\node[s,densely dashed,minimum width=76mm] (d1) at (0.15,-3.3) {$\tau_S$, written under the copy head in phase~(B)};
|
| 1877 |
+
\node[draw,rounded corners,align=left,anchor=north west,text width=31mm,minimum height=39mm,inner sep=4pt]
|
| 1878 |
+
(win) at (9.75,0.3)
|
| 1879 |
+
{\textbf{window}\\[2pt] the host's state, with\\ $P^\ast$ and $m^\ast$ in its\\ memory; the device's\\ $\mathrm{cnt}$, $\mathrm{lim}$, $\mathrm{dest}$;\\ $\mathrm{booted}$; $\kappa$, flipped\\ by the hand-over\\ at the halt};
|
| 1880 |
+
\draw[->] (a4.east) -- node[note,above] {runs} (win.west|-a4.east);
|
| 1881 |
+
\draw[->] (d0.east) -- node[note,above] {(A), (B)} (win.west|-d0.east);
|
| 1882 |
+
\draw[<-] (q1.east) -- node[note,above] {(A)} (win.west|-q1.east);
|
| 1883 |
+
\draw[<-] (d1.east) -- node[note,above] {(B)} (win.west|-d1.east);
|
| 1884 |
+
\end{tikzpicture}
|
| 1885 |
+
\caption{A generation of the stored host. Each pass evaluates the records of $S$
|
| 1886 |
+
and carries out one step of the host on the window. $P^\ast$ reads $\tau_S$
|
| 1887 |
+
twice: in phase~(A) it decodes it, and the device writes the decoded bytes, the
|
| 1888 |
+
image of $S$, under the arm; in phase~(B) it copies $\tau_S$ under the copy head.
|
| 1889 |
+
At the halt the hand-over flips $\kappa$, and the next pass, in the other bank,
|
| 1890 |
+
loads $m^\ast$ and runs the copy.}
|
| 1891 |
+
\label{fig:generation}
|
| 1892 |
+
\end{figure}
|
| 1893 |
+
|
| 1894 |
+
\begin{proposition}[One pass]\label{prop:storedpass}
|
| 1895 |
+
Let a state of $T^{12}_{G,L}$ with $G=36{,}074$ hold $S$ in the active bank from
|
| 1896 |
+
its first record, and in the window clear requests and a host state $x$. One pass
|
| 1897 |
+
replaces $x$ by $x_0(m^\ast)$ and clears $\mathrm{cnt}$, $\mathrm{lim}$ and
|
| 1898 |
+
$\mathrm{dest}$ if $\mathrm{booted}=0$; then carries out one step of $\Nhost$
|
| 1899 |
+
followed by the device of Definition~\ref{def:ring}; then sets $\mathrm{booted}$
|
| 1900 |
+
to the negation of the halt bit and, if the halt bit is $1$, changes $\kappa$ at
|
| 1901 |
+
its last step. It leaves $S$ in the active bank from its first record and the
|
| 1902 |
+
requests clear, whatever the temporaries held.
|
| 1903 |
+
\end{proposition}
|
| 1904 |
+
|
| 1905 |
+
\begin{proof}
|
| 1906 |
+
By Lemma~\ref{lem:feedback} the pass evaluates the blocks of
|
| 1907 |
+
Construction~\ref{con:stored} in order. The startup records leave every cell
|
| 1908 |
+
unchanged when $\mathrm{booted}=1$; otherwise they set each memory bit to its value
|
| 1909 |
+
in $m^\ast$ and clear the other cells they name. The step block is $\Nhost$
|
| 1910 |
+
compiled by Lemma~\ref{cor:compile}, in an order that Lemma~\ref{lem:feedback}
|
| 1911 |
+
admits: the first stage writes temporaries only, and no record reads a state bit
|
| 1912 |
+
after the record that writes its next value, a condition checked over the records.
|
| 1913 |
+
So after the block the state bits hold the next state of $\Nhost$. The device
|
| 1914 |
+
records form the requests $[y_c=1]$ as conjunctions of eight literals, the bit
|
| 1915 |
+
$[\mathrm{cnt}=\mathrm{lim}]$ as a conjunction of twenty equivalences, and its
|
| 1916 |
+
conjunction with $\mathrm{dest}$. They then write each bit of $R_{\mathrm{out}}$
|
| 1917 |
+
under the arm or the copy head by a multiplexer, followed by the request that turns
|
| 1918 |
+
that head, and clear $R_{\mathrm{out}}$ on a write; load each bit under the read
|
| 1919 |
+
head into $R_{\mathrm{in}}$ by a multiplexer on the condition of a read, followed
|
| 1920 |
+
by the request that turns the read tape; set $c_{\mathrm{eot}}$; increment
|
| 1921 |
+
$\mathrm{cnt}$ by carries formed before any of its bits changes; carry out the
|
| 1922 |
+
rewind; and clear the requests: these are clauses (i) to (iv) of
|
| 1923 |
+
Definition~\ref{def:ring}. The hand-over records set $\mathrm{booted}$ and,
|
| 1924 |
+
last, $\kappa$. Every temporary is written in the pass before it is read and is not
|
| 1925 |
+
written after its last read, so a cell shared by temporaries holds, at each read,
|
| 1926 |
+
the value of the temporary read. No record writes the active bank, which turns by
|
| 1927 |
+
$G$ records.
|
| 1928 |
+
\end{proof}
|
| 1929 |
+
|
| 1930 |
+
\begin{theorem}[Universal construction by the dynamics]\label{thm:storedconstruct}
|
| 1931 |
+
Let $X$ be an image of $G=36{,}074$ records, read as $198{,}407$ bytes, let $r$ be
|
| 1932 |
+
a recipe with $\delta(r)=X$, and let $L=8|r|$. Let $x$ be a state of
|
| 1933 |
+
$T^{12}_{G,L}$ with $S$ in the active bank from its first record, $r$ on the read
|
| 1934 |
+
tape from its head, and in the window $\mathrm{booted}=0$ and clear requests,
|
| 1935 |
+
whatever the idle bank, the copy tape and the other cells hold. After as many
|
| 1936 |
+
passes as Proposition~\ref{prop:steps} gives steps for $r$, the idle bank holds
|
| 1937 |
+
$X$ and the copy tape $r$, the active bank holds $S$ and the read tape $r$, each
|
| 1938 |
+
from its head, the window holds $\mathrm{booted}=0$ and clear requests, and
|
| 1939 |
+
$\kappa$ has changed, at the last step of the last pass; from then on
|
| 1940 |
+
$T^{12}_{G,L}$ evaluates the records of $X$.
|
| 1941 |
+
\end{theorem}
|
| 1942 |
+
|
| 1943 |
+
\begin{proof}
|
| 1944 |
+
By Proposition~\ref{prop:storedpass} the first pass loads $x_0(m^\ast)$ and
|
| 1945 |
+
carries out the first step of the host, and each later pass one more step, with
|
| 1946 |
+
the device of Definition~\ref{def:ring}, up to the pass in which the halt bit is
|
| 1947 |
+
set, which clears $\mathrm{booted}$ and changes $\kappa$ at its last step. By
|
| 1948 |
+
Theorem~\ref{thm:selfrep}, $P^\ast$ on $r$ with the device of
|
| 1949 |
+
Definition~\ref{def:transducer} halts after the steps of
|
| 1950 |
+
Proposition~\ref{prop:steps} with output $\delta(r)\cat r$, reads no byte at
|
| 1951 |
+
$h=|r|$ before it requests the rewind, and requests it at $h=|r|$. On this run the
|
| 1952 |
+
two devices agree. A token covers at least one byte in at most two, so
|
| 1953 |
+
$|r|\le2|X|+1<2^{20}$ and $\mathrm{cnt}$ does not wrap. Before the rewind
|
| 1954 |
+
$\mathrm{dest}=0$ and each read loads the next
|
| 1955 |
+
byte of $r$ and increments $\mathrm{cnt}$, so $\mathrm{cnt}=h$; at the rewind the
|
| 1956 |
+
read head has turned $8|r|=L$ cells and is back at its start, and $\mathrm{lim}$
|
| 1957 |
+
becomes $|r|$. After it each read loads the next byte while
|
| 1958 |
+
$\mathrm{cnt}<\mathrm{lim}$ and sets $c_{\mathrm{eot}}$ at $\mathrm{cnt}=|r|$, as
|
| 1959 |
+
Definition~\ref{def:transducer} does at $h=|r|$. The bytes emitted before the
|
| 1960 |
+
rewind, $\delta(r)=X$, are written under the arm, which turns
|
| 1961 |
+
$8\cdot198{,}407=N$ cells and comes back to its start, and those emitted after it,
|
| 1962 |
+
$r$, under the copy head, which turns $L$ cells. The active bank and the read tape
|
| 1963 |
+
are not written, and the read tape has turned $2L$ cells. From the next step on
|
| 1964 |
+
the bank holding $X$ is active, from its first record.
|
| 1965 |
+
\end{proof}
|
| 1966 |
+
|
| 1967 |
+
By Lemma~\ref{lem:complete} every image of $G$ records has a recipe, so the stored
|
| 1968 |
+
host builds every image of its own size, itself among them.
|
| 1969 |
+
|
| 1970 |
+
\begin{theorem}[Self-reproduction of the host by the dynamics]\label{thm:storedrep}
|
| 1971 |
+
Let $L=8|\tau_S|=1{,}599{,}768$ and let $x_0$ be the state of $T^{12}_{G,L}$ with
|
| 1972 |
+
$S$ in $Q_0$, $\tau_S$ on $D_0$, and $Q_1$, $D_1$ and the window clear. For every
|
| 1973 |
+
$g\ge1$, the state after $g$ generations of $2{,}202{,}812$ passes,
|
| 1974 |
+
$79{,}464{,}240{,}088$ applications of $T^{12}_{G,L}$ each, holds $S$ in both banks
|
| 1975 |
+
and $\tau_S$ on both tapes, each from its head, with $\kappa=g\bmod2$, and equals
|
| 1976 |
+
the state after $g+2$ generations. The network $N^{12}_{G,L}$ started from the bits
|
| 1977 |
+
of $x_0$ holds their bits at the same steps, and its orbit is periodic from the
|
| 1978 |
+
first generation on, with a period of two generations.
|
| 1979 |
+
\end{theorem}
|
| 1980 |
+
|
| 1981 |
+
\begin{proof}
|
| 1982 |
+
The first generation is Theorem~\ref{thm:storedconstruct} with $X=S$ and
|
| 1983 |
+
$r=\tau_S$, a recipe for $S$ by Lemma~\ref{lem:describe}. The recipe $\tau_S$ has
|
| 1984 |
+
$1563$ literal tokens and no repeat token, with $f_{\mathrm{lit}}=198{,}407$, so
|
| 1985 |
+
Proposition~\ref{prop:steps} gives $1{,}002{,}983+1+1{,}199{,}828$ passes. After
|
| 1986 |
+
it the idle bank and the copy tape hold $S$ and $\tau_S$, the active bank and the
|
| 1987 |
+
read tape still hold them, and the window holds $\mathrm{booted}=0$ and clear
|
| 1988 |
+
requests, so with the roles of the two banks and the two tapes exchanged the state
|
| 1989 |
+
satisfies the hypothesis of Theorem~\ref{thm:storedconstruct} again; induction over
|
| 1990 |
+
the generations gives the first statement. Generations $g$ and $g+2$ start from
|
| 1991 |
+
states that agree in the banks, the tapes, $\kappa$ and $\mathrm{booted}=0$. In the
|
| 1992 |
+
first pass of a generation the startup records write values that do not depend on
|
| 1993 |
+
the cells they read, and every other cell a record reads is written earlier in the
|
| 1994 |
+
pass, apart from $\kappa$, the cells under the heads and the sink, whose value
|
| 1995 |
+
changes no result; the cells from $2896$ on are never addressed. So the two
|
| 1996 |
+
generations perform the same steps and end in the same state.
|
| 1997 |
+
Theorem~\ref{thm:physnet} carries the statement to the network.
|
| 1998 |
+
\end{proof}
|
| 1999 |
+
|
| 2000 |
+
\begin{remark}[Corroboration]\label{rem:storedcheck}
|
| 2001 |
+
Three generations from $x_0$ were run on a transcription of
|
| 2002 |
+
Definition~\ref{def:twohead} in C, $79{,}464{,}240{,}088$ steps each: after each
|
| 2003 |
+
the new active bank held $S$ and the new read tape $\tau_S$, each from its head,
|
| 2004 |
+
the other bank and tape still held them, $\kappa$ alternated, and the full state
|
| 2005 |
+
after the third generation equalled the state after the first. A transcription in
|
| 2006 |
+
Python agreed with the C program on the full state after three passes and
|
| 2007 |
+
$12{,}345$ further steps. One pass was compared with the startup, one step of
|
| 2008 |
+
$\Nhost$ and the device of Definition~\ref{def:ring} from $300$ random states, a
|
| 2009 |
+
fifth of them not booted and a third with requests holding random bytes, with
|
| 2010 |
+
random tapes, idle bank, registers and temporaries, and agreed in every case; that no
|
| 2011 |
+
record of the step block reads a state bit after the record of its next value, and
|
| 2012 |
+
that no temporary is written after its last read, was checked over the records.
|
| 2013 |
+
\end{remark}
|
| 2014 |
+
|
| 2015 |
+
\begin{remark}\label{rem:storedvn}
|
| 2016 |
+
The network $N^{12}_{G,L}$ is the fixed physics; $S$ carries the constructor,
|
| 2017 |
+
phase~(A) of $P^\ast$, the copier, phase~(B), and the control, its startup and
|
| 2018 |
+
hand-over records; and $\tau_S$ is the description, used twice. The records of $S$ are the
|
| 2019 |
+
units of $\Nhost$, weights and biases, compiled into two-input units, together
|
| 2020 |
+
with its memory image in the startup records, so each generation rebuilds the
|
| 2021 |
+
stored network that computes, its weights included, by the dynamics of a fixed
|
| 2022 |
+
network and with no map outside it. The constructor is a universal computer and
|
| 2023 |
+
the description a recipe of Section~\ref{sec:univ}.
|
| 2024 |
+
\end{remark}
|
| 2025 |
+
|
| 2026 |
+
% =============================================================================
|
| 2027 |
+
\section{A constructor proved in Rocq}\label{sec:organism}
|
| 2028 |
+
% =============================================================================
|
| 2029 |
+
|
| 2030 |
+
Theorem~\ref{thm:storedrep} is proved on paper from Theorem~\ref{thm:physnet} and
|
| 2031 |
+
was run for three generations. This section gives a smaller stored network, the
|
| 2032 |
+
organism, that performs von Neumann's cycle in $T_{G,L}$, the machine of $64$
|
| 2033 |
+
cells, with a description code of its own; every step of its reproduction is
|
| 2034 |
+
proved in Rocq.
|
| 2035 |
|
| 2036 |
\begin{definition}[The description code]\label{def:code}
|
| 2037 |
A \emph{gate} is a record that computes the conjunction or the disjunction of
|
|
|
|
| 2053 |
\end{definition}
|
| 2054 |
|
| 2055 |
An image of $n$ records of which $e$ are not gates has a description of
|
| 2056 |
+
$22n+8e+4$ bits, and the gates include every unit that Lemma~\ref{cor:compile}
|
| 2057 |
+
produces.
|
| 2058 |
|
| 2059 |
\begin{lemma}[Completeness of the code]\label{lem:code}
|
| 2060 |
For every image $X$ of whole records, $\describe(X)$ is a description of $X$.
|
|
|
|
| 2070 |
\begin{construction}[The organism]\label{con:organism}
|
| 2071 |
The organism $\rho$ is the image of the $133$ records listed in
|
| 2072 |
Appendix~\ref{app:listings}, $3458$ bits. It uses $36$ window cells: the bank bit,
|
| 2073 |
+
the six head and request cells, the sink, thirteen cells $8$ to $20$ that hold the
|
| 2074 |
+
state of a decoder, and fifteen temporaries in cells $21$ to $35$, each written in
|
| 2075 |
+
a pass before it is read in that pass. The decoder's state is a mode $m$,
|
| 2076 |
+
construct ($m=0$) or copy, in cell $8$; a phase, codon C, gate bits G or address
|
| 2077 |
+
bits A, one cell each, $9$, $10$ and $11$; a codon register $c_3c_2c_1c_0$, $c_i$
|
| 2078 |
+
in cell $12+i$; and a counter $z=z_4\cdots z_0$, $z_i$ in cell $16+i$. One pass
|
| 2079 |
+
carries out one step of the decoder, with $r$ the bit under the read head:
|
| 2080 |
\begin{enumerate}[label=(\roman*),leftmargin=2em]
|
| 2081 |
\item in phase C, $r$ is consumed and shifted into the codon register, and in copy
|
| 2082 |
mode copied under the copy head; at $z=0$ the codon decides: at end the mode
|
|
|
|
| 2117 |
are checked in Rocq.
|
| 2118 |
\end{proof}
|
| 2119 |
|
| 2120 |
+
\begin{theorem}[Universal construction by the organism]\label{thm:construct}
|
| 2121 |
Let $X$ be an image of $133$ records and $d$ a description of $X$ of $L$ bits. Let
|
| 2122 |
$x$ be a state of $T_{133,L}$ with $\rho$ in the active bank $Q_\kappa$ from its
|
| 2123 |
first record, $d$ on the read tape from its head, and in the window clear
|
|
|
|
| 2148 |
bits, so in $T_{133,2930}$ the organism builds every image of $133$ gates, and in
|
| 2149 |
$T_{133,2930+8e}$ every image of $133$ records of which $e$ are not gates.
|
| 2150 |
|
| 2151 |
+
\begin{theorem}[Self-reproduction of the organism]\label{thm:organism}
|
| 2152 |
Let $x_0$ be the state of $T_{133,2930}$ with $\rho$ in $Q_0$, $\describe(\rho)$
|
| 2153 |
on $D_0$, $Q_1$ and $D_1$ clear, $\kappa=0$, and in the window clear requests and
|
| 2154 |
the decoder in phase C with $z=3$ in construct mode. For every $g\ge1$, the state
|
| 2155 |
after $g$ generations of $6924$ passes, $920{,}892$ applications of $T$ each,
|
| 2156 |
holds $\rho$ in both banks and $\describe(\rho)$ on both tapes, with
|
| 2157 |
+
$\kappa=g\bmod2$. The network $N^6_{133,2930}$ started from the bits of $x_0$ holds
|
| 2158 |
their bits at the same steps. Its orbit is periodic from the first generation
|
| 2159 |
on, with a period of two generations.
|
| 2160 |
\end{theorem}
|
|
|
|
| 2172 |
equal, so the orbit is periodic from the first generation on.
|
| 2173 |
\end{proof}
|
| 2174 |
|
| 2175 |
+
\begin{remark}\label{rem:organismcheck}
|
| 2176 |
+
The description of $\rho$ has $2930$ bits against $3458$ for the bank: a gate is
|
| 2177 |
+
named by four bits and its eight bits are written by the organism. Three
|
| 2178 |
+
generations from $x_0$ were also run on the transcription of
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2179 |
Definition~\ref{def:twohead}, each of $920{,}892$ steps, and on the netlist in C
|
| 2180 |
beside it (Remark~\ref{rem:physcheck}); after each both banks held $\rho$ and
|
| 2181 |
both tapes $\describe(\rho)$, and the full state after the third generation
|
| 2182 |
+
equalled the state after the first. The Rocq definition of the organism and its
|
| 2183 |
+
description equal those of the transcription, and so do the full states of $T$
|
| 2184 |
+
after $1000$ and $20{,}000$ steps.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2185 |
\end{remark}
|
| 2186 |
|
| 2187 |
% =============================================================================
|
|
|
|
| 2225 |
constructions use real-valued weights, and Loom includes a layer that restores
|
| 2226 |
persistent state to $\pm1$ after numerical drift. The two-head machine of
|
| 2227 |
Section~\ref{sec:interp} is a fixed ternary network of the same kind, which
|
| 2228 |
+
evaluates any network stored in its own state, and Section~\ref{sec:storedhost}
|
| 2229 |
+
stores a SUBLEQ computer in it.
|
| 2230 |
Valiant's universal circuits are combinational circuits of size
|
| 2231 |
$\Theta(n\log n)$ that simulate any circuit of size $n$ given its program bits as
|
| 2232 |
input~\cite{Valiant1976}; intrinsic simulation between families of automata
|
|
|
|
| 2298 |
the dynamics be simpler than the computation attributed to the
|
| 2299 |
system~\cite{CotlerHonglerHudcova2025}. In those terms Section~\ref{sec:selfrep}
|
| 2300 |
is a replicator relative to an instantiation map whose cost
|
| 2301 |
+
Proposition~\ref{prop:envcost} counts, and Sections~\ref{sec:storedhost}
|
| 2302 |
+
and~\ref{sec:organism} remove the map: the constructor is a configuration of a
|
| 2303 |
+
fixed threshold network, and the configuration holds the weights of the network
|
| 2304 |
+
that computes, in Section~\ref{sec:storedhost} the universal computer of
|
| 2305 |
+
Section~\ref{sec:host}.
|
| 2306 |
|
| 2307 |
\subsection{Networks that produce their own parameters}
|
| 2308 |
|
|
|
|
| 2511 |
\texttt{src/netlist\_eval.c}, with its own SUBLEQ reference, device, parser and
|
| 2512 |
levelization, sharing no code with (a)--(c). Evaluators (b)--(d) are built from
|
| 2513 |
$\sigma(\Nhost)$, and every generation of every run instantiated its evaluator
|
| 2514 |
+
afresh from the bytes the previous generation emitted. The two-head machine was
|
| 2515 |
+
evaluated by transcriptions of Definition~\ref{def:twohead} in Python and in C, by
|
| 2516 |
+
the netlist $N^\alpha_{G,L}$ in Python and in C, and in the Rocq kernel. The
|
| 2517 |
+
stored host is built from $\sigma(\Nhost)$ by \texttt{src/stored\_host.py}, which
|
| 2518 |
+
also compares one pass with the host's step and the device, and its generations
|
| 2519 |
+
are run by \texttt{src/stored\_host\_run.c}, a transcription of
|
| 2520 |
+
Definition~\ref{def:twohead} that decodes the active bank once per change of
|
| 2521 |
+
$\kappa$; the three generations of Remark~\ref{rem:storedcheck} take $9$ minutes.
|
| 2522 |
+
Separate code in \texttt{src/independent/}, written from the definitions of this
|
| 2523 |
+
paper, rebuilds $H_A$ from Construction~\ref{con:host} for $A=3$ to $12$,
|
| 2524 |
+
levelizes $\sigma(\Nhost)$, repeats Tables~\ref{tab:curve} to~\ref{tab:bound3}
|
| 2525 |
with a simulator in C and on the accelerator, and maps the datapath onto Loihi
|
| 2526 |
and Akida; its sizes, depths and exact runs are those stated here, and its noisy
|
| 2527 |
runs agree with Appendix~\ref{app:measure} within sampling error.
|
| 2528 |
|
| 2529 |
The Rocq development, \texttt{rocq/} in the artifact, has $25$ files and
|
| 2530 |
+
$4{,}017$ lines and builds with Rocq 9.1.1 in under four minutes on the machine
|
| 2531 |
+
below, most of it in the kernel's evaluations of the first three generations of
|
| 2532 |
+
the organism. It defines the two-head machine for every address width, its
|
| 2533 |
+
netlist block by block, the organism, the description code and the decoder, and
|
| 2534 |
+
proves Theorem~\ref{thm:physnet} for every address width $\alpha\ge3$, bank
|
| 2535 |
+
length $N\ge8+3\alpha$ and tape length $L\ge1$, together with the number of units
|
| 2536 |
+
and the weights, the machine of $64$ cells being the case $\alpha=6$ by
|
| 2537 |
+
computation; it proves Lemma~\ref{lem:code}, Proposition~\ref{prop:pass},
|
| 2538 |
+
Theorem~\ref{thm:construct} for images of any number of records with an idle bank
|
| 2539 |
+
of their length, and Theorem~\ref{thm:organism}. The file that defines the
|
| 2540 |
organism and its description is written by \texttt{src/twohead.py}, and the
|
| 2541 |
+
netlist definition, extracted to OCaml, writes for $N^6_{133,2930}$ and
|
| 2542 |
+
$N^{12}_{5,40}$ files byte for byte equal to those that
|
| 2543 |
\texttt{src/twohead\_net.py} writes.
|
| 2544 |
|
| 2545 |
Besides the runs recorded in the remarks of Sections~\ref{sec:host}
|
| 2546 |
+
to~\ref{sec:organism} and in Appendix~\ref{app:measure}, the following were
|
| 2547 |
checked. The encoder satisfies $\delta(\describe(f))=f$ within the bound of
|
| 2548 |
Lemma~\ref{lem:describe} on the $29$ serialized machines of the artifact,
|
| 2549 |
$971{,}266{,}155$ bytes, and on $68{,}061$ further strings chosen to straddle
|
|
|
|
| 2557 |
$\inst(\ser(\Omega))=\Omega$ on $310$ instances; and rebuilding the host from
|
| 2558 |
source reproduces its serialization byte for byte. Evaluator~(d) agrees with its
|
| 2559 |
own reference on $2^{20}$ random full states of the netlist and of its
|
| 2560 |
+
levelization, and $\Lev(\Nhost)$ agrees with the netlist it comes from on random
|
| 2561 |
+
states, every weight in $\Tern$ and every pre-activation an integer.
|
|
|
|
| 2562 |
|
| 2563 |
The constructor was run on the $29$ recipes of the artifact's machines on the
|
| 2564 |
integer reference, emitting $971{,}266{,}155$ bytes in $4{,}714{,}592{,}952$ steps,
|
|
|
|
| 2595 |
Every run of $\Omega^\ast$ produced the same output, of SHA-256 digest
|
| 2596 |
\texttt{c5950d3f\ldots6e7fb523}, and the artifact~\cite{Norton2026} is identified by
|
| 2597 |
the digests of $\ser(\Omega^\ast)$, of the host serialization, of the serialization
|
| 2598 |
+
of $N_3$, of $\ser(\Omega^\ast_3)$, of the netlist file of $N^6_{133,2930}$, of
|
| 2599 |
the organism's record image and its description written as $3458$ and $2930$
|
| 2600 |
+
bytes of value $0$ or $1$, and of the image of the stored host and $\tau_S$ as
|
| 2601 |
+
bytes:
|
| 2602 |
\begin{center}\ttfamily\small
|
| 2603 |
\begin{tabular}{@{}l@{\quad}l@{}}
|
| 2604 |
\normalfont $\ser(\Omega^\ast)$ & c5950d3fec6bcf70e8111586a030d21b2dfa55bd69a1c7fe5f016cb06e7fb523\\
|
| 2605 |
\normalfont $\sigma(\Nhost)$ & 55c555bd64302190d5bde57ee0cd41b36dac5cf65066d0ed3468567a57e85fa3\\
|
| 2606 |
\normalfont $\sigma(N_3)$ & 111bb202e6f2728449c6b0761f57a059bc0fb38e3e5ba8447bac6613ec7ce313\\
|
| 2607 |
\normalfont $\ser(\Omega^\ast_3)$ & 05005d59c373fb4998576ac098093de6df046355348e00370dbdccb1d458e3de\\
|
| 2608 |
+
\normalfont $N^6_{133,2930}$ & 0b86fbe2da1d67beafb252a445738794f4eb35ad4aa8987030c65d3612aa50fe\\
|
| 2609 |
\normalfont organism $\rho$ & e798ce81da252d6717b0f99321aa401924637b48fe09558a6590006de2e2ffe1\\
|
| 2610 |
+
\normalfont $\describe(\rho)$ & 59c917d4b2602b253bbae19d9866869587abea197730197fee8054acc8781d54\\
|
| 2611 |
+
\normalfont stored host $S$ & 7a769aa264a89860149962d7e98f8b2a5cb34ceb7778e88bcbffdccdc0996154\\
|
| 2612 |
+
\normalfont $\tau_S$ & fb23d9b4b41cd5d0576bce37d0cd53a0f63f33de6d4895f2e784eb1148387185
|
| 2613 |
\end{tabular}
|
| 2614 |
\end{center}
|
| 2615 |
+
The layouts behind these digests are the following. The metadata of
|
| 2616 |
+
$\sigma(\Nhost)$ is \texttt{machine} \texttt{subleq8},
|
| 2617 |
+
\texttt{weight\_quantization} \texttt{ternary}, \texttt{signal\_registry} the
|
| 2618 |
+
first string below, the state layout of Construction~\ref{con:host} by first
|
| 2619 |
+
coordinate and width, with the number of words for the memory, and \texttt{io}
|
| 2620 |
+
the second, the addresses of Table~\ref{tab:device}:
|
| 2621 |
+
\begin{center}\ttfamily\small
|
| 2622 |
+
\{"halt":[8,1],"mem":[9,256,8],"pc":[0,8]\}\\
|
| 2623 |
+
\{"c\_eot":250,"c\_rd":252,"c\_rw":251,"c\_wr":249,"halt\_pc":255,"r\_in":253,"r\_out":254\}
|
| 2624 |
+
\end{center}
|
| 2625 |
+
The scalars are the \texttt{I32} tensors
|
| 2626 |
+
\texttt{manifest.addr\_bits}, \texttt{data\_bits}, \texttt{memory\_words},
|
| 2627 |
+
\texttt{pc\_width}, \texttt{state\_bits}, \texttt{units} and \texttt{version},
|
| 2628 |
+
holding $8$, $8$, $256$, $8$, $2057$, $17{,}598$ and $6$, and the vectors are
|
| 2629 |
+
\texttt{net.fanin}, \texttt{net.next} and \texttt{net.pred} of type \texttt{I16}
|
| 2630 |
+
and \texttt{net.bias} of type \texttt{I8}. A netlist file holds little-endian
|
| 2631 |
+
$32$-bit integers: the numbers of state bits, units and edges; the bias of each
|
| 2632 |
+
unit; the fan-in of each unit; one signed entry per edge, its magnitude the index
|
| 2633 |
+
of the predecessor plus one and its sign the weight; and, for each state bit, the
|
| 2634 |
+
index of the signal computing its next value, the state bits being numbered first,
|
| 2635 |
+
in the order of Theorem~\ref{thm:physnet}, and the units after them in the order of
|
| 2636 |
+
the Rocq definition. The records of the organism and of $S$ are laid out as in
|
| 2637 |
+
Definition~\ref{def:twohead}, with the window cells of
|
| 2638 |
+
Constructions~\ref{con:organism} and~\ref{con:stored}; within each block of
|
| 2639 |
+
Construction~\ref{con:stored} the order of the records is that of
|
| 2640 |
+
\texttt{src/stored\_host.py}, which gives each temporary the least cell free over
|
| 2641 |
+
its live interval.
|
| 2642 |
+
One generation of $\Omega^\ast$ takes $0.3$ seconds on~(a), $45$ seconds on~(d)
|
| 2643 |
+
and $9$ minutes on~(b). All figures were
|
| 2644 |
produced with Python 3.12.3, PyTorch 2.14.0 with CUDA 12.6, NumPy 2.5.3,
|
| 2645 |
safetensors 0.8.0 and GCC 13.3.0 on Ubuntu 24.04, on an Intel Core i9-12900H
|
| 2646 |
with $20$ hardware threads and $31$ GiB of memory and an NVIDIA GeForce RTX 3070
|
| 2647 |
Ti Laptop GPU with $8$ GiB of memory.
|
| 2648 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2649 |
% =============================================================================
|
| 2650 |
\section{Program listings and the organism}\label{app:listings}
|
| 2651 |
% =============================================================================
|
|
|
|
| 2717 |
consists of the $133$ records below, in the order a pass evaluates them; record
|
| 2718 |
$k$ is written $k{:}\;{\pm}a\,{\pm}b\;\beta{\to}o$, reading window cells $a$ and $b$
|
| 2719 |
with weights $\pm1$ and writing cell $o$, and a record with one slot has weight
|
| 2720 |
+
$0$, written $00$, in the other, which names the sink, cell $7$. Cell $\kappa$ is
|
| 2721 |
+
$0$; $\mathrm{rd}$, $\mathrm{arm}$ and $\mathrm{cpy}$ are the cells $1$, $2$ and
|
| 2722 |
+
$3$ under the read head, the arm and the copy head, and $\mathrm{AR}$,
|
| 2723 |
+
$\mathrm{AA}$ and $\mathrm{AC}$ the requests $4$, $5$ and $6$ that turn them; $m$
|
| 2724 |
+
is the mode, in cell $8$, $\mathrm{C}$, $\mathrm{G}$ and $\mathrm{A}$ the phases,
|
| 2725 |
+
in cells $9$, $10$ and $11$, $c_i$ bit $i$ of the codon register, in cell $12+i$,
|
| 2726 |
+
and $z_i$ bit $i$ of the counter, in cell $16+i$; and $t_k$ is the temporary in
|
| 2727 |
+
cell $k$.
|
| 2728 |
|
| 2729 |
{\scriptsize\raggedright\noindent \mbox{$0{:}\;{-}z_0\,{-}z_1\;0{\to}t_{21}$}\hspace{0.7em plus 0.5em}
|
| 2730 |
\mbox{$1{:}\;{+}t_{21}\,{-}z_2\;{-}1{\to}t_{21}$}\hspace{0.7em plus 0.5em}
|
rocq/Assumptions.v
CHANGED
|
@@ -2,7 +2,9 @@
|
|
| 2 |
From TH Require Import PhysMain PhysFacts NetMain Complete Run PassLemma Main SelfRep.
|
| 3 |
|
| 4 |
Print Assumptions PhysMain.netlist_step.
|
|
|
|
| 5 |
Print Assumptions PhysFacts.phys_size.
|
|
|
|
| 6 |
Print Assumptions PhysFacts.phys_ternary.
|
| 7 |
Print Assumptions NetMain.network_orbit.
|
| 8 |
Print Assumptions NetMain.network_reproduces.
|
|
|
|
| 2 |
From TH Require Import PhysMain PhysFacts NetMain Complete Run PassLemma Main SelfRep.
|
| 3 |
|
| 4 |
Print Assumptions PhysMain.netlist_step.
|
| 5 |
+
Print Assumptions PhysMain.netlist_step64.
|
| 6 |
Print Assumptions PhysFacts.phys_size.
|
| 7 |
+
Print Assumptions PhysFacts.phys_size64.
|
| 8 |
Print Assumptions PhysFacts.phys_ternary.
|
| 9 |
Print Assumptions NetMain.network_orbit.
|
| 10 |
Print Assumptions NetMain.network_reproduces.
|
rocq/NetMain.v
CHANGED
|
@@ -2,56 +2,67 @@
|
|
| 2 |
reproduces in every generation. *)
|
| 3 |
From Stdlib Require Import List Bool Arith ZArith Lia.
|
| 4 |
Import ListNotations.
|
| 5 |
-
From TH Require Import TwoHead Tapes Iter Abstract Organism Net Phys PhysSem PhysMain Main.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
(* the network iterated on its state bits *)
|
| 8 |
-
Fixpoint netiter (N L n : nat) (x : list bool) : list bool :=
|
| 9 |
-
match n with
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
Definition shaped_st (N L : nat) (s : st) : Prop :=
|
| 12 |
-
length (win s) =
|
| 13 |
/\ length (contents (d0 s)) = L /\ length (contents (d1 s)) = L.
|
| 14 |
|
| 15 |
-
Lemma step_shaped : forall N L s,
|
|
|
|
| 16 |
Proof.
|
| 17 |
-
intros N L s HN HL (Hw & H0 & H1 & H2 & H3).
|
| 18 |
-
destruct (step_eq N L s HN HL H0 H1 H2 H3 Hw) as (qa' & Hqa & Hst).
|
| 19 |
-
pose proof (tapes_step N L s HN HL H0 H1 H2 H3 Hw qa' Hqa) as T. cbv zeta in T.
|
| 20 |
rewrite <- Hst in T. destruct T as (T0 & T1 & T2 & T3).
|
| 21 |
refine (conj _ (conj _ (conj _ (conj _ _)))).
|
| 22 |
- rewrite Hst, win_stepres. unfold clearq. rewrite !upd_length, length_wnext. exact Hw.
|
| 23 |
-
- rewrite T0. destruct (kk s), (advA s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption.
|
| 24 |
-
- rewrite T1. destruct (kk s), (advA s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption.
|
| 25 |
-
- rewrite T2. destruct (kk s), (advC s), (advR s); rewrite ?rot1_length, ?length_wrotec; assumption.
|
| 26 |
-
- rewrite T3. destruct (kk s), (advC s), (advR s); rewrite ?rot1_length, ?length_wrotec; assumption.
|
| 27 |
Qed.
|
| 28 |
|
| 29 |
(* every orbit of the network on encoded states is the encoding of the machine's orbit *)
|
| 30 |
-
Theorem network_orbit : forall N L n s,
|
| 31 |
-
netiter N L n (encode s) = encode (
|
| 32 |
Proof.
|
| 33 |
-
intros N L n. induction n as [|n IH]; intros s HN HL Hs; [reflexivity|].
|
| 34 |
-
cbn [netiter
|
| 35 |
-
rewrite (netlist_step N L s HN HL Hw H0 H1 H2 H3).
|
| 36 |
-
apply IH; [exact HN | exact HL |]. apply step_shaped;
|
| 37 |
Qed.
|
| 38 |
|
| 39 |
-
Lemma s0_shaped : shaped_st (26 * 133) 2930 s0.
|
| 40 |
Proof.
|
| 41 |
unfold shaped_st, s0, tape_of, contents. cbn [win q0 q1 d0 d1 fr bk rev]. rewrite !app_nil_r.
|
| 42 |
rewrite !repeat_length, length_rho, length_desc. repeat split; reflexivity.
|
| 43 |
Qed.
|
| 44 |
|
| 45 |
-
(* The network on 26 * 133 bank bits and 2930 description bits,
|
| 46 |
-
s0, holds after g + 1 generations the encoding of a state in which
|
| 47 |
-
both banks hold the organism and both description tapes its description. *)
|
| 48 |
Theorem network_reproduces : forall g,
|
| 49 |
-
exists t, netiter (26 * 133) 2930 (S g * gen_steps) (encode s0) = encode t
|
| 50 |
/\ wget (win t) KAPPA = Nat.even g
|
| 51 |
/\ contents (q0 t) = rho /\ contents (q1 t) = rho
|
| 52 |
/\ contents (d0 t) = desc /\ contents (d1 t) = desc.
|
| 53 |
Proof.
|
| 54 |
intro g. exists (itern (S g * gen_steps) s0). split.
|
| 55 |
-
- apply network_orbit; [lia | lia | exact s0_shaped].
|
| 56 |
- exact (every_generation g).
|
| 57 |
Qed.
|
|
|
|
| 2 |
reproduces in every generation. *)
|
| 3 |
From Stdlib Require Import List Bool Arith ZArith Lia.
|
| 4 |
Import ListNotations.
|
| 5 |
+
From TH Require Import TwoHead Tapes Iter Abstract Organism Net Phys PhysWF PhysSem PhysMain Main.
|
| 6 |
+
|
| 7 |
+
(* the machine with a window of 2^al cells, iterated *)
|
| 8 |
+
Fixpoint iterA (al n : nat) (s : st) : st :=
|
| 9 |
+
match n with O => s | S m => iterA al m (stepA al s) end.
|
| 10 |
+
|
| 11 |
+
Lemma iterA_6 : forall n s, iterA 6 n s = itern n s.
|
| 12 |
+
Proof. induction n as [|n IH]; intro s; [reflexivity|]. cbn [iterA itern]. rewrite stepA_6. apply IH. Qed.
|
| 13 |
|
| 14 |
(* the network iterated on its state bits *)
|
| 15 |
+
Fixpoint netiter (al N L n : nat) (x : list bool) : list bool :=
|
| 16 |
+
match n with
|
| 17 |
+
| O => x
|
| 18 |
+
| S m => netiter al N L m (netstep (nst al N L) (phys_units al N L) (phys_next al N L) x)
|
| 19 |
+
end.
|
| 20 |
|
| 21 |
+
Definition shaped_st (al N L : nat) (s : st) : Prop :=
|
| 22 |
+
length (win s) = W al /\ length (contents (q0 s)) = N /\ length (contents (q1 s)) = N
|
| 23 |
/\ length (contents (d0 s)) = L /\ length (contents (d1 s)) = L.
|
| 24 |
|
| 25 |
+
Lemma step_shaped : forall al N L s, 3 <= al -> recw al <= N -> 1 <= L ->
|
| 26 |
+
shaped_st al N L s -> shaped_st al N L (stepA al s).
|
| 27 |
Proof.
|
| 28 |
+
intros al N L s Hal HN HL (Hw & H0 & H1 & H2 & H3).
|
| 29 |
+
destruct (step_eq al N L s Hal HN HL H0 H1 H2 H3 Hw) as (qa' & Hqa & Hst).
|
| 30 |
+
pose proof (tapes_step al N L s Hal HN HL H0 H1 H2 H3 Hw qa' Hqa) as T. cbv zeta in T.
|
| 31 |
rewrite <- Hst in T. destruct T as (T0 & T1 & T2 & T3).
|
| 32 |
refine (conj _ (conj _ (conj _ (conj _ _)))).
|
| 33 |
- rewrite Hst, win_stepres. unfold clearq. rewrite !upd_length, length_wnext. exact Hw.
|
| 34 |
+
- rewrite T0. destruct (kk s), (advA al s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption.
|
| 35 |
+
- rewrite T1. destruct (kk s), (advA al s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption.
|
| 36 |
+
- rewrite T2. destruct (kk s), (advC al s), (advR al s); rewrite ?rot1_length, ?length_wrotec; assumption.
|
| 37 |
+
- rewrite T3. destruct (kk s), (advC al s), (advR al s); rewrite ?rot1_length, ?length_wrotec; assumption.
|
| 38 |
Qed.
|
| 39 |
|
| 40 |
(* every orbit of the network on encoded states is the encoding of the machine's orbit *)
|
| 41 |
+
Theorem network_orbit : forall al N L n s, 3 <= al -> recw al <= N -> 1 <= L -> shaped_st al N L s ->
|
| 42 |
+
netiter al N L n (encode al s) = encode al (iterA al n s).
|
| 43 |
Proof.
|
| 44 |
+
intros al N L n. induction n as [|n IH]; intros s Hal HN HL Hs; [reflexivity|].
|
| 45 |
+
cbn [netiter iterA]. pose proof Hs as (Hw & H0 & H1 & H2 & H3).
|
| 46 |
+
rewrite (netlist_step al N L s Hal HN HL Hw H0 H1 H2 H3).
|
| 47 |
+
apply IH; [exact Hal | exact HN | exact HL |]. apply step_shaped; assumption.
|
| 48 |
Qed.
|
| 49 |
|
| 50 |
+
Lemma s0_shaped : shaped_st 6 (26 * 133) 2930 s0.
|
| 51 |
Proof.
|
| 52 |
unfold shaped_st, s0, tape_of, contents. cbn [win q0 q1 d0 d1 fr bk rev]. rewrite !app_nil_r.
|
| 53 |
rewrite !repeat_length, length_rho, length_desc. repeat split; reflexivity.
|
| 54 |
Qed.
|
| 55 |
|
| 56 |
+
(* The network of the machine with 64 cells, on 26 * 133 bank bits and 2930 description bits,
|
| 57 |
+
started from the encoding of s0, holds after g + 1 generations the encoding of a state in which
|
| 58 |
+
the bank bit is even g, both banks hold the organism and both description tapes its description. *)
|
| 59 |
Theorem network_reproduces : forall g,
|
| 60 |
+
exists t, netiter 6 (26 * 133) 2930 (S g * gen_steps) (encode 6 s0) = encode 6 t
|
| 61 |
/\ wget (win t) KAPPA = Nat.even g
|
| 62 |
/\ contents (q0 t) = rho /\ contents (q1 t) = rho
|
| 63 |
/\ contents (d0 t) = desc /\ contents (d1 t) = desc.
|
| 64 |
Proof.
|
| 65 |
intro g. exists (itern (S g * gen_steps) s0). split.
|
| 66 |
+
- rewrite <- iterA_6. apply network_orbit; [lia | unfold recw; lia | lia | exact s0_shaped].
|
| 67 |
- exact (every_generation g).
|
| 68 |
Qed.
|
rocq/Phys.v
CHANGED
|
@@ -1,19 +1,23 @@
|
|
| 1 |
(* The two-head physics as a netlist of ternary threshold units, unit for unit in the order of
|
| 2 |
-
the generator, for banks of N bits and description tapes of L bits. *)
|
| 3 |
From Stdlib Require Import List Bool Arith ZArith Lia.
|
| 4 |
Import ListNotations.
|
| 5 |
From TH Require Import TwoHead Tapes Net Gates.
|
| 6 |
|
| 7 |
Section Phys.
|
| 8 |
-
Variables N L : nat.
|
| 9 |
|
| 10 |
-
(* the
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
Definition realcell (j : nat) : nat := if Nat.eqb j 0 then 0 else j + 3.
|
| 12 |
-
Definition oq0 : nat :=
|
| 13 |
-
Definition oq1 : nat :=
|
| 14 |
-
Definition od0 : nat :=
|
| 15 |
-
Definition od1 : nat :=
|
| 16 |
-
Definition nst : nat :=
|
| 17 |
|
| 18 |
Definition kap : sref := SIn 0.
|
| 19 |
Definition fld (j : nat) : sref := SRef 0 j 2.
|
|
@@ -21,7 +25,7 @@ Definition fld (j : nat) : sref := SRef 0 j 2.
|
|
| 21 |
Definition head_src (j : nat) : nat * nat :=
|
| 22 |
match j with 0 => (od1, od0) | 1 => (oq0, oq1) | _ => (od0, od1) end.
|
| 23 |
|
| 24 |
-
Definition bitsof (a t : nat) : bool := Nat.testbit a (
|
| 25 |
|
| 26 |
Definition cellref (a : nat) : sref :=
|
| 27 |
if Nat.eqb a 1 || Nat.eqb a 2 || Nat.eqb a 3 then SRef 1 (a - 1) 2
|
|
@@ -35,16 +39,16 @@ Definition hatq (bh base m : nat) : sref := if Nat.eqb m 0 then SRef bh 0 5 else
|
|
| 35 |
Definition hatd (dh base m : nat) : sref := if Nat.eqb m 0 then SRef dh 0 6 else SIn (base + m).
|
| 36 |
|
| 37 |
(* 0: the record in front of the active bank *)
|
| 38 |
-
Definition blk_fld : block := Blk
|
| 39 |
(* 1: the cells under the read head, the arm and the copy head *)
|
| 40 |
Definition blk_head : block :=
|
| 41 |
Blk 3 3 (fun j => mux3 1 j 0 kap (SIn (fst (head_src j))) (SIn (snd (head_src j)))).
|
| 42 |
(* 2, 3, 4: the decode lines of the two operand addresses and the output address *)
|
| 43 |
Definition blk_dec (o : nat) : block :=
|
| 44 |
-
Blk
|
| 45 |
(* 5 to 8: the two operands *)
|
| 46 |
-
Definition blk_term (bdec : nat) : block := Blk
|
| 47 |
-
Definition blk_xs (bterm : nat) : block := Blk 1 1 (fun _ => [sOR (map (fun a => (SRef bterm a 0, true)) (seq 0
|
| 48 |
(* 9 to 17: the weights, the bias and the threshold *)
|
| 49 |
Definition blk_pos : block := Blk 2 1 (fun i => [sAND [(fld (2 * i), false); (fld (2 * i + 1), true)]]).
|
| 50 |
Definition blk_neg : block := Blk 2 1 (fun i => [sAND [(fld (2 * i), true); (fld (2 * i + 1), false)]]).
|
|
@@ -63,14 +67,14 @@ Definition blk_bge : block :=
|
|
| 63 |
Definition blk_vand : block := Blk 5 1 (fun i => [sAND [(SRef 13 i 0, true); (SRef 15 0 (vand_bge i), true)]]).
|
| 64 |
Definition blk_v : block := Blk 1 1 (fun _ => [sOR (map (fun i => (SRef 16 i 0, true)) (seq 0 5))]).
|
| 65 |
(* 18, 19: the window after the write, and the cleared request cells *)
|
| 66 |
-
Definition blk_xhat : block := Blk
|
| 67 |
Definition blk_zero : block := Blk 1 1 (fun _ => [sOR []]).
|
| 68 |
(* 20 to 23: the banks; idlep is the value of kappa for which the bank is idle *)
|
| 69 |
Definition blk_bankh (bh : nat) (idlep : bool) (base : nat) : block :=
|
| 70 |
Blk 1 6 (fun _ => [sAND [(kap, idlep); (SRef 18 2 2, true)]; sAND [(kap, idlep); (SRef 18 2 2, false)];
|
| 71 |
sAND [(SRef 4 2 0, true); (kap, idlep)]] ++ mux3 bh 0 3 (SRef bh 0 2) (SRef 17 0 0) (SIn base)).
|
| 72 |
Definition blk_bank (bb bh : nat) (idlep : bool) (base : nat) : block :=
|
| 73 |
-
Blk N 4 (fun i => [sAND [(kap, negb idlep); (SIn (base + (i +
|
| 74 |
sAND [(SRef bh 0 0, true); (hatq bh base ((i + 1) mod N), true)];
|
| 75 |
sAND [(SRef bh 0 1, true); (hatq bh base i, true)];
|
| 76 |
sOR [(SRef bb i 0, true); (SRef bb i 1, true); (SRef bb i 2, true)]]).
|
|
@@ -83,14 +87,14 @@ Definition blk_desc (db dh base : nat) : block :=
|
|
| 83 |
Blk L 3 (fun i => mux3 db i 0 (SRef dh 0 2) (hatd dh base ((i + 1) mod L)) (hatd dh base i)).
|
| 84 |
|
| 85 |
Definition phys_blocks : list block :=
|
| 86 |
-
[blk_fld; blk_head; blk_dec 8; blk_dec
|
| 87 |
-
blk_pos; blk_neg; blk_mt; blk_nt; blk_pge; blk_b4; blk_bge; blk_vand; blk_v; blk_xhat; blk_zero;
|
| 88 |
blk_bankh 20 true oq0; blk_bank 21 20 true oq0; blk_bankh 22 false oq1; blk_bank 23 22 false oq1;
|
| 89 |
blk_desch 24 true od0; blk_desc 25 24 od0; blk_desch 26 false od1; blk_desc 27 26 od1].
|
| 90 |
|
| 91 |
(* the unit computing the next value of each state bit *)
|
| 92 |
Definition out_ref (i : nat) : sref :=
|
| 93 |
-
if i <?
|
| 94 |
else if i <? oq1 then SRef 21 (i - oq0) 3
|
| 95 |
else if i <? od0 then SRef 23 (i - oq1) 3
|
| 96 |
else if i <? od1 then SRef 25 (i - od0) 2
|
|
|
|
| 1 |
(* The two-head physics as a netlist of ternary threshold units, unit for unit in the order of
|
| 2 |
+
the generator, for a window of 2^al cells, banks of N bits and description tapes of L bits. *)
|
| 3 |
From Stdlib Require Import List Bool Arith ZArith Lia.
|
| 4 |
Import ListNotations.
|
| 5 |
From TH Require Import TwoHead Tapes Net Gates.
|
| 6 |
|
| 7 |
Section Phys.
|
| 8 |
+
Variables al N L : nat.
|
| 9 |
|
| 10 |
+
(* the window has W cells; all but cells 1, 2 and 3 are state bits *)
|
| 11 |
+
Definition W : nat := 2 ^ al.
|
| 12 |
+
Definition nwin : nat := W - 3.
|
| 13 |
+
|
| 14 |
+
(* the state: the window cells other than 1, 2 and 3, then Q0, Q1, D0, D1 *)
|
| 15 |
Definition realcell (j : nat) : nat := if Nat.eqb j 0 then 0 else j + 3.
|
| 16 |
+
Definition oq0 : nat := nwin.
|
| 17 |
+
Definition oq1 : nat := nwin + N.
|
| 18 |
+
Definition od0 : nat := nwin + 2 * N.
|
| 19 |
+
Definition od1 : nat := nwin + 2 * N + L.
|
| 20 |
+
Definition nst : nat := nwin + 2 * N + 2 * L.
|
| 21 |
|
| 22 |
Definition kap : sref := SIn 0.
|
| 23 |
Definition fld (j : nat) : sref := SRef 0 j 2.
|
|
|
|
| 25 |
Definition head_src (j : nat) : nat * nat :=
|
| 26 |
match j with 0 => (od1, od0) | 1 => (oq0, oq1) | _ => (od0, od1) end.
|
| 27 |
|
| 28 |
+
Definition bitsof (a t : nat) : bool := Nat.testbit a (al - 1 - t).
|
| 29 |
|
| 30 |
Definition cellref (a : nat) : sref :=
|
| 31 |
if Nat.eqb a 1 || Nat.eqb a 2 || Nat.eqb a 3 then SRef 1 (a - 1) 2
|
|
|
|
| 39 |
Definition hatd (dh base m : nat) : sref := if Nat.eqb m 0 then SRef dh 0 6 else SIn (base + m).
|
| 40 |
|
| 41 |
(* 0: the record in front of the active bank *)
|
| 42 |
+
Definition blk_fld : block := Blk (recw al) 3 (fun j => mux3 0 j 0 kap (SIn (oq1 + j)) (SIn (oq0 + j))).
|
| 43 |
(* 1: the cells under the read head, the arm and the copy head *)
|
| 44 |
Definition blk_head : block :=
|
| 45 |
Blk 3 3 (fun j => mux3 1 j 0 kap (SIn (fst (head_src j))) (SIn (snd (head_src j)))).
|
| 46 |
(* 2, 3, 4: the decode lines of the two operand addresses and the output address *)
|
| 47 |
Definition blk_dec (o : nat) : block :=
|
| 48 |
+
Blk W 1 (fun a => [sAND (map (fun t => (fld (o + t), bitsof a t)) (seq 0 al))]).
|
| 49 |
(* 5 to 8: the two operands *)
|
| 50 |
+
Definition blk_term (bdec : nat) : block := Blk W 1 (fun a => [sAND [(SRef bdec a 0, true); (cellref a, true)]]).
|
| 51 |
+
Definition blk_xs (bterm : nat) : block := Blk 1 1 (fun _ => [sOR (map (fun a => (SRef bterm a 0, true)) (seq 0 W))]).
|
| 52 |
(* 9 to 17: the weights, the bias and the threshold *)
|
| 53 |
Definition blk_pos : block := Blk 2 1 (fun i => [sAND [(fld (2 * i), false); (fld (2 * i + 1), true)]]).
|
| 54 |
Definition blk_neg : block := Blk 2 1 (fun i => [sAND [(fld (2 * i), true); (fld (2 * i + 1), false)]]).
|
|
|
|
| 67 |
Definition blk_vand : block := Blk 5 1 (fun i => [sAND [(SRef 13 i 0, true); (SRef 15 0 (vand_bge i), true)]]).
|
| 68 |
Definition blk_v : block := Blk 1 1 (fun _ => [sOR (map (fun i => (SRef 16 i 0, true)) (seq 0 5))]).
|
| 69 |
(* 18, 19: the window after the write, and the cleared request cells *)
|
| 70 |
+
Definition blk_xhat : block := Blk nwin 3 (fun j => mux3 18 j 0 (SRef 4 (realcell j) 0) (SRef 17 0 0) (SIn j)).
|
| 71 |
Definition blk_zero : block := Blk 1 1 (fun _ => [sOR []]).
|
| 72 |
(* 20 to 23: the banks; idlep is the value of kappa for which the bank is idle *)
|
| 73 |
Definition blk_bankh (bh : nat) (idlep : bool) (base : nat) : block :=
|
| 74 |
Blk 1 6 (fun _ => [sAND [(kap, idlep); (SRef 18 2 2, true)]; sAND [(kap, idlep); (SRef 18 2 2, false)];
|
| 75 |
sAND [(SRef 4 2 0, true); (kap, idlep)]] ++ mux3 bh 0 3 (SRef bh 0 2) (SRef 17 0 0) (SIn base)).
|
| 76 |
Definition blk_bank (bb bh : nat) (idlep : bool) (base : nat) : block :=
|
| 77 |
+
Blk N 4 (fun i => [sAND [(kap, negb idlep); (SIn (base + (i + recw al) mod N), true)];
|
| 78 |
sAND [(SRef bh 0 0, true); (hatq bh base ((i + 1) mod N), true)];
|
| 79 |
sAND [(SRef bh 0 1, true); (hatq bh base i, true)];
|
| 80 |
sOR [(SRef bb i 0, true); (SRef bb i 1, true); (SRef bb i 2, true)]]).
|
|
|
|
| 87 |
Blk L 3 (fun i => mux3 db i 0 (SRef dh 0 2) (hatd dh base ((i + 1) mod L)) (hatd dh base i)).
|
| 88 |
|
| 89 |
Definition phys_blocks : list block :=
|
| 90 |
+
[blk_fld; blk_head; blk_dec 8; blk_dec (8 + al); blk_dec (8 + 2 * al); blk_term 2; blk_xs 5; blk_term 3;
|
| 91 |
+
blk_xs 7; blk_pos; blk_neg; blk_mt; blk_nt; blk_pge; blk_b4; blk_bge; blk_vand; blk_v; blk_xhat; blk_zero;
|
| 92 |
blk_bankh 20 true oq0; blk_bank 21 20 true oq0; blk_bankh 22 false oq1; blk_bank 23 22 false oq1;
|
| 93 |
blk_desch 24 true od0; blk_desc 25 24 od0; blk_desch 26 false od1; blk_desc 27 26 od1].
|
| 94 |
|
| 95 |
(* the unit computing the next value of each state bit *)
|
| 96 |
Definition out_ref (i : nat) : sref :=
|
| 97 |
+
if i <? nwin then (if Nat.eqb i 1 || Nat.eqb i 2 || Nat.eqb i 3 then SRef 19 0 0 else SRef 18 i 2)
|
| 98 |
else if i <? oq1 then SRef 21 (i - oq0) 3
|
| 99 |
else if i <? od0 then SRef 23 (i - oq1) 3
|
| 100 |
else if i <? od1 then SRef 25 (i - od0) 2
|
rocq/PhysFacts.v
CHANGED
|
@@ -3,14 +3,18 @@ From Stdlib Require Import List Bool Arith ZArith Lia.
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Net Gates Phys PhysWF.
|
| 5 |
|
| 6 |
-
Lemma phys_size : forall N L, length (phys_units N L) =
|
| 7 |
Proof.
|
| 8 |
-
intros N L. unfold phys_units. rewrite length_compile by apply phys_shaped.
|
| 9 |
rewrite phys_length. cbn [phys_blocks boff bcount bsize blk_fld blk_head blk_dec blk_term blk_xs blk_pos
|
| 10 |
blk_neg blk_mt blk_nt blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank
|
| 11 |
-
blk_desch blk_desc]. lia.
|
| 12 |
Qed.
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
Definition ter (u : su) : Prop := forall x w, In (x, w) (sin u) -> w = 1%Z \/ w = (-1)%Z.
|
| 15 |
|
| 16 |
Lemma ter_lits : forall b ls, ter (SU b (map lw ls)).
|
|
@@ -35,9 +39,9 @@ Proof.
|
|
| 35 |
- destruct r; [exact Hu | apply IH].
|
| 36 |
Qed.
|
| 37 |
|
| 38 |
-
Lemma ter_shapes : forall N L b j, Forall ter (bshape (nth b (phys_blocks N L) blk0) j).
|
| 39 |
Proof.
|
| 40 |
-
intros N L b j.
|
| 41 |
do 28 (destruct b as [|b];
|
| 42 |
[ cbn [nth phys_blocks bshape blk_fld blk_head blk_dec blk_term blk_xs blk_pos blk_neg blk_mt blk_nt
|
| 43 |
blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank blk_desch blk_desc];
|
|
@@ -50,10 +54,10 @@ Proof.
|
|
| 50 |
Qed.
|
| 51 |
|
| 52 |
(* every unit of the netlist reads its predecessors with weight +1 or -1 *)
|
| 53 |
-
Theorem phys_ternary : forall N L u, In u (phys_units N L) ->
|
| 54 |
forall i w, In (i, w) (tin u) -> w = 1%Z \/ w = (-1)%Z.
|
| 55 |
Proof.
|
| 56 |
-
intros N L u Hu i w Hin. unfold phys_units, compile in Hu.
|
| 57 |
apply in_concat in Hu as (us & Hus & Hu). apply in_map_iff in Hus as (blk & <- & Hblk).
|
| 58 |
unfold flat_block in Hu. apply in_concat in Hu as (us & Hus & Hu).
|
| 59 |
apply in_map_iff in Hus as (j & <- & Hj). apply in_map_iff in Hu as (v & <- & Hv).
|
|
@@ -61,5 +65,5 @@ Proof.
|
|
| 61 |
cbn [fst snd] in E. injection E as _ <-.
|
| 62 |
apply In_nth with (d := blk0) in Hblk as (b & _ & <-).
|
| 63 |
apply In_nth with (d := su0) in Hv as (r & _ & <-).
|
| 64 |
-
exact (ter_nth _ r (ter_shapes N L b j) x w' Hin).
|
| 65 |
Qed.
|
|
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Net Gates Phys PhysWF.
|
| 5 |
|
| 6 |
+
Lemma phys_size : forall al N L, 3 <= al -> length (phys_units al N L) = 8 * 2 ^ al + 9 * al + 81 + 8 * N + 6 * L.
|
| 7 |
Proof.
|
| 8 |
+
intros al N L Hal. pose proof (W_ge al Hal) as HW. unfold phys_units. rewrite length_compile by apply phys_shaped.
|
| 9 |
rewrite phys_length. cbn [phys_blocks boff bcount bsize blk_fld blk_head blk_dec blk_term blk_xs blk_pos
|
| 10 |
blk_neg blk_mt blk_nt blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank
|
| 11 |
+
blk_desch blk_desc]. unfold nwin, recw, W in *. lia.
|
| 12 |
Qed.
|
| 13 |
|
| 14 |
+
(* the machine of 64 cells *)
|
| 15 |
+
Corollary phys_size64 : forall N L, length (phys_units 6 N L) = 647 + 8 * N + 6 * L.
|
| 16 |
+
Proof. intros N L. rewrite phys_size by lia. cbn [Nat.pow]. lia. Qed.
|
| 17 |
+
|
| 18 |
Definition ter (u : su) : Prop := forall x w, In (x, w) (sin u) -> w = 1%Z \/ w = (-1)%Z.
|
| 19 |
|
| 20 |
Lemma ter_lits : forall b ls, ter (SU b (map lw ls)).
|
|
|
|
| 39 |
- destruct r; [exact Hu | apply IH].
|
| 40 |
Qed.
|
| 41 |
|
| 42 |
+
Lemma ter_shapes : forall al N L b j, Forall ter (bshape (nth b (phys_blocks al N L) blk0) j).
|
| 43 |
Proof.
|
| 44 |
+
intros al N L b j.
|
| 45 |
do 28 (destruct b as [|b];
|
| 46 |
[ cbn [nth phys_blocks bshape blk_fld blk_head blk_dec blk_term blk_xs blk_pos blk_neg blk_mt blk_nt
|
| 47 |
blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank blk_desch blk_desc];
|
|
|
|
| 54 |
Qed.
|
| 55 |
|
| 56 |
(* every unit of the netlist reads its predecessors with weight +1 or -1 *)
|
| 57 |
+
Theorem phys_ternary : forall al N L u, In u (phys_units al N L) ->
|
| 58 |
forall i w, In (i, w) (tin u) -> w = 1%Z \/ w = (-1)%Z.
|
| 59 |
Proof.
|
| 60 |
+
intros al N L u Hu i w Hin. unfold phys_units, compile in Hu.
|
| 61 |
apply in_concat in Hu as (us & Hus & Hu). apply in_map_iff in Hus as (blk & <- & Hblk).
|
| 62 |
unfold flat_block in Hu. apply in_concat in Hu as (us & Hus & Hu).
|
| 63 |
apply in_map_iff in Hus as (j & <- & Hj). apply in_map_iff in Hu as (v & <- & Hv).
|
|
|
|
| 65 |
cbn [fst snd] in E. injection E as _ <-.
|
| 66 |
apply In_nth with (d := blk0) in Hblk as (b & _ & <-).
|
| 67 |
apply In_nth with (d := su0) in Hv as (r & _ & <-).
|
| 68 |
+
exact (ter_nth _ r (ter_shapes al N L b j) x w' Hin).
|
| 69 |
Qed.
|
rocq/PhysMain.v
CHANGED
|
@@ -3,89 +3,106 @@ From Stdlib Require Import List Bool Arith ZArith Lia.
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Tapes Abstract Net Gates Phys PhysWF PhysSem.
|
| 5 |
|
| 6 |
-
Lemma F_unfold : forall N L s x,
|
| 7 |
-
run (phys_units N L) (nst N L) (fun i => nth i (encode s) false) (idx (nst N L) (phys_blocks N L) x)
|
|
|
|
| 8 |
Proof. intros. unfold F, X. reflexivity. Qed.
|
| 9 |
|
| 10 |
-
Lemma wget_clearq_req : forall w a,
|
| 11 |
Proof.
|
| 12 |
-
intros w a Hw Ha. unfold clearq, AA, AR, AC. rewrite !wget_upd, !upd_length
|
|
|
|
|
|
|
|
|
|
| 13 |
destruct Ha as [-> | [-> | ->]]; reflexivity.
|
| 14 |
Qed.
|
| 15 |
|
| 16 |
Lemma win_stepres : forall s k qa' ao v, win (stepres s k qa' ao v) = clearq (wnext (win s) ao v).
|
| 17 |
Proof. intros s k qa' ao v. unfold stepres. cbv zeta. destruct k; reflexivity. Qed.
|
| 18 |
|
| 19 |
-
Lemma length_wrote : forall s l h, length (wrote s l h) = length l.
|
| 20 |
-
Proof. intros s l h. unfold wrote. destruct h; [apply wr0_length|reflexivity]. Qed.
|
| 21 |
|
| 22 |
-
Lemma length_wrotec : forall s l h, length (wrotec s l h) = length l.
|
| 23 |
-
Proof. intros s l h. unfold wrotec. destruct h; [apply wr0_length|reflexivity]. Qed.
|
| 24 |
|
| 25 |
-
(* From any state
|
| 26 |
-
|
| 27 |
-
the encoding of the next state. *)
|
| 28 |
-
Theorem netlist_step : forall N L s,
|
| 29 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 30 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 31 |
-
netstep (nst N L) (phys_units N L) (phys_next N L) (encode s) = encode (
|
| 32 |
Proof.
|
| 33 |
-
intros N L s HN HL Hw H0 H1 H2 H3.
|
| 34 |
-
|
| 35 |
-
|
|
|
|
| 36 |
rewrite <- Hst in T. destruct T as (T0 & T1 & T2 & T3).
|
| 37 |
-
assert (L0 : length (contents (q0 (
|
| 38 |
-
by (rewrite T0; destruct (kk s), (advA s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption).
|
| 39 |
-
assert (L1 : length (contents (q1 (
|
| 40 |
-
by (rewrite T1; destruct (kk s), (advA s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption).
|
| 41 |
-
assert (L2 : length (contents (d0 (
|
| 42 |
-
by (rewrite T2; destruct (kk s), (advC s), (advR s); rewrite ?rot1_length, ?length_wrotec; assumption).
|
| 43 |
-
assert (L3 : length (contents (d1 (
|
| 44 |
-
by (rewrite T3; destruct (kk s), (advC s), (advR s); rewrite ?rot1_length, ?length_wrotec; assumption).
|
| 45 |
unfold netstep, phys_next. rewrite map_map.
|
| 46 |
apply nth_ext with (d := false) (d' := false).
|
| 47 |
-
{ rewrite length_map, length_seq, (length_encode (
|
| 48 |
intros i Hi. rewrite length_map, length_seq in Hi.
|
| 49 |
-
rewrite (nth_map_seq _ (fun i => run (phys_units N L) (nst N L) (fun i0 => nth i0 (encode s) false)
|
| 50 |
-
(idx (nst N L) (phys_blocks N L) (out_ref N L i))) (nst N L) i false Hi).
|
| 51 |
rewrite F_unfold.
|
| 52 |
-
rewrite (nth_encode (
|
| 53 |
unfold out_ref, oq0, oq1, od0, od1, nst in *.
|
| 54 |
-
destruct (Nat.ltb_spec i
|
| 55 |
- (* the window *)
|
| 56 |
rewrite Hst, win_stepres.
|
| 57 |
destruct (Nat.eqb i 1 || Nat.eqb i 2 || Nat.eqb i 3) eqn:E.
|
| 58 |
-
+ rewrite (F_zero N L s HN HL H0 H1 H2 H3). symmetry.
|
|
|
|
| 59 |
unfold realcell. apply orb_true_iff in E as [E|E]; [apply orb_true_iff in E as [E|E]|];
|
| 60 |
apply Nat.eqb_eq in E; subst i; cbn; lia.
|
| 61 |
-
+ rewrite (F_xhat N L s HN HL H0 H1 H2 H3 i
|
| 62 |
apply orb_false_iff in E as [E E3]. apply orb_false_iff in E as [E1 E2].
|
| 63 |
apply Nat.eqb_neq in E1, E2, E3.
|
| 64 |
-
assert (Hr : realcell i <
|
| 65 |
/\ realcell i <> AA /\ realcell i <> AR /\ realcell i <> AC)
|
| 66 |
by (unfold realcell, AA, AR, AC; destruct (Nat.eqb_spec i 0); lia).
|
| 67 |
destruct Hr as (R0 & R1 & R2 & R3 & R4 & R5 & R6).
|
| 68 |
-
rewrite wget_clearq_other by assumption.
|
| 69 |
-
|
|
|
|
| 70 |
+ (* bank 0 *)
|
| 71 |
-
rewrite (F_bank N L s HN HL H0 H1 H2 H3 20 21 true
|
| 72 |
-
ltac:(left; repeat split) (i -
|
| 73 |
rewrite T0. destruct (kk s); reflexivity.
|
| 74 |
-
+ destruct (Nat.ltb_spec i (
|
| 75 |
* (* bank 1 *)
|
| 76 |
-
replace (i - (
|
| 77 |
-
rewrite (F_bank N L s HN HL H0 H1 H2 H3 22 23 false (oq1 N) (q1 s)
|
| 78 |
-
ltac:(right; repeat split) (i -
|
| 79 |
rewrite T1. destruct (kk s); reflexivity.
|
| 80 |
-
* destruct (Nat.ltb_spec i (
|
| 81 |
-- (* description tape 0 *)
|
| 82 |
-
replace (i - (
|
| 83 |
-
rewrite (F_desc N L s HN HL H0 H1 H2 H3 24 25 true (od0 N) (d0 s)
|
| 84 |
-
ltac:(left; repeat split) (i -
|
| 85 |
rewrite T2. destruct (kk s); reflexivity.
|
| 86 |
-- (* description tape 1 *)
|
| 87 |
-
replace (i - (
|
| 88 |
-
rewrite (F_desc N L s HN HL H0 H1 H2 H3 26 27 false (od1 N L) (d1 s)
|
| 89 |
-
ltac:(right; repeat split) (i -
|
| 90 |
rewrite T3. destruct (kk s); reflexivity.
|
| 91 |
Qed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Tapes Abstract Net Gates Phys PhysWF PhysSem.
|
| 5 |
|
| 6 |
+
Lemma F_unfold : forall al N L s x,
|
| 7 |
+
run (phys_units al N L) (nst al N L) (fun i => nth i (encode al s) false) (idx (nst al N L) (phys_blocks al N L) x)
|
| 8 |
+
= F al N L s x.
|
| 9 |
Proof. intros. unfold F, X. reflexivity. Qed.
|
| 10 |
|
| 11 |
+
Lemma wget_clearq_req : forall w a, 7 <= length w -> a = 4 \/ a = 5 \/ a = 6 -> wget (clearq w) a = false.
|
| 12 |
Proof.
|
| 13 |
+
intros w a Hw Ha. unfold clearq, AA, AR, AC. rewrite !wget_upd, !upd_length.
|
| 14 |
+
replace (Nat.ltb 4 (length w)) with true by (symmetry; apply Nat.ltb_lt; lia).
|
| 15 |
+
replace (Nat.ltb 5 (length w)) with true by (symmetry; apply Nat.ltb_lt; lia).
|
| 16 |
+
replace (Nat.ltb 6 (length w)) with true by (symmetry; apply Nat.ltb_lt; lia).
|
| 17 |
destruct Ha as [-> | [-> | ->]]; reflexivity.
|
| 18 |
Qed.
|
| 19 |
|
| 20 |
Lemma win_stepres : forall s k qa' ao v, win (stepres s k qa' ao v) = clearq (wnext (win s) ao v).
|
| 21 |
Proof. intros s k qa' ao v. unfold stepres. cbv zeta. destruct k; reflexivity. Qed.
|
| 22 |
|
| 23 |
+
Lemma length_wrote : forall al s l h, length (wrote al s l h) = length l.
|
| 24 |
+
Proof. intros al s l h. unfold wrote. destruct h; [apply wr0_length|reflexivity]. Qed.
|
| 25 |
|
| 26 |
+
Lemma length_wrotec : forall al s l h, length (wrotec al s l h) = length l.
|
| 27 |
+
Proof. intros al s l h. unfold wrotec. destruct h; [apply wr0_length|reflexivity]. Qed.
|
| 28 |
|
| 29 |
+
(* From any state of the machine with a window of 2^al cells, al >= 3, whose banks hold
|
| 30 |
+
N >= 8 + 3 al bits and whose description tapes hold L >= 1 bits, the netlist, evaluated unit
|
| 31 |
+
by unit on the encoded state, gives the encoding of the next state. *)
|
| 32 |
+
Theorem netlist_step : forall al N L s, 3 <= al -> recw al <= N -> 1 <= L -> length (win s) = W al ->
|
| 33 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 34 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 35 |
+
netstep (nst al N L) (phys_units al N L) (phys_next al N L) (encode al s) = encode al (stepA al s).
|
| 36 |
Proof.
|
| 37 |
+
intros al N L s Hal HN HL Hw H0 H1 H2 H3.
|
| 38 |
+
pose proof (W_ge al Hal) as HW8. pose proof (nwin_W al Hal) as HnW.
|
| 39 |
+
destruct (step_eq al N L s Hal HN HL H0 H1 H2 H3 Hw) as (qa' & Hqa & Hst).
|
| 40 |
+
pose proof (tapes_step al N L s Hal HN HL H0 H1 H2 H3 Hw qa' Hqa) as T. cbv zeta in T.
|
| 41 |
rewrite <- Hst in T. destruct T as (T0 & T1 & T2 & T3).
|
| 42 |
+
assert (L0 : length (contents (q0 (stepA al s))) = N)
|
| 43 |
+
by (rewrite T0; destruct (kk s), (advA al s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption).
|
| 44 |
+
assert (L1 : length (contents (q1 (stepA al s))) = N)
|
| 45 |
+
by (rewrite T1; destruct (kk s), (advA al s); rewrite ?rot1_length, ?length_wrote, ?rotn_length; assumption).
|
| 46 |
+
assert (L2 : length (contents (d0 (stepA al s))) = L)
|
| 47 |
+
by (rewrite T2; destruct (kk s), (advC al s), (advR al s); rewrite ?rot1_length, ?length_wrotec; assumption).
|
| 48 |
+
assert (L3 : length (contents (d1 (stepA al s))) = L)
|
| 49 |
+
by (rewrite T3; destruct (kk s), (advC al s), (advR al s); rewrite ?rot1_length, ?length_wrotec; assumption).
|
| 50 |
unfold netstep, phys_next. rewrite map_map.
|
| 51 |
apply nth_ext with (d := false) (d' := false).
|
| 52 |
+
{ rewrite length_map, length_seq, (length_encode al (stepA al s) N L L0 L1 L2 L3). reflexivity. }
|
| 53 |
intros i Hi. rewrite length_map, length_seq in Hi.
|
| 54 |
+
rewrite (nth_map_seq _ (fun i => run (phys_units al N L) (nst al N L) (fun i0 => nth i0 (encode al s) false)
|
| 55 |
+
(idx (nst al N L) (phys_blocks al N L) (out_ref al N L i))) (nst al N L) i false Hi).
|
| 56 |
rewrite F_unfold.
|
| 57 |
+
rewrite (nth_encode al (stepA al s) N L i L0 L1 L2 L3).
|
| 58 |
unfold out_ref, oq0, oq1, od0, od1, nst in *.
|
| 59 |
+
destruct (Nat.ltb_spec i (nwin al)) as [Hwi|Hwi].
|
| 60 |
- (* the window *)
|
| 61 |
rewrite Hst, win_stepres.
|
| 62 |
destruct (Nat.eqb i 1 || Nat.eqb i 2 || Nat.eqb i 3) eqn:E.
|
| 63 |
+
+ rewrite (F_zero al N L s Hal HN HL H0 H1 H2 H3). symmetry.
|
| 64 |
+
apply wget_clearq_req; [rewrite length_wnext; lia|].
|
| 65 |
unfold realcell. apply orb_true_iff in E as [E|E]; [apply orb_true_iff in E as [E|E]|];
|
| 66 |
apply Nat.eqb_eq in E; subst i; cbn; lia.
|
| 67 |
+
+ rewrite (F_xhat al N L s Hal HN HL H0 H1 H2 H3 i Hwi).
|
| 68 |
apply orb_false_iff in E as [E E3]. apply orb_false_iff in E as [E1 E2].
|
| 69 |
apply Nat.eqb_neq in E1, E2, E3.
|
| 70 |
+
assert (Hr : realcell i < W al /\ realcell i <> 1 /\ realcell i <> 2 /\ realcell i <> 3
|
| 71 |
/\ realcell i <> AA /\ realcell i <> AR /\ realcell i <> AC)
|
| 72 |
by (unfold realcell, AA, AR, AC; destruct (Nat.eqb_spec i 0); lia).
|
| 73 |
destruct Hr as (R0 & R1 & R2 & R3 & R4 & R5 & R6).
|
| 74 |
+
rewrite wget_clearq_other by assumption.
|
| 75 |
+
rewrite (wget_wn al N L s Hal HN HL H0 H1 H2 H3 Hw) by assumption. reflexivity.
|
| 76 |
+
- destruct (Nat.ltb_spec i (nwin al + N)) as [Hq|Hq].
|
| 77 |
+ (* bank 0 *)
|
| 78 |
+
rewrite (F_bank al N L s Hal HN HL H0 H1 H2 H3 20 21 true (oq0 al) (q0 s)
|
| 79 |
+
ltac:(left; repeat split) (i - nwin al) ltac:(lia)).
|
| 80 |
rewrite T0. destruct (kk s); reflexivity.
|
| 81 |
+
+ destruct (Nat.ltb_spec i (nwin al + 2 * N)) as [Hq'|Hq'].
|
| 82 |
* (* bank 1 *)
|
| 83 |
+
replace (i - (nwin al + N)) with (i - nwin al - N) by lia.
|
| 84 |
+
rewrite (F_bank al N L s Hal HN HL H0 H1 H2 H3 22 23 false (oq1 al N) (q1 s)
|
| 85 |
+
ltac:(right; repeat split) (i - nwin al - N) ltac:(lia)).
|
| 86 |
rewrite T1. destruct (kk s); reflexivity.
|
| 87 |
+
* destruct (Nat.ltb_spec i (nwin al + 2 * N + L)) as [Hd|Hd].
|
| 88 |
-- (* description tape 0 *)
|
| 89 |
+
replace (i - (nwin al + 2 * N)) with (i - nwin al - 2 * N) by lia.
|
| 90 |
+
rewrite (F_desc al N L s Hal HN HL H0 H1 H2 H3 24 25 true (od0 al N) (d0 s)
|
| 91 |
+
ltac:(left; repeat split) (i - nwin al - 2 * N) ltac:(lia)).
|
| 92 |
rewrite T2. destruct (kk s); reflexivity.
|
| 93 |
-- (* description tape 1 *)
|
| 94 |
+
replace (i - (nwin al + 2 * N + L)) with (i - nwin al - 2 * N - L) by lia.
|
| 95 |
+
rewrite (F_desc al N L s Hal HN HL H0 H1 H2 H3 26 27 false (od1 al N L) (d1 s)
|
| 96 |
+
ltac:(right; repeat split) (i - nwin al - 2 * N - L) ltac:(lia)).
|
| 97 |
rewrite T3. destruct (kk s); reflexivity.
|
| 98 |
Qed.
|
| 99 |
+
|
| 100 |
+
(* the machine of 64 cells, which runs the organism, is the case al = 6 *)
|
| 101 |
+
Corollary netlist_step64 : forall N L s, 26 <= N -> 1 <= L -> length (win s) = 64 ->
|
| 102 |
+
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 103 |
+
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 104 |
+
netstep (nst 6 N L) (phys_units 6 N L) (phys_next 6 N L) (encode 6 s) = encode 6 (step s).
|
| 105 |
+
Proof.
|
| 106 |
+
intros N L s HN HL Hw H0 H1 H2 H3. rewrite <- stepA_6.
|
| 107 |
+
apply netlist_step; first [exact Hw | assumption | unfold recw; lia | lia].
|
| 108 |
+
Qed.
|
rocq/PhysSem.v
CHANGED
|
@@ -4,39 +4,124 @@ Import ListNotations.
|
|
| 4 |
From TH Require Import TwoHead Tapes Abstract Net Gates Phys PhysWF.
|
| 5 |
|
| 6 |
(* the state bits of a machine state, in the order of the netlist *)
|
| 7 |
-
Definition encode (s : st) : list bool :=
|
| 8 |
-
map (fun j => wget (win s) (realcell j)) (seq 0
|
| 9 |
++ contents (q0 s) ++ contents (q1 s) ++ contents (d0 s) ++ contents (d1 s).
|
| 10 |
|
| 11 |
-
Lemma length_encode : forall s N L,
|
| 12 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 13 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 14 |
-
length (encode s) = nst N L.
|
| 15 |
Proof.
|
| 16 |
-
intros s N L H1 H2 H3 H4. unfold encode, nst.
|
| 17 |
rewrite !length_app, length_map, length_seq, H1, H2, H3, H4. lia.
|
| 18 |
Qed.
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
Section Sem.
|
| 21 |
-
Variables (N L : nat) (s : st).
|
| 22 |
-
Hypotheses (HN :
|
| 23 |
(Hq0 : length (contents (q0 s)) = N) (Hq1 : length (contents (q1 s)) = N)
|
| 24 |
(Hd0 : length (contents (d0 s)) = L) (Hd1 : length (contents (d1 s)) = L).
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
Lemma X_win : forall j, j <
|
| 30 |
Proof.
|
| 31 |
intros j Hj. unfold X, encode. rewrite app_nth1 by (rewrite length_map, length_seq; exact Hj).
|
| 32 |
-
exact (nth_map_seq _ (fun j => wget (win s) (realcell j))
|
| 33 |
Qed.
|
| 34 |
|
| 35 |
Lemma X_tape : forall i,
|
| 36 |
-
(i < N -> X (oq0 + i) = nth i (contents (q0 s)) false)
|
| 37 |
-
/\ (i < N -> X (oq1 N + i) = nth i (contents (q1 s)) false)
|
| 38 |
-
/\ (i < L -> X (od0 N + i) = nth i (contents (d0 s)) false)
|
| 39 |
-
/\ (i < L -> X (od1 N L + i) = nth i (contents (d1 s)) false).
|
| 40 |
Proof.
|
| 41 |
intro i. unfold X, encode, oq0, oq1, od0, od1.
|
| 42 |
repeat split; intro Hi; rewrite app_nth2 by (rewrite length_map, length_seq; lia);
|
|
@@ -47,32 +132,32 @@ Proof.
|
|
| 47 |
- rewrite app_nth2 by lia. rewrite app_nth2 by lia. rewrite app_nth2 by lia. f_equal. lia.
|
| 48 |
Qed.
|
| 49 |
|
| 50 |
-
Lemma F_in : forall i, i < nst N L -> F (SIn i) = X i.
|
| 51 |
Proof. intros i H. unfold F, phys_units. apply net_in. exact H. Qed.
|
| 52 |
|
| 53 |
Lemma F_unit : forall b j r, b < 28 ->
|
| 54 |
-
j < bcount (nth b (phys_blocks N L) blk0) -> r < bsize (nth b (phys_blocks N L) blk0) ->
|
| 55 |
-
F (SRef b j r) = sfire' (sunit (phys_blocks N L) b j r) F.
|
| 56 |
Proof.
|
| 57 |
intros b j r Hb Hj Hr. unfold F, phys_units. apply net_unit; [apply phys_wf; assumption| |assumption|assumption].
|
| 58 |
rewrite phys_length. exact Hb.
|
| 59 |
Qed.
|
| 60 |
|
| 61 |
Lemma F_and : forall b j r ls, b < 28 ->
|
| 62 |
-
j < bcount (nth b (phys_blocks N L) blk0) -> r < bsize (nth b (phys_blocks N L) blk0) ->
|
| 63 |
-
sunit (phys_blocks N L) b j r = sAND ls -> F (SRef b j r) = forallb (litv F) ls.
|
| 64 |
Proof. intros b j r ls Hb Hj Hr E. rewrite F_unit, E by assumption. apply sAND_fire. Qed.
|
| 65 |
|
| 66 |
Lemma F_or : forall b j r ls, b < 28 ->
|
| 67 |
-
j < bcount (nth b (phys_blocks N L) blk0) -> r < bsize (nth b (phys_blocks N L) blk0) ->
|
| 68 |
-
sunit (phys_blocks N L) b j r = sOR ls -> F (SRef b j r) = existsb (litv F) ls.
|
| 69 |
Proof. intros b j r ls Hb Hj Hr E. rewrite F_unit, E by assumption. apply sOR_fire. Qed.
|
| 70 |
|
| 71 |
Lemma F_mux : forall b j r0 sel a c, b < 28 ->
|
| 72 |
-
j < bcount (nth b (phys_blocks N L) blk0) -> S (S r0) < bsize (nth b (phys_blocks N L) blk0) ->
|
| 73 |
-
sunit (phys_blocks N L) b j r0 = sAND [(sel, true); (a, true)] ->
|
| 74 |
-
sunit (phys_blocks N L) b j (S r0) = sAND [(sel, false); (c, true)] ->
|
| 75 |
-
sunit (phys_blocks N L) b j (S (S r0)) = sOR [(SRef b j r0, true); (SRef b j (S r0), true)] ->
|
| 76 |
F (SRef b j (S (S r0))) = if F sel then F a else F c.
|
| 77 |
Proof.
|
| 78 |
intros b j r0 sel a c Hb Hj Hr E0 E1 E2.
|
|
@@ -93,10 +178,10 @@ Ltac blk_compute := cbn [nth phys_blocks bcount bsize bshape blk_fld blk_head bl
|
|
| 93 |
blk_desch blk_desc sunit mux3 app].
|
| 94 |
|
| 95 |
(* block 0: the record in front of the active bank *)
|
| 96 |
-
Lemma F_fld : forall j, j <
|
| 97 |
Proof.
|
| 98 |
intros j Hj. unfold fld.
|
| 99 |
-
rewrite (F_mux 0 j 0 kap (SIn (oq1 N + j)) (SIn (oq0 + j))) by (blk_compute; first [lia | reflexivity]).
|
| 100 |
rewrite F_kap, !F_in by (unfold nst, oq0, oq1; lia).
|
| 101 |
destruct (X_tape j) as (T0 & T1 & _ & _). rewrite T0, T1 by lia.
|
| 102 |
unfold qa. destruct kk; reflexivity.
|
|
@@ -116,47 +201,22 @@ Proof.
|
|
| 116 |
rewrite <- !plus_n_O in T0, T1, T2, T3.
|
| 117 |
repeat split;
|
| 118 |
(rewrite F_mux with (sel := kap)
|
| 119 |
-
(a := SIn (fst (head_src N L _))) (c := SIn (snd (head_src N L _))) by (blk_compute; first [lia | reflexivity]));
|
| 120 |
cbn [head_src fst snd]; rewrite F_kap, !F_in by (unfold nst, oq0, oq1, od0, od1; lia);
|
| 121 |
rewrite ?T0, ?T1, ?T2, ?T3 by lia; unfold rdv, armv, cpyv; rewrite <- ?nth0_hd0; destruct kk; reflexivity.
|
| 122 |
Qed.
|
| 123 |
|
| 124 |
(* ---- blocks 2 to 8: the three addresses and the two operands --------------------- *)
|
| 125 |
-
Lemma bits2nat_nat2bits : forall a, a < 64 -> bits2nat (nat2bits 6 a) = a.
|
| 126 |
-
Proof. intros a Ha. do 64 (destruct a as [|a]; [reflexivity|]). lia. Qed.
|
| 127 |
-
|
| 128 |
-
Lemma nat2bits_bits2nat : forall f, length f = 6 -> nat2bits 6 (bits2nat f) = f.
|
| 129 |
-
Proof.
|
| 130 |
-
intros f Hf. destruct f as [|b0 [|b1 [|b2 [|b3 [|b4 [|b5 [|? ?]]]]]]]; cbn [length] in Hf; try lia.
|
| 131 |
-
destruct b0, b1, b2, b3, b4, b5; reflexivity.
|
| 132 |
-
Qed.
|
| 133 |
-
|
| 134 |
-
Lemma lbeq_refl : forall l, lbeq l l = true.
|
| 135 |
-
Proof. induction l as [|x l IH]; [reflexivity|]. cbn [lbeq]. rewrite IH, eqb_reflx. reflexivity. Qed.
|
| 136 |
-
|
| 137 |
-
Lemma dec_ok : forall f a, length f = 6 -> a < 64 ->
|
| 138 |
-
forallb (fun t => Bool.eqb (nth t f false) (bitsof a t)) (seq 0 6) = Nat.eqb (bits2nat f) a.
|
| 139 |
-
Proof.
|
| 140 |
-
intros f a Hf Ha.
|
| 141 |
-
assert (E : forallb (fun t => Bool.eqb (nth t f false) (bitsof a t)) (seq 0 6) = lbeq f (nat2bits 6 a)).
|
| 142 |
-
{ destruct f as [|b0 [|b1 [|b2 [|b3 [|b4 [|b5 [|? ?]]]]]]]; cbn [length] in Hf; try lia.
|
| 143 |
-
unfold bitsof. cbn - [Nat.testbit Bool.eqb]. rewrite !andb_true_r. reflexivity. }
|
| 144 |
-
rewrite E. destruct (lbeq f (nat2bits 6 a)) eqn:El; destruct (Nat.eqb (bits2nat f) a) eqn:En; auto.
|
| 145 |
-
- apply lbeq_true in El. subst f. rewrite bits2nat_nat2bits in En by exact Ha.
|
| 146 |
-
rewrite Nat.eqb_refl in En. discriminate.
|
| 147 |
-
- apply Nat.eqb_eq in En. rewrite <- En, nat2bits_bits2nat, lbeq_refl in El by exact Hf. discriminate.
|
| 148 |
-
Qed.
|
| 149 |
-
|
| 150 |
Lemma length_qa : length qa = N.
|
| 151 |
Proof. unfold qa. destruct kk; assumption. Qed.
|
| 152 |
|
| 153 |
-
Definition field (o : nat) : list bool := firstn
|
| 154 |
|
| 155 |
-
Lemma length_field : forall o, o +
|
| 156 |
Proof. intros o Ho. unfold field. rewrite length_firstn, length_skipn, length_qa. lia. Qed.
|
| 157 |
|
| 158 |
-
Lemma nth_field : forall o t, t <
|
| 159 |
-
Proof. intros o t Ht. unfold field. rewrite nth_firstn. destruct (Nat.ltb_spec t
|
| 160 |
|
| 161 |
Lemma forallb_map' : forall (A B : Type) (f : B -> bool) (g : A -> B) l, forallb f (map g l) = forallb (fun x => f (g x)) l.
|
| 162 |
Proof. intros A B f g l. induction l as [|x l IH]; [reflexivity|]. cbn [map forallb]. rewrite IH. reflexivity. Qed.
|
|
@@ -170,15 +230,15 @@ Proof. intros A f g l H. induction l as [|x l IH]; [reflexivity|]. cbn [forallb]
|
|
| 170 |
Lemma existsb_ext_in : forall (A : Type) (f g : A -> bool) l, (forall x, In x l -> f x = g x) -> existsb f l = existsb g l.
|
| 171 |
Proof. intros A f g l H. induction l as [|x l IH]; [reflexivity|]. cbn [existsb]. rewrite H, IH; [reflexivity| |left; reflexivity]. intros y Hy. apply H. right. exact Hy. Qed.
|
| 172 |
|
| 173 |
-
Lemma F_dec : forall b o a, (b = 2 /\ o = 8) \/ (b = 3 /\ o =
|
| 174 |
F (SRef b a 0) = Nat.eqb (bits2nat (field o)) a.
|
| 175 |
Proof.
|
| 176 |
intros b o a Hbo Ha.
|
| 177 |
-
assert (Hs : sunit (phys_blocks N L) b a 0 = sAND (map (fun t => (fld (o + t), bitsof a t)) (seq 0
|
| 178 |
by (destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; reflexivity).
|
| 179 |
rewrite (F_and b a 0 _ ltac:(lia) ltac:(destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; blk_compute; lia)
|
| 180 |
ltac:(destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; blk_compute; lia) Hs).
|
| 181 |
-
rewrite forallb_map'. rewrite <-
|
| 182 |
apply forallb_ext_in. intros t Ht. apply in_seq in Ht.
|
| 183 |
unfold litv. cbn [fst snd]. rewrite F_fld by lia. rewrite nth_field by lia. reflexivity.
|
| 184 |
Qed.
|
|
@@ -186,7 +246,7 @@ Qed.
|
|
| 186 |
Definition cellv (a : nat) : bool :=
|
| 187 |
if Nat.eqb a 1 then rdv else if Nat.eqb a 2 then armv else if Nat.eqb a 3 then cpyv else wget (win s) a.
|
| 188 |
|
| 189 |
-
Lemma F_cellref : forall a, a <
|
| 190 |
Proof.
|
| 191 |
intros a Ha. destruct F_heads as (H1 & H2 & H3). unfold cellref, cellv.
|
| 192 |
destruct (Nat.eqb_spec a 1) as [->|E1]; [exact H1|].
|
|
@@ -215,43 +275,41 @@ Qed.
|
|
| 215 |
|
| 216 |
Definition fa (o : nat) : nat := bits2nat (field o).
|
| 217 |
|
| 218 |
-
Lemma fa_lt : forall o, o +
|
| 219 |
Proof.
|
| 220 |
-
intros o Ho. unfold fa.
|
| 221 |
-
rewrite <- (nat2bits_bits2nat (field o) H). remember (field o) as f eqn:Ef. clear Ef.
|
| 222 |
-
destruct f as [|b0 [|b1 [|b2 [|b3 [|b4 [|b5 [|? ?]]]]]]]; cbn [length] in H; try lia.
|
| 223 |
-
destruct b0, b1, b2, b3, b4, b5; cbn; lia.
|
| 224 |
Qed.
|
| 225 |
|
| 226 |
-
Lemma F_xs : forall i, i < 2 -> F (xsref i) = cellv (fa (8 +
|
| 227 |
Proof.
|
| 228 |
intros i Hi. unfold xsref.
|
| 229 |
-
assert (Hlt := fa_lt (8 + 6 * i) ltac:(lia)).
|
| 230 |
destruct (Nat.eqb_spec i 0) as [->|E].
|
| 231 |
-
-
|
|
|
|
| 232 |
rewrite existsb_map'.
|
| 233 |
rewrite (existsb_ext_in _ _ (fun a => Nat.eqb (fa 8) a && cellv a)).
|
| 234 |
-
+ rewrite existsb_pick.
|
| 235 |
replace (0 <=? fa 8) with true by (symmetry; apply Nat.leb_le; lia).
|
| 236 |
-
replace (fa 8 <? 0 +
|
| 237 |
reflexivity.
|
| 238 |
+ intros a Ha. apply in_seq in Ha. rewrite litv_pos.
|
| 239 |
rewrite (F_and 5 a 0 [(SRef 2 a 0, true); (cellref a, true)]) by (blk_compute; first [lia | reflexivity]).
|
| 240 |
cbn [forallb]. rewrite !litv_pos, andb_true_r.
|
| 241 |
rewrite F_dec with (o := 8) by (lia || (left; split; reflexivity)).
|
| 242 |
rewrite F_cellref by lia. reflexivity.
|
| 243 |
-
- replace i with 1 in * by lia.
|
| 244 |
-
|
|
|
|
| 245 |
rewrite existsb_map'.
|
| 246 |
-
rewrite (existsb_ext_in _ _ (fun a => Nat.eqb (fa
|
| 247 |
-
+ rewrite existsb_pick.
|
| 248 |
-
replace (0 <=? fa
|
| 249 |
-
replace (fa
|
| 250 |
reflexivity.
|
| 251 |
+ intros a Ha. apply in_seq in Ha. rewrite litv_pos.
|
| 252 |
rewrite (F_and 7 a 0 [(SRef 3 a 0, true); (cellref a, true)]) by (blk_compute; first [lia | reflexivity]).
|
| 253 |
cbn [forallb]. rewrite !litv_pos, andb_true_r.
|
| 254 |
-
rewrite F_dec with (o :=
|
| 255 |
rewrite F_cellref by lia. reflexivity.
|
| 256 |
Qed.
|
| 257 |
|
|
@@ -275,7 +333,7 @@ Lemma vnet_ok : forall f0 f1 f2 f3 f4 f5 f6 f7 y0 y1,
|
|
| 275 |
= Z.leb 0 (wcode f0 f1 * b2z y0 + wcode f2 f3 * b2z y1 + beta4 f4 f5 f6 f7)%Z.
|
| 276 |
Proof. intros. destruct f0, f1, f2, f3, f4, f5, f6, f7, y0, y1; reflexivity. Qed.
|
| 277 |
|
| 278 |
-
Lemma F_fb : forall j, j <
|
| 279 |
Proof. exact F_fld. Qed.
|
| 280 |
|
| 281 |
Lemma F_v : F (SRef 17 0 0) =
|
|
@@ -331,19 +389,22 @@ Proof.
|
|
| 331 |
Qed.
|
| 332 |
|
| 333 |
(* ---- blocks 18 and 19: the window after the write --------------------------------- *)
|
| 334 |
-
Definition vsem : bool :=
|
| 335 |
-
|
|
|
|
| 336 |
|
| 337 |
Lemma F_vsem : F (SRef 17 0 0) = vsem.
|
| 338 |
-
Proof.
|
|
|
|
|
|
|
| 339 |
|
| 340 |
-
Lemma F_lo : forall a, a <
|
| 341 |
Proof. intros a Ha. apply F_dec; [right; right; split; reflexivity | exact Ha]. Qed.
|
| 342 |
|
| 343 |
-
Lemma realcell_lt : forall j, j <
|
| 344 |
Proof. intros j Hj. unfold realcell. destruct (Nat.eqb j 0); lia. Qed.
|
| 345 |
|
| 346 |
-
Lemma F_xhat : forall j, j <
|
| 347 |
F (SRef 18 j 2) = if Nat.eqb aosem (realcell j) then vsem else wget (win s) (realcell j).
|
| 348 |
Proof.
|
| 349 |
intros j Hj.
|
|
@@ -392,30 +453,30 @@ Proof.
|
|
| 392 |
destruct here; destruct m; reflexivity.
|
| 393 |
Qed.
|
| 394 |
|
| 395 |
-
Lemma F_bank : forall bh bb idlep base T, (bh = 20 /\ bb = 21 /\ idlep = true /\ base = oq0 /\ T = q0 s)
|
| 396 |
-
\/ (bh = 22 /\ bb = 23 /\ idlep = false /\ base = oq1 N /\ T = q1 s) ->
|
| 397 |
forall i, i < N ->
|
| 398 |
F (SRef bb i 3) =
|
| 399 |
if Bool.eqb kk idlep
|
| 400 |
then nth i (if advA then rot1 (wrote (contents T) (Nat.eqb aosem 2)) else wrote (contents T) (Nat.eqb aosem 2)) false
|
| 401 |
-
else nth i (rotn
|
| 402 |
Proof.
|
| 403 |
intros bh bb idlep base T Hsel i Hi.
|
| 404 |
assert (HT : length (contents T) = N) by (destruct Hsel as [(_ & _ & _ & _ & ->)|(_ & _ & _ & _ & ->)]; assumption).
|
| 405 |
assert (Hx : forall m, m < N -> X (base + m) = nth m (contents T) false).
|
| 406 |
{ intros m Hm. destruct (X_tape m) as (T0 & T1 & _ & _).
|
| 407 |
destruct Hsel as [(_ & _ & _ & -> & ->)|(_ & _ & _ & -> & ->)]; [apply T0|apply T1]; exact Hm. }
|
| 408 |
-
assert (Hb : base + N <= nst N L) by (destruct Hsel as [(_ & _ & _ & -> & _)|(_ & _ & _ & -> & _)]; unfold nst, oq0, oq1; lia).
|
| 409 |
-
assert (Hc : forall j r, j < N -> r < 4 -> bb < 28 /\ j < bcount (nth bb (phys_blocks N L) blk0)
|
| 410 |
-
/\ r < bsize (nth bb (phys_blocks N L) blk0))
|
| 411 |
by (intros; destruct Hsel as [(_ & -> & _)|(_ & -> & _)]; blk_compute; lia).
|
| 412 |
-
assert (Hh : forall r, r < 6 -> bh < 28 /\ 0 < bcount (nth bh (phys_blocks N L) blk0)
|
| 413 |
-
/\ r < bsize (nth bh (phys_blocks N L) blk0))
|
| 414 |
by (intros; destruct Hsel as [(-> & _)|(-> & _)]; blk_compute; lia).
|
| 415 |
-
assert (Hsu : forall j, sunit (phys_blocks N L) bb j 3 = sOR [(SRef bb j 0, true); (SRef bb j 1, true); (SRef bb j 2, true)]
|
| 416 |
-
/\ sunit (phys_blocks N L) bb j 0 = sAND [(kap, negb idlep); (SIn (base + (j +
|
| 417 |
-
/\ sunit (phys_blocks N L) bb j 1 = sAND [(SRef bh 0 0, true); (hatq bh base ((j + 1) mod N), true)]
|
| 418 |
-
/\ sunit (phys_blocks N L) bb j 2 = sAND [(SRef bh 0 1, true); (hatq bh base j, true)])
|
| 419 |
by (intro j; destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 420 |
destruct (Hsu i) as (S3 & S0 & S1 & S2).
|
| 421 |
destruct (Hc i 3 Hi ltac:(lia)) as (C1 & C2 & C3).
|
|
@@ -430,12 +491,12 @@ Proof.
|
|
| 430 |
{ destruct F_adv as (_ & HA & _).
|
| 431 |
destruct (Hh 0 ltac:(lia)) as (H01 & H02 & H03). destruct (Hh 1 ltac:(lia)) as (H11 & H12 & H13).
|
| 432 |
destruct (Hh 2 ltac:(lia)) as (H21 & H22 & H23). destruct (Hh 5 ltac:(lia)) as (H51 & H52 & H53).
|
| 433 |
-
assert (U : sunit (phys_blocks N L) bh 0 0 = sAND [(kap, idlep); (SRef 18 2 2, true)]
|
| 434 |
-
/\ sunit (phys_blocks N L) bh 0 1 = sAND [(kap, idlep); (SRef 18 2 2, false)]
|
| 435 |
-
/\ sunit (phys_blocks N L) bh 0 2 = sAND [(SRef 4 2 0, true); (kap, idlep)]
|
| 436 |
-
/\ sunit (phys_blocks N L) bh 0 3 = sAND [(SRef bh 0 2, true); (SRef 17 0 0, true)]
|
| 437 |
-
/\ sunit (phys_blocks N L) bh 0 4 = sAND [(SRef bh 0 2, false); (SIn base, true)]
|
| 438 |
-
/\ sunit (phys_blocks N L) bh 0 5 = sOR [(SRef bh 0 3, true); (SRef bh 0 4, true)])
|
| 439 |
by (destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 440 |
destruct U as (U0 & U1 & U2 & U3 & U4 & U5).
|
| 441 |
split; [|split].
|
|
@@ -454,7 +515,7 @@ Proof.
|
|
| 454 |
{ intros m Hm. rewrite nth_wrote by lia. unfold hatq. destruct (Nat.eqb_spec m 0) as [->|E].
|
| 455 |
- rewrite Hh0. reflexivity.
|
| 456 |
- rewrite F_in by lia. apply Hx. exact Hm. }
|
| 457 |
-
pose proof (Nat.mod_upper_bound (i + 1) N ltac:(lia)). pose proof (Nat.mod_upper_bound (i +
|
| 458 |
rewrite Hia, Hih, !Hhat by lia. unfold litv. cbn [fst snd]. rewrite F_kap, F_in by lia. rewrite Hx by lia.
|
| 459 |
destruct (Bool.eqb kk idlep) eqn:Ek.
|
| 460 |
- apply Bool.eqb_prop in Ek. subst idlep. rewrite ?eqb_reflx, ?andb_true_r.
|
|
@@ -472,8 +533,8 @@ Qed.
|
|
| 472 |
(* ---- blocks 24 to 27: the description tapes -------------------------------------- *)
|
| 473 |
Definition wrotec (l : list bool) (here : bool) : list bool := if here then wr0 l vsem else l.
|
| 474 |
|
| 475 |
-
Lemma F_desc : forall dh db idlep base T, (dh = 24 /\ db = 25 /\ idlep = true /\ base = od0 N /\ T = d0 s)
|
| 476 |
-
\/ (dh = 26 /\ db = 27 /\ idlep = false /\ base = od1 N L /\ T = d1 s) ->
|
| 477 |
forall i, i < L ->
|
| 478 |
F (SRef db i 2) =
|
| 479 |
if Bool.eqb kk idlep
|
|
@@ -485,18 +546,18 @@ Proof.
|
|
| 485 |
assert (Hx : forall m, m < L -> X (base + m) = nth m (contents T) false).
|
| 486 |
{ intros m Hm. destruct (X_tape m) as (_ & _ & T2 & T3).
|
| 487 |
destruct Hsel as [(_ & _ & _ & -> & ->)|(_ & _ & _ & -> & ->)]; [apply T2|apply T3]; exact Hm. }
|
| 488 |
-
assert (Hb : base + L <= nst N L)
|
| 489 |
by (destruct Hsel as [(_ & _ & _ & -> & _)|(_ & _ & _ & -> & _)]; unfold nst, od0, od1; lia).
|
| 490 |
-
assert (Hh : forall r, r < 7 -> dh < 28 /\ 0 < bcount (nth dh (phys_blocks N L) blk0)
|
| 491 |
-
/\ r < bsize (nth dh (phys_blocks N L) blk0))
|
| 492 |
by (intros; destruct Hsel as [(-> & _)|(-> & _)]; blk_compute; lia).
|
| 493 |
-
assert (U : sunit (phys_blocks N L) dh 0 0 = sAND [(kap, negb idlep); (SRef 18 1 2, true)]
|
| 494 |
-
/\ sunit (phys_blocks N L) dh 0 1 = sAND [(kap, idlep); (SRef 18 3 2, true)]
|
| 495 |
-
/\ sunit (phys_blocks N L) dh 0 2 = sOR [(SRef dh 0 0, true); (SRef dh 0 1, true)]
|
| 496 |
-
/\ sunit (phys_blocks N L) dh 0 3 = sAND [(SRef 4 3 0, true); (kap, idlep)]
|
| 497 |
-
/\ sunit (phys_blocks N L) dh 0 4 = sAND [(SRef dh 0 3, true); (SRef 17 0 0, true)]
|
| 498 |
-
/\ sunit (phys_blocks N L) dh 0 5 = sAND [(SRef dh 0 3, false); (SIn base, true)]
|
| 499 |
-
/\ sunit (phys_blocks N L) dh 0 6 = sOR [(SRef dh 0 4, true); (SRef dh 0 5, true)])
|
| 500 |
by (destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 501 |
destruct U as (U0 & U1 & U2 & U3 & U4 & U5 & U6).
|
| 502 |
destruct F_adv as (HR & _ & HC).
|
|
@@ -522,12 +583,12 @@ Proof.
|
|
| 522 |
- rewrite Hh0. destruct (Nat.eqb aosem 3 && Bool.eqb kk idlep); reflexivity.
|
| 523 |
- rewrite F_in by lia. rewrite Hx by exact Hm.
|
| 524 |
destruct (Nat.eqb aosem 3 && Bool.eqb kk idlep); [destruct m; [lia|]|]; reflexivity. }
|
| 525 |
-
assert (Hm3 : sunit (phys_blocks N L) db i 0 = sAND [(SRef dh 0 2, true); (hatd dh base ((i + 1) mod L), true)]
|
| 526 |
-
/\ sunit (phys_blocks N L) db i 1 = sAND [(SRef dh 0 2, false); (hatd dh base i, true)]
|
| 527 |
-
/\ sunit (phys_blocks N L) db i 2 = sOR [(SRef db i 0, true); (SRef db i 1, true)])
|
| 528 |
by (destruct Hsel as [(-> & -> & _ & -> & _)|(-> & -> & _ & -> & _)]; repeat split; reflexivity).
|
| 529 |
destruct Hm3 as (M0 & M1 & M2).
|
| 530 |
-
assert (Hc : db < 28 /\ i < bcount (nth db (phys_blocks N L) blk0) /\ 2 < bsize (nth db (phys_blocks N L) blk0))
|
| 531 |
by (destruct Hsel as [(_ & -> & _)|(_ & -> & _)]; blk_compute; lia).
|
| 532 |
destruct Hc as (C1 & C2 & C3).
|
| 533 |
rewrite (F_mux db i 0 (SRef dh 0 2) (hatd dh base ((i + 1) mod L)) (hatd dh base i) C1 C2 C3 M0 M1 M2).
|
|
@@ -541,7 +602,7 @@ Proof.
|
|
| 541 |
Qed.
|
| 542 |
|
| 543 |
(* ---- one step of the machine in the same terms ------------------------------------ *)
|
| 544 |
-
Hypothesis Hw : length (win s) =
|
| 545 |
|
| 546 |
Lemma firstn_skipn_firstn : forall (l : list bool) a b c, a + b <= c ->
|
| 547 |
firstn b (skipn a (firstn c l)) = firstn b (skipn a l).
|
|
@@ -554,35 +615,38 @@ Proof.
|
|
| 554 |
reflexivity.
|
| 555 |
Qed.
|
| 556 |
|
| 557 |
-
Lemma decode_qa :
|
| 558 |
-
Rec (fa 8) (wcode (fb 0) (fb 1)) (fa
|
|
|
|
| 559 |
Proof.
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
|
|
|
|
|
|
| 563 |
Qed.
|
| 564 |
|
| 565 |
Lemma cellof_cellv : forall a, cellof s kk a = cellv a.
|
| 566 |
Proof. intro a. unfold cellof, cellv, rdv, armv, cpyv. rewrite !hd_t_contents. reflexivity. Qed.
|
| 567 |
|
| 568 |
-
Lemma step_eq : exists qa', contents qa' = rotn
|
| 569 |
Proof.
|
| 570 |
-
destruct (popn
|
| 571 |
exists qa'. split.
|
| 572 |
-
- pose proof (popn_turns
|
| 573 |
-
- assert (Hbits : bits = firstn
|
| 574 |
-
{ pose proof (popn_reads
|
| 575 |
fold qa. rewrite length_qa. lia. }
|
| 576 |
-
apply (
|
| 577 |
-
(beta4 (fb 4) (fb 5) (fb 6) (fb 7)) (fa
|
| 578 |
+ rewrite Hbits. apply decode_qa.
|
| 579 |
+ unfold vsem. rewrite vnet_ok, !cellof_cellv. reflexivity.
|
| 580 |
Qed.
|
| 581 |
|
| 582 |
-
Lemma aosem_lt : aosem <
|
| 583 |
-
Proof. apply fa_lt. lia. Qed.
|
| 584 |
|
| 585 |
-
Lemma wget_wn : forall a, a <
|
| 586 |
wget (wnext (win s) aosem vsem) a = if Nat.eqb aosem a then vsem else wget (win s) a.
|
| 587 |
Proof.
|
| 588 |
intros a Ha H1 H2 H3. unfold wnext.
|
|
@@ -592,7 +656,7 @@ Proof.
|
|
| 592 |
apply orb_true_iff in E as [E|E]; [apply orb_true_iff in E as [E|E]|]; apply Nat.eqb_eq in E; lia.
|
| 593 |
- rewrite wget_upd, Hw. pose proof aosem_lt.
|
| 594 |
destruct (Nat.eqb_spec aosem a) as [E2|E2].
|
| 595 |
-
+ rewrite E2, Nat.eqb_refl. replace (a <?
|
| 596 |
+ replace (Nat.eqb a aosem) with false by (symmetry; apply Nat.eqb_neq; lia). reflexivity.
|
| 597 |
Qed.
|
| 598 |
|
|
@@ -600,12 +664,12 @@ Lemma adv_wn : wget (wnext (win s) aosem vsem) AA = advA /\ wget (wnext (win s)
|
|
| 600 |
/\ wget (wnext (win s) aosem vsem) AC = advC.
|
| 601 |
Proof. unfold AA, AR, AC, advA, advR, advC. repeat split; apply wget_wn; lia. Qed.
|
| 602 |
|
| 603 |
-
Lemma tapes_step : forall qa', contents qa' = rotn
|
| 604 |
let t := stepres s kk qa' aosem vsem in
|
| 605 |
contents (q0 t) = (if kk then (if advA then rot1 (wrote (contents (q0 s)) (Nat.eqb aosem 2))
|
| 606 |
else wrote (contents (q0 s)) (Nat.eqb aosem 2))
|
| 607 |
-
else rotn
|
| 608 |
-
/\ contents (q1 t) = (if kk then rotn
|
| 609 |
else (if advA then rot1 (wrote (contents (q1 s)) (Nat.eqb aosem 2))
|
| 610 |
else wrote (contents (q1 s)) (Nat.eqb aosem 2)))
|
| 611 |
/\ contents (d0 t) = (if kk then (if advC then rot1 (wrotec (contents (d0 s)) (Nat.eqb aosem 3))
|
|
@@ -627,29 +691,28 @@ Qed.
|
|
| 627 |
End Sem.
|
| 628 |
|
| 629 |
(* ---- the netlist computes the step -------------------------------------------------- *)
|
| 630 |
-
Lemma nth_encode : forall s N L i,
|
| 631 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 632 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 633 |
-
nth i (encode s) false =
|
| 634 |
-
if i <?
|
| 635 |
-
else if i <?
|
| 636 |
-
else if i <?
|
| 637 |
-
else if i <?
|
| 638 |
-
else nth (i -
|
| 639 |
-
Proof.
|
| 640 |
-
intros s N L i H0 H1 H2 H3. unfold encode.
|
| 641 |
-
destruct (Nat.ltb_spec i
|
| 642 |
{ rewrite app_nth1 by (rewrite length_map, length_seq; lia).
|
| 643 |
-
exact (nth_map_seq _ (fun j => wget (win s) (realcell j))
|
| 644 |
rewrite app_nth2 by (rewrite length_map, length_seq; lia). rewrite length_map, length_seq.
|
| 645 |
-
destruct (Nat.ltb_spec i (
|
| 646 |
{ rewrite app_nth1 by lia. reflexivity. }
|
| 647 |
rewrite app_nth2 by lia. rewrite H0.
|
| 648 |
-
destruct (Nat.ltb_spec i (
|
| 649 |
{ rewrite app_nth1 by lia. f_equal; lia. }
|
| 650 |
rewrite app_nth2 by lia. rewrite H1.
|
| 651 |
-
destruct (Nat.ltb_spec i (
|
| 652 |
{ rewrite app_nth1 by lia. f_equal; lia. }
|
| 653 |
rewrite app_nth2 by lia. rewrite H2. f_equal; lia.
|
| 654 |
Qed.
|
| 655 |
-
|
|
|
|
| 4 |
From TH Require Import TwoHead Tapes Abstract Net Gates Phys PhysWF.
|
| 5 |
|
| 6 |
(* the state bits of a machine state, in the order of the netlist *)
|
| 7 |
+
Definition encode (al : nat) (s : st) : list bool :=
|
| 8 |
+
map (fun j => wget (win s) (realcell j)) (seq 0 (nwin al))
|
| 9 |
++ contents (q0 s) ++ contents (q1 s) ++ contents (d0 s) ++ contents (d1 s).
|
| 10 |
|
| 11 |
+
Lemma length_encode : forall al s N L,
|
| 12 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 13 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 14 |
+
length (encode al s) = nst al N L.
|
| 15 |
Proof.
|
| 16 |
+
intros al s N L H1 H2 H3 H4. unfold encode, nst.
|
| 17 |
rewrite !length_app, length_map, length_seq, H1, H2, H3, H4. lia.
|
| 18 |
Qed.
|
| 19 |
|
| 20 |
+
(* ---- addresses of al bits, most significant first ---------------------------------- *)
|
| 21 |
+
Lemma bits2nat_acc_eq : forall l acc, bits2nat_acc acc l = acc * 2 ^ length l + bits2nat l.
|
| 22 |
+
Proof.
|
| 23 |
+
unfold bits2nat. induction l as [|b l IH]; intro acc; cbn [bits2nat_acc length Nat.pow].
|
| 24 |
+
- lia.
|
| 25 |
+
- rewrite (IH (2 * acc + (if b then 1 else 0))), (IH (2 * 0 + (if b then 1 else 0))). destruct b; nia.
|
| 26 |
+
Qed.
|
| 27 |
+
|
| 28 |
+
Lemma bits2nat_cons : forall b l, bits2nat (b :: l) = (if b then 2 ^ length l else 0) + bits2nat l.
|
| 29 |
+
Proof.
|
| 30 |
+
intros b l. unfold bits2nat at 1. cbn [bits2nat_acc]. rewrite bits2nat_acc_eq. destruct b; lia.
|
| 31 |
+
Qed.
|
| 32 |
+
|
| 33 |
+
Lemma bits2nat_lt : forall l, bits2nat l < 2 ^ length l.
|
| 34 |
+
Proof.
|
| 35 |
+
induction l as [|b l IH]; [cbn; lia|].
|
| 36 |
+
rewrite bits2nat_cons. cbn [length Nat.pow]. destruct b; lia.
|
| 37 |
+
Qed.
|
| 38 |
+
|
| 39 |
+
Lemma testbit_bits2nat : forall l t, t < length l ->
|
| 40 |
+
Nat.testbit (bits2nat l) (length l - 1 - t) = nth t l false.
|
| 41 |
+
Proof.
|
| 42 |
+
induction l as [|b l IH]; intros t Ht; cbn [length] in Ht; [lia|].
|
| 43 |
+
rewrite bits2nat_cons. cbn [length]. pose proof (bits2nat_lt l) as Hlt.
|
| 44 |
+
destruct t as [|t].
|
| 45 |
+
- cbn [nth]. replace (S (length l) - 1 - 0) with (length l) by lia.
|
| 46 |
+
apply Nat.b2n_inj. rewrite Nat.testbit_spec'.
|
| 47 |
+
destruct b.
|
| 48 |
+
+ replace (2 ^ length l + bits2nat l) with (1 * 2 ^ length l + bits2nat l) by lia.
|
| 49 |
+
rewrite Nat.div_add_l by (apply Nat.pow_nonzero; lia). rewrite Nat.div_small by exact Hlt. reflexivity.
|
| 50 |
+
+ rewrite Nat.add_0_l, Nat.div_small by exact Hlt. reflexivity.
|
| 51 |
+
- cbn [nth]. replace (S (length l) - 1 - S t) with (length l - 1 - t) by lia.
|
| 52 |
+
rewrite <- (Nat.mod_pow2_bits_low _ (length l)) by lia.
|
| 53 |
+
replace ((if b then 2 ^ length l else 0) + bits2nat l) with (bits2nat l + (if b then 1 else 0) * 2 ^ length l)
|
| 54 |
+
by (destruct b; lia).
|
| 55 |
+
rewrite Nat.Div0.mod_add, Nat.mod_small by exact Hlt.
|
| 56 |
+
apply IH. lia.
|
| 57 |
+
Qed.
|
| 58 |
+
|
| 59 |
+
Lemma bits_eq_nat : forall x y w, x < 2 ^ w -> y < 2 ^ w ->
|
| 60 |
+
(forall i, i < w -> Nat.testbit x i = Nat.testbit y i) -> x = y.
|
| 61 |
+
Proof.
|
| 62 |
+
intros x y w Hx Hy H. apply Nat.bits_inj. intro n.
|
| 63 |
+
destruct (Nat.lt_ge_cases n w) as [Hn|Hn]; [apply H; exact Hn|].
|
| 64 |
+
assert (Z0 : forall z, z < 2 ^ w -> Nat.testbit z n = false).
|
| 65 |
+
{ intros z Hz. apply Bool.not_true_is_false. intro E.
|
| 66 |
+
pose proof (Nat.testbit_spec' z n) as S. rewrite E in S. cbn [Nat.b2n] in S.
|
| 67 |
+
rewrite Nat.div_small in S; [cbn in S; discriminate|].
|
| 68 |
+
pose proof (Nat.pow_le_mono_r 2 w n ltac:(lia) Hn). lia. }
|
| 69 |
+
rewrite !Z0 by assumption. reflexivity.
|
| 70 |
+
Qed.
|
| 71 |
+
|
| 72 |
+
Lemma dec_okA : forall al f a, length f = al -> a < 2 ^ al ->
|
| 73 |
+
forallb (fun t => Bool.eqb (nth t f false) (bitsof al a t)) (seq 0 al) = Nat.eqb (bits2nat f) a.
|
| 74 |
+
Proof.
|
| 75 |
+
intros al f a Hf Ha. unfold bitsof.
|
| 76 |
+
destruct (forallb (fun t => Bool.eqb (nth t f false) (Nat.testbit a (al - 1 - t))) (seq 0 al)) eqn:E; symmetry.
|
| 77 |
+
- apply Nat.eqb_eq. apply (bits_eq_nat _ _ al); [rewrite <- Hf; apply bits2nat_lt | exact Ha |].
|
| 78 |
+
intros i Hi. rewrite forallb_forall in E. specialize (E (al - 1 - i) ltac:(apply in_seq; lia)).
|
| 79 |
+
apply Bool.eqb_prop in E. replace (al - 1 - (al - 1 - i)) with i in E by lia.
|
| 80 |
+
rewrite <- E. pose proof (testbit_bits2nat f (al - 1 - i) ltac:(lia)) as T.
|
| 81 |
+
rewrite Hf in T. replace (al - 1 - (al - 1 - i)) with i in T by lia. exact T.
|
| 82 |
+
- apply Nat.eqb_neq. intro Eq. subst a.
|
| 83 |
+
assert (Et : forallb (fun t => Bool.eqb (nth t f false) (Nat.testbit (bits2nat f) (al - 1 - t))) (seq 0 al) = true).
|
| 84 |
+
{ apply forallb_forall. intros t Ht. apply in_seq in Ht.
|
| 85 |
+
pose proof (testbit_bits2nat f t ltac:(lia)) as T. rewrite Hf in T. rewrite T. apply eqb_reflx. }
|
| 86 |
+
congruence.
|
| 87 |
+
Qed.
|
| 88 |
+
|
| 89 |
+
(* the step of the machine with a window of 2^al cells, unfolded *)
|
| 90 |
+
Lemma step_charA : forall al s k bits qa' a0 w0 a1 w1 beta ao v,
|
| 91 |
+
wget (win s) KAPPA = k ->
|
| 92 |
+
popn (recw al) (if k then q1 s else q0 s) = (bits, qa') ->
|
| 93 |
+
decodeA al bits = Rec a0 w0 a1 w1 beta ao ->
|
| 94 |
+
v = Z.leb 0 (w0 * b2z (cellof s k a0) + w1 * b2z (cellof s k a1) + beta)%Z ->
|
| 95 |
+
stepA al s = stepres s k qa' ao v.
|
| 96 |
+
Proof.
|
| 97 |
+
intros al s k bits qa' a0 w0 a1 w1 beta ao v Hk Hp Hd Hv.
|
| 98 |
+
unfold stepA, stepres, cellof, wnext, clearq. cbv zeta. rewrite Hk, Hp, Hd. subst v. reflexivity.
|
| 99 |
+
Qed.
|
| 100 |
+
|
| 101 |
Section Sem.
|
| 102 |
+
Variables (al N L : nat) (s : st).
|
| 103 |
+
Hypotheses (Hal : 3 <= al) (HN : recw al <= N) (HL : 1 <= L)
|
| 104 |
(Hq0 : length (contents (q0 s)) = N) (Hq1 : length (contents (q1 s)) = N)
|
| 105 |
(Hd0 : length (contents (d0 s)) = L) (Hd1 : length (contents (d1 s)) = L).
|
| 106 |
|
| 107 |
+
Let HW8 : 8 <= W al := W_ge al Hal.
|
| 108 |
+
Let HnW : nwin al + 3 = W al := nwin_W al Hal.
|
| 109 |
+
Let Hrw : 8 + 3 * al = recw al := eq_refl.
|
| 110 |
+
|
| 111 |
+
Definition X (i : nat) : bool := nth i (encode al s) false.
|
| 112 |
+
Definition F (x : sref) : bool := run (phys_units al N L) (nst al N L) X (idx (nst al N L) (phys_blocks al N L) x).
|
| 113 |
|
| 114 |
+
Lemma X_win : forall j, j < nwin al -> X j = wget (win s) (realcell j).
|
| 115 |
Proof.
|
| 116 |
intros j Hj. unfold X, encode. rewrite app_nth1 by (rewrite length_map, length_seq; exact Hj).
|
| 117 |
+
exact (nth_map_seq _ (fun j => wget (win s) (realcell j)) (nwin al) j false Hj).
|
| 118 |
Qed.
|
| 119 |
|
| 120 |
Lemma X_tape : forall i,
|
| 121 |
+
(i < N -> X (oq0 al + i) = nth i (contents (q0 s)) false)
|
| 122 |
+
/\ (i < N -> X (oq1 al N + i) = nth i (contents (q1 s)) false)
|
| 123 |
+
/\ (i < L -> X (od0 al N + i) = nth i (contents (d0 s)) false)
|
| 124 |
+
/\ (i < L -> X (od1 al N L + i) = nth i (contents (d1 s)) false).
|
| 125 |
Proof.
|
| 126 |
intro i. unfold X, encode, oq0, oq1, od0, od1.
|
| 127 |
repeat split; intro Hi; rewrite app_nth2 by (rewrite length_map, length_seq; lia);
|
|
|
|
| 132 |
- rewrite app_nth2 by lia. rewrite app_nth2 by lia. rewrite app_nth2 by lia. f_equal. lia.
|
| 133 |
Qed.
|
| 134 |
|
| 135 |
+
Lemma F_in : forall i, i < nst al N L -> F (SIn i) = X i.
|
| 136 |
Proof. intros i H. unfold F, phys_units. apply net_in. exact H. Qed.
|
| 137 |
|
| 138 |
Lemma F_unit : forall b j r, b < 28 ->
|
| 139 |
+
j < bcount (nth b (phys_blocks al N L) blk0) -> r < bsize (nth b (phys_blocks al N L) blk0) ->
|
| 140 |
+
F (SRef b j r) = sfire' (sunit (phys_blocks al N L) b j r) F.
|
| 141 |
Proof.
|
| 142 |
intros b j r Hb Hj Hr. unfold F, phys_units. apply net_unit; [apply phys_wf; assumption| |assumption|assumption].
|
| 143 |
rewrite phys_length. exact Hb.
|
| 144 |
Qed.
|
| 145 |
|
| 146 |
Lemma F_and : forall b j r ls, b < 28 ->
|
| 147 |
+
j < bcount (nth b (phys_blocks al N L) blk0) -> r < bsize (nth b (phys_blocks al N L) blk0) ->
|
| 148 |
+
sunit (phys_blocks al N L) b j r = sAND ls -> F (SRef b j r) = forallb (litv F) ls.
|
| 149 |
Proof. intros b j r ls Hb Hj Hr E. rewrite F_unit, E by assumption. apply sAND_fire. Qed.
|
| 150 |
|
| 151 |
Lemma F_or : forall b j r ls, b < 28 ->
|
| 152 |
+
j < bcount (nth b (phys_blocks al N L) blk0) -> r < bsize (nth b (phys_blocks al N L) blk0) ->
|
| 153 |
+
sunit (phys_blocks al N L) b j r = sOR ls -> F (SRef b j r) = existsb (litv F) ls.
|
| 154 |
Proof. intros b j r ls Hb Hj Hr E. rewrite F_unit, E by assumption. apply sOR_fire. Qed.
|
| 155 |
|
| 156 |
Lemma F_mux : forall b j r0 sel a c, b < 28 ->
|
| 157 |
+
j < bcount (nth b (phys_blocks al N L) blk0) -> S (S r0) < bsize (nth b (phys_blocks al N L) blk0) ->
|
| 158 |
+
sunit (phys_blocks al N L) b j r0 = sAND [(sel, true); (a, true)] ->
|
| 159 |
+
sunit (phys_blocks al N L) b j (S r0) = sAND [(sel, false); (c, true)] ->
|
| 160 |
+
sunit (phys_blocks al N L) b j (S (S r0)) = sOR [(SRef b j r0, true); (SRef b j (S r0), true)] ->
|
| 161 |
F (SRef b j (S (S r0))) = if F sel then F a else F c.
|
| 162 |
Proof.
|
| 163 |
intros b j r0 sel a c Hb Hj Hr E0 E1 E2.
|
|
|
|
| 178 |
blk_desch blk_desc sunit mux3 app].
|
| 179 |
|
| 180 |
(* block 0: the record in front of the active bank *)
|
| 181 |
+
Lemma F_fld : forall j, j < recw al -> F (fld j) = nth j qa false.
|
| 182 |
Proof.
|
| 183 |
intros j Hj. unfold fld.
|
| 184 |
+
rewrite (F_mux 0 j 0 kap (SIn (oq1 al N + j)) (SIn (oq0 al + j))) by (blk_compute; first [lia | reflexivity]).
|
| 185 |
rewrite F_kap, !F_in by (unfold nst, oq0, oq1; lia).
|
| 186 |
destruct (X_tape j) as (T0 & T1 & _ & _). rewrite T0, T1 by lia.
|
| 187 |
unfold qa. destruct kk; reflexivity.
|
|
|
|
| 201 |
rewrite <- !plus_n_O in T0, T1, T2, T3.
|
| 202 |
repeat split;
|
| 203 |
(rewrite F_mux with (sel := kap)
|
| 204 |
+
(a := SIn (fst (head_src al N L _))) (c := SIn (snd (head_src al N L _))) by (blk_compute; first [lia | reflexivity]));
|
| 205 |
cbn [head_src fst snd]; rewrite F_kap, !F_in by (unfold nst, oq0, oq1, od0, od1; lia);
|
| 206 |
rewrite ?T0, ?T1, ?T2, ?T3 by lia; unfold rdv, armv, cpyv; rewrite <- ?nth0_hd0; destruct kk; reflexivity.
|
| 207 |
Qed.
|
| 208 |
|
| 209 |
(* ---- blocks 2 to 8: the three addresses and the two operands --------------------- *)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
Lemma length_qa : length qa = N.
|
| 211 |
Proof. unfold qa. destruct kk; assumption. Qed.
|
| 212 |
|
| 213 |
+
Definition field (o : nat) : list bool := firstn al (skipn o qa).
|
| 214 |
|
| 215 |
+
Lemma length_field : forall o, o + al <= recw al -> length (field o) = al.
|
| 216 |
Proof. intros o Ho. unfold field. rewrite length_firstn, length_skipn, length_qa. lia. Qed.
|
| 217 |
|
| 218 |
+
Lemma nth_field : forall o t, t < al -> nth t (field o) false = nth (o + t) qa false.
|
| 219 |
+
Proof. intros o t Ht. unfold field. rewrite nth_firstn. destruct (Nat.ltb_spec t al); [|lia]. apply nth_skipn. Qed.
|
| 220 |
|
| 221 |
Lemma forallb_map' : forall (A B : Type) (f : B -> bool) (g : A -> B) l, forallb f (map g l) = forallb (fun x => f (g x)) l.
|
| 222 |
Proof. intros A B f g l. induction l as [|x l IH]; [reflexivity|]. cbn [map forallb]. rewrite IH. reflexivity. Qed.
|
|
|
|
| 230 |
Lemma existsb_ext_in : forall (A : Type) (f g : A -> bool) l, (forall x, In x l -> f x = g x) -> existsb f l = existsb g l.
|
| 231 |
Proof. intros A f g l H. induction l as [|x l IH]; [reflexivity|]. cbn [existsb]. rewrite H, IH; [reflexivity| |left; reflexivity]. intros y Hy. apply H. right. exact Hy. Qed.
|
| 232 |
|
| 233 |
+
Lemma F_dec : forall b o a, (b = 2 /\ o = 8) \/ (b = 3 /\ o = 8 + al) \/ (b = 4 /\ o = 8 + 2 * al) -> a < W al ->
|
| 234 |
F (SRef b a 0) = Nat.eqb (bits2nat (field o)) a.
|
| 235 |
Proof.
|
| 236 |
intros b o a Hbo Ha.
|
| 237 |
+
assert (Hs : sunit (phys_blocks al N L) b a 0 = sAND (map (fun t => (fld (o + t), bitsof al a t)) (seq 0 al)))
|
| 238 |
by (destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; reflexivity).
|
| 239 |
rewrite (F_and b a 0 _ ltac:(lia) ltac:(destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; blk_compute; lia)
|
| 240 |
ltac:(destruct Hbo as [[-> ->]|[[-> ->]|[-> ->]]]; blk_compute; lia) Hs).
|
| 241 |
+
rewrite forallb_map'. rewrite <- (dec_okA al (field o) a) by (try apply length_field; unfold W in Ha; lia).
|
| 242 |
apply forallb_ext_in. intros t Ht. apply in_seq in Ht.
|
| 243 |
unfold litv. cbn [fst snd]. rewrite F_fld by lia. rewrite nth_field by lia. reflexivity.
|
| 244 |
Qed.
|
|
|
|
| 246 |
Definition cellv (a : nat) : bool :=
|
| 247 |
if Nat.eqb a 1 then rdv else if Nat.eqb a 2 then armv else if Nat.eqb a 3 then cpyv else wget (win s) a.
|
| 248 |
|
| 249 |
+
Lemma F_cellref : forall a, a < W al -> F (cellref a) = cellv a.
|
| 250 |
Proof.
|
| 251 |
intros a Ha. destruct F_heads as (H1 & H2 & H3). unfold cellref, cellv.
|
| 252 |
destruct (Nat.eqb_spec a 1) as [->|E1]; [exact H1|].
|
|
|
|
| 275 |
|
| 276 |
Definition fa (o : nat) : nat := bits2nat (field o).
|
| 277 |
|
| 278 |
+
Lemma fa_lt : forall o, o + al <= recw al -> fa o < W al.
|
| 279 |
Proof.
|
| 280 |
+
intros o Ho. unfold fa, W. rewrite <- (length_field o Ho). apply bits2nat_lt.
|
|
|
|
|
|
|
|
|
|
| 281 |
Qed.
|
| 282 |
|
| 283 |
+
Lemma F_xs : forall i, i < 2 -> F (xsref i) = cellv (fa (8 + al * i)).
|
| 284 |
Proof.
|
| 285 |
intros i Hi. unfold xsref.
|
|
|
|
| 286 |
destruct (Nat.eqb_spec i 0) as [->|E].
|
| 287 |
+
- assert (Hlt := fa_lt 8 ltac:(lia)).
|
| 288 |
+
rewrite (F_or 6 0 0 (map (fun a => (SRef 5 a 0, true)) (seq 0 (W al)))) by (blk_compute; first [lia | reflexivity]).
|
| 289 |
rewrite existsb_map'.
|
| 290 |
rewrite (existsb_ext_in _ _ (fun a => Nat.eqb (fa 8) a && cellv a)).
|
| 291 |
+
+ rewrite existsb_pick. rewrite Nat.mul_0_r, Nat.add_0_r.
|
| 292 |
replace (0 <=? fa 8) with true by (symmetry; apply Nat.leb_le; lia).
|
| 293 |
+
replace (fa 8 <? 0 + W al) with true by (symmetry; apply Nat.ltb_lt; lia).
|
| 294 |
reflexivity.
|
| 295 |
+ intros a Ha. apply in_seq in Ha. rewrite litv_pos.
|
| 296 |
rewrite (F_and 5 a 0 [(SRef 2 a 0, true); (cellref a, true)]) by (blk_compute; first [lia | reflexivity]).
|
| 297 |
cbn [forallb]. rewrite !litv_pos, andb_true_r.
|
| 298 |
rewrite F_dec with (o := 8) by (lia || (left; split; reflexivity)).
|
| 299 |
rewrite F_cellref by lia. reflexivity.
|
| 300 |
+
- replace i with 1 in * by lia. rewrite Nat.mul_1_r.
|
| 301 |
+
assert (Hlt := fa_lt (8 + al) ltac:(lia)).
|
| 302 |
+
rewrite (F_or 8 0 0 (map (fun a => (SRef 7 a 0, true)) (seq 0 (W al)))) by (blk_compute; first [lia | reflexivity]).
|
| 303 |
rewrite existsb_map'.
|
| 304 |
+
rewrite (existsb_ext_in _ _ (fun a => Nat.eqb (fa (8 + al)) a && cellv a)).
|
| 305 |
+
+ rewrite existsb_pick.
|
| 306 |
+
replace (0 <=? fa (8 + al)) with true by (symmetry; apply Nat.leb_le; lia).
|
| 307 |
+
replace (fa (8 + al) <? 0 + W al) with true by (symmetry; apply Nat.ltb_lt; lia).
|
| 308 |
reflexivity.
|
| 309 |
+ intros a Ha. apply in_seq in Ha. rewrite litv_pos.
|
| 310 |
rewrite (F_and 7 a 0 [(SRef 3 a 0, true); (cellref a, true)]) by (blk_compute; first [lia | reflexivity]).
|
| 311 |
cbn [forallb]. rewrite !litv_pos, andb_true_r.
|
| 312 |
+
rewrite F_dec with (o := 8 + al) by (lia || (right; left; split; reflexivity)).
|
| 313 |
rewrite F_cellref by lia. reflexivity.
|
| 314 |
Qed.
|
| 315 |
|
|
|
|
| 333 |
= Z.leb 0 (wcode f0 f1 * b2z y0 + wcode f2 f3 * b2z y1 + beta4 f4 f5 f6 f7)%Z.
|
| 334 |
Proof. intros. destruct f0, f1, f2, f3, f4, f5, f6, f7, y0, y1; reflexivity. Qed.
|
| 335 |
|
| 336 |
+
Lemma F_fb : forall j, j < recw al -> F (fld j) = fb j.
|
| 337 |
Proof. exact F_fld. Qed.
|
| 338 |
|
| 339 |
Lemma F_v : F (SRef 17 0 0) =
|
|
|
|
| 389 |
Qed.
|
| 390 |
|
| 391 |
(* ---- blocks 18 and 19: the window after the write --------------------------------- *)
|
| 392 |
+
Definition vsem : bool :=
|
| 393 |
+
vnet (fb 0) (fb 1) (fb 2) (fb 3) (fb 4) (fb 5) (fb 6) (fb 7) (cellv (fa 8)) (cellv (fa (8 + al))).
|
| 394 |
+
Definition aosem : nat := fa (8 + 2 * al).
|
| 395 |
|
| 396 |
Lemma F_vsem : F (SRef 17 0 0) = vsem.
|
| 397 |
+
Proof.
|
| 398 |
+
rewrite F_v, (F_xs 0), (F_xs 1) by lia. rewrite Nat.mul_0_r, Nat.add_0_r, Nat.mul_1_r. reflexivity.
|
| 399 |
+
Qed.
|
| 400 |
|
| 401 |
+
Lemma F_lo : forall a, a < W al -> F (SRef 4 a 0) = Nat.eqb aosem a.
|
| 402 |
Proof. intros a Ha. apply F_dec; [right; right; split; reflexivity | exact Ha]. Qed.
|
| 403 |
|
| 404 |
+
Lemma realcell_lt : forall j, j < nwin al -> realcell j < W al.
|
| 405 |
Proof. intros j Hj. unfold realcell. destruct (Nat.eqb j 0); lia. Qed.
|
| 406 |
|
| 407 |
+
Lemma F_xhat : forall j, j < nwin al ->
|
| 408 |
F (SRef 18 j 2) = if Nat.eqb aosem (realcell j) then vsem else wget (win s) (realcell j).
|
| 409 |
Proof.
|
| 410 |
intros j Hj.
|
|
|
|
| 453 |
destruct here; destruct m; reflexivity.
|
| 454 |
Qed.
|
| 455 |
|
| 456 |
+
Lemma F_bank : forall bh bb idlep base T, (bh = 20 /\ bb = 21 /\ idlep = true /\ base = oq0 al /\ T = q0 s)
|
| 457 |
+
\/ (bh = 22 /\ bb = 23 /\ idlep = false /\ base = oq1 al N /\ T = q1 s) ->
|
| 458 |
forall i, i < N ->
|
| 459 |
F (SRef bb i 3) =
|
| 460 |
if Bool.eqb kk idlep
|
| 461 |
then nth i (if advA then rot1 (wrote (contents T) (Nat.eqb aosem 2)) else wrote (contents T) (Nat.eqb aosem 2)) false
|
| 462 |
+
else nth i (rotn (recw al) (contents T)) false.
|
| 463 |
Proof.
|
| 464 |
intros bh bb idlep base T Hsel i Hi.
|
| 465 |
assert (HT : length (contents T) = N) by (destruct Hsel as [(_ & _ & _ & _ & ->)|(_ & _ & _ & _ & ->)]; assumption).
|
| 466 |
assert (Hx : forall m, m < N -> X (base + m) = nth m (contents T) false).
|
| 467 |
{ intros m Hm. destruct (X_tape m) as (T0 & T1 & _ & _).
|
| 468 |
destruct Hsel as [(_ & _ & _ & -> & ->)|(_ & _ & _ & -> & ->)]; [apply T0|apply T1]; exact Hm. }
|
| 469 |
+
assert (Hb : base + N <= nst al N L) by (destruct Hsel as [(_ & _ & _ & -> & _)|(_ & _ & _ & -> & _)]; unfold nst, oq0, oq1; lia).
|
| 470 |
+
assert (Hc : forall j r, j < N -> r < 4 -> bb < 28 /\ j < bcount (nth bb (phys_blocks al N L) blk0)
|
| 471 |
+
/\ r < bsize (nth bb (phys_blocks al N L) blk0))
|
| 472 |
by (intros; destruct Hsel as [(_ & -> & _)|(_ & -> & _)]; blk_compute; lia).
|
| 473 |
+
assert (Hh : forall r, r < 6 -> bh < 28 /\ 0 < bcount (nth bh (phys_blocks al N L) blk0)
|
| 474 |
+
/\ r < bsize (nth bh (phys_blocks al N L) blk0))
|
| 475 |
by (intros; destruct Hsel as [(-> & _)|(-> & _)]; blk_compute; lia).
|
| 476 |
+
assert (Hsu : forall j, sunit (phys_blocks al N L) bb j 3 = sOR [(SRef bb j 0, true); (SRef bb j 1, true); (SRef bb j 2, true)]
|
| 477 |
+
/\ sunit (phys_blocks al N L) bb j 0 = sAND [(kap, negb idlep); (SIn (base + (j + recw al) mod N), true)]
|
| 478 |
+
/\ sunit (phys_blocks al N L) bb j 1 = sAND [(SRef bh 0 0, true); (hatq bh base ((j + 1) mod N), true)]
|
| 479 |
+
/\ sunit (phys_blocks al N L) bb j 2 = sAND [(SRef bh 0 1, true); (hatq bh base j, true)])
|
| 480 |
by (intro j; destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 481 |
destruct (Hsu i) as (S3 & S0 & S1 & S2).
|
| 482 |
destruct (Hc i 3 Hi ltac:(lia)) as (C1 & C2 & C3).
|
|
|
|
| 491 |
{ destruct F_adv as (_ & HA & _).
|
| 492 |
destruct (Hh 0 ltac:(lia)) as (H01 & H02 & H03). destruct (Hh 1 ltac:(lia)) as (H11 & H12 & H13).
|
| 493 |
destruct (Hh 2 ltac:(lia)) as (H21 & H22 & H23). destruct (Hh 5 ltac:(lia)) as (H51 & H52 & H53).
|
| 494 |
+
assert (U : sunit (phys_blocks al N L) bh 0 0 = sAND [(kap, idlep); (SRef 18 2 2, true)]
|
| 495 |
+
/\ sunit (phys_blocks al N L) bh 0 1 = sAND [(kap, idlep); (SRef 18 2 2, false)]
|
| 496 |
+
/\ sunit (phys_blocks al N L) bh 0 2 = sAND [(SRef 4 2 0, true); (kap, idlep)]
|
| 497 |
+
/\ sunit (phys_blocks al N L) bh 0 3 = sAND [(SRef bh 0 2, true); (SRef 17 0 0, true)]
|
| 498 |
+
/\ sunit (phys_blocks al N L) bh 0 4 = sAND [(SRef bh 0 2, false); (SIn base, true)]
|
| 499 |
+
/\ sunit (phys_blocks al N L) bh 0 5 = sOR [(SRef bh 0 3, true); (SRef bh 0 4, true)])
|
| 500 |
by (destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 501 |
destruct U as (U0 & U1 & U2 & U3 & U4 & U5).
|
| 502 |
split; [|split].
|
|
|
|
| 515 |
{ intros m Hm. rewrite nth_wrote by lia. unfold hatq. destruct (Nat.eqb_spec m 0) as [->|E].
|
| 516 |
- rewrite Hh0. reflexivity.
|
| 517 |
- rewrite F_in by lia. apply Hx. exact Hm. }
|
| 518 |
+
pose proof (Nat.mod_upper_bound (i + 1) N ltac:(lia)). pose proof (Nat.mod_upper_bound (i + recw al) N ltac:(lia)).
|
| 519 |
rewrite Hia, Hih, !Hhat by lia. unfold litv. cbn [fst snd]. rewrite F_kap, F_in by lia. rewrite Hx by lia.
|
| 520 |
destruct (Bool.eqb kk idlep) eqn:Ek.
|
| 521 |
- apply Bool.eqb_prop in Ek. subst idlep. rewrite ?eqb_reflx, ?andb_true_r.
|
|
|
|
| 533 |
(* ---- blocks 24 to 27: the description tapes -------------------------------------- *)
|
| 534 |
Definition wrotec (l : list bool) (here : bool) : list bool := if here then wr0 l vsem else l.
|
| 535 |
|
| 536 |
+
Lemma F_desc : forall dh db idlep base T, (dh = 24 /\ db = 25 /\ idlep = true /\ base = od0 al N /\ T = d0 s)
|
| 537 |
+
\/ (dh = 26 /\ db = 27 /\ idlep = false /\ base = od1 al N L /\ T = d1 s) ->
|
| 538 |
forall i, i < L ->
|
| 539 |
F (SRef db i 2) =
|
| 540 |
if Bool.eqb kk idlep
|
|
|
|
| 546 |
assert (Hx : forall m, m < L -> X (base + m) = nth m (contents T) false).
|
| 547 |
{ intros m Hm. destruct (X_tape m) as (_ & _ & T2 & T3).
|
| 548 |
destruct Hsel as [(_ & _ & _ & -> & ->)|(_ & _ & _ & -> & ->)]; [apply T2|apply T3]; exact Hm. }
|
| 549 |
+
assert (Hb : base + L <= nst al N L)
|
| 550 |
by (destruct Hsel as [(_ & _ & _ & -> & _)|(_ & _ & _ & -> & _)]; unfold nst, od0, od1; lia).
|
| 551 |
+
assert (Hh : forall r, r < 7 -> dh < 28 /\ 0 < bcount (nth dh (phys_blocks al N L) blk0)
|
| 552 |
+
/\ r < bsize (nth dh (phys_blocks al N L) blk0))
|
| 553 |
by (intros; destruct Hsel as [(-> & _)|(-> & _)]; blk_compute; lia).
|
| 554 |
+
assert (U : sunit (phys_blocks al N L) dh 0 0 = sAND [(kap, negb idlep); (SRef 18 1 2, true)]
|
| 555 |
+
/\ sunit (phys_blocks al N L) dh 0 1 = sAND [(kap, idlep); (SRef 18 3 2, true)]
|
| 556 |
+
/\ sunit (phys_blocks al N L) dh 0 2 = sOR [(SRef dh 0 0, true); (SRef dh 0 1, true)]
|
| 557 |
+
/\ sunit (phys_blocks al N L) dh 0 3 = sAND [(SRef 4 3 0, true); (kap, idlep)]
|
| 558 |
+
/\ sunit (phys_blocks al N L) dh 0 4 = sAND [(SRef dh 0 3, true); (SRef 17 0 0, true)]
|
| 559 |
+
/\ sunit (phys_blocks al N L) dh 0 5 = sAND [(SRef dh 0 3, false); (SIn base, true)]
|
| 560 |
+
/\ sunit (phys_blocks al N L) dh 0 6 = sOR [(SRef dh 0 4, true); (SRef dh 0 5, true)])
|
| 561 |
by (destruct Hsel as [(-> & -> & -> & -> & _)|(-> & -> & -> & -> & _)]; repeat split; reflexivity).
|
| 562 |
destruct U as (U0 & U1 & U2 & U3 & U4 & U5 & U6).
|
| 563 |
destruct F_adv as (HR & _ & HC).
|
|
|
|
| 583 |
- rewrite Hh0. destruct (Nat.eqb aosem 3 && Bool.eqb kk idlep); reflexivity.
|
| 584 |
- rewrite F_in by lia. rewrite Hx by exact Hm.
|
| 585 |
destruct (Nat.eqb aosem 3 && Bool.eqb kk idlep); [destruct m; [lia|]|]; reflexivity. }
|
| 586 |
+
assert (Hm3 : sunit (phys_blocks al N L) db i 0 = sAND [(SRef dh 0 2, true); (hatd dh base ((i + 1) mod L), true)]
|
| 587 |
+
/\ sunit (phys_blocks al N L) db i 1 = sAND [(SRef dh 0 2, false); (hatd dh base i, true)]
|
| 588 |
+
/\ sunit (phys_blocks al N L) db i 2 = sOR [(SRef db i 0, true); (SRef db i 1, true)])
|
| 589 |
by (destruct Hsel as [(-> & -> & _ & -> & _)|(-> & -> & _ & -> & _)]; repeat split; reflexivity).
|
| 590 |
destruct Hm3 as (M0 & M1 & M2).
|
| 591 |
+
assert (Hc : db < 28 /\ i < bcount (nth db (phys_blocks al N L) blk0) /\ 2 < bsize (nth db (phys_blocks al N L) blk0))
|
| 592 |
by (destruct Hsel as [(_ & -> & _)|(_ & -> & _)]; blk_compute; lia).
|
| 593 |
destruct Hc as (C1 & C2 & C3).
|
| 594 |
rewrite (F_mux db i 0 (SRef dh 0 2) (hatd dh base ((i + 1) mod L)) (hatd dh base i) C1 C2 C3 M0 M1 M2).
|
|
|
|
| 602 |
Qed.
|
| 603 |
|
| 604 |
(* ---- one step of the machine in the same terms ------------------------------------ *)
|
| 605 |
+
Hypothesis Hw : length (win s) = W al.
|
| 606 |
|
| 607 |
Lemma firstn_skipn_firstn : forall (l : list bool) a b c, a + b <= c ->
|
| 608 |
firstn b (skipn a (firstn c l)) = firstn b (skipn a l).
|
|
|
|
| 615 |
reflexivity.
|
| 616 |
Qed.
|
| 617 |
|
| 618 |
+
Lemma decode_qa : decodeA al (firstn (recw al) qa) =
|
| 619 |
+
Rec (fa 8) (wcode (fb 0) (fb 1)) (fa (8 + al)) (wcode (fb 2) (fb 3)) (beta4 (fb 4) (fb 5) (fb 6) (fb 7))
|
| 620 |
+
(fa (8 + 2 * al)).
|
| 621 |
Proof.
|
| 622 |
+
assert (Hn : forall i, i < 8 -> nth i (firstn (recw al) qa) false = nth i qa false).
|
| 623 |
+
{ intros i Hi. rewrite nth_firstn. destruct (Nat.ltb_spec i (recw al)); [reflexivity | unfold recw in *; lia]. }
|
| 624 |
+
unfold decodeA. cbv zeta. unfold fa, field, fb, beta4.
|
| 625 |
+
rewrite !firstn_skipn_firstn by (unfold recw; lia). rewrite !Hn by lia.
|
| 626 |
+
rewrite firstn4_skipn4 by (rewrite length_qa; unfold recw in *; lia). reflexivity.
|
| 627 |
Qed.
|
| 628 |
|
| 629 |
Lemma cellof_cellv : forall a, cellof s kk a = cellv a.
|
| 630 |
Proof. intro a. unfold cellof, cellv, rdv, armv, cpyv. rewrite !hd_t_contents. reflexivity. Qed.
|
| 631 |
|
| 632 |
+
Lemma step_eq : exists qa', contents qa' = rotn (recw al) qa /\ stepA al s = stepres s kk qa' aosem vsem.
|
| 633 |
Proof.
|
| 634 |
+
destruct (popn (recw al) (if kk then q1 s else q0 s)) as [bits qa'] eqn:Ep.
|
| 635 |
exists qa'. split.
|
| 636 |
+
- pose proof (popn_turns (recw al) (if kk then q1 s else q0 s)) as P. rewrite Ep in P. exact P.
|
| 637 |
+
- assert (Hbits : bits = firstn (recw al) qa).
|
| 638 |
+
{ pose proof (popn_reads (recw al) (if kk then q1 s else q0 s)) as P. rewrite Ep in P. apply P.
|
| 639 |
fold qa. rewrite length_qa. lia. }
|
| 640 |
+
apply (step_charA al s kk bits qa' (fa 8) (wcode (fb 0) (fb 1)) (fa (8 + al)) (wcode (fb 2) (fb 3))
|
| 641 |
+
(beta4 (fb 4) (fb 5) (fb 6) (fb 7)) (fa (8 + 2 * al)) vsem eq_refl Ep).
|
| 642 |
+ rewrite Hbits. apply decode_qa.
|
| 643 |
+ unfold vsem. rewrite vnet_ok, !cellof_cellv. reflexivity.
|
| 644 |
Qed.
|
| 645 |
|
| 646 |
+
Lemma aosem_lt : aosem < W al.
|
| 647 |
+
Proof. apply fa_lt. unfold recw. lia. Qed.
|
| 648 |
|
| 649 |
+
Lemma wget_wn : forall a, a < W al -> a <> 1 -> a <> 2 -> a <> 3 ->
|
| 650 |
wget (wnext (win s) aosem vsem) a = if Nat.eqb aosem a then vsem else wget (win s) a.
|
| 651 |
Proof.
|
| 652 |
intros a Ha H1 H2 H3. unfold wnext.
|
|
|
|
| 656 |
apply orb_true_iff in E as [E|E]; [apply orb_true_iff in E as [E|E]|]; apply Nat.eqb_eq in E; lia.
|
| 657 |
- rewrite wget_upd, Hw. pose proof aosem_lt.
|
| 658 |
destruct (Nat.eqb_spec aosem a) as [E2|E2].
|
| 659 |
+
+ rewrite E2, Nat.eqb_refl. replace (a <? W al) with true by (symmetry; apply Nat.ltb_lt; lia). reflexivity.
|
| 660 |
+ replace (Nat.eqb a aosem) with false by (symmetry; apply Nat.eqb_neq; lia). reflexivity.
|
| 661 |
Qed.
|
| 662 |
|
|
|
|
| 664 |
/\ wget (wnext (win s) aosem vsem) AC = advC.
|
| 665 |
Proof. unfold AA, AR, AC, advA, advR, advC. repeat split; apply wget_wn; lia. Qed.
|
| 666 |
|
| 667 |
+
Lemma tapes_step : forall qa', contents qa' = rotn (recw al) qa ->
|
| 668 |
let t := stepres s kk qa' aosem vsem in
|
| 669 |
contents (q0 t) = (if kk then (if advA then rot1 (wrote (contents (q0 s)) (Nat.eqb aosem 2))
|
| 670 |
else wrote (contents (q0 s)) (Nat.eqb aosem 2))
|
| 671 |
+
else rotn (recw al) (contents (q0 s)))
|
| 672 |
+
/\ contents (q1 t) = (if kk then rotn (recw al) (contents (q1 s))
|
| 673 |
else (if advA then rot1 (wrote (contents (q1 s)) (Nat.eqb aosem 2))
|
| 674 |
else wrote (contents (q1 s)) (Nat.eqb aosem 2)))
|
| 675 |
/\ contents (d0 t) = (if kk then (if advC then rot1 (wrotec (contents (d0 s)) (Nat.eqb aosem 3))
|
|
|
|
| 691 |
End Sem.
|
| 692 |
|
| 693 |
(* ---- the netlist computes the step -------------------------------------------------- *)
|
| 694 |
+
Lemma nth_encode : forall al s N L i,
|
| 695 |
length (contents (q0 s)) = N -> length (contents (q1 s)) = N ->
|
| 696 |
length (contents (d0 s)) = L -> length (contents (d1 s)) = L ->
|
| 697 |
+
nth i (encode al s) false =
|
| 698 |
+
if i <? nwin al then wget (win s) (realcell i)
|
| 699 |
+
else if i <? nwin al + N then nth (i - nwin al) (contents (q0 s)) false
|
| 700 |
+
else if i <? nwin al + 2 * N then nth (i - nwin al - N) (contents (q1 s)) false
|
| 701 |
+
else if i <? nwin al + 2 * N + L then nth (i - nwin al - 2 * N) (contents (d0 s)) false
|
| 702 |
+
else nth (i - nwin al - 2 * N - L) (contents (d1 s)) false.
|
| 703 |
+
Proof.
|
| 704 |
+
intros al s N L i H0 H1 H2 H3. unfold encode.
|
| 705 |
+
destruct (Nat.ltb_spec i (nwin al)).
|
| 706 |
{ rewrite app_nth1 by (rewrite length_map, length_seq; lia).
|
| 707 |
+
exact (nth_map_seq _ (fun j => wget (win s) (realcell j)) (nwin al) i false H). }
|
| 708 |
rewrite app_nth2 by (rewrite length_map, length_seq; lia). rewrite length_map, length_seq.
|
| 709 |
+
destruct (Nat.ltb_spec i (nwin al + N)).
|
| 710 |
{ rewrite app_nth1 by lia. reflexivity. }
|
| 711 |
rewrite app_nth2 by lia. rewrite H0.
|
| 712 |
+
destruct (Nat.ltb_spec i (nwin al + 2 * N)).
|
| 713 |
{ rewrite app_nth1 by lia. f_equal; lia. }
|
| 714 |
rewrite app_nth2 by lia. rewrite H1.
|
| 715 |
+
destruct (Nat.ltb_spec i (nwin al + 2 * N + L)).
|
| 716 |
{ rewrite app_nth1 by lia. f_equal; lia. }
|
| 717 |
rewrite app_nth2 by lia. rewrite H2. f_equal; lia.
|
| 718 |
Qed.
|
|
|
rocq/PhysWF.v
CHANGED
|
@@ -3,15 +3,24 @@ From Stdlib Require Import List Bool Arith ZArith Lia.
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Net Gates Phys.
|
| 5 |
|
| 6 |
-
Lemma phys_shaped : forall N L, Forall shaped (phys_blocks N L).
|
| 7 |
Proof.
|
| 8 |
-
intros N L. unfold phys_blocks.
|
| 9 |
repeat apply Forall_cons; try apply Forall_nil; intros j Hj; reflexivity.
|
| 10 |
Qed.
|
| 11 |
|
| 12 |
-
Lemma phys_length : forall N L, length (phys_blocks N L) = 28.
|
| 13 |
Proof. reflexivity. Qed.
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
Ltac unfold_layout := unfold nst, oq0, oq1, od0, od1 in *.
|
| 16 |
|
| 17 |
(* a reference to an earlier block, or to an earlier unit of the same member, or a state bit *)
|
|
@@ -23,17 +32,17 @@ Ltac rb_solve :=
|
|
| 23 |
| left; split; [lia|];
|
| 24 |
cbn [nth phys_blocks bcount bsize blk_fld blk_head blk_dec blk_term blk_xs blk_pos blk_neg blk_mt
|
| 25 |
blk_nt blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank blk_desch blk_desc];
|
| 26 |
-
split; lia ].
|
| 27 |
|
| 28 |
Ltac crush_in Hin :=
|
| 29 |
-
cbn [nth mux3 sin sAND sOR map lw fst snd
|
| 30 |
repeat (destruct Hin as [Hin|Hin]; [injection Hin as <- <-|]); try destruct Hin.
|
| 31 |
|
| 32 |
(* open the helpers that name signals, splitting on the cases they distinguish *)
|
| 33 |
Ltac open_refs :=
|
| 34 |
unfold kap, hatq, hatd, cellref, xsref, realcell in *;
|
| 35 |
try match goal with |- context [vand_bge ?j] => destruct j as [|[|[|[|j]]]]; cbn [vand_bge] end;
|
| 36 |
-
try match goal with |- context [head_src _ _ ?j] => destruct j as [|[|j]]; cbn [head_src fst snd] end;
|
| 37 |
repeat match goal with |- context [if ?c then _ else _] => destruct c eqn:? end;
|
| 38 |
repeat match goal with
|
| 39 |
| H : (_ =? _) = true |- _ => apply Nat.eqb_eq in H
|
|
@@ -49,14 +58,67 @@ Ltac split_blocks b :=
|
|
| 49 |
blk_desch blk_desc] in *
|
| 50 |
| first [lia | split_blocks b] ].
|
| 51 |
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
Proof.
|
| 54 |
-
intros N L HN HL. split; [apply phys_shaped|].
|
| 55 |
intros b j r x w Hb Hj Hr Hin. unfold sunit in Hin. rewrite phys_length in Hb.
|
| 56 |
-
|
| 57 |
-
assert (
|
|
|
|
| 58 |
assert (M3 : forall i, (i + 1) mod L < L) by (intro i; apply Nat.mod_upper_bound; lia).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
split_blocks b.
|
|
|
|
| 60 |
all: repeat (destruct r as [|r]; [crush_in Hin | try (exfalso; lia)]).
|
| 61 |
all: try lia.
|
| 62 |
all: try rb_solve.
|
|
|
|
| 3 |
Import ListNotations.
|
| 4 |
From TH Require Import TwoHead Net Gates Phys.
|
| 5 |
|
| 6 |
+
Lemma phys_shaped : forall al N L, Forall shaped (phys_blocks al N L).
|
| 7 |
Proof.
|
| 8 |
+
intros al N L. unfold phys_blocks.
|
| 9 |
repeat apply Forall_cons; try apply Forall_nil; intros j Hj; reflexivity.
|
| 10 |
Qed.
|
| 11 |
|
| 12 |
+
Lemma phys_length : forall al N L, length (phys_blocks al N L) = 28.
|
| 13 |
Proof. reflexivity. Qed.
|
| 14 |
|
| 15 |
+
Lemma W_ge : forall al, 3 <= al -> 8 <= W al.
|
| 16 |
+
Proof.
|
| 17 |
+
intros al H. unfold W. replace al with (3 + (al - 3)) by lia. rewrite Nat.pow_add_r.
|
| 18 |
+
pose proof (Nat.pow_nonzero 2 (al - 3) ltac:(lia)). cbn [Nat.pow]. lia.
|
| 19 |
+
Qed.
|
| 20 |
+
|
| 21 |
+
Lemma nwin_W : forall al, 3 <= al -> nwin al + 3 = W al.
|
| 22 |
+
Proof. intros al H. pose proof (W_ge al H). unfold nwin. lia. Qed.
|
| 23 |
+
|
| 24 |
Ltac unfold_layout := unfold nst, oq0, oq1, od0, od1 in *.
|
| 25 |
|
| 26 |
(* a reference to an earlier block, or to an earlier unit of the same member, or a state bit *)
|
|
|
|
| 32 |
| left; split; [lia|];
|
| 33 |
cbn [nth phys_blocks bcount bsize blk_fld blk_head blk_dec blk_term blk_xs blk_pos blk_neg blk_mt
|
| 34 |
blk_nt blk_pge blk_b4 blk_bge blk_vand blk_v blk_xhat blk_zero blk_bankh blk_bank blk_desch blk_desc];
|
| 35 |
+
unfold recw in *; split; lia ].
|
| 36 |
|
| 37 |
Ltac crush_in Hin :=
|
| 38 |
+
cbn [nth mux3 sin sAND sOR map lw fst snd app kap fld xsref vand_bge] in Hin;
|
| 39 |
repeat (destruct Hin as [Hin|Hin]; [injection Hin as <- <-|]); try destruct Hin.
|
| 40 |
|
| 41 |
(* open the helpers that name signals, splitting on the cases they distinguish *)
|
| 42 |
Ltac open_refs :=
|
| 43 |
unfold kap, hatq, hatd, cellref, xsref, realcell in *;
|
| 44 |
try match goal with |- context [vand_bge ?j] => destruct j as [|[|[|[|j]]]]; cbn [vand_bge] end;
|
| 45 |
+
try match goal with |- context [head_src _ _ _ ?j] => destruct j as [|[|j]]; cbn [head_src fst snd] end;
|
| 46 |
repeat match goal with |- context [if ?c then _ else _] => destruct c eqn:? end;
|
| 47 |
repeat match goal with
|
| 48 |
| H : (_ =? _) = true |- _ => apply Nat.eqb_eq in H
|
|
|
|
| 58 |
blk_desch blk_desc] in *
|
| 59 |
| first [lia | split_blocks b] ].
|
| 60 |
|
| 61 |
+
(* the decode lines and the disjunctions of the operands read lists of symbolic length *)
|
| 62 |
+
Lemma in_dec_lits : forall al o a x w,
|
| 63 |
+
In (x, w) (sin (sAND (map (fun t => (fld (o + t), bitsof al a t)) (seq 0 al)))) ->
|
| 64 |
+
exists t, t < al /\ x = fld (o + t).
|
| 65 |
+
Proof.
|
| 66 |
+
intros al o a x w Hin. cbn [sin sAND] in Hin.
|
| 67 |
+
apply in_map_iff in Hin as (l & El & Hl). apply in_map_iff in Hl as (t & <- & Ht).
|
| 68 |
+
apply in_seq in Ht. unfold lw in El. cbn [fst] in El. injection El as Ex _.
|
| 69 |
+
exists t. split; [lia | symmetry; exact Ex].
|
| 70 |
+
Qed.
|
| 71 |
+
|
| 72 |
+
Lemma in_xs_lits : forall bterm al x w,
|
| 73 |
+
In (x, w) (sin (sOR (map (fun a => (SRef bterm a 0, true)) (seq 0 (W al))))) ->
|
| 74 |
+
exists a, a < W al /\ x = SRef bterm a 0.
|
| 75 |
+
Proof.
|
| 76 |
+
intros bterm al x w Hin. cbn [sin sOR] in Hin.
|
| 77 |
+
apply in_map_iff in Hin as (l & El & Hl). apply in_map_iff in Hl as (a & <- & Ha).
|
| 78 |
+
apply in_seq in Ha. unfold lw in El. cbn [fst] in El. injection El as Ex _.
|
| 79 |
+
exists a. split; [lia | symmetry; exact Ex].
|
| 80 |
+
Qed.
|
| 81 |
+
|
| 82 |
+
Lemma phys_wf : forall al N L, 3 <= al -> recw al <= N -> 1 <= L -> wf (phys_blocks al N L) (nst al N L).
|
| 83 |
Proof.
|
| 84 |
+
intros al N L Hal HN HL. split; [apply phys_shaped|].
|
| 85 |
intros b j r x w Hb Hj Hr Hin. unfold sunit in Hin. rewrite phys_length in Hb.
|
| 86 |
+
pose proof (nwin_W al Hal) as HW. pose proof (W_ge al Hal) as HW8.
|
| 87 |
+
assert (M1 : forall i, (i + recw al) mod N < N) by (intro i; apply Nat.mod_upper_bound; unfold recw in *; lia).
|
| 88 |
+
assert (M2 : forall i, (i + 1) mod N < N) by (intro i; apply Nat.mod_upper_bound; unfold recw in *; lia).
|
| 89 |
assert (M3 : forall i, (i + 1) mod L < L) by (intro i; apply Nat.mod_upper_bound; lia).
|
| 90 |
+
(* blocks 2, 3, 4: the decode lines *)
|
| 91 |
+
assert (Hdec : forall o, o <= 8 + 2 * al -> b <> 0 -> b < 5 ->
|
| 92 |
+
In (x, w) (sin (sAND (map (fun t => (fld (o + t), bitsof al j t)) (seq 0 al)))) ->
|
| 93 |
+
reads_back (phys_blocks al N L) (nst al N L) b j r x).
|
| 94 |
+
{ intros o Ho Hb0 Hb5 Hin'. destruct (in_dec_lits al o j x w Hin') as (t & Ht & ->).
|
| 95 |
+
unfold fld. cbn [reads_back]. left. split; [lia|].
|
| 96 |
+
cbn [nth phys_blocks bcount bsize blk_fld]. unfold recw. split; lia. }
|
| 97 |
+
(* blocks 6 and 8: the operands *)
|
| 98 |
+
assert (Hxs : forall bterm, bterm < b -> bcount (nth bterm (phys_blocks al N L) blk0) = W al ->
|
| 99 |
+
bsize (nth bterm (phys_blocks al N L) blk0) = 1 ->
|
| 100 |
+
In (x, w) (sin (sOR (map (fun a => (SRef bterm a 0, true)) (seq 0 (W al))))) ->
|
| 101 |
+
reads_back (phys_blocks al N L) (nst al N L) b j r x).
|
| 102 |
+
{ intros bterm Hbt Hc Hs Hin'. destruct (in_xs_lits bterm al x w Hin') as (a & Ha & ->).
|
| 103 |
+
cbn [reads_back]. left. rewrite Hc, Hs. lia. }
|
| 104 |
+
destruct (Nat.eq_dec b 2) as [->|N2].
|
| 105 |
+
{ cbn [nth phys_blocks bcount bsize bshape blk_dec] in *. destruct r as [|r]; [|lia].
|
| 106 |
+
apply (Hdec 8); [lia | lia | lia | exact Hin]. }
|
| 107 |
+
destruct (Nat.eq_dec b 3) as [->|N3].
|
| 108 |
+
{ cbn [nth phys_blocks bcount bsize bshape blk_dec] in *. destruct r as [|r]; [|lia].
|
| 109 |
+
apply (Hdec (8 + al)); [lia | lia | lia | exact Hin]. }
|
| 110 |
+
destruct (Nat.eq_dec b 4) as [->|N4].
|
| 111 |
+
{ cbn [nth phys_blocks bcount bsize bshape blk_dec] in *. destruct r as [|r]; [|lia].
|
| 112 |
+
apply (Hdec (8 + 2 * al)); [lia | lia | lia | exact Hin]. }
|
| 113 |
+
destruct (Nat.eq_dec b 6) as [->|N6].
|
| 114 |
+
{ cbn [nth phys_blocks bcount bsize bshape blk_xs] in *. destruct r as [|r]; [|lia].
|
| 115 |
+
apply (Hxs 5); [lia | reflexivity | reflexivity | exact Hin]. }
|
| 116 |
+
destruct (Nat.eq_dec b 8) as [->|N8].
|
| 117 |
+
{ cbn [nth phys_blocks bcount bsize bshape blk_xs] in *. destruct r as [|r]; [|lia].
|
| 118 |
+
apply (Hxs 7); [lia | reflexivity | reflexivity | exact Hin]. }
|
| 119 |
+
clear Hdec Hxs.
|
| 120 |
split_blocks b.
|
| 121 |
+
all: try (exfalso; lia).
|
| 122 |
all: repeat (destruct r as [|r]; [crush_in Hin | try (exfalso; lia)]).
|
| 123 |
all: try lia.
|
| 124 |
all: try rb_solve.
|
rocq/TwoHead.v
CHANGED
|
@@ -121,6 +121,60 @@ Fixpoint iterp (p : positive) (s : st) : st :=
|
|
| 121 |
| xI q => step (iterp q (iterp q s))
|
| 122 |
end.
|
| 123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
(* ---- the code of descriptions ----------------------------------------- *)
|
| 125 |
(* kind 0 AND, 1 OR, 2 COPY; s0, s1 the polarities of the two literals. *)
|
| 126 |
Definition gate_bits (kind : nat) (s0 s1 : bool) : list bool :=
|
|
|
|
| 121 |
| xI q => step (iterp q (iterp q s))
|
| 122 |
end.
|
| 123 |
|
| 124 |
+
(* ---- a window of 2^al cells: records of 8 + 3 al bits ------------------------ *)
|
| 125 |
+
Definition recw (al : nat) : nat := 8 + 3 * al.
|
| 126 |
+
|
| 127 |
+
Definition decodeA (al : nat) (bs : list bool) : rec :=
|
| 128 |
+
let g i := nth i bs false in
|
| 129 |
+
let braw := Z.of_nat (bits2nat (firstn 4 (skipn 4 bs))) in
|
| 130 |
+
Rec (bits2nat (firstn al (skipn 8 bs))) (wcode (g 0%nat) (g 1%nat))
|
| 131 |
+
(bits2nat (firstn al (skipn (8 + al) bs))) (wcode (g 2%nat) (g 3%nat))
|
| 132 |
+
(if Z.leb 8 braw then braw - 16 else braw)%Z
|
| 133 |
+
(bits2nat (firstn al (skipn (8 + 2 * al) bs))).
|
| 134 |
+
|
| 135 |
+
Definition enc_recA (al : nat) (r : rec) : list bool :=
|
| 136 |
+
match r with
|
| 137 |
+
| Rec a0 w0 a1 w1 beta ao =>
|
| 138 |
+
enc_w w0 ++ enc_w w1 ++ nat2bits 4 (Z.to_nat (Z.modulo beta 16))
|
| 139 |
+
++ nat2bits al a0 ++ nat2bits al a1 ++ nat2bits al ao
|
| 140 |
+
end.
|
| 141 |
+
|
| 142 |
+
Definition stepA (al : nat) (s : st) : st :=
|
| 143 |
+
let k := wget (win s) KAPPA in
|
| 144 |
+
let qa := if k then q1 s else q0 s in
|
| 145 |
+
let qi := if k then q0 s else q1 s in
|
| 146 |
+
let da := if k then d1 s else d0 s in
|
| 147 |
+
let di := if k then d0 s else d1 s in
|
| 148 |
+
let (bits, qa') := popn (recw al) qa in
|
| 149 |
+
match decodeA al bits with
|
| 150 |
+
| Rec a0 w0 a1 w1 beta ao =>
|
| 151 |
+
let cell a :=
|
| 152 |
+
if Nat.eqb a RD then hd_t da
|
| 153 |
+
else if Nat.eqb a ARM then hd_t qi
|
| 154 |
+
else if Nat.eqb a CPY then hd_t di
|
| 155 |
+
else wget (win s) a in
|
| 156 |
+
let v := Z.leb 0 (w0 * b2z (cell a0) + w1 * b2z (cell a1) + beta)%Z in
|
| 157 |
+
let wn := if Nat.eqb ao RD || Nat.eqb ao ARM || Nat.eqb ao CPY then win s
|
| 158 |
+
else upd (win s) ao v in
|
| 159 |
+
let qi1 := if Nat.eqb ao ARM then wr_t qi v else qi in
|
| 160 |
+
let di1 := if Nat.eqb ao CPY then wr_t di v else di in
|
| 161 |
+
let qi2 := if wget wn AA then turn1 qi1 else qi1 in
|
| 162 |
+
let da2 := if wget wn AR then turn1 da else da in
|
| 163 |
+
let di2 := if wget wn AC then turn1 di1 else di1 in
|
| 164 |
+
let w2 := upd (upd (upd wn AA false) AR false) AC false in
|
| 165 |
+
if k then mkS w2 qi2 qa' di2 da2 else mkS w2 qa' qi2 da2 di2
|
| 166 |
+
end.
|
| 167 |
+
|
| 168 |
+
(* the machine with 64 cells is the case al = 6 *)
|
| 169 |
+
Lemma stepA_6 : forall s, stepA 6 s = step s.
|
| 170 |
+
Proof. intro s. reflexivity. Qed.
|
| 171 |
+
|
| 172 |
+
Lemma decodeA_6 : forall bs, decodeA 6 bs = decode bs.
|
| 173 |
+
Proof. intro bs. reflexivity. Qed.
|
| 174 |
+
|
| 175 |
+
Lemma enc_recA_6 : forall r, enc_recA 6 r = enc_rec r.
|
| 176 |
+
Proof. intro r. reflexivity. Qed.
|
| 177 |
+
|
| 178 |
(* ---- the code of descriptions ----------------------------------------- *)
|
| 179 |
(* kind 0 AND, 1 OR, 2 COPY; s0, s1 the polarities of the two literals. *)
|
| 180 |
Definition gate_bits (kind : nat) (s0 s1 : bool) : list bool :=
|
rocq/extract/dump.ml
CHANGED
|
@@ -1,14 +1,14 @@
|
|
| 1 |
(* writes the netlist defined in Phys.v, extracted by Extract.v, in the layout of the netlist file of
|
| 2 |
-
src/twohead_net.py: dump N L PATH *)
|
| 3 |
let () =
|
| 4 |
-
let
|
| 5 |
-
let us = Physnet.phys_units n l and nx = Physnet.phys_next n l in
|
| 6 |
-
let oc = open_out_bin Sys.argv.(
|
| 7 |
let put x = (* little-endian int32 *)
|
| 8 |
let b = Bytes.create 4 in
|
| 9 |
Bytes.set_int32_le b 0 (Int32.of_int x); output_bytes oc b in
|
| 10 |
let edges = List.fold_left (fun a (u : Physnet.tu) -> a + List.length u.tin) 0 us in
|
| 11 |
-
put (Physnet.nst n l); put (List.length us); put edges;
|
| 12 |
List.iter (fun (u : Physnet.tu) -> put u.tb) us;
|
| 13 |
List.iter (fun (u : Physnet.tu) -> put (List.length u.tin)) us;
|
| 14 |
List.iter (fun (u : Physnet.tu) -> List.iter (fun (s, wt) -> put (wt * (s + 1))) u.tin) us;
|
|
|
|
| 1 |
(* writes the netlist defined in Phys.v, extracted by Extract.v, in the layout of the netlist file of
|
| 2 |
+
src/twohead_net.py, for a window of 2^AL cells: dump AL N L PATH *)
|
| 3 |
let () =
|
| 4 |
+
let al = int_of_string Sys.argv.(1) and n = int_of_string Sys.argv.(2) and l = int_of_string Sys.argv.(3) in
|
| 5 |
+
let us = Physnet.phys_units al n l and nx = Physnet.phys_next al n l in
|
| 6 |
+
let oc = open_out_bin Sys.argv.(4) in
|
| 7 |
let put x = (* little-endian int32 *)
|
| 8 |
let b = Bytes.create 4 in
|
| 9 |
Bytes.set_int32_le b 0 (Int32.of_int x); output_bytes oc b in
|
| 10 |
let edges = List.fold_left (fun a (u : Physnet.tu) -> a + List.length u.tin) 0 us in
|
| 11 |
+
put (Physnet.nst al n l); put (List.length us); put edges;
|
| 12 |
List.iter (fun (u : Physnet.tu) -> put u.tb) us;
|
| 13 |
List.iter (fun (u : Physnet.tu) -> put (List.length u.tin)) us;
|
| 14 |
List.iter (fun (u : Physnet.tu) -> List.iter (fun (s, wt) -> put (wt * (s + 1))) u.tin) us;
|
src/check_interp.py
DELETED
|
@@ -1,117 +0,0 @@
|
|
| 1 |
-
"""The one-record semantics of the interpreter, on its netlist.
|
| 2 |
-
|
| 3 |
-
For the member U of the paper the netlist, followed by the output clause that
|
| 4 |
-
the runtime applies, is compared with the reference of Definition 9.1 and its
|
| 5 |
-
device; the pointer clause is part of the netlist:
|
| 6 |
-
|
| 7 |
-
fields every weight pair, every bias and both input values of a record
|
| 8 |
-
evaluated at record counter 0, 576 configurations;
|
| 9 |
-
random uniformly random full states, stored records, pointer, PTR_ADV
|
| 10 |
-
and record counter included, with the halt bit clear;
|
| 11 |
-
halted uniformly random states with the halt bit set are fixed points;
|
| 12 |
-
counter the record counter advances modulo G from every value.
|
| 13 |
-
|
| 14 |
-
python src/check_interp.py [--states N] [--device cuda]
|
| 15 |
-
"""
|
| 16 |
-
import argparse
|
| 17 |
-
import json
|
| 18 |
-
import os
|
| 19 |
-
import sys
|
| 20 |
-
import time
|
| 21 |
-
|
| 22 |
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 23 |
-
import torch
|
| 24 |
-
from reflect import (Cfg, SparseLeveled, apply_output, build_net, encode_netlist,
|
| 25 |
-
ref_step, state_to_vec, vec_to_state)
|
| 26 |
-
|
| 27 |
-
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
def runs_path(name: str) -> str:
|
| 31 |
-
d = os.path.join(REPO, "paper", "runs")
|
| 32 |
-
os.makedirs(d, exist_ok=True)
|
| 33 |
-
return os.path.join(d, name)
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
def check_member(cfg, n_states, device, seed):
|
| 37 |
-
t0 = time.perf_counter()
|
| 38 |
-
net, inputs, outputs = build_net(cfg)
|
| 39 |
-
lev = SparseLeveled(net, inputs, outputs, device=device)
|
| 40 |
-
res = {"A": cfg.A, "S": cfg.S, "G": cfg.G, "banks": cfg.banks,
|
| 41 |
-
"units": len(net.gates)}
|
| 42 |
-
|
| 43 |
-
def compare(states):
|
| 44 |
-
X = torch.stack([state_to_vec(cfg, st) for st in states]).to(device)
|
| 45 |
-
Y = lev.step(X).cpu()
|
| 46 |
-
bad = 0
|
| 47 |
-
for st, y in zip(states, Y):
|
| 48 |
-
e = ref_step(cfg, st)
|
| 49 |
-
g = vec_to_state(cfg, y)
|
| 50 |
-
if st["halt"] == 0: # the output clause, applied by the runtime
|
| 51 |
-
apply_output(cfg, g["sig"])
|
| 52 |
-
if (g["sig"], g["gp"], g["halt"]) != (e["sig"], e["gp"], e["halt"]):
|
| 53 |
-
bad += 1
|
| 54 |
-
return bad
|
| 55 |
-
|
| 56 |
-
ra, rb, ro = cfg.WORK_BASE, cfg.WORK_BASE + 1, cfg.WORK_BASE + 2
|
| 57 |
-
states = []
|
| 58 |
-
for w0 in (-1, 0, 1):
|
| 59 |
-
for w1 in (-1, 0, 1):
|
| 60 |
-
for bias in range(-(1 << (cfg.BB - 1)), 1 << (cfg.BB - 1)):
|
| 61 |
-
nl = encode_netlist(cfg, [([(ra, w0, 0), (rb, w1, 0)], bias, (ro, 0))])
|
| 62 |
-
for va in (0, 1):
|
| 63 |
-
for vb in (0, 1):
|
| 64 |
-
sig = [0] * cfg.S
|
| 65 |
-
sig[cfg.NET0:cfg.NET0 + len(nl)] = nl
|
| 66 |
-
sig[ra], sig[rb] = va, vb
|
| 67 |
-
states.append({"sig": sig, "gp": 0, "halt": 0})
|
| 68 |
-
res["fields"] = len(states)
|
| 69 |
-
res["fields_wrong"] = compare(states)
|
| 70 |
-
|
| 71 |
-
gen = torch.Generator().manual_seed(seed)
|
| 72 |
-
wrong = 0
|
| 73 |
-
for lo in range(0, n_states, 256):
|
| 74 |
-
k = min(256, n_states - lo)
|
| 75 |
-
sig = (torch.rand(k, cfg.S, generator=gen) < 0.5).long().tolist()
|
| 76 |
-
gp = torch.randint(0, cfg.G, (k,), generator=gen).tolist()
|
| 77 |
-
wrong += compare([{"sig": s, "gp": g, "halt": 0} for s, g in zip(sig, gp)])
|
| 78 |
-
res["random"] = n_states
|
| 79 |
-
res["random_wrong"] = wrong
|
| 80 |
-
|
| 81 |
-
sig = (torch.rand(256, cfg.S, generator=gen) < 0.5).float()
|
| 82 |
-
gp = torch.randint(0, cfg.G, (256,), generator=gen)
|
| 83 |
-
X = torch.stack([state_to_vec(cfg, {"sig": s.long().tolist(), "gp": int(g), "halt": 1})
|
| 84 |
-
for s, g in zip(sig, gp)]).to(device)
|
| 85 |
-
res["halted_not_fixed"] = int((lev.step(X) != X).any(dim=1).sum())
|
| 86 |
-
|
| 87 |
-
cbad = 0
|
| 88 |
-
for g in range(cfg.G):
|
| 89 |
-
st = {"sig": [0] * cfg.S, "gp": g, "halt": 0}
|
| 90 |
-
y = vec_to_state(cfg, lev.step(state_to_vec(cfg, st).unsqueeze(0).to(device))[0].cpu())
|
| 91 |
-
cbad += y["gp"] != (g + 1) % cfg.G
|
| 92 |
-
res["counter_wrong"] = cbad
|
| 93 |
-
res["ok"] = (res["fields_wrong"] == 0 and wrong == 0 and res["halted_not_fixed"] == 0
|
| 94 |
-
and cbad == 0)
|
| 95 |
-
res["seconds"] = time.perf_counter() - t0
|
| 96 |
-
print(f" A = {cfg.A}, S = {cfg.S}, G = {cfg.G}, {res['units']:,} units: "
|
| 97 |
-
f"{res['fields']} record configurations, {res['fields_wrong']} wrong; "
|
| 98 |
-
f"{n_states:,} random states, {wrong} wrong; halted states fixed: "
|
| 99 |
-
f"{'yes' if res['halted_not_fixed'] == 0 else 'NO'}; counter modulo G: "
|
| 100 |
-
f"{'yes' if cbad == 0 else 'NO'} ({res['seconds']:.0f} s)", flush=True)
|
| 101 |
-
return res
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
def main() -> int:
|
| 105 |
-
ap = argparse.ArgumentParser()
|
| 106 |
-
ap.add_argument("--states", type=int, default=4096)
|
| 107 |
-
ap.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
|
| 108 |
-
args = ap.parse_args()
|
| 109 |
-
out = [check_member(Cfg(), args.states, args.device, 1)]
|
| 110 |
-
ok = all(r["ok"] for r in out)
|
| 111 |
-
json.dump({"members": out, "ok": ok}, open(runs_path("paper_interp.json"), "w"), indent=1)
|
| 112 |
-
print("INTERPRETER:", "PASS" if ok else "FAIL")
|
| 113 |
-
return 0 if ok else 1
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
if __name__ == "__main__":
|
| 117 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/check_lev.py
CHANGED
|
@@ -106,30 +106,13 @@ def main() -> int:
|
|
| 106 |
f"{len(D.W)} layers: {worst:.6f}")
|
| 107 |
print(f" maximum distance of a pre-activation from an integer: {frac:.3e}")
|
| 108 |
|
| 109 |
-
|
| 110 |
-
# Section 9 executes.
|
| 111 |
-
from reflect import Cfg, build_net, Leveled
|
| 112 |
-
cfg = Cfg()
|
| 113 |
-
unet, uin, uout = build_net(cfg)
|
| 114 |
-
UL = Leveled(unet, uin, uout, device="cpu")
|
| 115 |
-
BU = 64
|
| 116 |
-
VU = (torch.rand(BU, len(uin), generator=gen) < 0.5).float()
|
| 117 |
-
udirect = gate_by_gate(unet, uin, uout, VU)
|
| 118 |
-
ulev = UL.step(VU)
|
| 119 |
-
uagree = bool((udirect == ulev).all())
|
| 120 |
-
print(f" interpreter netlist has {len(unet.gates):,} gates on "
|
| 121 |
-
f"{len(uin):,} state bits")
|
| 122 |
-
print(f" gate-by-gate evaluation equals Lev(N_U) on {BU} uniformly random "
|
| 123 |
-
f"states: {'yes' if uagree else 'NO'}")
|
| 124 |
-
|
| 125 |
-
ok = (agree and agree_net and uagree and same_dense and not nonternary
|
| 126 |
and not nonint and abs(worst - 0.5) < 1e-9)
|
| 127 |
json.dump({"states": B, "gates": len(net.gates), "agree": agree,
|
| 128 |
"agree_grouped": agree_net,
|
| 129 |
"dense_agree": same_dense, "nonternary_layers": len(nonternary),
|
| 130 |
"noninteger_bias_layers": len(nonint),
|
| 131 |
-
"min_margin": worst, "max_noninteger": frac,
|
| 132 |
-
"u_states": BU, "u_gates": len(unet.gates), "u_agree": uagree},
|
| 133 |
open(runs_path("paper_lev.json"), "w"), indent=1)
|
| 134 |
return 0 if ok else 1
|
| 135 |
|
|
|
|
| 106 |
f"{len(D.W)} layers: {worst:.6f}")
|
| 107 |
print(f" maximum distance of a pre-activation from an integer: {frac:.3e}")
|
| 108 |
|
| 109 |
+
ok = (agree and agree_net and same_dense and not nonternary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
and not nonint and abs(worst - 0.5) < 1e-9)
|
| 111 |
json.dump({"states": B, "gates": len(net.gates), "agree": agree,
|
| 112 |
"agree_grouped": agree_net,
|
| 113 |
"dense_agree": same_dense, "nonternary_layers": len(nonternary),
|
| 114 |
"noninteger_bias_layers": len(nonint),
|
| 115 |
+
"min_margin": worst, "max_noninteger": frac},
|
|
|
|
| 116 |
open(runs_path("paper_lev.json"), "w"), indent=1)
|
| 117 |
return 0 if ok else 1
|
| 118 |
|
src/fanin2.py
DELETED
|
@@ -1,220 +0,0 @@
|
|
| 1 |
-
"""Bringing a ternary threshold netlist to effective fan-in at most two.
|
| 2 |
-
|
| 3 |
-
The interpreter evaluates records with two input slots, so a netlist it is to
|
| 4 |
-
interpret must have units of fan-in at most two. Every ternary unit is a
|
| 5 |
-
threshold over its literals: H(sum_P x - sum_N x + b) is 1 exactly when at
|
| 6 |
-
least t = |N| - b of the literals x_i (i in P) and not x_i (i in N) are true.
|
| 7 |
-
A disjunction (t = 1) or a conjunction (t = k) of k > 2 literals becomes a
|
| 8 |
-
balanced binary tree of k - 1 two-input units, a literal carried by the sign
|
| 9 |
-
of its weight and never by a unit of its own, so a leaf unit is a conjunction
|
| 10 |
-
or disjunction of two literals and every inner unit one of two signals. Any
|
| 11 |
-
other threshold, which in the host is a majority of three literals or two of
|
| 12 |
-
four, follows the recursion T(t, x_1..x_k) = T(t, x_2..x_k) or (x_1 and
|
| 13 |
-
T(t-1, x_2..x_k)), four units for a majority of three and eight for two of
|
| 14 |
-
four. The rewriting preserves the computed function exactly, which is checked
|
| 15 |
-
against the original netlist on random inputs.
|
| 16 |
-
"""
|
| 17 |
-
from __future__ import annotations
|
| 18 |
-
|
| 19 |
-
import os
|
| 20 |
-
import sys
|
| 21 |
-
from typing import Dict, List, Tuple
|
| 22 |
-
|
| 23 |
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 24 |
-
from matrix8 import Net
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def classify(ins: List[Tuple[str, int]], bias: int) -> str:
|
| 28 |
-
"""Which shape a unit has, by its weights and bias: a disjunction of
|
| 29 |
-
literals, a conjunction of literals, or a threshold of t of its k literals."""
|
| 30 |
-
pos = [s for s, w in ins if w == 1]
|
| 31 |
-
neg = [s for s, w in ins if w == -1]
|
| 32 |
-
if len(pos) + len(neg) != len(ins):
|
| 33 |
-
return "other"
|
| 34 |
-
t = len(neg) - bias
|
| 35 |
-
if t == 1:
|
| 36 |
-
return "or"
|
| 37 |
-
if t == len(ins):
|
| 38 |
-
return "and" # conjunction of literals
|
| 39 |
-
return "threshold"
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def threshold_of(ins: List[Tuple[str, int]], bias: int) -> int:
|
| 43 |
-
"""The number t of true literals the unit requires."""
|
| 44 |
-
return sum(1 for _, w in ins if w == -1) - bias
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
def _tree(net: Net, tag: str, kind: str, items: List[Tuple[str, int]],
|
| 48 |
-
counter: List[int] = None) -> str:
|
| 49 |
-
"""A balanced binary tree of k - 1 two-input units over k literals.
|
| 50 |
-
|
| 51 |
-
`items` are (signal, weight) pairs; weight -1 marks a negated literal,
|
| 52 |
-
which a unit reads with weight -1, so negation costs no unit: a
|
| 53 |
-
disjunction of two literals is H(+-a +-b + |N| - 1) and a conjunction
|
| 54 |
-
H(+-a +-b - |P|). Every unit of the tree outputs a positive signal, so
|
| 55 |
-
the levels above the leaves combine signals.
|
| 56 |
-
"""
|
| 57 |
-
level = list(items)
|
| 58 |
-
counter = counter if counter is not None else [0]
|
| 59 |
-
while len(level) > 1:
|
| 60 |
-
nxt = []
|
| 61 |
-
for i in range(0, len(level) - 1, 2):
|
| 62 |
-
(a, wa), (b, wb) = level[i], level[i + 1]
|
| 63 |
-
name = f"{tag}#{kind}{counter[0]}"
|
| 64 |
-
counter[0] += 1
|
| 65 |
-
pos = (wa == 1) + (wb == 1)
|
| 66 |
-
if kind == "or":
|
| 67 |
-
nxt.append((net.g(name, [(a, wa), (b, wb)], (2 - pos) - 1), 1))
|
| 68 |
-
else:
|
| 69 |
-
nxt.append((net.g(name, [(a, wa), (b, wb)], -pos), 1))
|
| 70 |
-
if len(level) % 2:
|
| 71 |
-
nxt.append(level[-1])
|
| 72 |
-
level = nxt
|
| 73 |
-
s, w = level[0]
|
| 74 |
-
if w != 1: # a single negated literal: one unit
|
| 75 |
-
name = f"{tag}#{kind}{counter[0]}"
|
| 76 |
-
counter[0] += 1
|
| 77 |
-
return net.g(name, [(s, -1)], 0)
|
| 78 |
-
return s
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
def _thresh(net: Net, tag: str, t: int, items: List[Tuple[str, int]],
|
| 82 |
-
counter: List[int]) -> Tuple[str, int]:
|
| 83 |
-
"""t of the k literals, by T(t, x_1..x_k) = T(t, rest) or (x_1 and T(t-1, rest)).
|
| 84 |
-
|
| 85 |
-
Returns a (signal, weight) pair: a positive signal, or a constant."""
|
| 86 |
-
k = len(items)
|
| 87 |
-
if t <= 0:
|
| 88 |
-
return ("#1", 1)
|
| 89 |
-
if t > k:
|
| 90 |
-
return ("#0", 1)
|
| 91 |
-
if k == 1:
|
| 92 |
-
return items[0]
|
| 93 |
-
if t == 1:
|
| 94 |
-
return (_tree(net, tag, "or", items, counter), 1)
|
| 95 |
-
if t == k:
|
| 96 |
-
return (_tree(net, tag, "and", items, counter), 1)
|
| 97 |
-
x, rest = items[0], items[1:]
|
| 98 |
-
a = _thresh(net, tag, t, rest, counter)
|
| 99 |
-
b = _thresh(net, tag, t - 1, rest, counter)
|
| 100 |
-
name = f"{tag}#and{counter[0]}"
|
| 101 |
-
counter[0] += 1
|
| 102 |
-
c = (net.g(name, [x, b], -((x[1] == 1) + 1)), 1)
|
| 103 |
-
name = f"{tag}#or{counter[0]}"
|
| 104 |
-
counter[0] += 1
|
| 105 |
-
return (net.g(name, [a, c], -1), 1)
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
def expand(net: Net, inputs: List[str], outputs: List[str]
|
| 109 |
-
) -> Tuple[Net, List[str], List[str]]:
|
| 110 |
-
"""An equivalent netlist whose units have effective fan-in at most two."""
|
| 111 |
-
out = Net()
|
| 112 |
-
sub: Dict[str, str] = {s: s for s in inputs}
|
| 113 |
-
sub["#0"] = "#0"
|
| 114 |
-
sub["#1"] = "#1"
|
| 115 |
-
|
| 116 |
-
gates = net.gates
|
| 117 |
-
indeg, cons = {}, {}
|
| 118 |
-
for g, (ins, _) in gates.items():
|
| 119 |
-
indeg[g] = len([s for s, _ in ins if s in gates])
|
| 120 |
-
for s, _ in ins:
|
| 121 |
-
cons.setdefault(s, []).append(g)
|
| 122 |
-
order = [g for g, d in indeg.items() if d == 0]
|
| 123 |
-
i = 0
|
| 124 |
-
while i < len(order):
|
| 125 |
-
for c in cons.get(order[i], []):
|
| 126 |
-
indeg[c] -= 1
|
| 127 |
-
if indeg[c] == 0:
|
| 128 |
-
order.append(c)
|
| 129 |
-
i += 1
|
| 130 |
-
if len(order) != len(gates):
|
| 131 |
-
raise ValueError("cycle")
|
| 132 |
-
|
| 133 |
-
for g in order:
|
| 134 |
-
ins, bias = gates[g]
|
| 135 |
-
kind = classify(ins, bias)
|
| 136 |
-
src = [(sub[s], w) for s, w in ins]
|
| 137 |
-
if len(src) <= 2: # already within the slot budget
|
| 138 |
-
sub[g] = out.g(g, src, bias)
|
| 139 |
-
continue
|
| 140 |
-
if kind in ("or", "and"):
|
| 141 |
-
sub[g] = _tree(out, g, kind, src)
|
| 142 |
-
elif kind == "threshold":
|
| 143 |
-
assert len(src) <= 6, f"unit {g}: a threshold of {len(src)} literals"
|
| 144 |
-
sig, w = _thresh(out, g, threshold_of(ins, bias), src, [0])
|
| 145 |
-
assert w == 1
|
| 146 |
-
sub[g] = sig
|
| 147 |
-
else:
|
| 148 |
-
raise ValueError(f"unit {g} carries a weight outside {{-1, 0, 1}}: "
|
| 149 |
-
f"{src[:4]} bias {bias}")
|
| 150 |
-
return out, list(inputs), [sub[s] for s in outputs]
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
def check(net, inputs, outputs, trials: int = 64, seed: int = 5) -> bool:
|
| 154 |
-
"""The expansion computes the same function as the original netlist."""
|
| 155 |
-
import torch
|
| 156 |
-
from check_lev import gate_by_gate
|
| 157 |
-
two, tin, tout = expand(net, inputs, outputs)
|
| 158 |
-
fan = max(len(ins) for ins, _ in two.gates.values())
|
| 159 |
-
assert fan <= 2, fan
|
| 160 |
-
gen = torch.Generator().manual_seed(seed)
|
| 161 |
-
V = (torch.rand(trials, len(inputs), generator=gen) < 0.5).float()
|
| 162 |
-
a = gate_by_gate(net, inputs, outputs, V)
|
| 163 |
-
b = gate_by_gate(two, tin, tout, V)
|
| 164 |
-
return bool((a == b).all())
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
def main() -> int:
|
| 168 |
-
"""The rewriting on the host and the interpreter, and on every ternary unit
|
| 169 |
-
of three to five inputs with every bias, against the truth tables."""
|
| 170 |
-
import itertools
|
| 171 |
-
import json
|
| 172 |
-
import time
|
| 173 |
-
import torch
|
| 174 |
-
from check_lev import gate_by_gate
|
| 175 |
-
from host_family import build
|
| 176 |
-
from reflect import Cfg, build_net
|
| 177 |
-
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 178 |
-
t0 = time.perf_counter()
|
| 179 |
-
tot = bad = 0
|
| 180 |
-
for k in (3, 4, 5):
|
| 181 |
-
names = [f"i{j}" for j in range(k)]
|
| 182 |
-
V = torch.tensor(list(itertools.product((0.0, 1.0), repeat=k)))
|
| 183 |
-
for signs in itertools.product((1, -1), repeat=k):
|
| 184 |
-
for bias in range(-k - 1, k + 2):
|
| 185 |
-
n1 = Net()
|
| 186 |
-
n1.g("u", [(names[j], signs[j]) for j in range(k)], bias)
|
| 187 |
-
e, _, o = expand(n1, names, ["u"])
|
| 188 |
-
a = gate_by_gate(n1, names, ["u"], V)
|
| 189 |
-
if o[0] in ("#0", "#1"):
|
| 190 |
-
b = torch.full_like(a, 1.0 if o[0] == "#1" else 0.0)
|
| 191 |
-
else:
|
| 192 |
-
b = gate_by_gate(e, names, o, V)
|
| 193 |
-
tot += 1
|
| 194 |
-
bad += not bool((a == b).all())
|
| 195 |
-
print(f" every ternary unit of 3 to 5 inputs with every bias, {tot} units, against "
|
| 196 |
-
f"its truth table: {'all exact' if bad == 0 else f'{bad} FAILED'}")
|
| 197 |
-
rec = {"small_units": tot, "small_unit_failures": bad, "netlists": {}}
|
| 198 |
-
for label, (net, inp, out) in (("N_host", build(8)), ("N_U", build_net(Cfg()))):
|
| 199 |
-
two, _, _ = expand(net, inp, out)
|
| 200 |
-
ok = check(net, inp, out, trials=32)
|
| 201 |
-
shapes = {}
|
| 202 |
-
for ins, b in net.gates.values():
|
| 203 |
-
if len(ins) > 2:
|
| 204 |
-
shapes[classify(ins, b)] = shapes.get(classify(ins, b), 0) + 1
|
| 205 |
-
rec["netlists"][label] = {"units": len(net.gates), "units_fanin2": len(two.gates),
|
| 206 |
-
"shapes_above_two": shapes, "agrees_on_random_inputs": ok}
|
| 207 |
-
bad += not ok
|
| 208 |
-
print(f" {label}: {len(net.gates):,} units become {len(two.gates):,}; shapes above "
|
| 209 |
-
f"fan-in two {shapes}; agrees with the original on 32 random states: {ok}")
|
| 210 |
-
rec["seconds"] = time.perf_counter() - t0
|
| 211 |
-
rec["ok"] = bad == 0
|
| 212 |
-
d = os.path.join(REPO, "paper", "runs")
|
| 213 |
-
os.makedirs(d, exist_ok=True)
|
| 214 |
-
json.dump(rec, open(os.path.join(d, "paper_fanin2.json"), "w"), indent=1)
|
| 215 |
-
print("FAN-IN TWO:", "PASS" if bad == 0 else "FAIL")
|
| 216 |
-
return 0 if bad == 0 else 1
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
if __name__ == "__main__":
|
| 220 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/hierarchy.py
DELETED
|
@@ -1,148 +0,0 @@
|
|
| 1 |
-
"""The interpreters form a hierarchy: a larger one runs a smaller one.
|
| 2 |
-
|
| 3 |
-
The size proposition rules out U interpreting a netlist realizing itself. It
|
| 4 |
-
does not rule out one member of the family running another, and that is what
|
| 5 |
-
is established here. Writing U_S for the interpreter on S signals, a netlist
|
| 6 |
-
realizing U_S is brought to effective fan-in two and laid out as records of
|
| 7 |
-
U_{S'} in topological order, followed by one record per state coordinate that
|
| 8 |
-
copies the next value back onto the coordinate. One pass of U_{S'} is then one
|
| 9 |
-
transition of U_S carried out in place, and k passes are k transitions: the
|
| 10 |
-
larger interpreter runs the smaller one, stored netlist and all, on every
|
| 11 |
-
state tested.
|
| 12 |
-
|
| 13 |
-
python src/hierarchy.py [--transitions K] [--device cuda]
|
| 14 |
-
"""
|
| 15 |
-
import argparse
|
| 16 |
-
import json
|
| 17 |
-
import os
|
| 18 |
-
import sys
|
| 19 |
-
import time
|
| 20 |
-
|
| 21 |
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 22 |
-
import torch
|
| 23 |
-
from fanin2 import expand
|
| 24 |
-
from reflect import (Cfg, Leveled, SparseLeveled, build_net, compile_to_reflect,
|
| 25 |
-
encode_netlist, state_to_vec)
|
| 26 |
-
|
| 27 |
-
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 28 |
-
|
| 29 |
-
SMALL = dict(A=7, G=3, banks=1, self_mod=False)
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
def runs_path(name: str) -> str:
|
| 33 |
-
d = os.path.join(REPO, "paper", "runs")
|
| 34 |
-
os.makedirs(d, exist_ok=True)
|
| 35 |
-
return os.path.join(d, name)
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
def host_config(n2: int, signals: int, slack: int = 64):
|
| 39 |
-
"""The smallest A' whose interpreter has room for n2 records and the
|
| 40 |
-
signals of the interpreted netlist, with G' chosen to make the addressed
|
| 41 |
-
span as small as the layout allows."""
|
| 42 |
-
for Ap in range(8, 28):
|
| 43 |
-
Sp = 1 << Ap
|
| 44 |
-
Rp = 3 * Ap + 11
|
| 45 |
-
Gp = (Sp - signals - slack) // Rp
|
| 46 |
-
if Gp >= n2:
|
| 47 |
-
return Cfg(A=Ap, G=Gp, banks=1, self_mod=False)
|
| 48 |
-
raise ValueError("no configuration is large enough")
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
def main() -> int:
|
| 52 |
-
ap = argparse.ArgumentParser()
|
| 53 |
-
ap.add_argument("--transitions", type=int, default=4)
|
| 54 |
-
ap.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
|
| 55 |
-
args = ap.parse_args()
|
| 56 |
-
t_start = time.perf_counter()
|
| 57 |
-
small = Cfg(**SMALL)
|
| 58 |
-
net, inputs, outputs = build_net(small)
|
| 59 |
-
two, tin, tout = expand(net, inputs, outputs)
|
| 60 |
-
n2 = len(two.gates)
|
| 61 |
-
signals = len(inputs) + n2
|
| 62 |
-
# coordinates whose next value is a different signal need a copy record;
|
| 63 |
-
# a coordinate the netlist passes through unchanged needs none
|
| 64 |
-
moved = [(s, t) for s, t in zip(inputs, tout) if t != s]
|
| 65 |
-
assert all(t in two.gates for _, t in moved), "a next value is another input"
|
| 66 |
-
print(f" U_S: S = {small.S}, G = {small.G}, {len(net.gates):,} units; "
|
| 67 |
-
f"at fan-in two {n2:,} units on {signals:,} signals; "
|
| 68 |
-
f"{len(moved)} of {len(inputs)} coordinates change", flush=True)
|
| 69 |
-
|
| 70 |
-
big = host_config(n2 + len(moved), signals)
|
| 71 |
-
print(f" U_S': S' = {big.S}, G' = {big.G}, b' = {big.R}, addressed span "
|
| 72 |
-
f"{big.span}; a record region of {big.G * big.R:,} bits", flush=True)
|
| 73 |
-
|
| 74 |
-
base = big.WORK_BASE
|
| 75 |
-
in_addr = {s: base + i for i, s in enumerate(inputs)}
|
| 76 |
-
rg, addr, top = compile_to_reflect(big, two, in_addr, tout,
|
| 77 |
-
base + len(inputs))
|
| 78 |
-
assert len(rg) == n2
|
| 79 |
-
assert top <= big.span, (top, big.span)
|
| 80 |
-
copies = [([(addr[t], 1, 0)], -1, (in_addr[s], 0)) for s, t in moved]
|
| 81 |
-
rg = rg + copies
|
| 82 |
-
assert len(rg) <= big.G
|
| 83 |
-
print(f" compiled to {n2:,} records and {len(copies)} copy records; "
|
| 84 |
-
f"highest signal used {top}, span {big.span}", flush=True)
|
| 85 |
-
|
| 86 |
-
t0 = time.perf_counter()
|
| 87 |
-
bnet, bin_, bout = build_net(big)
|
| 88 |
-
print(f" U_S' netlist: {len(bnet.gates):,} units "
|
| 89 |
-
f"({time.perf_counter() - t0:.0f}s)", flush=True)
|
| 90 |
-
t0 = time.perf_counter()
|
| 91 |
-
lev = SparseLeveled(bnet, bin_, bout, device=args.device)
|
| 92 |
-
print(f" levelized into {len(lev.plan)} layers "
|
| 93 |
-
f"({time.perf_counter() - t0:.0f}s)", flush=True)
|
| 94 |
-
|
| 95 |
-
nl = encode_netlist(big, rg)
|
| 96 |
-
sig0 = [0] * big.S
|
| 97 |
-
sig0[big.NET0:big.NET0 + len(nl)] = nl
|
| 98 |
-
base_vec = state_to_vec(big, {"sig": sig0, "gp": 0, "halt": 0})
|
| 99 |
-
|
| 100 |
-
# The states of U_S: random signal vectors, stored records included, a
|
| 101 |
-
# random record counter, and the halt bit clear.
|
| 102 |
-
B = 48
|
| 103 |
-
gen = torch.Generator().manual_seed(20260910)
|
| 104 |
-
small_lev = Leveled(net, inputs, outputs, device="cpu")
|
| 105 |
-
V = (torch.rand(B, len(inputs), generator=gen) < 0.5).float()
|
| 106 |
-
V[:, small.S + small.GPW] = 0.0 # halt bit clear
|
| 107 |
-
V[:, :small.S][:, small.HALT_SIG] = 0.0 # and the halt signal
|
| 108 |
-
X = base_vec.unsqueeze(0).repeat(B, 1)
|
| 109 |
-
for i, s in enumerate(inputs):
|
| 110 |
-
X[:, in_addr[s]] = V[:, i]
|
| 111 |
-
X = X.to(args.device)
|
| 112 |
-
in_idx = torch.tensor([in_addr[s] for s in inputs], device=args.device)
|
| 113 |
-
t0 = time.perf_counter()
|
| 114 |
-
exact = True
|
| 115 |
-
wrong = 0
|
| 116 |
-
per = []
|
| 117 |
-
for k in range(args.transitions):
|
| 118 |
-
V = small_lev.step(V)
|
| 119 |
-
for _ in range(big.G):
|
| 120 |
-
X = lev.step(X)
|
| 121 |
-
got = X[:, in_idx].cpu()
|
| 122 |
-
w = int((got != V).sum())
|
| 123 |
-
per.append(w)
|
| 124 |
-
wrong += w
|
| 125 |
-
exact &= w == 0
|
| 126 |
-
print(f" transition {k + 1}: U_S' state after {k + 1} passes "
|
| 127 |
-
f"{'equals' if w == 0 else 'DIFFERS FROM'} U_S after {k + 1} "
|
| 128 |
-
f"transitions on {B} random states "
|
| 129 |
-
f"({(time.perf_counter() - t0) / 60:.1f} min)", flush=True)
|
| 130 |
-
dt = time.perf_counter() - t0
|
| 131 |
-
out = {"small": {"S": small.S, "G": small.G, "units": len(net.gates),
|
| 132 |
-
"units_fanin2": n2, "signals": signals,
|
| 133 |
-
"state_bits": len(inputs)},
|
| 134 |
-
"big": {"S": big.S, "G": big.G, "b": big.R, "span": big.span,
|
| 135 |
-
"units": len(bnet.gates), "layers": len(lev.plan),
|
| 136 |
-
"Q_bits": big.G * big.R},
|
| 137 |
-
"records": len(rg), "copy_records": len(copies), "states": B,
|
| 138 |
-
"pass_steps": big.G, "transitions": args.transitions,
|
| 139 |
-
"mismatches_per_transition": per,
|
| 140 |
-
"exact": exact, "mismatched_coordinates": wrong,
|
| 141 |
-
"seconds": time.perf_counter() - t_start}
|
| 142 |
-
json.dump(out, open(runs_path("paper_hierarchy.json"), "w"), indent=1)
|
| 143 |
-
print("HIERARCHY:", "PASS" if exact else "FAIL")
|
| 144 |
-
return 0 if exact else 1
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
if __name__ == "__main__":
|
| 148 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/hosted_constructor.py
DELETED
|
@@ -1,653 +0,0 @@
|
|
| 1 |
-
"""The universal constructor as a netlist stored in the interpreter's state.
|
| 2 |
-
|
| 3 |
-
Section 9 of the paper interprets stored netlists; this module stores the
|
| 4 |
-
paper's own construction. A microprogram of records implements the SUBLEQ
|
| 5 |
-
transducer of Definitions 2.8 and 3.1 over a 128-byte memory, with the tape,
|
| 6 |
-
the output word, the head and the write pointer all held in signals of the
|
| 7 |
-
interpreter, and runs the constructor P on a recipe. One pass of the record
|
| 8 |
-
region is one SUBLEQ step: fetch, subtract, write back, apply the device,
|
| 9 |
-
branch. Nothing outside U takes part, not even U's own output device.
|
| 10 |
-
|
| 11 |
-
The program is P with its variable and device cells moved from the top of a
|
| 12 |
-
256-byte memory to the top of a 128-byte one, which is the same program: every
|
| 13 |
-
address it names is a datum, and the branch targets are unchanged.
|
| 14 |
-
|
| 15 |
-
python src/hosted_constructor.py [--target-bytes N]
|
| 16 |
-
"""
|
| 17 |
-
from __future__ import annotations
|
| 18 |
-
|
| 19 |
-
import argparse
|
| 20 |
-
import json
|
| 21 |
-
import os
|
| 22 |
-
import sys
|
| 23 |
-
import time
|
| 24 |
-
from typing import Dict, List, Tuple
|
| 25 |
-
|
| 26 |
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 27 |
-
import torch
|
| 28 |
-
from reflect import (Cfg, Leveled, SparseLeveled, build_net, encode_netlist,
|
| 29 |
-
state_to_vec, to_bits)
|
| 30 |
-
from selfrep import P, describe, decode
|
| 31 |
-
|
| 32 |
-
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 33 |
-
|
| 34 |
-
MEM_BYTES = 128
|
| 35 |
-
ADDR = 7 # address bits of the hosted machine
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
def remap(x: int) -> int:
|
| 39 |
-
"""Move a cell of the 256-byte memory to the same offset from the top of a
|
| 40 |
-
128-byte one."""
|
| 41 |
-
return x - 0x80 if x >= 0xF0 else x
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
P128 = [(remap(a), remap(b), remap(c)) for a, b, c in P]
|
| 45 |
-
Z, ONE, T1, T2, NEG1, EOK = 0x70, 0x71, 0x72, 0x73, 0x74, 0x75
|
| 46 |
-
C_WR, C_EOT, C_RW, C_RD, R_IN, R_OUT = 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E
|
| 47 |
-
HALT_PC = 0x7F
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
def image128() -> List[int]:
|
| 51 |
-
mem = [0] * MEM_BYTES
|
| 52 |
-
for idx, (a, b, c) in enumerate(P128):
|
| 53 |
-
mem[idx * 3] = a
|
| 54 |
-
mem[idx * 3 + 1] = b
|
| 55 |
-
mem[idx * 3 + 2] = c
|
| 56 |
-
mem[ONE] = 1
|
| 57 |
-
mem[NEG1] = 0xFF
|
| 58 |
-
mem[EOK] = 1
|
| 59 |
-
return mem
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
def reference128(mem0: List[int], tape: bytes, max_steps: int = 1 << 22):
|
| 63 |
-
"""The transducer of Definitions 2.8 and 3.1 on a 128-byte memory."""
|
| 64 |
-
mem = list(mem0)
|
| 65 |
-
out = bytearray()
|
| 66 |
-
h = 0
|
| 67 |
-
pc = 0
|
| 68 |
-
n = 0
|
| 69 |
-
while pc != HALT_PC and n < max_steps:
|
| 70 |
-
A = mem[pc % MEM_BYTES]
|
| 71 |
-
B = mem[(pc + 1) % MEM_BYTES]
|
| 72 |
-
C = mem[(pc + 2) % MEM_BYTES]
|
| 73 |
-
r = (mem[B % MEM_BYTES] - mem[A % MEM_BYTES]) & 0xFF
|
| 74 |
-
mem[B % MEM_BYTES] = r
|
| 75 |
-
pc = C % MEM_BYTES if (r == 0 or r >= 0x80) else (pc + 3) % MEM_BYTES
|
| 76 |
-
if mem[C_WR] == 1:
|
| 77 |
-
out.append(mem[R_OUT])
|
| 78 |
-
mem[R_OUT] = 0
|
| 79 |
-
if mem[C_RD] == 1:
|
| 80 |
-
if h < len(tape):
|
| 81 |
-
mem[R_IN] = tape[h]
|
| 82 |
-
mem[C_EOT] = 0
|
| 83 |
-
h += 1
|
| 84 |
-
else:
|
| 85 |
-
mem[C_EOT] = 1
|
| 86 |
-
if mem[C_RW] == 1:
|
| 87 |
-
h = 0
|
| 88 |
-
mem[C_WR] = mem[C_RD] = mem[C_RW] = 0
|
| 89 |
-
n += 1
|
| 90 |
-
return bytes(out), n, mem, h
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
# =============================================================================
|
| 94 |
-
# the microprogram
|
| 95 |
-
# =============================================================================
|
| 96 |
-
|
| 97 |
-
class Micro:
|
| 98 |
-
"""Records, with work signals allocated as they are named."""
|
| 99 |
-
|
| 100 |
-
def __init__(self, cfg, work_base: int, work_max: int):
|
| 101 |
-
self.cfg = cfg
|
| 102 |
-
self.recs: List[Tuple[List[Tuple[int, int, int]], int, Tuple[int, int]]] = []
|
| 103 |
-
self.next = work_base
|
| 104 |
-
self.limit = work_base + work_max
|
| 105 |
-
self.named: Dict[str, int] = {}
|
| 106 |
-
|
| 107 |
-
def sig(self, name: str = None) -> int:
|
| 108 |
-
s = self.next
|
| 109 |
-
self.next += 1
|
| 110 |
-
if self.next > self.limit:
|
| 111 |
-
raise ValueError("work signals exhausted")
|
| 112 |
-
if name:
|
| 113 |
-
self.named[name] = s
|
| 114 |
-
return s
|
| 115 |
-
|
| 116 |
-
def reg(self, name: str, width: int) -> List[int]:
|
| 117 |
-
r = [self.sig() for _ in range(width)]
|
| 118 |
-
self.named[name] = r[0]
|
| 119 |
-
return r
|
| 120 |
-
|
| 121 |
-
def emit(self, slots, bias, out):
|
| 122 |
-
self.recs.append((slots, bias, out))
|
| 123 |
-
|
| 124 |
-
# --- one-record primitives ------------------------------------------
|
| 125 |
-
def const(self, dst, v):
|
| 126 |
-
self.emit([], 0 if v else -1, (dst, 0))
|
| 127 |
-
|
| 128 |
-
def copy(self, dst, src):
|
| 129 |
-
self.emit([(src, 1, 0)], -1, (dst, 0))
|
| 130 |
-
|
| 131 |
-
def not_(self, dst, src):
|
| 132 |
-
self.emit([(src, -1, 0)], 0, (dst, 0))
|
| 133 |
-
|
| 134 |
-
def and2(self, dst, a, b, na=False, nb=False):
|
| 135 |
-
wa, wb = (-1 if na else 1), (-1 if nb else 1)
|
| 136 |
-
bias = -((0 if na else 1) + (0 if nb else 1))
|
| 137 |
-
self.emit([(a, wa, 0), (b, wb, 0)], bias, (dst, 0))
|
| 138 |
-
|
| 139 |
-
def or2(self, dst, a, b):
|
| 140 |
-
self.emit([(a, 1, 0), (b, 1, 0)], -1, (dst, 0))
|
| 141 |
-
|
| 142 |
-
def read_idx(self, dst, base):
|
| 143 |
-
"""dst <- sig[base + PTR]."""
|
| 144 |
-
self.emit([(base, 1, 1)], -1, (dst, 0))
|
| 145 |
-
|
| 146 |
-
def write_idx(self, base, src):
|
| 147 |
-
"""sig[base + PTR] <- src."""
|
| 148 |
-
self.emit([(src, 1, 0)], -1, (base, 1))
|
| 149 |
-
|
| 150 |
-
def write_idx_and(self, base, src, gate, ngate=False):
|
| 151 |
-
"""sig[base + PTR] <- src AND gate (or src AND NOT gate)."""
|
| 152 |
-
wg = -1 if ngate else 1
|
| 153 |
-
bias = -1 if ngate else -2
|
| 154 |
-
self.emit([(src, 1, 0), (gate, wg, 0)], bias, (base, 1))
|
| 155 |
-
|
| 156 |
-
# --- small cells ------------------------------------------------------
|
| 157 |
-
def xor(self, dst, a, b):
|
| 158 |
-
t1, t2 = self.sig(), self.sig()
|
| 159 |
-
self.or2(t1, a, b)
|
| 160 |
-
self.emit([(a, -1, 0), (b, -1, 0)], 1, (t2, 0)) # NAND
|
| 161 |
-
self.and2(dst, t1, t2)
|
| 162 |
-
|
| 163 |
-
def mux(self, dst, sel, x1, x0):
|
| 164 |
-
ns, a1, a0 = self.sig(), self.sig(), self.sig()
|
| 165 |
-
self.not_(ns, sel)
|
| 166 |
-
self.and2(a1, x1, sel)
|
| 167 |
-
self.and2(a0, x0, ns)
|
| 168 |
-
self.or2(dst, a1, a0)
|
| 169 |
-
|
| 170 |
-
def and_lits(self, dst, lits):
|
| 171 |
-
"""dst <- conjunction of literals (signal, want) via a binary tree."""
|
| 172 |
-
level = []
|
| 173 |
-
i = 0
|
| 174 |
-
while i < len(lits):
|
| 175 |
-
if i + 1 < len(lits):
|
| 176 |
-
(sa, wa), (sb, wb) = lits[i], lits[i + 1]
|
| 177 |
-
t = self.sig()
|
| 178 |
-
self.and2(t, sa, sb, na=not wa, nb=not wb)
|
| 179 |
-
level.append(t)
|
| 180 |
-
i += 2
|
| 181 |
-
else:
|
| 182 |
-
sa, wa = lits[i]
|
| 183 |
-
t = self.sig()
|
| 184 |
-
if wa:
|
| 185 |
-
self.copy(t, sa)
|
| 186 |
-
else:
|
| 187 |
-
self.not_(t, sa)
|
| 188 |
-
level.append(t)
|
| 189 |
-
i += 1
|
| 190 |
-
while len(level) > 1:
|
| 191 |
-
nxt = []
|
| 192 |
-
for j in range(0, len(level) - 1, 2):
|
| 193 |
-
last = len(level) == 2
|
| 194 |
-
t = dst if last else self.sig()
|
| 195 |
-
self.and2(t, level[j], level[j + 1])
|
| 196 |
-
nxt.append(t)
|
| 197 |
-
if len(level) % 2:
|
| 198 |
-
nxt.append(level[-1])
|
| 199 |
-
level = nxt
|
| 200 |
-
if level[0] != dst:
|
| 201 |
-
self.copy(dst, level[0])
|
| 202 |
-
|
| 203 |
-
def incr_gated(self, reg, gate):
|
| 204 |
-
"""reg <- reg + gate, on len(reg) bits, least significant first."""
|
| 205 |
-
carries = [gate]
|
| 206 |
-
for k in range(len(reg) - 1):
|
| 207 |
-
c = self.sig()
|
| 208 |
-
self.and2(c, reg[k], carries[k])
|
| 209 |
-
carries.append(c)
|
| 210 |
-
for k in range(len(reg)):
|
| 211 |
-
self.xor(reg[k], reg[k], carries[k])
|
| 212 |
-
|
| 213 |
-
def add_const(self, dst, src, c):
|
| 214 |
-
"""dst <- src + c on len(src) bits, least significant first."""
|
| 215 |
-
carry = None
|
| 216 |
-
for k in range(len(src)):
|
| 217 |
-
bit = (c >> k) & 1
|
| 218 |
-
if bit and carry is None:
|
| 219 |
-
self.not_(dst[k], src[k])
|
| 220 |
-
carry = src[k]
|
| 221 |
-
elif bit:
|
| 222 |
-
t = self.sig()
|
| 223 |
-
self.xor(t, src[k], carry)
|
| 224 |
-
self.not_(dst[k], t)
|
| 225 |
-
nc = self.sig()
|
| 226 |
-
self.or2(nc, src[k], carry)
|
| 227 |
-
carry = nc
|
| 228 |
-
elif carry is None:
|
| 229 |
-
self.copy(dst[k], src[k])
|
| 230 |
-
else:
|
| 231 |
-
nc = self.sig()
|
| 232 |
-
self.and2(nc, src[k], carry)
|
| 233 |
-
self.xor(dst[k], src[k], carry)
|
| 234 |
-
carry = nc
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
def build_microprogram(cfg, mem_base, tape_base, out_base, tape_len,
|
| 238 |
-
work_base, work_max):
|
| 239 |
-
"""The records implementing one SUBLEQ step with its device."""
|
| 240 |
-
m = Micro(cfg, work_base, work_max)
|
| 241 |
-
PC = m.reg("PC", ADDR) # least significant first
|
| 242 |
-
P1 = m.reg("P1", ADDR)
|
| 243 |
-
P2 = m.reg("P2", ADDR)
|
| 244 |
-
P3 = m.reg("P3", ADDR)
|
| 245 |
-
Ab = m.reg("A", 8)
|
| 246 |
-
Bb = m.reg("B", 8)
|
| 247 |
-
Cb = m.reg("C", 8)
|
| 248 |
-
X = m.reg("X", 8)
|
| 249 |
-
Y = m.reg("Y", 8)
|
| 250 |
-
Rb = m.reg("R", 8)
|
| 251 |
-
NPC = m.reg("NPC", ADDR)
|
| 252 |
-
head = m.reg("head", ADDR)
|
| 253 |
-
wp = m.reg("wp", ADDR)
|
| 254 |
-
|
| 255 |
-
def cell(addr, bit):
|
| 256 |
-
"""The signal holding bit `bit` of memory cell `addr`."""
|
| 257 |
-
return mem_base + bit * MEM_BYTES + addr
|
| 258 |
-
|
| 259 |
-
def ptr_set(src):
|
| 260 |
-
"""PTR <- src, on ADDR bits; the pointer is stored most significant
|
| 261 |
-
first, so bit k of the value is coordinate PTR_BASE + A - 1 - k."""
|
| 262 |
-
for k in range(ADDR):
|
| 263 |
-
m.copy(cfg.PTR_BASE + cfg.A - 1 - k, src[k])
|
| 264 |
-
|
| 265 |
-
# the pointer's high bits stay zero
|
| 266 |
-
for k in range(ADDR, cfg.A):
|
| 267 |
-
m.const(cfg.PTR_BASE + cfg.A - 1 - k, 0)
|
| 268 |
-
|
| 269 |
-
m.add_const(P1, PC, 1)
|
| 270 |
-
m.add_const(P2, PC, 2)
|
| 271 |
-
m.add_const(P3, PC, 3)
|
| 272 |
-
|
| 273 |
-
for reg, src in ((Ab, PC), (Bb, P1), (Cb, P2)):
|
| 274 |
-
ptr_set(src)
|
| 275 |
-
for b in range(8):
|
| 276 |
-
m.read_idx(reg[b], mem_base + b * MEM_BYTES)
|
| 277 |
-
for reg, src in ((X, Ab), (Y, Bb)):
|
| 278 |
-
ptr_set(src[:ADDR])
|
| 279 |
-
for b in range(8):
|
| 280 |
-
m.read_idx(reg[b], mem_base + b * MEM_BYTES)
|
| 281 |
-
|
| 282 |
-
# R = Y - X, and the branch decision
|
| 283 |
-
nx = [m.sig() for _ in range(8)]
|
| 284 |
-
for b in range(8):
|
| 285 |
-
m.not_(nx[b], X[b])
|
| 286 |
-
carry = None
|
| 287 |
-
for b in range(8):
|
| 288 |
-
t = m.sig()
|
| 289 |
-
if carry is None: # carry in is 1
|
| 290 |
-
m.xor(t, Y[b], nx[b])
|
| 291 |
-
m.not_(Rb[b], t)
|
| 292 |
-
c = m.sig()
|
| 293 |
-
m.or2(c, Y[b], nx[b])
|
| 294 |
-
else:
|
| 295 |
-
m.xor(t, Y[b], nx[b])
|
| 296 |
-
m.xor(Rb[b], t, carry)
|
| 297 |
-
c1, c2, c = m.sig(), m.sig(), m.sig()
|
| 298 |
-
m.and2(c1, Y[b], nx[b])
|
| 299 |
-
m.and2(c2, t, carry)
|
| 300 |
-
m.or2(c, c1, c2)
|
| 301 |
-
carry = c
|
| 302 |
-
nz = m.sig()
|
| 303 |
-
tree = Rb[0]
|
| 304 |
-
for b in range(1, 8):
|
| 305 |
-
t = m.sig()
|
| 306 |
-
m.or2(t, tree, Rb[b])
|
| 307 |
-
tree = t
|
| 308 |
-
m.not_(nz, tree)
|
| 309 |
-
leq = m.sig()
|
| 310 |
-
m.or2(leq, Rb[7], nz)
|
| 311 |
-
|
| 312 |
-
# write back to M[B]
|
| 313 |
-
ptr_set(Bb[:ADDR])
|
| 314 |
-
for b in range(8):
|
| 315 |
-
m.write_idx(mem_base + b * MEM_BYTES, Rb[b])
|
| 316 |
-
|
| 317 |
-
# --- the device ------------------------------------------------------
|
| 318 |
-
wr, rd, rw = m.sig(), m.sig(), m.sig()
|
| 319 |
-
m.and_lits(wr, [(cell(C_WR, 0), 1)] + [(cell(C_WR, b), 0) for b in range(1, 8)])
|
| 320 |
-
m.and_lits(rd, [(cell(C_RD, 0), 1)] + [(cell(C_RD, b), 0) for b in range(1, 8)])
|
| 321 |
-
m.and_lits(rw, [(cell(C_RW, 0), 1)] + [(cell(C_RW, b), 0) for b in range(1, 8)])
|
| 322 |
-
|
| 323 |
-
# read: R_IN <- tape[head] when the head is inside the tape
|
| 324 |
-
ateot = m.sig()
|
| 325 |
-
m.and_lits(ateot, [(head[k], (tape_len >> k) & 1) for k in range(ADDR)])
|
| 326 |
-
inrange = m.sig()
|
| 327 |
-
m.not_(inrange, ateot)
|
| 328 |
-
g = m.sig()
|
| 329 |
-
m.and2(g, rd, inrange)
|
| 330 |
-
ptr_set(head)
|
| 331 |
-
tb = [m.sig() for _ in range(8)]
|
| 332 |
-
for b in range(8):
|
| 333 |
-
m.read_idx(tb[b], tape_base + b * tape_len)
|
| 334 |
-
for b in range(8):
|
| 335 |
-
m.mux(cell(R_IN, b), g, tb[b], cell(R_IN, b))
|
| 336 |
-
# end-of-tape status: set by a read at the end, cleared by a read inside
|
| 337 |
-
m.mux(cell(C_EOT, 0), rd, ateot, cell(C_EOT, 0))
|
| 338 |
-
for b in range(1, 8):
|
| 339 |
-
m.and2(cell(C_EOT, b), cell(C_EOT, b), rd, nb=True)
|
| 340 |
-
m.incr_gated(head, g)
|
| 341 |
-
for k in range(ADDR): # rewind sets the head to zero
|
| 342 |
-
m.and2(head[k], head[k], rw, nb=True)
|
| 343 |
-
|
| 344 |
-
# write: append R_OUT to the output word, then clear R_OUT
|
| 345 |
-
ptr_set(wp)
|
| 346 |
-
for b in range(8):
|
| 347 |
-
m.write_idx_and(out_base + b * tape_len, cell(R_OUT, b), wr)
|
| 348 |
-
for b in range(8):
|
| 349 |
-
m.and2(cell(R_OUT, b), cell(R_OUT, b), wr, nb=True)
|
| 350 |
-
m.incr_gated(wp, wr)
|
| 351 |
-
|
| 352 |
-
# the request cells are cleared at the end of every step
|
| 353 |
-
for b in range(8):
|
| 354 |
-
m.const(cell(C_WR, b), 0)
|
| 355 |
-
m.const(cell(C_RD, b), 0)
|
| 356 |
-
m.const(cell(C_RW, b), 0)
|
| 357 |
-
|
| 358 |
-
# --- branch and halt --------------------------------------------------
|
| 359 |
-
for k in range(ADDR):
|
| 360 |
-
m.mux(NPC[k], leq, Cb[k], P3[k])
|
| 361 |
-
m.and_lits(cfg.HALT_SIG, [(NPC[k], (HALT_PC >> k) & 1) for k in range(ADDR)])
|
| 362 |
-
for k in range(ADDR):
|
| 363 |
-
m.copy(PC[k], NPC[k])
|
| 364 |
-
return m
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
def step128(mem, pc, tape, h, out, wp):
|
| 368 |
-
"""One step of the transducer of Definitions 2.8 and 3.1 on a 128-byte
|
| 369 |
-
memory whose tape is the whole tape region: the SUBLEQ instruction, then
|
| 370 |
-
the write, read, rewind and clear clauses of the device."""
|
| 371 |
-
A = mem[pc % MEM_BYTES]
|
| 372 |
-
B = mem[(pc + 1) % MEM_BYTES]
|
| 373 |
-
C = mem[(pc + 2) % MEM_BYTES]
|
| 374 |
-
r = (mem[B % MEM_BYTES] - mem[A % MEM_BYTES]) & 0xFF
|
| 375 |
-
mem[B % MEM_BYTES] = r
|
| 376 |
-
pc = C % MEM_BYTES if (r == 0 or r >= 0x80) else (pc + 3) % MEM_BYTES
|
| 377 |
-
if mem[C_WR] == 1:
|
| 378 |
-
out[wp] = mem[R_OUT]
|
| 379 |
-
wp += 1
|
| 380 |
-
mem[R_OUT] = 0
|
| 381 |
-
if mem[C_RD] == 1:
|
| 382 |
-
if h < len(tape):
|
| 383 |
-
mem[R_IN] = tape[h]
|
| 384 |
-
mem[C_EOT] = 0
|
| 385 |
-
h += 1
|
| 386 |
-
else:
|
| 387 |
-
mem[C_EOT] = 1
|
| 388 |
-
if mem[C_RW] == 1:
|
| 389 |
-
h = 0
|
| 390 |
-
mem[C_WR] = mem[C_RD] = mem[C_RW] = 0
|
| 391 |
-
return pc, h, wp
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
def random_pass_check(cfg, m, nl, mem_base, tape_base, out_base, tape_len,
|
| 395 |
-
n_ref: int, n_net: int, device: str, seed: int = 11):
|
| 396 |
-
"""One pass of the microprogram against one step of the transducer, from
|
| 397 |
-
random states: random memory, counter, tape, head, write pointer, output
|
| 398 |
-
below the write pointer and scratch registers; the output region above the
|
| 399 |
-
write pointer is clear, as it is along every run."""
|
| 400 |
-
import random as _r
|
| 401 |
-
rng = _r.Random(seed)
|
| 402 |
-
regs = {k: m.named[k] for k in ("PC", "head", "wp")}
|
| 403 |
-
|
| 404 |
-
def make():
|
| 405 |
-
sig = [rng.randint(0, 1) for _ in range(cfg.S)]
|
| 406 |
-
sig[cfg.NET0:cfg.NET0 + len(nl)] = nl
|
| 407 |
-
for c in (cfg.PTR_ADV, cfg.OUT_STROBE, cfg.HALT_SIG, cfg.BANK_SIG):
|
| 408 |
-
sig[c] = 0
|
| 409 |
-
mem = [rng.randrange(256) for _ in range(MEM_BYTES)]
|
| 410 |
-
tape = [rng.randrange(256) for _ in range(tape_len)]
|
| 411 |
-
pc = rng.choice([x for x in range(MEM_BYTES) if x != HALT_PC])
|
| 412 |
-
h = rng.randint(0, tape_len)
|
| 413 |
-
wp = rng.randint(0, tape_len - 2)
|
| 414 |
-
out = [rng.randrange(256) if j < wp else 0 for j in range(tape_len)]
|
| 415 |
-
for j in range(MEM_BYTES):
|
| 416 |
-
for b in range(8):
|
| 417 |
-
sig[mem_base + b * MEM_BYTES + j] = (mem[j] >> b) & 1
|
| 418 |
-
for j in range(tape_len):
|
| 419 |
-
for b in range(8):
|
| 420 |
-
sig[tape_base + b * tape_len + j] = (tape[j] >> b) & 1
|
| 421 |
-
sig[out_base + b * tape_len + j] = (out[j] >> b) & 1
|
| 422 |
-
for name, val in (("PC", pc), ("head", h), ("wp", wp)):
|
| 423 |
-
for k in range(ADDR):
|
| 424 |
-
sig[regs[name] + k] = (val >> k) & 1
|
| 425 |
-
return sig, mem, tape, pc, h, out, wp
|
| 426 |
-
|
| 427 |
-
def expect(mem, tape, pc, h, out, wp):
|
| 428 |
-
mem, out = list(mem), list(out)
|
| 429 |
-
pc, h, wp = step128(mem, pc, tape, h, out, wp)
|
| 430 |
-
return mem, pc, h, out, wp
|
| 431 |
-
|
| 432 |
-
def observe(sig):
|
| 433 |
-
byte = lambda base, stride, j: sum(int(sig[base + b * stride + j]) << b for b in range(8))
|
| 434 |
-
val = lambda name: sum(int(sig[regs[name] + k]) << k for k in range(ADDR))
|
| 435 |
-
return ([byte(mem_base, MEM_BYTES, j) for j in range(MEM_BYTES)], val("PC"),
|
| 436 |
-
val("head"), [byte(out_base, tape_len, j) for j in range(tape_len)],
|
| 437 |
-
val("wp"), int(sig[cfg.HALT_SIG]))
|
| 438 |
-
|
| 439 |
-
def agrees(got, e_mem, e_pc, e_h, e_out, e_wp):
|
| 440 |
-
g_mem, g_pc, g_h, g_out, g_wp, g_halt = got
|
| 441 |
-
if e_pc == HALT_PC:
|
| 442 |
-
# the counter is copied after the halt signal is raised, and the
|
| 443 |
-
# interpreter stops within the copy, so a halting step is judged
|
| 444 |
-
# on everything but the counter
|
| 445 |
-
return (g_mem, g_h, g_out, g_wp, g_halt) == (e_mem, e_h, e_out, e_wp, 1)
|
| 446 |
-
return got == (e_mem, e_pc, e_h, e_out, e_wp, 0)
|
| 447 |
-
|
| 448 |
-
bad_ref = 0
|
| 449 |
-
for _ in range(n_ref):
|
| 450 |
-
sig, mem, tape, pc, h, out, wp = make()
|
| 451 |
-
e = expect(mem, tape, pc, h, out, wp)
|
| 452 |
-
run_records(m.recs, sig, cfg, 1)
|
| 453 |
-
if not agrees(observe(sig), *e):
|
| 454 |
-
bad_ref += 1
|
| 455 |
-
if n_net == 0:
|
| 456 |
-
return bad_ref, 0
|
| 457 |
-
states = [make() for _ in range(n_net)]
|
| 458 |
-
lev = SparseLeveled(*build_net(cfg), device=device)
|
| 459 |
-
X = torch.stack([state_to_vec(cfg, {"sig": st[0], "gp": 0, "halt": 0})
|
| 460 |
-
for st in states]).to(device)
|
| 461 |
-
for _ in range(cfg.G):
|
| 462 |
-
X = lev.step(X)
|
| 463 |
-
X = X.cpu()
|
| 464 |
-
bad_net = 0
|
| 465 |
-
for i, (sig, mem, tape, pc, h, out, wp) in enumerate(states):
|
| 466 |
-
e = expect(mem, tape, pc, h, out, wp)
|
| 467 |
-
if not agrees(observe(X[i].tolist()), *e):
|
| 468 |
-
bad_net += 1
|
| 469 |
-
return bad_ref, bad_net
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
def run_records(recs, sig, cfg, max_passes):
|
| 473 |
-
"""Definition 9.1 applied record by record, in place.
|
| 474 |
-
|
| 475 |
-
Identical in semantics to reflect.ref_gate, and used here so that the
|
| 476 |
-
microprogram can be checked against the reference machine without
|
| 477 |
-
evaluating the interpreter's netlist.
|
| 478 |
-
"""
|
| 479 |
-
S, PB, A = cfg.S, cfg.PTR_BASE, cfg.A
|
| 480 |
-
for p in range(max_passes):
|
| 481 |
-
for slots, bias, (oa, oidx) in recs:
|
| 482 |
-
ptr = 0
|
| 483 |
-
for k in range(A):
|
| 484 |
-
ptr = (ptr << 1) | sig[PB + k]
|
| 485 |
-
acc = bias
|
| 486 |
-
for (a, w, idx) in slots:
|
| 487 |
-
acc += w * sig[(a + (ptr if idx else 0)) & (S - 1)]
|
| 488 |
-
sig[(oa + (ptr if oidx else 0)) & (S - 1)] = 1 if acc >= 0 else 0
|
| 489 |
-
if sig[cfg.HALT_SIG]:
|
| 490 |
-
return p + 1, True
|
| 491 |
-
return max_passes, False
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
def layout(tape_len: int, out_len: int, work_max: int = 700,
|
| 495 |
-
min_records: int = 1):
|
| 496 |
-
"""The smallest configuration with room for the microprogram and the
|
| 497 |
-
regions it addresses."""
|
| 498 |
-
for A in range(12, 22):
|
| 499 |
-
S = 1 << A
|
| 500 |
-
R = 3 * A + 11
|
| 501 |
-
work_base = A + 6
|
| 502 |
-
mem_base = work_base + work_max
|
| 503 |
-
tape_base = mem_base + 8 * MEM_BYTES
|
| 504 |
-
out_base = tape_base + 8 * tape_len
|
| 505 |
-
top = out_base + 8 * out_len
|
| 506 |
-
for G in range((S - top) // R, min_records - 1, -1):
|
| 507 |
-
span = S - G * R
|
| 508 |
-
if span >= top + 8:
|
| 509 |
-
return A, G, span, mem_base, tape_base, out_base, work_base
|
| 510 |
-
raise ValueError("no configuration is large enough")
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
def main() -> int:
|
| 514 |
-
ap = argparse.ArgumentParser()
|
| 515 |
-
ap.add_argument("--target", default="ABCCCCCCCCDE")
|
| 516 |
-
ap.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
|
| 517 |
-
ap.add_argument("--random-states", type=int, default=2000)
|
| 518 |
-
ap.add_argument("--net-states", type=int, default=256)
|
| 519 |
-
args = ap.parse_args()
|
| 520 |
-
|
| 521 |
-
target = args.target.encode()
|
| 522 |
-
tape = describe(target)
|
| 523 |
-
assert decode(tape) == target
|
| 524 |
-
tape_len = out_len = 64
|
| 525 |
-
assert len(tape) < tape_len and len(target) < out_len
|
| 526 |
-
|
| 527 |
-
A, G, span, mem_base, tape_base, out_base, work_base = layout(
|
| 528 |
-
tape_len, out_len, min_records=520)
|
| 529 |
-
cfg = Cfg(A=A, G=G, banks=1, self_mod=False)
|
| 530 |
-
assert cfg.span == span, (cfg.span, span)
|
| 531 |
-
m = build_microprogram(cfg, mem_base, tape_base, out_base, tape_len,
|
| 532 |
-
work_base, 700)
|
| 533 |
-
n = len(m.recs)
|
| 534 |
-
assert n <= G, (n, G)
|
| 535 |
-
print(f" hosted machine: SUBLEQ over {MEM_BYTES} bytes with the tape, the "
|
| 536 |
-
f"output word, the head and the write pointer in signals", flush=True)
|
| 537 |
-
print(f" microprogram: {n} records; interpreter U_S': S = {cfg.S}, "
|
| 538 |
-
f"G = {cfg.G}, b = {cfg.R}, addressed span {cfg.span}", flush=True)
|
| 539 |
-
print(f" regions: work {work_base}..{m.next - 1}, memory {mem_base}, "
|
| 540 |
-
f"tape {tape_base}, output {out_base}", flush=True)
|
| 541 |
-
|
| 542 |
-
exp_out, exp_steps, exp_mem, exp_head = reference128(image128(), tape)
|
| 543 |
-
assert exp_out == target, (exp_out, target)
|
| 544 |
-
print(f" the reference runs P on a {len(tape)}-byte recipe in "
|
| 545 |
-
f"{exp_steps} instructions, emitting {len(exp_out)} bytes", flush=True)
|
| 546 |
-
|
| 547 |
-
nl = encode_netlist(cfg, m.recs)
|
| 548 |
-
|
| 549 |
-
def initial_signals():
|
| 550 |
-
sig = [0] * cfg.S
|
| 551 |
-
sig[cfg.NET0:cfg.NET0 + len(nl)] = nl
|
| 552 |
-
mem0 = image128()
|
| 553 |
-
for j in range(MEM_BYTES):
|
| 554 |
-
for b in range(8):
|
| 555 |
-
sig[mem_base + b * MEM_BYTES + j] = (mem0[j] >> b) & 1
|
| 556 |
-
for j, byte in enumerate(tape):
|
| 557 |
-
for b in range(8):
|
| 558 |
-
sig[tape_base + b * tape_len + j] = (byte >> b) & 1
|
| 559 |
-
return sig
|
| 560 |
-
|
| 561 |
-
def readout(sig):
|
| 562 |
-
def byte_at(base, stride, j):
|
| 563 |
-
return sum(int(sig[base + b * stride + j]) << b for b in range(8))
|
| 564 |
-
return (bytes(byte_at(out_base, tape_len, j) for j in range(len(target))),
|
| 565 |
-
[byte_at(mem_base, MEM_BYTES, j) for j in range(MEM_BYTES)],
|
| 566 |
-
sum(int(sig[m.named["wp"] + k]) << k for k in range(ADDR)),
|
| 567 |
-
sum(int(sig[m.named["head"] + k]) << k for k in range(ADDR)))
|
| 568 |
-
|
| 569 |
-
# first at the level of Definition 9.1, record by record
|
| 570 |
-
t0 = time.perf_counter()
|
| 571 |
-
rsig = initial_signals()
|
| 572 |
-
rpasses, rhalted = run_records(m.recs, rsig, cfg, exp_steps + 3)
|
| 573 |
-
r_out, r_mem, r_wp, r_head = readout(rsig)
|
| 574 |
-
rec_ok = (rhalted and rpasses == exp_steps and r_out == target
|
| 575 |
-
and r_mem == exp_mem and r_head == exp_head)
|
| 576 |
-
print(f" record semantics: halted after {rpasses} passes, emitted "
|
| 577 |
-
f"{r_wp} bytes {r_out!r}, memory and head match the reference: "
|
| 578 |
-
f"{'yes' if rec_ok else 'NO'} ({time.perf_counter() - t0:.1f}s)",
|
| 579 |
-
flush=True)
|
| 580 |
-
|
| 581 |
-
t0 = time.perf_counter()
|
| 582 |
-
unet, uin, uout = build_net(cfg)
|
| 583 |
-
lev = Leveled(unet, uin, uout, device=args.device)
|
| 584 |
-
print(f" U_S' netlist: {len(unet.gates):,} units, {len(lev.plan)} layers "
|
| 585 |
-
f"({time.perf_counter() - t0:.0f}s)", flush=True)
|
| 586 |
-
|
| 587 |
-
V = state_to_vec(cfg, {"sig": initial_signals(), "gp": 0, "halt": 0}
|
| 588 |
-
).unsqueeze(0).to(args.device)
|
| 589 |
-
|
| 590 |
-
t0 = time.perf_counter()
|
| 591 |
-
halted_at = None
|
| 592 |
-
for inst in range(exp_steps + 2):
|
| 593 |
-
for _ in range(cfg.G):
|
| 594 |
-
V = lev.step(V)
|
| 595 |
-
if int(V[0, cfg.S + cfg.GPW]) == 1:
|
| 596 |
-
halted_at = inst + 1
|
| 597 |
-
break
|
| 598 |
-
if inst and inst % 20 == 0:
|
| 599 |
-
print(f" {inst}/{exp_steps} instructions "
|
| 600 |
-
f"({inst * cfg.G / (time.perf_counter() - t0):.0f} steps/s)",
|
| 601 |
-
flush=True)
|
| 602 |
-
dt = time.perf_counter() - t0
|
| 603 |
-
got, got_mem, wp_val, head_val = readout(V[0].cpu())
|
| 604 |
-
|
| 605 |
-
exact = got == target
|
| 606 |
-
mem_same = got_mem == exp_mem
|
| 607 |
-
print(f" ran to a halt after {halted_at} instructions "
|
| 608 |
-
f"({halted_at * cfg.G:,} interpreter steps, {dt / 60:.1f} min, "
|
| 609 |
-
f"{halted_at * cfg.G / dt:.0f} steps/s)", flush=True)
|
| 610 |
-
print(f" emitted {wp_val} bytes: {got!r}")
|
| 611 |
-
print(f" equals the target: {'yes' if exact else 'NO'}; final memory "
|
| 612 |
-
f"equals the reference: {'yes' if mem_same else 'NO'}; head "
|
| 613 |
-
f"{head_val} of {len(tape)}: "
|
| 614 |
-
f"{'yes' if head_val == exp_head else 'NO'}")
|
| 615 |
-
|
| 616 |
-
t0 = time.perf_counter()
|
| 617 |
-
dev_rand = "cuda" if torch.cuda.is_available() else args.device
|
| 618 |
-
bad_ref, bad_net = random_pass_check(cfg, m, nl, mem_base, tape_base, out_base,
|
| 619 |
-
tape_len, args.random_states,
|
| 620 |
-
args.net_states, dev_rand)
|
| 621 |
-
print(f" one pass against one step of the transducer from random states: "
|
| 622 |
-
f"{args.random_states:,} on the record semantics, "
|
| 623 |
-
f"{'all exact' if bad_ref == 0 else f'{bad_ref} WRONG'}; "
|
| 624 |
-
f"{args.net_states:,} on the netlist, "
|
| 625 |
-
f"{'all exact' if bad_net == 0 else f'{bad_net} WRONG'} "
|
| 626 |
-
f"({time.perf_counter() - t0:.0f}s)", flush=True)
|
| 627 |
-
|
| 628 |
-
ok = (rec_ok and exact and mem_same and halted_at == exp_steps
|
| 629 |
-
and head_val == exp_head and bad_ref == 0 and bad_net == 0)
|
| 630 |
-
d = os.path.join(REPO, "paper", "runs")
|
| 631 |
-
os.makedirs(d, exist_ok=True)
|
| 632 |
-
json.dump({"records": n, "record_semantics_ok": rec_ok,
|
| 633 |
-
"S": cfg.S, "G": cfg.G, "b": cfg.R,
|
| 634 |
-
"span": cfg.span, "units": len(unet.gates),
|
| 635 |
-
"layers": len(lev.plan), "memory_bytes": MEM_BYTES,
|
| 636 |
-
"tape_bytes": len(tape), "target_bytes": len(target),
|
| 637 |
-
"target": target.decode(), "instructions": halted_at,
|
| 638 |
-
"reference_instructions": exp_steps,
|
| 639 |
-
"interpreter_steps": halted_at * cfg.G,
|
| 640 |
-
"emitted": got.decode(errors="replace"), "exact": exact,
|
| 641 |
-
"memory_matches_reference": mem_same, "head": head_val,
|
| 642 |
-
"random_states_records": args.random_states,
|
| 643 |
-
"random_states_records_wrong": bad_ref,
|
| 644 |
-
"random_states_netlist": args.net_states,
|
| 645 |
-
"random_states_netlist_wrong": bad_net,
|
| 646 |
-
"seconds": dt, "ok": ok},
|
| 647 |
-
open(os.path.join(d, "paper_hosted.json"), "w"), indent=1)
|
| 648 |
-
print("HOSTED CONSTRUCTOR:", "PASS" if ok else "FAIL")
|
| 649 |
-
return 0 if ok else 1
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
if __name__ == "__main__":
|
| 653 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/independent/interpreter.py
DELETED
|
@@ -1,495 +0,0 @@
|
|
| 1 |
-
"""Definition 9.1 transcribed afresh, and the two runs of Section 9 on it.
|
| 2 |
-
|
| 3 |
-
python src/independent/interpreter.py
|
| 4 |
-
|
| 5 |
-
The artifact supplies only the objects under test: the 494 stored records of
|
| 6 |
-
Theorem 9.10 with the register addresses they use, and the netlist of U_128 that
|
| 7 |
-
Proposition 9.8 stores. Record decoding, the interpreter, the fan-in-two
|
| 8 |
-
compilation, the layout of Proposition 9.8, the SUBLEQ machine on 128 bytes, the
|
| 9 |
-
device and the constructor P (from Table 9 of the paper) are written here.
|
| 10 |
-
"""
|
| 11 |
-
import json
|
| 12 |
-
import os
|
| 13 |
-
import random
|
| 14 |
-
import sys
|
| 15 |
-
import time
|
| 16 |
-
|
| 17 |
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 18 |
-
RUNS = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'paper', 'runs')
|
| 19 |
-
|
| 20 |
-
# ---------------------------------------------------------------------------
|
| 21 |
-
# Definition 9.1
|
| 22 |
-
# ---------------------------------------------------------------------------
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
class Member:
|
| 26 |
-
def __init__(self, A, G, span, banks=1):
|
| 27 |
-
self.A, self.G, self.span = A, G, span
|
| 28 |
-
self.S = 1 << A
|
| 29 |
-
self.b = 3 * A + 11
|
| 30 |
-
self.OUT_DATA, self.OUT_STROBE, self.ADV, self.KAPPA, self.HALT = A, A + 1, A + 2, A + 3, A + 4
|
| 31 |
-
self.Q0 = self.S - banks * G * self.b
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
def decode_record(bits, A):
|
| 35 |
-
"""(a0, w0, i0, a1, w1, i1, beta, ao, io), addresses most significant bit first."""
|
| 36 |
-
pos = 0
|
| 37 |
-
|
| 38 |
-
def take(n):
|
| 39 |
-
nonlocal pos
|
| 40 |
-
v = 0
|
| 41 |
-
for k in range(n):
|
| 42 |
-
v = (v << 1) | bits[pos + k]
|
| 43 |
-
pos += n
|
| 44 |
-
return v
|
| 45 |
-
wmap = {0b01: 1, 0b10: -1, 0b00: 0, 0b11: 0}
|
| 46 |
-
a0 = take(A); w0 = wmap[take(2)]; i0 = take(1)
|
| 47 |
-
a1 = take(A); w1 = wmap[take(2)]; i1 = take(1)
|
| 48 |
-
beta = take(4); beta = beta - 16 if beta >= 8 else beta
|
| 49 |
-
ao = take(A); io = take(1)
|
| 50 |
-
assert pos == 3 * A + 11
|
| 51 |
-
return a0, w0, i0, a1, w1, i1, beta, ao, io
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
def encode_record(rec, A):
|
| 55 |
-
a0, w0, i0, a1, w1, i1, beta, ao, io = rec
|
| 56 |
-
out = []
|
| 57 |
-
put = lambda v, n: out.extend((v >> (n - 1 - k)) & 1 for k in range(n))
|
| 58 |
-
wc = {1: 0b01, -1: 0b10, 0: 0b00}
|
| 59 |
-
put(a0, A); put(wc[w0], 2); put(i0, 1)
|
| 60 |
-
put(a1, A); put(wc[w1], 2); put(i1, 1)
|
| 61 |
-
put(beta & 15, 4); put(ao, A); put(io, 1)
|
| 62 |
-
return out
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
class Interp:
|
| 66 |
-
"""The interpreter on a state x of S coordinates, with record counter and halt bit."""
|
| 67 |
-
def __init__(self, M, x):
|
| 68 |
-
self.M, self.x, self.g, self.halt, self.out = M, x, 0, 0, []
|
| 69 |
-
self.recs = [decode_record(x[M.Q0 + k * M.b: M.Q0 + (k + 1) * M.b], M.A) for k in range(M.G)]
|
| 70 |
-
|
| 71 |
-
def ptr(self):
|
| 72 |
-
v = 0
|
| 73 |
-
for k in range(self.M.A):
|
| 74 |
-
v = (v << 1) | self.x[k]
|
| 75 |
-
return v
|
| 76 |
-
|
| 77 |
-
def apply(self):
|
| 78 |
-
M, x = self.M, self.x
|
| 79 |
-
if self.halt:
|
| 80 |
-
return
|
| 81 |
-
a0, w0, i0, a1, w1, i1, beta, ao, io = self.recs[self.g]
|
| 82 |
-
p = self.ptr()
|
| 83 |
-
eff = lambda a, i: (a + i * p) % M.S
|
| 84 |
-
rd = lambda a: x[a] if a < M.span else 0
|
| 85 |
-
v = 1 if w0 * rd(eff(a0, i0)) + w1 * rd(eff(a1, i1)) + beta >= 0 else 0
|
| 86 |
-
nhalt = self.halt | x[M.HALT]
|
| 87 |
-
dst = eff(ao, io)
|
| 88 |
-
if dst < M.span:
|
| 89 |
-
x[dst] = v
|
| 90 |
-
if x[M.ADV]: # the pointer clause
|
| 91 |
-
q = (p + 1) % M.S
|
| 92 |
-
for k in range(M.A):
|
| 93 |
-
x[k] = (q >> (M.A - 1 - k)) & 1
|
| 94 |
-
x[M.ADV] = 0
|
| 95 |
-
if x[M.OUT_STROBE]: # the output clause, by the runtime
|
| 96 |
-
self.out.append(x[M.OUT_DATA])
|
| 97 |
-
x[M.OUT_STROBE] = 0
|
| 98 |
-
self.g = (self.g + 1) % M.G
|
| 99 |
-
self.halt = nhalt
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
# ---------------------------------------------------------------------------
|
| 103 |
-
# The hosted transducer: SUBLEQ on 128 bytes (Definition 3.1 with addresses
|
| 104 |
-
# modulo 128, halting at 0x7F) and the device of Definition 2.8 at the top cells
|
| 105 |
-
# ---------------------------------------------------------------------------
|
| 106 |
-
|
| 107 |
-
Z, ONE, T1, T2, NEG1, EOK = 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5
|
| 108 |
-
C_WR, C_EOT, C_RW, C_RD, R_IN, R_OUT = 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE
|
| 109 |
-
TABLE9 = [ # Table 9 of the paper
|
| 110 |
-
(T2, T2, 0x03), (T1, T1, 0x06), (NEG1, C_RD, 0x09), (R_IN, T1, 0x0C), (T1, T2, 0x0F),
|
| 111 |
-
(Z, T2, 0x15), (Z, Z, 0x1B), (Z, T1, 0x3C), (Z, Z, 0x2D), (NEG1, C_RD, 0x1E),
|
| 112 |
-
(R_IN, R_OUT, 0x21), (NEG1, C_WR, 0x24), (ONE, T2, 0x2A), (Z, Z, 0x1B), (Z, Z, 0x00),
|
| 113 |
-
(NEG1, C_RD, 0x30), (R_IN, R_OUT, 0x33), (NEG1, C_WR, 0x36), (ONE, T1, 0x2A), (Z, Z, 0x30),
|
| 114 |
-
(Z, Z, 0xFF)]
|
| 115 |
-
mv = lambda c: c - 0x80 if c >= 0xF0 else c
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
def p128_image():
|
| 119 |
-
mem = [0] * 128
|
| 120 |
-
for k, (a, b, c) in enumerate(TABLE9):
|
| 121 |
-
mem[3 * k:3 * k + 3] = [mv(a), mv(b), mv(c)]
|
| 122 |
-
mem[mv(ONE)] = 1
|
| 123 |
-
mem[mv(NEG1)] = 255
|
| 124 |
-
mem[mv(EOK)] = 1
|
| 125 |
-
return mem
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
def hosted_step(mem, p, tau, h, omega):
|
| 129 |
-
"""One step of the hosted transducer; returns (mem, p, h, omega)."""
|
| 130 |
-
mem = list(mem)
|
| 131 |
-
a, b, c = mem[p], mem[(p + 1) % 128], mem[(p + 2) % 128]
|
| 132 |
-
a, b = a % 128, b % 128
|
| 133 |
-
r = (mem[b] - mem[a]) % 256
|
| 134 |
-
mem[b] = r
|
| 135 |
-
p2 = c % 128 if (r == 0 or r >= 128) else (p + 3) % 128
|
| 136 |
-
cwr, crd, crw = mem[mv(C_WR)] == 1, mem[mv(C_RD)] == 1, mem[mv(C_RW)] == 1
|
| 137 |
-
omega = list(omega)
|
| 138 |
-
if cwr:
|
| 139 |
-
omega.append(mem[mv(R_OUT)])
|
| 140 |
-
mem[mv(R_OUT)] = 0
|
| 141 |
-
if crd:
|
| 142 |
-
if h < len(tau):
|
| 143 |
-
mem[mv(R_IN)] = tau[h]
|
| 144 |
-
mem[mv(C_EOT)] = 0
|
| 145 |
-
h += 1
|
| 146 |
-
else:
|
| 147 |
-
mem[mv(C_EOT)] = 1
|
| 148 |
-
if crw:
|
| 149 |
-
h = 0
|
| 150 |
-
mem[mv(C_WR)] = mem[mv(C_RD)] = mem[mv(C_RW)] = 0
|
| 151 |
-
return mem, p2, h, omega
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
def run_hosted(tau, max_steps=100000):
|
| 155 |
-
mem, p, h, omega = p128_image(), 0, 0, []
|
| 156 |
-
for k in range(1, max_steps + 1):
|
| 157 |
-
mem, p, h, omega = hosted_step(mem, p, tau, h, omega)
|
| 158 |
-
if p == 0x7F:
|
| 159 |
-
return k, mem, h, omega
|
| 160 |
-
raise RuntimeError('no halt')
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
def nu(x):
|
| 164 |
-
return (-x) % 256
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
def delta(r):
|
| 168 |
-
out, i = [], 0
|
| 169 |
-
while True:
|
| 170 |
-
t = r[i]
|
| 171 |
-
if t == 0:
|
| 172 |
-
return bytes(out)
|
| 173 |
-
if 1 <= t <= 127:
|
| 174 |
-
out += [nu(b) for b in r[i + 1:i + 1 + t]]
|
| 175 |
-
i += 1 + t
|
| 176 |
-
elif t >= 129:
|
| 177 |
-
out += [nu(r[i + 1])] * (256 - t)
|
| 178 |
-
i += 2
|
| 179 |
-
else:
|
| 180 |
-
raise ValueError('tag 128')
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
def describe(f):
|
| 184 |
-
"""The encoder of Lemma 4.4."""
|
| 185 |
-
out, i = [], 0
|
| 186 |
-
while i < len(f):
|
| 187 |
-
ell = 1
|
| 188 |
-
while i + ell < len(f) and f[i + ell] == f[i] and ell < 127:
|
| 189 |
-
ell += 1
|
| 190 |
-
if ell >= 4:
|
| 191 |
-
out += [256 - ell, nu(f[i])]
|
| 192 |
-
i += ell
|
| 193 |
-
continue
|
| 194 |
-
k = i + 1
|
| 195 |
-
while k < len(f) and k < i + 127:
|
| 196 |
-
if k + 3 < len(f) and f[k] == f[k + 1] == f[k + 2] == f[k + 3]:
|
| 197 |
-
break
|
| 198 |
-
k += 1
|
| 199 |
-
out += [k - i] + [nu(c) for c in f[i:k]]
|
| 200 |
-
i = k
|
| 201 |
-
return bytes(out + [0])
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
def census_steps(r):
|
| 205 |
-
"""Theorem 4.6: 5 f_lit + 4 f_rep + 7L + 9R + 8."""
|
| 206 |
-
i, steps = 0, 8
|
| 207 |
-
while r[i] != 0:
|
| 208 |
-
t = r[i]
|
| 209 |
-
if t <= 127:
|
| 210 |
-
steps += 5 * t + 7
|
| 211 |
-
i += 1 + t
|
| 212 |
-
else:
|
| 213 |
-
steps += 4 * (256 - t) + 9
|
| 214 |
-
i += 2
|
| 215 |
-
return steps
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
def random_recipe(rng, max_len=64, max_out=63):
|
| 219 |
-
while True:
|
| 220 |
-
toks, out_len = [], 0
|
| 221 |
-
for _ in range(rng.randint(0, 6)):
|
| 222 |
-
if rng.random() < 0.5:
|
| 223 |
-
n = rng.randint(1, 12)
|
| 224 |
-
toks += [n] + [rng.randrange(256) for _ in range(n)]
|
| 225 |
-
out_len += n
|
| 226 |
-
else:
|
| 227 |
-
ell = rng.randint(1, 20)
|
| 228 |
-
toks += [256 - ell, rng.randrange(256)]
|
| 229 |
-
out_len += ell
|
| 230 |
-
r = toks + [0]
|
| 231 |
-
if len(r) <= max_len and out_len <= max_out:
|
| 232 |
-
return bytes(r)
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
# ---------------------------------------------------------------------------
|
| 236 |
-
# Theorem 9.10
|
| 237 |
-
# ---------------------------------------------------------------------------
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
def hosted_check(recipes_n=40, random_n=2000, seed=11):
|
| 241 |
-
import hosted_constructor as HC
|
| 242 |
-
from reflect import Cfg, encode_netlist
|
| 243 |
-
A, G, span, mem_base, tape_base, out_base, work_base = HC.layout(64, 64, min_records=520)
|
| 244 |
-
cfg = Cfg(A=A, G=G, banks=1, self_mod=False)
|
| 245 |
-
m = HC.build_microprogram(cfg, mem_base, tape_base, out_base, 64, work_base, 700)
|
| 246 |
-
bits = encode_netlist(cfg, m.recs)
|
| 247 |
-
M = Member(A, G, span)
|
| 248 |
-
assert (A, G, span, mem_base, tape_base, out_base) == (15, 535, 2808, 721, 1745, 2257)
|
| 249 |
-
named = m.named
|
| 250 |
-
PC, HEAD, WP = named['pc'] if 'pc' in named else named['PC'], named['head'], named['wp']
|
| 251 |
-
n_real = len(m.recs)
|
| 252 |
-
|
| 253 |
-
def blank():
|
| 254 |
-
x = [0] * M.S
|
| 255 |
-
x[M.Q0:M.Q0 + len(bits)] = bits
|
| 256 |
-
return x
|
| 257 |
-
|
| 258 |
-
def put_reg(x, base, v):
|
| 259 |
-
for k in range(7):
|
| 260 |
-
x[base + k] = (v >> k) & 1
|
| 261 |
-
|
| 262 |
-
def get_reg(x, base):
|
| 263 |
-
return sum(x[base + k] << k for k in range(7))
|
| 264 |
-
|
| 265 |
-
def put_bytes(x, base, stride, data):
|
| 266 |
-
for j, byte in enumerate(data):
|
| 267 |
-
for t in range(8):
|
| 268 |
-
x[base + t * stride + j] = (byte >> t) & 1
|
| 269 |
-
|
| 270 |
-
def get_bytes(x, base, stride, n):
|
| 271 |
-
return [sum(x[base + t * stride + j] << t for t in range(8)) for j in range(n)]
|
| 272 |
-
|
| 273 |
-
res = dict(records=n_real, noops=G - n_real)
|
| 274 |
-
# every record after the 494th is a no-op writing the sink
|
| 275 |
-
tail = [decode_record(bits[k * M.b:(k + 1) * M.b], A) for k in range(n_real, G)]
|
| 276 |
-
res['tail_noops'] = all(r[1] == 0 and r[4] == 0 and r[6] == -1 and r[7] == A + 5 and r[8] == 0 for r in tail)
|
| 277 |
-
# the decoded records equal the artifact's own description of them
|
| 278 |
-
same = True
|
| 279 |
-
for k, (slots, bias, (oa, oi)) in enumerate(m.recs):
|
| 280 |
-
sl = list(slots) + [(0, 0, 0)] * (2 - len(slots))
|
| 281 |
-
rec = decode_record(bits[k * M.b:(k + 1) * M.b], A)
|
| 282 |
-
same &= rec == (sl[0][0], sl[0][1], sl[0][2], sl[1][0], sl[1][1], sl[1][2], bias, oa, oi)
|
| 283 |
-
res['decode_matches'] = same
|
| 284 |
-
# recipes run to the halt
|
| 285 |
-
rng = random.Random(seed)
|
| 286 |
-
tests = [b'ABCCCCCCCCDE']
|
| 287 |
-
runs = []
|
| 288 |
-
for k in range(recipes_n + 1):
|
| 289 |
-
if k == 0:
|
| 290 |
-
target = tests[0]
|
| 291 |
-
r = describe(target)
|
| 292 |
-
assert delta(r) == target and r == bytes([2, nu(65), nu(66), 248, nu(67), 2, nu(68), nu(69), 0])
|
| 293 |
-
else:
|
| 294 |
-
r = random_recipe(rng)
|
| 295 |
-
tau = list(r) + [0] * (64 - len(r))
|
| 296 |
-
steps, emem, eh, eomega = run_hosted(tau)
|
| 297 |
-
assert steps == census_steps(r) and bytes(eomega) == delta(r)
|
| 298 |
-
x = blank()
|
| 299 |
-
put_bytes(x, mem_base, 128, p128_image())
|
| 300 |
-
put_bytes(x, tape_base, 64, tau)
|
| 301 |
-
I = Interp(M, x)
|
| 302 |
-
apps = 0
|
| 303 |
-
while not I.halt and apps < (steps + 2) * G:
|
| 304 |
-
I.apply()
|
| 305 |
-
apps += 1
|
| 306 |
-
passes = -(-apps // G)
|
| 307 |
-
got_out = bytes(get_bytes(x, out_base, 64, 64))
|
| 308 |
-
ok = (I.halt and passes == steps and got_out[:len(eomega)] == bytes(eomega)
|
| 309 |
-
and not any(got_out[len(eomega):]) and get_bytes(x, mem_base, 128, 128) == emem
|
| 310 |
-
and get_reg(x, HEAD) == eh == len(r) and get_reg(x, WP) == len(eomega) and not I.out)
|
| 311 |
-
runs.append(dict(recipe_len=len(r), out_len=len(eomega), steps=steps, passes=passes,
|
| 312 |
-
applications=apps, ok=ok))
|
| 313 |
-
res['recipes'] = len(runs)
|
| 314 |
-
res['recipes_ok'] = sum(r['ok'] for r in runs)
|
| 315 |
-
res['first'] = runs[0]
|
| 316 |
-
# one pass from random held states
|
| 317 |
-
bad = 0
|
| 318 |
-
halting = 0
|
| 319 |
-
for _ in range(random_n):
|
| 320 |
-
x = blank()
|
| 321 |
-
for c in range(M.A + 6, mem_base): # the work region, temporaries included, random
|
| 322 |
-
x[c] = rng.randrange(2)
|
| 323 |
-
for c in range(M.A):
|
| 324 |
-
x[c] = rng.randrange(2)
|
| 325 |
-
x[M.OUT_DATA] = rng.randrange(2)
|
| 326 |
-
x[M.ADV] = x[M.OUT_STROBE] = x[M.HALT] = 0
|
| 327 |
-
mem = [rng.randrange(256) for _ in range(128)]
|
| 328 |
-
p = rng.randrange(127)
|
| 329 |
-
u = rng.random()
|
| 330 |
-
if u < 0.125:
|
| 331 |
-
p = 0x7C # p + 3 is the halt address
|
| 332 |
-
elif u < 0.25:
|
| 333 |
-
mem[(p + 2) % 128] = 0x7F # the branch target is the halt address
|
| 334 |
-
tau = [rng.randrange(256) for _ in range(64)]
|
| 335 |
-
h = rng.randint(0, 64)
|
| 336 |
-
w = rng.randint(0, 63)
|
| 337 |
-
omega = [rng.randrange(256) for _ in range(w)]
|
| 338 |
-
put_bytes(x, mem_base, 128, mem)
|
| 339 |
-
put_bytes(x, tape_base, 64, tau)
|
| 340 |
-
put_bytes(x, out_base, 64, omega + [0] * (64 - w))
|
| 341 |
-
put_reg(x, PC, p); put_reg(x, HEAD, h); put_reg(x, WP, w)
|
| 342 |
-
emem, ep, eh, eomega = hosted_step(mem, p, tau, h, omega)
|
| 343 |
-
I = Interp(M, x)
|
| 344 |
-
for _ in range(G):
|
| 345 |
-
I.apply()
|
| 346 |
-
got_out = get_bytes(x, out_base, 64, 64)
|
| 347 |
-
common = (get_bytes(x, mem_base, 128, 128) == emem and get_reg(x, HEAD) == eh
|
| 348 |
-
and get_reg(x, WP) == len(eomega) and got_out[:len(eomega)] == eomega
|
| 349 |
-
and not any(got_out[len(eomega):]) and get_bytes(x, tape_base, 64, 64) == tau
|
| 350 |
-
and not I.out)
|
| 351 |
-
if ep == 0x7F:
|
| 352 |
-
halting += 1
|
| 353 |
-
ok = common and I.halt
|
| 354 |
-
else:
|
| 355 |
-
ok = common and not I.halt and get_reg(x, PC) == ep and I.g == 0
|
| 356 |
-
bad += not ok
|
| 357 |
-
res['random_states'] = random_n
|
| 358 |
-
res['random_halting_steps'] = halting
|
| 359 |
-
res['random_disagree'] = bad
|
| 360 |
-
return res
|
| 361 |
-
|
| 362 |
-
|
| 363 |
-
# ---------------------------------------------------------------------------
|
| 364 |
-
# Proposition 9.8
|
| 365 |
-
# ---------------------------------------------------------------------------
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
def hierarchy_check(states=48, passes=4, seed=5):
|
| 369 |
-
from reflect import Cfg, build_net, encode_netlist
|
| 370 |
-
small = Cfg(A=7, G=3, banks=1, self_mod=False)
|
| 371 |
-
net, inputs, outputs = build_net(small)
|
| 372 |
-
# the netlist as units over named signals; inputs are the state coordinates in order
|
| 373 |
-
gates = net.gates
|
| 374 |
-
order, seen = [], set(inputs) | {'#0', '#1'}
|
| 375 |
-
pending = dict(gates)
|
| 376 |
-
while pending: # a topological order of the units
|
| 377 |
-
prog = [g for g, (ins, _) in pending.items() if all(s in seen for s, _ in ins)]
|
| 378 |
-
assert prog
|
| 379 |
-
for g in prog:
|
| 380 |
-
order.append(g); seen.add(g); del pending[g]
|
| 381 |
-
# fan-in two (Corollary 9.6): every unit of fan-in > 2 must be a conjunction or a disjunction
|
| 382 |
-
units2 = [] # (name, [(sig, w)], bias)
|
| 383 |
-
cnt = [0]
|
| 384 |
-
|
| 385 |
-
def fresh():
|
| 386 |
-
cnt[0] += 1
|
| 387 |
-
return f'_t{cnt[0]}'
|
| 388 |
-
|
| 389 |
-
def kind(ins, b):
|
| 390 |
-
pos = sum(1 for _, w in ins if w > 0)
|
| 391 |
-
neg = len(ins) - pos
|
| 392 |
-
if b == -pos:
|
| 393 |
-
return 'and'
|
| 394 |
-
if b == neg - 1:
|
| 395 |
-
return 'or'
|
| 396 |
-
return None
|
| 397 |
-
|
| 398 |
-
def tree(name, k, lits):
|
| 399 |
-
"""lits: [(sig, polarity)], a balanced tree of two-input units, the root named name."""
|
| 400 |
-
level = list(lits)
|
| 401 |
-
while len(level) > 2:
|
| 402 |
-
nxt = []
|
| 403 |
-
for i in range(0, len(level) - 1, 2):
|
| 404 |
-
t = fresh()
|
| 405 |
-
(s1, p1), (s2, p2) = level[i], level[i + 1]
|
| 406 |
-
pos = p1 + p2
|
| 407 |
-
b = -pos if k == 'and' else (2 - pos) - 1
|
| 408 |
-
units2.append((t, [(s1, 1 if p1 else -1), (s2, 1 if p2 else -1)], b))
|
| 409 |
-
nxt.append((t, 1))
|
| 410 |
-
if len(level) % 2:
|
| 411 |
-
nxt.append(level[-1])
|
| 412 |
-
level = nxt
|
| 413 |
-
if len(level) == 2:
|
| 414 |
-
(s1, p1), (s2, p2) = level
|
| 415 |
-
pos = p1 + p2
|
| 416 |
-
b = -pos if k == 'and' else (2 - pos) - 1
|
| 417 |
-
units2.append((name, [(s1, 1 if p1 else -1), (s2, 1 if p2 else -1)], b))
|
| 418 |
-
else:
|
| 419 |
-
(s1, p1), = level
|
| 420 |
-
units2.append((name, [(s1, 1 if p1 else -1)], -1 if p1 else 0))
|
| 421 |
-
for g in order:
|
| 422 |
-
ins, b = gates[g]
|
| 423 |
-
if len(ins) <= 2:
|
| 424 |
-
units2.append((g, list(ins), b))
|
| 425 |
-
else:
|
| 426 |
-
k = kind(ins, b)
|
| 427 |
-
assert k is not None, (g, ins, b)
|
| 428 |
-
tree(g, k, [(s, 1 if w > 0 else 0) for s, w in ins])
|
| 429 |
-
# constants are wired as units
|
| 430 |
-
consts = {}
|
| 431 |
-
# the coordinates whose next value is not the coordinate itself
|
| 432 |
-
changed = [i for i, o in enumerate(outputs) if o != inputs[i]]
|
| 433 |
-
nstate = len(inputs)
|
| 434 |
-
n2 = len(units2)
|
| 435 |
-
# the larger member: A' = 17, one bank, G' = 2088, span 1616
|
| 436 |
-
big = Member(17, 2088, 1616)
|
| 437 |
-
base = big.A + 6
|
| 438 |
-
addr = {s: base + i for i, s in enumerate(inputs)}
|
| 439 |
-
for i, (name, _, _) in enumerate(units2):
|
| 440 |
-
addr[name] = base + nstate + i
|
| 441 |
-
recs = []
|
| 442 |
-
for name, ins, b in units2:
|
| 443 |
-
sl = [(addr[s] if s not in ('#0', '#1') else None, w) for s, w in ins]
|
| 444 |
-
assert all(a is not None for a, _ in sl)
|
| 445 |
-
sl += [(0, 0)] * (2 - len(sl))
|
| 446 |
-
recs.append((sl[0][0], sl[0][1], 0, sl[1][0], sl[1][1], 0, b, addr[name], 0))
|
| 447 |
-
for i in changed:
|
| 448 |
-
src = outputs[i]
|
| 449 |
-
if src == '#0':
|
| 450 |
-
recs.append((0, 0, 0, 0, 0, 0, -1, addr[inputs[i]], 0))
|
| 451 |
-
elif src == '#1':
|
| 452 |
-
recs.append((0, 0, 0, 0, 0, 0, 0, addr[inputs[i]], 0))
|
| 453 |
-
else:
|
| 454 |
-
recs.append((addr[src], 1, 0, 0, 0, 0, -1, addr[inputs[i]], 0))
|
| 455 |
-
assert len(recs) <= big.G and base + nstate + n2 <= big.span
|
| 456 |
-
noop = (0, 0, 0, 0, 0, 0, -1, big.A + 5, 0)
|
| 457 |
-
recs += [noop] * (big.G - len(recs))
|
| 458 |
-
bits = sum((encode_record(r, big.A) for r in recs), [])
|
| 459 |
-
rng = random.Random(seed)
|
| 460 |
-
|
| 461 |
-
def eval_small(vals):
|
| 462 |
-
v = dict(zip(inputs, vals)); v['#0'], v['#1'] = 0, 1
|
| 463 |
-
for g in order:
|
| 464 |
-
ins, b = gates[g]
|
| 465 |
-
v[g] = 1 if b + sum(w * v[s] for s, w in ins) >= 0 else 0
|
| 466 |
-
return [v[o] for o in outputs]
|
| 467 |
-
bad = 0
|
| 468 |
-
for _ in range(states):
|
| 469 |
-
y = [rng.randrange(2) for _ in range(nstate)]
|
| 470 |
-
x = [0] * big.S
|
| 471 |
-
x[big.Q0:big.Q0 + len(bits)] = bits
|
| 472 |
-
for i, s in enumerate(inputs):
|
| 473 |
-
x[addr[s]] = y[i]
|
| 474 |
-
I = Interp(big, x)
|
| 475 |
-
for _ in range(passes):
|
| 476 |
-
for _ in range(big.G):
|
| 477 |
-
I.apply()
|
| 478 |
-
y = eval_small(y)
|
| 479 |
-
got = [x[addr[s]] for s in inputs]
|
| 480 |
-
bad += got != y
|
| 481 |
-
return dict(small_units=len(gates), small_state_bits=nstate, fanin2_units=n2,
|
| 482 |
-
signals=nstate + n2, changed=len(changed), records=len(recs) - recs.count(noop),
|
| 483 |
-
big=dict(A=big.A, G=big.G, b=big.b, span=big.span), states=states, passes=passes,
|
| 484 |
-
disagree=bad)
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
if __name__ == '__main__':
|
| 488 |
-
out = {}
|
| 489 |
-
for which, fn in (('hierarchy', hierarchy_check), ('hosted', hosted_check)):
|
| 490 |
-
t0 = time.time()
|
| 491 |
-
res = fn()
|
| 492 |
-
res['seconds'] = round(time.time() - t0, 1)
|
| 493 |
-
print(which, json.dumps(res), flush=True)
|
| 494 |
-
out[which] = res
|
| 495 |
-
json.dump(out, open(os.path.join(RUNS, 'independent_interpreter.json'), 'w'), indent=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/paper_stats.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
"""Structural statistics for the host
|
| 2 |
|
| 3 |
Reproduces the level assignment of matrix8.compile_net without materialising the
|
| 4 |
dense matrices, so the layer widths, the number of identity units, the total
|
|
@@ -208,33 +208,6 @@ def main() -> int:
|
|
| 208 |
print(f" widths {lev['widths']}")
|
| 209 |
out["lev_host"] = lev
|
| 210 |
|
| 211 |
-
print()
|
| 212 |
-
print("=" * 74)
|
| 213 |
-
print(" Interpreter U (reflect.Cfg default)")
|
| 214 |
-
print("=" * 74)
|
| 215 |
-
from reflect import Cfg, build_net
|
| 216 |
-
cfg = Cfg()
|
| 217 |
-
unet, uin, uout = build_net(cfg)
|
| 218 |
-
ulev = levelize(unet, uin, uout)
|
| 219 |
-
for k in ("depth", "gates", "netlist_gates", "state_bits", "M",
|
| 220 |
-
"dense_entries", "identity_units",
|
| 221 |
-
"new_units", "max_fanin_netlist", "nonzero_weights_netlist",
|
| 222 |
-
"bias_min", "bias_max"):
|
| 223 |
-
print(f" {k:<26} {ulev[k]:,}" if isinstance(ulev[k], int) else f" {k:<26} {ulev[k]}")
|
| 224 |
-
print(f" fan-in histogram {ulev['fanin_hist']}")
|
| 225 |
-
print(f" cfg: S={cfg.S} G={cfg.G} F={cfg.F} BB={cfg.BB} banks={cfg.banks} "
|
| 226 |
-
f"record_bits={cfg.R} acc_bits={cfg.ACC} slot={cfg.SLOT}")
|
| 227 |
-
print(f" regions: PTR@{cfg.PTR_BASE} width {cfg.A}; control {cfg.OUT_DATA}..{cfg.WORK_BASE-1}; "
|
| 228 |
-
f"data {cfg.WORK_BASE}..{cfg.NET0-1} ({cfg.NET0-cfg.WORK_BASE} bits); "
|
| 229 |
-
f"Q0 {cfg.NET0}..{cfg.NET1-1}; Q1 {cfg.NET1}..{cfg.S-1}; "
|
| 230 |
-
f"|Q|={cfg.G*cfg.R} b={cfg.R}")
|
| 231 |
-
out["lev_U"] = ulev
|
| 232 |
-
out["U_cfg"] = {"S": cfg.S, "G": cfg.G, "F": cfg.F, "BB": cfg.BB,
|
| 233 |
-
"banks": cfg.banks, "R": cfg.R, "ACC": cfg.ACC,
|
| 234 |
-
"SLOT": cfg.SLOT, "A": cfg.A, "NET0": cfg.NET0,
|
| 235 |
-
"NET1": cfg.NET1, "WORK_BASE": cfg.WORK_BASE,
|
| 236 |
-
"span": cfg.span, "STATE_BITS": cfg.STATE_BITS}
|
| 237 |
-
|
| 238 |
path = runs_path("paper_stats.json")
|
| 239 |
json.dump(out, open(path, "w"), indent=1)
|
| 240 |
print(f"\nwrote {path}")
|
|
|
|
| 1 |
+
"""Structural statistics for the host and its levelization.
|
| 2 |
|
| 3 |
Reproduces the level assignment of matrix8.compile_net without materialising the
|
| 4 |
dense matrices, so the layer widths, the number of identity units, the total
|
|
|
|
| 208 |
print(f" widths {lev['widths']}")
|
| 209 |
out["lev_host"] = lev
|
| 210 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
path = runs_path("paper_stats.json")
|
| 212 |
json.dump(out, open(path, "w"), indent=1)
|
| 213 |
print(f"\nwrote {path}")
|
src/paper_verify.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
| 1 |
-
"""
|
| 2 |
-
|
| 3 |
-
Everything here finishes in minutes. The long generation runs are in
|
| 4 |
-
paper_runs.py.
|
| 5 |
"""
|
| 6 |
|
| 7 |
from __future__ import annotations
|
|
@@ -229,63 +227,10 @@ def check_host_datapath():
|
|
| 229 |
"counter_pairs": 65536, "counter_failures": bad_ctr}
|
| 230 |
|
| 231 |
|
| 232 |
-
# ---------------------------------------------------------------------------
|
| 233 |
-
def check_interpreter():
|
| 234 |
-
"""One-record semantics exhaustively over record fields, and the record counter."""
|
| 235 |
-
print("[5] Interpreter U")
|
| 236 |
-
import torch
|
| 237 |
-
from reflect import (Cfg, build_net, Leveled, encode_netlist, state_to_vec,
|
| 238 |
-
vec_to_state)
|
| 239 |
-
cfg = Cfg()
|
| 240 |
-
net, inputs, outputs = build_net(cfg)
|
| 241 |
-
lev = Leveled(net, inputs, outputs, device="cpu")
|
| 242 |
-
|
| 243 |
-
def U(sig, gp, halt=0):
|
| 244 |
-
v = state_to_vec(cfg, {"sig": sig, "gp": gp, "halt": halt}).unsqueeze(0)
|
| 245 |
-
out = lev.step(v[:, :len(inputs)])[0]
|
| 246 |
-
return vec_to_state(cfg, out)
|
| 247 |
-
|
| 248 |
-
ra, rb, ro = cfg.WORK_BASE, cfg.WORK_BASE + 1, cfg.WORK_BASE + 2
|
| 249 |
-
bad = total = 0
|
| 250 |
-
for w0 in (-1, 0, 1):
|
| 251 |
-
for w1 in (-1, 0, 1):
|
| 252 |
-
for bias in range(-(1 << (cfg.BB - 1)), 1 << (cfg.BB - 1)):
|
| 253 |
-
nl = encode_netlist(cfg, [([(ra, w0, 0), (rb, w1, 0)], bias, (ro, 0))])
|
| 254 |
-
for va in (0, 1):
|
| 255 |
-
for vb in (0, 1):
|
| 256 |
-
sig = [0] * cfg.S
|
| 257 |
-
sig[cfg.NET0:cfg.NET0 + len(nl)] = nl
|
| 258 |
-
sig[ra], sig[rb] = va, vb
|
| 259 |
-
g = U(sig, 0)
|
| 260 |
-
exp = 1 if w0 * va + w1 * vb + bias >= 0 else 0
|
| 261 |
-
total += 1
|
| 262 |
-
if g["sig"][ro] != exp or g["gp"] != 1:
|
| 263 |
-
bad += 1
|
| 264 |
-
print(f" one-record semantics over all {total} (w0,w1,bias,x0,x1) "
|
| 265 |
-
f"configurations: {'exact' if bad == 0 else f'{bad} FAILED'}")
|
| 266 |
-
|
| 267 |
-
# record counter advances modulo G
|
| 268 |
-
cbad = 0
|
| 269 |
-
nl = encode_netlist(cfg, [])
|
| 270 |
-
for gp in range(cfg.G):
|
| 271 |
-
sig = [0] * cfg.S
|
| 272 |
-
sig[cfg.NET0:cfg.NET0 + len(nl)] = nl
|
| 273 |
-
g = U(sig, gp)
|
| 274 |
-
if g["gp"] != (gp + 1) % cfg.G:
|
| 275 |
-
cbad += 1
|
| 276 |
-
print(f" record counter advances mod G on all {cfg.G} values: "
|
| 277 |
-
f"{'exact' if cbad == 0 else 'FAILED'}")
|
| 278 |
-
|
| 279 |
-
R["interpreter"] = {
|
| 280 |
-
"onerecord_cases": total, "onerecord_failures": bad,
|
| 281 |
-
"counter_failures": cbad, "S": cfg.S, "G": cfg.G, "b": cfg.R,
|
| 282 |
-
}
|
| 283 |
-
|
| 284 |
-
|
| 285 |
# ---------------------------------------------------------------------------
|
| 286 |
def check_lev_sparse_dense():
|
| 287 |
"""The sparse and dense evaluations of Lev(N_host) agree."""
|
| 288 |
-
print("[
|
| 289 |
import torch
|
| 290 |
from selfrep import LevEvaluator, NetEvaluator, read_host
|
| 291 |
sigma = read_host()
|
|
@@ -313,7 +258,6 @@ def main() -> int:
|
|
| 313 |
check_framing()
|
| 314 |
check_serialization()
|
| 315 |
check_host_datapath()
|
| 316 |
-
check_interpreter()
|
| 317 |
check_lev_sparse_dense()
|
| 318 |
R["seconds"] = time.perf_counter() - t0
|
| 319 |
path = runs_path("paper_verify.json")
|
|
|
|
| 1 |
+
"""The recipe codec, the framing, the serialization, the host's datapath and the
|
| 2 |
+
levelization, each against its definition; the record is paper/runs/paper_verify.json.
|
|
|
|
|
|
|
| 3 |
"""
|
| 4 |
|
| 5 |
from __future__ import annotations
|
|
|
|
| 227 |
"counter_pairs": 65536, "counter_failures": bad_ctr}
|
| 228 |
|
| 229 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
# ---------------------------------------------------------------------------
|
| 231 |
def check_lev_sparse_dense():
|
| 232 |
"""The sparse and dense evaluations of Lev(N_host) agree."""
|
| 233 |
+
print("[5] Lev(N_host): sparse vs dense")
|
| 234 |
import torch
|
| 235 |
from selfrep import LevEvaluator, NetEvaluator, read_host
|
| 236 |
sigma = read_host()
|
|
|
|
| 258 |
check_framing()
|
| 259 |
check_serialization()
|
| 260 |
check_host_datapath()
|
|
|
|
| 261 |
check_lev_sparse_dense()
|
| 262 |
R["seconds"] = time.perf_counter() - t0
|
| 263 |
path = runs_path("paper_verify.json")
|
src/stored_host.py
ADDED
|
@@ -0,0 +1,694 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The host as a stored network of the two-head machine.
|
| 2 |
+
|
| 3 |
+
The two-head machine T_{G,L} of Section 7 is taken with a window of W = 2^ALPHA cells,
|
| 4 |
+
so that a record (w0 code, w1 code, beta, a0, a1, ao) has 8 + 3 ALPHA bits. The host
|
| 5 |
+
H_8, read from its serialization sigma(N_host), is compiled into records of two
|
| 6 |
+
literals each, evaluated in an order in which every unit follows its inputs and the
|
| 7 |
+
next value of each state bit is written over that bit after the last record that
|
| 8 |
+
reads the old one; temporaries share window cells by live interval. One pass of the
|
| 9 |
+
records is one step of H_8 followed by the device of Definition 2.8 acting on the
|
| 10 |
+
tape under the read head, the idle bank under the arm and the copy tape under the
|
| 11 |
+
copy head. A startup block, active in the first pass after a hand-over, loads the
|
| 12 |
+
memory image m* of P*; the hand-over flips the bank bit when the host halts.
|
| 13 |
+
|
| 14 |
+
Run from the image of these records in the active bank and tau* = describe(image) on
|
| 15 |
+
the read tape, P* writes the image into the idle bank, copies tau* onto the copy
|
| 16 |
+
tape and halts, and the hand-over starts the copy.
|
| 17 |
+
|
| 18 |
+
python src/stored_host.py check one pass against H_8 and the device
|
| 19 |
+
python src/stored_host.py build the image, tau*, sizes and digests
|
| 20 |
+
python src/stored_host.py run [GENERATIONS] generations on the machine, in C
|
| 21 |
+
"""
|
| 22 |
+
import hashlib
|
| 23 |
+
import json
|
| 24 |
+
import os
|
| 25 |
+
import random
|
| 26 |
+
import struct
|
| 27 |
+
import subprocess
|
| 28 |
+
import sys
|
| 29 |
+
import time
|
| 30 |
+
|
| 31 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 32 |
+
import selfrep as SR
|
| 33 |
+
|
| 34 |
+
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 35 |
+
RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_stored_host.json')
|
| 36 |
+
|
| 37 |
+
ALPHA = 12
|
| 38 |
+
W = 1 << ALPHA
|
| 39 |
+
B = 8 + 3 * ALPHA
|
| 40 |
+
KAPPA, RD, ARM, CPY, AR, AA, AC, SINK = range(8)
|
| 41 |
+
CW = 20 # width of the device's byte counters
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# ---------------------------------------------------------------------------
|
| 45 |
+
# the host netlist from its serialization
|
| 46 |
+
# ---------------------------------------------------------------------------
|
| 47 |
+
|
| 48 |
+
def host_units():
|
| 49 |
+
data = SR.read_host()
|
| 50 |
+
hlen = struct.unpack('<Q', data[:8])[0]
|
| 51 |
+
head = json.loads(data[8:8 + hlen])
|
| 52 |
+
T = {}
|
| 53 |
+
import array
|
| 54 |
+
for k, spec in head.items():
|
| 55 |
+
if k == '__metadata__':
|
| 56 |
+
continue
|
| 57 |
+
lo, hi = spec['data_offsets']
|
| 58 |
+
a = array.array({'I8': 'b', 'I16': 'h', 'I32': 'i'}[spec['dtype']])
|
| 59 |
+
a.frombytes(data[8 + hlen + lo:8 + hlen + hi])
|
| 60 |
+
T[k] = list(a)
|
| 61 |
+
bias, fanin, pred, nxt = T['net.bias'], T['net.fanin'], T['net.pred'], T['net.next']
|
| 62 |
+
units, p = [], 0
|
| 63 |
+
for j in range(len(bias)):
|
| 64 |
+
units.append((bias[j], [(abs(e) - 1, 1 if e > 0 else -1) for e in pred[p:p + fanin[j]]]))
|
| 65 |
+
p += fanin[j]
|
| 66 |
+
return len(nxt), units, nxt
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
# state layout of sigma: pc bits 0..7 most significant first, halt 8, memory byte j bit k at 9 + 8 j + k,
|
| 70 |
+
# k = 0 the most significant
|
| 71 |
+
def mem_bit(j, t):
|
| 72 |
+
"""State index of bit t (value 2^t) of memory byte j."""
|
| 73 |
+
return 9 + 8 * j + (7 - t)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
PC_BIT = lambda t: 7 - t # bit t of the counter
|
| 77 |
+
HALT = 8
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
# ---------------------------------------------------------------------------
|
| 81 |
+
# records over named cells
|
| 82 |
+
# ---------------------------------------------------------------------------
|
| 83 |
+
|
| 84 |
+
class Prog:
|
| 85 |
+
def __init__(self):
|
| 86 |
+
self.recs = [] # (a0, w0, a1, w1, beta, ao), cells by name
|
| 87 |
+
self.uid = 0
|
| 88 |
+
|
| 89 |
+
def tmp(self):
|
| 90 |
+
self.uid += 1
|
| 91 |
+
return ('t', self.uid)
|
| 92 |
+
|
| 93 |
+
def emit(self, a0, w0, a1, w1, beta, ao):
|
| 94 |
+
assert -8 <= beta <= 7
|
| 95 |
+
self.recs.append((a0 if w0 else ('c', SINK), w0, a1 if w1 else ('c', SINK), w1, beta, ao))
|
| 96 |
+
|
| 97 |
+
def AND(self, x, y, dst):
|
| 98 |
+
(a, pa), (b, pb) = x, y
|
| 99 |
+
self.emit(a, 1 if pa else -1, b, 1 if pb else -1, -(pa + pb), dst)
|
| 100 |
+
|
| 101 |
+
def OR(self, x, y, dst):
|
| 102 |
+
(a, pa), (b, pb) = x, y
|
| 103 |
+
self.emit(a, 1 if pa else -1, b, 1 if pb else -1, 1 - pa - pb, dst)
|
| 104 |
+
|
| 105 |
+
def COPY(self, x, dst):
|
| 106 |
+
a, pa = x
|
| 107 |
+
self.emit(a, 1 if pa else -1, None, 0, -1 if pa else 0, dst)
|
| 108 |
+
|
| 109 |
+
def CONST(self, v, dst):
|
| 110 |
+
# a gate of one literal and its negation: OR is 1, AND is 0
|
| 111 |
+
x = ('c', SINK)
|
| 112 |
+
(self.OR if v else self.AND)((x, True), (x, False), dst)
|
| 113 |
+
|
| 114 |
+
def XOR(self, x, y, dst):
|
| 115 |
+
t1, t2 = self.tmp(), self.tmp()
|
| 116 |
+
self.OR(x, y, t1)
|
| 117 |
+
self.OR((x[0], not x[1]), (y[0], not y[1]), t2)
|
| 118 |
+
self.AND((t1, True), (t2, True), dst)
|
| 119 |
+
|
| 120 |
+
def MUX(self, s, a, b, dst):
|
| 121 |
+
"""dst <- s ? a : b, s a cell, a and b literals."""
|
| 122 |
+
t1, t2 = self.tmp(), self.tmp()
|
| 123 |
+
self.AND((s, True), a, t1)
|
| 124 |
+
self.AND((s, False), b, t2)
|
| 125 |
+
self.OR((t1, True), (t2, True), dst)
|
| 126 |
+
|
| 127 |
+
def chain(self, kind, lits, dst, before=None):
|
| 128 |
+
"""kind 'and' or 'or' of the literals into dst; before(i) emits literal i's signal
|
| 129 |
+
just ahead of its use. dst receives one write, the last."""
|
| 130 |
+
assert lits
|
| 131 |
+
if len(lits) == 1:
|
| 132 |
+
if before:
|
| 133 |
+
before(0)
|
| 134 |
+
self.COPY(lits[0], dst)
|
| 135 |
+
return
|
| 136 |
+
g = self.AND if kind == 'and' else self.OR
|
| 137 |
+
acc = self.tmp()
|
| 138 |
+
if before:
|
| 139 |
+
before(0); before(1)
|
| 140 |
+
if len(lits) == 2:
|
| 141 |
+
g(lits[0], lits[1], dst)
|
| 142 |
+
return
|
| 143 |
+
g(lits[0], lits[1], acc)
|
| 144 |
+
for i in range(2, len(lits)):
|
| 145 |
+
if before:
|
| 146 |
+
before(i)
|
| 147 |
+
g((acc, True), lits[i], dst if i == len(lits) - 1 else acc)
|
| 148 |
+
|
| 149 |
+
def threshold(self, t, lits, dst):
|
| 150 |
+
"""at least t of the literals, by T_t(x1..xk) = T_t(x2..xk) or (x1 and T_{t-1}(x2..xk))."""
|
| 151 |
+
k = len(lits)
|
| 152 |
+
if t <= 0:
|
| 153 |
+
self.CONST(1, dst); return
|
| 154 |
+
if t > k:
|
| 155 |
+
self.CONST(0, dst); return
|
| 156 |
+
if t == 1:
|
| 157 |
+
self.chain('or', lits, dst); return
|
| 158 |
+
if t == k:
|
| 159 |
+
self.chain('and', lits, dst); return
|
| 160 |
+
a, b = self.tmp(), self.tmp()
|
| 161 |
+
self.threshold(t, lits[1:], a)
|
| 162 |
+
self.threshold(t - 1, lits[1:], b)
|
| 163 |
+
c = self.tmp()
|
| 164 |
+
self.AND(lits[0], (b, True), c)
|
| 165 |
+
self.OR((a, True), (c, True), dst)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def compile_host(P):
|
| 169 |
+
"""The records of one step of H_8; state bits are cells ('s', i). A unit read by a single
|
| 170 |
+
unit is emitted just ahead of its use; the next value of each state bit is written over
|
| 171 |
+
the bit after every record that reads the old value."""
|
| 172 |
+
n, units, nxt = host_units()
|
| 173 |
+
cons = {}
|
| 174 |
+
for u, (_, ins) in enumerate(units):
|
| 175 |
+
for s, _w in ins:
|
| 176 |
+
if s >= n:
|
| 177 |
+
cons.setdefault(s - n, []).append(u)
|
| 178 |
+
is_next = {nxt[i] - n: i for i in range(n)}
|
| 179 |
+
assert len(is_next) == n and all(v >= n for v in nxt)
|
| 180 |
+
fusable = {u for u, c in cons.items() if len(c) == 1}
|
| 181 |
+
done, cell = set(), {}
|
| 182 |
+
|
| 183 |
+
def cell_of(s):
|
| 184 |
+
return ('s', s) if s < n else cell[s - n]
|
| 185 |
+
|
| 186 |
+
def ensure_ancestors(u):
|
| 187 |
+
for s, _w in units[u][1]:
|
| 188 |
+
if s >= n:
|
| 189 |
+
v = s - n
|
| 190 |
+
if v in fusable:
|
| 191 |
+
ensure_ancestors(v)
|
| 192 |
+
else:
|
| 193 |
+
need(v)
|
| 194 |
+
|
| 195 |
+
def need(u):
|
| 196 |
+
if u in done:
|
| 197 |
+
return
|
| 198 |
+
assert u not in is_next, 'a next value is read before the state is written'
|
| 199 |
+
ensure_ancestors(u)
|
| 200 |
+
cell[u] = P.tmp()
|
| 201 |
+
emit_unit(u, cell[u])
|
| 202 |
+
done.add(u)
|
| 203 |
+
|
| 204 |
+
def fused(v):
|
| 205 |
+
if v not in done:
|
| 206 |
+
cell[v] = P.tmp()
|
| 207 |
+
emit_unit(v, cell[v])
|
| 208 |
+
done.add(v)
|
| 209 |
+
|
| 210 |
+
def emit_unit(u, dst):
|
| 211 |
+
b, ins = units[u]
|
| 212 |
+
k = len(ins)
|
| 213 |
+
t = sum(1 for _, w in ins if w < 0) - b
|
| 214 |
+
lits = [None] * k
|
| 215 |
+
|
| 216 |
+
def before(i):
|
| 217 |
+
s = ins[i][0]
|
| 218 |
+
if s >= n and (s - n) in fusable:
|
| 219 |
+
fused(s - n)
|
| 220 |
+
lits[i] = (cell_of(s), ins[i][1] > 0)
|
| 221 |
+
if t <= 0 or t > k:
|
| 222 |
+
P.CONST(1 if t <= 0 else 0, dst)
|
| 223 |
+
elif 1 < t < k:
|
| 224 |
+
for i in range(k):
|
| 225 |
+
before(i)
|
| 226 |
+
P.threshold(t, lits, dst)
|
| 227 |
+
else:
|
| 228 |
+
_chain_lazy(P, 'and' if t == k else 'or', lits, dst, before)
|
| 229 |
+
|
| 230 |
+
order_next = [nxt[PC_BIT(t)] - n for t in range(8)] + [nxt[HALT] - n] + \
|
| 231 |
+
[nxt[mem_bit(j, t)] - n for j in range(256) for t in range(8)]
|
| 232 |
+
for u in order_next: # stage A: everything the next values read
|
| 233 |
+
ensure_ancestors(u)
|
| 234 |
+
for u in order_next: # stage B: the next values, in place
|
| 235 |
+
emit_unit(u, ('s', is_next[u]))
|
| 236 |
+
done.add(u)
|
| 237 |
+
return n, units, nxt
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def _chain_lazy(P, kind, lits, dst, before):
|
| 241 |
+
k = len(lits)
|
| 242 |
+
if k == 1:
|
| 243 |
+
before(0)
|
| 244 |
+
P.COPY(lits[0], dst)
|
| 245 |
+
return
|
| 246 |
+
g = P.AND if kind == 'and' else P.OR
|
| 247 |
+
before(0); before(1)
|
| 248 |
+
if k == 2:
|
| 249 |
+
g(lits[0], lits[1], dst)
|
| 250 |
+
return
|
| 251 |
+
acc = P.tmp()
|
| 252 |
+
g(lits[0], lits[1], acc)
|
| 253 |
+
for i in range(2, k):
|
| 254 |
+
before(i)
|
| 255 |
+
g((acc, True), lits[i], dst if i == k - 1 else acc)
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
# ---------------------------------------------------------------------------
|
| 259 |
+
# the device, the startup block and the hand-over
|
| 260 |
+
# ---------------------------------------------------------------------------
|
| 261 |
+
|
| 262 |
+
def mem_cell(j, t):
|
| 263 |
+
return ('s', mem_bit(j, t))
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def byte_is_one(P, j):
|
| 267 |
+
"""[memory byte j == 1]"""
|
| 268 |
+
dst = P.tmp()
|
| 269 |
+
lits = [(mem_cell(j, 0), True)] + [(mem_cell(j, t), False) for t in range(1, 8)]
|
| 270 |
+
P.chain('and', lits, dst)
|
| 271 |
+
return dst
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def compile_device(P):
|
| 275 |
+
cnt = [('d', 'cnt', i) for i in range(CW)]
|
| 276 |
+
lim = [('d', 'lim', i) for i in range(CW)]
|
| 277 |
+
dest = ('d', 'dest')
|
| 278 |
+
wr, rd, rw = byte_is_one(P, SR.C_WR), byte_is_one(P, SR.C_RD), byte_is_one(P, SR.C_RW)
|
| 279 |
+
# [cnt == lim]
|
| 280 |
+
eq = P.tmp()
|
| 281 |
+
xs = []
|
| 282 |
+
for i in range(CW):
|
| 283 |
+
e = P.tmp()
|
| 284 |
+
a1, a0 = P.tmp(), P.tmp()
|
| 285 |
+
P.AND((cnt[i], True), (lim[i], True), a1)
|
| 286 |
+
P.AND((cnt[i], False), (lim[i], False), a0)
|
| 287 |
+
P.OR((a1, True), (a0, True), e)
|
| 288 |
+
xs.append((e, True))
|
| 289 |
+
P.chain('and', xs, eq)
|
| 290 |
+
eot = P.tmp() # the end of the tape is known after the rewind
|
| 291 |
+
P.AND((eq, True), (dest, True), eot)
|
| 292 |
+
# (i) R_out, most significant bit first, under the arm or under the copy head
|
| 293 |
+
ca, cc = P.tmp(), P.tmp()
|
| 294 |
+
P.AND((wr, True), (dest, False), ca)
|
| 295 |
+
P.AND((wr, True), (dest, True), cc)
|
| 296 |
+
for t in range(7, -1, -1):
|
| 297 |
+
P.MUX(ca, (mem_cell(SR.R_OUT, t), True), (('c', ARM), True), ('c', ARM))
|
| 298 |
+
P.COPY((ca, True), ('c', AA))
|
| 299 |
+
P.MUX(cc, (mem_cell(SR.R_OUT, t), True), (('c', CPY), True), ('c', CPY))
|
| 300 |
+
P.COPY((cc, True), ('c', AC))
|
| 301 |
+
for t in range(8):
|
| 302 |
+
P.AND((mem_cell(SR.R_OUT, t), True), (wr, False), mem_cell(SR.R_OUT, t))
|
| 303 |
+
g = P.tmp()
|
| 304 |
+
P.AND((rd, True), (eot, False), g)
|
| 305 |
+
# (ii) the byte under the read head into R_in, most significant bit first, each bit turning the tape
|
| 306 |
+
for t in range(7, -1, -1):
|
| 307 |
+
P.MUX(g, (('c', RD), True), (mem_cell(SR.R_IN, t), True), mem_cell(SR.R_IN, t))
|
| 308 |
+
P.COPY((g, True), ('c', AR))
|
| 309 |
+
# c_eot: bit 0 <- [cnt == lim] on a read, the other bits cleared on a read
|
| 310 |
+
P.MUX(rd, (eot, True), (mem_cell(SR.C_EOT, 0), True), mem_cell(SR.C_EOT, 0))
|
| 311 |
+
for t in range(1, 8):
|
| 312 |
+
P.AND((mem_cell(SR.C_EOT, t), True), (rd, False), mem_cell(SR.C_EOT, t))
|
| 313 |
+
# the counter of bytes read: carries first, then the sum bits
|
| 314 |
+
car = [g]
|
| 315 |
+
for i in range(CW - 1):
|
| 316 |
+
c = P.tmp()
|
| 317 |
+
P.AND((car[-1], True), (cnt[i], True), c)
|
| 318 |
+
car.append(c)
|
| 319 |
+
for i in range(CW):
|
| 320 |
+
P.XOR((cnt[i], True), (car[i], True), cnt[i])
|
| 321 |
+
# (iii) a rewind: the limit takes the count, the count returns to 0, the writes go to the copy tape
|
| 322 |
+
for i in range(CW):
|
| 323 |
+
P.MUX(rw, (cnt[i], True), (lim[i], True), lim[i])
|
| 324 |
+
P.AND((cnt[i], True), (rw, False), cnt[i])
|
| 325 |
+
P.OR((dest, True), (rw, True), dest)
|
| 326 |
+
# (iv) the request cells cleared
|
| 327 |
+
for j in (SR.C_WR, SR.C_RD, SR.C_RW):
|
| 328 |
+
for t in range(8):
|
| 329 |
+
P.CONST(0, mem_cell(j, t))
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def compile_startup(P, mem_image):
|
| 333 |
+
"""Active while 'booted' is 0: the memory image, a zero counter and halt bit, the device
|
| 334 |
+
registers cleared; then 'booted' is set."""
|
| 335 |
+
b = ('d', 'booted')
|
| 336 |
+
for j in range(256):
|
| 337 |
+
for t in range(8):
|
| 338 |
+
c = mem_cell(j, t)
|
| 339 |
+
if (mem_image[j] >> t) & 1:
|
| 340 |
+
P.OR((c, True), (b, False), c) # b ? c : 1
|
| 341 |
+
else:
|
| 342 |
+
P.AND((c, True), (b, True), c) # b ? c : 0
|
| 343 |
+
for t in range(8):
|
| 344 |
+
P.AND((('s', PC_BIT(t)), True), (b, True), ('s', PC_BIT(t)))
|
| 345 |
+
P.AND((('s', HALT), True), (b, True), ('s', HALT))
|
| 346 |
+
for i in range(CW):
|
| 347 |
+
P.AND((('d', 'cnt', i), True), (b, True), ('d', 'cnt', i))
|
| 348 |
+
P.AND((('d', 'lim', i), True), (b, True), ('d', 'lim', i))
|
| 349 |
+
P.AND((('d', 'dest'), True), (b, True), ('d', 'dest'))
|
| 350 |
+
P.CONST(1, b)
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
def compile_handover(P):
|
| 354 |
+
"""When the host has halted: the next pass starts up, and the bank bit flips at the last
|
| 355 |
+
record of the pass."""
|
| 356 |
+
h = ('s', HALT)
|
| 357 |
+
P.AND((('d', 'booted'), True), (h, False), ('d', 'booted'))
|
| 358 |
+
P.XOR((('c', KAPPA), True), (h, True), ('c', KAPPA))
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
# ---------------------------------------------------------------------------
|
| 362 |
+
# allocation and encoding
|
| 363 |
+
# ---------------------------------------------------------------------------
|
| 364 |
+
|
| 365 |
+
def allocate(recs):
|
| 366 |
+
"""Window addresses: the special cells, the state, the device registers, then the
|
| 367 |
+
temporaries by live interval. Every temporary is written before it is read."""
|
| 368 |
+
fixed = {}
|
| 369 |
+
nxt_addr = 8
|
| 370 |
+
names = []
|
| 371 |
+
for r in recs:
|
| 372 |
+
for a in (r[0], r[2], r[5]):
|
| 373 |
+
if a is not None and a[0] in ('s', 'd') and a not in fixed:
|
| 374 |
+
names.append(a)
|
| 375 |
+
fixed[a] = None
|
| 376 |
+
for a in sorted(names, key=lambda x: (x[0], x[1:] if x[0] == 'd' else x[1])) :
|
| 377 |
+
fixed[a] = nxt_addr
|
| 378 |
+
nxt_addr += 1
|
| 379 |
+
first_w, last_r = {}, {}
|
| 380 |
+
for i, (a0, w0, a1, w1, be, ao) in enumerate(recs):
|
| 381 |
+
for a, w in ((a0, w0), (a1, w1)):
|
| 382 |
+
if w and a[0] == 't':
|
| 383 |
+
assert a in first_w, ('read before written', a)
|
| 384 |
+
last_r[a] = i
|
| 385 |
+
if ao[0] == 't':
|
| 386 |
+
first_w.setdefault(ao, i)
|
| 387 |
+
base = nxt_addr
|
| 388 |
+
free_at = {} # cell -> index after which it is free
|
| 389 |
+
addr = dict(fixed)
|
| 390 |
+
for name in sorted(first_w, key=lambda x: first_w[x]):
|
| 391 |
+
start, end = first_w[name], last_r.get(name, first_w[name])
|
| 392 |
+
cand = [c for c, f in free_at.items() if f < start]
|
| 393 |
+
c = min(cand) if cand else base + len(free_at)
|
| 394 |
+
addr[name] = c
|
| 395 |
+
free_at[c] = end
|
| 396 |
+
top = base + len(free_at)
|
| 397 |
+
assert top <= W, ('window too small', top)
|
| 398 |
+
|
| 399 |
+
def res(a):
|
| 400 |
+
if a is None:
|
| 401 |
+
return SINK
|
| 402 |
+
if a[0] == 'c':
|
| 403 |
+
return a[1]
|
| 404 |
+
return addr[a]
|
| 405 |
+
out = [(res(a0), w0, res(a1), w1, be, res(ao)) for (a0, w0, a1, w1, be, ao) in recs]
|
| 406 |
+
return out, addr, top
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
def encode_record(r):
|
| 410 |
+
a0, w0, a1, w1, beta, ao = r
|
| 411 |
+
bits = []
|
| 412 |
+
put = lambda v, w: bits.extend((v >> (w - 1 - j)) & 1 for j in range(w))
|
| 413 |
+
wc = {1: 1, -1: 2, 0: 0}
|
| 414 |
+
put(wc[w0], 2); put(wc[w1], 2); put(beta & 15, 4)
|
| 415 |
+
put(a0, ALPHA); put(a1, ALPHA); put(ao, ALPHA)
|
| 416 |
+
return bits
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def decode_record(bits):
|
| 420 |
+
it = iter(bits)
|
| 421 |
+
get = lambda w: sum(next(it) << (w - 1 - j) for j in range(w))
|
| 422 |
+
c0 = get(2); c1 = get(2); beta = get(4)
|
| 423 |
+
a0 = get(ALPHA); a1 = get(ALPHA); ao = get(ALPHA)
|
| 424 |
+
wd = {1: 1, 2: -1, 0: 0, 3: 0}
|
| 425 |
+
return a0, wd[c0], a1, wd[c1], beta - 16 if beta >= 8 else beta, ao
|
| 426 |
+
|
| 427 |
+
|
| 428 |
+
def bits_to_bytes(bits):
|
| 429 |
+
assert len(bits) % 8 == 0
|
| 430 |
+
return bytes(sum(bits[i + k] << (7 - k) for k in range(8)) for i in range(0, len(bits), 8))
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
def bytes_to_bits(data):
|
| 434 |
+
return [(b >> (7 - k)) & 1 for b in data for k in range(8)]
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def check_schedule(recs, lo, hi, n):
|
| 438 |
+
"""Within the host block recs[lo:hi], every state bit is written once, by the record of its
|
| 439 |
+
next value, and read by no later record; in all records, no temporary is written after
|
| 440 |
+
its last read, so that temporaries with disjoint live intervals may share a cell."""
|
| 441 |
+
written = {}
|
| 442 |
+
for i in range(lo, hi):
|
| 443 |
+
ao = recs[i][5]
|
| 444 |
+
if ao[0] == 's':
|
| 445 |
+
assert ao not in written, ('state bit written twice', ao)
|
| 446 |
+
written[ao] = i
|
| 447 |
+
assert len(written) == n, 'a state bit without its next value'
|
| 448 |
+
for i in range(lo, hi):
|
| 449 |
+
a0, w0, a1, w1, _, _ = recs[i]
|
| 450 |
+
for a, w in ((a0, w0), (a1, w1)):
|
| 451 |
+
if w and a[0] == 's':
|
| 452 |
+
assert i <= written[a], ('state bit read after it is written', a)
|
| 453 |
+
last_r, last_w = {}, {}
|
| 454 |
+
for i, (a0, w0, a1, w1, _, ao) in enumerate(recs):
|
| 455 |
+
for a, w in ((a0, w0), (a1, w1)):
|
| 456 |
+
if w and a[0] == 't':
|
| 457 |
+
last_r[a] = i
|
| 458 |
+
if ao[0] == 't':
|
| 459 |
+
last_w[ao] = i
|
| 460 |
+
assert all(last_w[t] < last_r.get(t, last_w[t] + 1) or t not in last_r for t in last_w), \
|
| 461 |
+
'a temporary written after its last read'
|
| 462 |
+
return dict(state_bits_written=len(written))
|
| 463 |
+
|
| 464 |
+
|
| 465 |
+
def build():
|
| 466 |
+
P = Prog()
|
| 467 |
+
compile_startup(P, SR.M_STAR)
|
| 468 |
+
lo = len(P.recs)
|
| 469 |
+
n, units, nxt = compile_host(P)
|
| 470 |
+
n_host = len(P.recs) - lo
|
| 471 |
+
check_schedule(P.recs, lo, len(P.recs), n)
|
| 472 |
+
compile_device(P)
|
| 473 |
+
compile_handover(P)
|
| 474 |
+
recs, addr, top = allocate(P.recs)
|
| 475 |
+
if len(recs) % 2: # an image of whole bytes
|
| 476 |
+
recs.insert(len(recs) - 3, (SINK, 0, SINK, 0, -1, SINK))
|
| 477 |
+
image_bits = [b for r in recs for b in encode_record(r)]
|
| 478 |
+
image = bits_to_bytes(image_bits)
|
| 479 |
+
tau = SR.describe(image)
|
| 480 |
+
assert SR.decode(tau) == image
|
| 481 |
+
return dict(recs=recs, addr=addr, top=top, image=image, image_bits=image_bits, tau=tau,
|
| 482 |
+
n_host_records=n_host, host=(n, units, nxt))
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
# ---------------------------------------------------------------------------
|
| 486 |
+
# the machine, transcribed
|
| 487 |
+
# ---------------------------------------------------------------------------
|
| 488 |
+
|
| 489 |
+
class Machine:
|
| 490 |
+
"""T_{G,L} with a window of W cells; banks and tapes listed from their heads."""
|
| 491 |
+
def __init__(self, Q0, Q1, D0, D1, window):
|
| 492 |
+
self.Q = [list(Q0), list(Q1)]
|
| 493 |
+
self.D = [list(D0), list(D1)]
|
| 494 |
+
self.h = [[0, 0], [0, 0]] # heads of the banks and of the tapes
|
| 495 |
+
self.w = list(window)
|
| 496 |
+
self.N, self.L = len(Q0), len(D0)
|
| 497 |
+
|
| 498 |
+
def cell(self, a):
|
| 499 |
+
k = self.w[KAPPA]
|
| 500 |
+
if a == RD:
|
| 501 |
+
return self.D[k][self.h[1][k]]
|
| 502 |
+
if a == ARM:
|
| 503 |
+
return self.Q[1 - k][self.h[0][1 - k]]
|
| 504 |
+
if a == CPY:
|
| 505 |
+
return self.D[1 - k][self.h[1][1 - k]]
|
| 506 |
+
return self.w[a]
|
| 507 |
+
|
| 508 |
+
def step(self, rec=None):
|
| 509 |
+
k = self.w[KAPPA]
|
| 510 |
+
if rec is None:
|
| 511 |
+
hq = self.h[0][k]
|
| 512 |
+
rec = decode_record([self.Q[k][(hq + i) % self.N] for i in range(B)])
|
| 513 |
+
a0, w0, a1, w1, beta, ao = rec
|
| 514 |
+
v = 1 if w0 * self.cell(a0) + w1 * self.cell(a1) + beta >= 0 else 0
|
| 515 |
+
if ao == ARM:
|
| 516 |
+
self.Q[1 - k][self.h[0][1 - k]] = v
|
| 517 |
+
elif ao == CPY:
|
| 518 |
+
self.D[1 - k][self.h[1][1 - k]] = v
|
| 519 |
+
elif ao != RD:
|
| 520 |
+
self.w[ao] = v
|
| 521 |
+
self.h[0][k] = (self.h[0][k] + B) % self.N
|
| 522 |
+
if self.w[AA]:
|
| 523 |
+
self.h[0][1 - k] = (self.h[0][1 - k] + 1) % self.N
|
| 524 |
+
if self.w[AR]:
|
| 525 |
+
self.h[1][k] = (self.h[1][k] + 1) % self.L
|
| 526 |
+
if self.w[AC]:
|
| 527 |
+
self.h[1][1 - k] = (self.h[1][1 - k] + 1) % self.L
|
| 528 |
+
self.w[AA] = self.w[AR] = self.w[AC] = 0
|
| 529 |
+
|
| 530 |
+
|
| 531 |
+
# ---------------------------------------------------------------------------
|
| 532 |
+
# one pass against H_8 and the device
|
| 533 |
+
# ---------------------------------------------------------------------------
|
| 534 |
+
|
| 535 |
+
def host_step(n, units, nxt, x):
|
| 536 |
+
sig = list(x) + [0] * len(units)
|
| 537 |
+
for u, (b, ins) in enumerate(units):
|
| 538 |
+
sig[n + u] = 1 if b + sum(w * sig[s] for s, w in ins) >= 0 else 0
|
| 539 |
+
return [sig[v] for v in nxt]
|
| 540 |
+
|
| 541 |
+
|
| 542 |
+
def check(trials=40, seed=3, verbose=False):
|
| 543 |
+
S = build()
|
| 544 |
+
recs, addr = S['recs'], S['addr']
|
| 545 |
+
n, units, nxt = S['host']
|
| 546 |
+
G = len(recs)
|
| 547 |
+
rng = random.Random(seed)
|
| 548 |
+
bad = 0
|
| 549 |
+
image_bits = [b for r in recs for b in encode_record(r)]
|
| 550 |
+
x0 = [0] * n # the state x_0(m*)
|
| 551 |
+
for j in range(256):
|
| 552 |
+
for t in range(8):
|
| 553 |
+
x0[mem_bit(j, t)] = (SR.M_STAR[j] >> t) & 1
|
| 554 |
+
for trial in range(trials):
|
| 555 |
+
# a random host state with random device registers, temporaries and tapes; every fifth
|
| 556 |
+
# state not yet booted, and in every third the requests hold random bytes
|
| 557 |
+
x = [rng.randrange(2) for _ in range(n)]
|
| 558 |
+
x[HALT] = 0 if trial % 4 else 1
|
| 559 |
+
booted = 0 if trial % 5 == 0 else 1
|
| 560 |
+
for j in (SR.C_WR, SR.C_RD, SR.C_RW):
|
| 561 |
+
v = rng.randrange(256) if trial % 3 == 0 else rng.choice((0, 1))
|
| 562 |
+
for t in range(8):
|
| 563 |
+
x[mem_bit(j, t)] = (v >> t) & 1
|
| 564 |
+
L = 64
|
| 565 |
+
cnt, lim = rng.randrange(8), rng.randrange(8)
|
| 566 |
+
dest = rng.randrange(2)
|
| 567 |
+
win = [rng.randrange(2) for _ in range(W)]
|
| 568 |
+
win[KAPPA] = 0
|
| 569 |
+
for i in range(n):
|
| 570 |
+
win[addr[('s', i)]] = x[i]
|
| 571 |
+
for i in range(CW):
|
| 572 |
+
win[addr[('d', 'cnt', i)]] = (cnt >> i) & 1
|
| 573 |
+
win[addr[('d', 'lim', i)]] = (lim >> i) & 1
|
| 574 |
+
win[addr[('d', 'dest')]] = dest
|
| 575 |
+
win[addr[('d', 'booted')]] = booted
|
| 576 |
+
win[AR] = win[AA] = win[AC] = 0
|
| 577 |
+
D0 = [rng.randrange(2) for _ in range(L)]
|
| 578 |
+
Q1 = [rng.randrange(2) for _ in range(len(image_bits))]
|
| 579 |
+
D1 = [rng.randrange(2) for _ in range(L)]
|
| 580 |
+
M = Machine(image_bits, Q1, D0, D1, win)
|
| 581 |
+
for g in range(G):
|
| 582 |
+
M.step(recs[g])
|
| 583 |
+
# expected: the startup if not booted, one step of H_8, then the device on the ring tapes
|
| 584 |
+
if not booted:
|
| 585 |
+
x, cnt, lim, dest = list(x0), 0, 0, 0
|
| 586 |
+
y = host_step(n, units, nxt, x)
|
| 587 |
+
get = lambda j: sum(y[mem_bit(j, t)] << t for t in range(8))
|
| 588 |
+
|
| 589 |
+
def put(j, v):
|
| 590 |
+
for t in range(8):
|
| 591 |
+
y[mem_bit(j, t)] = (v >> t) & 1
|
| 592 |
+
e_q1, e_d1, hq1, hd0, hd1 = list(Q1), list(D1), 0, 0, 0
|
| 593 |
+
e_cnt, e_lim, e_dest = cnt, lim, dest
|
| 594 |
+
if get(SR.C_WR) == 1:
|
| 595 |
+
byte = get(SR.R_OUT)
|
| 596 |
+
for kk in range(8):
|
| 597 |
+
bit = (byte >> (7 - kk)) & 1
|
| 598 |
+
if e_dest:
|
| 599 |
+
e_d1[hd1] = bit; hd1 += 1
|
| 600 |
+
else:
|
| 601 |
+
e_q1[hq1] = bit; hq1 += 1
|
| 602 |
+
put(SR.R_OUT, 0)
|
| 603 |
+
if get(SR.C_RD) == 1:
|
| 604 |
+
if not (e_dest and e_cnt == e_lim):
|
| 605 |
+
put(SR.R_IN, sum(D0[hd0 + kk] << (7 - kk) for kk in range(8)))
|
| 606 |
+
hd0 += 8
|
| 607 |
+
put(SR.C_EOT, 0)
|
| 608 |
+
e_cnt = (e_cnt + 1) % (1 << CW)
|
| 609 |
+
else:
|
| 610 |
+
put(SR.C_EOT, 1)
|
| 611 |
+
if get(SR.C_RW) == 1:
|
| 612 |
+
e_lim, e_cnt, e_dest = e_cnt, 0, 1
|
| 613 |
+
put(SR.C_WR, 0); put(SR.C_RD, 0); put(SR.C_RW, 0)
|
| 614 |
+
e_kappa = 1 if y[HALT] else 0
|
| 615 |
+
got = [M.w[addr[('s', i)]] for i in range(n)]
|
| 616 |
+
g_cnt = sum(M.w[addr[('d', 'cnt', i)]] << i for i in range(CW))
|
| 617 |
+
g_lim = sum(M.w[addr[('d', 'lim', i)]] << i for i in range(CW))
|
| 618 |
+
parts = dict(state=got == y, cnt=g_cnt == e_cnt, lim=g_lim == e_lim,
|
| 619 |
+
dest=M.w[addr[('d', 'dest')]] == e_dest, bank=M.Q[1] == e_q1, copy=M.D[1] == e_d1,
|
| 620 |
+
arm=M.h[0][1] == hq1, read=M.h[1][0] == hd0, copyhead=M.h[1][1] == hd1,
|
| 621 |
+
kappa=M.w[KAPPA] == e_kappa, tape=M.D[0] == D0,
|
| 622 |
+
booted=M.w[addr[('d', 'booted')]] == 1 - y[HALT],
|
| 623 |
+
requests=M.w[AR] == M.w[AA] == M.w[AC] == 0, active=M.Q[0] == image_bits)
|
| 624 |
+
ok = all(parts.values())
|
| 625 |
+
if not ok and verbose:
|
| 626 |
+
print(trial, [k for k, v in parts.items() if not v], 'reqs',
|
| 627 |
+
[get(j) for j in (SR.C_WR, SR.C_RD, SR.C_RW)], 'dest', dest, 'cnt', cnt, 'lim', lim,
|
| 628 |
+
'halt', x[HALT], [i for i in range(n) if got[i] != y[i]][:10])
|
| 629 |
+
bad += not ok
|
| 630 |
+
return dict(trials=trials, disagreements=bad, records=G, window_cells=S['top'])
|
| 631 |
+
|
| 632 |
+
|
| 633 |
+
def update_record(key, value):
|
| 634 |
+
rec = json.load(open(RECORD)) if os.path.exists(RECORD) else {}
|
| 635 |
+
rec[key] = value
|
| 636 |
+
json.dump(rec, open(RECORD, 'w'), indent=1)
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
def run(generations):
|
| 640 |
+
"""Generations from the image in the active bank and tau* on the read tape, on the
|
| 641 |
+
machine in C, against the reference run of P* on tau*."""
|
| 642 |
+
S = build()
|
| 643 |
+
recs, image_bits, tau = S['recs'], S['image_bits'], S['tau']
|
| 644 |
+
G = len(recs)
|
| 645 |
+
out, steps = SR.run_reference(SR.M_STAR, tau)
|
| 646 |
+
assert out == S['image'] + tau
|
| 647 |
+
tau_bits = bytes_to_bits(tau)
|
| 648 |
+
work = os.path.join(REPO, 'variants')
|
| 649 |
+
inp, exe = os.path.join(work, '.stored_host.bin'), os.path.join(work, '.stored_host_run')
|
| 650 |
+
with open(inp, 'wb') as f:
|
| 651 |
+
f.write(struct.pack('<4i', W, ALPHA, G, len(tau_bits)))
|
| 652 |
+
f.write(bytes(image_bits) + bytes(tau_bits) + bytes(W))
|
| 653 |
+
subprocess.run(['gcc', '-O3', '-march=native', '-o', exe, os.path.join(REPO, 'src', 'stored_host_run.c')], check=True)
|
| 654 |
+
t0 = time.time()
|
| 655 |
+
p = subprocess.run([exe, inp, str(generations)], capture_output=True, text=True)
|
| 656 |
+
os.remove(inp); os.remove(exe)
|
| 657 |
+
lines = [json.loads(l) for l in p.stdout.split('\n') if l.strip()]
|
| 658 |
+
gens = [l for l in lines if 'generation' in l]
|
| 659 |
+
res = dict(records=G, window_cells=S['top'], record_bits=B, bank_bits=len(image_bits),
|
| 660 |
+
image_bytes=len(S['image']), tau_bytes=len(tau), passes_expected=steps,
|
| 661 |
+
generations=gens, seconds=round(time.time() - t0, 1),
|
| 662 |
+
sha256_image=hashlib.sha256(S['image']).hexdigest(),
|
| 663 |
+
sha256_tau=hashlib.sha256(tau).hexdigest())
|
| 664 |
+
for l in lines:
|
| 665 |
+
if 'state_after_3_equals_after_1' in l:
|
| 666 |
+
res['state_after_3_equals_after_1'] = l['state_after_3_equals_after_1']
|
| 667 |
+
res['every_generation_exact'] = all(g['passes'] == steps and g['steps'] == steps * G and g['bank_holds_image']
|
| 668 |
+
and g['tape_holds_tau'] for g in gens) and len(gens) == generations
|
| 669 |
+
update_record('run', res)
|
| 670 |
+
return res
|
| 671 |
+
|
| 672 |
+
|
| 673 |
+
if __name__ == '__main__':
|
| 674 |
+
cmd = sys.argv[1] if len(sys.argv) > 1 else 'build'
|
| 675 |
+
if cmd == 'check':
|
| 676 |
+
t0 = time.time()
|
| 677 |
+
res = check(int(sys.argv[2]) if len(sys.argv) > 2 else 40)
|
| 678 |
+
res['seconds'] = round(time.time() - t0, 1)
|
| 679 |
+
update_record('pass_check', res)
|
| 680 |
+
print(json.dumps(res))
|
| 681 |
+
sys.exit(0 if res['disagreements'] == 0 else 1)
|
| 682 |
+
elif cmd == 'run':
|
| 683 |
+
gens = int(sys.argv[2]) if len(sys.argv) > 2 else 3
|
| 684 |
+
res = run(gens)
|
| 685 |
+
print(json.dumps(res, indent=1))
|
| 686 |
+
sys.exit(0 if res['every_generation_exact'] and (gens < 3 or res.get('state_after_3_equals_after_1') == 1)
|
| 687 |
+
else 1)
|
| 688 |
+
elif cmd == 'build':
|
| 689 |
+
t0 = time.time()
|
| 690 |
+
S = build()
|
| 691 |
+
print(json.dumps(dict(records=len(S['recs']), host_records=S['n_host_records'],
|
| 692 |
+
window_cells=S['top'], record_bits=B, bank_bits=len(S['image_bits']),
|
| 693 |
+
image_bytes=len(S['image']), tau_bytes=len(S['tau']),
|
| 694 |
+
seconds=round(time.time() - t0, 1))))
|
src/stored_host_run.c
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Generations of the stored host on the two-head machine T_{G,L} with a window of W cells.
|
| 2 |
+
*
|
| 3 |
+
* stored_host_run IN.bin GENERATIONS
|
| 4 |
+
*
|
| 5 |
+
* IN.bin holds little-endian int32 W, ALPHA, G, L, then the G * (8 + 3 ALPHA) bits of the
|
| 6 |
+
* image, the L bits of tau*, and the W cells of the initial window, one byte per bit. The
|
| 7 |
+
* banks start with the image in Q0 and Q1 clear, the tapes with tau* on D0 and D1 clear.
|
| 8 |
+
* A step reads the record in front of the active bank, writes v = H(w0 x0 + w1 x1 + beta)
|
| 9 |
+
* into the window, under the arm or under the copy head, turns the active bank by one
|
| 10 |
+
* record and the other three by one cell on request, and clears the requests. The active
|
| 11 |
+
* bank is never written, so its records are decoded once each time the bank bit changes.
|
| 12 |
+
* After every generation, at the step that changes the bank bit, the program reports the
|
| 13 |
+
* steps it took, whether the new active bank holds the image and the new read tape holds
|
| 14 |
+
* tau*, the positions of the heads and a digest of the window.
|
| 15 |
+
*/
|
| 16 |
+
#include <stdint.h>
|
| 17 |
+
#include <stdio.h>
|
| 18 |
+
#include <stdlib.h>
|
| 19 |
+
#include <string.h>
|
| 20 |
+
|
| 21 |
+
typedef struct { int a0, w0, a1, w1, beta, ao; } rec_t;
|
| 22 |
+
|
| 23 |
+
static int W, ALPHA, B, G, N, L;
|
| 24 |
+
|
| 25 |
+
static rec_t decode(const unsigned char *bits) {
|
| 26 |
+
int p = 0;
|
| 27 |
+
#define GET(w) ({ int v_ = 0; for (int j_ = 0; j_ < (w); j_++) v_ = (v_ << 1) | bits[p++]; v_; })
|
| 28 |
+
int c0 = GET(2), c1 = GET(2), beta = GET(4);
|
| 29 |
+
int a0 = GET(ALPHA), a1 = GET(ALPHA), ao = GET(ALPHA);
|
| 30 |
+
#undef GET
|
| 31 |
+
rec_t r;
|
| 32 |
+
r.w0 = c0 == 1 ? 1 : c0 == 2 ? -1 : 0;
|
| 33 |
+
r.w1 = c1 == 1 ? 1 : c1 == 2 ? -1 : 0;
|
| 34 |
+
r.beta = beta >= 8 ? beta - 16 : beta;
|
| 35 |
+
r.a0 = a0; r.a1 = a1; r.ao = ao;
|
| 36 |
+
return r;
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
static uint64_t fnv(const unsigned char *p, size_t n) {
|
| 40 |
+
uint64_t h = 1469598103934665603ULL;
|
| 41 |
+
for (size_t i = 0; i < n; i++) { h ^= p[i]; h *= 1099511628211ULL; }
|
| 42 |
+
return h;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
int main(int argc, char **argv) {
|
| 46 |
+
FILE *f = fopen(argv[1], "rb");
|
| 47 |
+
int gens = atoi(argv[2]);
|
| 48 |
+
int hdr[4];
|
| 49 |
+
if (fread(hdr, 4, 4, f) != 4) return 1;
|
| 50 |
+
W = hdr[0]; ALPHA = hdr[1]; G = hdr[2]; L = hdr[3];
|
| 51 |
+
B = 8 + 3 * ALPHA; N = G * B;
|
| 52 |
+
unsigned char *image = malloc(N), *tau = malloc(L), *win = malloc(W);
|
| 53 |
+
if (fread(image, 1, N, f) != (size_t)N || fread(tau, 1, L, f) != (size_t)L || fread(win, 1, W, f) != (size_t)W) return 1;
|
| 54 |
+
fclose(f);
|
| 55 |
+
unsigned char *Q[2] = { malloc(N), calloc(N, 1) }, *D[2] = { malloc(L), calloc(L, 1) };
|
| 56 |
+
memcpy(Q[0], image, N); memcpy(D[0], tau, L);
|
| 57 |
+
long hq[2] = {0, 0}, hd[2] = {0, 0};
|
| 58 |
+
rec_t *recs = malloc(sizeof(rec_t) * G);
|
| 59 |
+
int k = win[0];
|
| 60 |
+
for (int g = 0; g < G; g++) recs[g] = decode(Q[k] + (size_t)g * B);
|
| 61 |
+
long ridx = 0; /* the record in front of the active bank */
|
| 62 |
+
if (gens == 0) { /* a fixed number of steps, for comparison */
|
| 63 |
+
long long n = atoll(argv[3]);
|
| 64 |
+
for (long long s = 0; s < n; s++) {
|
| 65 |
+
k = win[0];
|
| 66 |
+
const rec_t *r = &recs[ridx];
|
| 67 |
+
int ki = 1 - k;
|
| 68 |
+
int x0 = r->w0 ? (r->a0 == 1 ? D[k][hd[k]] : r->a0 == 2 ? Q[ki][hq[ki]] : r->a0 == 3 ? D[ki][hd[ki]] : win[r->a0]) : 0;
|
| 69 |
+
int x1 = r->w1 ? (r->a1 == 1 ? D[k][hd[k]] : r->a1 == 2 ? Q[ki][hq[ki]] : r->a1 == 3 ? D[ki][hd[ki]] : win[r->a1]) : 0;
|
| 70 |
+
int v = r->w0 * x0 + r->w1 * x1 + r->beta >= 0;
|
| 71 |
+
if (r->ao == 2) Q[ki][hq[ki]] = v; else if (r->ao == 3) D[ki][hd[ki]] = v; else if (r->ao != 1) win[r->ao] = v;
|
| 72 |
+
ridx = ridx + 1 == G ? 0 : ridx + 1;
|
| 73 |
+
hq[k] = (hq[k] + B) % N;
|
| 74 |
+
if (win[5]) hq[ki] = (hq[ki] + 1) % N;
|
| 75 |
+
if (win[4]) hd[k] = (hd[k] + 1) % L;
|
| 76 |
+
if (win[6]) hd[ki] = (hd[ki] + 1) % L;
|
| 77 |
+
win[4] = win[5] = win[6] = 0;
|
| 78 |
+
if (win[0] != k) { k = win[0]; for (int g = 0; g < G; g++) recs[g] = decode(Q[k] + (size_t)g * B); }
|
| 79 |
+
}
|
| 80 |
+
printf("{\"win\": \"%016llx\", \"q0\": \"%016llx\", \"q1\": \"%016llx\", \"d0\": \"%016llx\", \"d1\": \"%016llx\", \"heads\": [%ld, %ld, %ld, %ld]}\n",
|
| 81 |
+
(unsigned long long)fnv(win, W), (unsigned long long)fnv(Q[0], N), (unsigned long long)fnv(Q[1], N),
|
| 82 |
+
(unsigned long long)fnv(D[0], L), (unsigned long long)fnv(D[1], L), hq[0], hq[1], hd[0], hd[1]);
|
| 83 |
+
return 0;
|
| 84 |
+
}
|
| 85 |
+
unsigned char *first_state = NULL; size_t state_size = 0;
|
| 86 |
+
for (int gen = 1; gen <= gens; gen++) {
|
| 87 |
+
long long steps = 0;
|
| 88 |
+
for (;;) {
|
| 89 |
+
k = win[0];
|
| 90 |
+
const rec_t *r = &recs[ridx];
|
| 91 |
+
int ki = 1 - k;
|
| 92 |
+
#define CELL(a) ((a) == 1 ? D[k][hd[k]] : (a) == 2 ? Q[ki][hq[ki]] : (a) == 3 ? D[ki][hd[ki]] : win[(a)])
|
| 93 |
+
int x0 = r->w0 ? CELL(r->a0) : 0, x1 = r->w1 ? CELL(r->a1) : 0;
|
| 94 |
+
int v = r->w0 * x0 + r->w1 * x1 + r->beta >= 0;
|
| 95 |
+
int ao = r->ao;
|
| 96 |
+
if (ao == 2) Q[ki][hq[ki]] = v;
|
| 97 |
+
else if (ao == 3) D[ki][hd[ki]] = v;
|
| 98 |
+
else if (ao != 1) win[ao] = v;
|
| 99 |
+
ridx = ridx + 1 == G ? 0 : ridx + 1; /* the active bank turns by one record */
|
| 100 |
+
if (win[5]) hq[ki] = hq[ki] + 1 == N ? 0 : hq[ki] + 1;
|
| 101 |
+
if (win[4]) hd[k] = hd[k] + 1 == L ? 0 : hd[k] + 1;
|
| 102 |
+
if (win[6]) hd[ki] = hd[ki] + 1 == L ? 0 : hd[ki] + 1;
|
| 103 |
+
win[4] = win[5] = win[6] = 0;
|
| 104 |
+
steps++;
|
| 105 |
+
if (win[0] != k) break;
|
| 106 |
+
}
|
| 107 |
+
k = win[0];
|
| 108 |
+
/* the bank that was active turned by whole passes and is back at its first record */
|
| 109 |
+
if (ridx != 0) { fprintf(stderr, "hand-over inside a pass\n"); return 1; }
|
| 110 |
+
int bank_ok = memcmp(Q[k], image, N) == 0 && hq[k] == 0;
|
| 111 |
+
int tape_ok = memcmp(D[k], tau, L) == 0 && hd[k] == 0;
|
| 112 |
+
printf("{\"generation\": %d, \"steps\": %lld, \"passes\": %lld, \"kappa\": %d, \"bank_holds_image\": %d, "
|
| 113 |
+
"\"tape_holds_tau\": %d, \"heads\": [%ld, %ld, %ld, %ld], \"window_fnv\": \"%016llx\"}\n",
|
| 114 |
+
gen, steps, steps / G, k, bank_ok, tape_ok, hq[0], hq[1], hd[0], hd[1],
|
| 115 |
+
(unsigned long long)fnv(win, W));
|
| 116 |
+
fflush(stdout);
|
| 117 |
+
/* the full state after the first and the third generation */
|
| 118 |
+
size_t sz = (size_t)W + 2 * (size_t)N + 2 * (size_t)L;
|
| 119 |
+
unsigned char *st = malloc(sz);
|
| 120 |
+
memcpy(st, win, W); memcpy(st + W, Q[0], N); memcpy(st + W + N, Q[1], N);
|
| 121 |
+
memcpy(st + W + 2 * (size_t)N, D[0], L); memcpy(st + W + 2 * (size_t)N + L, D[1], L);
|
| 122 |
+
if (gen == 1) { first_state = st; state_size = sz; }
|
| 123 |
+
else {
|
| 124 |
+
if (gen == 3) printf("{\"state_after_3_equals_after_1\": %d}\n", memcmp(st, first_state, state_size) == 0);
|
| 125 |
+
free(st);
|
| 126 |
+
}
|
| 127 |
+
for (int g = 0; g < G; g++) recs[g] = decode(Q[k] + (size_t)g * B);
|
| 128 |
+
}
|
| 129 |
+
return 0;
|
| 130 |
+
}
|
src/twohead.py
CHANGED
|
@@ -116,20 +116,20 @@ class Asm:
|
|
| 116 |
return self
|
| 117 |
|
| 118 |
|
| 119 |
-
def encode_record(r):
|
| 120 |
-
"""r = (a0, w0, a1, w1, beta, ao), laid out gate first."""
|
| 121 |
a0, w0, a1, w1, beta, ao = r
|
| 122 |
bits = []
|
| 123 |
put = lambda val, w: bits.extend((val >> (w - 1 - j)) & 1 for j in range(w))
|
| 124 |
wc = {1: 1, -1: 2, 0: 0}
|
| 125 |
-
put(wc[w0], 2); put(wc[w1], 2); put(beta & 15, 4); put(a0,
|
| 126 |
return bits
|
| 127 |
|
| 128 |
|
| 129 |
-
def decode_record(bits):
|
| 130 |
it = iter(bits)
|
| 131 |
get = lambda w: sum(next(it) << (w - 1 - j) for j in range(w))
|
| 132 |
-
c0 = get(2); c1 = get(2); beta = get(4); a0 = get(
|
| 133 |
wd = {1: 1, 2: -1, 0: 0, 3: 0}
|
| 134 |
return a0, wd[c0], a1, wd[c1], beta - 16 if beta >= 8 else beta, ao
|
| 135 |
|
|
@@ -182,12 +182,14 @@ def translate(desc):
|
|
| 182 |
|
| 183 |
|
| 184 |
class Machine:
|
| 185 |
-
"""The physics, transcribed: tapes listed from their heads."""
|
| 186 |
-
def __init__(self, G, L, Q0, Q1, D0, D1, window):
|
| 187 |
-
self.
|
|
|
|
| 188 |
self.Q = [list(Q0), list(Q1)]
|
| 189 |
self.D = [list(D0), list(D1)]
|
| 190 |
self.w = list(window)
|
|
|
|
| 191 |
self.steps = 0
|
| 192 |
|
| 193 |
def cell(self, a):
|
|
@@ -202,7 +204,7 @@ class Machine:
|
|
| 202 |
|
| 203 |
def step(self):
|
| 204 |
k = self.w[KAPPA]
|
| 205 |
-
a0, w0, a1, w1, beta, ao = decode_record(self.Q[k][:B])
|
| 206 |
val = 1 if w0 * self.cell(a0) + w1 * self.cell(a1) + beta >= 0 else 0
|
| 207 |
if ao == ARM:
|
| 208 |
self.Q[1 - k][0] = val
|
|
@@ -211,7 +213,7 @@ class Machine:
|
|
| 211 |
elif ao != RD:
|
| 212 |
self.w[ao] = val
|
| 213 |
rot = lambda t, s: t[s:] + t[:s]
|
| 214 |
-
self.Q[k] = rot(self.Q[k], B)
|
| 215 |
if self.w[AA]:
|
| 216 |
self.Q[1 - k] = rot(self.Q[1 - k], 1)
|
| 217 |
if self.w[AR]:
|
|
|
|
| 116 |
return self
|
| 117 |
|
| 118 |
|
| 119 |
+
def encode_record(r, alpha=ALPHA):
|
| 120 |
+
"""r = (a0, w0, a1, w1, beta, ao), laid out gate first, with addresses of alpha bits."""
|
| 121 |
a0, w0, a1, w1, beta, ao = r
|
| 122 |
bits = []
|
| 123 |
put = lambda val, w: bits.extend((val >> (w - 1 - j)) & 1 for j in range(w))
|
| 124 |
wc = {1: 1, -1: 2, 0: 0}
|
| 125 |
+
put(wc[w0], 2); put(wc[w1], 2); put(beta & 15, 4); put(a0, alpha); put(a1, alpha); put(ao, alpha)
|
| 126 |
return bits
|
| 127 |
|
| 128 |
|
| 129 |
+
def decode_record(bits, alpha=ALPHA):
|
| 130 |
it = iter(bits)
|
| 131 |
get = lambda w: sum(next(it) << (w - 1 - j) for j in range(w))
|
| 132 |
+
c0 = get(2); c1 = get(2); beta = get(4); a0 = get(alpha); a1 = get(alpha); ao = get(alpha)
|
| 133 |
wd = {1: 1, 2: -1, 0: 0, 3: 0}
|
| 134 |
return a0, wd[c0], a1, wd[c1], beta - 16 if beta >= 8 else beta, ao
|
| 135 |
|
|
|
|
| 182 |
|
| 183 |
|
| 184 |
class Machine:
|
| 185 |
+
"""The physics, transcribed: tapes listed from their heads; a window of 2^alpha cells."""
|
| 186 |
+
def __init__(self, G, L, Q0, Q1, D0, D1, window, alpha=ALPHA):
|
| 187 |
+
self.alpha, self.B = alpha, 8 + 3 * alpha
|
| 188 |
+
self.G, self.N, self.L = G, G * self.B, L
|
| 189 |
self.Q = [list(Q0), list(Q1)]
|
| 190 |
self.D = [list(D0), list(D1)]
|
| 191 |
self.w = list(window)
|
| 192 |
+
assert len(self.w) == 1 << alpha
|
| 193 |
self.steps = 0
|
| 194 |
|
| 195 |
def cell(self, a):
|
|
|
|
| 204 |
|
| 205 |
def step(self):
|
| 206 |
k = self.w[KAPPA]
|
| 207 |
+
a0, w0, a1, w1, beta, ao = decode_record(self.Q[k][:self.B], self.alpha)
|
| 208 |
val = 1 if w0 * self.cell(a0) + w1 * self.cell(a1) + beta >= 0 else 0
|
| 209 |
if ao == ARM:
|
| 210 |
self.Q[1 - k][0] = val
|
|
|
|
| 213 |
elif ao != RD:
|
| 214 |
self.w[ao] = val
|
| 215 |
rot = lambda t, s: t[s:] + t[:s]
|
| 216 |
+
self.Q[k] = rot(self.Q[k], self.B)
|
| 217 |
if self.w[AA]:
|
| 218 |
self.Q[1 - k] = rot(self.Q[1 - k], 1)
|
| 219 |
if self.w[AR]:
|
src/twohead_net.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
| 1 |
"""The two-head physics as a netlist of ternary threshold units.
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
tape bit's next value: the active bank
|
| 9 |
-
under the arm and turned by one cell on
|
| 10 |
-
likewise. The unit order is the order of
|
| 11 |
-
unit for unit.
|
|
|
|
| 12 |
|
| 13 |
python src/twohead_net.py check one step against the transcription on random states
|
| 14 |
python src/twohead_net.py export [PATH] the netlist file (default variants/twohead_physics.bin)
|
|
@@ -59,7 +60,10 @@ class Net:
|
|
| 59 |
return self.OR((self.AND((s, True), (a, True)), True), (self.AND((s, False), (b, True)), True))
|
| 60 |
|
| 61 |
|
| 62 |
-
def build(G, L):
|
|
|
|
|
|
|
|
|
|
| 63 |
N = G * B
|
| 64 |
real = [0] + list(range(4, W)) # window cells held in the state
|
| 65 |
wpos = {a: i for i, a in enumerate(real)}
|
|
@@ -70,7 +74,8 @@ def build(G, L):
|
|
| 70 |
kap = wpos[KAPPA]
|
| 71 |
# the record in front of the active bank
|
| 72 |
f = [net.MUX(kap, q1 + j, q0 + j) for j in range(B)]
|
| 73 |
-
c0, c1, be
|
|
|
|
| 74 |
# the cells under the three heads
|
| 75 |
rd = net.MUX(kap, d1, d0)
|
| 76 |
armv = net.MUX(kap, q0, q1)
|
|
@@ -81,8 +86,8 @@ def build(G, L):
|
|
| 81 |
def decode(field):
|
| 82 |
lines = []
|
| 83 |
for a in range(W):
|
| 84 |
-
bits = [(a >> (
|
| 85 |
-
lines.append(net.u(-sum(bits), [(field[j], 1 if bits[j] else -1) for j in range(
|
| 86 |
return lines
|
| 87 |
|
| 88 |
l0, l1, lo = decode(a0), decode(a1), decode(ao)
|
|
@@ -142,7 +147,16 @@ def build(G, L):
|
|
| 142 |
for i in range(L):
|
| 143 |
nxt[base + i] = net.MUX(rot, hat((i + 1) % L), hat(i))
|
| 144 |
assert all(x is not None for x in nxt)
|
| 145 |
-
return net, nxt, dict(real=real, q0=q0, q1=q1, d0=d0, d1=d1, n=n, N=N, L=L)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
|
| 148 |
def stats(net, nxt):
|
|
@@ -165,19 +179,22 @@ def encode(M, lay):
|
|
| 165 |
return [M.w[a] for a in lay['real']] + M.Q[0] + M.Q[1] + M.D[0] + M.D[1]
|
| 166 |
|
| 167 |
|
| 168 |
-
def check(G, L, trials, seed=7):
|
| 169 |
-
"""One step of the netlist against the transcription from uniformly random full states
|
| 170 |
-
|
|
|
|
| 171 |
rnd = random.Random(seed)
|
| 172 |
bad = 0
|
|
|
|
| 173 |
for _ in range(trials):
|
| 174 |
-
N = G * B
|
| 175 |
bits = lambda k: [rnd.randint(0, 1) for _ in range(k)]
|
| 176 |
-
M = T.Machine(G, L, bits(N), bits(N), bits(L), bits(L), bits(
|
| 177 |
y = evaluate(net, nxt, encode(M, lay))
|
| 178 |
M.step()
|
| 179 |
bad += y != encode(M, lay)
|
| 180 |
-
|
|
|
|
|
|
|
| 181 |
|
| 182 |
|
| 183 |
def netfile_bytes(net, nxt):
|
|
@@ -207,11 +224,13 @@ def main():
|
|
| 207 |
cmd = sys.argv[1] if len(sys.argv) > 1 else 'check'
|
| 208 |
if cmd == 'check':
|
| 209 |
t0 = time.time()
|
| 210 |
-
small = check(5, 40, 300)
|
| 211 |
A, rho, desc, net, nxt, lay = organism_netlist()
|
| 212 |
-
full = check(len(A.recs), len(desc), 20)
|
|
|
|
| 213 |
res = dict(small=dict(G=5, L=40, states=300, disagreements=small),
|
| 214 |
full=dict(G=len(A.recs), L=len(desc), states=20, disagreements=full),
|
|
|
|
| 215 |
netlist=stats(net, nxt), seconds=round(time.time() - t0, 1))
|
| 216 |
update_record('random_states', res)
|
| 217 |
print(json.dumps(res, indent=1))
|
|
@@ -249,15 +268,24 @@ def main():
|
|
| 249 |
subprocess.run(['ocamlfind', 'ocamlopt', '-package', 'stdlib', 'physnet.mli', 'physnet.ml', 'dump.ml',
|
| 250 |
'-o', 'dump'], cwd=ex, check=True)
|
| 251 |
A, rho, desc, net, nxt, lay = organism_netlist()
|
| 252 |
-
ours = netfile_bytes(net, nxt)
|
| 253 |
out = os.path.join(ex, 'phys_rocq.bin')
|
| 254 |
-
|
| 255 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
for f in os.listdir(ex):
|
| 257 |
if f not in ('dump.ml', 'physnet.ml', 'physnet.mli'):
|
| 258 |
os.remove(os.path.join(ex, f))
|
| 259 |
-
res = dict(
|
| 260 |
-
sha256_generator=hashlib.sha256(ours).hexdigest(), sha256_rocq=hashlib.sha256(theirs).hexdigest())
|
| 261 |
update_record('extraction', res)
|
| 262 |
print(json.dumps(res, indent=1))
|
| 263 |
|
|
|
|
| 1 |
"""The two-head physics as a netlist of ternary threshold units.
|
| 2 |
|
| 3 |
+
For a window of 2^alpha cells and records of 8 + 3 alpha bits, the state bits are
|
| 4 |
+
the window cells other than 1, 2 and 3, then Q0, Q1, D0 and D1, each listed from its
|
| 5 |
+
head. The netlist selects the record in front of the active bank by a multiplexer
|
| 6 |
+
on kappa, decodes its three addresses, reads the two operands through the decode
|
| 7 |
+
lines, forms v = H(w0 x0 + w1 x1 + beta) from the weight codes and the bias bits,
|
| 8 |
+
writes v into the window, and computes every tape bit's next value: the active bank
|
| 9 |
+
turned by one record, the idle bank written under the arm and turned by one cell on
|
| 10 |
+
request, and the two description tapes likewise. The unit order is the order of
|
| 11 |
+
construction, which rocq/Phys.v follows unit for unit. The organism runs on the
|
| 12 |
+
member with alpha = 6, a window of 64 cells.
|
| 13 |
|
| 14 |
python src/twohead_net.py check one step against the transcription on random states
|
| 15 |
python src/twohead_net.py export [PATH] the netlist file (default variants/twohead_physics.bin)
|
|
|
|
| 60 |
return self.OR((self.AND((s, True), (a, True)), True), (self.AND((s, False), (b, True)), True))
|
| 61 |
|
| 62 |
|
| 63 |
+
def build(G, L, alpha=ALPHA):
|
| 64 |
+
"""The netlist N_{G,L} of the machine with a window of 2^alpha cells and records of
|
| 65 |
+
8 + 3 alpha bits."""
|
| 66 |
+
W, B = 1 << alpha, 8 + 3 * alpha
|
| 67 |
N = G * B
|
| 68 |
real = [0] + list(range(4, W)) # window cells held in the state
|
| 69 |
wpos = {a: i for i, a in enumerate(real)}
|
|
|
|
| 74 |
kap = wpos[KAPPA]
|
| 75 |
# the record in front of the active bank
|
| 76 |
f = [net.MUX(kap, q1 + j, q0 + j) for j in range(B)]
|
| 77 |
+
c0, c1, be = f[0:2], f[2:4], f[4:8]
|
| 78 |
+
a0, a1, ao = f[8:8 + alpha], f[8 + alpha:8 + 2 * alpha], f[8 + 2 * alpha:8 + 3 * alpha]
|
| 79 |
# the cells under the three heads
|
| 80 |
rd = net.MUX(kap, d1, d0)
|
| 81 |
armv = net.MUX(kap, q0, q1)
|
|
|
|
| 86 |
def decode(field):
|
| 87 |
lines = []
|
| 88 |
for a in range(W):
|
| 89 |
+
bits = [(a >> (alpha - 1 - j)) & 1 for j in range(alpha)]
|
| 90 |
+
lines.append(net.u(-sum(bits), [(field[j], 1 if bits[j] else -1) for j in range(alpha)]))
|
| 91 |
return lines
|
| 92 |
|
| 93 |
l0, l1, lo = decode(a0), decode(a1), decode(ao)
|
|
|
|
| 147 |
for i in range(L):
|
| 148 |
nxt[base + i] = net.MUX(rot, hat((i + 1) % L), hat(i))
|
| 149 |
assert all(x is not None for x in nxt)
|
| 150 |
+
return net, nxt, dict(real=real, q0=q0, q1=q1, d0=d0, d1=d1, n=n, N=N, L=L, alpha=alpha)
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def sizes(alpha, N, L):
|
| 154 |
+
"""The units and edges of N_{G,L} for a window of 2^alpha cells and banks of N bits,
|
| 155 |
+
counted block by block."""
|
| 156 |
+
W = 1 << alpha
|
| 157 |
+
return dict(units=8 * W + 9 * alpha + 81 + 8 * N + 6 * L,
|
| 158 |
+
edges=3 * alpha * W + 12 * W + 18 * alpha + 170 + 18 * N + 12 * L,
|
| 159 |
+
state_bits=W - 3 + 2 * N + 2 * L)
|
| 160 |
|
| 161 |
|
| 162 |
def stats(net, nxt):
|
|
|
|
| 179 |
return [M.w[a] for a in lay['real']] + M.Q[0] + M.Q[1] + M.D[0] + M.D[1]
|
| 180 |
|
| 181 |
|
| 182 |
+
def check(G, L, trials, seed=7, alpha=ALPHA):
|
| 183 |
+
"""One step of the netlist against the transcription from uniformly random full states;
|
| 184 |
+
returns the number of disagreements and the netlist's statistics."""
|
| 185 |
+
net, nxt, lay = build(G, L, alpha)
|
| 186 |
rnd = random.Random(seed)
|
| 187 |
bad = 0
|
| 188 |
+
N = G * (8 + 3 * alpha)
|
| 189 |
for _ in range(trials):
|
|
|
|
| 190 |
bits = lambda k: [rnd.randint(0, 1) for _ in range(k)]
|
| 191 |
+
M = T.Machine(G, L, bits(N), bits(N), bits(L), bits(L), bits(1 << alpha), alpha)
|
| 192 |
y = evaluate(net, nxt, encode(M, lay))
|
| 193 |
M.step()
|
| 194 |
bad += y != encode(M, lay)
|
| 195 |
+
st = stats(net, nxt)
|
| 196 |
+
assert {k: st[k] for k in ('units', 'edges', 'state_bits')} == sizes(alpha, N, L)
|
| 197 |
+
return bad, st
|
| 198 |
|
| 199 |
|
| 200 |
def netfile_bytes(net, nxt):
|
|
|
|
| 224 |
cmd = sys.argv[1] if len(sys.argv) > 1 else 'check'
|
| 225 |
if cmd == 'check':
|
| 226 |
t0 = time.time()
|
| 227 |
+
small, _ = check(5, 40, 300)
|
| 228 |
A, rho, desc, net, nxt, lay = organism_netlist()
|
| 229 |
+
full, _ = check(len(A.recs), len(desc), 20)
|
| 230 |
+
wide, st_wide = check(5, 40, 40, alpha=12)
|
| 231 |
res = dict(small=dict(G=5, L=40, states=300, disagreements=small),
|
| 232 |
full=dict(G=len(A.recs), L=len(desc), states=20, disagreements=full),
|
| 233 |
+
wide=dict(alpha=12, G=5, L=40, states=40, disagreements=wide, netlist=st_wide),
|
| 234 |
netlist=stats(net, nxt), seconds=round(time.time() - t0, 1))
|
| 235 |
update_record('random_states', res)
|
| 236 |
print(json.dumps(res, indent=1))
|
|
|
|
| 268 |
subprocess.run(['ocamlfind', 'ocamlopt', '-package', 'stdlib', 'physnet.mli', 'physnet.ml', 'dump.ml',
|
| 269 |
'-o', 'dump'], cwd=ex, check=True)
|
| 270 |
A, rho, desc, net, nxt, lay = organism_netlist()
|
|
|
|
| 271 |
out = os.path.join(ex, 'phys_rocq.bin')
|
| 272 |
+
members = []
|
| 273 |
+
# the member that carries the organism, and a member with a window of 4096 cells
|
| 274 |
+
for alpha, G, L, built in ((ALPHA, len(A.recs), len(desc), (net, nxt)), (12, 5, 40, None)):
|
| 275 |
+
if built is None:
|
| 276 |
+
n2, x2, _ = build(G, L, alpha)
|
| 277 |
+
built = (n2, x2)
|
| 278 |
+
ours = netfile_bytes(*built)
|
| 279 |
+
N = G * (8 + 3 * alpha)
|
| 280 |
+
subprocess.run([os.path.join(ex, 'dump'), str(alpha), str(N), str(L), out], check=True)
|
| 281 |
+
theirs = open(out, 'rb').read()
|
| 282 |
+
members.append(dict(alpha=alpha, N=N, L=L, identical=ours == theirs,
|
| 283 |
+
sha256_generator=hashlib.sha256(ours).hexdigest(),
|
| 284 |
+
sha256_rocq=hashlib.sha256(theirs).hexdigest()))
|
| 285 |
for f in os.listdir(ex):
|
| 286 |
if f not in ('dump.ml', 'physnet.ml', 'physnet.mli'):
|
| 287 |
os.remove(os.path.join(ex, f))
|
| 288 |
+
res = dict(members=members, identical=all(m['identical'] for m in members))
|
|
|
|
| 289 |
update_record('extraction', res)
|
| 290 |
print(json.dumps(res, indent=1))
|
| 291 |
|
src/verify.py
DELETED
|
@@ -1,161 +0,0 @@
|
|
| 1 |
-
"""Every statement of the paper, checked, with the time each check takes.
|
| 2 |
-
|
| 3 |
-
The checks are in three tiers, and the checks of a tier run concurrently. The
|
| 4 |
-
first establishes the statements: each one is an exhaustive or near-exhaustive
|
| 5 |
-
audit of a definition, a lemma or a proposition, and none of them runs the full
|
| 6 |
-
instance; it covers the host family H_A for every word width from 3 to 12, the
|
| 7 |
-
fan-in-two rewriting, and the amplified host N_3 of Section 6.3. The second
|
| 8 |
-
executes every construction end to end: the instances on the integer reference,
|
| 9 |
-
four machines on the netlist that sigma denotes, the hierarchy, the constructor
|
| 10 |
-
inside the interpreter, the host on the evaluator in C, which runs three
|
| 11 |
-
generations of the self-reproducing instance, the translating organism on the
|
| 12 |
-
two-head machine and on its netlist in C, and the Rocq development, which needs
|
| 13 |
-
rocq and ocamlfind on the PATH.
|
| 14 |
-
|
| 15 |
-
The third runs the complete instance on the threshold evaluators, the
|
| 16 |
-
perturbation experiments, the orbit certificate, and the amplified host: its
|
| 17 |
-
exact self-reproduction on the evaluator in C, the self-reproducing instance of
|
| 18 |
-
the host on it under read noise, its deviation curve split by layer, and the
|
| 19 |
-
correction of single wrong copies along a noisy run. Its cost belongs to
|
| 20 |
-
the object: one generation is 1,664,939 steps of a map of 41,967 units, and
|
| 21 |
-
the amplified host reproduces itself in 33,796,449 steps of 125,901 units.
|
| 22 |
-
The rate of each evaluator is in paper/runs/paper_throughput.json, so the cost
|
| 23 |
-
of any one line below is a multiplication.
|
| 24 |
-
|
| 25 |
-
python src/verify.py # the statements
|
| 26 |
-
python src/verify.py --tier 2 # and every construction, end to end
|
| 27 |
-
python src/verify.py --tier 3 # and the full-scale runs
|
| 28 |
-
"""
|
| 29 |
-
from __future__ import annotations
|
| 30 |
-
|
| 31 |
-
import argparse
|
| 32 |
-
import concurrent.futures as cf
|
| 33 |
-
import json
|
| 34 |
-
import os
|
| 35 |
-
import subprocess
|
| 36 |
-
import sys
|
| 37 |
-
import time
|
| 38 |
-
|
| 39 |
-
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 40 |
-
SRC = os.path.join(REPO, "src")
|
| 41 |
-
PY = sys.executable
|
| 42 |
-
|
| 43 |
-
TIER1 = [
|
| 44 |
-
("check_sigma.py", [], "the canonical serialization, Definition 2.10"),
|
| 45 |
-
("check_device.py", [], "the device, Definition 2.8"),
|
| 46 |
-
("check_framing.py", [], "the framing, Definition 2.12"),
|
| 47 |
-
("check_host.py", [], "the machine, Definition 3.1"),
|
| 48 |
-
("check_lev.py", [], "the levelization, Lemma 2.6"),
|
| 49 |
-
("check_ternarity.py", [], "ternary depth, Proposition 3.4"),
|
| 50 |
-
("check_codec.py", [], "the recipe codec, Lemma 4.4"),
|
| 51 |
-
("check_optimal.py", [], "optimality of the bound, Proposition 4.3"),
|
| 52 |
-
("check_steps.py", [], "the step counts, Theorem 4.6 and Proposition 5.4"),
|
| 53 |
-
("check_environment.py", [], "the environment, Proposition 2.15"),
|
| 54 |
-
("check_interp.py", [], "the interpreter netlist, Construction 9.2"),
|
| 55 |
-
("check_host_family.py", [], "the host family H_A against SUBLEQ_A, Remark 3.10"),
|
| 56 |
-
("check_host_fold.py", [], "the folded host family, depth 11, Remark 3.11"),
|
| 57 |
-
("fanin2.py", [], "the fan-in-two rewriting, Corollary 9.6"),
|
| 58 |
-
("redundant.py", ["build"], "the amplified host N_3, Construction 6.12"),
|
| 59 |
-
("twohead_net.py", ["check"], "one step of the two-head netlist, Theorem 7.2"),
|
| 60 |
-
]
|
| 61 |
-
|
| 62 |
-
TIER2 = [
|
| 63 |
-
("hosted_constructor.py", [], "the constructor inside the interpreter, Theorem 9.10"),
|
| 64 |
-
("hierarchy.py", [], "a larger interpreter runs a smaller one, Proposition 9.8"),
|
| 65 |
-
("check_family_gate.py", [], "four machines on the netlist of sigma"),
|
| 66 |
-
("check_c.py", [], "the host on the evaluator in C"),
|
| 67 |
-
("paper_runs.py", ["reference"], "the constructions on the integer reference"),
|
| 68 |
-
("twohead.py", ["run", "--generations", "3"], "the translating organism, three generations, Theorem 8.6"),
|
| 69 |
-
("twohead_net.py", ["lockstep", "3"], "the organism on the two-head netlist in C, three generations"),
|
| 70 |
-
("check_rocq.py", [], "the Rocq development, its assumptions and the extracted netlist"),
|
| 71 |
-
]
|
| 72 |
-
|
| 73 |
-
TIER3 = [
|
| 74 |
-
("paper_verify.py", [], "the codec over the whole artifact, 971 MB"),
|
| 75 |
-
("check_family.py", [], "all 29 machines on the integer reference"),
|
| 76 |
-
("paper_runs.py", ["lockstep", "--device", "cuda"],
|
| 77 |
-
"four evaluators in lockstep"),
|
| 78 |
-
("paper_runs.py", ["net", "--device", "cuda"],
|
| 79 |
-
"three generations on the netlist of sigma"),
|
| 80 |
-
("paper_runs.py", ["lev", "--device", "cuda", "--generations", "1"],
|
| 81 |
-
"one generation on Lev(N_host)"),
|
| 82 |
-
("throughput.py", [], "the rate of each evaluator"),
|
| 83 |
-
("noise.py", ["margin"], "the margin along the trajectory, Theorem 6.2"),
|
| 84 |
-
("noise.py", ["curve"], "the deviation rate against the union bound"),
|
| 85 |
-
("noise.py", ["leak", "--steps", "10000"],
|
| 86 |
-
"static weight error with the zeros leaking"),
|
| 87 |
-
("noise.py", ["omega"], "the instance under read noise, to completion"),
|
| 88 |
-
("noise.py", ["profile"], "the pre-activation profile and its bound"),
|
| 89 |
-
("noise.py", ["certify"], "the active-input counts along the orbits, Proposition 6.4"),
|
| 90 |
-
("redundant.py", ["selfrep"], "exact self-reproduction of N_3 on the evaluator in C"),
|
| 91 |
-
("redundant.py", ["omega"], "Omega* on N_3 under read noise, to completion"),
|
| 92 |
-
("redundant.py", ["curve"], "the deviation rate of N_3 against the bounds"),
|
| 93 |
-
("redundant.py", ["restore", "--batch", "64", "--steps", "20000"],
|
| 94 |
-
"the failure rate of the state of N_3 read by majority"),
|
| 95 |
-
("redundant.py", ["bound"], "the restoration bound of N_3"),
|
| 96 |
-
("redundant.py", ["layers"], "the profile bound of N_3 split by layer"),
|
| 97 |
-
]
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
def run(entry, quiet, threads=None):
|
| 101 |
-
name, args, what = entry
|
| 102 |
-
t0 = time.perf_counter()
|
| 103 |
-
env = dict(os.environ)
|
| 104 |
-
if threads:
|
| 105 |
-
env["OMP_NUM_THREADS"] = str(threads)
|
| 106 |
-
p = subprocess.run([PY, os.path.join(SRC, name)] + args,
|
| 107 |
-
capture_output=True, text=True, cwd=REPO, env=env)
|
| 108 |
-
dt = time.perf_counter() - t0
|
| 109 |
-
ok = p.returncode == 0
|
| 110 |
-
label = f"{name} {' '.join(args)}".strip()
|
| 111 |
-
print(f" {'ok ' if ok else 'FAIL'} {label:<34} {dt:7.1f} s {what}",
|
| 112 |
-
flush=True)
|
| 113 |
-
if not ok and not quiet:
|
| 114 |
-
print(p.stdout[-1500:])
|
| 115 |
-
print(p.stderr[-1500:])
|
| 116 |
-
return ok, dt
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
def main() -> int:
|
| 120 |
-
ap = argparse.ArgumentParser()
|
| 121 |
-
ap.add_argument("--tier", type=int, default=1)
|
| 122 |
-
ap.add_argument("--quiet", action="store_true")
|
| 123 |
-
ap.add_argument("--jobs", type=int, default=os.cpu_count() or 1,
|
| 124 |
-
help="checks of a tier run concurrently")
|
| 125 |
-
args = ap.parse_args()
|
| 126 |
-
|
| 127 |
-
plan = [("statements", TIER1)]
|
| 128 |
-
if args.tier >= 2:
|
| 129 |
-
plan.append(("constructions", TIER2))
|
| 130 |
-
if args.tier >= 3:
|
| 131 |
-
plan.append(("full scale", TIER3))
|
| 132 |
-
|
| 133 |
-
total = 0.0
|
| 134 |
-
bad = 0
|
| 135 |
-
record = {}
|
| 136 |
-
for title, entries in plan:
|
| 137 |
-
print(f"[{title}]", flush=True)
|
| 138 |
-
t0 = time.perf_counter()
|
| 139 |
-
jobs = max(1, min(args.jobs, len(entries)))
|
| 140 |
-
threads = max(1, (os.cpu_count() or 1) // jobs)
|
| 141 |
-
with cf.ThreadPoolExecutor(max_workers=jobs) as ex:
|
| 142 |
-
futs = {ex.submit(run, e, args.quiet, threads): e for e in entries}
|
| 143 |
-
for f in cf.as_completed(futs):
|
| 144 |
-
e = futs[f]
|
| 145 |
-
ok, dt = f.result()
|
| 146 |
-
bad += not ok
|
| 147 |
-
record[f"{e[0]} {' '.join(e[1])}".strip()] = {"ok": ok, "seconds": dt}
|
| 148 |
-
sub = time.perf_counter() - t0
|
| 149 |
-
total += sub
|
| 150 |
-
print(f" {title}: {sub / 60:.1f} min wall time", flush=True)
|
| 151 |
-
print(f"total {total / 60:.1f} min; failures: {bad}")
|
| 152 |
-
d = os.path.join(REPO, "paper", "runs")
|
| 153 |
-
os.makedirs(d, exist_ok=True)
|
| 154 |
-
json.dump({"tier": args.tier, "total_seconds": total, "failures": bad,
|
| 155 |
-
"checks": record},
|
| 156 |
-
open(os.path.join(d, "paper_verify_times.json"), "w"), indent=1)
|
| 157 |
-
return 0 if bad == 0 else 1
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
if __name__ == "__main__":
|
| 161 |
-
sys.exit(main())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|