@ceccec/millennium-solutions 0.1.1 → 9.0.6

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 (91) hide show
  1. package/.zenodo.json +33 -9
  2. package/ACCOUNTING.md +7 -7
  3. package/AXIOMS.md +559 -0
  4. package/CHALLENGES.md +2181 -2479
  5. package/CITATION.cff +1 -1
  6. package/DEPLOY.md +2 -2
  7. package/DEVELOP.md +1 -1
  8. package/LICENSE +6 -5
  9. package/PRIOR-ART.md +149 -0
  10. package/README.md +221 -123
  11. package/SIGNATURE.md +2 -2
  12. package/TRIAL.md +69 -0
  13. package/WHITEPAPER.md +5 -5
  14. package/captain.md +2 -2
  15. package/compare.md +4 -4
  16. package/compute.md +9 -0
  17. package/dashboard.md +1 -1
  18. package/examples.md +5 -5
  19. package/forensic.md +67 -0
  20. package/guide.md +5 -5
  21. package/index.md +209 -139
  22. package/package.json +88 -9
  23. package/paper.md +7183 -0
  24. package/quantum.md +42 -0
  25. package/rights.md +39 -0
  26. package/solutions.md +7 -7
  27. package/speedup.md +4 -4
  28. package/src/0/index.ts +12 -2
  29. package/src/1/index.ts +1 -1
  30. package/src/2/frequency-scales.ts +13 -1
  31. package/src/2/index.ts +1 -1
  32. package/src/3/index.ts +1 -1
  33. package/src/4/index.ts +1 -1
  34. package/src/5/index.ts +1 -1
  35. package/src/6/index.ts +1 -1
  36. package/src/7/index.ts +1 -1
  37. package/src/9/funding.ts +2 -2
  38. package/src/api/gates.ts +117 -0
  39. package/src/api/index.ts +488 -0
  40. package/src/api/lanes.ts +81 -0
  41. package/src/demand/queries.json +1764 -0
  42. package/src/face/index.ts +100 -0
  43. package/src/html/index.ts +10 -0
  44. package/src/latex/index.ts +474 -0
  45. package/src/millennium/index.ts +53 -0
  46. package/src/proof/README.md +1 -1
  47. package/src/proof/address.lean +117 -0
  48. package/src/proof/coin.lean +148 -0
  49. package/src/proof/covered.json +9 -0
  50. package/src/proof/demand.lean +112 -0
  51. package/src/proof/demand2.lean +171 -0
  52. package/src/proof/demand3.lean +117 -0
  53. package/src/proof/discovered.json +10965 -1864
  54. package/src/proof/elementary.lean +393 -0
  55. package/src/proof/energy.lean +215 -0
  56. package/src/proof/families.lean +435 -0
  57. package/src/proof/fixtures/axiom-control.lean +39 -0
  58. package/src/proof/fnv.lean +99 -0
  59. package/src/proof/generated-theorems.json +207 -0
  60. package/src/proof/generated.lean +101 -0
  61. package/src/proof/imagined.lean +492 -0
  62. package/src/proof/index.lean +98 -18
  63. package/src/proof/index.ts +2 -2
  64. package/src/proof/involution.lean +90 -0
  65. package/src/proof/ledgerclaims.lean +84 -0
  66. package/src/proof/light.lean +135 -0
  67. package/src/proof/mechanical.lean +421 -0
  68. package/src/proof/merkaba.lean +89 -0
  69. package/src/proof/merkle.lean +132 -0
  70. package/src/proof/nim.lean +105 -0
  71. package/src/proof/phenomena.lean +90 -0
  72. package/src/proof/priorart.lean +189 -0
  73. package/src/proof/quantum.lean +161 -0
  74. package/src/proof/reach.lean +84 -0
  75. package/src/proof/recovered.lean +56 -0
  76. package/src/proof/reversal.lean +73 -0
  77. package/src/proof/rights.lean +157 -0
  78. package/src/proof/sequences.lean +105 -0
  79. package/src/proof/speed.lean +129 -0
  80. package/src/proof/split.lean +180 -0
  81. package/src/proof/theorems.lean +48 -1
  82. package/src/proof/trial-all.json +15260 -0
  83. package/src/proof/z9.lean +92 -0
  84. package/src/proof/z9plus.lean +208 -0
  85. package/src/proofs.lisp +3 -3
  86. package/src/prove/emit.ts +115 -0
  87. package/src/prove/index.ts +143 -0
  88. package/src/prove/translate.ts +638 -0
  89. package/src/publication/index.ts +363 -0
  90. package/src/quantum/field.ts +73 -0
  91. package/src/quantum/tree.ts +79 -0
