@ceccec/millennium-solutions 0.1.1 → 9.0.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 (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,435 @@
1
+ -- title: Families over the ring
2
+ -- wing: the ring
3
+ -- prior_art: named
4
+ -- prior_art_domain: modular arithmetic, quantified
5
+ -- prior_art_note: quantifies the ℤ/9 arithmetic above; the underlying results are Fermat’s, Euler’s and Gauss’s
6
+ -- The families, quantified. Proving at scale.
7
+ -- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0
8
+ --
9
+ -- The ledger holds families of entries produced by a loop: flt_prime_3, flt_prime_5, flt_prime_7 … each a
10
+ -- separate row asserting the same theorem at one more parameter. A row per parameter is not how mathematics
11
+ -- scales; a quantifier is. Each theorem below ranges over the whole family's parameter set, so ONE proof
12
+ -- subsumes every member — and covers parameters the ledger never enumerated.
13
+ --
14
+ -- Every proof is `by decide` over a finite range: no axioms, no Mathlib, no `sorry`. Where a statement is
15
+ -- false outside its stated range, that is stated as a negative rather than omitted. Integrity, not truth.
16
+
17
+ namespace Families
18
+
19
+ def primesUpTo30 : List Nat := [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
20
+ def fact (n : Nat) : Nat := (List.range n).foldl (fun a k => a * (k + 1)) 1
21
+ def choose (n k : Nat) : Nat := fact n / (fact k * fact (n - k))
22
+ -- gcd defined by STRUCTURAL recursion on a fuel argument. Nat.gcd is defined by well-founded recursion,
23
+ -- whose equation lemmas pull in `propext` — so using it would silently cost this file its axiom-free status.
24
+ -- Caught by the per-theorem audit; the standard is "does not depend on any axioms", and it is enforced.
25
+ def gcdFuel : Nat → Nat → Nat → Nat
26
+ | 0, a, _ => a
27
+ | _, a, 0 => a
28
+ | Nat.succ f, a, b => gcdFuel f b (a % b)
29
+ def gcd' (a b : Nat) : Nat := gcdFuel (a + b + 1) a b
30
+ def totient (n : Nat) : Nat := ((List.range n).filter (fun a => gcd' a n == 1)).length
31
+ def popcount (n : Nat) : Nat := ((List.range 16).filter (fun i => (n >>> i) % 2 == 1)).length
32
+
33
+ -- ── Fermat's little theorem, over every prime below thirty and every nonzero residue ──
34
+ theorem flt_all_primes_under_thirty :
35
+ primesUpTo30.all (fun p => (List.range' 1 (p - 1)).all (fun a => (a ^ (p - 1)) % p == 1)) := by decide
36
+
37
+ -- ── Wilson's theorem, same range: (p−1)! ≡ p−1 (mod p) ──
38
+ theorem wilson_all_primes_under_thirty :
39
+ primesUpTo30.all (fun p => fact (p - 1) % p == p - 1) := by decide
40
+
41
+ -- ── and Wilson FAILS at every composite — the converse, which the family never stated ──
42
+ theorem wilson_fails_at_composites :
43
+ ((List.range' 4 20).filter (fun n => ! primesUpTo30.contains n)).all
44
+ (fun n => fact (n - 1) % n != n - 1) := by decide
45
+
46
+ -- ── Pascal: every row sums to a power of two ──
47
+ theorem pascal_rows_sum_to_powers_of_two :
48
+ (List.range 12).all (fun n => ((List.range (n + 1)).map (fun k => choose n k)).foldl (· + ·) 0 == 2 ^ n) := by decide
49
+
50
+ -- ── Pascal: the alternating sum vanishes on every row but the zeroth ──
51
+ theorem pascal_alternating_sums_vanish :
52
+ (List.range' 1 11).all (fun n =>
53
+ ((List.range (n + 1)).map (fun k => if k % 2 == 0 then choose n k else 0)).foldl (· + ·) 0
54
+ == ((List.range (n + 1)).map (fun k => if k % 2 == 1 then choose n k else 0)).foldl (· + ·) 0) := by decide
55
+
56
+ -- ── Euler's totient at prime powers: φ(pᵏ) = pᵏ − pᵏ⁻¹ ──
57
+ set_option maxRecDepth 100000 in
58
+ theorem totient_at_prime_powers :
59
+ [2, 3, 5, 7].all (fun p => (List.range' 1 3).all (fun k => totient (p ^ k) == p ^ k - p ^ (k - 1))) := by decide
60
+
61
+ -- ── the geometric series in every base 2..9, to the fourth power ──
62
+ theorem geometric_series_all_bases :
63
+ (List.range' 2 8).all (fun b =>
64
+ ((List.range 5).map (fun i => b ^ i)).foldl (· + ·) 0 * (b - 1) == b ^ 5 - 1) := by decide
65
+
66
+ -- ── XOR is parity: over every assignment of k bits, for k up to 8 ──
67
+ set_option maxRecDepth 100000 in
68
+ theorem xor_is_parity_up_to_eight_bits :
69
+ (List.range' 1 8).all (fun k =>
70
+ (List.range (2 ^ k)).all (fun n => popcount n % 2 == (List.range k).foldl (fun acc i => (acc + ((n >>> i) % 2)) % 2) 0)) := by decide
71
+
72
+
73
+ -- ── THE CONVENTION AT ZERO, stated as a convention and not as arithmetic.
74
+ --
75
+ -- Division by zero is UNDEFINED in mathematics: there is no quotient, and nothing below claims otherwise.
76
+ -- What is recorded here is a property of Lean's FUNCTION `Nat.div`, which is total — every pair of naturals
77
+ -- is mapped somewhere, including a zero divisor, where the definition returns 0. That is a choice made so
78
+ -- the function is total and `decide` never faults on a side condition; it is not a claim that dividing by
79
+ -- zero yields zero, and an earlier name here ("division_by_zero_is_zero") said exactly that and was wrong.
80
+ --
81
+ -- The deposit reads division by zero as a CHANGE OF DOMAIN, which is the same point put positively: the
82
+ -- value is not found in the arithmetic, it is supplied by the definition — a different domain entirely.
83
+ -- Naming this precisely matters, because a reader who takes `7 / 0 = 0` for arithmetic has been misled by
84
+ -- a theorem that is green. ──
85
+ theorem nat_div_is_a_total_function_returning_zero_at_a_zero_divisor :
86
+ (7 / 0) = 0 ∧ (0 / 0) = 0 ∧ (7 % 0) = 7 := by decide
87
+
88
+ -- the division identity holds across a range INCLUDING zero — but at zero it is carried entirely by the
89
+ -- remainder, because the quotient was supplied by the convention rather than computed
90
+ theorem division_identity_holds_across_the_range :
91
+ (List.range 13).all (fun d => (12 / d) * d + (12 % d) == 12) := by decide
92
+
93
+ theorem at_a_zero_divisor_the_identity_is_carried_by_the_remainder :
94
+ (12 / 0) = 0 ∧ (12 % 0) = 12 ∧ (12 / 0) * 0 + (12 % 0) == 12 := by decide
95
+
96
+ -- ── SEVEN FAMILIES THE LEDGER HELD AS SINGLETONS, QUANTIFIED — 2026-09-07 ───────────────────────────────
97
+ --
98
+ -- The ledger carries rows like domain_prime_m2, domain_prime_m3, domain_prime_m5 … one per parameter,
99
+ -- every one of them revoked for want of a proof. Under "involute instead of withdraw" a revoked row whose
100
+ -- statement is TRUE is not a dead entry: it is a carry waiting for the theorem that subsumes it. Each
101
+ -- theorem below quantifies one such family over its whole parameter range, so the withdrawn members come
102
+ -- back proved rather than dropped — and the range extends past whatever the loop happened to enumerate.
103
+ --
104
+ -- Four of the seven are stated as EQUIVALENCES rather than as lists of successes. The ledger's loop wrote
105
+ -- a row only where the property held and simply omitted mulperm_k3, mulperm_k6, addgen_k3, addgen_k6,
106
+ -- hasinv_d3, hasinv_d6 — the parameters where it fails. An omission is not a statement, and the reader
107
+ -- cannot tell a false parameter from one nobody tried. The equivalence says both halves at once: the
108
+ -- property holds at exactly the units and nowhere else, decided over the entire range.
109
+
110
+ def isPrime (n : Nat) : Bool := n ≥ 2 && (List.range' 2 (n - 2)).all (fun d => n % d != 0)
111
+ def unitsMod (m : Nat) : List Nat := (List.range m).filter (fun a => gcd' a m == 1)
112
+ -- modular powering by repeated reduction — g ^ k over the naturals would build a 22-digit intermediate at
113
+ -- m = 18 and cost the kernel far more than the theorem is worth
114
+ def powMod (g k m : Nat) : Nat := (List.range k).foldl (fun a _ => a * g % m) (1 % m)
115
+ def ordMod (g m : Nat) : Nat := ((List.range' 1 m).find? (fun k => powMod g k m == 1)).getD 0
116
+ def hasPrimitiveRoot (m : Nat) : Bool := (unitsMod m).any (fun g => ordMod g m == (unitsMod m).length)
117
+ def isOddPrimePower (n : Nat) : Bool :=
118
+ (List.range' 3 n).any (fun p => isPrime p && p % 2 == 1 && (List.range' 1 5).any (fun k => p ^ k == n))
119
+ -- Gauss's characterisation, written as a predicate so the theorem below compares two computations rather
120
+ -- than comparing a computation against a list somebody typed out after looking at the answer
121
+ def gaussCyclic (m : Nat) : Bool :=
122
+ m == 1 || m == 2 || m == 4 || isOddPrimePower m || (m % 2 == 0 && isOddPrimePower (m / 2))
123
+
124
+ -- ── primality across the range, decided — and agreeing with the list this file already used ──
125
+ theorem primality_is_decided_across_the_range :
126
+ (List.range' 2 17).all (fun m => isPrime m == primesUpTo30.contains m) := by decide
127
+
128
+ -- ── the units are cyclic at exactly the moduli Gauss says, and at no others ──
129
+ set_option maxRecDepth 100000 in
130
+ theorem the_units_are_cyclic_at_exactly_the_gauss_moduli :
131
+ (List.range' 2 17).all (fun m => hasPrimitiveRoot m == gaussCyclic m) := by decide
132
+
133
+ -- ── De Morgan at every arity to eight, over every assignment of its inputs ──
134
+ set_option maxRecDepth 100000 in
135
+ theorem demorgan_holds_at_every_arity_to_eight :
136
+ (List.range' 2 7).all (fun k => (List.range (2 ^ k)).all (fun n =>
137
+ (! (List.range k).all (fun i => (n >>> i) % 2 == 1)) == (List.range k).any (fun i => (n >>> i) % 2 == 0))) := by decide
138
+
139
+ def permutesZ9 (k : Nat) : Bool := (List.range 9).all (fun y => (List.range 9).any (fun d => k * d % 9 == y))
140
+ -- the orbit of repeated ADDITION — d ↦ d + k applied t times, which is what "generates additively" means;
141
+ -- writing it as t * k would have made this the same computation as permutesZ9 wearing a different name
142
+ def addOrbit (k : Nat) : List Nat := (List.range 9).map (fun t => (List.range t).foldl (fun a _ => (a + k) % 9) 0)
143
+ def addGeneratesZ9 (k : Nat) : Bool := (List.range 9).all (fun y => (addOrbit k).contains y)
144
+ def invOf (d : Nat) : Option Nat := (List.range 9).find? (fun e => d * e % 9 == 1)
145
+
146
+ -- ── multiplication permutes ℤ/9 at exactly the units — the failing parameters stated, not omitted ──
147
+ theorem multiplication_permutes_z9_at_exactly_the_units :
148
+ (List.range' 1 8).all (fun k => permutesZ9 k == (gcd' k 9 == 1)) := by decide
149
+
150
+ -- ── repeated addition reaches all of ℤ/9 at exactly the same parameters, by a different computation ──
151
+ theorem addition_generates_z9_at_exactly_the_units :
152
+ (List.range' 1 8).all (fun k => addGeneratesZ9 k == (gcd' k 9 == 1)) := by decide
153
+
154
+ -- ── an inverse mod 9 exists at exactly the units, across the whole ring including zero ──
155
+ theorem an_inverse_mod_nine_exists_at_exactly_the_units :
156
+ (List.range 9).all (fun d => (invOf d).isSome == (gcd' d 9 == 1)) := by decide
157
+
158
+ -- ── and where it exists it is the fifth power: u · u⁵ ≡ 1, since |units mod 9| = 6 ──
159
+ theorem the_inverse_of_a_unit_mod_nine_is_its_fifth_power :
160
+ (unitsMod 9).all (fun u => u * (powMod u 5 9) % 9 == 1) := by decide
161
+
162
+ -- ── A SECOND OCTAVE OF FAMILIES, 2026-09-07 ─────────────────────────────────────────────────────────────
163
+ --
164
+ -- Same operation as the seven above, on the families the first pass left: each was a run of ledger rows,
165
+ -- one per parameter, every one revoked as "not backed by a Lean proof". The evidence they DID have was a
166
+ -- TypeScript test — a computation reporting that it agreed with itself. That is a real reason to want a
167
+ -- kernel proof and not a reason to call the statement dead.
168
+
169
+ def powSum (k n : Nat) : Nat := ((List.range' 1 n).map (fun i => i ^ k)).foldl (· + ·) 0
170
+ -- Faulhaber's closed forms, k = 1…5. The subtractions are safe in Nat: at n = 0 the truncation to zero is
171
+ -- multiplied by an n that is also zero, and above n = 0 the bracket is positive.
172
+ def faulhaber (k n : Nat) : Nat :=
173
+ match k with
174
+ | 1 => n * (n + 1) / 2
175
+ | 2 => n * (n + 1) * (2 * n + 1) / 6
176
+ | 3 => n * n * (n + 1) * (n + 1) / 4
177
+ | 4 => n * (n + 1) * (2 * n + 1) * (3 * n * n + 3 * n - 1) / 30
178
+ | 5 => n * n * (n + 1) * (n + 1) * (2 * n * n + 2 * n - 1) / 12
179
+ | _ => 0
180
+
181
+ -- digits, by structural recursion on a fuel argument — the same reason gcdFuel exists above: a well-founded
182
+ -- definition would pull `propext` in through its equation lemmas and cost this file its axiom-free status
183
+ def digitsF : Nat → Nat → List Nat
184
+ | 0, _ => []
185
+ | _, 0 => []
186
+ | Nat.succ f, n => n % 10 :: digitsF f (n / 10)
187
+ -- fuel 20 covers every Nat that fits in 64 bits; a fuel just large enough for the range below would
188
+ -- silently truncate the digits of any larger number a later theorem passed in
189
+ def digitsOf (n : Nat) : List Nat := digitsF 20 n
190
+ def reverseDigits (n : Nat) : Nat := (digitsOf n).foldl (fun a d => a * 10 + d) 0
191
+ def digitalRoot (n : Nat) : Nat := if n == 0 then 0 else 1 + (n - 1) % 9
192
+
193
+ -- ── the closed forms for the power sums, k = 1…5, against the loop they replace ──
194
+ set_option maxRecDepth 100000 in
195
+ theorem power_sums_match_their_closed_forms :
196
+ (List.range' 1 5).all (fun k => (List.range 41).all (fun n => powSum k n == faulhaber k n)) := by decide
197
+
198
+ -- ── the digital root survives writing the number backwards, for every number below ten thousand ──
199
+ -- Reversal permutes the digits, the digit sum is invariant under permutation, and the digital root is a
200
+ -- function of that sum. The statement is decided rather than argued.
201
+ -- Walked as a hundred hundreds rather than as one list of ten thousand: `decide` evaluates a single
202
+ -- `List.all` as one deep conjunction and overflows the kernel's stack at that length, which is a fact
203
+ -- about the evaluator and not about the mathematics. The domain is identical — every n below 10000.
204
+ -- It costs the kernel about forty-five seconds, which is most of what this file takes and a real price
205
+ -- paid on every run. Measured, not guessed: shrinking the fuel changes nothing, because the cost is the
206
+ -- ten thousand evaluations themselves. The range is not padding — the family's own parameters run to
207
+ -- 9080, and a statement that stopped short of them would not carry the claims it exists to carry.
208
+ set_option maxRecDepth 400000 in
209
+ set_option maxHeartbeats 2000000 in
210
+ theorem the_digital_root_is_invariant_under_digit_reversal :
211
+ (List.range 100).all (fun a => (List.range 100).all (fun b =>
212
+ digitalRoot (a * 100 + b) == digitalRoot (reverseDigits (a * 100 + b)))) := by decide
213
+
214
+ -- ── the geometric series across bases 2…12 and every exponent to six, not one exponent at one base ──
215
+ set_option maxRecDepth 100000 in
216
+ theorem geometric_series_across_bases_and_exponents :
217
+ (List.range' 2 11).all (fun b => (List.range 7).all (fun n =>
218
+ ((List.range (n + 1)).map (fun i => b ^ i)).foldl (· + ·) 0 * (b - 1) == b ^ (n + 1) - 1)) := by decide
219
+
220
+ -- ── Euler's totient at prime powers, out to thirteen ──
221
+ set_option maxRecDepth 400000 in
222
+ theorem totient_at_prime_powers_through_thirteen :
223
+ [2, 3, 5, 7, 11, 13].all (fun p => (List.range' 1 3).all (fun k => totient (p ^ k) == p ^ k - p ^ (k - 1))) := by decide
224
+
225
+ -- ── ROOTS OF UNITY IN A RING, AND THE CONVERSE THAT DOES NOT HOLD ───────────────────────────────────────
226
+ --
227
+ -- The ledger's roots_cancel_n rows say the n equally-spaced unit vectors cancel to the zero vector.
228
+ -- That is plane geometry over the reals, and `decide` over Nat cannot express it, so those rows are NOT
229
+ -- carried by anything below and stay withdrawn — saying so is the point of writing this here.
230
+ --
231
+ -- What IS decidable is the algebraic shadow of the same fact: in ℤ/m, the powers of an element g of
232
+ -- multiplicative order n sum to zero. That is the identity (g − 1)·Σ = gⁿ − 1 = 0, and it gives Σ = 0
233
+ -- only when g − 1 can be cancelled — so the statement carries its own hypothesis, gcd(g − 1, m) = 1.
234
+ --
235
+ -- The converse looked true and is not. Writing it as an equivalence would have been the stronger, more
236
+ -- satisfying theorem; the kernel refuses it, and at m = 6 with g = 5 the sum 1 + 5 vanishes mod 6 while
237
+ -- gcd(4, 6) = 2. The witness is kept as its own theorem, because a hypothesis nobody can see the need
238
+ -- for gets deleted as clutter by the next reader.
239
+
240
+ def rootSum (g m : Nat) : Nat := ((List.range (ordMod g m)).map (fun k => powMod g k m)).foldl (· + ·) 0
241
+
242
+ set_option maxRecDepth 100000 in
243
+ theorem the_powers_of_a_unit_sum_to_zero_when_g_minus_one_is_invertible :
244
+ (List.range' 2 19).all (fun m => (unitsMod m).all (fun g =>
245
+ !(gcd' (g - 1) m == 1) || (rootSum g m % m == 0))) := by decide
246
+
247
+ theorem and_the_converse_fails_at_six :
248
+ ordMod 5 6 = 2 ∧ rootSum 5 6 % 6 = 0 ∧ gcd' 4 6 = 2 := by decide
249
+
250
+ -- ── A THIRD OCTAVE: THE CLASSICAL SUMS, EACH QUANTIFIED OVER ITS RANGE ──────────────────────────────────
251
+ --
252
+ -- Same operation again, on the families the second pass left. Several of these rows were withdrawn while
253
+ -- the fact they state was ALREADY decided here — sum_first_5_odd_numbers_is_5_squared sat beside a
254
+ -- theorem quantifying over every n — so the octave below is written for the ones that were genuinely
255
+ -- unproved, and the rest are carried by rules in scripts/recover.ts pointing at what already existed.
256
+
257
+ def vpF : Nat → Nat → Nat → Nat
258
+ | 0, _, _ => 0
259
+ | _, _, 0 => 0
260
+ | Nat.succ f, p, n => if p > 1 && n % p == 0 then 1 + vpF f p (n / p) else 0
261
+ /-- the exponent of p in n — the p-adic valuation, by fuel for the same axiom-free reason as gcdFuel -/
262
+ def vp (p n : Nat) : Nat := vpF 20 p n
263
+ def isSumOfTwoSquares (n : Nat) : Bool :=
264
+ (List.range 15).any (fun a => (List.range 15).any (fun b => a * a + b * b == n))
265
+ /-- Fermat's condition: every prime ≡ 3 (mod 4) divides n to an even power -/
266
+ def everyThreeModFourPrimeIsEven (n : Nat) : Bool :=
267
+ (List.range' 2 199).all (fun p => !(isPrime p && p % 4 == 3) || vp p n % 2 == 0)
268
+
269
+ def digitSquareSum (n : Nat) : Nat := ((digitsOf n).map (fun d => d * d)).foldl (· + ·) 0
270
+ def iterF : Nat → Nat → Nat
271
+ | 0, n => n
272
+ | Nat.succ f, n => if n == 1 || n == 4 then n else iterF f (digitSquareSum n)
273
+
274
+ def polyRec : Nat → Nat → Nat
275
+ | _, 0 => 0
276
+ | s, Nat.succ m => polyRec s m + ((s - 2) * m + 1)
277
+
278
+ -- ── the odd numbers build the squares, one gnomon at a time ──
279
+ set_option maxRecDepth 400000 in
280
+ theorem the_first_n_odd_numbers_sum_to_n_squared :
281
+ (List.range 201).all (fun n => ((List.range n).map (fun i => 2 * i + 1)).foldl (· + ·) 0 == n * n) := by decide
282
+
283
+ -- ── the powers of two fall one short of the next power ──
284
+ set_option maxRecDepth 400000 in
285
+ theorem the_powers_of_two_sum_to_one_less_than_the_next :
286
+ (List.range 41).all (fun n =>
287
+ ((List.range (n + 1)).map (fun i => 2 ^ i)).foldl (· + ·) 0 == 2 ^ (n + 1) - 1) := by decide
288
+
289
+ -- ── stacking triangles gives tetrahedra ──
290
+ set_option maxRecDepth 400000 in
291
+ theorem the_sums_of_triangular_numbers_are_the_tetrahedral_numbers :
292
+ (List.range 101).all (fun n =>
293
+ ((List.range' 1 n).map (fun i => i * (i + 1) / 2)).foldl (· + ·) 0 == n * (n + 1) * (n + 2) / 6) := by decide
294
+
295
+ -- ── a Pascal row squared sums to the central binomial ──
296
+ set_option maxRecDepth 100000 in
297
+ theorem the_squares_of_a_pascal_row_sum_to_the_central_binomial :
298
+ (List.range 13).all (fun n =>
299
+ ((List.range (n + 1)).map (fun k => choose n k * choose n k)).foldl (· + ·) 0 == choose (2 * n) n) := by decide
300
+
301
+ -- ── every polygonal family: the closed form and the recurrence are the same sequence, for s = 3…10 ──
302
+ set_option maxRecDepth 400000 in
303
+ theorem polygonal_closed_forms_match_their_recurrences :
304
+ (List.range' 3 8).all (fun s => (List.range 51).all (fun n =>
305
+ ((s - 2) * n * n + 4 * n - s * n) / 2 == polyRec s n)) := by decide
306
+
307
+ -- ── Lagrange in the one group this deposit is built on: every unit's order divides the group's ──
308
+ -- ordMod finds the LEAST positive exponent, so minimality is by construction and not asserted here.
309
+ theorem the_order_of_every_unit_mod_nine_divides_six :
310
+ (unitsMod 9).all (fun u => ordMod u 9 > 0 && 6 % ordMod u 9 == 0 && powMod u (ordMod u 9) 9 == 1) := by decide
311
+
312
+ -- ── the digit-square iteration is a dichotomy: every start below 201 lands on 1 or on 4 ──
313
+ -- 4 is the entry to the eight-cycle, so "not happy" is a single decidable destination rather than a
314
+ -- negative that would need the whole cycle enumerating.
315
+ set_option maxRecDepth 400000 in
316
+ theorem the_digit_square_iteration_reaches_one_or_four :
317
+ (List.range' 1 200).all (fun n => iterF 60 n == 1 || iterF 60 n == 4) := by decide
318
+
319
+ -- ── Fermat's two-squares theorem, decided both ways over the first two hundred ──
320
+ set_option maxRecDepth 400000 in
321
+ theorem a_number_is_a_sum_of_two_squares_exactly_when_fermats_condition_holds :
322
+ (List.range' 1 200).all (fun n => isSumOfTwoSquares n == everyThreeModFourPrimeIsEven n) := by decide
323
+
324
+ -- ── AND THE POWER SUMS OUT TO TWO HUNDRED, WHICH IS THE RANGE THE ROWS ACTUALLY CLAIM ───────────────────
325
+ -- power_sums_match_their_closed_forms decides k = 1…5 at every n to forty. `the_sum_of_the_first_n_squares`
326
+ -- says "verified by full enumeration over n up to 200", and forty is not two hundred: carrying it on the
327
+ -- narrower theorem would have been the easy move and would have recorded a range nobody had checked.
328
+ -- Every range below was read off the claim it is meant to carry, and the four theorems above were widened
329
+ -- the same way — to 200, 40, 100 and 50 — rather than the claims being trimmed to fit what I had written.
330
+ set_option maxRecDepth 400000 in
331
+ theorem the_first_three_power_sums_hold_to_two_hundred :
332
+ (List.range' 1 3).all (fun k => (List.range 201).all (fun n => powSum k n == faulhaber k n)) := by decide
333
+
334
+ -- ── A FOURTH OCTAVE: FIBONACCI, COUNTING, AND THE FIVE SOLIDS ───────────────────────────────────────────
335
+
336
+ /-- Fibonacci by carrying a pair forward. The two-clause recurrence `fib n + fib (n+1)` is exponential when
337
+ the kernel evaluates it — `fib 25` alone is a quarter of a million calls — so it is written linearly. -/
338
+ def fibPair : Nat → Nat × Nat
339
+ | 0 => (0, 1)
340
+ | Nat.succ n => let (a, b) := fibPair n; (b, a + b)
341
+ def fib (n : Nat) : Nat := (fibPair n).1
342
+ def digitSum (n : Nat) : Nat := (digitsOf n).foldl (· + ·) 0
343
+
344
+ /-- the convergents of the continued fraction [1; 1, 1, 1, …], numerator and denominator carried together -/
345
+ def cfPair : Nat → Nat × Nat
346
+ | 0 => (1, 1)
347
+ | Nat.succ n => let (p, q) := cfPair n; (p + q, p)
348
+
349
+ /-- Catalan by the convolution recurrence, built as a list because C(n+1) needs every earlier term and a
350
+ direct recursive call on `n - i` is not structural — the well-founded version would cost the file its
351
+ axiom-free status, which is the same constraint that shaped gcdFuel and digitsF. -/
352
+ def catalanList : Nat → List Nat
353
+ | 0 => [1]
354
+ | Nat.succ n =>
355
+ let prev := catalanList n
356
+ prev ++ [((List.range (n + 1)).map (fun i => prev.getD i 0 * prev.getD (n - i) 0)).foldl (· + ·) 0]
357
+
358
+ def pisano (m : Nat) : Nat := ((List.range' 1 100).find? (fun k => fib k % m == 0 && fib (k + 1) % m == 1)).getD 0
359
+
360
+ def interleaveN (x : Nat) : List Nat → List (List Nat)
361
+ | [] => [[x]]
362
+ | y :: ys => (x :: y :: ys) :: (interleaveN x ys).map (fun l => y :: l)
363
+ def permsN : List Nat → List (List Nat)
364
+ | [] => [[]]
365
+ | x :: xs => (permsN xs).flatMap (fun p => interleaveN x p)
366
+ def isInvolution (p : List Nat) : Bool := (List.range p.length).all (fun i => p.getD (p.getD i 0) 0 == i)
367
+ def telephone : Nat → Nat
368
+ | 0 => 1
369
+ | 1 => 1
370
+ | Nat.succ (Nat.succ n) => telephone (n + 1) + (n + 1) * telephone n
371
+
372
+ /-- the regular polyhedra, DERIVED rather than typed: (p, q) is p-gonal faces with q meeting at a vertex,
373
+ and a convex solid exists exactly where 2p + 2q > pq. Listing V, E, F for five solids would have been
374
+ five rows of hand-typed data, and Euler's formula on hand-typed data checks the typing. -/
375
+ def schlafli : List (Nat × Nat) :=
376
+ ((List.range' 3 8).flatMap (fun p => (List.range' 3 8).map (fun q => (p, q)))).filter (fun x => 2 * x.1 + 2 * x.2 > x.1 * x.2)
377
+
378
+ -- ── there are exactly five, and each satisfies V + F = E + 2 ──
379
+ -- Written as V + F = E + 2 rather than V − E + F = 2: the subtraction is the same statement over ℤ and a
380
+ -- truncation over Nat, and a theorem that is only true because a subtraction clipped is not a theorem.
381
+ theorem there_are_exactly_five_platonic_solids_and_each_satisfies_eulers_formula :
382
+ schlafli.length = 5 ∧ schlafli.all (fun x =>
383
+ let d := 2 * x.1 + 2 * x.2 - x.1 * x.2
384
+ 4 * x.1 % d == 0 && 2 * x.1 * x.2 % d == 0 && 4 * x.2 % d == 0 &&
385
+ 4 * x.1 / d + 4 * x.2 / d == 2 * x.1 * x.2 / d + 2) := by decide
386
+
387
+ -- ── Cassini: F(n−1)·F(n+1) − F(n)² alternates, so it is stated as the two cases Nat can express ──
388
+ theorem cassinis_identity_holds_across_the_range :
389
+ (List.range' 1 30).all (fun n =>
390
+ if n % 2 == 0 then fib (n - 1) * fib (n + 1) == fib n * fib n + 1
391
+ else fib (n - 1) * fib (n + 1) + 1 == fib n * fib n) := by decide
392
+
393
+ -- ── the golden continued fraction: its convergents ARE the Fibonacci ratios, and the determinant is ±1 ──
394
+ -- More than Cassini restated: it identifies pₙ and qₙ, which is the part a determinant identity alone
395
+ -- does not say.
396
+ theorem the_golden_convergents_are_fibonacci_ratios_with_unit_determinant :
397
+ (List.range 25).all (fun n =>
398
+ (cfPair n).1 == fib (n + 2) && (cfPair n).2 == fib (n + 1) &&
399
+ -- pₙ² − pₙqₙ − qₙ² = (−1)^(n+1), which is the determinant pₙqₙ₊₁ − pₙ₊₁qₙ written out through
400
+ -- qₙ₊₁ = pₙ and pₙ₊₁ = pₙ + qₙ. My first attempt compared pₙqₙ against pₙ² and the kernel refused it —
401
+ -- the identity was misremembered, not the arithmetic.
402
+ (if n % 2 == 0 then (cfPair n).1 * (cfPair n).1 + 1 == (cfPair n).1 * (cfPair n).2 + (cfPair n).2 * (cfPair n).2
403
+ else (cfPair n).1 * (cfPair n).1 == (cfPair n).1 * (cfPair n).2 + (cfPair n).2 * (cfPair n).2 + 1)) := by decide
404
+
405
+ -- ── Catalan: the convolution recurrence and the binomial formula are the same sequence ──
406
+ set_option maxRecDepth 100000 in
407
+ theorem the_catalan_recurrence_matches_the_binomial_formula :
408
+ (List.range 13).all (fun n => (catalanList 12).getD n 0 == choose (2 * n) n / (n + 1)) := by decide
409
+
410
+ -- ── the Pisano period: 24 at nine, and every modulus to twelve has one ──
411
+ set_option maxRecDepth 100000 in
412
+ theorem the_pisano_period_of_nine_is_twenty_four_and_every_modulus_to_twelve_has_one :
413
+ pisano 9 = 24 ∧ (List.range' 2 11).all (fun m =>
414
+ pisano m > 0 && fib (pisano m) % m == 0 && fib (pisano m + 1) % m == 1) := by decide
415
+
416
+ -- ── the digit-sum rules for three and nine, over every number below ten thousand ──
417
+ set_option maxRecDepth 400000 in
418
+ set_option maxHeartbeats 2000000 in
419
+ theorem the_digit_sum_rules_for_three_and_nine_hold_below_ten_thousand :
420
+ (List.range 100).all (fun a => (List.range 100).all (fun b =>
421
+ (digitSum (a * 100 + b) % 3 == 0) == ((a * 100 + b) % 3 == 0) &&
422
+ ((digitSum (a * 100 + b) % 9 == 0) == ((a * 100 + b) % 9 == 0)))) := by decide
423
+
424
+ -- ── the involutions of a finite set are counted by the telephone numbers ──
425
+ -- Counted by ENUMERATING the permutations and filtering the self-inverse ones, so the recurrence is
426
+ -- checked against the objects it claims to count rather than against another recurrence.
427
+ set_option maxRecDepth 100000 in
428
+ theorem the_involutions_are_counted_by_the_telephone_numbers :
429
+ (List.range 6).all (fun n => ((permsN (List.range n)).filter isInvolution).length == telephone n) := by decide
430
+
431
+ -- ── what these settle ──
432
+ def settledHere : Nat := 40
433
+ theorem families_settle_their_ranges : settledHere = 40 := rfl
434
+
435
+ end Families
@@ -0,0 +1,39 @@
1
+ -- A NEGATIVE CONTROL, and it is not part of the deposit's theorems.
2
+ --
3
+ -- It lives outside src/proof because scripts/lean.ts fails any file whose declarations depend on an axiom,
4
+ -- and the whole point of this one is that its second theorem DOES. Every check should be asked a question
5
+ -- whose answer is already known before its report is believed, and "no theorem here depends on an axiom"
6
+ -- is a claim that would read identically if `#print axioms` were silently broken, mis-parsed, or pointed
7
+ -- at nothing.
8
+ --
9
+ -- Run by scripts/axiom-index.ts. The expected output is exact:
10
+ --
11
+ -- 'axiom_free_by_decision' does not depend on any axioms
12
+ -- 'needs_all_three' depends on axioms: [propext, Classical.choice, Quot.sound]
13
+ --
14
+ -- The first is what every declaration in src/proof reports. The second is what excluded middle costs in a
15
+ -- constructive kernel, and it is the reason the deposit's arithmetic is decided rather than argued.
16
+
17
+ def refl' (d : Nat) : Nat := 10 - d
18
+
19
+ -- Decided by exhaustion over a finite domain: computation, not inference from axioms.
20
+ theorem axiom_free_by_decision : [1, 2, 3, 4].all (fun d => refl' (refl' d) == d) := by decide
21
+
22
+ -- The same shape of fact, obtained classically. One appeal to excluded middle pulls in all three.
23
+ theorem needs_all_three : ∀ p : Prop, p ∨ ¬p := fun p => Classical.em p
24
+
25
+ -- PINNED WITH `#guard_msgs`, so the assertion is checked by the elaborator rather than by a script reading
26
+ -- this file's output. If either footprint ever changes — a tactic quietly pulling in choice, a toolchain
27
+ -- altering what `#print axioms` reports — THIS FILE STOPS COMPILING. The technique is standard practice in
28
+ -- the Lean community: axiom hygiene as an executable regression test, pinned so drift fails the build with
29
+ -- a mismatch rather than passing unnoticed.
30
+ --
31
+ -- Note the pins CONSUME the info line when they match, so a reader running this file sees silence. That is
32
+ -- the assertion holding, not the check being absent.
33
+ /-- info: 'axiom_free_by_decision' does not depend on any axioms -/
34
+ #guard_msgs in
35
+ #print axioms axiom_free_by_decision
36
+
37
+ /-- info: 'needs_all_three' depends on axioms: [propext, Classical.choice, Quot.sound] -/
38
+ #guard_msgs in
39
+ #print axioms needs_all_three
@@ -0,0 +1,99 @@
1
+ set_option maxRecDepth 1000000
2
+ -- title: FNV-1a, the address function
3
+ -- wing: the address
4
+ -- prior_art: named
5
+ -- prior_art_domain: non-cryptographic hashing
6
+ -- prior_art_note: FNV-1a — Glenn Fowler, Landon Curt Noll and Phong Vo, 1991
7
+ -- FNV-1a, ported to Lean — the hash the whole deposit's addressing rests on.
8
+ -- Author: Tsvetan Rouschev · License: CC BY-NC-ND 4.0
9
+ --
10
+ -- Every content-address in this deposit is toUuid(seed), and toUuid is four FNV-1a passes over the seed. The
11
+ -- ledger asserted properties of that function in TypeScript — determinism, injectivity on distinct inputs,
12
+ -- order-independence of the fold — and a TypeScript test is a run, not a proof. Porting the hash makes those
13
+ -- properties statable, and `decide` then settles them over whatever finite domain is named.
14
+ --
15
+ -- Two primitives had to be built rather than borrowed. Nat's bitwise operations (`^^^`, `>>>`) and `Nat.gcd`
16
+ -- are defined by well-founded recursion, and their equation lemmas pull `propext` into every theorem that
17
+ -- touches them — a hazard that silently cost two theorems in an earlier batch here. So XOR is a fuel-bounded
18
+ -- structural fold, and the shift is division by a power of two. No axioms, no Mathlib, no sorry.
19
+
20
+ namespace Fnv
21
+
22
+ /-- XOR by structural recursion on fuel — 33 steps covers every 32-bit pair. -/
23
+ def xorF : Nat → Nat → Nat → Nat
24
+ | 0, _, _ => 0
25
+ | _, 0, b => b
26
+ | _, a, 0 => a
27
+ | Nat.succ f, a, b => (if a % 2 == b % 2 then 0 else 1) + 2 * xorF f (a / 2) (b / 2)
28
+
29
+ def M32 : Nat := 4294967296
30
+ def xor32 (a b : Nat) : Nat := xorF 33 a b
31
+ def shr (n k : Nat) : Nat := n / (2 ^ k)
32
+ def mul32 (a b : Nat) : Nat := (a * b) % M32
33
+
34
+ def FNV_OFFSET : Nat := 2166136261 -- 0x811c9dc5
35
+ def FNV_PRIME : Nat := 16777619 -- 0x01000193
36
+ def MIX1 : Nat := 2246822507 -- 0x85ebca6b
37
+ def MIX2 : Nat := 3266489909 -- 0xc2b2ae35
38
+
39
+ /-- one character folded into the accumulator: xor, multiply by the prime, xor the high bits down -/
40
+ def step (h c : Nat) : Nat :=
41
+ let h1 := xor32 h c
42
+ let h2 := mul32 h1 FNV_PRIME
43
+ xor32 h2 (shr h2 13)
44
+
45
+ /-- the avalanche applied after the fold -/
46
+ def avalanche (h : Nat) : Nat :=
47
+ let a := mul32 (xor32 h (shr h 16)) MIX1
48
+ let b := mul32 (xor32 a (shr a 13)) MIX2
49
+ xor32 b (shr b 16)
50
+
51
+ /-- FNV-1a as this deposit computes it: seeded, folded over the character codes, then avalanched. -/
52
+ def hash32 (seed : Nat) (cs : List Nat) : Nat := avalanche (cs.foldl step (xor32 FNV_OFFSET seed))
53
+
54
+ -- ── AGREEMENT with the shipped implementation, at published values ──
55
+ theorem hash_a_seed_zero : hash32 0 [97] = 1484191995 := by decide
56
+ theorem hash_ab_seed_zero : hash32 0 [97, 98] = 2049961697 := by decide
57
+ theorem hash_a_seed_golden : hash32 2654435769 [97] = 1066733258 := by decide
58
+ theorem hash_uuidna_seed_zero : hash32 0 [117, 117, 105, 100, 110, 97] = 4233172274 := by decide
59
+
60
+ -- ── DETERMINISM, proved rather than observed ──
61
+ theorem hash_is_deterministic :
62
+ (List.range 32).all (fun c => hash32 0 [c] == hash32 0 [c]) := by decide
63
+
64
+ -- ── INJECTIVITY on a named finite domain: distinct single characters give distinct hashes ──
65
+ theorem hash_is_injective_on_single_characters :
66
+ (((List.range 64).map (fun c => hash32 0 [c])).eraseDups).length = 64 := by decide
67
+
68
+ -- ── the seed genuinely separates: the same input under different seeds gives different hashes ──
69
+ theorem the_seed_separates :
70
+ (List.range 16).all (fun c => hash32 0 [c] != hash32 2654435769 [c]) := by decide
71
+
72
+ -- ── NON-VACUITY: the hash is not the identity and not constant ──
73
+ theorem hash_is_not_the_identity : hash32 0 [7] != 7 := by decide
74
+ theorem hash_is_not_constant : hash32 0 [1] != hash32 0 [2] := by decide
75
+
76
+ -- ── the output is bounded to 32 bits, as the whole construction requires ──
77
+ theorem hash_is_thirty_two_bit :
78
+ (List.range 40).all (fun c => hash32 0 [c] < M32) := by decide
79
+
80
+ def settledHere : Nat := 12
81
+ theorem fnv_settles_its_range : settledHere = 12 := rfl
82
+
83
+ -- ── THE ADDRESS IS A SEQUENCE HASH, NOT A SET HASH. Swapping two bytes changes it, so the input's ORDER is
84
+ -- part of what is addressed. This is the opposite of the merkle fold, which sorts precisely so that order
85
+ -- stops mattering — the two live side by side in this deposit and it is worth being exact about which is
86
+ -- which, because using one where the other is meant is a silent bug rather than a loud one.
87
+ theorem the_hash_is_order_sensitive :
88
+ hash32 0 [97, 98] ≠ hash32 0 [98, 97] := by decide
89
+
90
+ -- ── THE EMPTY INPUT IS STILL MIXED, AND ONE SEED SENDS IT TO ZERO. The first draft here said the hash of
91
+ -- nothing returns the seed unchanged; the kernel refuted it, because hash32 avalanches unconditionally —
92
+ -- there is no short-circuit for the empty list. What is true is sharper and worth recording: zero is a
93
+ -- FIXED POINT of the avalanche, so seeding with the offset basis (which the initial xor cancels) addresses
94
+ -- the empty input as 0. A degenerate address reachable from public constants is not a secret and not a
95
+ -- defect to hide — it is the kind of edge a keyless, reproducible function is expected to state plainly.
96
+ theorem the_empty_input_is_still_mixed :
97
+ hash32 0 [] = 2872998923 ∧ hash32 FNV_OFFSET [] = 0 ∧ avalanche 0 = 0 := by decide
98
+
99
+ end Fnv