@ceccec/millennium-solutions 9.3.3 → 9.3.4

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.
Files changed (259) hide show
  1. package/README.md +14 -0
  2. package/dist/mod.core.d.ts +9 -0
  3. package/dist/mod.core.js +9 -0
  4. package/dist/src/0/index.d.ts +47 -0
  5. package/dist/src/0/index.js +189 -0
  6. package/dist/src/0/ledger.d.ts +1 -0
  7. package/dist/src/0/ledger.js +25 -0
  8. package/dist/src/0/trinity-matrix.d.ts +1 -0
  9. package/dist/src/0/trinity-matrix.js +16 -0
  10. package/dist/src/5/aspects.d.ts +1 -0
  11. package/dist/src/5/aspects.js +22 -0
  12. package/dist/src/5/reflection.d.ts +1 -0
  13. package/dist/src/5/reflection.js +25 -0
  14. package/dist/src/7/rosetta.d.ts +1 -0
  15. package/dist/src/7/rosetta.js +24 -0
  16. package/dist/src/9/enumeration.d.ts +1 -0
  17. package/dist/src/9/enumeration.js +14 -0
  18. package/dist/src/honesty/index.d.ts +16 -0
  19. package/dist/src/honesty/index.js +69 -0
  20. package/package.json +27 -10
  21. package/.zenodo.json +0 -51
  22. package/ABSTRACT.md +0 -155
  23. package/ACCOUNTING.md +0 -27
  24. package/AXIOMS.md +0 -574
  25. package/CHALLENGES.md +0 -2595
  26. package/DEPLOY.md +0 -39
  27. package/DEVELOP.md +0 -34
  28. package/HEART.md +0 -112
  29. package/PHYSICS-SCALES.md +0 -80
  30. package/PRIOR-ART.md +0 -151
  31. package/PROOF-OF-CONCEPT.md +0 -81
  32. package/REALISATIONS.md +0 -87
  33. package/RESEARCH.md +0 -188
  34. package/RULES.md +0 -57
  35. package/SEQUENCE-DECODE.md +0 -196
  36. package/SIGNATURE.md +0 -34
  37. package/THEOREMS.md +0 -97
  38. package/WHITEPAPER.md +0 -40
  39. package/WORKFLOWS.md +0 -47
  40. package/boundaries.md +0 -23
  41. package/captain.md +0 -85
  42. package/compare.md +0 -42
  43. package/compute.md +0 -543
  44. package/cryptography.md +0 -55
  45. package/dashboard.md +0 -50
  46. package/examples.md +0 -47
  47. package/folds.md +0 -65
  48. package/forensic.md +0 -67
  49. package/guide.md +0 -126
  50. package/harness.md +0 -20
  51. package/index.md +0 -217
  52. package/mod.core.ts +0 -10
  53. package/nature.md +0 -58
  54. package/organism.md +0 -30
  55. package/paper.md +0 -8789
  56. package/proofs.md +0 -26
  57. package/quantum.md +0 -40
  58. package/rights.md +0 -39
  59. package/solutions.md +0 -28
  60. package/speedup.md +0 -41
  61. package/src/0/chacha.ts +0 -3
  62. package/src/0/crypt.ts +0 -4
  63. package/src/0/csp.ts +0 -10
  64. package/src/0/entanglement.ts +0 -31
  65. package/src/0/fusion.ts +0 -28
  66. package/src/0/holographic.ts +0 -57
  67. package/src/0/impossible.ts +0 -30
  68. package/src/0/imprint.ts +0 -160
  69. package/src/0/index.ts +0 -263
  70. package/src/0/ledger.ts +0 -25
  71. package/src/0/legible.ts +0 -29
  72. package/src/0/limit.ts +0 -29
  73. package/src/0/merkle-proof.ts +0 -3
  74. package/src/0/null-token.ts +0 -24
  75. package/src/0/sha256.ts +0 -3
  76. package/src/0/singularity.ts +0 -20
  77. package/src/0/stream.ts +0 -47
  78. package/src/0/trinities.ts +0 -37
  79. package/src/0/trinity-matrix.ts +0 -20
  80. package/src/0/version-matrix.ts +0 -70
  81. package/src/1/acceptance.ts +0 -26
  82. package/src/1/index.ts +0 -80
  83. package/src/1/paradox.ts +0 -28
  84. package/src/1/vortex.lean +0 -6
  85. package/src/2/frequency-scales.ts +0 -28
  86. package/src/2/iching.ts +0 -34
  87. package/src/2/index.ts +0 -78
  88. package/src/2/primes-vortex.ts +0 -12
  89. package/src/2/quantum.ts +0 -48
  90. package/src/2/string-scale.ts +0 -14
  91. package/src/2/vortex.lean +0 -10
  92. package/src/3/index.ts +0 -63
  93. package/src/3/pi-bbp.ts +0 -13
  94. package/src/3/trinity.ts +0 -39
  95. package/src/3/vortex.lean +0 -7
  96. package/src/4/git.ts +0 -30
  97. package/src/4/index.ts +0 -63
  98. package/src/4/vortex.lean +0 -6
  99. package/src/5/aspects.ts +0 -27
  100. package/src/5/center.ts +0 -35
  101. package/src/5/development.ts +0 -45
  102. package/src/5/diamond.ts +0 -35
  103. package/src/5/folds.ts +0 -12
  104. package/src/5/index.ts +0 -63
  105. package/src/5/reflection.lean +0 -14
  106. package/src/5/reflection.ts +0 -14
  107. package/src/5/vortex.lean +0 -10
  108. package/src/6/dna.ts +0 -27
  109. package/src/6/index.ts +0 -63
  110. package/src/6/vortex.lean +0 -7
  111. package/src/7/cross.ts +0 -31
  112. package/src/7/glagolitic.ts +0 -51
  113. package/src/7/index.ts +0 -67
  114. package/src/7/language-lens.ts +0 -41
  115. package/src/7/lens.ts +0 -41
  116. package/src/7/locale.ts +0 -105
  117. package/src/7/rbac.ts +0 -31
  118. package/src/7/rosetta-clay.ts +0 -15
  119. package/src/7/rosetta.lean +0 -11
  120. package/src/7/rosetta.ts +0 -11
  121. package/src/7/string-dimensions.ts +0 -14
  122. package/src/7/vortex.lean +0 -6
  123. package/src/8/infinite.ts +0 -26
  124. package/src/8/merkaba/field.ts +0 -27
  125. package/src/8/merkaba/geometry.ts +0 -16
  126. package/src/8/merkaba/touch.ts +0 -26
  127. package/src/8/nucleus/magic.lean +0 -15
  128. package/src/8/nucleus/proton-mass-fit.ts +0 -9
  129. package/src/8/nucleus/proton-mass.lean +0 -10
  130. package/src/8/nucleus/shell-model-magic.ts +0 -10
  131. package/src/8/vortex.lean +0 -7
  132. package/src/9/access.ts +0 -34
  133. package/src/9/aura-funding.ts +0 -25
  134. package/src/9/coins.ts +0 -25
  135. package/src/9/enumeration.ts +0 -13
  136. package/src/9/funding.ts +0 -85
  137. package/src/9/security.ts +0 -36
  138. package/src/9/society.ts +0 -32
  139. package/src/9/vortex.lean +0 -11
  140. package/src/api/gates.ts +0 -122
  141. package/src/api/index.ts +0 -447
  142. package/src/api/lanes.ts +0 -81
  143. package/src/claims/index.ts +0 -81
  144. package/src/demand/queries.json +0 -1764
  145. package/src/face/index.ts +0 -100
  146. package/src/from/the/heart/index.ts +0 -11
  147. package/src/honesty/boundaries.ts +0 -29
  148. package/src/honesty/index.ts +0 -63
  149. package/src/html/index.ts +0 -10
  150. package/src/latex/index.ts +0 -474
  151. package/src/millennium/index.ts +0 -53
  152. package/src/play/the/game/index.ts +0 -12
  153. package/src/proof/README.md +0 -118
  154. package/src/proof/address.lean +0 -168
  155. package/src/proof/coin.lean +0 -152
  156. package/src/proof/covered.json +0 -9
  157. package/src/proof/demand.lean +0 -160
  158. package/src/proof/demand2.lean +0 -219
  159. package/src/proof/demand3.lean +0 -209
  160. package/src/proof/discovered.json +0 -19530
  161. package/src/proof/elementary.lean +0 -495
  162. package/src/proof/energy.lean +0 -329
  163. package/src/proof/families.lean +0 -740
  164. package/src/proof/fixtures/axiom-control.lean +0 -39
  165. package/src/proof/flow.lean +0 -78
  166. package/src/proof/fnv.lean +0 -127
  167. package/src/proof/generated-theorems.json +0 -207
  168. package/src/proof/generated.lean +0 -101
  169. package/src/proof/imagined.lean +0 -492
  170. package/src/proof/index.lean +0 -156
  171. package/src/proof/index.ts +0 -916
  172. package/src/proof/involution.lean +0 -90
  173. package/src/proof/ledgerclaims.lean +0 -84
  174. package/src/proof/light.lean +0 -168
  175. package/src/proof/mechanical.lean +0 -563
  176. package/src/proof/merkaba.lean +0 -89
  177. package/src/proof/merkle.lean +0 -132
  178. package/src/proof/nim.lean +0 -332
  179. package/src/proof/novelty.json +0 -751
  180. package/src/proof/phenomena.lean +0 -90
  181. package/src/proof/priorart.lean +0 -190
  182. package/src/proof/quantum.lean +0 -159
  183. package/src/proof/reach.lean +0 -121
  184. package/src/proof/recovered.lean +0 -56
  185. package/src/proof/reversal.lean +0 -402
  186. package/src/proof/revoked.json +0 -317
  187. package/src/proof/rights.lean +0 -155
  188. package/src/proof/sequences.lean +0 -284
  189. package/src/proof/speed.lean +0 -158
  190. package/src/proof/split.lean +0 -209
  191. package/src/proof/theorems.lean +0 -67
  192. package/src/proof/trial-all.json +0 -16532
  193. package/src/proof/z9.lean +0 -126
  194. package/src/proof/z9plus.lean +0 -345
  195. package/src/proofs.lisp +0 -170
  196. package/src/prove/emit.ts +0 -115
  197. package/src/prove/index.ts +0 -143
  198. package/src/prove/translate.ts +0 -638
  199. package/src/publication/index.ts +0 -362
  200. package/src/quantum/field.ts +0 -73
  201. package/src/quantum/tree.ts +0 -79
  202. package/src/receipts/1431b4c4-7950-8d7b-88d1-b633219692f8.json +0 -7
  203. package/src/receipts/171e09c0-4cfd-8ce0-a6ed-cd33d5553da3.json +0 -7
  204. package/src/receipts/1a1f16c9-3491-8050-b221-e2a362439be4.json +0 -12
  205. package/src/receipts/1da15f83-83a6-8d04-b1ac-334c2dd6abb3.json +0 -7
  206. package/src/receipts/375a57ed-ef99-855e-8f34-b77d08010f3c.json +0 -6
  207. package/src/receipts/3dcbbf9e-0e49-8ba7-921e-17e478dbafaf.json +0 -6
  208. package/src/receipts/43a24136-5ad9-81ef-97c9-17be1c05bb5f.json +0 -11
  209. package/src/receipts/4991be51-74ba-8f66-9534-e6dba52fb569.json +0 -10
  210. package/src/receipts/52375d8f-232b-8c01-9d82-a824ffa7b2b7.json +0 -6
  211. package/src/receipts/593b546a-36b4-8553-941a-0e03b7053a64.json +0 -7
  212. package/src/receipts/7f75c989-96c9-8a24-8d0d-7e690861ccb4.json +0 -6
  213. package/src/receipts/80f80b59-81d8-866d-9a14-f469729d3dc8.json +0 -6
  214. package/src/receipts/85ac8585-9dc1-8964-9848-ae0f49cc82fb.json +0 -7
  215. package/src/receipts/85db092e-f2c0-88e5-bf75-61c4a65d84e7.json +0 -7
  216. package/src/receipts/95bacad3-9e56-8741-b0f8-def2c6ecb050.json +0 -7
  217. package/src/receipts/a1d33966-7bbd-84ca-902b-49e315af60e0.json +0 -6
  218. package/src/receipts/b20ced61-24ad-8123-adee-56031ab734dd.json +0 -11
  219. package/src/receipts/ba0447cd-f489-841a-a70f-a39b18ec2946.json +0 -11
  220. package/src/receipts/bcddbe66-06cf-8f31-a261-98b836938947.json +0 -7
  221. package/src/receipts/c1bac0d8-d906-8196-a4f0-3d8270b2e944.json +0 -6
  222. package/src/receipts/ce851ea3-3cf8-8646-a5d6-c0c6281210fe.json +0 -10
  223. package/src/receipts/cf43a122-c880-8d86-9e25-6f22f92d6b0a.json +0 -7
  224. package/src/receipts/daad8cd4-d4db-8dca-9c97-9a838cbce528.json +0 -7
  225. package/src/receipts/dc8bdb82-599f-8020-9eb2-cb016b408ec1.json +0 -6
  226. package/src/receipts/df77c265-d1a8-8354-8a9e-769fa5c676e2.json +0 -6
  227. package/src/receipts/e96686da-a411-8838-a5c8-ee7472bce048.json +0 -10
  228. package/src/receipts/f073c46f-7b67-83d0-aca5-db11fac4b5ec.json +0 -7
  229. package/src/receipts/f946d99d-a1c2-89f7-9426-a367c5b04191.json +0 -6
  230. package/src/receipts/fc069e45-115d-8983-ad25-fb9f735da84b.json +0 -6
  231. package/src/the/abstract/index.ts +0 -21
  232. package/src/the/abundance/index.ts +0 -20
  233. package/src/the/apple/earth/index.ts +0 -23
  234. package/src/the/apple/earth/navigation/index.ts +0 -28
  235. package/src/the/apple/earth/truth/index.ts +0 -19
  236. package/src/the/apple/index.ts +0 -27
  237. package/src/the/cancer/index.ts +0 -26
  238. package/src/the/clown/index.ts +0 -25
  239. package/src/the/creation/index.ts +0 -16
  240. package/src/the/crystal/index.ts +0 -23
  241. package/src/the/domain/index.ts +0 -16
  242. package/src/the/game/index.ts +0 -11
  243. package/src/the/gold/compass/index.ts +0 -26
  244. package/src/the/gold/index.ts +0 -35
  245. package/src/the/heart/index.ts +0 -15
  246. package/src/the/index.ts +0 -23
  247. package/src/the/law/index.ts +0 -20
  248. package/src/the/path/index.ts +0 -19
  249. package/src/the/rosetta/index.ts +0 -33
  250. package/src/the/sequence/index.ts +0 -12
  251. package/src/the/solids/index.ts +0 -25
  252. package/src/the/state/index.ts +0 -20
  253. package/src/the/superposition/state/index.ts +0 -22
  254. package/src/the/surface/index.ts +0 -26
  255. package/src/the/theorem/index.ts +0 -14
  256. package/src/the/torus/index.ts +0 -23
  257. package/src/the/waves/index.ts +0 -23
  258. package/the.md +0 -20
  259. package/verify.md +0 -67
@@ -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
@@ -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
@@ -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