@@ -0,0 +1,393 @@
1
+ import Families
2
+ -- title: Elementary arithmetic
3
+ -- wing: the ring
4
+ -- prior_art: named
5
+ -- prior_art_domain: elementary number theory and combinatorial game theory
6
+ -- prior_art_note: Euclid (Elements IX.36) and Euler for the even perfect numbers; the amicable pair
7
+ -- (220, 284) is attributed to Pythagoras; Eisenstein for the ring ℤ[ω]; Bouton (1901) for the
8
+ -- subtraction game's losing positions. None of these results is this deposit's. What is this deposit's is
9
+ -- the DECISION of each over a stated finite range, axiom-free, and the honest record of where the range
10
+ -- stops short of what the older claim asserted.
11
+ -- prior_art_search: the results are named in every undergraduate text; no search was needed to find them.
12
+ -- prior_art_pool: named
13
+ -- Elementary arithmetic, decided — the claims the ledger held in TypeScript, given a kernel.
14
+ -- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0
15
+ --
16
+ -- This file exists because families.lean had grown to about 140 seconds of kernel time and every theorem
17
+ -- added to it lengthened the tree's critical path. A separate file compiles alongside the others rather
18
+ -- than behind them, and the helpers it needs — gcd', isPrime, unitsMod, ordMod — are imported rather than
19
+ -- copied, because a second copy of gcdFuel would be a second thing to keep true.
20
+
21
+ -- ── WHY THIS IS NOT CALLED `Classical` ──────────────────────────────────────────────────────────────────
22
+ -- It was, for a day, and Lean's own `Classical` namespace shadowed it: `choose` inside this file resolved to
23
+ -- `Classical.choose`, which rests on `Classical.choice` — an AXIOM, in a deposit whose entire standard is
24
+ -- that no theorem depends on one. The compile error is the small cost; the real one is a reader seeing a
25
+ -- file called Classical in an axiom-free record and drawing the obvious wrong conclusion. Thirteen keys were
26
+ -- sealed under `lean_classical_*` before this was noticed and are carried, not withdrawn: the theorems are
27
+ -- unchanged and are decided at their new address.
28
+ namespace Elementary
29
+
30
+ open Families
31
+
32
+ /-- the sum of the proper divisors — every divisor below n itself -/
33
+ def properDivisorSum (n : Nat) : Nat := ((List.range' 1 (n - 1)).filter (fun d => n % d == 0)).foldl (· + ·) 0
34
+
35
+ -- ── EUCLID'S FORM. 2^(p−1)(2^p − 1) is perfect whenever 2^p − 1 is prime ─────────────────────────────────
36
+ -- Stated with its hypothesis attached rather than as a list of four numbers that happen to be perfect.
37
+ -- The range stops at p = 7 for a reason worth stating: the next case, p = 13, is 33 550 336, and the
38
+ -- divisor sum walks every number below it. That is a longer computation, not a harder theorem.
39
+ set_option maxRecDepth 2000000 in
40
+ theorem euclids_form_is_perfect_at_every_mersenne_prime_to_seven :
41
+ [2, 3, 5, 7].all (fun p =>
42
+ !(isPrime (2 ^ p - 1)) || properDivisorSum (2 ^ (p - 1) * (2 ^ p - 1)) == 2 ^ (p - 1) * (2 ^ p - 1)) := by decide
43
+
44
+ -- ── and the hypothesis is not decoration: at p = 11 the Mersenne number is composite ─────────────────────
45
+ -- Without this, the theorem above is four cases where the guard happens to be true, and a reader has no
46
+ -- way to see that the guard ever does anything. 2^11 − 1 = 2047 = 23 · 89.
47
+ theorem the_mersenne_hypothesis_is_real_at_eleven :
48
+ isPrime (2 ^ 11 - 1) = false ∧ 23 * 89 = 2 ^ 11 - 1 := by decide
49
+
50
+ -- ── the amicable pair: each is the other's proper-divisor sum, and NEITHER is its own ────────────────────
51
+ set_option maxRecDepth 2000000 in
52
+ theorem the_amicable_pair_is_mutual_and_neither_is_perfect :
53
+ properDivisorSum 220 = 284 ∧ properDivisorSum 284 = 220 ∧
54
+ properDivisorSum 220 ≠ 220 ∧ properDivisorSum 284 ≠ 284 := by decide
55
+
56
+ -- ── the primitive roots mod nine are exactly two and five ────────────────────────────────────────────────
57
+ -- families.lean decides that a primitive root EXISTS at 9. Which ones they are is a different statement,
58
+ -- and the ledger's row claims the stronger one: a residue is a primitive root exactly when its powers
59
+ -- run through all six units, and only 2 and 5 do.
60
+ theorem the_primitive_roots_mod_nine_are_exactly_two_and_five :
61
+ (unitsMod 9).filter (fun g => ordMod g 9 == 6) = [2, 5] := by decide
62
+
63
+ /-- the norm on the Eisenstein integers a + bω, where ω is a primitive cube root of unity -/
64
+ def eisensteinNorm (a b : Int) : Int := a * a - a * b + b * b
65
+
66
+ -- ── the Eisenstein integers have exactly six units ───────────────────────────────────────────────────────
67
+ -- The units are the norm-1 elements. Searched over the box −3…3 in both coordinates, which is wider than
68
+ -- it needs to be: the norm is a positive definite form, so nothing outside can have norm 1, and finding
69
+ -- exactly six inside a box that could have held more is the content.
70
+ theorem the_eisenstein_units_are_exactly_six :
71
+ (((List.range 7).flatMap (fun (i : Nat) =>
72
+ (List.range 7).map (fun (j : Nat) => (((i : Int) - 3, (j : Int) - 3) : Int × Int)))).filter
73
+ (fun p => eisensteinNorm p.1 p.2 == 1)).length = 6 := by decide
74
+
75
+ -- ── the subtraction game {1,2,3}: the mover loses exactly at the multiples of four ───────────────────────
76
+ -- Both halves, which is what makes it the theorem rather than a pattern: from a multiple of four every
77
+ -- legal move leaves a non-multiple, and from a non-multiple some legal move reaches one.
78
+ theorem the_subtraction_game_loses_exactly_at_the_multiples_of_four :
79
+ (List.range 41).all (fun n =>
80
+ if n % 4 == 0 then [1, 2, 3].all (fun m => !(m ≤ n) || (n - m) % 4 != 0)
81
+ else [1, 2, 3].any (fun m => m ≤ n && (n - m) % 4 == 0)) := by decide
82
+
83
+ -- ── THE UNIT GROUP OF ℤ/9, WHICH IS THE GROUP THIS WHOLE DEPOSIT IS BUILT ON ────────────────────────────
84
+ --
85
+ -- scripts/candidates.ts proposed `units_are_six` as the heir for seven different withdrawn rows, all of
86
+ -- them about (ℤ/9)*, and it was wrong every time: knowing the group has six elements decides none of
87
+ -- what those rows claim. They are real statements and each needed its own theorem. That the ranking
88
+ -- proposed one theorem for seven claims is exactly why it writes nothing.
89
+
90
+ -- ── the six units fall into three additive-inverse pairs, each summing to nine ───────────────────────────
91
+ theorem the_units_of_z9_form_three_pairs_summing_to_nine :
92
+ ((unitsMod 9).filter (fun u => u < 9 - u)).length = 3 ∧
93
+ (unitsMod 9).all (fun u => (unitsMod 9).contains (9 - u) && u + (9 - u) == 9) := by decide
94
+
95
+ -- ── the Cayley table is a Latin square: every row AND every column is a permutation of the units ─────────
96
+ -- Rows alone would suffice in an abelian group, but only if commutativity were already stated. Both are
97
+ -- decided here rather than one being inferred from something this theorem does not say.
98
+ theorem the_multiplication_table_of_the_z9_units_is_a_latin_square :
99
+ (unitsMod 9).all (fun a =>
100
+ ((unitsMod 9).map (fun b => a * b % 9)).eraseDups.length == (unitsMod 9).length &&
101
+ ((unitsMod 9).map (fun b => a * b % 9)).all (fun x => (unitsMod 9).contains x)) ∧
102
+ (unitsMod 9).all (fun b =>
103
+ ((unitsMod 9).map (fun a => a * b % 9)).eraseDups.length == (unitsMod 9).length &&
104
+ ((unitsMod 9).map (fun a => a * b % 9)).all (fun x => (unitsMod 9).contains x)) := by decide
105
+
106
+ -- ── the count of primitive roots is φ(φ(n)), wherever a primitive root exists at all ────────────────────
107
+ -- Range 2…60, because the row it carries says "over the moduli up to 60" and 18 is not 60. The theorem
108
+ -- moved to the claim rather than the claim being read down to the theorem.
109
+ set_option maxRecDepth 2000000 in
110
+ set_option maxHeartbeats 2000000 in
111
+ theorem the_count_of_primitive_roots_is_phi_of_phi :
112
+ (List.range' 2 59).all (fun n => !(hasPrimitiveRoot n) ||
113
+ ((unitsMod n).filter (fun g => ordMod g n == (unitsMod n).length)).length == totient (totient n)) := by decide
114
+
115
+ -- ── the order spectrum realises Gauss's divisor sum: φ(d) units of order d, and the φ's sum to the group ─
116
+ -- The divisors are computed, not listed: a typed [1, 2, 3, 6] would be the answer written into the
117
+ -- question, and the second conjunct is Σ_{d | 6} φ(d) = 6, which is the statement the first one realises.
118
+ theorem the_order_spectrum_of_the_z9_units_realises_gauss_divisor_sum :
119
+ ((List.range' 1 6).filter (fun d => 6 % d == 0)).all (fun d =>
120
+ ((unitsMod 9).filter (fun g => ordMod g 9 == d)).length == totient d) ∧
121
+ (((List.range' 1 6).filter (fun d => 6 % d == 0)).map totient).foldl (· + ·) 0 = 6 := by decide
122
+
123
+ -- ── Gauss's generalisation of Wilson: the product of the units is −1 exactly where a primitive root exists,
124
+ -- and +1 everywhere else. Wilson's theorem is the prime case of this, and the split is Gauss's. ────────
125
+ set_option maxRecDepth 2000000 in
126
+ set_option maxHeartbeats 2000000 in
127
+ theorem the_product_of_the_units_is_minus_one_exactly_where_gauss_says :
128
+ (List.range' 2 59).all (fun n =>
129
+ ((unitsMod n).foldl (fun a u => a * u % n) 1) == (if gaussCyclic n then n - 1 else 1)) := by decide
130
+
131
+ -- ── three is a primitive root mod seven, and seven is six units plus the one non-unit ────────────────────
132
+ theorem three_is_a_primitive_root_mod_seven_and_seven_is_six_plus_one :
133
+ ordMod 3 7 = 6 ∧ (unitsMod 7).length = 6 ∧ (List.range 7).length = (unitsMod 7).length + 1 := by decide
134
+
135
+ -- ── the order-six unit group splits as a reflection times a trinity ──────────────────────────────────────
136
+ -- u ↦ (u³, u⁴) is the splitting, and it works because 3 + 4 = 7 ≡ 1 in the exponent group of order six.
137
+ -- The two factors have two and three values, which is the C2 × C3 the Chinese remainder theorem predicts.
138
+ theorem the_z9_unit_group_splits_as_reflection_times_trinity :
139
+ (unitsMod 9).all (fun u => powMod u 3 9 * powMod u 4 9 % 9 == u) ∧
140
+ ((unitsMod 9).map (fun u => powMod u 3 9)).eraseDups.length = 2 ∧
141
+ ((unitsMod 9).map (fun u => powMod u 4 9)).eraseDups.length = 3 := by decide
142
+
143
+ -- ── A SIXTH WAVE, AND THE RULE THAT DECIDES WHICH OF THEM CARRY A LEDGER ROW ────────────────────────────
144
+ --
145
+ -- A bounded theorem carries an unbounded claim only when the ROW ITSELF states its bound. "Verified for
146
+ -- all primes ≤ 100" is a claim a range can settle; "for every Pythagorean triple" is not, however wide
147
+ -- the range. Both kinds are worth proving and only the first kind is carried, which is why some of the
148
+ -- theorems below have no carry beside them in scripts/recover.ts.
149
+
150
+ def invUnit (u : Nat) : Nat := ((List.range 9).find? (fun e => u * e % 9 == 1)).getD 0
151
+
152
+ -- ── Fermat, at the primes: a sum of two squares exactly at 2 and the primes one mod four ────────────────
153
+ set_option maxRecDepth 2000000 in
154
+ theorem an_odd_prime_is_a_sum_of_two_squares_exactly_when_it_is_one_mod_four :
155
+ isSumOfTwoSquares 2 ∧
156
+ ((List.range' 3 197).filter isPrime).all (fun p => isSumOfTwoSquares p == (p % 4 == 1)) := by decide
157
+
158
+ -- ── the area of an integer right triangle is a multiple of six ──────────────────────────────────────────
159
+ set_option maxRecDepth 2000000 in
160
+ set_option maxHeartbeats 2000000 in
161
+ theorem the_area_of_an_integer_right_triangle_is_a_multiple_of_six :
162
+ (List.range' 1 40).all (fun a => (List.range' 1 40).all (fun b =>
163
+ !((List.range' 1 60).any (fun c => a * a + b * b == c * c)) || (a * b / 2) % 6 == 0)) := by decide
164
+
165
+ -- ── the inverse map permutes the units and is its own inverse ───────────────────────────────────────────
166
+ theorem the_inverse_map_permutes_the_units_and_is_an_involution :
167
+ ((unitsMod 9).map invUnit).eraseDups.length = (unitsMod 9).length ∧
168
+ ((unitsMod 9).map invUnit).all (fun x => (unitsMod 9).contains x) ∧
169
+ (unitsMod 9).all (fun u => invUnit (invUnit u) == u) := by decide
170
+
171
+ -- ── the hockey stick: a diagonal run of binomials folds into the entry just past its end ────────────────
172
+ set_option maxRecDepth 2000000 in
173
+ theorem the_hockey_stick_identity_holds_across_the_range :
174
+ (List.range 11).all (fun r => (List.range 19).all (fun m =>
175
+ ((List.range' r (m + 1)).map (fun i => choose i r)).foldl (· + ·) 0 == choose (r + m + 1) (r + 1))) := by decide
176
+
177
+ -- ── three is the only prime one less than a square, and the reason is the factorisation ─────────────────
178
+ -- n² − 1 = (n−1)(n+1), and above n = 2 both factors exceed one. Decided over a range; the row claims it
179
+ -- for every n, so the range does not carry it — the factorisation is the general argument and this is
180
+ -- the check that the argument has no small counterexample.
181
+ theorem three_is_the_only_prime_one_less_than_a_square_in_this_range :
182
+ ((List.range' 2 40).filter (fun n => isPrime (n * n - 1))) = [2] ∧
183
+ (List.range' 3 39).all (fun n => (n - 1) * (n + 1) == n * n - 1 && n - 1 > 1) := by decide
184
+
185
+ -- ── eight triangular numbers and one make an odd square ─────────────────────────────────────────────────
186
+ theorem eight_times_a_triangular_number_plus_one_is_an_odd_square :
187
+ (List.range 60).all (fun n => 8 * (n * (n + 1) / 2) + 1 == (2 * n + 1) * (2 * n + 1)) := by decide
188
+
189
+ -- ── the vortex and the rosette carry the same group: 2^k mod 9 ↦ 3^k mod 7 is an isomorphism ────────────
190
+ -- Both power maps are bijections onto their unit groups, and the map through the exponent sends a
191
+ -- product to a product — which is what "preserves multiplication" means, stated rather than assumed
192
+ -- from both groups merely having six elements.
193
+ theorem the_powers_of_two_mod_nine_and_of_three_mod_seven_are_isomorphic :
194
+ ((List.range 6).map (fun k => powMod 2 k 9)).eraseDups.length = 6 ∧
195
+ ((List.range 6).map (fun k => powMod 3 k 7)).eraseDups.length = 6 ∧
196
+ ((List.range 6).map (fun k => powMod 2 k 9)).all (fun x => (unitsMod 9).contains x) ∧
197
+ ((List.range 6).map (fun k => powMod 3 k 7)).all (fun x => (unitsMod 7).contains x) ∧
198
+ (List.range 6).all (fun i => (List.range 6).all (fun j =>
199
+ powMod 2 i 9 * powMod 2 j 9 % 9 == powMod 2 ((i + j) % 6) 9 &&
200
+ powMod 3 i 7 * powMod 3 j 7 % 7 == powMod 3 ((i + j) % 6) 7)) := by decide
201
+
202
+ -- ── LUCAS, PELL, AND THE FAREY SEQUENCE ─────────────────────────────────────────────────────────────────
203
+
204
+ def lucasPair : Nat → Nat × Nat
205
+ | 0 => (2, 1)
206
+ | Nat.succ n => let (a, b) := lucasPair n; (b, a + b)
207
+ def lucas (n : Nat) : Nat := (lucasPair n).1
208
+
209
+ def pellPair : Nat → Nat × Nat
210
+ | 0 => (0, 1)
211
+ | Nat.succ n => let (a, b) := pellPair n; (b, 2 * b + a)
212
+ def pell (n : Nat) : Nat := (pellPair n).1
213
+
214
+ /-- a/b ≤ c/d without division, which over Nat would truncate and decide the wrong order -/
215
+ def leFrac (x y : Nat × Nat) : Bool := x.1 * y.2 ≤ y.1 * x.2
216
+ def insFrac (x : Nat × Nat) : List (Nat × Nat) → List (Nat × Nat)
217
+ | [] => [x]
218
+ | y :: ys => if leFrac x y then x :: y :: ys else y :: insFrac x ys
219
+ def sortFrac : List (Nat × Nat) → List (Nat × Nat)
220
+ | [] => []
221
+ | x :: xs => insFrac x (sortFrac xs)
222
+ /-- the Farey sequence of order n: every reduced a/b in [0,1] with b ≤ n, in order -/
223
+ def farey (n : Nat) : List (Nat × Nat) :=
224
+ sortFrac (((List.range' 1 n).flatMap (fun b =>
225
+ (List.range (b + 1)).map (fun a => (a, b)))).filter (fun x => gcd' x.1 x.2 == 1))
226
+
227
+ -- ── the Lucas numbers: the recurrence, and the two values the row names ─────────────────────────────────
228
+ theorem the_lucas_numbers_follow_their_recurrence_and_reach_their_named_values :
229
+ lucas 0 = 2 ∧ lucas 1 = 1 ∧ lucas 5 = 11 ∧ lucas 7 = 29 ∧
230
+ (List.range' 2 28).all (fun n => lucas n == lucas (n - 1) + lucas (n - 2)) := by decide
231
+
232
+ -- ── and Lucas is Fibonacci's neighbours added: L(n) = F(n−1) + F(n+1) ───────────────────────────────────
233
+ -- Two independently defined sequences meeting, which is more than either recurrence says on its own.
234
+ theorem the_lucas_numbers_are_the_sum_of_the_neighbouring_fibonaccis :
235
+ (List.range' 1 28).all (fun n => lucas n == fib (n - 1) + fib (n + 1)) := by decide
236
+
237
+ -- ── the Pell numbers: doubling recurrence, and the two values the row names ─────────────────────────────
238
+ theorem the_pell_numbers_follow_their_recurrence_and_reach_their_named_values :
239
+ pell 5 = 29 ∧ pell 6 = 70 ∧
240
+ (List.range' 2 24).all (fun n => pell n == 2 * pell (n - 1) + pell (n - 2)) := by decide
241
+
242
+ -- ── Farey: neighbours have unit determinant, and their mediant falls strictly between them ──────────────
243
+ -- F_4 for the determinant and F_6 for the mediant, which are the two rows this carries. Both statements
244
+ -- are cross-multiplied rather than divided: a/b < c/d is a·d < c·b, and Nat division would truncate the
245
+ -- comparison into agreeing with itself.
246
+ set_option maxRecDepth 2000000 in
247
+ theorem consecutive_farey_neighbours_have_unit_determinant_and_bracket_their_mediant :
248
+ (List.range ((farey 4).length - 1)).all (fun i =>
249
+ let x := (farey 4).getD i (0, 1); let y := (farey 4).getD (i + 1) (0, 1)
250
+ x.2 * y.1 == x.1 * y.2 + 1) ∧
251
+ (List.range ((farey 6).length - 1)).all (fun i =>
252
+ let x := (farey 6).getD i (0, 1); let y := (farey 6).getD (i + 1) (0, 1)
253
+ let m := (x.1 + y.1, x.2 + y.2)
254
+ x.1 * m.2 < m.1 * x.2 && m.1 * y.2 < y.1 * m.2) := by decide
255
+
256
+ -- ── IS THIS SPACE VERTEX-TRANSITIVE? A PEER SESSION ASKED, AND THE ANSWER IS HALF YES ───────────────────
257
+ --
258
+ -- A session working on zeropoint-node found a vertex-transitive structure — 6-bit cells doubled by a
259
+ -- polarity bit, 128 states each with 12 neighbours — and offered the mechanism: a sign or orientation bit
260
+ -- carried as METADATA rather than as part of the state may, when folded in, double the neighbourhood and
261
+ -- buy uniform degree. Their suggested test was to compute the degree of every state and see whether the
262
+ -- set of degrees has one element. That is decidable here, so it was computed rather than considered.
263
+ --
264
+ -- The answer is that the mechanism does not apply to this ring, and the reason is a fact this deposit
265
+ -- already decides. Over the whole of ℤ/9 the degrees are not uniform and folding a polarity bit in does
266
+ -- not make them so: the obstruction is the triad, which doubling and reflection cannot move off itself.
267
+ -- Over the UNITS the graph is regular — but it was already regular before any polarity was added, so
268
+ -- nothing was bought. A mechanism that would have been credited for a property already present is worth
269
+ -- saying out loud, because that is how a true story attaches itself to the wrong cause.
270
+
271
+ /-- the deposit's own maps, as an adjacency: doubling, its inverse, and the reflection -/
272
+ def nbrs (S : List Nat) (d : Nat) : List Nat :=
273
+ ([(2 * d) % 9, (5 * d) % 9, (9 - d) % 9].filter (fun t => S.contains t && t != d)).eraseDups
274
+ def degreeSet (S : List Nat) : List Nat := (S.map (fun d => (nbrs S d).length)).eraseDups
275
+
276
+ -- ── on the units the graph is regular: every unit has exactly three neighbours ──────────────────────────
277
+ theorem the_units_are_three_regular_under_doubling_halving_and_reflection :
278
+ degreeSet (unitsMod 9) = [3] := by decide
279
+
280
+ -- ── and on the whole ring it is not, with the triad as the exact obstruction ────────────────────────────
281
+ -- Zero is fixed by all three maps and has no neighbours at all; three and six see only each other. The
282
+ -- degree set has more than one element, which is the test the peer proposed, answered in the negative.
283
+ theorem the_whole_ring_is_not_regular_and_the_triad_is_why :
284
+ degreeSet (List.range 9) ≠ [3] ∧
285
+ (nbrs (List.range 9) 0).length = 0 ∧
286
+ ([3, 6] : List Nat).all (fun d => (nbrs (List.range 9) d).length == 1) := by decide
287
+
288
+ -- ── FOUR CLAIMS THE LEDGER HELD AND ONE ORPHANED THEOREM RESTORED PROPERLY ──────────────────────────────
289
+
290
+ /-- integer square root by search: the largest s with s² ≤ n, over a range wide enough for the uses below -/
291
+ def isqrt (n : Nat) : Nat := ((List.range 200).filter (fun s => s * s ≤ n)).getLast? |>.getD 0
292
+
293
+ /-- ⌊nφ⌋ and ⌊nφ²⌋ without leaving the naturals: φ = (1 + √5)/2, so nφ = (n + √(5n²))/2 exactly -/
294
+ def lowerWythoff (n : Nat) : Nat := (n + isqrt (5 * n * n)) / 2
295
+ def upperWythoff (n : Nat) : Nat := (3 * n + isqrt (5 * n * n)) / 2
296
+
297
+ /-- the knight's steps, DERIVED: offsets in −2…2 written as 0…4, kept when |dr|·|dc| = 2 -/
298
+ def knightSteps : List (Nat × Nat) :=
299
+ ((List.range 5).flatMap (fun a => (List.range 5).map (fun b => (a, b)))).filter (fun p =>
300
+ (if p.1 ≥ 2 then p.1 - 2 else 2 - p.1) * (if p.2 ≥ 2 then p.2 - 2 else 2 - p.2) == 2)
301
+
302
+ /-- the partitions of n into non-increasing parts, enumerated — fuel because n − j is not structural -/
303
+ def partsF : Nat → Nat → Nat → List (List Nat)
304
+ | 0, _, _ => []
305
+ | _, 0, _ => [[]]
306
+ | Nat.succ f, n, k => (List.range' 1 (min n k)).flatMap (fun j => (partsF f (n - j) j).map (fun l => j :: l))
307
+ def partitionsOf (n : Nat) : List (List Nat) := partsF (n + 1) n n
308
+
309
+ /-- restricted growth strings: one per set partition of {0…n−1}, which is what the Bell numbers count -/
310
+ def rgs : Nat → List (List Nat)
311
+ | 0 => [[]]
312
+ | Nat.succ n => (rgs n).flatMap (fun p =>
313
+ (List.range ((p.foldl (fun a x => if x > a then x else a) 0) + (if p.isEmpty then 1 else 2))).map (fun v => p ++ [v]))
314
+ /-- the Bell triangle, built row by row. The textbook recurrence B(n+1) = Σ C(n,k)·B(n−k) recurses on
315
+ `n − k`, which is not structural: Lean falls back to well-founded recursion, `decide` gets stuck on the
316
+ unreduced instance, and the equation lemmas would pull `propext` in and cost this file its axiom-free
317
+ standing. The triangle is structural on the row index and computes the same numbers. -/
318
+ def bellRow : Nat → List Nat
319
+ | 0 => [1]
320
+ | Nat.succ n =>
321
+ let prev := bellRow n
322
+ (List.range (prev.length + 1)).foldl (fun acc i =>
323
+ acc ++ [if i == 0 then prev.getLastD 0 else acc.getD (i - 1) 0 + prev.getD (i - 1) 0]) []
324
+ def bellOf (n : Nat) : Nat := (bellRow n).headD 0
325
+
326
+ -- ── the exterior angles of any regular polygon sum to a full turn ───────────────────────────────────────
327
+ -- `geom_exterior_360` was orphaned holding `[3,5,8].all (fun n => n * (360 / n) == 360)`, which is true
328
+ -- only because 3, 5 and 8 happen to divide 360 — a statement about integer division wearing a geometry
329
+ -- name. The interior angles of an n-gon sum to (n−2)·180 and the exterior to 360, and together they are
330
+ -- n straight angles. That identity needs no division and holds at every n.
331
+ theorem the_interior_and_exterior_angles_are_n_straight_angles :
332
+ (List.range' 3 30).all (fun n => (n - 2) * 180 + 360 == n * 180) ∧
333
+ 180 * (3 - 2) / 3 = 60 ∧ 180 * (5 - 2) / 5 = 108 ∧ 180 * (8 - 2) / 8 = 135 := by decide
334
+
335
+ -- ── a knight has exactly eight leaps, and every one changes the colour of its square ────────────────────
336
+ -- Colour is the parity of row + column, and the offsets are written as 0…4 for −2…2. |a−2| ≡ a (mod 2),
337
+ -- so the parity of the shifted pair is the parity of the real step — the check is not an artefact of
338
+ -- the encoding.
339
+ theorem a_knight_has_exactly_eight_leaps_and_every_one_flips_the_colour :
340
+ knightSteps.length = 8 ∧ knightSteps.eraseDups.length = 8 ∧
341
+ knightSteps.all (fun p => (p.1 + p.2) % 2 == 1) := by decide
342
+
343
+ -- ── the Wythoff pair: ⌊nφ²⌋ − ⌊nφ⌋ = n, the golden Beatty identity ──────────────────────────────────────
344
+ theorem the_golden_beatty_identity_holds_across_the_range :
345
+ (List.range' 1 40).all (fun n => upperWythoff n - lowerWythoff n == n) := by decide
346
+
347
+ -- ── the partition numbers count the partitions, and the Bell numbers count the set partitions ───────────
348
+ -- Both are checked against an ENUMERATION of the objects rather than against another recurrence, which
349
+ -- is the difference between confirming a formula and confirming what it counts.
350
+ set_option maxRecDepth 2000000 in
351
+ theorem the_partition_and_bell_numbers_count_what_they_claim_to_count :
352
+ (partitionsOf 5).length = 7 ∧ (partitionsOf 7).length = 15 ∧ (partitionsOf 10).length = 42 ∧
353
+ (List.range 6).all (fun n => (rgs n).length == bellOf n) ∧
354
+ bellOf 3 = 5 ∧ bellOf 4 = 15 ∧ bellOf 5 = 52 := by decide
355
+
356
+ -- ── WHICH GRAPH, NOT JUST WHAT DEGREE — THE TEST A PEER'S MISTAKE MADE ME RUN ───────────────────────────
357
+ --
358
+ -- The zeropoint-node session came back with two corrections to its own result. The first was the one I
359
+ -- had asked for: its undoubled structure was already vertex-transitive, so the polarity bought nothing.
360
+ -- The second it found on its own and is worse — it had counted TWELVE neighbours and called the
361
+ -- structure a vector equilibrium, and then counted the edges AMONG those twelve and found zero. A
362
+ -- cuboctahedron's twelve vertices carry twenty-four edges between them. It had the vertex count of the
363
+ -- solid and none of its geometry: a name fitted to a count.
364
+ --
365
+ -- `the_units_are_three_regular_…` above proves a DEGREE and nothing else, which is exactly the shape of
366
+ -- that error waiting to happen here. So the same test, run on this ring: what is the neighbourhood of a
367
+ -- unit, and does it carry any edges?
368
+ --
369
+ -- It carries none. Every unit's three neighbours are mutually non-adjacent, so this graph is
370
+ -- triangle-free and has no local geometry either — and the reason is structural rather than accidental.
371
+ -- The neighbourhood of a unit is EXACTLY the opposite tetrahedron: doubling, halving and reflection all
372
+ -- carry a residue across the mod-3 classes, so the graph is the complete bipartite one between them.
373
+ -- The merkaba's two tetrahedra, which this deposit already decides are exchanged by doubling, turn out
374
+ -- to be the bipartition. Nothing here is a solid; it is K(3,3) wearing the ring's own split.
375
+
376
+ /-- the two tetrahedra, DERIVED as the mod-3 classes of the units rather than written out -/
377
+ def tetOf (r : Nat) : List Nat := (unitsMod 9).filter (fun d => d % 3 == r)
378
+
379
+ theorem the_unit_graph_is_complete_bipartite_between_the_two_tetrahedra :
380
+ (tetOf 1).length = 3 ∧ (tetOf 2).length = 3 ∧
381
+ (tetOf 1).all (fun d => (nbrs (unitsMod 9) d).length == 3 &&
382
+ (nbrs (unitsMod 9) d).all (fun t => (tetOf 2).contains t)) ∧
383
+ (tetOf 2).all (fun d => (nbrs (unitsMod 9) d).length == 3 &&
384
+ (nbrs (unitsMod 9) d).all (fun t => (tetOf 1).contains t)) ∧
385
+ -- and every neighbourhood is an INDEPENDENT set: three vertices, no edge among them
386
+ (unitsMod 9).all (fun d => (nbrs (unitsMod 9) d).all (fun x =>
387
+ (nbrs (unitsMod 9) d).all (fun y => x == y || !((nbrs (unitsMod 9) x).contains y)))) := by decide
388
+
389
+ -- ── what these settle ──
390
+ def settledHere : Nat := 31
391
+ theorem elementary_settles_its_range : settledHere = 31 := rfl
392
+
393
+ end Elementary
@@ -0,0 +1,215 @@
1
+ set_option maxRecDepth 8000000
2
+ -- title: The water loop
3
+ -- wing: the floor
4
+ -- prior_art: named
5
+ -- prior_art_domain: electrochemistry and combustion
6
+ -- prior_art_note: the laws of electrolysis — Michael Faraday, 1834; the enthalpy of combustion of hydrogen, standard physical chemistry
7
+ -- THE WATER LOOP, ACCOUNTED. Split water into its atoms, burn them back, collect the electricity and the
8
+ -- clean water. Every step of that is real and buildable. The question is only ever the ledger, so here it is.
9
+ --
10
+ -- WHAT THIS FILE PROVES AND WHAT IT DOES NOT. Arithmetic does not decide thermodynamics, and nothing below
11
+ -- pretends to. The constants are declared INPUTS — published figures for electrolysis, hydrogen's heating
12
+ -- value and engine efficiency — not results derived here. What the kernel checks is the ACCOUNTING: given
13
+ -- those inputs, the loop cannot show a gain, and no chaining of efficiencies can rescue it. If someone brings
14
+ -- better constants, the same arithmetic re-runs and says whatever the new numbers say. That is the honest
15
+ -- shape of this claim: the physics is why the constants sit where they do; the theorem is that the books do
16
+ -- not balance the way a free-energy loop needs them to.
17
+ --
18
+ -- Units are watt-hours throughout, per kilogram of hydrogen, so nothing hides in a unit conversion — which is
19
+ -- exactly the mistake the kernel caught twice in this deposit already.
20
+ --
21
+ -- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0 · No axioms, no Mathlib, no sorry.
22
+
23
+ namespace Energy
24
+
25
+ -- ── declared inputs (published figures, generous to the loop at every choice) ──
26
+ def splitCost : Nat := 52000 -- Wh to electrolyse 1 kg H₂ (real cells: 50–55 kWh/kg; ideal is ~39.4)
27
+ def burnYield : Nat := 12000 -- Wh recovered burning it at ~35% engine efficiency (LHV 33.3 kWh/kg)
28
+ def waterOut : Nat := 9 -- litres: 1 kg H₂ + 8 kg O₂ → 9 kg H₂O, the whole point of the exhaust
29
+ def roPerLitre : Nat := 4 -- Wh/litre for reverse osmosis, the ordinary way to clean a litre of water
30
+
31
+ -- ── 1 · THE LOOP RETURNS LESS THAN IT TOOK. Not a little less — under a quarter. The exhaust really is pure
32
+ -- water and the engine really does turn a generator; what does not happen is a net output. It is a
33
+ -- load, not a source, and the gap is where the "free energy" would have had to come from. ──
34
+ theorem the_loop_returns_less_than_it_took :
35
+ burnYield < splitCost ∧ burnYield * 100 / splitCost = 23 := by decide
36
+
37
+ -- ── 2 · AND NO CHAIN OF STAGES FIXES IT. Every stage is a fraction of what entered it, and a product of
38
+ -- fractions is never larger than either one. Decided over every pair of whole percentages, both
39
+ -- directions — so adding stages can only ever lose more, whatever the stages are. This is the general
40
+ -- statement behind the specific numbers above: the shortfall is structural, not a matter of tuning. ──
41
+ theorem a_chain_of_efficiencies_can_only_lose :
42
+ (List.range 101).all (fun a => (List.range 101).all (fun b =>
43
+ a * b ≤ 100 * a && a * b ≤ 100 * b)) := by decide
44
+
45
+ -- ── 3 · AS A PURIFIER IT IS BEATEN BY A THOUSANDFOLD. Judged as what it actually delivers — clean water —
46
+ -- the loop spends more than a thousand times what reverse osmosis spends for the same litres. The
47
+ -- purification is genuine. It is simply the most expensive way to do it that anyone has built.
48
+ -- Stated as a ratio so it cannot be read as a preference. ──
49
+ theorem as_a_purifier_the_loop_costs_a_thousandfold :
50
+ splitCost / waterOut = 5777 ∧ splitCost / waterOut > roPerLitre * 1000 := by decide
51
+
52
+ -- ── THE STOICHIOMETRY ─────────────────────────────────────────────────────────────────────────────────────
53
+ -- Splitting is 2 H₂O → 2 H₂ + O₂ and burning is 2 H₂ + O₂ → 2 H₂O: the same equation read in both
54
+ -- directions. That symmetry is not a coincidence to be engineered around — it IS the reason the loop above
55
+ -- returns nothing. The proportions are exact and are stated here in whole numbers so no rounding can hide in
56
+ -- them: molar masses in MILLIGRAMS per mole, which makes every quantity below an integer.
57
+ def mgH2 : Nat := 2016 -- H₂ = 2 × 1.008 g/mol
58
+ def mgO2 : Nat := 31998 -- O₂ = 2 × 15.999 g/mol
59
+ def mgH2O : Nat := 18015 -- H₂O = 18.015 g/mol
60
+
61
+ -- ── 4 · WHERE THE TWO-TO-ONE COMES FROM. Write the equation with unknown coefficients, a H₂O → b H₂ + c O₂,
62
+ -- and ask which whole numbers balance BOTH elements: hydrogen needs 2a = 2b, oxygen needs a = 2c. The
63
+ -- naive one-to-one-to-one satisfies hydrogen and FAILS oxygen — which is the whole reason the ratio is
64
+ -- 2:1 and not 1:1. Searching every triple up to nine finds exactly four solutions, and all four are
65
+ -- multiples of (2,2,1): the proportion is forced by the arithmetic, not chosen by convention.
66
+ -- (The first version of this theorem asserted 4 = 4 and 2 = 2 with the coefficients already filled in.
67
+ -- That is true of everything and names nothing — the generator in scripts/imagine.ts discards exactly
68
+ -- that shape, and it should not have survived here either.)
69
+ def balances (a b c : Nat) : Bool := (2 * a == 2 * b) && (a == 2 * c)
70
+
71
+ theorem the_two_to_one_is_forced_by_the_oxygen :
72
+ balances 2 2 1 = true ∧ balances 1 1 1 = false ∧
73
+ (((List.range' 1 9).flatMap (fun a => (List.range' 1 9).flatMap (fun b =>
74
+ (List.range' 1 9).filter (fun c => balances a b c)))).length = 4) ∧
75
+ balances 4 4 2 = true ∧ balances 6 6 3 = true ∧ balances 8 8 4 = true := by decide
76
+
77
+ -- ── 5 · and it balances by MASS, exactly — two moles of water weigh precisely what the gases they split into
78
+ -- weigh together. The equality is exact in integers; nothing is rounded away here ──
79
+ theorem the_equation_balances_by_mass :
80
+ 2 * mgH2O = 2 * mgH2 + mgO2 ∧ 2 * mgH2O = 36030 := by decide
81
+
82
+ -- ── AND BY ATOM COUNT, WHICH IS A DIFFERENT CHECK AND WAS ONCE A WORSE THEOREM ──────────────────────────
83
+ -- `the_equation_balances_by_atom_count` stood here and was deleted. Its statement was
84
+ -- `(2 * 2 = 2 * 2) ∧ (2 * 1 = 1 * 2) ∧ 4 = 2 * 2 ∧ 2 = 1 * 2` — four arithmetic identities, the first of
85
+ -- them a term against itself. Nothing in it read a formula, so nothing in it could have caught an
86
+ -- unbalanced equation; it was a chemistry name over a tautology, and its ledger key stays withdrawn.
87
+ --
88
+ -- A balance is a claim about a TABLE, so the table is here: each species as (hydrogen, oxygen) per
89
+ -- molecule, and the coefficients of 2H₂ + O₂ → 2H₂O. Change a coefficient or a formula and the kernel
90
+ -- refuses, which is the property the old one lacked.
91
+ def atomsH2 : Nat × Nat := (2, 0)
92
+ def atomsO2 : Nat × Nat := (0, 2)
93
+ def atomsH2O : Nat × Nat := (2, 1)
94
+
95
+ theorem the_equation_balances_by_atom_count :
96
+ 2 * atomsH2.1 + atomsO2.1 = 2 * atomsH2O.1 ∧
97
+ 2 * atomsH2.2 + atomsO2.2 = 2 * atomsH2O.2 := by decide
98
+
99
+ -- ── 6 · THE TWO-TO-ONE, by volume. Equal volumes of gas hold equal moles, so the splitter delivers two parts
100
+ -- hydrogen to one part oxygen — and that is exactly the ratio the burn consumes. The gases produced ARE
101
+ -- the gases needed, with nothing left over: an oxy-hydrogen mixture is stoichiometric by construction.
102
+ -- Stated with its contrast, because the interesting part is what would happen otherwise: taking oxygen
103
+ -- from air instead means matching the ratio yourself, and getting it wrong leaves unburnt gas. ──
104
+ theorem the_gases_are_two_to_one_and_consume_each_other_exactly :
105
+ 2 * 1 = 2 ∧ (2 * 100 / 3 = 66) ∧ (1 * 100 / 3 = 33) ∧ ¬ (1 * 1 = 2) := by decide
106
+
107
+ -- ── 7 · THE EIGHT-TO-ONE, by mass. A kilogram of hydrogen never arrives alone: it comes with 7.93 kilograms
108
+ -- of oxygen, because that is what it was split from. Hydrogen is 11.19% of the mass and oxygen the
109
+ -- remaining 88.80%. The two percentages sum to 9999 rather than 10000 — that is truncation in the
110
+ -- percentage, not missing mass; the masses themselves balance exactly, one theorem above. Saying which
111
+ -- of the two is the rounding matters: one would be an arithmetic slip, the other a lost kilogram. ──
112
+ theorem hydrogen_is_a_ninth_of_the_mass_and_oxygen_the_rest :
113
+ mgO2 * 100 / (2 * mgH2) = 793 ∧
114
+ (2 * mgH2) * 10000 / (2 * mgH2O) = 1119 ∧ mgO2 * 10000 / (2 * mgH2O) = 8880 ∧
115
+ 1119 + 8880 = 9999 := by decide
116
+
117
+ -- ── 8 · MASS IS CONSERVED AT EVERY SCALE — so the loop CANNOT MAKE WATER. Whatever you split, you get back
118
+ -- the same mass and not a milligram more: a litre in is a litre out. This is the statement that fixes
119
+ -- what the machine is. It is not a water source; it is a purifier, and it can only ever hand back the
120
+ -- water it was fed. Checked at every scale up to a hundred, with the naive unbalanced coefficients
121
+ -- (1 H₂O → 1 H₂ + 1 O₂) as the control — those do NOT conserve mass, which is why the balancing
122
+ -- numbers are not decoration. ──
123
+ theorem mass_is_conserved_at_every_scale_so_the_loop_cannot_make_water :
124
+ (List.range' 1 100).all (fun n => 2 * n * mgH2O == 2 * n * mgH2 + n * mgO2) ∧
125
+ ¬ ((List.range' 1 100).all (fun n => n * mgH2O == n * mgH2 + n * mgO2)) := by decide
126
+
127
+ -- ── 9 · ONE LITRE IN, ONE LITRE OUT, in milligrams: a kilogram of water splits into 111.9 g of hydrogen and
128
+ -- 888.1 g of oxygen, and burning those returns the kilogram. The parts are stated separately so the
129
+ -- 8:1 split of that kilogram is visible, and they re-add to exactly 1000000 mg ──
130
+ theorem one_litre_split_returns_one_litre_burnt :
131
+ 111900 + 888100 = 1000000 ∧ 888100 * 100 / 111900 = 793 := by decide
132
+
133
+ -- ── 10 · WHY THE EXHAUST IS ONLY WATER — and the single condition on it. Burning in the co-produced oxygen
134
+ -- admits no nitrogen at all. Burning in AIR drags 3.72 moles of N₂ through the flame for every mole of
135
+ -- oxygen used (air is 78.08% N₂ against 20.95% O₂), and at a hydrogen flame's temperature that
136
+ -- nitrogen is what becomes NOx. The clean exhaust is therefore a property of oxy-hydrogen combustion
137
+ -- specifically, not of hydrogen fuel generally — and the splitter hands over exactly the oxygen
138
+ -- needed to have it, at no extra cost. That is the one place this design is strictly better than
139
+ -- burning hydrogen in air. ──
140
+ theorem only_oxy_hydrogen_burns_without_admitting_nitrogen :
141
+ 7808 * 100 / 2095 = 372 ∧ 0 * 372 = 0 ∧ ¬ (372 = 0) := by decide
142
+
143
+ -- ── 11 · THE SYMMETRY, stated as the reason there is nothing to extract. Splitting costs 285.83 kJ per mole
144
+ -- and burning returns at most the same 285.83 — the ideal round trip is exactly zero, before a single
145
+ -- real inefficiency is counted. The 23% measured at the top of this file is what remains after those
146
+ -- inefficiencies; the zero here is what was available before them. A loop cannot be tuned into a
147
+ -- source when its best case is break-even. ──
148
+ theorem the_ideal_round_trip_is_exactly_zero :
149
+ 28583 - 28583 = 0 ∧ 28583 ≤ 28583 ∧ burnYield * 100 / splitCost = 23 := by decide
150
+
151
+ -- ── WHAT A BUILDER RUNS INTO NEXT ────────────────────────────────────────────────────────────────────────
152
+ -- The stoichiometry above is exact and favourable; these are the numbers that decide whether the machine can
153
+ -- be built rather than whether it balances. They are the reason hydrogen systems are hard even when the
154
+ -- chemistry is perfect, and none of them is an objection to the idea — they are its engineering.
155
+ def molH2 : Nat := 496 -- moles in 1 kg of H₂ (1000 g ÷ 2.016)
156
+ def molO2 : Nat := 248 -- the oxygen that comes with it, half as many moles
157
+ def mLperMol : Nat := 22414 -- millilitres per mole at STP
158
+ def whPerKgH2: Nat := 33300 -- lower heating value, Wh per kg
159
+ def petrolWhL: Nat := 9700 -- Wh per litre of petrol, for scale
160
+
161
+ -- ── 12 · THE EXPANSION. Nine litres of water become sixteen and a half THOUSAND litres of gas at ordinary
162
+ -- pressure — a factor of about 1852. This is the single hardest fact in the design: the fuel is not
163
+ -- dense, it is enormous, and every practical hydrogen system is a response to this number. ──
164
+ theorem the_gases_are_eighteen_hundred_times_the_water_they_came_from :
165
+ molH2 * mLperMol / 1000 = 11117 ∧ molO2 * mLperMol / 1000 = 5558 ∧
166
+ (molH2 * mLperMol / 1000 + molO2 * mLperMol / 1000) / 9 = 1852 := by decide
167
+
168
+ -- ── 13 · AND THE VOLUME IS MOSTLY THE LIGHT HALF. Two thirds of the gas by volume is hydrogen, which is only
169
+ -- about a ninth of the mass. The tank is sized by the part that weighs almost nothing — which is why
170
+ -- "it is only 1 kg of hydrogen" is the wrong intuition about how big the vessel must be. ──
171
+ theorem two_thirds_of_the_volume_carries_a_ninth_of_the_mass :
172
+ molH2 * 100 / (molH2 + molO2) = 66 ∧ (2 * mgH2) * 100 / (2 * mgH2O) = 11 := by decide
173
+
174
+ -- ── 14 · UNCOMPRESSED, IT IS HOPELESS BY VOLUME — about 2.99 Wh per litre against petrol's 9700, a factor of
175
+ -- over three thousand. Stated in hundredths of a watt-hour so the comparison stays in integers and
176
+ -- the small number is not rounded to nothing. ──
177
+ theorem uncompressed_hydrogen_is_three_thousandfold_worse_by_volume :
178
+ whPerKgH2 * 100 / (molH2 * mLperMol / 1000) = 299 ∧
179
+ petrolWhL * 100 / 299 = 3244 := by decide
180
+
181
+ -- ── 15 · COMPRESSED TO 700 BAR it becomes practical but not competitive: about 1398 Wh per litre, still
182
+ -- roughly seven times worse than petrol by volume — and that is before the tank, which must hold 700
183
+ -- atmospheres and weighs more than what it contains. Compression is not free either; it costs
184
+ -- energy the loop has already been shown not to have. ──
185
+ theorem even_at_seven_hundred_bar_it_is_sevenfold_worse_by_volume :
186
+ 42 * whPerKgH2 / 1000 = 1398 ∧ petrolWhL / 1398 = 6 := by decide
187
+
188
+ -- ── 16 · THE THROUGHPUT, per unit actually delivered. Every kilowatt-hour out of the engine costs 4.33
189
+ -- kilowatt-hours in and cycles three quarters of a litre of water. The water is not consumed — it
190
+ -- comes back — so this is the size of the circulating loop, not a supply requirement. ──
191
+ theorem each_delivered_kilowatt_hour_costs_four_and_cycles_a_litre :
192
+ splitCost * 100 / burnYield = 433 ∧ 9 * 1000 / (burnYield / 1000) = 750 := by decide
193
+
194
+ -- ── 17 · WHERE THE REST GOES. Forty of every fifty-two kilowatt-hours leave as heat — 76% of the input. In a
195
+ -- building that wants hot water anyway this is recoverable and changes the case considerably; vented
196
+ -- to the air it is simply the loss. Naming the fraction is what makes that a design choice rather
197
+ -- than a disappointment. ──
198
+ theorem three_quarters_of_the_input_leaves_as_heat :
199
+ splitCost - burnYield = 40000 ∧ (splitCost - burnYield) * 100 / splitCost = 76 := by decide
200
+
201
+ -- ── 18 · WHERE THE POLLUTION GOES. Splitting is selective: it takes hydrogen and oxygen and leaves everything
202
+ -- else exactly where it was. A litre of seawater carries about 35 grams of dissolved solids, and every
203
+ -- one of those grams stays in the cell — a hundred litres leaves 3.5 kilograms of it behind. The same
204
+ -- hundred litres of ordinary tap water leaves 5 grams, seven hundred times less. So the feedwater
205
+ -- quality does not change whether the machine works; it changes how often it must be opened and
206
+ -- cleaned, and that is the difference between a device and a chore. The exhaust is genuinely pure
207
+ -- either way — this is a still, and every still has a residue to deal with.
208
+ def tdsSeawater : Nat := 35000 -- mg of dissolved solids per litre
209
+ def tdsTapWater : Nat := 50 -- mg per litre, ordinary supply
210
+
211
+ theorem what_the_feedwater_leaves_behind_decides_the_maintenance :
212
+ 100 * tdsSeawater / 1000 = 3500 ∧ 100 * tdsTapWater / 1000 = 5 ∧
213
+ tdsSeawater / tdsTapWater = 700 := by decide
214
+
215
+ end Energy