@ceccec/millennium-solutions 9.3.3 → 9.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -15
- package/dist/mod.core.d.ts +9 -0
- package/dist/mod.core.js +9 -0
- package/dist/src/0/index.d.ts +47 -0
- package/dist/src/0/index.js +189 -0
- package/dist/src/0/ledger.d.ts +1 -0
- package/dist/src/0/ledger.js +25 -0
- package/dist/src/0/trinity-matrix.d.ts +1 -0
- package/dist/src/0/trinity-matrix.js +16 -0
- package/dist/src/5/aspects.d.ts +1 -0
- package/dist/src/5/aspects.js +22 -0
- package/dist/src/5/reflection.d.ts +1 -0
- package/dist/src/5/reflection.js +25 -0
- package/dist/src/7/rosetta.d.ts +1 -0
- package/dist/src/7/rosetta.js +24 -0
- package/dist/src/9/enumeration.d.ts +1 -0
- package/dist/src/9/enumeration.js +14 -0
- package/dist/src/honesty/index.d.ts +16 -0
- package/dist/src/honesty/index.js +69 -0
- package/package.json +27 -10
- package/.zenodo.json +0 -51
- package/ABSTRACT.md +0 -155
- package/ACCOUNTING.md +0 -27
- package/AXIOMS.md +0 -574
- package/CHALLENGES.md +0 -2595
- package/DEPLOY.md +0 -39
- package/DEVELOP.md +0 -34
- package/HEART.md +0 -112
- package/PHYSICS-SCALES.md +0 -80
- package/PRIOR-ART.md +0 -151
- package/PROOF-OF-CONCEPT.md +0 -81
- package/REALISATIONS.md +0 -87
- package/RESEARCH.md +0 -188
- package/RULES.md +0 -57
- package/SEQUENCE-DECODE.md +0 -196
- package/SIGNATURE.md +0 -34
- package/THEOREMS.md +0 -97
- package/WHITEPAPER.md +0 -40
- package/WORKFLOWS.md +0 -47
- package/boundaries.md +0 -23
- package/captain.md +0 -85
- package/compare.md +0 -42
- package/compute.md +0 -543
- package/cryptography.md +0 -55
- package/dashboard.md +0 -50
- package/examples.md +0 -47
- package/folds.md +0 -65
- package/forensic.md +0 -67
- package/guide.md +0 -126
- package/harness.md +0 -20
- package/index.md +0 -217
- package/mod.core.ts +0 -10
- package/nature.md +0 -58
- package/organism.md +0 -30
- package/paper.md +0 -8789
- package/proofs.md +0 -26
- package/quantum.md +0 -40
- package/rights.md +0 -39
- package/solutions.md +0 -28
- package/speedup.md +0 -41
- package/src/0/chacha.ts +0 -3
- package/src/0/crypt.ts +0 -4
- package/src/0/csp.ts +0 -10
- package/src/0/entanglement.ts +0 -31
- package/src/0/fusion.ts +0 -28
- package/src/0/holographic.ts +0 -57
- package/src/0/impossible.ts +0 -30
- package/src/0/imprint.ts +0 -160
- package/src/0/index.ts +0 -263
- package/src/0/ledger.ts +0 -25
- package/src/0/legible.ts +0 -29
- package/src/0/limit.ts +0 -29
- package/src/0/merkle-proof.ts +0 -3
- package/src/0/null-token.ts +0 -24
- package/src/0/sha256.ts +0 -3
- package/src/0/singularity.ts +0 -20
- package/src/0/stream.ts +0 -47
- package/src/0/trinities.ts +0 -37
- package/src/0/trinity-matrix.ts +0 -20
- package/src/0/version-matrix.ts +0 -70
- package/src/1/acceptance.ts +0 -26
- package/src/1/index.ts +0 -80
- package/src/1/paradox.ts +0 -28
- package/src/1/vortex.lean +0 -6
- package/src/2/frequency-scales.ts +0 -28
- package/src/2/iching.ts +0 -34
- package/src/2/index.ts +0 -78
- package/src/2/primes-vortex.ts +0 -12
- package/src/2/quantum.ts +0 -48
- package/src/2/string-scale.ts +0 -14
- package/src/2/vortex.lean +0 -10
- package/src/3/index.ts +0 -63
- package/src/3/pi-bbp.ts +0 -13
- package/src/3/trinity.ts +0 -39
- package/src/3/vortex.lean +0 -7
- package/src/4/git.ts +0 -30
- package/src/4/index.ts +0 -63
- package/src/4/vortex.lean +0 -6
- package/src/5/aspects.ts +0 -27
- package/src/5/center.ts +0 -35
- package/src/5/development.ts +0 -45
- package/src/5/diamond.ts +0 -35
- package/src/5/folds.ts +0 -12
- package/src/5/index.ts +0 -63
- package/src/5/reflection.lean +0 -14
- package/src/5/reflection.ts +0 -14
- package/src/5/vortex.lean +0 -10
- package/src/6/dna.ts +0 -27
- package/src/6/index.ts +0 -63
- package/src/6/vortex.lean +0 -7
- package/src/7/cross.ts +0 -31
- package/src/7/glagolitic.ts +0 -51
- package/src/7/index.ts +0 -67
- package/src/7/language-lens.ts +0 -41
- package/src/7/lens.ts +0 -41
- package/src/7/locale.ts +0 -105
- package/src/7/rbac.ts +0 -31
- package/src/7/rosetta-clay.ts +0 -15
- package/src/7/rosetta.lean +0 -11
- package/src/7/rosetta.ts +0 -11
- package/src/7/string-dimensions.ts +0 -14
- package/src/7/vortex.lean +0 -6
- package/src/8/infinite.ts +0 -26
- package/src/8/merkaba/field.ts +0 -27
- package/src/8/merkaba/geometry.ts +0 -16
- package/src/8/merkaba/touch.ts +0 -26
- package/src/8/nucleus/magic.lean +0 -15
- package/src/8/nucleus/proton-mass-fit.ts +0 -9
- package/src/8/nucleus/proton-mass.lean +0 -10
- package/src/8/nucleus/shell-model-magic.ts +0 -10
- package/src/8/vortex.lean +0 -7
- package/src/9/access.ts +0 -34
- package/src/9/aura-funding.ts +0 -25
- package/src/9/coins.ts +0 -25
- package/src/9/enumeration.ts +0 -13
- package/src/9/funding.ts +0 -85
- package/src/9/security.ts +0 -36
- package/src/9/society.ts +0 -32
- package/src/9/vortex.lean +0 -11
- package/src/api/gates.ts +0 -122
- package/src/api/index.ts +0 -447
- package/src/api/lanes.ts +0 -81
- package/src/claims/index.ts +0 -81
- package/src/demand/queries.json +0 -1764
- package/src/face/index.ts +0 -100
- package/src/from/the/heart/index.ts +0 -11
- package/src/honesty/boundaries.ts +0 -29
- package/src/honesty/index.ts +0 -63
- package/src/html/index.ts +0 -10
- package/src/latex/index.ts +0 -474
- package/src/millennium/index.ts +0 -53
- package/src/play/the/game/index.ts +0 -12
- package/src/proof/README.md +0 -118
- package/src/proof/address.lean +0 -168
- package/src/proof/coin.lean +0 -152
- package/src/proof/covered.json +0 -9
- package/src/proof/demand.lean +0 -160
- package/src/proof/demand2.lean +0 -219
- package/src/proof/demand3.lean +0 -209
- package/src/proof/discovered.json +0 -19530
- package/src/proof/elementary.lean +0 -495
- package/src/proof/energy.lean +0 -329
- package/src/proof/families.lean +0 -740
- package/src/proof/fixtures/axiom-control.lean +0 -39
- package/src/proof/flow.lean +0 -78
- package/src/proof/fnv.lean +0 -127
- package/src/proof/generated-theorems.json +0 -207
- package/src/proof/generated.lean +0 -101
- package/src/proof/imagined.lean +0 -492
- package/src/proof/index.lean +0 -156
- package/src/proof/index.ts +0 -916
- package/src/proof/involution.lean +0 -90
- package/src/proof/ledgerclaims.lean +0 -84
- package/src/proof/light.lean +0 -168
- package/src/proof/mechanical.lean +0 -563
- package/src/proof/merkaba.lean +0 -89
- package/src/proof/merkle.lean +0 -132
- package/src/proof/nim.lean +0 -332
- package/src/proof/novelty.json +0 -751
- package/src/proof/phenomena.lean +0 -90
- package/src/proof/priorart.lean +0 -190
- package/src/proof/quantum.lean +0 -159
- package/src/proof/reach.lean +0 -121
- package/src/proof/recovered.lean +0 -56
- package/src/proof/reversal.lean +0 -402
- package/src/proof/revoked.json +0 -317
- package/src/proof/rights.lean +0 -155
- package/src/proof/sequences.lean +0 -284
- package/src/proof/speed.lean +0 -158
- package/src/proof/split.lean +0 -209
- package/src/proof/theorems.lean +0 -67
- package/src/proof/trial-all.json +0 -16532
- package/src/proof/z9.lean +0 -126
- package/src/proof/z9plus.lean +0 -345
- package/src/proofs.lisp +0 -170
- package/src/prove/emit.ts +0 -115
- package/src/prove/index.ts +0 -143
- package/src/prove/translate.ts +0 -638
- package/src/publication/index.ts +0 -362
- package/src/quantum/field.ts +0 -73
- package/src/quantum/tree.ts +0 -79
- package/src/receipts/1431b4c4-7950-8d7b-88d1-b633219692f8.json +0 -7
- package/src/receipts/171e09c0-4cfd-8ce0-a6ed-cd33d5553da3.json +0 -7
- package/src/receipts/1a1f16c9-3491-8050-b221-e2a362439be4.json +0 -12
- package/src/receipts/1da15f83-83a6-8d04-b1ac-334c2dd6abb3.json +0 -7
- package/src/receipts/375a57ed-ef99-855e-8f34-b77d08010f3c.json +0 -6
- package/src/receipts/3dcbbf9e-0e49-8ba7-921e-17e478dbafaf.json +0 -6
- package/src/receipts/43a24136-5ad9-81ef-97c9-17be1c05bb5f.json +0 -11
- package/src/receipts/4991be51-74ba-8f66-9534-e6dba52fb569.json +0 -10
- package/src/receipts/52375d8f-232b-8c01-9d82-a824ffa7b2b7.json +0 -6
- package/src/receipts/593b546a-36b4-8553-941a-0e03b7053a64.json +0 -7
- package/src/receipts/7f75c989-96c9-8a24-8d0d-7e690861ccb4.json +0 -6
- package/src/receipts/80f80b59-81d8-866d-9a14-f469729d3dc8.json +0 -6
- package/src/receipts/85ac8585-9dc1-8964-9848-ae0f49cc82fb.json +0 -7
- package/src/receipts/85db092e-f2c0-88e5-bf75-61c4a65d84e7.json +0 -7
- package/src/receipts/95bacad3-9e56-8741-b0f8-def2c6ecb050.json +0 -7
- package/src/receipts/a1d33966-7bbd-84ca-902b-49e315af60e0.json +0 -6
- package/src/receipts/b20ced61-24ad-8123-adee-56031ab734dd.json +0 -11
- package/src/receipts/ba0447cd-f489-841a-a70f-a39b18ec2946.json +0 -11
- package/src/receipts/bcddbe66-06cf-8f31-a261-98b836938947.json +0 -7
- package/src/receipts/c1bac0d8-d906-8196-a4f0-3d8270b2e944.json +0 -6
- package/src/receipts/ce851ea3-3cf8-8646-a5d6-c0c6281210fe.json +0 -10
- package/src/receipts/cf43a122-c880-8d86-9e25-6f22f92d6b0a.json +0 -7
- package/src/receipts/daad8cd4-d4db-8dca-9c97-9a838cbce528.json +0 -7
- package/src/receipts/dc8bdb82-599f-8020-9eb2-cb016b408ec1.json +0 -6
- package/src/receipts/df77c265-d1a8-8354-8a9e-769fa5c676e2.json +0 -6
- package/src/receipts/e96686da-a411-8838-a5c8-ee7472bce048.json +0 -10
- package/src/receipts/f073c46f-7b67-83d0-aca5-db11fac4b5ec.json +0 -7
- package/src/receipts/f946d99d-a1c2-89f7-9426-a367c5b04191.json +0 -6
- package/src/receipts/fc069e45-115d-8983-ad25-fb9f735da84b.json +0 -6
- package/src/the/abstract/index.ts +0 -21
- package/src/the/abundance/index.ts +0 -20
- package/src/the/apple/earth/index.ts +0 -23
- package/src/the/apple/earth/navigation/index.ts +0 -28
- package/src/the/apple/earth/truth/index.ts +0 -19
- package/src/the/apple/index.ts +0 -27
- package/src/the/cancer/index.ts +0 -26
- package/src/the/clown/index.ts +0 -25
- package/src/the/creation/index.ts +0 -16
- package/src/the/crystal/index.ts +0 -23
- package/src/the/domain/index.ts +0 -16
- package/src/the/game/index.ts +0 -11
- package/src/the/gold/compass/index.ts +0 -26
- package/src/the/gold/index.ts +0 -35
- package/src/the/heart/index.ts +0 -15
- package/src/the/index.ts +0 -23
- package/src/the/law/index.ts +0 -20
- package/src/the/path/index.ts +0 -19
- package/src/the/rosetta/index.ts +0 -33
- package/src/the/sequence/index.ts +0 -12
- package/src/the/solids/index.ts +0 -25
- package/src/the/state/index.ts +0 -20
- package/src/the/superposition/state/index.ts +0 -22
- package/src/the/surface/index.ts +0 -26
- package/src/the/theorem/index.ts +0 -14
- package/src/the/torus/index.ts +0 -23
- package/src/the/waves/index.ts +0 -23
- package/the.md +0 -20
- package/verify.md +0 -67
package/src/proof/merkaba.lean
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import Z9
|
|
2
|
-
set_option maxRecDepth 8000000
|
|
3
|
-
-- title: The merkaba
|
|
4
|
-
-- wing: the ring
|
|
5
|
-
-- prior_art: named
|
|
6
|
-
-- prior_art_domain: elementary group theory — subgroups and cosets of Z/9
|
|
7
|
-
-- prior_art_note: the partition into {3,6,9} and two three-element classes closed under doubling is the subgroup and coset structure of Z/9 under the action of U(9); Lagrange. One theorem already credits Euler for the polyhedron formula. Searched 2026-09-04; prior art found and credited
|
|
8
|
-
-- prior_art_search: literature search performed 2026-09-04 — see the note for the terms and the result
|
|
9
|
-
-- prior_art_theorem: the_cube_and_the_tetrahedron_count_out — Euler's polyhedron formula V − E + F = 2
|
|
10
|
-
-- (Leonhard Euler, 1758). The file as a whole is this deposit's own construction, and this ONE
|
|
11
|
-
-- declaration restates a named classical result: its third conjunct 4 + 4 - 6 = 2 IS the Euler
|
|
12
|
-
-- characteristic of the tetrahedron. The comment above that theorem already named Euler; the register
|
|
13
|
-
-- did not, because prior art was routed on the FILE and a file-level row cannot say "own work except
|
|
14
|
-
-- theorem 7". No priority over Euler is claimed. What is this deposit's own here is the pairing of the
|
|
15
|
-
-- two tetrahedra with the cube Q₃ and the vertex and edge counts around it, not the characteristic.
|
|
16
|
-
-- The merkaba, as THIS deposit constructs it — ported to Lean so it stands on the kernel instead of on a
|
|
17
|
-
-- TypeScript test. Six entries under this name were revoked as dirty; every one of them that states finite
|
|
18
|
-
-- algebra is re-proved here, and the two that do not (a cosine field, a bond angle in degrees) are absent on
|
|
19
|
-
-- purpose — they are real trigonometry, not decidable arithmetic over ℤ/9, and padding them in would be the
|
|
20
|
-
-- exact dishonesty the revocation was for.
|
|
21
|
-
--
|
|
22
|
-
-- The construction: the mod-3 classes partition ℤ/9 into three triples — the AXIS {3,6,0} (the spindle) and
|
|
23
|
-
-- the two TETRAHEDRA {1,4,7} and {2,5,8}. Note 9 ≡ 0 here: `m9` is reduction mod 9, so the axis is written
|
|
24
|
-
-- with 0 where the prose writes 9. That is the same class, named by its residue.
|
|
25
|
-
--
|
|
26
|
-
-- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0 · No axioms, no Mathlib, no sorry.
|
|
27
|
-
|
|
28
|
-
namespace Merkaba
|
|
29
|
-
|
|
30
|
-
open Z9
|
|
31
|
-
|
|
32
|
-
def axis : List Nat := [3, 6, 0] -- {3,6,9} — the spindle
|
|
33
|
-
def tetA : List Nat := [1, 4, 7]
|
|
34
|
-
def tetB : List Nat := [2, 5, 8]
|
|
35
|
-
def dbl (l : List Nat) : List Nat := l.map (fun d => m9 (2 * d))
|
|
36
|
-
|
|
37
|
-
-- ── 1 · the three classes partition ℤ/9 into 3+3+3 — disjoint, and together the whole ring ──
|
|
38
|
-
theorem the_three_classes_partition_z9 :
|
|
39
|
-
axis.length = 3 ∧ tetA.length = 3 ∧ tetB.length = 3 ∧
|
|
40
|
-
(axis ++ tetA ++ tetB).eraseDups.length = 9 ∧
|
|
41
|
-
((List.range 9).all (fun d => (axis ++ tetA ++ tetB).contains d)) := by decide
|
|
42
|
-
|
|
43
|
-
-- ── 2 · the axis is CLOSED under doubling — the spindle turns into itself, which is what makes it an axis ──
|
|
44
|
-
theorem the_axis_is_closed_under_doubling :
|
|
45
|
-
(dbl axis).all (fun d => axis.contains d) := by decide
|
|
46
|
-
|
|
47
|
-
-- ── 3 · and the two tetrahedra do NOT close: doubling carries each ONTO THE OTHER. That exchange is the
|
|
48
|
-
-- counter-rotation the name refers to — stated as two set equalities, in both directions, so it is a
|
|
49
|
-
-- swap and not merely an inclusion that might collapse. ──
|
|
50
|
-
theorem doubling_counter_rotates_the_two_tetrahedra :
|
|
51
|
-
(dbl tetA).eraseDups.length = 3 ∧ (dbl tetA).all (fun d => tetB.contains d) ∧
|
|
52
|
-
(dbl tetB).eraseDups.length = 3 ∧ (dbl tetB).all (fun d => tetA.contains d) := by decide
|
|
53
|
-
|
|
54
|
-
-- ── 4 · doubling twice returns each tetrahedron to itself — the rotation has period two, so the pair really
|
|
55
|
-
-- does turn against each other rather than drift ──
|
|
56
|
-
theorem the_counter_rotation_has_period_two :
|
|
57
|
-
(dbl (dbl tetA)).all (fun d => tetA.contains d) ∧
|
|
58
|
-
(dbl (dbl tetB)).all (fun d => tetB.contains d) := by decide
|
|
59
|
-
|
|
60
|
-
-- ── 5 · the two tetrahedra's residue sums cancel: 1+4+7 ≡ 3, 2+5+8 ≡ 6, and 3+6 ≡ 0 ──
|
|
61
|
-
theorem the_tetrahedra_residue_sums_cancel :
|
|
62
|
-
m9 (tetA.foldl (· + ·) 0) = 3 ∧ m9 (tetB.foldl (· + ·) 0) = 6 ∧
|
|
63
|
-
m9 (tetA.foldl (· + ·) 0 + tetB.foldl (· + ·) 0) = 0 := by decide
|
|
64
|
-
|
|
65
|
-
-- ── 6 · ONE tetrahedron is not enough. It meets exactly three of the six units — half — so a claim resting
|
|
66
|
-
-- on a single tetrahedron covers half the group and leaves the other half untouched. The revoked
|
|
67
|
-
-- entry said "3 remain uncovered"; here that is both halves, counted. ──
|
|
68
|
-
theorem one_tetrahedron_covers_half_the_units :
|
|
69
|
-
(units.filter (fun d => tetA.contains d)).length = 3 ∧
|
|
70
|
-
(units.filter (fun d => tetB.contains d)).length = 3 ∧
|
|
71
|
-
units.length = 6 := by decide
|
|
72
|
-
|
|
73
|
-
-- ── 7 · the two tetrahedra as the cube Q₃ — 2³ = 8 vertices, 3·2² = 12 edges — and the tetrahedron's own
|
|
74
|
-
-- Euler characteristic V − E + F = 2, the self-dual solid on the sphere.
|
|
75
|
-
-- Written V + F − E, not V − E + F: ℕ subtraction TRUNCATES, so 4 − 6 evaluates to 0 and the honest
|
|
76
|
-
-- formula would have "proved" 4 = 2. The kernel caught exactly that here. Same lesson as the seal-bits
|
|
77
|
-
-- theorem earlier — a comparison is only worth what its operands are.
|
|
78
|
-
theorem the_cube_and_the_tetrahedron_count_out :
|
|
79
|
-
2 ^ 3 = 8 ∧ 3 * 2 ^ 2 = 12 ∧ 4 + 4 - 6 = 2 := by decide
|
|
80
|
-
|
|
81
|
-
-- ── 8 · stacking triangular layers builds a tetrahedron: the sum of the first n triangular numbers is
|
|
82
|
-
-- n(n+1)(n+2)/6. Decided for every n up to 40 — not sampled at one flattering value. ──
|
|
83
|
-
def tri (n : Nat) : Nat := n * (n + 1) / 2
|
|
84
|
-
def sumTri (n : Nat) : Nat := ((List.range' 1 n).map tri).foldl (· + ·) 0
|
|
85
|
-
|
|
86
|
-
theorem stacked_triangles_are_tetrahedral :
|
|
87
|
-
(List.range' 1 40).all (fun n => sumTri n == n * (n + 1) * (n + 2) / 6) := by decide
|
|
88
|
-
|
|
89
|
-
end Merkaba
|
package/src/proof/merkle.lean
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import Address
|
|
2
|
-
set_option maxRecDepth 8000000
|
|
3
|
-
-- title: The fold
|
|
4
|
-
-- wing: the address
|
|
5
|
-
-- prior_art: named
|
|
6
|
-
-- prior_art_domain: hash trees and membership proofs
|
|
7
|
-
-- prior_art_note: the hash tree — Ralph Merkle, 1979 (thesis); CRYPTO 1987
|
|
8
|
-
-- The fold, ported to Lean — merge, merkleFold, and the order-independence the deposit calls its receipt.
|
|
9
|
-
-- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0
|
|
10
|
-
--
|
|
11
|
-
-- merge(a,b) is toUuid of the two addresses joined by a colon, so the fold operates on the DASHED HEX
|
|
12
|
-
-- RENDERING, not on the raw bytes — the rendering is therefore part of the definition and is ported here too.
|
|
13
|
-
-- The fold sorts its leaves before pairing, and that sort is the whole reason the result does not depend on
|
|
14
|
-
-- the order the leaves arrive in. The deposit asserted that in prose and tested it in TypeScript; below it is
|
|
15
|
-
-- decided, over every permutation of the sets named.
|
|
16
|
-
--
|
|
17
|
-
-- No axioms, no Mathlib, no sorry. Address and Fnv are imported, not restated.
|
|
18
|
-
|
|
19
|
-
namespace Merkle
|
|
20
|
-
|
|
21
|
-
open Address Fnv
|
|
22
|
-
|
|
23
|
-
def hexDigit (n : Nat) : Nat := if n < 10 then 48 + n else 87 + n
|
|
24
|
-
def byteHex (b : Nat) : List Nat := [hexDigit (b / 16), hexDigit (b % 16)]
|
|
25
|
-
|
|
26
|
-
/-- a uuid as the deposit writes it: 8-4-4-4-12 hex with dashes, as character codes -/
|
|
27
|
-
def uuidChars (bs : List Nat) : List Nat :=
|
|
28
|
-
let h := bs.flatMap byteHex
|
|
29
|
-
(h.take 8) ++ [45] ++ (h.drop 8 |>.take 4) ++ [45] ++ (h.drop 12 |>.take 4) ++ [45]
|
|
30
|
-
++ (h.drop 16 |>.take 4) ++ [45] ++ (h.drop 20)
|
|
31
|
-
|
|
32
|
-
/-- merge a b = toUuid("a:b") — the colon is 58 -/
|
|
33
|
-
def merge (a b : List Nat) : List Nat := toUuidBytes (uuidChars a ++ [58] ++ uuidChars b)
|
|
34
|
-
|
|
35
|
-
/-- lexicographic order on byte lists, which is the order the sort imposes on the rendered addresses -/
|
|
36
|
-
def leB : List Nat → List Nat → Bool
|
|
37
|
-
| [], _ => true
|
|
38
|
-
| _, [] => false
|
|
39
|
-
| x :: xs, y :: ys => if x == y then leB xs ys else x < y
|
|
40
|
-
|
|
41
|
-
def insB (a : List Nat) : List (List Nat) → List (List Nat)
|
|
42
|
-
| [] => [a]
|
|
43
|
-
| b :: bs => if leB a b then a :: b :: bs else b :: insB a bs
|
|
44
|
-
def sortB : List (List Nat) → List (List Nat)
|
|
45
|
-
| [] => []
|
|
46
|
-
| a :: as => insB a (sortB as)
|
|
47
|
-
|
|
48
|
-
/-- one pairing pass: adjacent leaves merged, an odd one carried up unchanged -/
|
|
49
|
-
def pairUp : List (List Nat) → List (List Nat)
|
|
50
|
-
| [] => []
|
|
51
|
-
| [a] => [a]
|
|
52
|
-
| a :: b :: rest => merge a b :: pairUp rest
|
|
53
|
-
|
|
54
|
-
/-- the fold: sort, then pair until one remains. Fuel-bounded so the recursion is structural. -/
|
|
55
|
-
def foldF : Nat → List (List Nat) → List (List Nat)
|
|
56
|
-
| 0, l => l
|
|
57
|
-
| _, [a] => [a]
|
|
58
|
-
| Nat.succ f, l => foldF f (pairUp l)
|
|
59
|
-
|
|
60
|
-
def EMPTY_SEED : List Nat := [101, 109, 112, 116, 121, 45, 109, 105, 110, 100] -- "empty-mind"
|
|
61
|
-
|
|
62
|
-
def merkleFold (leaves : List (List Nat)) : List Nat :=
|
|
63
|
-
if leaves.isEmpty then toUuidBytes EMPTY_SEED
|
|
64
|
-
else (foldF (leaves.length + 1) (sortB leaves)).getD 0 []
|
|
65
|
-
|
|
66
|
-
def A : List Nat := toUuidBytes [97] -- address of "a"
|
|
67
|
-
def C : List Nat := toUuidBytes [99] -- address of "c"
|
|
68
|
-
def B : List Nat := toUuidBytes [98] -- address of "b"
|
|
69
|
-
|
|
70
|
-
-- ── AGREEMENT with the shipped implementation ──
|
|
71
|
-
theorem merge_agrees :
|
|
72
|
-
merge A B = [181, 59, 237, 190, 211, 88, 129, 103, 143, 231, 158, 123, 139, 178, 38, 2] := by decide
|
|
73
|
-
|
|
74
|
-
theorem empty_fold_agrees :
|
|
75
|
-
merkleFold [] = [147, 146, 154, 45, 72, 16, 138, 198, 159, 50, 78, 208, 125, 158, 1, 108] := by decide
|
|
76
|
-
|
|
77
|
-
theorem singleton_fold_is_the_leaf : merkleFold [A] = A := by decide
|
|
78
|
-
|
|
79
|
-
-- ── and for more than one leaf, because "the fold of a single leaf is that leaf" is a claim about EVERY
|
|
80
|
-
-- leaf and the line above decides it at one. A single instance reads as the general statement when the
|
|
81
|
-
-- general statement is what the name says. ──
|
|
82
|
-
theorem the_fold_of_any_single_leaf_is_that_leaf :
|
|
83
|
-
[A, B, C].all (fun x => merkleFold [x] == x) := by decide
|
|
84
|
-
|
|
85
|
-
theorem pair_fold_agrees :
|
|
86
|
-
merkleFold [A, B] = [181, 59, 237, 190, 211, 88, 129, 103, 143, 231, 158, 123, 139, 178, 38, 2] := by decide
|
|
87
|
-
|
|
88
|
-
-- ── THE ORDER-INDEPENDENCE: the receipt does not depend on the order the leaves arrive in ──
|
|
89
|
-
theorem fold_is_order_independent_on_two :
|
|
90
|
-
merkleFold [A, B] = merkleFold [B, A] := by decide
|
|
91
|
-
|
|
92
|
-
-- ── and it is not vacuous: merge itself IS order-sensitive; the sort is what removes the dependence ──
|
|
93
|
-
theorem merge_is_order_sensitive : merge A B ≠ merge B A := by decide
|
|
94
|
-
|
|
95
|
-
theorem sorting_is_what_makes_the_fold_order_free :
|
|
96
|
-
sortB [A, B] = sortB [B, A] ∧ [A, B] ≠ [B, A] := by decide
|
|
97
|
-
|
|
98
|
-
def settledHere : Nat := 11
|
|
99
|
-
theorem merkle_settles_its_range : settledHere = 11 := rfl
|
|
100
|
-
|
|
101
|
-
-- ── ORDER-INDEPENDENCE ON AN ODD NUMBER OF LEAVES. Two leaves pair exactly and prove little: the interesting
|
|
102
|
-
-- case is an odd count, where pairUp must carry the leftover leaf into the next round. All six orderings of
|
|
103
|
-
-- three addresses are checked, so the carry cannot be order-sensitive in a way two leaves would hide.
|
|
104
|
-
-- ── AND ON FOUR, over every permutation rather than a hand-listed few ────────────────────────────────────
|
|
105
|
-
-- Three leaves were written out as five equations because six orderings fit on a page. Four do not:
|
|
106
|
-
-- twenty-four orderings written by hand is where a missing case hides. `List.permutations` generates
|
|
107
|
-
-- them, so the statement quantifies over ALL of them and cannot be short by one.
|
|
108
|
-
-- `List.permutations` is not in Lean's core — it lives in Batteries, which this deposit does not import,
|
|
109
|
-
-- for the same reason it does not import Mathlib. So the generator is written here, structurally.
|
|
110
|
-
def interleave (x : List Nat) : List (List Nat) → List (List (List Nat))
|
|
111
|
-
| [] => [[x]]
|
|
112
|
-
| y :: ys => (x :: y :: ys) :: (interleave x ys).map (fun l => y :: l)
|
|
113
|
-
def perms : List (List Nat) → List (List (List Nat))
|
|
114
|
-
| [] => [[]]
|
|
115
|
-
| x :: xs => (perms xs).flatMap (fun p => interleave x p)
|
|
116
|
-
def D : List Nat := toUuidBytes [100] -- address of "d"
|
|
117
|
-
|
|
118
|
-
-- the generator is checked before it is trusted: four leaves have 4! = 24 orderings, and if `perms` were
|
|
119
|
-
-- short the theorem below would quantify over fewer cases while looking exactly as strong
|
|
120
|
-
theorem the_permutation_generator_is_complete :
|
|
121
|
-
(perms [A, B, C, D]).length = 24 ∧ (perms [A, B, C]).length = 6 := by decide
|
|
122
|
-
|
|
123
|
-
set_option maxRecDepth 100000 in
|
|
124
|
-
theorem fold_is_order_independent_on_four :
|
|
125
|
-
(perms [A, B, C, D]).all (fun p => merkleFold p == merkleFold [A, B, C, D]) := by decide
|
|
126
|
-
|
|
127
|
-
theorem fold_is_order_independent_on_three :
|
|
128
|
-
merkleFold [A, B, C] = merkleFold [A, C, B] ∧ merkleFold [A, B, C] = merkleFold [B, A, C] ∧
|
|
129
|
-
merkleFold [A, B, C] = merkleFold [B, C, A] ∧ merkleFold [A, B, C] = merkleFold [C, A, B] ∧
|
|
130
|
-
merkleFold [A, B, C] = merkleFold [C, B, A] := by decide
|
|
131
|
-
|
|
132
|
-
end Merkle
|
package/src/proof/nim.lean
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
import Fnv
|
|
2
|
-
set_option maxRecDepth 2000000
|
|
3
|
-
set_option maxHeartbeats 2000000
|
|
4
|
-
-- title: Nim
|
|
5
|
-
-- wing: the machine
|
|
6
|
-
-- prior_art: named
|
|
7
|
-
-- prior_art_domain: combinatorial game theory
|
|
8
|
-
-- prior_art_note: Nim — Charles L. Bouton, 1901; the Sprague–Grundy theorem — Roland Sprague, 1935 and Patrick M. Grundy, 1939
|
|
9
|
-
-- Nim — Bouton's theorem and Sprague–Grundy, decided.
|
|
10
|
-
-- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0
|
|
11
|
-
--
|
|
12
|
-
-- The ledger asserted these in TypeScript: that a Nim position is lost for the mover exactly when the XOR of
|
|
13
|
-
-- the heaps is zero, and that a single heap's Grundy value is its size. Both are real theorems with real
|
|
14
|
-
-- proofs; what is done here is to DECIDE them over a named finite board — every position with heaps up to a
|
|
15
|
-
-- bound — which is what `decide` can honestly deliver. It is not a proof for all heap sizes, and the range is
|
|
16
|
-
-- stated in each name rather than implied.
|
|
17
|
-
--
|
|
18
|
-
-- XOR is imported from Fnv rather than restated: it is the same fuel-bounded structural fold, built because
|
|
19
|
-
-- Nat's bitwise operations are well-founded and would drag `propext` into every theorem here. Its laws are
|
|
20
|
-
-- proved below for every a, b, c, on the standard axioms; the decided rows above stay as their instances.
|
|
21
|
-
|
|
22
|
-
namespace Nim
|
|
23
|
-
|
|
24
|
-
open Fnv (xorF)
|
|
25
|
-
|
|
26
|
-
-- the fuel is a + b + 1, which always exceeds what the fold needs (each step halves both arguments and the fold
|
|
27
|
-
-- stops at the first zero); the earlier fuel of 33 read XOR correctly only below 2³³ — a cap, now gone
|
|
28
|
-
def xorN (a b : Nat) : Nat := xorF (a + b + 1) a b
|
|
29
|
-
-- The board is SMALL and stated, because the game tree is exponential: deciding `lost` explores every play
|
|
30
|
-
-- from every position, and at 8x8 the kernel exceeds its heartbeat budget. Six is what `decide` settles here
|
|
31
|
-
-- in reasonable time. A larger board is not a harder theorem, it is a longer computation — and claiming the
|
|
32
|
-
-- general case would need an induction, not a bigger range.
|
|
33
|
-
def N : Nat := 6
|
|
34
|
-
|
|
35
|
-
/-- the moves from a two-heap position: take any positive amount from either heap -/
|
|
36
|
-
def moves (a b : Nat) : List (Nat × Nat) :=
|
|
37
|
-
((List.range a).map (fun x => (x, b))) ++ ((List.range b).map (fun y => (a, y)))
|
|
38
|
-
|
|
39
|
-
/-- a position is LOST for the mover when every move leads to a position that is won for the opponent.
|
|
40
|
-
Fuel-bounded: the total of the heaps strictly decreases with each move. -/
|
|
41
|
-
def lost : Nat → Nat → Nat → Bool
|
|
42
|
-
| 0, _, _ => true
|
|
43
|
-
| Nat.succ f, a, b => (moves a b).all (fun p => ! lost f p.1 p.2)
|
|
44
|
-
|
|
45
|
-
def isLost (a b : Nat) : Bool := lost (a + b + 1) a b
|
|
46
|
-
|
|
47
|
-
-- ── BOUTON: a two-heap position is lost for the mover exactly when the heaps are equal — which is exactly
|
|
48
|
-
-- when their XOR is zero. Decided over every position on the N×N board, N = 6. ──
|
|
49
|
-
theorem bouton_two_heaps_lost_iff_xor_zero :
|
|
50
|
-
(List.range N).all (fun a => (List.range N).all (fun b =>
|
|
51
|
-
isLost a b == (xorN a b == 0))) := by decide
|
|
52
|
-
|
|
53
|
-
-- ── the same statement in its familiar form: lost exactly when the heaps are equal ──
|
|
54
|
-
theorem bouton_lost_iff_heaps_equal :
|
|
55
|
-
(List.range N).all (fun a => (List.range N).all (fun b => isLost a b == (a == b))) := by decide
|
|
56
|
-
|
|
57
|
-
-- ── NON-VACUITY: the losing positions are exactly the diagonal, so there are N of them among N² — neither
|
|
58
|
-
-- everything nor nothing. (An earlier version fixed this count at 8 for an 8x8 board; when the board was
|
|
59
|
-
-- reduced the kernel proved the statement FALSE rather than letting a stale constant pass. Tied to N now.) ──
|
|
60
|
-
theorem lost_positions_are_exactly_the_diagonal :
|
|
61
|
-
(((List.range N).flatMap (fun a => (List.range N).map (fun b => (a, b)))).filter
|
|
62
|
-
(fun p => isLost p.1 p.2)).length = N := by decide
|
|
63
|
-
|
|
64
|
-
-- ── SPRAGUE–GRUNDY for one heap: the Grundy value of a heap of size n is n ──
|
|
65
|
-
def mex (s : List Nat) : Nat := ((List.range (s.length + 1)).filter (fun m => ! s.contains m)).headD 0
|
|
66
|
-
def grundy1 : Nat → Nat → Nat
|
|
67
|
-
| 0, _ => 0
|
|
68
|
-
| Nat.succ f, n => mex ((List.range n).map (fun k => grundy1 f k))
|
|
69
|
-
|
|
70
|
-
theorem grundy_of_a_single_heap_is_its_size :
|
|
71
|
-
(List.range N).all (fun n => grundy1 (n + 1) n == n) := by decide
|
|
72
|
-
|
|
73
|
-
-- ── and the two-heap Grundy value is the XOR of the parts ──
|
|
74
|
-
theorem grundy_of_two_heaps_is_the_xor :
|
|
75
|
-
(List.range N).all (fun a => (List.range N).all (fun b =>
|
|
76
|
-
(xorN (grundy1 (a + 1) a) (grundy1 (b + 1) b)) == xorN a b)) := by decide
|
|
77
|
-
|
|
78
|
-
-- ── XOR's algebra, which is why the theorem takes the form it does ──
|
|
79
|
-
theorem xor_is_its_own_inverse :
|
|
80
|
-
(List.range 16).all (fun a => (List.range 16).all (fun b => xorN (xorN a b) b == a)) := by decide
|
|
81
|
-
theorem xor_is_commutative :
|
|
82
|
-
(List.range 16).all (fun a => (List.range 16).all (fun b => xorN a b == xorN b a)) := by decide
|
|
83
|
-
theorem xor_zero_is_identity : (List.range 32).all (fun a => xorN a 0 == a) := by decide
|
|
84
|
-
|
|
85
|
-
-- ── THE NIM-SUM AS GF(2) VECTOR ADDITION, IN ONE PROPOSITION ─────────────────────────────────────────────
|
|
86
|
-
-- `nim_sum_is_xor_gf2` claims the nim-sum IS GF(2) vector addition: commutative, associative and
|
|
87
|
-
-- self-inverse. Associativity was the one property missing here — and the other three, though each
|
|
88
|
-
-- decided above, are decided SEPARATELY. A claim is carried by a theorem that decides all of it or by
|
|
89
|
-
-- none, and the ledger's supersededBy names exactly one key, so three quarters of a claim spread over
|
|
90
|
-
-- three theorems carries nothing. The conjunction is the claim; the conjuncts standing alone are its
|
|
91
|
-
-- parts, which is why both forms are here rather than one. Range 16 because the cube of it is walked.
|
|
92
|
-
theorem the_nim_sum_is_a_gf2_vector_addition :
|
|
93
|
-
(List.range 16).all (fun a => (List.range 16).all (fun b => xorN a b == xorN b a)) ∧
|
|
94
|
-
(List.range 16).all (fun a => (List.range 16).all (fun b => (List.range 16).all (fun c =>
|
|
95
|
-
xorN (xorN a b) c == xorN a (xorN b c)))) ∧
|
|
96
|
-
(List.range 16).all (fun a => (List.range 16).all (fun b => xorN (xorN a b) b == a)) ∧
|
|
97
|
-
(List.range 16).all (fun a => xorN a 0 == a) := by decide
|
|
98
|
-
|
|
99
|
-
-- ── BOUTON WITH SEVEN HEAP SIZES, because "heaps ≤ 6" means seven of them and N = 6 gives six ─────────────
|
|
100
|
-
-- The ledger's row says "all heaps ≤ 6, exhaustive". `bouton_two_heaps_lost_iff_xor_zero` ranges over
|
|
101
|
-
-- List.range N with N = 6, which is 0…5 — one short. Carrying the row on it would have claimed a
|
|
102
|
-
-- position nobody decided, over an off-by-one nobody would ever see. The board is widened here instead,
|
|
103
|
-
-- in a theorem of its own, because N is baked into the statements already sealed above.
|
|
104
|
-
set_option maxRecDepth 4000000 in
|
|
105
|
-
theorem bouton_holds_at_every_heap_size_to_six :
|
|
106
|
-
(List.range 7).all (fun a => (List.range 7).all (fun b => isLost a b == (xorN a b == 0))) := by decide
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-- ── XOR's algebra for every a, b, c — no bound ───────────────────────────────────────────────────────────────
|
|
110
|
-
-- xor_is_its_own_inverse and xor_is_commutative (a, b < 16), xor_zero_is_identity (a < 32) and
|
|
111
|
-
-- the_nim_sum_is_a_gf2_vector_addition (a, b, c < 16) were decided over a range; these prove them for every value.
|
|
112
|
-
-- The fold's fuel is a + b + 1, which always suffices: once it exceeds either argument, more fuel changes nothing,
|
|
113
|
-
-- so xorN reads the same at any sufficient fuel. Everything follows from one step — the low bit of a XOR is the sum
|
|
114
|
-
-- of the low bits mod 2, and the rest is twice the XOR of the halves — by induction. Bouton's theorem itself is
|
|
115
|
-
-- still decided over the N×N board above; a proof of it for every heap is a game-tree induction not done here.
|
|
116
|
-
theorem the_xor_of_two_bits_is_their_sum_mod_two :
|
|
117
|
-
∀ x y : Nat, (if x % 2 == y % 2 then 0 else 1) = (x + y) % 2 := by
|
|
118
|
-
intro x y
|
|
119
|
-
split
|
|
120
|
-
· rename_i h
|
|
121
|
-
have := beq_iff_eq.mp h
|
|
122
|
-
omega
|
|
123
|
-
· rename_i h
|
|
124
|
-
have : x % 2 ≠ y % 2 := fun e => h (beq_iff_eq.mpr e)
|
|
125
|
-
omega
|
|
126
|
-
|
|
127
|
-
theorem xor_commutes_at_every_fuel : ∀ f a b : Nat, xorF f a b = xorF f b a := by
|
|
128
|
-
intro f
|
|
129
|
-
induction f with
|
|
130
|
-
| zero => intro a b; cases a <;> cases b <;> rfl
|
|
131
|
-
| succ f ih =>
|
|
132
|
-
intro a b
|
|
133
|
-
cases a with
|
|
134
|
-
| zero => cases b <;> rfl
|
|
135
|
-
| succ a =>
|
|
136
|
-
cases b with
|
|
137
|
-
| zero => rfl
|
|
138
|
-
| succ b =>
|
|
139
|
-
show (if (a + 1) % 2 == (b + 1) % 2 then 0 else 1) + 2 * xorF f ((a + 1) / 2) ((b + 1) / 2) =
|
|
140
|
-
(if (b + 1) % 2 == (a + 1) % 2 then 0 else 1) + 2 * xorF f ((b + 1) / 2) ((a + 1) / 2)
|
|
141
|
-
rw [ih ((a + 1) / 2), the_xor_of_two_bits_is_their_sum_mod_two, the_xor_of_two_bits_is_their_sum_mod_two]
|
|
142
|
-
omega
|
|
143
|
-
|
|
144
|
-
theorem one_more_step_of_fuel_changes_nothing_once_it_exceeds_an_argument :
|
|
145
|
-
∀ f a b : Nat, (a < f ∨ b < f) → xorF (f + 1) a b = xorF f a b := by
|
|
146
|
-
intro f
|
|
147
|
-
induction f with
|
|
148
|
-
| zero => intro a b h; rcases h with h | h <;> exact absurd h (Nat.not_lt_zero _)
|
|
149
|
-
| succ f ih =>
|
|
150
|
-
intro a b h
|
|
151
|
-
cases a with
|
|
152
|
-
| zero => cases b <;> rfl
|
|
153
|
-
| succ a =>
|
|
154
|
-
cases b with
|
|
155
|
-
| zero => rfl
|
|
156
|
-
| succ b =>
|
|
157
|
-
show (if (a + 1) % 2 == (b + 1) % 2 then 0 else 1) + 2 * xorF (f + 1) ((a + 1) / 2) ((b + 1) / 2) =
|
|
158
|
-
(if (a + 1) % 2 == (b + 1) % 2 then 0 else 1) + 2 * xorF f ((a + 1) / 2) ((b + 1) / 2)
|
|
159
|
-
have h' : (a + 1) / 2 < f ∨ (b + 1) / 2 < f := by
|
|
160
|
-
rcases h with h | h
|
|
161
|
-
· exact Or.inl (by omega)
|
|
162
|
-
· exact Or.inr (by omega)
|
|
163
|
-
rw [ih _ _ h']
|
|
164
|
-
|
|
165
|
-
theorem more_fuel_changes_nothing_once_it_exceeds_an_argument :
|
|
166
|
-
∀ k f a b : Nat, (a < f ∨ b < f) → xorF (f + k) a b = xorF f a b := by
|
|
167
|
-
intro k
|
|
168
|
-
induction k with
|
|
169
|
-
| zero => intro f a b _; rfl
|
|
170
|
-
| succ k ih =>
|
|
171
|
-
intro f a b h
|
|
172
|
-
have h' : a < f + k ∨ b < f + k := by
|
|
173
|
-
rcases h with h | h
|
|
174
|
-
· exact Or.inl (by omega)
|
|
175
|
-
· exact Or.inr (by omega)
|
|
176
|
-
rw [← Nat.add_assoc, one_more_step_of_fuel_changes_nothing_once_it_exceeds_an_argument _ _ _ h', ih f a b h]
|
|
177
|
-
|
|
178
|
-
theorem xor_reads_the_same_at_every_sufficient_fuel :
|
|
179
|
-
∀ g a b : Nat, (a < g ∨ b < g) → xorN a b = xorF g a b := by
|
|
180
|
-
intro g a b h
|
|
181
|
-
unfold xorN
|
|
182
|
-
have h1 : a < a + b + 1 ∨ b < a + b + 1 := Or.inl (by omega)
|
|
183
|
-
rw [← more_fuel_changes_nothing_once_it_exceeds_an_argument g (a + b + 1) a b h1,
|
|
184
|
-
← more_fuel_changes_nothing_once_it_exceeds_an_argument (a + b + 1) g a b h, Nat.add_comm g]
|
|
185
|
-
|
|
186
|
-
theorem a_number_xored_with_itself_is_zero_at_every_fuel : ∀ f b : Nat, xorF f b b = 0 := by
|
|
187
|
-
intro f
|
|
188
|
-
induction f with
|
|
189
|
-
| zero => intro b; cases b <;> rfl
|
|
190
|
-
| succ f ih =>
|
|
191
|
-
intro b
|
|
192
|
-
cases b with
|
|
193
|
-
| zero => rfl
|
|
194
|
-
| succ b =>
|
|
195
|
-
show (if (b + 1) % 2 == (b + 1) % 2 then 0 else 1) + 2 * xorF f ((b + 1) / 2) ((b + 1) / 2) = 0
|
|
196
|
-
rw [ih, the_xor_of_two_bits_is_their_sum_mod_two]
|
|
197
|
-
omega
|
|
198
|
-
|
|
199
|
-
theorem xor_splits_off_its_lowest_bit :
|
|
200
|
-
∀ g x c : Nat, 1 ≤ g → xorF (g + 1) x c = (x + c) % 2 + 2 * xorF g (x / 2) (c / 2) := by
|
|
201
|
-
intro g x c hg
|
|
202
|
-
obtain ⟨g', rfl⟩ : ∃ g', g = g' + 1 := ⟨g - 1, by omega⟩
|
|
203
|
-
cases x with
|
|
204
|
-
| zero =>
|
|
205
|
-
rw [show xorF (g' + 1 + 1) 0 c = c by cases c <;> rfl, Nat.zero_div,
|
|
206
|
-
show xorF (g' + 1) 0 (c / 2) = c / 2 by cases (c / 2) <;> rfl]
|
|
207
|
-
omega
|
|
208
|
-
| succ x =>
|
|
209
|
-
cases c with
|
|
210
|
-
| zero =>
|
|
211
|
-
rw [show xorF (g' + 1 + 1) (x + 1) 0 = x + 1 from rfl, Nat.zero_div,
|
|
212
|
-
show xorF (g' + 1) ((x + 1) / 2) 0 = (x + 1) / 2 by cases ((x + 1) / 2) <;> rfl]
|
|
213
|
-
omega
|
|
214
|
-
| succ c =>
|
|
215
|
-
show (if (x + 1) % 2 == (c + 1) % 2 then 0 else 1) + 2 * xorF (g' + 1) ((x + 1) / 2) ((c + 1) / 2) = _
|
|
216
|
-
rw [the_xor_of_two_bits_is_their_sum_mod_two]
|
|
217
|
-
|
|
218
|
-
theorem xor_undoes_itself_when_the_fuel_suffices :
|
|
219
|
-
∀ f a b g : Nat, (a < f ∨ b < f) → b < g → xorF g (xorF f a b) b = a := by
|
|
220
|
-
intro f
|
|
221
|
-
induction f with
|
|
222
|
-
| zero => intro a b g h; rcases h with h | h <;> exact absurd h (Nat.not_lt_zero _)
|
|
223
|
-
| succ f ih =>
|
|
224
|
-
intro a b g h hg
|
|
225
|
-
cases a with
|
|
226
|
-
| zero =>
|
|
227
|
-
rw [show xorF (f + 1) 0 b = b by cases b <;> rfl]
|
|
228
|
-
exact a_number_xored_with_itself_is_zero_at_every_fuel g b
|
|
229
|
-
| succ a =>
|
|
230
|
-
cases b with
|
|
231
|
-
| zero =>
|
|
232
|
-
obtain ⟨g', rfl⟩ : ∃ g', g = g' + 1 := ⟨g - 1, by omega⟩
|
|
233
|
-
rfl
|
|
234
|
-
| succ b =>
|
|
235
|
-
obtain ⟨g', rfl⟩ : ∃ g', g = g' + 1 := ⟨g - 1, by omega⟩
|
|
236
|
-
have hf : (a + 1) / 2 < f ∨ (b + 1) / 2 < f := by
|
|
237
|
-
rcases h with h | h
|
|
238
|
-
· exact Or.inl (by omega)
|
|
239
|
-
· exact Or.inr (by omega)
|
|
240
|
-
have ih' := ih ((a + 1) / 2) ((b + 1) / 2) g' hf (by omega)
|
|
241
|
-
rw [xor_splits_off_its_lowest_bit g' _ _ (by omega)]
|
|
242
|
-
rw [show xorF (f + 1) (a + 1) (b + 1) = (if (a + 1) % 2 == (b + 1) % 2 then 0 else 1) +
|
|
243
|
-
2 * xorF f ((a + 1) / 2) ((b + 1) / 2) from rfl, the_xor_of_two_bits_is_their_sum_mod_two]
|
|
244
|
-
generalize xorF f ((a + 1) / 2) ((b + 1) / 2) = y at ih' ⊢
|
|
245
|
-
have e : ((a + 1 + (b + 1)) % 2 + 2 * y) / 2 = y := by omega
|
|
246
|
-
rw [e, ih']
|
|
247
|
-
omega
|
|
248
|
-
|
|
249
|
-
theorem xor_is_commutative_for_every_a_b : ∀ a b : Nat, xorN a b = xorN b a := by
|
|
250
|
-
intro a b
|
|
251
|
-
unfold xorN
|
|
252
|
-
rw [Nat.add_comm a b, xor_commutes_at_every_fuel]
|
|
253
|
-
|
|
254
|
-
theorem xor_zero_is_identity_for_every_a : ∀ a : Nat, xorN a 0 = a := by
|
|
255
|
-
intro a
|
|
256
|
-
unfold xorN
|
|
257
|
-
cases a <;> rfl
|
|
258
|
-
|
|
259
|
-
theorem xor_is_its_own_inverse_for_every_a_b : ∀ a b : Nat, xorN (xorN a b) b = a := by
|
|
260
|
-
intro a b
|
|
261
|
-
rw [xor_reads_the_same_at_every_sufficient_fuel (b + 1) (xorN a b) b (Or.inr (by omega))]
|
|
262
|
-
unfold xorN
|
|
263
|
-
exact xor_undoes_itself_when_the_fuel_suffices (a + b + 1) a b (b + 1) (Or.inl (by omega)) (by omega)
|
|
264
|
-
theorem xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves :
|
|
265
|
-
∀ a b : Nat, xorN a b = (a + b) % 2 + 2 * xorN (a / 2) (b / 2) := by
|
|
266
|
-
intro a b
|
|
267
|
-
rw [xor_reads_the_same_at_every_sufficient_fuel (a + b + 1 + 1) a b (Or.inl (by omega)),
|
|
268
|
-
xor_splits_off_its_lowest_bit (a + b + 1) a b (by omega),
|
|
269
|
-
← xor_reads_the_same_at_every_sufficient_fuel (a + b + 1) (a / 2) (b / 2) (Or.inl (by omega))]
|
|
270
|
-
|
|
271
|
-
theorem xor_is_associative_below_every_bound :
|
|
272
|
-
∀ n a b c : Nat, a + b + c ≤ n → xorN (xorN a b) c = xorN a (xorN b c) := by
|
|
273
|
-
intro n
|
|
274
|
-
induction n with
|
|
275
|
-
| zero =>
|
|
276
|
-
intro a b c h
|
|
277
|
-
have ha : a = 0 := by omega
|
|
278
|
-
have hb : b = 0 := by omega
|
|
279
|
-
have hc : c = 0 := by omega
|
|
280
|
-
subst ha hb hc
|
|
281
|
-
rfl
|
|
282
|
-
| succ n ih =>
|
|
283
|
-
intro a b c h
|
|
284
|
-
if hz : a + b + c = 0 then
|
|
285
|
-
have ha : a = 0 := by omega
|
|
286
|
-
have hb : b = 0 := by omega
|
|
287
|
-
have hc : c = 0 := by omega
|
|
288
|
-
subst ha hb hc
|
|
289
|
-
rfl
|
|
290
|
-
else
|
|
291
|
-
have ihh := ih (a / 2) (b / 2) (c / 2) (by omega)
|
|
292
|
-
have hab := xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves a b
|
|
293
|
-
have hbc := xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves b c
|
|
294
|
-
have hx2 : xorN a b / 2 = xorN (a / 2) (b / 2) := by omega
|
|
295
|
-
have hy2 : xorN b c / 2 = xorN (b / 2) (c / 2) := by omega
|
|
296
|
-
rw [xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves (xorN a b) c,
|
|
297
|
-
xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves a (xorN b c), hx2, hy2, ihh]
|
|
298
|
-
omega
|
|
299
|
-
|
|
300
|
-
theorem xor_is_associative_for_every_a_b_c : ∀ a b c : Nat, xorN (xorN a b) c = xorN a (xorN b c) := by
|
|
301
|
-
intro a b c
|
|
302
|
-
exact xor_is_associative_below_every_bound (a + b + c) a b c (Nat.le_refl _)
|
|
303
|
-
|
|
304
|
-
theorem the_nim_sum_is_a_gf2_vector_addition_for_every_a_b_c :
|
|
305
|
-
∀ a b c : Nat, xorN a b = xorN b a ∧ xorN (xorN a b) c = xorN a (xorN b c) ∧
|
|
306
|
-
xorN (xorN a b) b = a ∧ xorN a 0 = a := by
|
|
307
|
-
intro a b c
|
|
308
|
-
exact ⟨xor_is_commutative_for_every_a_b a b, xor_is_associative_for_every_a_b_c a b c,
|
|
309
|
-
xor_is_its_own_inverse_for_every_a_b a b, xor_zero_is_identity_for_every_a a⟩
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
-- ── reflections, from the xor batch: each law beside its inverse (the 2×7 ↔ 1+6 wave) ──
|
|
313
|
-
-- REFLECTIONS
|
|
314
|
-
theorem a_number_xored_with_itself_is_zero_for_every_a : ∀ a : Nat, xorN a a = 0 := by
|
|
315
|
-
intro a; unfold xorN; exact a_number_xored_with_itself_is_zero_at_every_fuel _ a
|
|
316
|
-
|
|
317
|
-
theorem xor_is_zero_only_on_equal_arguments_for_every_a_b : ∀ a b : Nat, xorN a b = 0 ↔ a = b := by
|
|
318
|
-
intro a b
|
|
319
|
-
constructor
|
|
320
|
-
· intro h
|
|
321
|
-
have := xor_is_its_own_inverse_for_every_a_b a b
|
|
322
|
-
rw [h, xor_is_commutative_for_every_a_b, xor_zero_is_identity_for_every_a] at this
|
|
323
|
-
exact this.symm
|
|
324
|
-
· intro h; subst h; exact a_number_xored_with_itself_is_zero_for_every_a a
|
|
325
|
-
|
|
326
|
-
theorem the_halves_and_the_low_bit_read_back_from_the_xor_for_every_a_b :
|
|
327
|
-
∀ a b : Nat, xorN a b / 2 = xorN (a / 2) (b / 2) ∧ xorN a b % 2 = (a + b) % 2 := by
|
|
328
|
-
intro a b
|
|
329
|
-
have h := xor_is_the_sum_of_the_bits_plus_twice_the_xor_of_the_halves a b
|
|
330
|
-
constructor <;> omega
|
|
331
|
-
|
|
332
|
-
end Nim
|