phanerozoic commited on
Commit
8cfe9fa
·
1 Parent(s): 9dc9d2f

Prove in Rocq that the host family computes SUBLEQ at every word width, check the stored host's startup and step records on decision diagrams, state the stored-host theorems for every stored host with their overhead, bound self-reproduction under noise, remove the neuromorphic mappings, and cut the paper to 30 pages

Browse files
.gitignore CHANGED
@@ -17,6 +17,9 @@ rocq/.*.aux
17
  rocq/.lia.cache
18
  rocq/extract/physnet.ml
19
  rocq/extract/physnet.mli
 
 
 
20
  rocq/.nia.cache
21
  rocq/extract/dump
22
  rocq/extract/*.cm*
 
17
  rocq/.lia.cache
18
  rocq/extract/physnet.ml
19
  rocq/extract/physnet.mli
20
+ rocq/extract/hostnet.ml
21
+ rocq/extract/hostnet.mli
22
+ rocq/extract/dumphost
23
  rocq/.nia.cache
24
  rocq/extract/dump
25
  rocq/extract/*.cm*
README.md CHANGED
@@ -596,7 +596,9 @@ that netlist. It also shows where the restriction to {-1, 0, 1} is paid for,
596
  and that a fixed ternary network, the two-head machine of
597
  `src/twohead.py`, holds a stored network in its state and evaluates one
598
  record per step, which `rocq/` proves for every window of 2^α cells, bank and
599
- tape. The host itself, compiled by `src/twohead.py` into 36,074 records of
 
 
600
  two inputs with records that load its memory, its tape device and a hand-over,
601
  and stored in the member with 4096 cells, runs the 27-instruction program on a
602
  recipe for its own records: it writes them into the idle bank, copies the recipe
@@ -997,8 +999,8 @@ src/ the library; `python src/<file>.py <command>
997
  │ and `constructor8`, the neural_subleq8io suite
998
  ├── twohead.py the two-head machine: the organism (`organism`), the netlist
999
  │ N_{G,L} (`net`), and the host stored in it (`stored`)
1000
- ├── noise.py read noise and weight error on the host (`host`), the amplified
1001
- │ host (`amplified`), and the neuromorphic datapath
1002
  ├── paper.py the paper's checks and runs, one command each
1003
  ├── independent.py code written from the paper's text alone
1004
  ├── netlist_eval.c an evaluator of the host family and the amplified host in C
@@ -1007,10 +1009,10 @@ src/ the library; `python src/<file>.py <command>
1007
  ├── restore_bound.c the restoration bound of the amplified host along the orbit
1008
  └── nsim.c the noise simulator of independent.py
1009
  paper/ the manuscript, and the record of every run it reports
1010
- rocq/ Rocq proofs: the netlist of the two-head machine computes its
1011
- step for every window of 2^α cells, the organism builds every
1012
- image from any description of it and reproduces in every
1013
- generation
1014
  tools/play.py the playground, and a demonstration on each machine
1015
  llm_integration/
1016
  ├── llm.py SmolLM2 with the frozen circuits: the circuit wrapper, the
 
596
  and that a fixed ternary network, the two-head machine of
597
  `src/twohead.py`, holds a stored network in its state and evaluates one
598
  record per step, which `rocq/` proves for every window of 2^α cells, bank and
599
+ tape; `rocq/` also proves that the host family computes SUBLEQ at every word
600
+ width, and the H_8 it defines is the netlist of the published serialization. The
601
+ host itself, compiled by `src/twohead.py` into 36,074 records of
602
  two inputs with records that load its memory, its tape device and a hand-over,
603
  and stored in the member with 4096 cells, runs the 27-instruction program on a
604
  recipe for its own records: it writes them into the idle bank, copies the recipe
 
999
  │ and `constructor8`, the neural_subleq8io suite
1000
  ├── twohead.py the two-head machine: the organism (`organism`), the netlist
1001
  │ N_{G,L} (`net`), and the host stored in it (`stored`)
1002
+ ├── noise.py read noise and weight error on the host (`host`), and the
1003
+ │ amplified host (`amplified`)
1004
  ├── paper.py the paper's checks and runs, one command each
1005
  ├── independent.py code written from the paper's text alone
1006
  ├── netlist_eval.c an evaluator of the host family and the amplified host in C
 
1009
  ├── restore_bound.c the restoration bound of the amplified host along the orbit
1010
  └── nsim.c the noise simulator of independent.py
1011
  paper/ the manuscript, and the record of every run it reports
1012
+ rocq/ Rocq proofs: the host family H_A computes SUBLEQ for every word
1013
+ width, the netlist of the two-head machine computes its step
1014
+ for every window of 2^α cells, the organism builds every image
1015
+ from any description of it and reproduces in every generation
1016
  tools/play.py the playground, and a demonstration on each machine
1017
  llm_integration/
1018
  ├── llm.py SmolLM2 with the frozen circuits: the circuit wrapper, the
paper/README.md CHANGED
@@ -12,8 +12,7 @@ runs/ the record written by each command
12
  ## What each command establishes
13
 
14
  Each command is `python src/<file>.py <command>` and writes its record to `runs/`;
15
- `paper.py rocq` needs Rocq 9.1 and ocamlfind on the PATH, and `noise.py neuromorphic run`
16
- needs Lava, which requires Python 3.10.
17
 
18
  | Command | Record | Establishes |
19
  |---|---|---|
@@ -37,14 +36,13 @@ needs Lava, which requires Python 3.10.
37
  | `paper.py family-gate` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
38
  | `paper.py c` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
39
  | `paper.py throughput` | `paper_throughput.json` | the rate of each evaluator |
40
- | `paper.py rocq` | `paper_rocq.json` | the Rocq development of `rocq/`, its assumptions and the netlist extracted from it |
41
  | `twohead.py organism` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
42
  | `twohead.py net` | `paper_twohead_net.json` | the netlist N_{G,L} against the machine for windows of 64 and 4096 cells, its file, the organism on it in C, and the netlist extracted from Rocq |
43
- | `twohead.py stored` | `paper_stored_host.json` | the host compiled into records of the two-head machine: one pass against the host's step and its device, and three generations in C |
44
  | `noise.py host` | `paper_noise_*.json` | the margin, the profile bound, read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
45
  | `noise.py amplified` | `paper_redundant_*.json` | the amplified host N_3: one step on replicated states, the margin 3/2, exact self-reproduction in C, the run under noise, the deviation curve and its bound by layer, the failure rate of the state read by majority and the restoration bound, computed by `src/restore_bound.c` |
46
- | `noise.py neuromorphic` | `paper_neuromorphic.json` | the datapath on the Loihi and Akida neuron models |
47
- | `independent.py` | `independent_*.json` | code written from the paper's definitions alone: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma, Tables 3 to 6 with the noise simulator `src/nsim.c`, and the datapath on Loihi and Akida |
48
 
49
  Rebuild the typeset paper with any TeX installation:
50
 
 
12
  ## What each command establishes
13
 
14
  Each command is `python src/<file>.py <command>` and writes its record to `runs/`;
15
+ `paper.py rocq` needs Rocq 9.1 and ocamlfind on the PATH.
 
16
 
17
  | Command | Record | Establishes |
18
  |---|---|---|
 
36
  | `paper.py family-gate` | `paper_runs_family_gate.json` | four of them on the netlist of sigma |
37
  | `paper.py c` | `paper_c_evaluator.json` | the host on the evaluator in C, `src/netlist_eval.c` |
38
  | `paper.py throughput` | `paper_throughput.json` | the rate of each evaluator |
39
+ | `paper.py rocq` | `paper_rocq.json` | the Rocq development of `rocq/`, its assumptions, and the host H_8 extracted from it against the netlist sigma(N_host) denotes |
40
  | `twohead.py organism` | `paper_twohead.json` | the translating organism on the two-head machine, three generations |
41
  | `twohead.py net` | `paper_twohead_net.json` | the netlist N_{G,L} against the machine for windows of 64 and 4096 cells, its file, the organism on it in C, and the netlist extracted from Rocq |
42
+ | `twohead.py stored` | `paper_stored_host.json` | the host compiled into records of the two-head machine: one pass against the host's step and its device, the startup and step records on decision diagrams over the signals of N_host (`stored symbolic`), and three generations in C |
43
  | `noise.py host` | `paper_noise_*.json` | the margin, the profile bound, read noise, the deviation curve, weight error with leakage, the active-input counts of the orbit certificate |
44
  | `noise.py amplified` | `paper_redundant_*.json` | the amplified host N_3: one step on replicated states, the margin 3/2, exact self-reproduction in C, the run under noise, the deviation curve and its bound by layer, the failure rate of the state read by majority and the restoration bound, computed by `src/restore_bound.c` |
45
+ | `independent.py` | `independent_*.json` | code written from the paper's definitions alone: H_A rebuilt from Construction 3.8 for A = 3 to 12, Lev(N_host) from sigma and the measurements of Section 6.1 and Appendix A with the noise simulator `src/nsim.c` |
 
46
 
47
  Rebuild the typeset paper with any TeX installation:
48
 
paper/runs/independent_neuromorphic.json DELETED
@@ -1,34 +0,0 @@
1
- {
2
- "datapath": {
3
- "units": 106,
4
- "depth": 5,
5
- "widths": [
6
- 48,
7
- 58,
8
- 23,
9
- 23,
10
- 9
11
- ]
12
- },
13
- "akida": {
14
- "backend": "akida 2.19.3",
15
- "patterns": 65536,
16
- "failures": 0
17
- },
18
- "lava_vth_16": {
19
- "backend": "lava fixed_pt",
20
- "vth": 16,
21
- "patterns": 4096,
22
- "failures": 0,
23
- "margin_firing_side": 128,
24
- "margin_quiet_side": 0
25
- },
26
- "lava_vth_17": {
27
- "backend": "lava fixed_pt",
28
- "vth": 17,
29
- "patterns": 4096,
30
- "failures": 0,
31
- "margin_firing_side": 64,
32
- "margin_quiet_side": 64
33
- }
34
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paper/runs/paper_neuromorphic.json DELETED
@@ -1,29 +0,0 @@
1
- {
2
- "backend": "Lava 0.10.0, fixed_pt tag (Loihi neuron model)",
3
- "units": 106,
4
- "layers": 5,
5
- "widths": [
6
- 48,
7
- 58,
8
- 23,
9
- 23,
10
- 9
11
- ],
12
- "worst_accumulation": 16,
13
- "patterns": 4096,
14
- "failures": 0,
15
- "margin_membrane_units": 64,
16
- "weight_scale": 2,
17
- "synapse_granularity": 2,
18
- "bias_offset": 9,
19
- "ok": true,
20
- "akida": {
21
- "backend": "akida 2.19.3, software backend",
22
- "layers": 5,
23
- "patterns": 65536,
24
- "failures": 0,
25
- "weights_bits": 2,
26
- "act_bits": 1,
27
- "ok": true
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paper/runs/paper_rocq.json CHANGED
@@ -1,7 +1,7 @@
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",
@@ -18,7 +18,16 @@
18
  "Main.every_generation": "closed",
19
  "SelfRep.self_reproduction": "closed",
20
  "SelfRep.second_generation": "closed",
21
- "SelfRep.periodic": "closed"
 
22
  },
23
- "extraction_identical": true
 
 
 
 
 
 
 
 
24
  }
 
1
  {
2
  "rocq": "The Rocq Prover, version 9.1.1",
3
+ "files": 30,
4
+ "build_seconds": 303.5,
5
  "theorems": {
6
  "PhysMain.netlist_step": "closed",
7
  "PhysMain.netlist_step64": "closed",
 
18
  "Main.every_generation": "closed",
19
  "SelfRep.self_reproduction": "closed",
20
  "SelfRep.second_generation": "closed",
21
+ "SelfRep.periodic": "closed",
22
+ "HostSem.host_step": "closed"
23
  },
24
+ "extraction_identical": true,
25
+ "lines": 5093,
26
+ "host_extraction": {
27
+ "A": 8,
28
+ "units": 17598,
29
+ "identical": true,
30
+ "sha256_sigma": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a",
31
+ "sha256_rocq": "2263144948d68cafbf1616a6c0bd74e98cb597c1a6d5b1512d65d3aff574f17a"
32
+ }
33
  }
paper/runs/paper_stored_host.json CHANGED
@@ -66,5 +66,14 @@
66
  "records": 36074,
67
  "window_cells": 2896,
68
  "seconds": 131.8
 
 
 
 
 
 
 
 
 
69
  }
70
  }
 
66
  "records": 36074,
67
  "window_cells": 2896,
68
  "seconds": 131.8
69
+ },
70
+ "symbolic": {
71
+ "startup_records": 2099,
72
+ "step_records": 33568,
73
+ "startup_exact": true,
74
+ "step_exact": true,
75
+ "sha256_image": "7a769aa264a89860149962d7e98f8b2a5cb34ceb7778e88bcbffdccdc0996154",
76
+ "nodes": 1435999,
77
+ "seconds": 3.6
78
  }
79
  }
paper/universal_construction_ternary.pdf CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:cf817d63746a8601c860f094ef25e7a746218a355e721248f44559caf8f3f441
3
- size 364795
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c973871985a763cf000c4cfa9e8126aa37eb0efb94c99261d4289b10a39e1b10
3
+ size 327298
paper/universal_construction_ternary.tex CHANGED
The diff for this file is too large to render. See raw diff
 
rocq/Adder.v ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (* The subtractor of Lemma 3.2: the carry-lookahead terms are the ripple carries of y + not x + 1,
2
+ and the sum bits spell (y - x) mod 2^A. *)
3
+ From Stdlib Require Import List Bool Arith Lia.
4
+ Import ListNotations.
5
+ From TH Require Import TwoHead Net PhysSem.
6
+
7
+ (* the value of the bits f 0 .. f (n - 1), least significant first *)
8
+ Definition bv (f : nat -> bool) (n : nat) : nat := bits2nat (rev (map f (seq 0 n))).
9
+
10
+ Lemma bv_S : forall f n, bv f (S n) = (if f n then 2 ^ n else 0) + bv f n.
11
+ Proof.
12
+ intros f n. unfold bv. rewrite seq_S, map_app, rev_app_distr. cbn [map rev app].
13
+ rewrite bits2nat_cons, length_rev, length_map, length_seq. reflexivity.
14
+ Qed.
15
+
16
+ Lemma bv_lt : forall f n, bv f n < 2 ^ n.
17
+ Proof.
18
+ intros f n. unfold bv. pose proof (bits2nat_lt (rev (map f (seq 0 n)))) as H.
19
+ rewrite length_rev, length_map, length_seq in H. exact H.
20
+ Qed.
21
+
22
+ Lemma testbit_bv : forall f n k, k < n -> Nat.testbit (bv f n) k = f k.
23
+ Proof.
24
+ intros f n k Hk. unfold bv.
25
+ pose proof (testbit_bits2nat (rev (map f (seq 0 n))) (n - 1 - k)) as T.
26
+ rewrite length_rev, length_map, length_seq in T. replace (n - 1 - (n - 1 - k)) with k in T by lia.
27
+ rewrite T by lia. rewrite rev_nth by (rewrite length_map, length_seq; lia).
28
+ rewrite length_map, length_seq. replace (n - S (n - 1 - k)) with k by lia.
29
+ rewrite nth_map_d with (d' := 0) by (rewrite length_seq; lia). rewrite seq_nth by lia. reflexivity.
30
+ Qed.
31
+
32
+ Lemma bv_testbit : forall z n, z < 2 ^ n -> bv (Nat.testbit z) n = z.
33
+ Proof.
34
+ intros z n Hz. apply (bits_eq_nat _ _ n); [apply bv_lt | exact Hz |].
35
+ intros i Hi. apply testbit_bv. exact Hi.
36
+ Qed.
37
+
38
+ Lemma bv_compl : forall f n, bv f n + bv (fun i => negb (f i)) n + 1 = 2 ^ n.
39
+ Proof.
40
+ intros f n. induction n as [|n IH]; [reflexivity|].
41
+ rewrite !bv_S. cbn [Nat.pow]. destruct (f n); cbn [negb]; lia.
42
+ Qed.
43
+
44
+ Section Sub.
45
+ Variables x y : nat.
46
+
47
+ Definition xb (i : nat) : bool := Nat.testbit x i.
48
+ Definition yb (i : nat) : bool := Nat.testbit y i.
49
+ Definition gb (i : nat) : bool := yb i && negb (xb i).
50
+ Definition pg (i : nat) : bool := negb (xb i) || yb i.
51
+
52
+ Fixpoint carry (k : nat) : bool := match k with O => true | S m => gb m || (pg m && carry m) end.
53
+
54
+ Definition sumbit (k : nat) : bool := xorb (xorb (yb k) (negb (xb k))) (carry k).
55
+
56
+ Lemma adder : forall n,
57
+ bv yb n + bv (fun i => negb (xb i)) n + 1 = bv sumbit n + (if carry n then 2 ^ n else 0).
58
+ Proof.
59
+ induction n as [|n IH]; [reflexivity|].
60
+ rewrite !bv_S. cbn [carry Nat.pow]. unfold sumbit, gb, pg in *.
61
+ destruct (yb n), (xb n), (carry n); cbn [negb xorb andb orb] in *; lia.
62
+ Qed.
63
+
64
+ Lemma sub_value : forall A, x < 2 ^ A -> y < 2 ^ A -> bv sumbit A = (y + 2 ^ A - x) mod 2 ^ A.
65
+ Proof.
66
+ intros A Hx Hy. pose proof (adder A) as H. pose proof (bv_compl xb A) as C.
67
+ change (bv yb A) with (bv (Nat.testbit y) A) in H. rewrite (bv_testbit y A Hy) in H.
68
+ change (bv xb A) with (bv (Nat.testbit x) A) in C. rewrite (bv_testbit x A Hx) in C.
69
+ pose proof (bv_lt sumbit A) as L.
70
+ assert (E : y + 2 ^ A - x = bv sumbit A + (if carry A then 1 else 0) * 2 ^ A)
71
+ by (destruct (carry A); lia).
72
+ rewrite E, Nat.Div0.mod_add, Nat.mod_small by exact L. reflexivity.
73
+ Qed.
74
+
75
+ Lemma sub_bits : forall A k, x < 2 ^ A -> y < 2 ^ A -> k < A ->
76
+ Nat.testbit ((y + 2 ^ A - x) mod 2 ^ A) k = sumbit k.
77
+ Proof. intros A k Hx Hy Hk. rewrite <- sub_value by assumption. apply testbit_bv. exact Hk. Qed.
78
+
79
+ Lemma existsb_and_r : forall (T : Type) (g : T -> bool) c l, existsb (fun a => g a && c) l = existsb g l && c.
80
+ Proof.
81
+ intros T g c l. induction l as [|a l IH]; [reflexivity|]. cbn [existsb]. rewrite IH.
82
+ destruct (g a), c, (existsb g l); reflexivity.
83
+ Qed.
84
+
85
+ Lemma forallb_seq_S : forall (f : nat -> bool) m n, forallb f (seq m (S n)) = forallb f (seq m n) && f (m + n).
86
+ Proof. intros f m n. rewrite seq_S, forallb_app. cbn [forallb]. rewrite andb_true_r. reflexivity. Qed.
87
+
88
+ (* the carry into bit k: all of 0 .. k-1 propagate, or some j generates and j+1 .. k-1 propagate *)
89
+ Lemma carry_closed : forall k,
90
+ carry k = forallb pg (seq 0 k) || existsb (fun j => gb j && forallb pg (seq (S j) (k - S j))) (seq 0 k).
91
+ Proof.
92
+ induction k as [|k IH]; [reflexivity|].
93
+ cbn [carry]. rewrite IH, forallb_seq_S, seq_S, existsb_app. cbn [existsb]. rewrite Nat.add_0_l.
94
+ replace (S k - S k) with 0 by lia. cbn [seq forallb]. rewrite andb_true_r, orb_false_r.
95
+ assert (E : existsb (fun j => gb j && forallb pg (seq (S j) (S k - S j))) (seq 0 k)
96
+ = existsb (fun j => gb j && forallb pg (seq (S j) (k - S j))) (seq 0 k) && pg k).
97
+ { rewrite (existsb_ext_in _ _ (fun j => (gb j && forallb pg (seq (S j) (k - S j))) && pg k)).
98
+ - apply (existsb_and_r _ (fun j => gb j && forallb pg (seq (S j) (k - S j)))).
99
+ - intros j Hj. apply in_seq in Hj. replace (S k - S j) with (S (k - S j)) by lia. rewrite forallb_seq_S.
100
+ replace (S j + (k - S j)) with k by lia. rewrite andb_assoc. reflexivity. }
101
+ rewrite E. destruct (pg k), (gb k); cbn [andb orb]; rewrite ?andb_true_r, ?andb_false_r, ?orb_false_r,
102
+ ?orb_true_r; reflexivity.
103
+ Qed.
104
+
105
+ End Sub.
106
+
107
+ Lemma testbit_top : forall r n, 1 <= n -> r < 2 ^ n -> Nat.testbit r (n - 1) = (2 ^ (n - 1) <=? r).
108
+ Proof.
109
+ intros r n Hn Hr. replace n with (S (n - 1)) in Hr by lia. rewrite Nat.pow_succ_r' in Hr.
110
+ apply Nat.b2n_inj. rewrite Nat.testbit_spec'.
111
+ destruct (Nat.leb_spec (2 ^ (n - 1)) r) as [H|H].
112
+ - assert (D : r / 2 ^ (n - 1) = 1).
113
+ { symmetry. apply Nat.div_unique with (r - 2 ^ (n - 1)); lia. }
114
+ rewrite D. reflexivity.
115
+ - rewrite Nat.div_small by exact H. reflexivity.
116
+ Qed.
117
+
118
+ Lemma sub_zero : forall A x y, x < 2 ^ A -> y < 2 ^ A -> Nat.eqb ((y + 2 ^ A - x) mod 2 ^ A) 0 = Nat.eqb x y.
119
+ Proof.
120
+ intros A x y Hx Hy. pose proof (Nat.pow_nonzero 2 A ltac:(lia)) as Hn.
121
+ destruct (Nat.eqb_spec x y) as [->|E].
122
+ - replace (y + 2 ^ A - y) with (1 * 2 ^ A) by lia. rewrite Nat.Div0.mod_mul. reflexivity.
123
+ - apply Nat.eqb_neq. intro Z.
124
+ destruct (Nat.le_gt_cases x y) as [L|L].
125
+ + replace (y + 2 ^ A - x) with ((y - x) + 1 * 2 ^ A) in Z by lia.
126
+ rewrite Nat.Div0.mod_add, Nat.mod_small in Z by lia. lia.
127
+ + rewrite Nat.mod_small in Z by lia. lia.
128
+ Qed.
rocq/Assumptions.v CHANGED
@@ -1,5 +1,5 @@
1
- (* The assumptions of the main theorems, printed by src/check_rocq.py after the build. *)
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.
@@ -17,3 +17,4 @@ Print Assumptions Main.every_generation.
17
  Print Assumptions SelfRep.self_reproduction.
18
  Print Assumptions SelfRep.second_generation.
19
  Print Assumptions SelfRep.periodic.
 
 
1
+ (* The assumptions of the main theorems, printed by src/paper.py rocq after the build. *)
2
+ From TH Require Import PhysMain PhysFacts NetMain Complete Run PassLemma Main SelfRep HostSem.
3
 
4
  Print Assumptions PhysMain.netlist_step.
5
  Print Assumptions PhysMain.netlist_step64.
 
17
  Print Assumptions SelfRep.self_reproduction.
18
  Print Assumptions SelfRep.second_generation.
19
  Print Assumptions SelfRep.periodic.
20
+ Print Assumptions HostSem.host_step.
rocq/ExtractHost.v ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ From Stdlib Require Import Extraction ExtrOcamlBasic ExtrOcamlNatInt ExtrOcamlZInt.
2
+ From TH Require Import Net Host.
3
+ Extraction Language OCaml.
4
+ Set Extraction Output Directory "extract".
5
+ Extraction "hostnet.ml" host_units host_next nH.
rocq/Host.v ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (* The SUBLEQ host H_A as a netlist of ternary threshold units, block by block in the order of
2
+ the generator, for words of A bits (Construction 3.8), and the machine it computes. *)
3
+ From Stdlib Require Import List Bool Arith ZArith Lia.
4
+ Import ListNotations.
5
+ From TH Require Import TwoHead Net Gates.
6
+
7
+ Section Host.
8
+ Variable A : nat.
9
+
10
+ (* the words of memory, and the state bits: the counter, the halt bit, the memory *)
11
+ Definition SW : nat := 2 ^ A.
12
+ Definition nH : nat := A + 1 + SW * A.
13
+
14
+ (* bit t of an A-bit value, most significant first *)
15
+ Definition bitof (v t : nat) : bool := Nat.testbit v (A - 1 - t).
16
+
17
+ Definition pcb (i : nat) : sref := SIn i.
18
+ Definition haltb : sref := SIn A.
19
+ Definition mu (j t : nat) : sref := SIn (A + 1 + j * A + t).
20
+
21
+ (* the literals asserting that the bits f 0 .. f (A - 1), most significant first, spell v *)
22
+ Definition lits (f : nat -> sref) (v : nat) : list lit := map (fun t => (f t, bitof v t)) (seq 0 A).
23
+
24
+ Definition opb (o t : nat) : sref := SRef 6 (o * A + t) 0.
25
+ Definition xv (i : nat) : sref := SRef 14 (A - 1 - i) 0.
26
+ Definition yv (i : nat) : sref := SRef 15 (A - 1 - i) 0.
27
+ Definition prr (i : nat) : sref := SRef 16 i 0.
28
+ Definition tb : nat := 16 + A.
29
+
30
+ (* 0 to 16: decode, fetch, operands, reads, propagate signals *)
31
+ Definition blk_P : block := Blk SW 1 (fun j => [sAND (lits pcb j)]).
32
+ Definition blk_HP : block := Blk A 1 (fun i => [sAND [(pcb i, true); (haltb, true)]]).
33
+ Definition blk_FA (o : nat) : block :=
34
+ Blk (A * SW) 1 (fun m => [sAND [(mu ((m mod SW + o) mod SW) (m / SW), true); (SRef 0 (m mod SW) 0, true)]]).
35
+ Definition blk_Q : block :=
36
+ Blk A 1 (fun i => [sOR (map (fun j => (SRef 0 j 0, true))
37
+ (filter (fun j => bitof ((j + 3) mod SW) i) (seq 0 SW)))]).
38
+ Definition blk_F : block :=
39
+ Blk (3 * A) 1 (fun m => [sOR (map (fun j => (SRef (2 + m / A) ((m mod A) * SW + j) 0, true)) (seq 0 SW))]).
40
+ Definition blk_PA : block := Blk SW 1 (fun j => [sAND (lits (opb 0) j)]).
41
+ Definition blk_PB : block := Blk SW 1 (fun j => [sAND (lits (opb 1) j)]).
42
+ Definition blk_AC : block := Blk 1 1 (fun _ => [sAND (map (fun t => (opb 2 t, true)) (seq 0 A))]).
43
+ Definition blk_W : block := Blk SW 1 (fun j => [sAND [(haltb, false); (SRef 8 j 0, true)]]).
44
+ Definition blk_RX : block :=
45
+ Blk (A * SW) 1 (fun m => [sAND [(mu (m mod SW) (m / SW), true); (SRef 7 (m mod SW) 0, true)]]).
46
+ Definition blk_RY : block :=
47
+ Blk (A * SW) 1 (fun m => [sAND [(mu (m mod SW) (m / SW), true); (SRef 8 (m mod SW) 0, true)]]).
48
+ Definition blk_KP : block :=
49
+ Blk (SW * A) 1 (fun m => [sAND [(mu (m / A) (m mod A), true); (SRef 10 (m / A) 0, false)]]).
50
+ Definition blk_X : block := Blk A 1 (fun t => [sOR (map (fun j => (SRef 11 (t * SW + j) 0, true)) (seq 0 SW))]).
51
+ Definition blk_Y : block := Blk A 1 (fun t => [sOR (map (fun j => (SRef 12 (t * SW + j) 0, true)) (seq 0 SW))]).
52
+ Definition blk_PR : block := Blk (A - 1) 1 (fun i => [sOR [(xv i, false); (yv i, true)]]).
53
+
54
+ (* 17 to 15 + A: the carry terms into bit k, for k = 1 .. A - 1 *)
55
+ Definition blk_T (k : nat) : block :=
56
+ Blk 1 (S k) (fun _ => sAND (map (fun i => (prr i, true)) (seq 0 k))
57
+ :: map (fun j => sAND ([(yv j, true); (xv j, false)]
58
+ ++ map (fun i => (prr i, true)) (seq (S j) (k - S j))))
59
+ (seq 0 k)).
60
+
61
+ (* tb to tb + 14: carries, equality, sum bits, branch, next counter, halt latch, next memory *)
62
+ Definition blk_C : block :=
63
+ Blk (A - 1) 1 (fun m => [sOR ((SRef (16 + S m) 0 0, true)
64
+ :: map (fun j => (SRef (16 + S m) 0 (S j), true)) (seq 0 (S m)))]).
65
+ Definition blk_AX : block := Blk A 1 (fun i => [sAND [(xv i, true); (yv i, true)]]).
66
+ Definition blk_NX : block := Blk A 1 (fun i => [sAND [(xv i, false); (yv i, false)]]).
67
+ Definition blk_XN : block := Blk A 1 (fun i => [sOR [(SRef (tb + 1) i 0, true); (SRef (tb + 2) i 0, true)]]).
68
+ Definition blk_EQ : block := Blk 1 1 (fun _ => [sAND (map (fun i => (SRef (tb + 3) i 0, true)) (seq 0 A))]).
69
+ Definition blk_R0 : block :=
70
+ Blk 1 3 (fun _ => [sOR [(yv 0, true); (xv 0, true)]; sOR [(yv 0, false); (xv 0, false)];
71
+ sAND [(SRef (tb + 5) 0 0, true); (SRef (tb + 5) 0 1, true)]]).
72
+ Definition blk_H : block :=
73
+ Blk (A - 1) 3 (fun m => map (fun b => SU b [(yv (S m), 1%Z); (xv (S m), (-1)%Z); (SRef tb m 0, 1%Z)])
74
+ [0%Z; (-1)%Z; (-2)%Z]).
75
+ Definition blk_R : block :=
76
+ Blk (A - 1) 1 (fun m => [SU (-1) [(SRef (tb + 6) m 0, 1%Z); (SRef (tb + 6) m 1, (-1)%Z);
77
+ (SRef (tb + 6) m 2, 1%Z)]]).
78
+ Definition blk_LEQ : block :=
79
+ Blk 1 1 (fun _ => [SU (-1) [(SRef (tb + 6) (A - 2) 0, 1%Z); (SRef (tb + 6) (A - 2) 1, (-1)%Z);
80
+ (SRef (tb + 6) (A - 2) 2, 1%Z); (SRef (tb + 4) 0 0, 1%Z)]]).
81
+ Definition rbit (k : nat) : sref := if Nat.eqb k 0 then SRef (tb + 5) 0 2 else SRef (tb + 7) (k - 1) 0.
82
+ Definition blk_TA : block :=
83
+ Blk A 1 (fun i => [sAND [(haltb, false); (SRef (tb + 8) 0 0, true); (opb 2 i, true)]]).
84
+ Definition blk_TB : block :=
85
+ Blk A 1 (fun i => [sAND [(haltb, false); (SRef (tb + 8) 0 0, false); (SRef 5 i 0, true)]]).
86
+ Definition blk_NP : block :=
87
+ Blk A 1 (fun i => [sOR [(SRef 1 i 0, true); (SRef (tb + 9) i 0, true); (SRef (tb + 10) i 0, true)]]).
88
+ Definition blk_HAB : block :=
89
+ Blk 1 3 (fun _ => [sAND [(haltb, false); (SRef (tb + 8) 0 0, true); (SRef 9 0 0, true)];
90
+ sAND [(haltb, false); (SRef (tb + 8) 0 0, false); (SRef 0 (SW - 4) 0, true)];
91
+ sOR [(haltb, true); (SRef (tb + 12) 0 0, true); (SRef (tb + 12) 0 1, true)]]).
92
+ Definition blk_WR : block :=
93
+ Blk (SW * A) 1 (fun m => [sAND [(rbit (A - 1 - m mod A), true); (SRef 10 (m / A) 0, true)]]).
94
+ Definition blk_NM : block := Blk (SW * A) 1 (fun m => [sOR [(SRef 13 m 0, true); (SRef (tb + 13) m 0, true)]]).
95
+
96
+ Definition hpre : list block :=
97
+ [blk_P; blk_HP; blk_FA 0; blk_FA 1; blk_FA 2; blk_Q; blk_F; blk_PA; blk_PB; blk_AC; blk_W; blk_RX; blk_RY;
98
+ blk_KP; blk_X; blk_Y; blk_PR].
99
+ Definition hpost : list block :=
100
+ [blk_C; blk_AX; blk_NX; blk_XN; blk_EQ; blk_R0; blk_H; blk_R; blk_LEQ; blk_TA; blk_TB; blk_NP; blk_HAB;
101
+ blk_WR; blk_NM].
102
+ Definition hblocks : list block := hpre ++ map blk_T (seq 1 (A - 1)) ++ hpost.
103
+
104
+ (* the unit computing the next value of each state bit *)
105
+ Definition hout (i : nat) : sref :=
106
+ if i <? A then SRef (tb + 11) i 0
107
+ else if Nat.eqb i A then SRef (tb + 12) 0 2
108
+ else SRef (tb + 14) (i - A - 1) 0.
109
+
110
+ Definition host_units : list tu := compile nH hblocks.
111
+ Definition host_next : list nat := map (fun i => idx nH hblocks (hout i)) (seq 0 nH).
112
+
113
+ (* ---- the machine: SUBLEQ on 2^A words of A bits, Definition 3.1 ------------------------ *)
114
+ Record hst := mkH { hpc : nat; hhalt : bool; hmem : list nat }.
115
+
116
+ Definition memv (s : hst) (j : nat) : nat := nth j (hmem s) 0.
117
+
118
+ Definition subleq (s : hst) : hst :=
119
+ if hhalt s then s
120
+ else
121
+ let p := hpc s in
122
+ let a := memv s p in
123
+ let b := memv s ((p + 1) mod SW) in
124
+ let c := memv s ((p + 2) mod SW) in
125
+ let r := (memv s b + SW - memv s a) mod SW in
126
+ let leq := Nat.eqb r 0 || Nat.leb (2 ^ (A - 1)) r in
127
+ let p' := if leq then c else (p + 3) mod SW in
128
+ mkH p' (Nat.eqb p' (SW - 1)) (map (fun j => if Nat.eqb j b then r else memv s j) (seq 0 SW)).
129
+
130
+ (* the state bits: the counter and each word most significant bit first *)
131
+ Definition wbits (v : nat) : list bool := map (bitof v) (seq 0 A).
132
+ Definition encodeH (s : hst) : list bool := wbits (hpc s) ++ [hhalt s] ++ concat (map wbits (hmem s)).
133
+
134
+ Definition hvalid (s : hst) : Prop :=
135
+ hpc s < SW /\ length (hmem s) = SW /\ Forall (fun v => v < SW) (hmem s).
136
+
137
+ End Host.
rocq/HostSem.v ADDED
@@ -0,0 +1,555 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (* The host netlist computes one step of SUBLEQ on 2^A words of A bits, from every state, for
2
+ every A >= 3 (Proposition 3.9). *)
3
+ From Stdlib Require Import List Bool Arith ZArith Lia.
4
+ Import ListNotations.
5
+ From TH Require Import TwoHead Net Gates PhysSem Host HostWF Adder.
6
+
7
+ (* ---- the state bits ----------------------------------------------------------------- *)
8
+ Lemma length_wbits : forall A v, length (wbits A v) = A.
9
+ Proof. intros A v. unfold wbits. rewrite length_map, length_seq. reflexivity. Qed.
10
+
11
+ Lemma nth_wbits : forall A v t, t < A -> nth t (wbits A v) false = bitof A v t.
12
+ Proof.
13
+ intros A v t Ht. unfold wbits. rewrite nth_map_d with (d' := 0) by (rewrite length_seq; lia).
14
+ rewrite seq_nth by lia. reflexivity.
15
+ Qed.
16
+
17
+ Lemma length_encodeH : forall A s, length (hmem s) = SW A -> length (encodeH A s) = nH A.
18
+ Proof.
19
+ intros A s H. unfold encodeH, nH. rewrite !length_app, length_wbits. cbn [length].
20
+ rewrite (length_concat_const _ _ A).
21
+ - rewrite length_map, H. lia.
22
+ - apply Forall_forall. intros l Hl. apply in_map_iff in Hl as (v & <- & _). apply length_wbits.
23
+ Qed.
24
+
25
+ Lemma nth_encodeH_pc : forall A s i, i < A -> nth i (encodeH A s) false = bitof A (hpc s) i.
26
+ Proof. intros A s i Hi. unfold encodeH. rewrite app_nth1 by (rewrite length_wbits; lia). apply nth_wbits. exact Hi. Qed.
27
+
28
+ Lemma nth_encodeH_halt : forall A s, nth A (encodeH A s) false = hhalt s.
29
+ Proof.
30
+ intros A s. unfold encodeH. rewrite app_nth2 by (rewrite length_wbits; lia).
31
+ rewrite length_wbits, Nat.sub_diag. reflexivity.
32
+ Qed.
33
+
34
+ Lemma nth_encodeH_mem : forall A s j t, length (hmem s) = SW A -> j < SW A -> t < A ->
35
+ nth (A + 1 + j * A + t) (encodeH A s) false = bitof A (memv s j) t.
36
+ Proof.
37
+ intros A s j t Hl Hj Ht. unfold encodeH. rewrite app_nth2 by (rewrite length_wbits; lia). rewrite length_wbits.
38
+ replace (A + 1 + j * A + t - A) with (S (A * j + t)) by lia. cbn [app nth].
39
+ rewrite (nth_concat_const _ false (map (wbits A) (hmem s)) A j t).
40
+ - rewrite nth_map_d with (d' := 0) by lia. apply nth_wbits. exact Ht.
41
+ - apply Forall_forall. intros l Hl'. apply in_map_iff in Hl' as (v & <- & _). apply length_wbits.
42
+ - rewrite length_map. lia.
43
+ - exact Ht.
44
+ Qed.
45
+
46
+ (* ---- addresses ---------------------------------------------------------------------- *)
47
+ Lemma bits_eqb : forall A p j, p < 2 ^ A -> j < 2 ^ A ->
48
+ forallb (fun t => Bool.eqb (bitof A p t) (bitof A j t)) (seq 0 A) = Nat.eqb p j.
49
+ Proof.
50
+ intros A p j Hp Hj. destruct (Nat.eqb_spec p j) as [->|E].
51
+ - apply forallb_forall. intros t _. apply eqb_reflx.
52
+ - apply Bool.not_true_is_false. intro F. apply E. apply (bits_eq_nat _ _ A Hp Hj).
53
+ intros i Hi. rewrite forallb_forall in F. specialize (F (A - 1 - i) ltac:(apply in_seq; lia)).
54
+ apply Bool.eqb_prop in F. unfold bitof in F. replace (A - 1 - (A - 1 - i)) with i in F by lia. exact F.
55
+ Qed.
56
+
57
+ Lemma testbits_eqb : forall A x y, x < 2 ^ A -> y < 2 ^ A ->
58
+ forallb (fun i => Bool.eqb (Nat.testbit x i) (Nat.testbit y i)) (seq 0 A) = Nat.eqb x y.
59
+ Proof.
60
+ intros A x y Hx Hy. destruct (Nat.eqb_spec x y) as [->|E].
61
+ - apply forallb_forall. intros t _. apply eqb_reflx.
62
+ - apply Bool.not_true_is_false. intro F. apply E. apply (bits_eq_nat _ _ A Hx Hy).
63
+ intros i Hi. rewrite forallb_forall in F. specialize (F i ltac:(apply in_seq; lia)).
64
+ apply Bool.eqb_prop in F. exact F.
65
+ Qed.
66
+
67
+ Lemma lits_fire : forall A (V : sref -> bool) f v w, v < 2 ^ A -> w < 2 ^ A ->
68
+ (forall t, t < A -> V (f t) = bitof A w t) -> forallb (litv V) (lits A f v) = Nat.eqb w v.
69
+ Proof.
70
+ intros A V f v w Hv Hw H. unfold lits. rewrite forallb_map', <- (bits_eqb A w v Hw Hv).
71
+ apply forallb_ext_in. intros t Ht. apply in_seq in Ht. unfold litv. cbn [fst snd]. rewrite H by lia. reflexivity.
72
+ Qed.
73
+
74
+ Lemma all_ones : forall A w, w < 2 ^ A -> forallb (bitof A w) (seq 0 A) = Nat.eqb w (2 ^ A - 1).
75
+ Proof.
76
+ intros A w Hw. rewrite <- (bits_eqb A w (2 ^ A - 1) Hw) by lia.
77
+ apply forallb_ext_in. intros t Ht. apply in_seq in Ht.
78
+ assert (B : bitof A (2 ^ A - 1) t = true).
79
+ { unfold bitof. replace (2 ^ A - 1) with (Nat.ones A) by (rewrite Nat.ones_equiv; lia).
80
+ apply Nat.ones_spec_low. lia. }
81
+ rewrite B. destruct (bitof A w t); reflexivity.
82
+ Qed.
83
+
84
+ Lemma existsb_filter_eq : forall (f : nat -> bool) p n, p < n ->
85
+ existsb (fun j => Nat.eqb p j) (filter f (seq 0 n)) = f p.
86
+ Proof.
87
+ intros f p n Hp. assert (E : forall l, existsb (fun j => Nat.eqb p j) (filter f l) = existsb (fun j => Nat.eqb p j && f j) l).
88
+ { induction l as [|a l IH]; [reflexivity|]. cbn [filter existsb]. destruct (f a) eqn:Fa; cbn [existsb];
89
+ rewrite IH; destruct (Nat.eqb p a); reflexivity. }
90
+ rewrite E, existsb_pick. replace ((0 <=? p) && (p <? 0 + n)) with true by (symmetry; apply andb_true_iff; split;
91
+ [apply Nat.leb_le | apply Nat.ltb_lt]; lia). reflexivity.
92
+ Qed.
93
+
94
+ Lemma existsb_pick_r : forall (g : nat -> bool) c n, c < n ->
95
+ existsb (fun a => g a && Nat.eqb c a) (seq 0 n) = g c.
96
+ Proof.
97
+ intros g c n Hc. rewrite (existsb_ext_in _ _ (fun a => Nat.eqb c a && g a)) by (intros a _; apply andb_comm).
98
+ rewrite existsb_pick. replace ((0 <=? c) && (c <? 0 + n)) with true by (symmetry; apply andb_true_iff; split;
99
+ [apply Nat.leb_le | apply Nat.ltb_lt]; lia). reflexivity.
100
+ Qed.
101
+
102
+ (* ---- the step, block by block --------------------------------------------------------- *)
103
+ Section HSem.
104
+ Variables (A : nat) (s : hst).
105
+ Hypotheses (HA : 3 <= A) (Hv : hvalid A s).
106
+
107
+ Let HS : 8 <= SW A := SW_ge A HA.
108
+
109
+ Definition hp : nat := hpc s.
110
+ Definition hh : bool := hhalt s.
111
+ Definition mv (j : nat) : nat := memv s j.
112
+
113
+ Lemma hp_lt : hp < SW A.
114
+ Proof. destruct Hv as (H & _ & _). exact H. Qed.
115
+
116
+ Lemma mv_lt : forall j, j < SW A -> mv j < SW A.
117
+ Proof.
118
+ destruct Hv as (_ & Hl & Hf). intros j Hj. unfold mv, memv. rewrite Forall_forall in Hf.
119
+ apply Hf. apply nth_In. lia.
120
+ Qed.
121
+
122
+ Definition HX (i : nat) : bool := nth i (encodeH A s) false.
123
+ Definition HF (x : sref) : bool := run (host_units A) (nH A) HX (idx (nH A) (hblocks A) x).
124
+
125
+ Lemma HX_pc : forall i, i < A -> HX i = bitof A hp i.
126
+ Proof. intros i Hi. apply nth_encodeH_pc. exact Hi. Qed.
127
+
128
+ Lemma HX_mu : forall j t, j < SW A -> t < A -> HX (A + 1 + j * A + t) = bitof A (mv j) t.
129
+ Proof. destruct Hv as (_ & Hl & _). intros j t Hj Ht. apply nth_encodeH_mem; assumption. Qed.
130
+
131
+ Lemma HF_in : forall i, i < nH A -> HF (SIn i) = HX i.
132
+ Proof. intros i H. unfold HF, host_units. apply net_in. exact H. Qed.
133
+
134
+ Lemma HF_pc : forall i, i < A -> HF (pcb i) = bitof A hp i.
135
+ Proof. intros i Hi. unfold pcb. rewrite HF_in by (unfold nH; lia). apply HX_pc. exact Hi. Qed.
136
+
137
+ Lemma HF_halt : HF (haltb A) = hh.
138
+ Proof. unfold haltb. rewrite HF_in by (unfold nH; lia). apply nth_encodeH_halt. Qed.
139
+
140
+ Lemma HF_mu : forall j t, j < SW A -> t < A -> HF (mu A j t) = bitof A (mv j) t.
141
+ Proof. intros j t Hj Ht. unfold mu. rewrite HF_in by (unfold nH; nia). apply HX_mu; assumption. Qed.
142
+
143
+ Lemma HF_unit : forall b j r, b < length (hblocks A) ->
144
+ j < bcount (nth b (hblocks A) blk0) -> r < bsize (nth b (hblocks A) blk0) ->
145
+ HF (SRef b j r) = sfire' (sunit (hblocks A) b j r) HF.
146
+ Proof.
147
+ intros b j r Hb Hj Hr. unfold HF, host_units.
148
+ apply net_unit; [apply host_wf; exact HA | exact Hb | exact Hj | exact Hr].
149
+ Qed.
150
+
151
+ (* the units of the blocks before the carry terms, after them, and the carry terms *)
152
+ Lemma HF_pre : forall b j r, b < 17 -> j < bcount (nth b (hpre A) blk0) -> r < bsize (nth b (hpre A) blk0) ->
153
+ HF (SRef b j r) = sfire' (nth r (bshape (nth b (hpre A) blk0) j) su0) HF.
154
+ Proof.
155
+ intros b j r Hb Hj Hr. rewrite HF_unit; unfold sunit; rewrite ?nth_hb_pre by exact Hb; try reflexivity; try assumption.
156
+ rewrite length_hblocks by lia. unfold tb. lia.
157
+ Qed.
158
+
159
+ Lemma HF_post : forall i j r, i < 15 -> j < bcount (nth i (hpost A) blk0) -> r < bsize (nth i (hpost A) blk0) ->
160
+ HF (SRef (tb A + i) j r) = sfire' (nth r (bshape (nth i (hpost A) blk0) j) su0) HF.
161
+ Proof.
162
+ intros i j r Hi Hj Hr. rewrite HF_unit; unfold sunit; rewrite ?nth_hb_post by lia; try reflexivity; try assumption.
163
+ rewrite length_hblocks by lia. lia.
164
+ Qed.
165
+
166
+ Lemma HF_Tu : forall k r, 1 <= k -> k < A -> r < S k ->
167
+ HF (SRef (16 + k) 0 r) = sfire' (nth r (bshape (blk_T A k) 0) su0) HF.
168
+ Proof.
169
+ intros k r H1 H2 H3. rewrite HF_unit; unfold sunit; rewrite ?nth_hb_T by assumption; try reflexivity.
170
+ - rewrite length_hblocks by lia. unfold tb. lia.
171
+ - cbn [bcount blk_T]. lia.
172
+ - cbn [bsize blk_T]. exact H3.
173
+ Qed.
174
+
175
+ Ltac pre_fire b := rewrite (HF_pre b) by (cbn [nth hpre bcount bsize blk_P blk_HP blk_FA blk_Q blk_F blk_PA blk_PB
176
+ blk_AC blk_W blk_RX blk_RY blk_KP blk_X blk_Y blk_PR]; nia);
177
+ cbn [nth hpre bshape blk_P blk_HP blk_FA blk_Q blk_F blk_PA blk_PB blk_AC blk_W blk_RX blk_RY blk_KP blk_X blk_Y
178
+ blk_PR].
179
+
180
+ Ltac post_fire i := rewrite (HF_post i) by (cbn [nth hpost bcount bsize blk_C blk_AX blk_NX blk_XN blk_EQ blk_R0
181
+ blk_H blk_R blk_LEQ blk_TA blk_TB blk_NP blk_HAB blk_WR blk_NM]; nia);
182
+ cbn [nth hpost bshape blk_C blk_AX blk_NX blk_XN blk_EQ blk_R0 blk_H blk_R blk_LEQ blk_TA blk_TB blk_NP blk_HAB
183
+ blk_WR blk_NM].
184
+
185
+ (* 0: decode lines of the counter *)
186
+ Lemma HF_P : forall j, j < SW A -> HF (SRef 0 j 0) = Nat.eqb hp j.
187
+ Proof.
188
+ intros j Hj. pre_fire 0. rewrite sAND_fire. apply (lits_fire A HF (pcb) j hp Hj hp_lt).
189
+ intros t Ht. apply HF_pc. exact Ht.
190
+ Qed.
191
+
192
+ (* 1 *)
193
+ Lemma HF_HP : forall i, i < A -> HF (SRef 1 i 0) = bitof A hp i && hh.
194
+ Proof.
195
+ intros i Hi. pre_fire 1. rewrite sAND_fire. cbn [forallb]. rewrite !litv_pos, HF_pc, HF_halt by exact Hi.
196
+ rewrite andb_true_r. reflexivity.
197
+ Qed.
198
+
199
+ (* 2, 3, 4: the fetch conjunctions *)
200
+ Lemma HF_FA : forall o m, o < 3 -> m < A * SW A ->
201
+ HF (SRef (2 + o) m 0) = bitof A (mv ((m mod SW A + o) mod SW A)) (m / SW A) && Nat.eqb hp (m mod SW A).
202
+ Proof.
203
+ intros o m Ho Hm. pose proof (Nat.mod_upper_bound m (SW A) ltac:(lia)).
204
+ pose proof (Nat.Div0.div_lt_upper_bound m (SW A) A ltac:(lia)).
205
+ assert (E : HF (SRef (2 + o) m 0)
206
+ = forallb (litv HF) [(mu A ((m mod SW A + o) mod SW A) (m / SW A), true); (SRef 0 (m mod SW A) 0, true)]).
207
+ { destruct o as [|[|[|o]]]; [pre_fire 2 | pre_fire 3 | pre_fire 4 | lia]; apply sAND_fire. }
208
+ rewrite E. cbn [forallb]. rewrite !litv_pos, andb_true_r.
209
+ rewrite HF_mu by (try apply Nat.mod_upper_bound; lia). rewrite HF_P by lia. reflexivity.
210
+ Qed.
211
+
212
+ (* 5: the bits of p + 3 *)
213
+ Lemma HF_Q : forall i, i < A -> HF (SRef 5 i 0) = bitof A ((hp + 3) mod SW A) i.
214
+ Proof.
215
+ intros i Hi. pre_fire 5. rewrite sOR_fire, existsb_map'.
216
+ rewrite (existsb_ext_in _ _ (fun j => Nat.eqb hp j)).
217
+ - apply (existsb_filter_eq (fun j => bitof A ((j + 3) mod SW A) i) hp (SW A) hp_lt).
218
+ - intros j Hj. apply filter_In in Hj as [Hj _]. apply in_seq in Hj. rewrite litv_pos. apply HF_P. lia.
219
+ Qed.
220
+
221
+ (* 6: the operands *)
222
+ Lemma HF_F : forall m, m < 3 * A -> HF (SRef 6 m 0) = bitof A (mv ((hp + m / A) mod SW A)) (m mod A).
223
+ Proof.
224
+ intros m Hm. pose proof (Nat.Div0.div_lt_upper_bound m A 3 ltac:(lia)). pose proof (Nat.mod_upper_bound m A ltac:(lia)).
225
+ pre_fire 6. rewrite sOR_fire, existsb_map'.
226
+ rewrite (existsb_ext_in _ _ (fun j => bitof A (mv ((j + m / A) mod SW A)) (m mod A) && Nat.eqb hp j)).
227
+ - apply (existsb_pick_r (fun j => bitof A (mv ((j + m / A) mod SW A)) (m mod A))). exact hp_lt.
228
+ - intros j Hj. apply in_seq in Hj. rewrite litv_pos. rewrite HF_FA by (try lia; nia).
229
+ replace ((m mod A * SW A + j) mod SW A) with j
230
+ by (rewrite (Nat.add_comm (m mod A * SW A) j), Nat.Div0.mod_add, Nat.mod_small by lia; reflexivity).
231
+ replace ((m mod A * SW A + j) / SW A) with (m mod A)
232
+ by (rewrite (Nat.add_comm (m mod A * SW A) j), Nat.div_add, Nat.div_small by lia; lia).
233
+ reflexivity.
234
+ Qed.
235
+
236
+ Definition ha : nat := mv hp.
237
+ Definition hb : nat := mv ((hp + 1) mod SW A).
238
+ Definition hc : nat := mv ((hp + 2) mod SW A).
239
+
240
+ Lemma ha_lt : ha < SW A.
241
+ Proof. apply mv_lt. exact hp_lt. Qed.
242
+ Lemma hb_lt : hb < SW A.
243
+ Proof. apply mv_lt. apply Nat.mod_upper_bound. lia. Qed.
244
+ Lemma hc_lt : hc < SW A.
245
+ Proof. apply mv_lt. apply Nat.mod_upper_bound. lia. Qed.
246
+
247
+ Lemma HF_opb : forall o t, o < 3 -> t < A -> HF (opb A o t) = bitof A (mv ((hp + o) mod SW A)) t.
248
+ Proof.
249
+ intros o t Ho Ht. unfold opb. rewrite HF_F by nia.
250
+ replace ((o * A + t) / A) with o by (rewrite Nat.add_comm, Nat.div_add, Nat.div_small by lia; lia).
251
+ replace ((o * A + t) mod A) with t by (rewrite Nat.add_comm, Nat.Div0.mod_add, Nat.mod_small by lia; reflexivity).
252
+ reflexivity.
253
+ Qed.
254
+
255
+ Lemma HF_opa : forall t, t < A -> HF (opb A 0 t) = bitof A ha t.
256
+ Proof. intros t Ht. rewrite HF_opb by lia. rewrite Nat.add_0_r, Nat.mod_small by exact hp_lt. reflexivity. Qed.
257
+
258
+ (* 7, 8: decode lines of A and B *)
259
+ Lemma HF_PA : forall j, j < SW A -> HF (SRef 7 j 0) = Nat.eqb ha j.
260
+ Proof.
261
+ intros j Hj. pre_fire 7. rewrite sAND_fire. apply (lits_fire A HF (opb A 0) j ha Hj ha_lt).
262
+ intros t Ht. apply HF_opa. exact Ht.
263
+ Qed.
264
+
265
+ Lemma HF_PB : forall j, j < SW A -> HF (SRef 8 j 0) = Nat.eqb hb j.
266
+ Proof.
267
+ intros j Hj. pre_fire 8. rewrite sAND_fire. apply (lits_fire A HF (opb A 1) j hb Hj hb_lt).
268
+ intros t Ht. rewrite HF_opb by lia. reflexivity.
269
+ Qed.
270
+
271
+ (* 9: C is the halt address *)
272
+ Lemma HF_AC : HF (SRef 9 0 0) = Nat.eqb hc (SW A - 1).
273
+ Proof.
274
+ pre_fire 9. rewrite sAND_fire, forallb_map'. unfold SW. rewrite <- all_ones by exact hc_lt.
275
+ apply forallb_ext_in. intros t Ht. apply in_seq in Ht. rewrite litv_pos, HF_opb by lia. reflexivity.
276
+ Qed.
277
+
278
+ (* 10: write enables *)
279
+ Lemma HF_W : forall j, j < SW A -> HF (SRef 10 j 0) = negb hh && Nat.eqb hb j.
280
+ Proof.
281
+ intros j Hj. pre_fire 10. rewrite sAND_fire. cbn [forallb]. rewrite litv_neg, litv_pos, HF_halt, HF_PB by exact Hj.
282
+ rewrite andb_true_r. reflexivity.
283
+ Qed.
284
+
285
+ (* 11, 12: read conjunctions *)
286
+ Lemma HF_RX : forall m, m < A * SW A ->
287
+ HF (SRef 11 m 0) = bitof A (mv (m mod SW A)) (m / SW A) && Nat.eqb ha (m mod SW A).
288
+ Proof.
289
+ intros m Hm. pose proof (Nat.mod_upper_bound m (SW A) ltac:(lia)).
290
+ pose proof (Nat.Div0.div_lt_upper_bound m (SW A) A ltac:(lia)).
291
+ pre_fire 11. rewrite sAND_fire. cbn [forallb]. rewrite !litv_pos, HF_mu, HF_PA by lia. rewrite andb_true_r. reflexivity.
292
+ Qed.
293
+
294
+ Lemma HF_RY : forall m, m < A * SW A ->
295
+ HF (SRef 12 m 0) = bitof A (mv (m mod SW A)) (m / SW A) && Nat.eqb hb (m mod SW A).
296
+ Proof.
297
+ intros m Hm. pose proof (Nat.mod_upper_bound m (SW A) ltac:(lia)).
298
+ pose proof (Nat.Div0.div_lt_upper_bound m (SW A) A ltac:(lia)).
299
+ pre_fire 12. rewrite sAND_fire. cbn [forallb]. rewrite !litv_pos, HF_mu, HF_PB by lia. rewrite andb_true_r. reflexivity.
300
+ Qed.
301
+
302
+ (* 13: the cells kept *)
303
+ Lemma HF_KP : forall m, m < SW A * A ->
304
+ HF (SRef 13 m 0) = bitof A (mv (m / A)) (m mod A) && negb (negb hh && Nat.eqb hb (m / A)).
305
+ Proof.
306
+ intros m Hm. pose proof (Nat.mod_upper_bound m A ltac:(lia)).
307
+ pose proof (Nat.Div0.div_lt_upper_bound m A (SW A) ltac:(lia)).
308
+ pre_fire 13. rewrite sAND_fire. cbn [forallb]. rewrite litv_pos, litv_neg, HF_mu, HF_W by lia.
309
+ rewrite andb_true_r. reflexivity.
310
+ Qed.
311
+
312
+ (* 14, 15: x = M[A], y = M[B] *)
313
+ Definition hx : nat := mv ha.
314
+ Definition hy : nat := mv hb.
315
+
316
+ Lemma HF_X : forall t, t < A -> HF (SRef 14 t 0) = bitof A hx t.
317
+ Proof.
318
+ intros t Ht. pre_fire 14. rewrite sOR_fire, existsb_map'.
319
+ rewrite (existsb_ext_in _ _ (fun j => bitof A (mv j) t && Nat.eqb ha j)).
320
+ - apply (existsb_pick_r (fun j => bitof A (mv j) t)). exact ha_lt.
321
+ - intros j Hj. apply in_seq in Hj. rewrite litv_pos, HF_RX by nia.
322
+ rewrite (Nat.add_comm (t * SW A) j), Nat.Div0.mod_add, Nat.mod_small by lia.
323
+ replace ((j + t * SW A) / SW A) with t by (rewrite Nat.div_add, Nat.div_small by lia; lia).
324
+ reflexivity.
325
+ Qed.
326
+
327
+ Lemma HF_Y : forall t, t < A -> HF (SRef 15 t 0) = bitof A hy t.
328
+ Proof.
329
+ intros t Ht. pre_fire 15. rewrite sOR_fire, existsb_map'.
330
+ rewrite (existsb_ext_in _ _ (fun j => bitof A (mv j) t && Nat.eqb hb j)).
331
+ - apply (existsb_pick_r (fun j => bitof A (mv j) t)). exact hb_lt.
332
+ - intros j Hj. apply in_seq in Hj. rewrite litv_pos, HF_RY by nia.
333
+ rewrite (Nat.add_comm (t * SW A) j), Nat.Div0.mod_add, Nat.mod_small by lia.
334
+ replace ((j + t * SW A) / SW A) with t by (rewrite Nat.div_add, Nat.div_small by lia; lia).
335
+ reflexivity.
336
+ Qed.
337
+
338
+ Lemma HF_xv : forall i, i < A -> HF (xv A i) = Nat.testbit hx i.
339
+ Proof. intros i Hi. unfold xv. rewrite HF_X by lia. unfold bitof. f_equal. lia. Qed.
340
+
341
+ Lemma HF_yv : forall i, i < A -> HF (yv A i) = Nat.testbit hy i.
342
+ Proof. intros i Hi. unfold yv. rewrite HF_Y by lia. unfold bitof. f_equal. lia. Qed.
343
+
344
+ (* 16: propagate signals *)
345
+ Lemma HF_PR : forall i, i < A - 1 -> HF (prr i) = pg hx hy i.
346
+ Proof.
347
+ intros i Hi. unfold prr. pre_fire 16. rewrite sOR_fire. cbn [existsb]. rewrite litv_neg, litv_pos, HF_xv, HF_yv by lia.
348
+ rewrite orb_false_r. reflexivity.
349
+ Qed.
350
+
351
+ (* 17 to 15 + A: the carry terms *)
352
+ Lemma HF_Tn : forall k, 1 <= k -> k < A -> HF (SRef (16 + k) 0 0) = forallb (pg hx hy) (seq 0 k).
353
+ Proof.
354
+ intros k H1 H2. rewrite HF_Tu by lia. cbn [bshape blk_T nth]. rewrite sAND_fire, forallb_map'.
355
+ apply forallb_ext_in. intros i Hi. apply in_seq in Hi. rewrite litv_pos. apply HF_PR. lia.
356
+ Qed.
357
+
358
+ Lemma HF_Tj : forall k j, 1 <= k -> k < A -> j < k ->
359
+ HF (SRef (16 + k) 0 (S j)) = gb hx hy j && forallb (pg hx hy) (seq (S j) (k - S j)).
360
+ Proof.
361
+ intros k j H1 H2 H3. rewrite HF_Tu by lia. cbn [bshape blk_T nth].
362
+ rewrite nth_map_d with (d' := 0) by (rewrite length_seq; lia). rewrite seq_nth by lia.
363
+ rewrite sAND_fire. cbn [Nat.add forallb]. rewrite forallb_app. cbn [forallb].
364
+ rewrite litv_pos, litv_neg, HF_xv, HF_yv by lia. rewrite andb_true_r, forallb_map'.
365
+ rewrite (forallb_ext_in _ _ (pg hx hy)).
366
+ - unfold gb, xb, yb. reflexivity.
367
+ - intros i Hi. apply in_seq in Hi. rewrite litv_pos. apply HF_PR. lia.
368
+ Qed.
369
+
370
+ (* tb: carries *)
371
+ Lemma HF_C : forall m, m < A - 1 -> HF (SRef (tb A) m 0) = carry hx hy (S m).
372
+ Proof.
373
+ intros m Hm. rewrite <- (Nat.add_0_r (tb A)). post_fire 0. rewrite sOR_fire. cbn [existsb]. rewrite litv_pos.
374
+ rewrite HF_Tn by lia. rewrite existsb_map'.
375
+ rewrite (existsb_ext_in _ _ (fun j => gb hx hy j && forallb (pg hx hy) (seq (S j) (S m - S j)))).
376
+ - rewrite carry_closed. reflexivity.
377
+ - intros j Hj. apply in_seq in Hj. rewrite litv_pos. apply HF_Tj; lia.
378
+ Qed.
379
+
380
+ (* tb + 1 to tb + 4: equality *)
381
+ Lemma HF_XN : forall i, i < A -> HF (SRef (tb A + 3) i 0) = Bool.eqb (Nat.testbit hx i) (Nat.testbit hy i).
382
+ Proof.
383
+ intros i Hi. post_fire 3. rewrite sOR_fire. cbn [existsb]. rewrite !litv_pos, orb_false_r.
384
+ post_fire 1. post_fire 2. rewrite !sAND_fire. cbn [forallb]. rewrite !litv_pos, !litv_neg, HF_xv, HF_yv by lia.
385
+ destruct (Nat.testbit hx i), (Nat.testbit hy i); reflexivity.
386
+ Qed.
387
+
388
+ Lemma HF_EQ : HF (SRef (tb A + 4) 0 0) = Nat.eqb hx hy.
389
+ Proof.
390
+ post_fire 4. rewrite sAND_fire, forallb_map'. unfold SW in *.
391
+ rewrite <- (testbits_eqb A hx hy) by (apply mv_lt; first [exact ha_lt | exact hb_lt]).
392
+ apply forallb_ext_in. intros i Hi. apply in_seq in Hi. rewrite litv_pos. apply HF_XN. lia.
393
+ Qed.
394
+
395
+ (* tb + 5 to tb + 7: the sum bits *)
396
+ Lemma HF_R0 : HF (SRef (tb A + 5) 0 2) = sumbit hx hy 0.
397
+ Proof.
398
+ post_fire 5. rewrite sAND_fire. cbn [forallb]. rewrite !litv_pos, andb_true_r.
399
+ post_fire 5. post_fire 5. rewrite !sOR_fire. cbn [existsb]. rewrite !litv_pos, !litv_neg, HF_xv, HF_yv by lia.
400
+ unfold sumbit, xb, yb. cbn [carry]. destruct (Nat.testbit hx 0), (Nat.testbit hy 0); reflexivity.
401
+ Qed.
402
+
403
+ Definition cnt (k : nat) : nat :=
404
+ (if yb hy k then 1 else 0) + (if xb hx k then 0 else 1) + (if carry hx hy k then 1 else 0).
405
+
406
+ Lemma HF_H : forall m u, m < A - 1 -> u < 3 -> HF (SRef (tb A + 6) m u) = Nat.leb (S u) (cnt (S m)).
407
+ Proof.
408
+ intros m u Hm Hu. post_fire 6. rewrite nth_map_d with (d' := 0%Z) by (cbn [length]; lia).
409
+ unfold sfire'. cbn [sb sin swsum]. rewrite HF_xv, HF_yv by lia. rewrite HF_C by lia.
410
+ unfold cnt, xb, yb. destruct u as [|[|[|u]]]; [| | | lia]; cbn [nth];
411
+ destruct (Nat.testbit hy (S m)), (Nat.testbit hx (S m)), (carry hx hy (S m)); reflexivity.
412
+ Qed.
413
+
414
+ Lemma HF_R : forall m, m < A - 1 -> HF (SRef (tb A + 7) m 0) = sumbit hx hy (S m).
415
+ Proof.
416
+ intros m Hm. post_fire 7. unfold sfire'. cbn [sb sin swsum]. rewrite !HF_H by lia.
417
+ unfold sumbit, cnt, xb, yb. destruct (Nat.testbit hy (S m)), (Nat.testbit hx (S m)), (carry hx hy (S m)); reflexivity.
418
+ Qed.
419
+
420
+ Lemma HF_rbit : forall k, k < A -> HF (rbit A k) = sumbit hx hy k.
421
+ Proof.
422
+ intros k Hk. unfold rbit. destruct (Nat.eqb_spec k 0) as [->|E]; [apply HF_R0|].
423
+ rewrite HF_R by lia. f_equal. lia.
424
+ Qed.
425
+
426
+ (* the difference and the branch *)
427
+ Definition hr : nat := (hy + SW A - hx) mod SW A.
428
+ Definition hleq : bool := Nat.eqb hr 0 || Nat.leb (2 ^ (A - 1)) hr.
429
+
430
+ Lemma hx_lt : hx < 2 ^ A.
431
+ Proof. apply mv_lt. exact ha_lt. Qed.
432
+ Lemma hy_lt : hy < 2 ^ A.
433
+ Proof. apply mv_lt. exact hb_lt. Qed.
434
+
435
+ Lemma hr_bits : forall k, k < A -> Nat.testbit hr k = sumbit hx hy k.
436
+ Proof. intros k Hk. unfold hr, SW. apply sub_bits; [exact hx_lt | exact hy_lt | exact Hk]. Qed.
437
+
438
+ (* tb + 8: the branch *)
439
+ Lemma HF_LEQ : HF (SRef (tb A + 8) 0 0) = hleq.
440
+ Proof.
441
+ post_fire 8. unfold sfire'. cbn [sb sin swsum]. rewrite !HF_H by lia. rewrite HF_EQ.
442
+ replace (S (A - 2)) with (A - 1) by lia.
443
+ assert (T : sumbit hx hy (A - 1) = Nat.leb (2 ^ (A - 1)) hr).
444
+ { rewrite <- hr_bits by lia. apply testbit_top; [lia|]. unfold hr, SW. apply Nat.mod_upper_bound, Nat.pow_nonzero.
445
+ lia. }
446
+ assert (Z : Nat.eqb hx hy = Nat.eqb hr 0).
447
+ { unfold hr, SW. rewrite sub_zero; [reflexivity | exact hx_lt | exact hy_lt]. }
448
+ unfold hleq. rewrite <- T, <- Z. unfold sumbit, cnt, xb, yb.
449
+ destruct (Nat.testbit hy (A - 1)), (Nat.testbit hx (A - 1)), (carry hx hy (A - 1)), (Nat.eqb hx hy); reflexivity.
450
+ Qed.
451
+
452
+ (* tb + 9 to tb + 11: the next counter *)
453
+ Lemma HF_NP : forall i, i < A ->
454
+ HF (SRef (tb A + 11) i 0) = (bitof A hp i && hh) || (negb hh && hleq && bitof A hc i)
455
+ || (negb hh && negb hleq && bitof A ((hp + 3) mod SW A) i).
456
+ Proof.
457
+ intros i Hi. post_fire 11. rewrite sOR_fire. cbn [existsb]. rewrite !litv_pos, orb_false_r.
458
+ rewrite HF_HP by exact Hi. post_fire 9. post_fire 10. rewrite !sAND_fire. cbn [forallb].
459
+ rewrite !litv_pos, !litv_neg, HF_halt, HF_LEQ, HF_Q by exact Hi. rewrite HF_opb by lia.
460
+ rewrite !andb_true_r, !andb_assoc, orb_assoc. reflexivity.
461
+ Qed.
462
+
463
+ (* tb + 12: the halt latch *)
464
+ Lemma HF_NH : HF (SRef (tb A + 12) 0 2) =
465
+ hh || (negb hh && hleq && Nat.eqb hc (SW A - 1)) || (negb hh && negb hleq && Nat.eqb hp (SW A - 4)).
466
+ Proof.
467
+ post_fire 12. rewrite sOR_fire. cbn [existsb]. rewrite !litv_pos, orb_false_r, HF_halt.
468
+ post_fire 12. post_fire 12. rewrite !sAND_fire. cbn [forallb].
469
+ rewrite !litv_pos, !litv_neg, HF_halt, HF_LEQ, HF_AC, HF_P by lia.
470
+ rewrite !andb_true_r, !andb_assoc, orb_assoc. reflexivity.
471
+ Qed.
472
+
473
+ (* tb + 13, tb + 14: the next memory *)
474
+ Lemma HF_NM : forall m, m < SW A * A ->
475
+ HF (SRef (tb A + 14) m 0) =
476
+ (bitof A (mv (m / A)) (m mod A) && negb (negb hh && Nat.eqb hb (m / A)))
477
+ || (bitof A hr (m mod A) && (negb hh && Nat.eqb hb (m / A))).
478
+ Proof.
479
+ intros m Hm. pose proof (Nat.mod_upper_bound m A ltac:(lia)).
480
+ pose proof (Nat.Div0.div_lt_upper_bound m A (SW A) ltac:(lia)).
481
+ post_fire 14. rewrite sOR_fire. cbn [existsb]. rewrite !litv_pos, orb_false_r. rewrite HF_KP by exact Hm.
482
+ post_fire 13. rewrite sAND_fire. cbn [forallb]. rewrite !litv_pos, andb_true_r, HF_rbit, HF_W by lia.
483
+ rewrite <- hr_bits by lia. unfold bitof. reflexivity.
484
+ Qed.
485
+
486
+ End HSem.
487
+
488
+ (* ---- the step ------------------------------------------------------------------------ *)
489
+ Lemma p3_halt : forall A p, 3 <= A -> p < SW A -> Nat.eqb ((p + 3) mod SW A) (SW A - 1) = Nat.eqb p (SW A - 4).
490
+ Proof.
491
+ intros A p HA Hp. pose proof (SW_ge A HA).
492
+ destruct (Nat.lt_ge_cases (p + 3) (SW A)) as [L|L].
493
+ - rewrite Nat.mod_small by exact L. destruct (Nat.eqb_spec (p + 3) (SW A - 1)), (Nat.eqb_spec p (SW A - 4)); lia.
494
+ - replace (p + 3) with ((p + 3 - SW A) + 1 * SW A) by lia. rewrite Nat.Div0.mod_add, Nat.mod_small by lia.
495
+ destruct (Nat.eqb_spec (p + 3 - SW A) (SW A - 1)), (Nat.eqb_spec p (SW A - 4)); lia.
496
+ Qed.
497
+
498
+ (* the step of the machine in the names of the section *)
499
+ Lemma subleq_halted : forall A s, hhalt s = true -> subleq A s = s.
500
+ Proof. intros A s H. unfold subleq. rewrite H. reflexivity. Qed.
501
+
502
+ Lemma subleq_run : forall A s, hhalt s = false ->
503
+ subleq A s = mkH (if hleq A s then hc A s else (hp s + 3) mod SW A)
504
+ (Nat.eqb (if hleq A s then hc A s else (hp s + 3) mod SW A) (SW A - 1))
505
+ (map (fun j => if Nat.eqb j (hb A s) then hr A s else memv s j) (seq 0 (SW A))).
506
+ Proof. intros A s H. unfold subleq. rewrite H. reflexivity. Qed.
507
+
508
+ Lemma memv_run : forall A s j, hhalt s = false -> j < SW A ->
509
+ memv (subleq A s) j = if Nat.eqb j (hb A s) then hr A s else memv s j.
510
+ Proof.
511
+ intros A s j H Hj. rewrite subleq_run by exact H. unfold memv at 1. cbn [hmem].
512
+ rewrite nth_map_seq by exact Hj. reflexivity.
513
+ Qed.
514
+
515
+ Theorem host_step : forall A s, 3 <= A -> hvalid A s ->
516
+ netstep (nH A) (host_units A) (host_next A) (encodeH A s) = encodeH A (subleq A s).
517
+ Proof.
518
+ intros A s HA Hv. pose proof (SW_ge A HA) as HS. pose proof Hv as (Hp & Hl & Hf).
519
+ assert (Hl' : length (hmem (subleq A s)) = SW A).
520
+ { unfold subleq. destruct (hhalt s); [exact Hl|]. cbn [hmem]. rewrite length_map, length_seq. reflexivity. }
521
+ unfold netstep, host_next. rewrite map_map.
522
+ apply nth_ext with (d := false) (d' := false).
523
+ { rewrite length_map, length_seq, length_encodeH by exact Hl'. reflexivity. }
524
+ intros i Hi. rewrite length_map, length_seq in Hi.
525
+ rewrite (nth_map_seq _ (fun i => run (host_units A) (nH A) (fun i0 => nth i0 (encodeH A s) false)
526
+ (idx (nH A) (hblocks A) (hout A i))) (nH A) i false Hi).
527
+ change (run (host_units A) (nH A) (fun i0 => nth i0 (encodeH A s) false) (idx (nH A) (hblocks A) (hout A i)))
528
+ with (HF A s (hout A i)).
529
+ unfold hout. destruct (Nat.ltb_spec i A) as [Hi1|Hi1].
530
+ - (* the counter *)
531
+ rewrite HF_NP by assumption. rewrite nth_encodeH_pc by exact Hi1. unfold hh.
532
+ destruct (hhalt s) eqn:Eh.
533
+ + rewrite subleq_halted by exact Eh. cbn [negb andb orb]. rewrite andb_true_r, !orb_false_r. reflexivity.
534
+ + rewrite subleq_run by exact Eh. cbn [hpc negb andb orb]. rewrite andb_false_r, orb_false_l.
535
+ destruct (hleq A s); cbn [negb andb orb]; rewrite ?orb_false_r; reflexivity.
536
+ - destruct (Nat.eqb_spec i A) as [->|Hi2].
537
+ + (* the halt bit *)
538
+ rewrite HF_NH by assumption. rewrite nth_encodeH_halt. unfold hh.
539
+ destruct (hhalt s) eqn:Eh.
540
+ * rewrite subleq_halted by exact Eh. rewrite Eh. reflexivity.
541
+ * rewrite subleq_run by exact Eh. cbn [hhalt negb andb orb].
542
+ destruct (hleq A s); cbn [negb andb orb]; [rewrite orb_false_r; reflexivity|].
543
+ rewrite p3_halt by (unfold hp; assumption). reflexivity.
544
+ + (* the memory *)
545
+ remember (i - A - 1) as m eqn:Em. assert (Hm : m < SW A * A) by (unfold nH in Hi; lia).
546
+ pose proof (Nat.mod_upper_bound m A ltac:(lia)). pose proof (Nat.Div0.div_lt_upper_bound m A (SW A) ltac:(lia)).
547
+ replace i with (A + 1 + (m / A) * A + m mod A) by (pose proof (Nat.div_mod_eq m A); lia).
548
+ rewrite HF_NM by assumption. rewrite nth_encodeH_mem by assumption. unfold hh.
549
+ destruct (hhalt s) eqn:Eh.
550
+ * rewrite subleq_halted by exact Eh. cbn [negb andb orb]. rewrite andb_true_r, andb_false_r, orb_false_r.
551
+ reflexivity.
552
+ * rewrite memv_run by assumption. rewrite (Nat.eqb_sym (m / A) (hb A s)).
553
+ destruct (Nat.eqb (hb A s) (m / A)); cbn [negb andb orb];
554
+ rewrite ?andb_true_r, ?andb_false_r, ?orb_false_r, ?orb_false_l; reflexivity.
555
+ Qed.
rocq/HostWF.v ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (* The host netlist reads, at every unit, only state bits and earlier units, for every A >= 3. *)
2
+ From Stdlib Require Import List Bool Arith ZArith Lia.
3
+ Import ListNotations.
4
+ From TH Require Import TwoHead Net Gates Host.
5
+
6
+ Lemma SW_ge : forall A, 3 <= A -> 8 <= SW A.
7
+ Proof.
8
+ intros A H. unfold SW. replace A with (3 + (A - 3)) by lia. rewrite Nat.pow_add_r.
9
+ pose proof (Nat.pow_nonzero 2 (A - 3) ltac:(lia)). cbn [Nat.pow]. lia.
10
+ Qed.
11
+
12
+ Lemma length_hpre : forall A, length (hpre A) = 17.
13
+ Proof. reflexivity. Qed.
14
+
15
+ Lemma length_hpost : forall A, length (hpost A) = 15.
16
+ Proof. reflexivity. Qed.
17
+
18
+ Lemma length_hblocks : forall A, 1 <= A -> length (hblocks A) = tb A + 15.
19
+ Proof.
20
+ intros A H. unfold hblocks, tb. rewrite !length_app, length_map, length_seq, length_hpre, length_hpost. lia.
21
+ Qed.
22
+
23
+ Lemma nth_hb_pre : forall A b, b < 17 -> nth b (hblocks A) blk0 = nth b (hpre A) blk0.
24
+ Proof. intros A b H. unfold hblocks. rewrite app_nth1 by (rewrite length_hpre; exact H). reflexivity. Qed.
25
+
26
+ Lemma nth_hb_T : forall A k, 1 <= k -> k < A -> nth (16 + k) (hblocks A) blk0 = blk_T A k.
27
+ Proof.
28
+ intros A k H1 H2. unfold hblocks. rewrite app_nth2 by (rewrite length_hpre; lia). rewrite length_hpre.
29
+ rewrite app_nth1 by (rewrite length_map, length_seq; lia).
30
+ rewrite nth_map_d with (d' := 0) by (rewrite length_seq; lia). rewrite seq_nth by lia. f_equal. lia.
31
+ Qed.
32
+
33
+ Lemma nth_hb_post : forall A i, 1 <= A -> nth (tb A + i) (hblocks A) blk0 = nth i (hpost A) blk0.
34
+ Proof.
35
+ intros A i H. unfold hblocks, tb. rewrite app_nth2 by (rewrite length_hpre; lia). rewrite length_hpre.
36
+ rewrite app_nth2 by (rewrite length_map, length_seq; lia). rewrite length_map, length_seq. f_equal. lia.
37
+ Qed.
38
+
39
+ (* what a conjunction or a disjunction of literals reads *)
40
+ Lemma in_sin_lits : forall ls x w,
41
+ In (x, w) (sin (sAND ls)) \/ In (x, w) (sin (sOR ls)) -> In x (map fst ls).
42
+ Proof.
43
+ intros ls x w H. cbn [sin sAND sOR] in H.
44
+ assert (K : In (x, w) (map lw ls) -> In x (map fst ls)).
45
+ { intro H'. apply in_map_iff in H' as ([y p] & E & Hl). unfold lw in E. cbn [fst snd] in E.
46
+ injection E as Ey _. subst y. apply in_map_iff. exists (x, p). split; [reflexivity | exact Hl]. }
47
+ destruct H as [H|H]; apply K; exact H.
48
+ Qed.
49
+
50
+ Section Reads.
51
+ Variable A : nat.
52
+
53
+ Let rb := reads_back (hblocks A) (nH A).
54
+
55
+ Lemma rb_in : forall b j r i, i < nH A -> rb b j r (SIn i).
56
+ Proof. intros b j r i H. exact H. Qed.
57
+
58
+ Lemma rb_mu : forall b j r j' t, j' < SW A -> t < A -> rb b j r (mu A j' t).
59
+ Proof. intros b j r j' t H1 H2. unfold mu. apply rb_in. unfold nH. nia. Qed.
60
+
61
+ Lemma rb_pre : forall b j r b' j' r', b' < 17 -> b' < b ->
62
+ j' < bcount (nth b' (hpre A) blk0) -> r' < bsize (nth b' (hpre A) blk0) -> rb b j r (SRef b' j' r').
63
+ Proof. intros b j r b' j' r' H1 H2 H3 H4. left. rewrite nth_hb_pre by exact H1. auto. Qed.
64
+
65
+ Lemma rb_T : forall b j r k r', 1 <= k -> k < A -> 16 + k < b -> r' < S k -> rb b j r (SRef (16 + k) 0 r').
66
+ Proof. intros b j r k r' H1 H2 H3 H4. left. rewrite nth_hb_T by assumption. cbn [bcount bsize blk_T]. lia. Qed.
67
+
68
+ Lemma rb_post : forall b j r i j' r', 1 <= A -> tb A + i < b ->
69
+ j' < bcount (nth i (hpost A) blk0) -> r' < bsize (nth i (hpost A) blk0) -> rb b j r (SRef (tb A + i) j' r').
70
+ Proof. intros b j r i j' r' H0 H1 H2 H3. left. rewrite nth_hb_post by lia. auto. Qed.
71
+
72
+ Lemma rb_post0 : forall b j r j' r', 1 <= A -> tb A < b ->
73
+ j' < bcount (nth 0 (hpost A) blk0) -> r' < bsize (nth 0 (hpost A) blk0) -> rb b j r (SRef (tb A) j' r').
74
+ Proof.
75
+ intros b j r j' r' H0 H1 H2 H3. left. pose proof (nth_hb_post A 0 H0) as E. rewrite Nat.add_0_r in E.
76
+ rewrite E. auto.
77
+ Qed.
78
+
79
+ Lemma rb_self : forall b j r r', r' < r -> rb b j r (SRef b j r').
80
+ Proof. intros b j r r' H. right. auto. Qed.
81
+
82
+ Lemma rb_xv : forall b j r i, 1 <= A -> 15 < b -> rb b j r (xv A i).
83
+ Proof. intros b j r i H0 H. unfold xv. apply rb_pre; cbn [nth hpre bcount bsize blk_X]; lia. Qed.
84
+
85
+ Lemma rb_yv : forall b j r i, 1 <= A -> 15 < b -> rb b j r (yv A i).
86
+ Proof. intros b j r i H0 H. unfold yv. apply rb_pre; cbn [nth hpre bcount bsize blk_Y]; lia. Qed.
87
+
88
+ Lemma rb_opb : forall b j r o t, 6 < b -> o < 3 -> t < A -> rb b j r (opb A o t).
89
+ Proof. intros b j r o t H1 H2 H3. unfold opb. apply rb_pre; cbn [nth hpre bcount bsize blk_F]; nia. Qed.
90
+
91
+ Lemma rb_prr : forall b j r i, 16 < b -> i < A - 1 -> rb b j r (prr i).
92
+ Proof. intros b j r i H1 H2. unfold prr. apply rb_pre; cbn [nth hpre bcount bsize blk_PR]; lia. Qed.
93
+
94
+ Lemma rb_rbit : forall b j r k, tb A + 7 < b -> k < A -> rb b j r (rbit A k).
95
+ Proof.
96
+ intros b j r k H1 H2. unfold rbit. destruct (Nat.eqb_spec k 0).
97
+ - apply rb_post; cbn [nth hpost bcount bsize blk_R0]; lia.
98
+ - apply rb_post; cbn [nth hpost bcount bsize blk_R]; lia.
99
+ Qed.
100
+
101
+ End Reads.
102
+
103
+ Lemma mod_lt : forall a n, 0 < n -> a mod n < n.
104
+ Proof. intros a n H. apply Nat.mod_upper_bound. lia. Qed.
105
+
106
+ Lemma div_lt : forall a b n, a < b * n -> 0 < n -> a / n < b.
107
+ Proof. intros a b n H1 H2. apply Nat.Div0.div_lt_upper_bound. lia. Qed.
108
+
109
+ Ltac lits_in Hin :=
110
+ let H := fresh in
111
+ pose proof (in_sin_lits _ _ _ (or_introl Hin)) as H || pose proof (in_sin_lits _ _ _ (or_intror Hin)) as H;
112
+ clear Hin; unfold lits in H; rewrite ?map_map in H; cbn [map fst] in H.
113
+
114
+ Theorem host_wf : forall A, 3 <= A -> wf (hblocks A) (nH A).
115
+ Proof.
116
+ intros A HA. pose proof (SW_ge A HA) as HS.
117
+ split.
118
+ { unfold hblocks. apply Forall_app; split; [|apply Forall_app; split].
119
+ - unfold hpre. repeat apply Forall_cons; try apply Forall_nil; intros j Hj; reflexivity.
120
+ - apply Forall_forall. intros blk Hin. apply in_map_iff in Hin as (k & <- & _).
121
+ intros j Hj. cbn [bshape bsize blk_T length]. rewrite length_map, length_seq. reflexivity.
122
+ - unfold hpost. repeat apply Forall_cons; try apply Forall_nil; intros j Hj; reflexivity. }
123
+ intros b j r x w Hb Hj Hr Hin. rewrite length_hblocks in Hb by lia. unfold sunit in Hin.
124
+ destruct (Nat.lt_ge_cases b 17) as [Hp|Hp].
125
+ { rewrite nth_hb_pre in Hj, Hr, Hin by exact Hp.
126
+ assert (Hc : b = 0 \/ b = 1 \/ b = 2 \/ b = 3 \/ b = 4 \/ b = 5 \/ b = 6 \/ b = 7 \/ b = 8 \/ b = 9
127
+ \/ b = 10 \/ b = 11 \/ b = 12 \/ b = 13 \/ b = 14 \/ b = 15 \/ b = 16) by lia.
128
+ destruct Hc as [->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->| ->]]]]]]]]]]]]]]]];
129
+ cbn [nth hpre bcount bsize bshape blk_P blk_HP blk_FA blk_Q blk_F blk_PA blk_PB blk_AC blk_W
130
+ blk_RX blk_RY blk_KP blk_X blk_Y blk_PR] in Hj, Hr, Hin;
131
+ (destruct r as [|r]; [|lia]); cbn [nth] in Hin.
132
+ - (* P *) lits_in Hin. apply in_map_iff in H as (t & <- & Ht). apply in_seq in Ht. apply rb_in. unfold nH. nia.
133
+ - (* HP *) lits_in Hin. destruct H as [<-|[<-|[]]]; apply rb_in; unfold nH; nia.
134
+ - (* FA 0 *) lits_in Hin. pose proof (mod_lt j (SW A) ltac:(lia)). pose proof (div_lt j A (SW A) ltac:(lia) ltac:(lia)).
135
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; [apply mod_lt|]; lia|].
136
+ apply rb_pre; cbn [nth hpre bcount bsize blk_P]; lia.
137
+ - (* FA 1 *) lits_in Hin. pose proof (mod_lt j (SW A) ltac:(lia)). pose proof (div_lt j A (SW A) ltac:(lia) ltac:(lia)).
138
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; [apply mod_lt|]; lia|].
139
+ apply rb_pre; cbn [nth hpre bcount bsize blk_P]; lia.
140
+ - (* FA 2 *) lits_in Hin. pose proof (mod_lt j (SW A) ltac:(lia)). pose proof (div_lt j A (SW A) ltac:(lia) ltac:(lia)).
141
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; [apply mod_lt|]; lia|].
142
+ apply rb_pre; cbn [nth hpre bcount bsize blk_P]; lia.
143
+ - (* Q *) lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (j' & <- & Hj').
144
+ apply filter_In in Hj' as [Hj' _]. apply in_seq in Hj'.
145
+ apply rb_pre; cbn [nth hpre bcount bsize blk_P]; lia.
146
+ - (* F *) lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (j' & <- & Hj'). apply in_seq in Hj'.
147
+ cbn [fst]. pose proof (div_lt j 3 A ltac:(lia) ltac:(lia)). pose proof (mod_lt j A ltac:(lia)).
148
+ apply rb_pre; [lia | lia | |].
149
+ + assert (Ho : j / A = 0 \/ j / A = 1 \/ j / A = 2) by lia.
150
+ destruct Ho as [-> | [-> | ->]]; cbn [Nat.add nth hpre bcount blk_FA]; nia.
151
+ + assert (Ho : j / A = 0 \/ j / A = 1 \/ j / A = 2) by lia.
152
+ destruct Ho as [-> | [-> | ->]]; cbn [Nat.add nth hpre bsize blk_FA]; lia.
153
+ - (* PA *) lits_in Hin. apply in_map_iff in H as (t & <- & Ht). apply in_seq in Ht. apply rb_opb; lia.
154
+ - (* PB *) lits_in Hin. apply in_map_iff in H as (t & <- & Ht). apply in_seq in Ht. apply rb_opb; lia.
155
+ - (* AC *) lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (t & <- & Ht). apply in_seq in Ht.
156
+ apply rb_opb; lia.
157
+ - (* W *) lits_in Hin. destruct H as [<-|[<-|[]]]; [apply rb_in; unfold nH; nia|].
158
+ apply rb_pre; cbn [nth hpre bcount bsize blk_PB]; lia.
159
+ - (* RX *) lits_in Hin. pose proof (mod_lt j (SW A) ltac:(lia)). pose proof (div_lt j A (SW A) ltac:(lia) ltac:(lia)).
160
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; lia|]. apply rb_pre; cbn [nth hpre bcount bsize blk_PA]; lia.
161
+ - (* RY *) lits_in Hin. pose proof (mod_lt j (SW A) ltac:(lia)). pose proof (div_lt j A (SW A) ltac:(lia) ltac:(lia)).
162
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; lia|]. apply rb_pre; cbn [nth hpre bcount bsize blk_PB]; lia.
163
+ - (* KP *) lits_in Hin. pose proof (mod_lt j A ltac:(lia)). pose proof (div_lt j (SW A) A ltac:(lia) ltac:(lia)).
164
+ destruct H as [<-|[<-|[]]]; [apply rb_mu; lia|]. apply rb_pre; cbn [nth hpre bcount bsize blk_W]; lia.
165
+ - (* X *) lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (j' & <- & Hj'). apply in_seq in Hj'.
166
+ apply rb_pre; cbn [nth hpre bcount bsize blk_RX]; nia.
167
+ - (* Y *) lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (j' & <- & Hj'). apply in_seq in Hj'.
168
+ apply rb_pre; cbn [nth hpre bcount bsize blk_RY]; nia.
169
+ - (* PR *) lits_in Hin. destruct H as [<-|[<-|[]]]; [apply rb_xv | apply rb_yv]; lia. }
170
+ destruct (Nat.lt_ge_cases b (tb A)) as [HT|HT].
171
+ { (* the carry terms into bit k = b - 16 *)
172
+ unfold tb in HT. replace b with (16 + (b - 16)) in Hj, Hr, Hin |- * by lia.
173
+ rewrite nth_hb_T in Hj, Hr, Hin by lia. cbn [bcount bsize bshape blk_T] in Hj, Hr, Hin.
174
+ destruct r as [|r].
175
+ - cbn [nth] in Hin. lits_in Hin. rewrite ?map_map in H. apply in_map_iff in H as (i & <- & Hi). apply in_seq in Hi.
176
+ apply rb_prr; lia.
177
+ - cbn [nth] in Hin. rewrite nth_map_d with (d' := 0) in Hin by (rewrite length_seq; lia).
178
+ rewrite seq_nth in Hin by lia. lits_in Hin. rewrite ?map_app, ?map_map in H. cbn [map fst] in H.
179
+ destruct H as [<-|[<-|H]]; [apply rb_yv; lia | apply rb_xv; lia|].
180
+ apply in_map_iff in H as (i & <- & Hi). apply in_seq in Hi. apply rb_prr; lia. }
181
+ replace b with (tb A + (b - tb A)) in Hj, Hr, Hin |- * by lia.
182
+ rewrite nth_hb_post in Hj, Hr, Hin by lia.
183
+ assert (Hi : b - tb A < 15) by (unfold tb in *; lia).
184
+ remember (b - tb A) as i eqn:Ei. clear Ei Hb Hp HT.
185
+ assert (Hc : i = 0 \/ i = 1 \/ i = 2 \/ i = 3 \/ i = 4 \/ i = 5 \/ i = 6 \/ i = 7 \/ i = 8 \/ i = 9
186
+ \/ i = 10 \/ i = 11 \/ i = 12 \/ i = 13 \/ i = 14) by lia.
187
+ destruct Hc as [->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->|[->| ->]]]]]]]]]]]]]];
188
+ cbn [nth hpost bcount bsize bshape blk_C blk_AX blk_NX blk_XN blk_EQ blk_R0 blk_H blk_R blk_LEQ
189
+ blk_TA blk_TB blk_NP blk_HAB blk_WR blk_NM] in Hj, Hr, Hin.
190
+ - (* C *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin. destruct H as [<-|H].
191
+ + apply rb_T; unfold tb; lia.
192
+ + rewrite ?map_map in H. apply in_map_iff in H as (j' & <- & Hj'). apply in_seq in Hj'. apply rb_T; unfold tb; lia.
193
+ - (* AX *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
194
+ destruct H as [<-|[<-|[]]]; [apply rb_xv | apply rb_yv]; unfold tb; lia.
195
+ - (* NX *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
196
+ destruct H as [<-|[<-|[]]]; [apply rb_xv | apply rb_yv]; unfold tb; lia.
197
+ - (* XN *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
198
+ destruct H as [<-|[<-|[]]]; apply rb_post; cbn [nth hpost bcount bsize blk_AX blk_NX]; lia.
199
+ - (* EQ *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin. rewrite ?map_map in H.
200
+ apply in_map_iff in H as (i' & <- & Hi'). apply in_seq in Hi'.
201
+ apply rb_post; cbn [nth hpost bcount bsize blk_XN]; lia.
202
+ - (* R0 *) assert (Hj0 : j = 0) by lia. subst j. assert (Hr3 : r = 0 \/ r = 1 \/ r = 2) by lia.
203
+ destruct Hr3 as [->|[->| ->]]; cbn [nth] in Hin; lits_in Hin.
204
+ + destruct H as [<-|[<-|[]]]; [apply rb_yv | apply rb_xv]; unfold tb; lia.
205
+ + destruct H as [<-|[<-|[]]]; [apply rb_yv | apply rb_xv]; unfold tb; lia.
206
+ + destruct H as [<-|[<-|[]]]; apply rb_self; lia.
207
+ - (* H *) assert (Hr3 : r = 0 \/ r = 1 \/ r = 2) by lia.
208
+ destruct Hr3 as [->|[->| ->]];
209
+ cbn [nth map sin] in Hin; repeat (destruct Hin as [Hin|Hin]; [injection Hin as <- <-|]); try destruct Hin;
210
+ first [apply rb_yv; unfold tb; lia | apply rb_xv; unfold tb; lia
211
+ | apply rb_post0; cbn [nth hpost bcount bsize blk_C]; lia].
212
+ - (* R *) destruct r as [|r]; [|lia]. cbn [nth sin] in Hin.
213
+ repeat (destruct Hin as [Hin|Hin]; [injection Hin as <- <-|]); try destruct Hin;
214
+ apply rb_post; cbn [nth hpost bcount bsize blk_H]; lia.
215
+ - (* LEQ *) destruct r as [|r]; [|lia]. cbn [nth sin] in Hin.
216
+ repeat (destruct Hin as [Hin|Hin]; [injection Hin as <- <-|]); try destruct Hin;
217
+ apply rb_post; cbn [nth hpost bcount bsize blk_H blk_EQ]; lia.
218
+ - (* TA *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
219
+ destruct H as [<-|[<-|[<-|[]]]]; [apply rb_in; unfold nH; lia
220
+ | apply rb_post; cbn [nth hpost bcount bsize blk_LEQ]; lia
221
+ | apply rb_opb; unfold tb; lia].
222
+ - (* TB *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
223
+ destruct H as [<-|[<-|[<-|[]]]]; [apply rb_in; unfold nH; lia
224
+ | apply rb_post; cbn [nth hpost bcount bsize blk_LEQ]; lia
225
+ | apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_Q]; lia
226
+ | cbn [nth hpre bsize blk_Q]; lia]].
227
+ - (* NP *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
228
+ destruct H as [<-|[<-|[<-|[]]]];
229
+ [ apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_HP]; lia | cbn [nth hpre bsize blk_HP]; lia]
230
+ | apply rb_post; cbn [nth hpost bcount bsize blk_TA]; lia
231
+ | apply rb_post; cbn [nth hpost bcount bsize blk_TB]; lia ].
232
+ - (* HA, HB, NH *) assert (Hj0 : j = 0) by lia. subst j. assert (Hr3 : r = 0 \/ r = 1 \/ r = 2) by lia.
233
+ destruct Hr3 as [->|[->| ->]]; cbn [nth] in Hin; lits_in Hin.
234
+ + destruct H as [<-|[<-|[<-|[]]]];
235
+ [ apply rb_in; unfold nH; lia
236
+ | apply rb_post; cbn [nth hpost bcount bsize blk_LEQ]; lia
237
+ | apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_AC]; lia | cbn [nth hpre bsize blk_AC]; lia] ].
238
+ + destruct H as [<-|[<-|[<-|[]]]];
239
+ [ apply rb_in; unfold nH; lia
240
+ | apply rb_post; cbn [nth hpost bcount bsize blk_LEQ]; lia
241
+ | apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_P]; lia | cbn [nth hpre bsize blk_P]; lia] ].
242
+ + destruct H as [<-|[<-|[<-|[]]]]; [apply rb_in; unfold nH; lia | apply rb_self; lia | apply rb_self; lia].
243
+ - (* WR *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
244
+ pose proof (div_lt j (SW A) A ltac:(lia) ltac:(lia)).
245
+ destruct H as [<-|[<-|[]]]; [apply rb_rbit; lia|].
246
+ apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_W]; lia | cbn [nth hpre bsize blk_W]; lia].
247
+ - (* NM *) destruct r as [|r]; [|lia]. cbn [nth] in Hin. lits_in Hin.
248
+ destruct H as [<-|[<-|[]]];
249
+ [ apply rb_pre; [lia | unfold tb; lia | cbn [nth hpre bcount blk_KP]; lia | cbn [nth hpre bsize blk_KP]; lia]
250
+ | apply rb_post; cbn [nth hpost bcount bsize blk_WR]; lia ].
251
+ Qed.
rocq/PhysSem.v CHANGED
@@ -98,6 +98,21 @@ Proof.
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)
@@ -258,21 +273,6 @@ Proof.
258
  destruct (Nat.eqb_spec (a - 3) 0); [lia|]. f_equal. lia.
259
  Qed.
260
 
261
- Lemma existsb_pick : forall (g : nat -> bool) c n m,
262
- existsb (fun a => Nat.eqb c a && g a) (seq m n) = if (m <=? c) && (c <? m + n) then g c else false.
263
- Proof.
264
- intros g c n. induction n as [|n IH]; intro m; cbn [seq existsb].
265
- - destruct (Nat.leb_spec m c), (Nat.ltb_spec c (m + 0)); cbn [andb]; try reflexivity; lia.
266
- - rewrite IH. destruct (Nat.eqb_spec c m) as [E|E].
267
- + subst c. rewrite Nat.leb_refl.
268
- replace (m <? m + S n) with true by (symmetry; apply Nat.ltb_lt; lia).
269
- replace (S m <=? m) with false by (symmetry; apply Nat.leb_gt; lia).
270
- cbn [andb orb]. destruct (g m); reflexivity.
271
- + cbn [andb orb].
272
- destruct (Nat.leb_spec m c), (Nat.leb_spec (S m) c), (Nat.ltb_spec c (S m + n)), (Nat.ltb_spec c (m + S n));
273
- cbn [andb]; try reflexivity; lia.
274
- Qed.
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.
 
98
  unfold stepA, stepres, cellof, wnext, clearq. cbv zeta. rewrite Hk, Hp, Hd. subst v. reflexivity.
99
  Qed.
100
 
101
+ Lemma existsb_pick : forall (g : nat -> bool) c n m,
102
+ existsb (fun a => Nat.eqb c a && g a) (seq m n) = if (m <=? c) && (c <? m + n) then g c else false.
103
+ Proof.
104
+ intros g c n. induction n as [|n IH]; intro m; cbn [seq existsb].
105
+ - destruct (Nat.leb_spec m c), (Nat.ltb_spec c (m + 0)); cbn [andb]; try reflexivity; lia.
106
+ - rewrite IH. destruct (Nat.eqb_spec c m) as [E|E].
107
+ + subst c. rewrite Nat.leb_refl.
108
+ replace (m <? m + S n) with true by (symmetry; apply Nat.ltb_lt; lia).
109
+ replace (S m <=? m) with false by (symmetry; apply Nat.leb_gt; lia).
110
+ cbn [andb orb]. destruct (g m); reflexivity.
111
+ + cbn [andb orb].
112
+ destruct (Nat.leb_spec m c), (Nat.leb_spec (S m) c), (Nat.ltb_spec c (S m + n)), (Nat.ltb_spec c (m + S n));
113
+ cbn [andb]; try reflexivity; lia.
114
+ Qed.
115
+
116
  Section Sem.
117
  Variables (al N L : nat) (s : st).
118
  Hypotheses (Hal : 3 <= al) (HN : recw al <= N) (HL : 1 <= L)
 
273
  destruct (Nat.eqb_spec (a - 3) 0); [lia|]. f_equal. lia.
274
  Qed.
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.
rocq/_CoqProject CHANGED
@@ -24,3 +24,8 @@ PhysMain.v
24
  PhysFacts.v
25
  NetMain.v
26
  Extract.v
 
 
 
 
 
 
24
  PhysFacts.v
25
  NetMain.v
26
  Extract.v
27
+ Host.v
28
+ HostWF.v
29
+ Adder.v
30
+ HostSem.v
31
+ ExtractHost.v
rocq/extract/dumphost.ml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (* writes the host netlist defined in Host.v, extracted by ExtractHost.v: dumphost A PATH *)
2
+ let () =
3
+ let a = int_of_string Sys.argv.(1) in
4
+ let us = Hostnet.host_units a and nx = Hostnet.host_next a in
5
+ let oc = open_out_bin Sys.argv.(2) in
6
+ let put x = let b = Bytes.create 4 in Bytes.set_int32_le b 0 (Int32.of_int x); output_bytes oc b in
7
+ let edges = List.fold_left (fun acc (u : Hostnet.tu) -> acc + List.length u.tin) 0 us in
8
+ put (Hostnet.nH a); put (List.length us); put edges;
9
+ List.iter (fun (u : Hostnet.tu) -> put u.tb) us;
10
+ List.iter (fun (u : Hostnet.tu) -> put (List.length u.tin)) us;
11
+ List.iter (fun (u : Hostnet.tu) -> List.iter (fun (s, wt) -> put (wt * (s + 1))) u.tin) us;
12
+ List.iter put nx;
13
+ close_out oc
src/independent.py CHANGED
@@ -1,4 +1,4 @@
1
- """Code written from the paper's text alone: H_A, the levelization, noise, weight error, the datapath."""
2
  import hashlib
3
  import json
4
  import math
@@ -393,177 +393,6 @@ def main_levelize():
393
  w(len(blob))
394
  f.write(blob)
395
 
396
- NPZ = os.path.join(WORK, 'datapath.npz')
397
-
398
- RECORD = os.path.join(REPO, 'paper', 'runs', 'independent_neuromorphic.json')
399
-
400
- K = 9
401
-
402
-
403
- def record(key, value):
404
- rec = json.load(open(RECORD)) if os.path.exists(RECORD) else {}
405
- rec[key] = value
406
- json.dump(rec, open(RECORD, 'w'), indent=1)
407
-
408
-
409
- def export():
410
- N, nxt = build(8)
411
- blocks = N.block
412
- nst = N.n
413
- keep = [k for k, b in enumerate(blocks) if b in ('sub', 'eq', 'LEQ')]
414
- keepset = set(N.n + k for k in keep)
415
- # inputs: the units X_t, Y_t of block XY; outputs: r_0..r_7 and LEQ
416
- xy = [N.n + k for k, b in enumerate(blocks) if b == 'XY']
417
- X, Y = xy[:8], xy[8:]
418
- units = {N.n + k: (N.bias[k], N.ins[k]) for k in keep}
419
- # the outputs: the sum bits are the last 8 units feeding WR, recovered as the inputs of NM's AND units
420
- sub = [N.n + k for k, b in enumerate(blocks) if b == 'sub']
421
- r = [sub[-8]] + sub[-7:] # r_0 is the AND of the XOR cell, then r_1..r_7
422
- leq = [N.n + k for k, b in enumerate(blocks) if b == 'LEQ'][0]
423
- inputs = X + Y
424
- outputs = r + [leq]
425
- # check the choice of outputs by evaluating the cut-out circuit on all pairs
426
- def ev(xa, xb):
427
- v = {}
428
- for t in range(8):
429
- v[X[t]] = (xa >> t) & 1
430
- v[Y[t]] = (xb >> t) & 1
431
- for u in sorted(units):
432
- b, ins = units[u]
433
- v[u] = 1 if b + sum(w * v[s] for s, w in ins) >= 0 else 0
434
- return sum(v[r[k]] << k for k in range(8)), v[leq]
435
- for xa in range(256):
436
- for xb in (0, 1, 127, 128, 255, xa, (xa + 1) % 256):
437
- res = (xb - xa) % 256
438
- assert ev(xa, xb) == (res, int(res == 0 or res >= 128)), (xa, xb)
439
- # levelize (Lemma 2.6) with the inputs at layer 0
440
- depth = {s: 0 for s in inputs}
441
- for u in sorted(units):
442
- depth[u] = 1 + max(depth[s] for s, _ in units[u][1])
443
- d = max(depth[o] for o in outputs)
444
- lam = {}
445
- for u in units:
446
- for s, _ in units[u][1]:
447
- lam[s] = max(lam.get(s, 0), depth[u])
448
- for o in outputs:
449
- lam[o] = d + 1
450
- layers, prev = [], {s: i for i, s in enumerate(inputs)}
451
- for l in range(1, d + 1):
452
- rows = []
453
- if l < d:
454
- for s in list(inputs) + sorted(units):
455
- if s in units and depth[s] == l:
456
- rows.append((s, units[s][0], units[s][1]))
457
- elif depth[s] < l < lam.get(s, -1):
458
- rows.append((s, -1, [(s, 1)]))
459
- else:
460
- for o in outputs:
461
- rows.append((o, units[o][0], units[o][1]) if depth[o] == d else (o, -1, [(o, 1)]))
462
- W = np.zeros((len(rows), len(prev)), dtype=np.int32)
463
- b = np.zeros(len(rows), dtype=np.int32)
464
- for i, (_, bb, ins) in enumerate(rows):
465
- b[i] = bb
466
- for s, w in ins:
467
- W[i, prev[s]] = w
468
- layers.append((W, b))
469
- prev = {s: i for i, (s, _, _) in enumerate(rows)}
470
- out = dict(n_layers=np.array([d]), n_units=np.array([len(units)]))
471
- for i, (W, b) in enumerate(layers):
472
- out[f'W{i}'], out[f'b{i}'] = W, b
473
- os.makedirs(WORK, exist_ok=True)
474
- np.savez(NPZ, **out)
475
- res = dict(units=len(units), depth=d, widths=[int(W.shape[0]) for W, _ in layers])
476
- record('datapath', res)
477
- print(json.dumps(res))
478
-
479
-
480
- def reference(xa, xb):
481
- res = (xb - xa) % 256
482
- return res, int(res == 0 or res >= 128)
483
-
484
-
485
- def operands(n, seed):
486
- rng = np.random.default_rng(seed)
487
- xa = rng.integers(0, 256, n)
488
- xb = rng.integers(0, 256, n)
489
- xa[:256], xb[:256] = np.arange(256), 0
490
- xa[256:512], xb[256:512] = 0, np.arange(256)
491
- xa[512:768], xb[512:768] = np.arange(256), np.arange(256)
492
- return xa, xb
493
-
494
-
495
- def lava(off):
496
- from lava.magma.core.run_conditions import RunSteps
497
- from lava.magma.core.run_configs import Loihi2SimCfg
498
- from lava.proc.dense.process import Dense
499
- from lava.proc.io.sink import RingBuffer as Sink
500
- from lava.proc.io.source import RingBuffer as Source
501
- from lava.proc.lif.process import LIF
502
- z = np.load(NPZ)
503
- L = int(z['n_layers'][0])
504
- layers = [(z[f'W{i}'], z[f'b{i}']) for i in range(L)]
505
- N = 4096
506
- xa, xb = operands(N, 77)
507
- spikes = np.zeros((16, N))
508
- for k in range(8):
509
- spikes[k] = (xa >> k) & 1
510
- spikes[8 + k] = (xb >> k) & 1
511
- T = N + L + 2
512
- src = Source(data=np.pad(spikes, ((0, 0), (0, T - N))))
513
- prev, first = src.s_out, None
514
- vth = 2 * K - 2 + off
515
- for W, b in layers:
516
- dn = Dense(weights=(2 * W).astype(np.int32))
517
- lif = LIF(shape=(W.shape[0],), du=4095, dv=4095, bias_mant=(b + K).astype(np.int32), bias_exp=7, vth=vth)
518
- prev.connect(dn.s_in)
519
- dn.a_out.connect(lif.a_in)
520
- prev, first = lif.s_out, first or lif
521
- snk = Sink(shape=(9,), buffer=T)
522
- prev.connect(snk.a_in)
523
- first.run(condition=RunSteps(num_steps=T), run_cfg=Loihi2SimCfg(select_tag='fixed_pt'))
524
- out = snk.data.get()
525
- first.stop()
526
- bad = 0
527
- for t in range(N):
528
- col = out[:, t + L]
529
- bad += (sum(int(col[k]) << k for k in range(8)), int(col[8])) != reference(int(xa[t]), int(xb[t]))
530
- # the membrane potential of a unit at pre-activation z is 128 (z + K); the threshold is 64 vth
531
- margin_fire = 128 * K - 64 * vth
532
- margin_quiet = 64 * vth - 128 * (K - 1)
533
- res = dict(backend='lava fixed_pt', vth=vth, patterns=N, failures=bad,
534
- margin_firing_side=margin_fire, margin_quiet_side=margin_quiet)
535
- record(f'lava_vth_{vth}', res)
536
- print(json.dumps(res))
537
-
538
-
539
- def akida():
540
- import akida as ak
541
- from akida import FullyConnected, InputData, Model
542
- z = np.load(NPZ)
543
- L = int(z['n_layers'][0])
544
- layers = [(z[f'W{i}'], z[f'b{i}']) for i in range(L)]
545
- m = Model()
546
- m.add(InputData(input_shape=(1, 1, 16), input_bits=1))
547
- for i, (W, b) in enumerate(layers):
548
- m.add(FullyConnected(units=int(W.shape[0]), weights_bits=2, activation=True, act_bits=1, name=f'l{i}'))
549
- lay = m.get_layer(i + 1)
550
- wv = np.zeros(lay.variables['weights'].shape, dtype=np.int8)
551
- wv[0, 0, :, :] = W.T.astype(np.int8)
552
- lay.variables['weights'] = wv
553
- lay.variables['threshold'] = (-b - 1).astype(np.int32)
554
- N = 65536
555
- xa, xb = np.arange(N) % 256, np.arange(N) // 256
556
- Xin = np.zeros((N, 1, 1, 16), dtype=np.uint8)
557
- for k in range(8):
558
- Xin[:, 0, 0, k] = (xa >> k) & 1
559
- Xin[:, 0, 0, 8 + k] = (xb >> k) & 1
560
- out = np.concatenate([m.forward(Xin[i:i + 8192]).reshape(-1, 9) for i in range(0, N, 8192)])
561
- bad = sum((sum(int(out[t, k]) << k for k in range(8)), int(out[t, 8])) != reference(int(xa[t]), int(xb[t]))
562
- for t in range(N))
563
- res = dict(backend=f'akida {ak.__version__}', patterns=N, failures=int(bad))
564
- record('akida', res)
565
- print(json.dumps(res))
566
-
567
  NSIM, BIN, HIST = os.path.join(WORK, 'nsim'), os.path.join(WORK, 'host_lev.bin'), os.path.join(WORK, 'hist_sd.bin')
568
 
569
  M = 41967
@@ -624,7 +453,6 @@ def main_noise():
624
  print(json.dumps({k: v for k, v in out.items() if k in ('exact_self_reproducing', 'profile', 'seconds')}))
625
 
626
 
627
-
628
  def load():
629
  b = open(BIN, 'rb').read()
630
  pos = 0
@@ -748,17 +576,7 @@ def cmd_host_family():
748
  json.dump(out, open(os.path.join(RUNS, 'independent_host_family.json'), 'w'), indent=1)
749
 
750
 
751
- def cmd_neuromorphic():
752
- cmd = sys.argv[1]
753
- if cmd == 'export':
754
- export()
755
- elif cmd == 'lava':
756
- lava(int(sys.argv[2]))
757
- else:
758
- akida()
759
-
760
-
761
- COMMANDS = {'host-family': cmd_host_family, 'levelize': main_levelize, 'neuromorphic': cmd_neuromorphic, 'noise': main_noise, 'weight-error': main_weight_error}
762
 
763
 
764
  if __name__ == "__main__":
 
1
+ """Code written from the paper's text alone: H_A, the levelization, noise and weight error."""
2
  import hashlib
3
  import json
4
  import math
 
393
  w(len(blob))
394
  f.write(blob)
395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  NSIM, BIN, HIST = os.path.join(WORK, 'nsim'), os.path.join(WORK, 'host_lev.bin'), os.path.join(WORK, 'hist_sd.bin')
397
 
398
  M = 41967
 
453
  print(json.dumps({k: v for k, v in out.items() if k in ('exact_self_reproducing', 'profile', 'seconds')}))
454
 
455
 
 
456
  def load():
457
  b = open(BIN, 'rb').read()
458
  pos = 0
 
576
  json.dump(out, open(os.path.join(RUNS, 'independent_host_family.json'), 'w'), indent=1)
577
 
578
 
579
+ COMMANDS = {'host-family': cmd_host_family, 'levelize': main_levelize, 'noise': main_noise, 'weight-error': main_weight_error}
 
 
 
 
 
 
 
 
 
 
580
 
581
 
582
  if __name__ == "__main__":
src/noise.py CHANGED
@@ -1,4 +1,4 @@
1
- """Perturbation experiments on the levelized host, the amplified host, and the neuromorphic datapath."""
2
  from __future__ import annotations
3
 
4
  import argparse
@@ -12,8 +12,6 @@ import tempfile
12
  import time
13
  from typing import Dict, List, Tuple
14
 
15
- import numpy as np
16
-
17
  from host import (
18
  encode,
19
  M_P,
@@ -21,17 +19,14 @@ from host import (
21
  HALT_PC,
22
  Tape,
23
  describe,
24
- field,
25
  inst,
26
  read_host,
27
  ser,
28
  tau_star,
29
- run_reference,
30
  STATE_LAYOUT,
31
  IO_CELLS,
32
- STATE_BITS,
33
  )
34
- from paper import levelize, parse_sigma, write_flat, framed_parts
35
 
36
 
37
  REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -1301,227 +1296,7 @@ def main_amplified() -> int:
1301
  "curve": cmd_curve, "restore": cmd_restore, "layers": cmd_layers,
1302
  "bound": cmd_bound}[args.mode](args)
1303
 
1304
- K = 9 # bias offset making the threshold >= 0
1305
-
1306
- NPZ = os.path.join(REPO, "paper", "runs", "datapath_layers.npz")
1307
-
1308
-
1309
- def datapath_net():
1310
- """The subtractor, equality test and branch of H_8, cut out of the host netlist."""
1311
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
1312
- from host import build
1313
- from machines import Net
1314
- full, _, _ = build(8)
1315
- A = 8
1316
- xv = [f"X{A - 1 - i}" for i in range(A)]
1317
- yv = [f"Y{A - 1 - i}" for i in range(A)]
1318
- keep = set()
1319
- stack = [f"R{k}" for k in range(A)] + ["LEQ"]
1320
- while stack:
1321
- g = stack.pop()
1322
- if g in keep or g in xv or g in yv:
1323
- continue
1324
- keep.add(g)
1325
- stack.extend(s for s, _ in full.gates[g][0])
1326
- net = Net()
1327
- for gname, (ins, bias) in full.gates.items():
1328
- if gname in keep:
1329
- net.g(gname, list(ins), bias)
1330
- return net, xv, yv, [f"R{k}" for k in range(A)], "LEQ"
1331
-
1332
-
1333
- def export() -> int:
1334
- """Levelize the datapath and write its integer weights and biases."""
1335
- sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
1336
- from machines import compile_net
1337
- net, xv, yv, r, leq = datapath_net()
1338
- inputs = xv + yv
1339
- outputs = r + [leq]
1340
- layers, info = compile_net(net, inputs, outputs, final_ordered=True)
1341
- d = {"n_layers": np.array([len(layers)]),
1342
- "n_units": np.array([len(net.gates)]),
1343
- "n_inputs": np.array([len(inputs)]),
1344
- "n_outputs": np.array([len(outputs)])}
1345
- for i, (W, bb) in enumerate(layers):
1346
- d[f"W{i}"] = W.numpy().astype(np.int32)
1347
- d[f"b{i}"] = bb.numpy().astype(np.int32)
1348
- os.makedirs(os.path.dirname(NPZ), exist_ok=True)
1349
- np.savez(NPZ, **d)
1350
- print(f" datapath: {len(net.gates)} units on {len(inputs)} inputs, "
1351
- f"{len(layers)} layers of widths "
1352
- f"{[int(W.shape[0]) for W, _ in layers]}")
1353
- print(f" wrote {NPZ}")
1354
- return 0
1355
-
1356
-
1357
- def reference(xa, xb):
1358
- """The subtraction and the branch predicate of Definition 3.1, as integers."""
1359
- res = (xb - xa) & 0xFF
1360
- leq = 1 if (res == 0 or res >= 128) else 0
1361
- return res, leq
1362
-
1363
-
1364
- def run() -> int:
1365
- from lava.magma.core.run_conditions import RunSteps
1366
- from lava.magma.core.run_configs import Loihi2SimCfg
1367
- from lava.proc.dense.process import Dense
1368
- from lava.proc.io.sink import RingBuffer as Sink
1369
- from lava.proc.io.source import RingBuffer as Source
1370
- from lava.proc.lif.process import LIF
1371
-
1372
- z = np.load(NPZ)
1373
- L = int(z["n_layers"][0])
1374
- n_in = int(z["n_inputs"][0])
1375
- n_out = int(z["n_outputs"][0])
1376
- layers = [(z[f"W{i}"], z[f"b{i}"]) for i in range(L)]
1377
- print(f" datapath: {int(z['n_units'][0])} units on {n_in} inputs, "
1378
- f"{L} layers of widths {[int(W.shape[0]) for W, _ in layers]}",
1379
- flush=True)
1380
-
1381
- worst = 0
1382
- for W, b in layers:
1383
- hi = np.maximum(W, 0).sum(axis=1) + b + K
1384
- lo = np.minimum(W, 0).sum(axis=1) + b + K
1385
- worst = max(worst, int(np.abs(np.concatenate([hi, lo])).max()))
1386
- print(f" worst |<w,x> + b + K| over all units and all inputs: {worst}, "
1387
- f"so the membrane potential stays below {128 * worst} < 4096: "
1388
- f"{'yes' if 128 * worst < 4096 else 'NO'}", flush=True)
1389
- assert 128 * worst < 4096
1390
-
1391
- rng = np.random.default_rng(20260910)
1392
- N = 4096
1393
- xa = rng.integers(0, 256, N)
1394
- xb = rng.integers(0, 256, N)
1395
- xa[:256] = np.arange(256); xb[:256] = 0 # every difference through zero
1396
- xa[256:512] = 0; xb[256:512] = np.arange(256)
1397
- xa[512:768] = np.arange(256); xb[512:768] = np.arange(256) # x = y
1398
-
1399
- spikes = np.zeros((n_in, N))
1400
- for t in range(N):
1401
- for k in range(8):
1402
- spikes[k, t] = (xa[t] >> k) & 1 # x, value bits
1403
- spikes[8 + k, t] = (xb[t] >> k) & 1 # y
1404
-
1405
- T = N + L + 2
1406
- src = Source(data=np.pad(spikes, ((0, 0), (0, T - N))))
1407
- prev = src.s_out
1408
- first_lif = None
1409
- for W, b in layers:
1410
- dn = Dense(weights=(2 * W).astype(np.int32))
1411
- lif = LIF(shape=(W.shape[0],), du=4095, dv=4095,
1412
- bias_mant=(b + K).astype(np.int32), bias_exp=7, vth=2 * K - 1)
1413
- prev.connect(dn.s_in)
1414
- dn.a_out.connect(lif.a_in)
1415
- prev = lif.s_out
1416
- first_lif = first_lif or lif
1417
- snk = Sink(shape=(n_out,), buffer=T)
1418
- prev.connect(snk.a_in)
1419
-
1420
- print(f" running {T} time steps of the {L}-layer chain on the "
1421
- f"bit-accurate fixed-point model", flush=True)
1422
- first_lif.run(condition=RunSteps(num_steps=T),
1423
- run_cfg=Loihi2SimCfg(select_tag="fixed_pt"))
1424
- out = snk.data.get()
1425
- first_lif.stop()
1426
-
1427
- bad = []
1428
- for t in range(N):
1429
- col = out[:, t + L]
1430
- res = sum(int(col[k]) << k for k in range(8))
1431
- leq = int(col[8])
1432
- want = reference(int(xa[t]), int(xb[t]))
1433
- if (res, leq) != want:
1434
- bad.append((t, (res, leq), want))
1435
- print(f" {N} operand pairs, pipelined one per time step: "
1436
- f"{'all exact' if not bad else f'{len(bad)} FAILED {bad[:3]}'}",
1437
- flush=True)
1438
-
1439
- print(f" one unit weight moves the membrane potential by 128 units and "
1440
- f"the comparator sits midway between the firing and non-firing "
1441
- f"values, so the margin of Theorem 6.2 is 64 units of membrane "
1442
- f"potential on this model")
1443
-
1444
- ok = not bad
1445
- json.dump({"backend": "Lava 0.10.0, fixed_pt tag (Loihi neuron model)",
1446
- "units": int(z["n_units"][0]), "layers": L,
1447
- "widths": [int(W.shape[0]) for W, _ in layers],
1448
- "worst_accumulation": worst, "patterns": N,
1449
- "failures": len(bad), "margin_membrane_units": 64,
1450
- "weight_scale": 2, "synapse_granularity": 2,
1451
- "bias_offset": K, "ok": ok},
1452
- open(runs_path("paper_neuromorphic.json"), "w"), indent=1)
1453
- print("NEUROMORPHIC:", "PASS" if ok else "FAIL")
1454
- return 0 if ok else 1
1455
-
1456
-
1457
- def akida() -> int:
1458
- """The same datapath on the Akida layer model."""
1459
- import numpy as np
1460
- import akida as ak
1461
- from akida import FullyConnected, InputData, Model
1462
-
1463
- z = np.load(NPZ)
1464
- L = int(z["n_layers"][0])
1465
- n_in = int(z["n_inputs"][0])
1466
- layers = [(z[f"W{i}"], z[f"b{i}"]) for i in range(L)]
1467
- print(f" Akida {ak.__version__}; devices attached: {len(ak.devices())}; "
1468
- f"{L} layers of widths {[int(W.shape[0]) for W, _ in layers]}",
1469
- flush=True)
1470
-
1471
- m = Model()
1472
- m.add(InputData(input_shape=(1, 1, n_in), input_bits=1))
1473
- for i, (W, b) in enumerate(layers):
1474
- m.add(FullyConnected(units=int(W.shape[0]), weights_bits=2,
1475
- activation=True, act_bits=1, name=f"layer{i}"))
1476
- lay = m.get_layer(i + 1)
1477
- wv = np.zeros(lay.variables["weights"].shape, dtype=np.int8)
1478
- wv[0, 0, :, :] = W.T.astype(np.int8)
1479
- lay.variables["weights"] = wv
1480
- lay.variables["threshold"] = (-b - 1).astype(np.int32)
1481
-
1482
- N = 65536 # every operand pair
1483
- xa = np.arange(N) % 256
1484
- xb = np.arange(N) // 256
1485
- X = np.zeros((N, 1, 1, n_in), dtype=np.uint8)
1486
- for k in range(8):
1487
- X[:, 0, 0, k] = (xa >> k) & 1
1488
- X[:, 0, 0, 8 + k] = (xb >> k) & 1
1489
- out = np.concatenate([m.forward(X[i:i + 8192]).reshape(-1, out_w)
1490
- for i in range(0, N, 8192)
1491
- for out_w in [int(layers[-1][0].shape[0])]])
1492
-
1493
- bad = []
1494
- for t in range(N):
1495
- res = sum(int(out[t, k]) << k for k in range(8))
1496
- leq = int(out[t, 8])
1497
- want = reference(int(xa[t]), int(xb[t]))
1498
- if (res, leq) != want:
1499
- bad.append((t, (res, leq), want))
1500
- print(f" all {N} operand pairs forwarded through the layer stack: "
1501
- f"{'all exact' if not bad else f'{len(bad)} FAILED {bad[:3]}'}",
1502
- flush=True)
1503
- print(f" weights are stored at two bits and thresholds as integers, so "
1504
- f"the circuit is represented without rounding")
1505
-
1506
- ok = not bad
1507
- old = {}
1508
- p = runs_path("paper_neuromorphic.json")
1509
- if os.path.exists(p):
1510
- old = json.load(open(p))
1511
- old["akida"] = {"backend": f"akida {ak.__version__}, software backend",
1512
- "layers": L, "patterns": N, "failures": len(bad),
1513
- "weights_bits": 2, "act_bits": 1, "ok": ok}
1514
- json.dump(old, open(p, "w"), indent=1)
1515
- print("AKIDA:", "PASS" if ok else "FAIL")
1516
- return 0 if ok else 1
1517
-
1518
-
1519
- def cmd_neuromorphic():
1520
- mode = sys.argv[1] if len(sys.argv) > 1 else "run"
1521
- sys.exit({"export": export, "run": run, "akida": akida}[mode]())
1522
-
1523
-
1524
- COMMANDS = {'host': main_host, 'amplified': main_amplified, 'neuromorphic': cmd_neuromorphic}
1525
 
1526
 
1527
  if __name__ == "__main__":
 
1
+ """Perturbation experiments on the levelized host and on the amplified host."""
2
  from __future__ import annotations
3
 
4
  import argparse
 
12
  import time
13
  from typing import Dict, List, Tuple
14
 
 
 
15
  from host import (
16
  encode,
17
  M_P,
 
19
  HALT_PC,
20
  Tape,
21
  describe,
 
22
  inst,
23
  read_host,
24
  ser,
25
  tau_star,
 
26
  STATE_LAYOUT,
27
  IO_CELLS,
 
28
  )
29
+ from paper import levelize, parse_sigma, write_flat
30
 
31
 
32
  REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
1296
  "curve": cmd_curve, "restore": cmd_restore, "layers": cmd_layers,
1297
  "bound": cmd_bound}[args.mode](args)
1298
 
1299
+ COMMANDS = {'host': main_host, 'amplified': main_amplified}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1300
 
1301
 
1302
  if __name__ == "__main__":
src/paper.py CHANGED
@@ -1048,6 +1048,30 @@ ROCQ = os.path.join(REPO, 'rocq')
1048
  RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_rocq.json')
1049
 
1050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1051
  def main_rocq():
1052
  for tool in ('rocq', 'make', 'ocamlfind'):
1053
  if shutil.which(tool) is None:
@@ -1075,13 +1099,15 @@ def main_rocq():
1075
  if len(lines) != len(names) or any(l != 'Closed under the global context' for l in lines):
1076
  print(out.stdout)
1077
  return 1
 
1078
  ext = subprocess.run([sys.executable, os.path.join(REPO, 'src', 'twohead.py'), 'net', 'extract'],
1079
  capture_output=True, text=True)
1080
- identical = ext.returncode == 0 and '"identical": true' in ext.stdout
1081
  files = [l for l in open(os.path.join(ROCQ, '_CoqProject')).read().split() if l.endswith('.v')]
1082
- res = dict(rocq=version.splitlines()[0], files=len(files),
 
1083
  build_seconds=round(build, 1), theorems={n: 'closed' for n in names},
1084
- extraction_identical=identical)
1085
  rec = json.load(open(RECORD)) if os.path.exists(RECORD) else {}
1086
  rec.update(res)
1087
  json.dump(rec, open(RECORD, 'w'), indent=1)
 
1048
  RECORD = os.path.join(REPO, 'paper', 'runs', 'paper_rocq.json')
1049
 
1050
 
1051
+ def host_extraction():
1052
+ """The host netlist of rocq/Host.v for A = 8, extracted to OCaml, against the netlist sigma(N_host) denotes."""
1053
+ ex = os.path.join(ROCQ, 'extract')
1054
+ subprocess.run(['ocamlfind', 'ocamlopt', '-package', 'stdlib', 'hostnet.mli', 'hostnet.ml', 'dumphost.ml',
1055
+ '-o', 'dumphost'], cwd=ex, check=True)
1056
+ out = os.path.join(ex, 'host_rocq.bin')
1057
+ subprocess.run([os.path.join(ex, 'dumphost'), '8', out], check=True)
1058
+ theirs = open(out, 'rb').read()
1059
+ n, units, nxt = parse_sigma(read_host())
1060
+ words = array('i', [n, len(units), sum(len(ins) for _, ins in units)])
1061
+ words.extend(b for b, _ in units)
1062
+ words.extend(len(ins) for _, ins in units)
1063
+ words.extend(w * (k + 1) for _, ins in units for k, w in ins)
1064
+ words.extend(nxt)
1065
+ if sys.byteorder != 'little':
1066
+ words.byteswap()
1067
+ ours = words.tobytes()
1068
+ for f in os.listdir(ex):
1069
+ if not f.endswith(('.ml', '.mli')):
1070
+ os.remove(os.path.join(ex, f))
1071
+ return dict(A=8, units=len(units), identical=ours == theirs,
1072
+ sha256_sigma=hashlib.sha256(ours).hexdigest(), sha256_rocq=hashlib.sha256(theirs).hexdigest())
1073
+
1074
+
1075
  def main_rocq():
1076
  for tool in ('rocq', 'make', 'ocamlfind'):
1077
  if shutil.which(tool) is None:
 
1099
  if len(lines) != len(names) or any(l != 'Closed under the global context' for l in lines):
1100
  print(out.stdout)
1101
  return 1
1102
+ host = host_extraction()
1103
  ext = subprocess.run([sys.executable, os.path.join(REPO, 'src', 'twohead.py'), 'net', 'extract'],
1104
  capture_output=True, text=True)
1105
+ identical = ext.returncode == 0 and '"identical": true' in ext.stdout and host['identical']
1106
  files = [l for l in open(os.path.join(ROCQ, '_CoqProject')).read().split() if l.endswith('.v')]
1107
+ lines = sum(len(open(os.path.join(ROCQ, f)).read().splitlines()) for f in files)
1108
+ res = dict(rocq=version.splitlines()[0], files=len(files), lines=lines,
1109
  build_seconds=round(build, 1), theorems={n: 'closed' for n in names},
1110
+ host_extraction=host, extraction_identical=identical)
1111
  rec = json.load(open(RECORD)) if os.path.exists(RECORD) else {}
1112
  rec.update(res)
1113
  json.dump(rec, open(RECORD, 'w'), indent=1)
src/twohead.py CHANGED
@@ -653,7 +653,7 @@ def main_net():
653
  sha256_generator=hashlib.sha256(ours).hexdigest(),
654
  sha256_rocq=hashlib.sha256(theirs).hexdigest()))
655
  for f in os.listdir(ex):
656
- if f not in ('dump.ml', 'physnet.ml', 'physnet.mli'):
657
  os.remove(os.path.join(ex, f))
658
  res = dict(members=members, identical=all(m['identical'] for m in members))
659
  net_update_record('extraction', res)
@@ -714,6 +714,7 @@ HALT = 8
714
  class Prog:
715
  def __init__(self):
716
  self.recs = [] # (a0, w0, a1, w1, beta, ao), cells by name
 
717
  self.uid = 0
718
 
719
  def tmp(self):
@@ -853,6 +854,7 @@ def compile_host(P):
853
  P.threshold(t, lits, dst)
854
  else:
855
  _chain_lazy(P, 'and' if t == k else 'or', lits, dst, before)
 
856
 
857
  order_next = [nxt[PC_BIT(t)] - n for t in range(8)] + [nxt[HALT] - n] + \
858
  [nxt[mem_bit(j, t)] - n for j in range(256) for t in range(8)]
@@ -1082,7 +1084,7 @@ def build_stored():
1082
  tau = SR.describe(image)
1083
  assert SR.decode(tau) == image
1084
  return dict(recs=recs, addr=addr, top=top, image=image, image_bits=image_bits, tau=tau,
1085
- n_host_records=n_host, host=(n, units, nxt))
1086
 
1087
 
1088
  # ---------------------------------------------------------------------------
@@ -1233,6 +1235,118 @@ def check_stored(trials=40, seed=3, verbose=False):
1233
  return dict(trials=trials, disagreements=bad, records=G, window_cells=S['top'])
1234
 
1235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1236
  def stored_update_record(key, value):
1237
  rec = json.load(open(STORED_RECORD)) if os.path.exists(STORED_RECORD) else {}
1238
  rec[key] = value
@@ -1281,6 +1395,11 @@ def cmd_stored():
1281
  stored_update_record('pass_check', res)
1282
  print(json.dumps(res))
1283
  sys.exit(0 if res['disagreements'] == 0 else 1)
 
 
 
 
 
1284
  elif cmd == 'run':
1285
  gens = int(sys.argv[2]) if len(sys.argv) > 2 else 3
1286
  res = run_stored(gens)
 
653
  sha256_generator=hashlib.sha256(ours).hexdigest(),
654
  sha256_rocq=hashlib.sha256(theirs).hexdigest()))
655
  for f in os.listdir(ex):
656
+ if not f.endswith(('.ml', '.mli')):
657
  os.remove(os.path.join(ex, f))
658
  res = dict(members=members, identical=all(m['identical'] for m in members))
659
  net_update_record('extraction', res)
 
714
  class Prog:
715
  def __init__(self):
716
  self.recs = [] # (a0, w0, a1, w1, beta, ao), cells by name
717
+ self.ends = {} # record -> the unit of the host whose value it writes
718
  self.uid = 0
719
 
720
  def tmp(self):
 
854
  P.threshold(t, lits, dst)
855
  else:
856
  _chain_lazy(P, 'and' if t == k else 'or', lits, dst, before)
857
+ P.ends[len(P.recs) - 1] = u
858
 
859
  order_next = [nxt[PC_BIT(t)] - n for t in range(8)] + [nxt[HALT] - n] + \
860
  [nxt[mem_bit(j, t)] - n for j in range(256) for t in range(8)]
 
1084
  tau = SR.describe(image)
1085
  assert SR.decode(tau) == image
1086
  return dict(recs=recs, addr=addr, top=top, image=image, image_bits=image_bits, tau=tau,
1087
+ n_host_records=n_host, host=(n, units, nxt), ends=P.ends)
1088
 
1089
 
1090
  # ---------------------------------------------------------------------------
 
1235
  return dict(trials=trials, disagreements=bad, records=G, window_cells=S['top'])
1236
 
1237
 
1238
+ class BDD:
1239
+ """Reduced ordered decision diagrams; a node is an integer, 0 and 1 the leaves."""
1240
+ def __init__(self):
1241
+ self.node = [None, None]
1242
+ self.uniq, self.memo = {}, {}
1243
+
1244
+ def mk(self, v, lo, hi):
1245
+ if lo == hi:
1246
+ return lo
1247
+ r = self.uniq.get((v, lo, hi))
1248
+ if r is None:
1249
+ r = self.uniq[(v, lo, hi)] = len(self.node)
1250
+ self.node.append((v, lo, hi))
1251
+ return r
1252
+
1253
+ def var(self, v):
1254
+ return self.mk(v, 0, 1)
1255
+
1256
+ def ite(self, f, g, h):
1257
+ if f < 2:
1258
+ return g if f else h
1259
+ if g == h:
1260
+ return g
1261
+ if g == 1 and h == 0:
1262
+ return f
1263
+ key = (f, g, h)
1264
+ r = self.memo.get(key)
1265
+ if r is None:
1266
+ v = min(self.node[x][0] for x in key if x > 1)
1267
+ lo = [x if x < 2 or self.node[x][0] != v else self.node[x][1] for x in key]
1268
+ hi = [x if x < 2 or self.node[x][0] != v else self.node[x][2] for x in key]
1269
+ r = self.memo[key] = self.mk(v, self.ite(*lo), self.ite(*hi))
1270
+ return r
1271
+
1272
+ def record(self, w0, x, w1, y, beta):
1273
+ """H(w0 x + w1 y + beta) of the bits x and y."""
1274
+ val = lambda a, b: 1 if w0 * a + w1 * b + beta >= 0 else 0
1275
+ return self.ite(x, self.ite(y, val(1, 1), val(1, 0)), self.ite(y, val(0, 1), val(0, 0)))
1276
+
1277
+ def atleast(self, t, lits):
1278
+ """At least t of the literals (x, positive) are true."""
1279
+ if t <= 0:
1280
+ return 1
1281
+ row = [1] + [0] * t
1282
+ for x, pos in reversed(lits):
1283
+ row = [1] + [self.ite(x, row[j - 1], row[j]) if pos else self.ite(x, row[j], row[j - 1])
1284
+ for j in range(1, t + 1)]
1285
+ return row[t]
1286
+
1287
+
1288
+ def symbolic_check():
1289
+ """The startup and step records of the image of S on decision diagrams over the signals of N_host."""
1290
+ sys.setrecursionlimit(100000)
1291
+ t0 = time.time()
1292
+ S = build_stored()
1293
+ n, units, nxt = host_units()
1294
+ bits = bytes_to_bits(S['image'])
1295
+ recs = [decode_record(bits[k * SH_B:(k + 1) * SH_B], SH_ALPHA) for k in range(len(bits) // SH_B)]
1296
+ lo, hi = 2099, 2099 + S['n_host_records']
1297
+ addr = S['addr']
1298
+ D = BDD()
1299
+ # the value of every signal on the current state: a unit that is a constant or a literal is that,
1300
+ # and the units of one function share the variable of the first; fn[u] is the function of unit u
1301
+ # of the values of its predecessors
1302
+ val, first, fn = [D.var(s) for s in range(n)], {}, []
1303
+ for u, (b, ins) in enumerate(units):
1304
+ f = D.atleast(sum(1 for _, w in ins if w < 0) - b, [(val[s], w > 0) for s, w in ins])
1305
+ fn.append(f)
1306
+ val.append(D.var(first.setdefault(f, n + u)) if f > 1 and D.node[f][1:] not in ((0, 1), (1, 0)) else f)
1307
+ unknown = lambda c: D.var(1 << 30 | c)
1308
+ state = [addr[('s', i)] for i in range(n)]
1309
+ ends = S['ends']
1310
+ agree = [True]
1311
+
1312
+ def run(window, a, b):
1313
+ # at the record that the compiler names as writing the value of unit u, the cell must hold
1314
+ # the function of u, and from then on it holds the value of u
1315
+ for k in range(a, b):
1316
+ a0, w0, a1, w1, beta, ao = recs[k]
1317
+ assert ao >= 7, ('a record writes a head or a request', k)
1318
+ g = D.record(w0, window[a0], w1, window[a1], beta)
1319
+ if k in ends:
1320
+ u = ends[k]
1321
+ agree[0] &= g == fn[u]
1322
+ g = val[n + u]
1323
+ window[ao] = g
1324
+
1325
+ # the startup: x_0(m*) when booted is 0, the window unchanged when it is 1
1326
+ boot = addr[('d', 'booted')]
1327
+ window = [unknown(c) for c in range(SH_W)]
1328
+ regs = [addr[('d', 'cnt', i)] for i in range(CW)] + [addr[('d', 'lim', i)] for i in range(CW)] + \
1329
+ [addr[('d', 'dest')]]
1330
+ before = list(window)
1331
+ run(window, 0, lo)
1332
+ B0 = before[boot]
1333
+ x0 = [0] * n
1334
+ for j in range(256):
1335
+ for t in range(8):
1336
+ x0[mem_bit(j, t)] = (SR.M_STAR[j] >> t) & 1
1337
+ startup = window[boot] == 1 and all(window[c] == D.ite(B0, before[c], 0) for c in regs) and \
1338
+ all(window[state[i]] == D.ite(B0, before[state[i]], x0[i]) for i in range(n))
1339
+ # the step: from every window, the state bits end holding the next state of N_host
1340
+ window = [unknown(c) for c in range(SH_W)]
1341
+ for i in range(n):
1342
+ window[state[i]] = val[i]
1343
+ run(window, lo, hi)
1344
+ step = agree[0] and len(ends) == len(units) and all(window[state[i]] == val[nxt[i]] for i in range(n))
1345
+ return dict(startup_records=lo, step_records=hi - lo, startup_exact=startup, step_exact=step,
1346
+ sha256_image=hashlib.sha256(S['image']).hexdigest(), nodes=len(D.node),
1347
+ seconds=round(time.time() - t0, 1))
1348
+
1349
+
1350
  def stored_update_record(key, value):
1351
  rec = json.load(open(STORED_RECORD)) if os.path.exists(STORED_RECORD) else {}
1352
  rec[key] = value
 
1395
  stored_update_record('pass_check', res)
1396
  print(json.dumps(res))
1397
  sys.exit(0 if res['disagreements'] == 0 else 1)
1398
+ elif cmd == 'symbolic':
1399
+ res = symbolic_check()
1400
+ stored_update_record('symbolic', res)
1401
+ print(json.dumps(res))
1402
+ sys.exit(0 if res['startup_exact'] and res['step_exact'] else 1)
1403
  elif cmd == 'run':
1404
  gens = int(sys.argv[2]) if len(sys.argv) > 2 else 3
1405
  res = run_stored(gens)