@ceccec/millennium-solutions 9.3.3 → 9.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -15
- package/dist/mod.core.d.ts +9 -0
- package/dist/mod.core.js +9 -0
- package/dist/src/0/index.d.ts +47 -0
- package/dist/src/0/index.js +189 -0
- package/dist/src/0/ledger.d.ts +1 -0
- package/dist/src/0/ledger.js +25 -0
- package/dist/src/0/trinity-matrix.d.ts +1 -0
- package/dist/src/0/trinity-matrix.js +16 -0
- package/dist/src/5/aspects.d.ts +1 -0
- package/dist/src/5/aspects.js +22 -0
- package/dist/src/5/reflection.d.ts +1 -0
- package/dist/src/5/reflection.js +25 -0
- package/dist/src/7/rosetta.d.ts +1 -0
- package/dist/src/7/rosetta.js +24 -0
- package/dist/src/9/enumeration.d.ts +1 -0
- package/dist/src/9/enumeration.js +14 -0
- package/dist/src/honesty/index.d.ts +16 -0
- package/dist/src/honesty/index.js +69 -0
- package/package.json +27 -10
- package/.zenodo.json +0 -51
- package/ABSTRACT.md +0 -155
- package/ACCOUNTING.md +0 -27
- package/AXIOMS.md +0 -574
- package/CHALLENGES.md +0 -2595
- package/DEPLOY.md +0 -39
- package/DEVELOP.md +0 -34
- package/HEART.md +0 -112
- package/PHYSICS-SCALES.md +0 -80
- package/PRIOR-ART.md +0 -151
- package/PROOF-OF-CONCEPT.md +0 -81
- package/REALISATIONS.md +0 -87
- package/RESEARCH.md +0 -188
- package/RULES.md +0 -57
- package/SEQUENCE-DECODE.md +0 -196
- package/SIGNATURE.md +0 -34
- package/THEOREMS.md +0 -97
- package/WHITEPAPER.md +0 -40
- package/WORKFLOWS.md +0 -47
- package/boundaries.md +0 -23
- package/captain.md +0 -85
- package/compare.md +0 -42
- package/compute.md +0 -543
- package/cryptography.md +0 -55
- package/dashboard.md +0 -50
- package/examples.md +0 -47
- package/folds.md +0 -65
- package/forensic.md +0 -67
- package/guide.md +0 -126
- package/harness.md +0 -20
- package/index.md +0 -217
- package/mod.core.ts +0 -10
- package/nature.md +0 -58
- package/organism.md +0 -30
- package/paper.md +0 -8789
- package/proofs.md +0 -26
- package/quantum.md +0 -40
- package/rights.md +0 -39
- package/solutions.md +0 -28
- package/speedup.md +0 -41
- package/src/0/chacha.ts +0 -3
- package/src/0/crypt.ts +0 -4
- package/src/0/csp.ts +0 -10
- package/src/0/entanglement.ts +0 -31
- package/src/0/fusion.ts +0 -28
- package/src/0/holographic.ts +0 -57
- package/src/0/impossible.ts +0 -30
- package/src/0/imprint.ts +0 -160
- package/src/0/index.ts +0 -263
- package/src/0/ledger.ts +0 -25
- package/src/0/legible.ts +0 -29
- package/src/0/limit.ts +0 -29
- package/src/0/merkle-proof.ts +0 -3
- package/src/0/null-token.ts +0 -24
- package/src/0/sha256.ts +0 -3
- package/src/0/singularity.ts +0 -20
- package/src/0/stream.ts +0 -47
- package/src/0/trinities.ts +0 -37
- package/src/0/trinity-matrix.ts +0 -20
- package/src/0/version-matrix.ts +0 -70
- package/src/1/acceptance.ts +0 -26
- package/src/1/index.ts +0 -80
- package/src/1/paradox.ts +0 -28
- package/src/1/vortex.lean +0 -6
- package/src/2/frequency-scales.ts +0 -28
- package/src/2/iching.ts +0 -34
- package/src/2/index.ts +0 -78
- package/src/2/primes-vortex.ts +0 -12
- package/src/2/quantum.ts +0 -48
- package/src/2/string-scale.ts +0 -14
- package/src/2/vortex.lean +0 -10
- package/src/3/index.ts +0 -63
- package/src/3/pi-bbp.ts +0 -13
- package/src/3/trinity.ts +0 -39
- package/src/3/vortex.lean +0 -7
- package/src/4/git.ts +0 -30
- package/src/4/index.ts +0 -63
- package/src/4/vortex.lean +0 -6
- package/src/5/aspects.ts +0 -27
- package/src/5/center.ts +0 -35
- package/src/5/development.ts +0 -45
- package/src/5/diamond.ts +0 -35
- package/src/5/folds.ts +0 -12
- package/src/5/index.ts +0 -63
- package/src/5/reflection.lean +0 -14
- package/src/5/reflection.ts +0 -14
- package/src/5/vortex.lean +0 -10
- package/src/6/dna.ts +0 -27
- package/src/6/index.ts +0 -63
- package/src/6/vortex.lean +0 -7
- package/src/7/cross.ts +0 -31
- package/src/7/glagolitic.ts +0 -51
- package/src/7/index.ts +0 -67
- package/src/7/language-lens.ts +0 -41
- package/src/7/lens.ts +0 -41
- package/src/7/locale.ts +0 -105
- package/src/7/rbac.ts +0 -31
- package/src/7/rosetta-clay.ts +0 -15
- package/src/7/rosetta.lean +0 -11
- package/src/7/rosetta.ts +0 -11
- package/src/7/string-dimensions.ts +0 -14
- package/src/7/vortex.lean +0 -6
- package/src/8/infinite.ts +0 -26
- package/src/8/merkaba/field.ts +0 -27
- package/src/8/merkaba/geometry.ts +0 -16
- package/src/8/merkaba/touch.ts +0 -26
- package/src/8/nucleus/magic.lean +0 -15
- package/src/8/nucleus/proton-mass-fit.ts +0 -9
- package/src/8/nucleus/proton-mass.lean +0 -10
- package/src/8/nucleus/shell-model-magic.ts +0 -10
- package/src/8/vortex.lean +0 -7
- package/src/9/access.ts +0 -34
- package/src/9/aura-funding.ts +0 -25
- package/src/9/coins.ts +0 -25
- package/src/9/enumeration.ts +0 -13
- package/src/9/funding.ts +0 -85
- package/src/9/security.ts +0 -36
- package/src/9/society.ts +0 -32
- package/src/9/vortex.lean +0 -11
- package/src/api/gates.ts +0 -122
- package/src/api/index.ts +0 -447
- package/src/api/lanes.ts +0 -81
- package/src/claims/index.ts +0 -81
- package/src/demand/queries.json +0 -1764
- package/src/face/index.ts +0 -100
- package/src/from/the/heart/index.ts +0 -11
- package/src/honesty/boundaries.ts +0 -29
- package/src/honesty/index.ts +0 -63
- package/src/html/index.ts +0 -10
- package/src/latex/index.ts +0 -474
- package/src/millennium/index.ts +0 -53
- package/src/play/the/game/index.ts +0 -12
- package/src/proof/README.md +0 -118
- package/src/proof/address.lean +0 -168
- package/src/proof/coin.lean +0 -152
- package/src/proof/covered.json +0 -9
- package/src/proof/demand.lean +0 -160
- package/src/proof/demand2.lean +0 -219
- package/src/proof/demand3.lean +0 -209
- package/src/proof/discovered.json +0 -19530
- package/src/proof/elementary.lean +0 -495
- package/src/proof/energy.lean +0 -329
- package/src/proof/families.lean +0 -740
- package/src/proof/fixtures/axiom-control.lean +0 -39
- package/src/proof/flow.lean +0 -78
- package/src/proof/fnv.lean +0 -127
- package/src/proof/generated-theorems.json +0 -207
- package/src/proof/generated.lean +0 -101
- package/src/proof/imagined.lean +0 -492
- package/src/proof/index.lean +0 -156
- package/src/proof/index.ts +0 -916
- package/src/proof/involution.lean +0 -90
- package/src/proof/ledgerclaims.lean +0 -84
- package/src/proof/light.lean +0 -168
- package/src/proof/mechanical.lean +0 -563
- package/src/proof/merkaba.lean +0 -89
- package/src/proof/merkle.lean +0 -132
- package/src/proof/nim.lean +0 -332
- package/src/proof/novelty.json +0 -751
- package/src/proof/phenomena.lean +0 -90
- package/src/proof/priorart.lean +0 -190
- package/src/proof/quantum.lean +0 -159
- package/src/proof/reach.lean +0 -121
- package/src/proof/recovered.lean +0 -56
- package/src/proof/reversal.lean +0 -402
- package/src/proof/revoked.json +0 -317
- package/src/proof/rights.lean +0 -155
- package/src/proof/sequences.lean +0 -284
- package/src/proof/speed.lean +0 -158
- package/src/proof/split.lean +0 -209
- package/src/proof/theorems.lean +0 -67
- package/src/proof/trial-all.json +0 -16532
- package/src/proof/z9.lean +0 -126
- package/src/proof/z9plus.lean +0 -345
- package/src/proofs.lisp +0 -170
- package/src/prove/emit.ts +0 -115
- package/src/prove/index.ts +0 -143
- package/src/prove/translate.ts +0 -638
- package/src/publication/index.ts +0 -362
- package/src/quantum/field.ts +0 -73
- package/src/quantum/tree.ts +0 -79
- package/src/receipts/1431b4c4-7950-8d7b-88d1-b633219692f8.json +0 -7
- package/src/receipts/171e09c0-4cfd-8ce0-a6ed-cd33d5553da3.json +0 -7
- package/src/receipts/1a1f16c9-3491-8050-b221-e2a362439be4.json +0 -12
- package/src/receipts/1da15f83-83a6-8d04-b1ac-334c2dd6abb3.json +0 -7
- package/src/receipts/375a57ed-ef99-855e-8f34-b77d08010f3c.json +0 -6
- package/src/receipts/3dcbbf9e-0e49-8ba7-921e-17e478dbafaf.json +0 -6
- package/src/receipts/43a24136-5ad9-81ef-97c9-17be1c05bb5f.json +0 -11
- package/src/receipts/4991be51-74ba-8f66-9534-e6dba52fb569.json +0 -10
- package/src/receipts/52375d8f-232b-8c01-9d82-a824ffa7b2b7.json +0 -6
- package/src/receipts/593b546a-36b4-8553-941a-0e03b7053a64.json +0 -7
- package/src/receipts/7f75c989-96c9-8a24-8d0d-7e690861ccb4.json +0 -6
- package/src/receipts/80f80b59-81d8-866d-9a14-f469729d3dc8.json +0 -6
- package/src/receipts/85ac8585-9dc1-8964-9848-ae0f49cc82fb.json +0 -7
- package/src/receipts/85db092e-f2c0-88e5-bf75-61c4a65d84e7.json +0 -7
- package/src/receipts/95bacad3-9e56-8741-b0f8-def2c6ecb050.json +0 -7
- package/src/receipts/a1d33966-7bbd-84ca-902b-49e315af60e0.json +0 -6
- package/src/receipts/b20ced61-24ad-8123-adee-56031ab734dd.json +0 -11
- package/src/receipts/ba0447cd-f489-841a-a70f-a39b18ec2946.json +0 -11
- package/src/receipts/bcddbe66-06cf-8f31-a261-98b836938947.json +0 -7
- package/src/receipts/c1bac0d8-d906-8196-a4f0-3d8270b2e944.json +0 -6
- package/src/receipts/ce851ea3-3cf8-8646-a5d6-c0c6281210fe.json +0 -10
- package/src/receipts/cf43a122-c880-8d86-9e25-6f22f92d6b0a.json +0 -7
- package/src/receipts/daad8cd4-d4db-8dca-9c97-9a838cbce528.json +0 -7
- package/src/receipts/dc8bdb82-599f-8020-9eb2-cb016b408ec1.json +0 -6
- package/src/receipts/df77c265-d1a8-8354-8a9e-769fa5c676e2.json +0 -6
- package/src/receipts/e96686da-a411-8838-a5c8-ee7472bce048.json +0 -10
- package/src/receipts/f073c46f-7b67-83d0-aca5-db11fac4b5ec.json +0 -7
- package/src/receipts/f946d99d-a1c2-89f7-9426-a367c5b04191.json +0 -6
- package/src/receipts/fc069e45-115d-8983-ad25-fb9f735da84b.json +0 -6
- package/src/the/abstract/index.ts +0 -21
- package/src/the/abundance/index.ts +0 -20
- package/src/the/apple/earth/index.ts +0 -23
- package/src/the/apple/earth/navigation/index.ts +0 -28
- package/src/the/apple/earth/truth/index.ts +0 -19
- package/src/the/apple/index.ts +0 -27
- package/src/the/cancer/index.ts +0 -26
- package/src/the/clown/index.ts +0 -25
- package/src/the/creation/index.ts +0 -16
- package/src/the/crystal/index.ts +0 -23
- package/src/the/domain/index.ts +0 -16
- package/src/the/game/index.ts +0 -11
- package/src/the/gold/compass/index.ts +0 -26
- package/src/the/gold/index.ts +0 -35
- package/src/the/heart/index.ts +0 -15
- package/src/the/index.ts +0 -23
- package/src/the/law/index.ts +0 -20
- package/src/the/path/index.ts +0 -19
- package/src/the/rosetta/index.ts +0 -33
- package/src/the/sequence/index.ts +0 -12
- package/src/the/solids/index.ts +0 -25
- package/src/the/state/index.ts +0 -20
- package/src/the/superposition/state/index.ts +0 -22
- package/src/the/surface/index.ts +0 -26
- package/src/the/theorem/index.ts +0 -14
- package/src/the/torus/index.ts +0 -23
- package/src/the/waves/index.ts +0 -23
- package/the.md +0 -20
- package/verify.md +0 -67
package/src/latex/index.ts
DELETED
|
@@ -1,474 +0,0 @@
|
|
|
1
|
-
// LEAN → LATEX (and MathML), for the subset this deposit's statements actually use.
|
|
2
|
-
//
|
|
3
|
-
// The paper printed every statement as verbatim Lean. That is honest and it is hard to read: a reader who
|
|
4
|
-
// wants the mathematics has to parse `(List.range' 1 9).all (fun d => (List.range' 1 9).any (fun e =>
|
|
5
|
-
// M9 (d + e) == 0))` in their head. This translates that to ∀ d ∈ {1,…,9}, ∃ e ∈ {1,…,9} : M9(d+e) = 0.
|
|
6
|
-
//
|
|
7
|
-
// A TRANSLATION CAN LIE, so this one is built to refuse rather than approximate:
|
|
8
|
-
//
|
|
9
|
-
// · It is a real parser, not a chain of regex substitutions. A substitution pass silently produces
|
|
10
|
-
// plausible-looking output for input it did not understand, which is the worst possible failure here —
|
|
11
|
-
// a formula that reads as mathematics and is not the theorem.
|
|
12
|
-
// · Parsing is TOTAL or it FAILS. Every token must be consumed and every construct must be one this
|
|
13
|
-
// grammar knows; anything else throws, and the caller prints the verbatim Lean instead. There is no
|
|
14
|
-
// partial rendering.
|
|
15
|
-
// · The verbatim Lean stays on the page next to the typeset form. The kernel checked the Lean, not this.
|
|
16
|
-
// The rendering is a reading aid and is labelled as one.
|
|
17
|
-
//
|
|
18
|
-
// The vocabulary was derived by counting what the 460 statements contain, not guessed: `.all` (280),
|
|
19
|
-
// `.contains` (124), `.length` (120), `List.range` (113), `.map` (96), `List.range'` (82), `.eraseDups`
|
|
20
|
-
// (74), `.filter` (36), `.any` (33), `.foldl` (27), and the arithmetic and logical operators.
|
|
21
|
-
|
|
22
|
-
import { escapeHtml } from '../html/index.ts'
|
|
23
|
-
|
|
24
|
-
// ── tokens ───────────────────────────────────────────────────────────────────────────────────────────────
|
|
25
|
-
type Tok = { k: 'num' | 'id' | 'op'; v: string }
|
|
26
|
-
|
|
27
|
-
const OPS3 = ['>>>', '<<<']
|
|
28
|
-
const OPS2 = ['==', '!=', '<=', '>=', '=>', '++', '&&', '||', ':=']
|
|
29
|
-
const OPS1 = '+-*/%^<>=()[],.¬∧∨→↔≠≤≥·!:;'
|
|
30
|
-
|
|
31
|
-
export function lex(src: string): Tok[] {
|
|
32
|
-
const out: Tok[] = []
|
|
33
|
-
let i = 0
|
|
34
|
-
while (i < src.length) {
|
|
35
|
-
const c = src[i]
|
|
36
|
-
if (/\s/.test(c)) { i++; continue }
|
|
37
|
-
if (/[0-9]/.test(c)) {
|
|
38
|
-
let j = i; while (j < src.length && /[0-9]/.test(src[j])) j++
|
|
39
|
-
out.push({ k: 'num', v: src.slice(i, j) }); i = j; continue
|
|
40
|
-
}
|
|
41
|
-
if (/[A-Za-z_]/.test(c)) {
|
|
42
|
-
// A DOT JOINS THE NAME ONLY FOR A QUALIFIED CONSTANT — one whose namespace is capitalised, as
|
|
43
|
-
// Lean writes them: List.range, Families.gcd'. Treating any dot as part of the name swallowed
|
|
44
|
-
// `axis.contains d` into one identifier and rendered it `axis.contains(d)` instead of `d ∈ axis`:
|
|
45
|
-
// a silently plausible formula that was not the theorem, which is the one failure this module
|
|
46
|
-
// exists to prevent. A lowercase receiver ends the identifier, so the dot becomes a method call.
|
|
47
|
-
const qualified = /[A-Z]/.test(c)
|
|
48
|
-
let j = i
|
|
49
|
-
while (j < src.length && (/[A-Za-z0-9_']/.test(src[j]) || src[j] === '!' || src[j] === '?' || (qualified && src[j] === '.' && /[A-Za-z_]/.test(src[j + 1] ?? '')))) j++
|
|
50
|
-
out.push({ k: 'id', v: src.slice(i, j) }); i = j; continue
|
|
51
|
-
}
|
|
52
|
-
const three = src.slice(i, i + 3), two = src.slice(i, i + 2)
|
|
53
|
-
if (OPS3.includes(three)) { out.push({ k: 'op', v: three }); i += 3; continue }
|
|
54
|
-
if (OPS2.includes(two)) { out.push({ k: 'op', v: two }); i += 2; continue }
|
|
55
|
-
if (OPS1.includes(c)) { out.push({ k: 'op', v: c }); i++; continue }
|
|
56
|
-
throw new Error('lex: unexpected character ' + JSON.stringify(c))
|
|
57
|
-
}
|
|
58
|
-
return out
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ── AST ──────────────────────────────────────────────────────────────────────────────────────────────────
|
|
62
|
-
export type Node =
|
|
63
|
-
| { t: 'num'; v: string }
|
|
64
|
-
| { t: 'id'; v: string }
|
|
65
|
-
| { t: 'bin'; op: string; l: Node; r: Node }
|
|
66
|
-
| { t: 'un'; op: string; e: Node }
|
|
67
|
-
| { t: 'app'; f: Node; a: Node }
|
|
68
|
-
| { t: 'dot'; o: Node; name: string }
|
|
69
|
-
| { t: 'lam'; ps: string[]; b: Node }
|
|
70
|
-
| { t: 'list'; xs: Node[] }
|
|
71
|
-
| { t: 'ite'; c: Node; a: Node; b: Node }
|
|
72
|
-
| { t: 'hole'; op: string } // (· + ·) — the operator section
|
|
73
|
-
| { t: 'asc'; e: Node; ty: Node } // (1 : Int) — a type ascription; the value is unchanged
|
|
74
|
-
| { t: 'tuple'; xs: Node[] } // (a, b)
|
|
75
|
-
| { t: 'proj'; o: Node; i: string } // p.1, p.2 — tuple projection
|
|
76
|
-
| { t: 'let'; name: string; e: Node; b: Node } // let x := e; body
|
|
77
|
-
|
|
78
|
-
const KEYWORD = new Set(['then', 'else', 'fun', 'if', 'let'])
|
|
79
|
-
|
|
80
|
-
class P {
|
|
81
|
-
i = 0
|
|
82
|
-
ts: Tok[]
|
|
83
|
-
// An explicit field, not a parameter property: this repo runs .ts through node directly, and node's
|
|
84
|
-
// strip-only TypeScript mode rejects `constructor(private ts: Tok[])`.
|
|
85
|
-
constructor(ts: Tok[]) { this.ts = ts }
|
|
86
|
-
peek(o = 0) { return this.ts[this.i + o] }
|
|
87
|
-
is(v: string, o = 0) { const t = this.peek(o); return !!t && t.v === v }
|
|
88
|
-
eat(v: string) { if (!this.is(v)) throw new Error('expected ' + v + ' got ' + (this.peek()?.v ?? 'EOF')); this.i++ }
|
|
89
|
-
done() { return this.i >= this.ts.length }
|
|
90
|
-
|
|
91
|
-
// Precedence, loosest first. Lean's real table is larger; this covers exactly what the statements use.
|
|
92
|
-
expr(): Node {
|
|
93
|
-
// `let x := e; body` — a local binding. Ten statements use it, and it is written as mathematics the way
|
|
94
|
-
// mathematics writes it: the body, then "where x = e". The binding is NOT substituted into the body;
|
|
95
|
-
// substituting would show the reader an expression the source does not contain.
|
|
96
|
-
if (this.is('let')) {
|
|
97
|
-
this.i++
|
|
98
|
-
const n = this.peek(); if (!n || n.k !== 'id') throw new Error('expected a name after let')
|
|
99
|
-
this.i++; this.eat(':='); const e = this.expr(); this.eat(';')
|
|
100
|
-
return { t: 'let', name: n.v, e, b: this.expr() }
|
|
101
|
-
}
|
|
102
|
-
return this.iff()
|
|
103
|
-
}
|
|
104
|
-
iff(): Node { let l = this.implies(); while (this.is('↔')) { this.i++; l = { t: 'bin', op: '↔', l, r: this.implies() } } return l }
|
|
105
|
-
implies(): Node { let l = this.or(); if (this.is('→')) { this.i++; return { t: 'bin', op: '→', l, r: this.implies() } } return l }
|
|
106
|
-
or(): Node { let l = this.and(); while (this.is('∨') || this.is('||')) { this.i++; l = { t: 'bin', op: '∨', l, r: this.and() } } return l }
|
|
107
|
-
and(): Node { let l = this.cmp(); while (this.is('∧') || this.is('&&')) { this.i++; l = { t: 'bin', op: '∧', l, r: this.cmp() } } return l }
|
|
108
|
-
cmp(): Node {
|
|
109
|
-
let l = this.shift()
|
|
110
|
-
while (['==', '=', '!=', '≠', '<=', '≤', '>=', '≥', '<', '>'].some((o) => this.is(o))) {
|
|
111
|
-
const op = this.peek()!.v; this.i++; l = { t: 'bin', op, l, r: this.shift() }
|
|
112
|
-
}
|
|
113
|
-
return l
|
|
114
|
-
}
|
|
115
|
-
shift(): Node { let l = this.add(); while (this.is('>>>') || this.is('<<<')) { const op = this.peek()!.v; this.i++; l = { t: 'bin', op, l, r: this.add() } } return l }
|
|
116
|
-
add(): Node { let l = this.mul(); while (this.is('+') || this.is('-') || this.is('++')) { const op = this.peek()!.v; this.i++; l = { t: 'bin', op, l, r: this.mul() } } return l }
|
|
117
|
-
mul(): Node { let l = this.pow(); while (this.is('*') || this.is('/') || this.is('%')) { const op = this.peek()!.v; this.i++; l = { t: 'bin', op, l, r: this.pow() } } return l }
|
|
118
|
-
pow(): Node { const l = this.unary(); if (this.is('^')) { this.i++; return { t: 'bin', op: '^', l, r: this.pow() } } return l }
|
|
119
|
-
unary(): Node { if (this.is('¬') || this.is('!')) { this.i++; return { t: 'un', op: '¬', e: this.unary() } } if (this.is('-')) { this.i++; return { t: 'un', op: '-', e: this.unary() } } return this.appl() }
|
|
120
|
-
|
|
121
|
-
/** Application is juxtaposition: `M9 (d + e)`, `List.range 9`, `refl (refl d)`. */
|
|
122
|
-
appl(): Node {
|
|
123
|
-
let f = this.post()
|
|
124
|
-
while (!this.done() && this.startsAtom()) f = { t: 'app', f, a: this.post() }
|
|
125
|
-
return f
|
|
126
|
-
}
|
|
127
|
-
startsAtom(): boolean {
|
|
128
|
-
const t = this.peek()!
|
|
129
|
-
// `then` and `else` lex as identifiers, so juxtaposition happily consumed them as arguments and the
|
|
130
|
-
// whole `if _ then _ else _` failed to parse. They terminate an application instead.
|
|
131
|
-
if (t.k === 'id') return !KEYWORD.has(t.v)
|
|
132
|
-
if (t.k === 'num') return true
|
|
133
|
-
return t.v === '(' || t.v === '['
|
|
134
|
-
}
|
|
135
|
-
post(): Node {
|
|
136
|
-
let e = this.atom()
|
|
137
|
-
while (this.is('.')) {
|
|
138
|
-
this.i++
|
|
139
|
-
const n = this.peek()
|
|
140
|
-
if (!n) throw new Error('expected method name')
|
|
141
|
-
// `p.1` is a projection, not a method — the dot is followed by a numeral.
|
|
142
|
-
if (n.k === 'num') { this.i++; e = { t: 'proj', o: e, i: n.v }; continue }
|
|
143
|
-
if (n.k !== 'id') throw new Error('expected method name')
|
|
144
|
-
this.i++; e = { t: 'dot', o: e, name: n.v }
|
|
145
|
-
}
|
|
146
|
-
return e
|
|
147
|
-
}
|
|
148
|
-
atom(): Node {
|
|
149
|
-
const t = this.peek()
|
|
150
|
-
if (!t) throw new Error('unexpected end of statement')
|
|
151
|
-
if (t.k === 'num') { this.i++; return { t: 'num', v: t.v } }
|
|
152
|
-
if (t.v === 'fun') {
|
|
153
|
-
// SEVERAL PARAMETERS. `fun acc i => …` binds two; reading only the first left the second where the
|
|
154
|
-
// arrow was expected, which is the "expected => got i" this grammar used to fail on. Curried into
|
|
155
|
-
// nested lambdas, which is what Lean means by it.
|
|
156
|
-
this.i++
|
|
157
|
-
const ps: string[] = []
|
|
158
|
-
while (this.peek() && this.peek()!.k === 'id' && !this.is('=>')) { ps.push(this.peek()!.v); this.i++ }
|
|
159
|
-
if (!ps.length) throw new Error('expected lambda parameter')
|
|
160
|
-
this.eat('=>')
|
|
161
|
-
// The parameter LIST is kept, not curried into nested lambdas. Currying is what Lean means, but
|
|
162
|
-
// unparse then writes back an extra `fun` and `=>` per parameter and the round-trip reports a loss
|
|
163
|
-
// that never happened. The tree records what was written.
|
|
164
|
-
return { t: 'lam', ps, b: this.expr() }
|
|
165
|
-
}
|
|
166
|
-
if (t.v === 'if') {
|
|
167
|
-
this.i++; const c = this.expr(); this.eat('then'); const a = this.expr(); this.eat('else'); const b = this.expr()
|
|
168
|
-
return { t: 'ite', c, a, b }
|
|
169
|
-
}
|
|
170
|
-
if (t.k === 'id') { this.i++; return { t: 'id', v: t.v } }
|
|
171
|
-
if (t.v === '(') {
|
|
172
|
-
this.i++
|
|
173
|
-
// the operator section (· + ·) — a lambda written in Lean's dot notation
|
|
174
|
-
if (this.is('·')) {
|
|
175
|
-
this.i++; const op = this.peek(); if (!op || op.k !== 'op') throw new Error('expected operator in section')
|
|
176
|
-
this.i++; this.eat('·'); this.eat(')')
|
|
177
|
-
return { t: 'hole', op: op.v }
|
|
178
|
-
}
|
|
179
|
-
const e = this.expr()
|
|
180
|
-
// `(1 : Int)` — an ascription names the type and leaves the value alone. The type is KEPT in the tree
|
|
181
|
-
// so unparse can put it back; only the rendering drops it, because a reader of the mathematics wants
|
|
182
|
-
// the value and the round-trip wants every token.
|
|
183
|
-
if (this.is(':')) { this.i++; const ty = this.expr(); this.eat(')'); return { t: 'asc', e, ty } }
|
|
184
|
-
if (this.is(',')) {
|
|
185
|
-
const xs = [e]
|
|
186
|
-
while (this.is(',')) { this.i++; xs.push(this.expr()) }
|
|
187
|
-
this.eat(')'); return { t: 'tuple', xs }
|
|
188
|
-
}
|
|
189
|
-
this.eat(')'); return e
|
|
190
|
-
}
|
|
191
|
-
if (t.v === '[') {
|
|
192
|
-
this.i++
|
|
193
|
-
const xs: Node[] = []
|
|
194
|
-
if (!this.is(']')) { xs.push(this.expr()); while (this.is(',')) { this.i++; xs.push(this.expr()) } }
|
|
195
|
-
this.eat(']')
|
|
196
|
-
return { t: 'list', xs }
|
|
197
|
-
}
|
|
198
|
-
throw new Error('unexpected token ' + JSON.stringify(t.v))
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Parse a statement, or throw. Throwing is the point: the caller prints the Lean source instead. */
|
|
203
|
-
export function parse(src: string): Node {
|
|
204
|
-
const p = new P(lex(src))
|
|
205
|
-
const e = p.expr()
|
|
206
|
-
if (!p.done()) throw new Error('trailing tokens from ' + JSON.stringify(p.peek()!.v))
|
|
207
|
-
return e
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
/** `.filter f` and `.all f` pass a FUNCTION, not a lambda — `instruments.filter claim`. The set-builder
|
|
212
|
-
* needs a bound variable the source never wrote, so one is supplied. `x` is chosen because these
|
|
213
|
-
* statements bind d, e, k, n, p, u and t, never x; a collision would shadow a real binder. */
|
|
214
|
-
const BOUND = 'x'
|
|
215
|
-
const applied = (f: Node, texOf: (n: Node) => string) => `${texOf(f)}\\mathopen{}\\left(${BOUND}\\right)`
|
|
216
|
-
|
|
217
|
-
// ── LaTeX ────────────────────────────────────────────────────────────────────────────────────────────────
|
|
218
|
-
export const LATEX_NAME: Record<string, string> = { '==': '=', '=': '=', '!=': '\\neq', '≠': '\\neq', '<=': '\\le', '≤': '\\le', '>=': '\\ge', '≥': '\\ge', '<': '<', '>': '>', '+': '+', '-': '-', '*': '\\cdot', '/': '/', '%': '\\bmod', '∧': '\\land', '∨': '\\lor', '→': '\\to', '↔': '\\leftrightarrow', '++': '\\mathbin{+\\!\\!+}' }
|
|
219
|
-
|
|
220
|
-
const idTex = (v: string) => (/^[a-zA-Z]$/.test(v) ? v : '\\mathrm{' + v.replace(/_/g, '\\_') + '}')
|
|
221
|
-
|
|
222
|
-
/** The domain a range denotes, as a set. List.range n = [0,…,n-1]; List.range' a n = [a,…,a+n-1]. */
|
|
223
|
-
const num = (n: Node): number | null => (n.t === 'num' ? Number(n.v) : null)
|
|
224
|
-
const rangeTex = (f: Node, args: Node[]): string | null => {
|
|
225
|
-
if (f.t !== 'id') return null
|
|
226
|
-
// With literal bounds the set is written out — {1,…,9}, not {1,…,1+9-1}, which is the same set
|
|
227
|
-
// spelled as the arithmetic that produced it.
|
|
228
|
-
if (f.v === 'List.range' && args.length === 1) {
|
|
229
|
-
const n = num(args[0])
|
|
230
|
-
return n !== null ? `\\{0,\\dots,${n - 1}\\}` : `\\{0,\\dots,${tex(args[0])}-1\\}`
|
|
231
|
-
}
|
|
232
|
-
if (f.v === "List.range'" && args.length === 2) {
|
|
233
|
-
const a = num(args[0]), k = num(args[1])
|
|
234
|
-
return a !== null && k !== null ? `\\{${a},\\dots,${a + k - 1}\\}` : `\\{${tex(args[0])},\\dots,${tex(args[0])}+${tex(args[1])}-1\\}`
|
|
235
|
-
}
|
|
236
|
-
return null
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/** Flatten an application spine into head + arguments. */
|
|
240
|
-
const spine = (n: Node): { head: Node; args: Node[] } => {
|
|
241
|
-
const args: Node[] = []
|
|
242
|
-
let h = n
|
|
243
|
-
while (h.t === 'app') { args.unshift(h.a); h = h.f }
|
|
244
|
-
return { head: h, args }
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export function tex(n: Node): string {
|
|
248
|
-
switch (n.t) {
|
|
249
|
-
case 'num': return n.v
|
|
250
|
-
case 'id': return idTex(n.v)
|
|
251
|
-
case 'hole': return `(\\cdot\\,${LATEX_NAME[n.op] ?? n.op}\\,\\cdot)`
|
|
252
|
-
case 'un': return n.op === '¬' ? `\\lnot ${tex(n.e)}` : `-${tex(n.e)}`
|
|
253
|
-
case 'lam': return `${n.ps.map(idTex).join(',\\,')} \\mapsto ${tex(n.b)}`
|
|
254
|
-
case 'list': return `[${n.xs.map(tex).join(',\\,')}]`
|
|
255
|
-
case 'asc': return tex(n.e)
|
|
256
|
-
case 'tuple': return `\\left(${n.xs.map(tex).join(',\\,')}\\right)`
|
|
257
|
-
case 'proj': return `${tex(n.o)}_{${n.i}}`
|
|
258
|
-
case 'let': return `${tex(n.b)} \\quad \\text{where } ${idTex(n.name)} = ${tex(n.e)}`
|
|
259
|
-
case 'ite': return `\\begin{cases}${tex(n.a)} & \\text{if } ${tex(n.c)}\\\\ ${tex(n.b)} & \\text{otherwise}\\end{cases}`
|
|
260
|
-
case 'bin': {
|
|
261
|
-
const l = tex(n.l), r = tex(n.r)
|
|
262
|
-
if (n.op === '^') return `${l}^{${r}}`
|
|
263
|
-
if (n.op === '/') return `\\frac{${l}}{${r}}`
|
|
264
|
-
if (n.op === '%') return `${l} \\bmod ${r}`
|
|
265
|
-
if (n.op === '>>>') return `${l} \\gg ${r}`
|
|
266
|
-
if (n.op === '<<<') return `${l} \\ll ${r}`
|
|
267
|
-
return `${l} ${LATEX_NAME[n.op] ?? n.op} ${r}`
|
|
268
|
-
}
|
|
269
|
-
case 'dot': return dotTex(n, [])
|
|
270
|
-
case 'app': {
|
|
271
|
-
const { head, args } = spine(n)
|
|
272
|
-
const r = rangeTex(head, args)
|
|
273
|
-
if (r) return r
|
|
274
|
-
if (head.t === 'dot') return dotTex(head, args)
|
|
275
|
-
return `${tex(head)}\\mathopen{}\\left(${args.map(tex).join(',\\,')}\\right)`
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/** A method call, rendered as the mathematics it means. Unknown methods throw — see the header. */
|
|
281
|
-
function dotTex(d: Extract<Node, { t: 'dot' }>, args: Node[]): string {
|
|
282
|
-
const o = tex(d.o)
|
|
283
|
-
const lam = (a: Node | undefined) => (a && a.t === 'lam' && a.ps.length === 1 ? a : null)
|
|
284
|
-
switch (d.name) {
|
|
285
|
-
case 'all': { const f = lam(args[0])
|
|
286
|
-
if (f) return `\\forall ${idTex(f.ps[0])} \\in ${o},\\; ${tex(f.b)}`
|
|
287
|
-
if (args.length === 1) return `\\forall ${BOUND} \\in ${o},\\; ${applied(args[0], tex)}`
|
|
288
|
-
break }
|
|
289
|
-
case 'any': { const f = lam(args[0])
|
|
290
|
-
if (f) return `\\exists ${idTex(f.ps[0])} \\in ${o} : ${tex(f.b)}`
|
|
291
|
-
if (args.length === 1) return `\\exists ${BOUND} \\in ${o} : ${applied(args[0], tex)}`
|
|
292
|
-
break }
|
|
293
|
-
case 'filter': { const f = lam(args[0])
|
|
294
|
-
if (f) return `\\{\\, ${idTex(f.ps[0])} \\in ${o} \\mid ${tex(f.b)} \\,\\}`
|
|
295
|
-
if (args.length === 1) return `\\{\\, ${BOUND} \\in ${o} \\mid ${applied(args[0], tex)} \\,\\}`
|
|
296
|
-
break }
|
|
297
|
-
case 'map': { const f = lam(args[0]); if (f) return `\\{\\, ${tex(f.b)} \\mid ${idTex(f.ps[0])} \\in ${o} \\,\\}`; if (args.length === 1) return `${tex(args[0])}[${o}]` ; break }
|
|
298
|
-
case 'length': if (!args.length) return `\\left|${o}\\right|`; break
|
|
299
|
-
case 'contains': if (args.length === 1) return `${tex(args[0])} \\in ${o}`; break
|
|
300
|
-
case 'eraseDups': if (!args.length) return `\\operatorname{dedup}\\left(${o}\\right)`; break
|
|
301
|
-
case 'flatMap': { const f = lam(args[0]); if (!f) break
|
|
302
|
-
return `\\bigcup_{${idTex(f.ps[0])} \\in ${o}} ${tex(f.b)}` }
|
|
303
|
-
case 'foldr':
|
|
304
|
-
case 'foldl': {
|
|
305
|
-
// foldl (· + ·) 0 is a sum and nothing else here is; anything other than that exact shape falls
|
|
306
|
-
// through to the throw, rather than being rendered as a sum it is not.
|
|
307
|
-
if (args.length === 2 && args[0].t === 'hole' && args[0].op === '+' && args[1].t === 'num' && args[1].v === '0')
|
|
308
|
-
return `\\sum ${o}`
|
|
309
|
-
// Any other fold is named rather than given a symbol it does not have: an operator and a seed,
|
|
310
|
-
// applied along the list. Inventing ∑-like notation for an arbitrary combiner would say more than
|
|
311
|
-
// the statement does.
|
|
312
|
-
if (args.length === 2) return `\\operatorname{fold}_{${tex(args[0])}}\\left(${o},\\, ${tex(args[1])}\\right)`
|
|
313
|
-
break
|
|
314
|
-
}
|
|
315
|
-
case 'get!': if (args.length === 1) return `${o}_{${tex(args[0])}}`; break
|
|
316
|
-
case 'head?': if (!args.length) return `\\operatorname{head}\\left(${o}\\right)`; break
|
|
317
|
-
case 'getLast?': if (!args.length) return `\\operatorname{last}\\left(${o}\\right)`; break
|
|
318
|
-
// Option's two predicates. `(invOf d).isSome` is how a statement says "an inverse EXISTS", and without
|
|
319
|
-
// notation for it the whole site build died on the one theorem that said so — see the note in
|
|
320
|
-
// src/publication/index.ts. Rendered as the existence it means, not as the method it is spelled with.
|
|
321
|
-
case 'isSome': if (!args.length) return `\\exists\\,${o}`; break
|
|
322
|
-
case 'isNone': if (!args.length) return `\\nexists\\,${o}`; break
|
|
323
|
-
case 'reverse': if (!args.length) return `\\operatorname{reverse}\\left(${o}\\right)`; break
|
|
324
|
-
case 'sum': if (!args.length) return `\\sum ${o}`; break
|
|
325
|
-
}
|
|
326
|
-
throw new Error('no notation for method .' + d.name + ' with ' + args.length + ' argument(s)')
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/** Lean source → LaTeX, or null when this grammar does not cover it. Never a partial rendering. */
|
|
330
|
-
export function toLatex(statement: string): string | null {
|
|
331
|
-
try { return tex(parse(statement)) } catch { return null }
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// ── MathML ───────────────────────────────────────────────────────────────────────────────────────────────
|
|
335
|
-
// Emitted from the SAME tree as the LaTeX, so the typeset page and the copyable LaTeX cannot disagree.
|
|
336
|
-
// MathML is rendered natively by browsers, which keeps the page free of a maths library and a CDN.
|
|
337
|
-
const X = escapeHtml
|
|
338
|
-
const mo = (s: string) => `<mo>${X(s)}</mo>`
|
|
339
|
-
const mi = (s: string) => `<mi>${X(s)}</mi>`
|
|
340
|
-
const MOP: Record<string, string> = { '==': '=', '=': '=', '!=': '≠', '≠': '≠', '<=': '≤', '≤': '≤', '>=': '≥', '≥': '≥', '∧': '∧', '∨': '∨', '→': '→', '↔': '↔', '*': '⋅', '%': 'mod', '++': '⧺' }
|
|
341
|
-
|
|
342
|
-
function ml(n: Node): string {
|
|
343
|
-
switch (n.t) {
|
|
344
|
-
case 'num': return `<mn>${X(n.v)}</mn>`
|
|
345
|
-
case 'id': return mi(n.v)
|
|
346
|
-
case 'hole': return `<mrow>${mo('(')}${mo('·')}${mo(MOP[n.op] ?? n.op)}${mo('·')}${mo(')')}</mrow>`
|
|
347
|
-
case 'un': return `<mrow>${mo(n.op === '¬' ? '¬' : '−')}${ml(n.e)}</mrow>`
|
|
348
|
-
case 'lam': return `<mrow>${n.ps.map(mi).join(mo(','))}${mo('↦')}${ml(n.b)}</mrow>`
|
|
349
|
-
case 'list': return `<mrow>${mo('[')}${n.xs.map(ml).join(mo(','))}${mo(']')}</mrow>`
|
|
350
|
-
case 'asc': return ml(n.e)
|
|
351
|
-
case 'tuple': return `<mrow>${mo('(')}${n.xs.map(ml).join(mo(','))}${mo(')')}</mrow>`
|
|
352
|
-
case 'proj': return `<msub>${ml(n.o)}<mn>${X(n.i)}</mn></msub>`
|
|
353
|
-
case 'let': return `<mrow>${ml(n.b)}${mo('where')}${mi(n.name)}${mo('=')}${ml(n.e)}</mrow>`
|
|
354
|
-
// Bracketed: unbracketed, `… = 1 if isUnit(d) ; otherwise 0 ∧ provenHere = 0` reads as though the
|
|
355
|
-
// conjunct were part of the else-branch.
|
|
356
|
-
case 'ite': return `<mrow>${mo('(')}${ml(n.a)}${mo('if')}${ml(n.c)}${mo(';')}${mo('otherwise')}${ml(n.b)}${mo(')')}</mrow>`
|
|
357
|
-
case 'bin': {
|
|
358
|
-
if (n.op === '^') return `<msup>${ml(n.l)}${ml(n.r)}</msup>`
|
|
359
|
-
if (n.op === '/') return `<mfrac>${ml(n.l)}${ml(n.r)}</mfrac>`
|
|
360
|
-
if (n.op === '>>>') return `<mrow>${ml(n.l)}${mo('≫')}${ml(n.r)}</mrow>`
|
|
361
|
-
if (n.op === '<<<') return `<mrow>${ml(n.l)}${mo('≪')}${ml(n.r)}</mrow>`
|
|
362
|
-
return `<mrow>${ml(n.l)}${mo(MOP[n.op] ?? n.op)}${ml(n.r)}</mrow>`
|
|
363
|
-
}
|
|
364
|
-
case 'dot': return dotMl(n, [])
|
|
365
|
-
case 'app': {
|
|
366
|
-
const { head, args } = spine(n)
|
|
367
|
-
if (head.t === 'id' && (head.v === 'List.range' || head.v === "List.range'")) {
|
|
368
|
-
// The SAME literal-bound simplification the LaTeX emitter applies. It was written only there, so
|
|
369
|
-
// one tree produced {0,…,8} in LaTeX and {0,…,9−1} in MathML — two renderings of one theorem
|
|
370
|
-
// disagreeing, in the module whose header claims they cannot.
|
|
371
|
-
const a = head.v === 'List.range' ? 0 : num(args[0])
|
|
372
|
-
const k = head.v === 'List.range' ? num(args[0]) : num(args[1])
|
|
373
|
-
const lo = head.v === 'List.range' ? '<mn>0</mn>' : ml(args[0])
|
|
374
|
-
if (a !== null && k !== null)
|
|
375
|
-
return `<mrow>${mo('{')}<mn>${a}</mn>${mo(',')}${mo('…')}${mo(',')}<mn>${a + k - 1}</mn>${mo('}')}</mrow>`
|
|
376
|
-
const hi = head.v === 'List.range'
|
|
377
|
-
? `<mrow>${ml(args[0])}${mo('−')}<mn>1</mn></mrow>`
|
|
378
|
-
: `<mrow>${ml(args[0])}${mo('+')}${ml(args[1])}${mo('−')}<mn>1</mn></mrow>`
|
|
379
|
-
return `<mrow>${mo('{')}${lo}${mo(',')}${mo('…')}${mo(',')}${hi}${mo('}')}</mrow>`
|
|
380
|
-
}
|
|
381
|
-
if (head.t === 'dot') return dotMl(head, args)
|
|
382
|
-
return `<mrow>${ml(head)}${mo('(')}${args.map(ml).join(mo(','))}${mo(')')}</mrow>`
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
function dotMl(d: Extract<Node, { t: 'dot' }>, args: Node[]): string {
|
|
388
|
-
const o = ml(d.o)
|
|
389
|
-
const lam = (a: Node | undefined) => (a && a.t === 'lam' && a.ps.length === 1 ? a : null)
|
|
390
|
-
switch (d.name) {
|
|
391
|
-
case 'all': { const f = lam(args[0])
|
|
392
|
-
if (f) return `<mrow>${mo('∀')}${mi(f.ps[0])}${mo('∈')}${o}${mo(',')}${ml(f.b)}</mrow>`
|
|
393
|
-
if (args.length === 1) return `<mrow>${mo('∀')}${mi(BOUND)}${mo('∈')}${o}${mo(',')}${ml(args[0])}${mo('(')}${mi(BOUND)}${mo(')')}</mrow>`
|
|
394
|
-
break }
|
|
395
|
-
case 'any': { const f = lam(args[0])
|
|
396
|
-
if (f) return `<mrow>${mo('∃')}${mi(f.ps[0])}${mo('∈')}${o}${mo(':')}${ml(f.b)}</mrow>`
|
|
397
|
-
if (args.length === 1) return `<mrow>${mo('∃')}${mi(BOUND)}${mo('∈')}${o}${mo(':')}${ml(args[0])}${mo('(')}${mi(BOUND)}${mo(')')}</mrow>`
|
|
398
|
-
break }
|
|
399
|
-
case 'filter': { const f = lam(args[0])
|
|
400
|
-
if (f) return `<mrow>${mo('{')}${mi(f.ps[0])}${mo('∈')}${o}${mo('∣')}${ml(f.b)}${mo('}')}</mrow>`
|
|
401
|
-
if (args.length === 1) return `<mrow>${mo('{')}${mi(BOUND)}${mo('∈')}${o}${mo('∣')}${ml(args[0])}${mo('(')}${mi(BOUND)}${mo(')')}${mo('}')}</mrow>`
|
|
402
|
-
break }
|
|
403
|
-
case 'map': { const f = lam(args[0]); if (f) return `<mrow>${mo('{')}${ml(f.b)}${mo('∣')}${mi(f.ps[0])}${mo('∈')}${o}${mo('}')}</mrow>`; if (args.length === 1) return `<mrow>${ml(args[0])}${mo('[')}${o}${mo(']')}</mrow>`; break }
|
|
404
|
-
case 'length': if (!args.length) return `<mrow>${mo('|')}${o}${mo('|')}</mrow>`; break
|
|
405
|
-
case 'contains': if (args.length === 1) return `<mrow>${ml(args[0])}${mo('∈')}${o}</mrow>`; break
|
|
406
|
-
case 'eraseDups': if (!args.length) return `<mrow>${mi('dedup')}${mo('(')}${o}${mo(')')}</mrow>`; break
|
|
407
|
-
case 'flatMap': { const f = lam(args[0]); if (!f) break
|
|
408
|
-
return `<mrow>${mo('⋃')}${mi(f.ps[0])}${mo('∈')}${o}${mo(',')}${ml(f.b)}</mrow>` }
|
|
409
|
-
case 'foldr':
|
|
410
|
-
case 'foldl':
|
|
411
|
-
if (args.length === 2 && args[0].t === 'hole' && args[0].op === '+' && args[1].t === 'num' && args[1].v === '0')
|
|
412
|
-
return `<mrow>${mo('∑')}${o}</mrow>`
|
|
413
|
-
if (args.length === 2) return `<mrow>${mi('fold')}${mo('(')}${ml(args[0])}${mo(',')}${o}${mo(',')}${ml(args[1])}${mo(')')}</mrow>`
|
|
414
|
-
break
|
|
415
|
-
case 'get!': if (args.length === 1) return `<msub>${o}${ml(args[0])}</msub>`; break
|
|
416
|
-
case 'head?': if (!args.length) return `<mrow>${mi('head')}${mo('(')}${o}${mo(')')}</mrow>`; break
|
|
417
|
-
case 'getLast?': if (!args.length) return `<mrow>${mi('last')}${mo('(')}${o}${mo(')')}</mrow>`; break
|
|
418
|
-
case 'reverse': if (!args.length) return `<mrow>${mi('reverse')}${mo('(')}${o}${mo(')')}</mrow>`; break
|
|
419
|
-
// the Option predicates, in the SAME reading as the LaTeX above — latex-gate exists to catch exactly
|
|
420
|
-
// the case where one emitter learns a notation and the other does not, and it caught this one
|
|
421
|
-
case 'isSome': if (!args.length) return `<mrow>${mo('∃')}${o}</mrow>`; break
|
|
422
|
-
case 'isNone': if (!args.length) return `<mrow>${mo('∄')}${o}</mrow>`; break
|
|
423
|
-
case 'sum': if (!args.length) return `<mrow>${mo('∑')}${o}</mrow>`; break
|
|
424
|
-
}
|
|
425
|
-
throw new Error('no notation for method .' + d.name)
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/** Lean source → MathML, or null when this grammar does not cover it. */
|
|
429
|
-
export function toMathML(statement: string): string | null {
|
|
430
|
-
try { return `<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">${ml(parse(statement))}</math>` } catch { return null }
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// ── round-trip, so a wrong parse cannot pass quietly ─────────────────────────────────────────────────────
|
|
434
|
-
// Throwing catches input the grammar does not know. It does NOT catch input the grammar mis-reads: the
|
|
435
|
-
// lexer once folded `axis.contains d` into a single identifier and rendered `axis.contains(d)` — no error,
|
|
436
|
-
// wrong formula. So the tree is written back out as Lean and the token sequence compared with the source.
|
|
437
|
-
// A parse that dropped, duplicated or reordered anything fails here.
|
|
438
|
-
//
|
|
439
|
-
// ITS LIMIT, STATED: parentheses are excluded from the comparison (the tree does not record where the
|
|
440
|
-
// source put redundant ones), so this verifies that the same symbols were read in the same order — it does
|
|
441
|
-
// NOT prove the operators were grouped with the right precedence. Precedence is covered separately by the
|
|
442
|
-
// assertions in scripts/latex-gate.ts, against Lean's own table.
|
|
443
|
-
export function unparse(n: Node): string {
|
|
444
|
-
switch (n.t) {
|
|
445
|
-
case 'num': return n.v
|
|
446
|
-
case 'id': return n.v
|
|
447
|
-
case 'hole': return `(· ${n.op} ·)`
|
|
448
|
-
case 'un': return `(${n.op} ${unparse(n.e)})`
|
|
449
|
-
case 'lam': return `(fun ${n.ps.join(' ')} => ${unparse(n.b)})`
|
|
450
|
-
case 'list': return `[${n.xs.map(unparse).join(', ')}]`
|
|
451
|
-
case 'asc': return `(${unparse(n.e)} : ${unparse(n.ty)})`
|
|
452
|
-
case 'tuple': return `(${n.xs.map(unparse).join(', ')})`
|
|
453
|
-
case 'proj': return `(${unparse(n.o)}).${n.i}`
|
|
454
|
-
case 'let': return `let ${n.name} := ${unparse(n.e)}; ${unparse(n.b)}`
|
|
455
|
-
case 'ite': return `(if ${unparse(n.c)} then ${unparse(n.a)} else ${unparse(n.b)})`
|
|
456
|
-
case 'bin': return `(${unparse(n.l)} ${n.op} ${unparse(n.r)})`
|
|
457
|
-
case 'dot': return `(${unparse(n.o)}).${n.name}`
|
|
458
|
-
case 'app': return `(${unparse(n.f)} ${unparse(n.a)})`
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Lean spells several operators two ways and the parser keeps one of them, so the comparison canonicalises
|
|
463
|
-
// both sides. Without this the check reported 72 failures that were only `||` against `∨` — a check that
|
|
464
|
-
// cries wolf gets switched off, which is its own way of proving nothing.
|
|
465
|
-
const CANON: Record<string, string> = { '||': '∨', '&&': '∧', '==': '=', '!=': '≠', '<=': '≤', '>=': '≥', '!': '¬' }
|
|
466
|
-
|
|
467
|
-
/** The token sequence with grouping removed and spellings canonicalised — what the round-trip compares. */
|
|
468
|
-
export const shape = (src: string): string =>
|
|
469
|
-
lex(src).filter((t) => !'()'.includes(t.v)).map((t) => CANON[t.v] ?? t.v).join(' ')
|
|
470
|
-
|
|
471
|
-
/** True when the parse read exactly the symbols the source contains, in order. */
|
|
472
|
-
export function roundTrips(statement: string): boolean {
|
|
473
|
-
try { return shape(unparse(parse(statement))) === shape(statement) } catch { return false }
|
|
474
|
-
}
|
package/src/millennium/index.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// THE SEVEN, in problem order — the qualified outlet and the honest bound for each Clay problem this
|
|
2
|
-
// framework has a theorem ADJACENT to. This lived only in theorem/[key].paths.ts, so the collected paper had
|
|
3
|
-
// no way to say which of its theorems sit at the Millennium floor without the bounds being retyped into a
|
|
4
|
-
// second place — and a retyped bound is a bound that can drift from the one the theorem page shows.
|
|
5
|
-
//
|
|
6
|
-
// The `bound` is the load-bearing field. It states what the theorem actually establishes and, explicitly,
|
|
7
|
-
// what it does NOT: none of these is the conjecture, and provenHere = 0.
|
|
8
|
-
export const MILLENNIUM: Record<string, { problem: string; name: string; bound: string; outlet: string; outletName: string; outlet2?: string; outlet2Name?: string }> = {
|
|
9
|
-
riemann_reflection_and_heart: {
|
|
10
|
-
problem: 'Riemann Hypothesis',
|
|
11
|
-
name: "Riemann — the reflection's symmetry and its one computed heart",
|
|
12
|
-
bound: 'the functional-equation symmetry axis and its ½-analogue centre (the heart, computed as the reflection’s unique fixed point) — not where the ζ-zeros lie',
|
|
13
|
-
outlet: 'https://www.claymath.org/millennium/riemann-hypothesis/',
|
|
14
|
-
outletName: 'Clay Mathematics Institute — Riemann Hypothesis' },
|
|
15
|
-
p_vs_np_inverse_is_unique: {
|
|
16
|
-
problem: 'P versus NP',
|
|
17
|
-
name: 'P vs NP — a unique inverse, verification in one step',
|
|
18
|
-
bound: 'each unit has exactly one inverse (verify in one multiply), non-units none — a cheap-verification fact, not a separation of the classes',
|
|
19
|
-
outlet: 'https://www.claymath.org/millennium/p-vs-np/',
|
|
20
|
-
outletName: 'Clay Mathematics Institute — P vs NP' },
|
|
21
|
-
navier_stokes_flow_is_bounded: {
|
|
22
|
-
problem: 'Navier–Stokes Existence & Smoothness',
|
|
23
|
-
name: 'Navier–Stokes — the doubling flow is bounded for all time',
|
|
24
|
-
bound: 'every iterate stays inside a bounded 6-cycle forever (no blowup) — bounded evolution, not global existence & smoothness',
|
|
25
|
-
outlet: 'https://www.claymath.org/millennium/navier-stokes-equation/',
|
|
26
|
-
outletName: 'Clay Mathematics Institute — Navier–Stokes Equation' },
|
|
27
|
-
yang_mills_spectral_gap: {
|
|
28
|
-
problem: 'Yang–Mills Existence & Mass Gap',
|
|
29
|
-
name: 'Yang–Mills — a discrete spectral gap (order exactly 6)',
|
|
30
|
-
bound: 'the doubling has order exactly 6 — a discrete gap in the cyclic spectrum, not the Yang–Mills mass gap',
|
|
31
|
-
outlet: 'https://www.claymath.org/millennium/yang-mills-the-maths-gap/',
|
|
32
|
-
outletName: 'Clay Mathematics Institute — Yang–Mills & the Mass Gap' },
|
|
33
|
-
hodge_span_is_the_units: {
|
|
34
|
-
problem: 'Hodge Conjecture',
|
|
35
|
-
name: 'Hodge — the algebraic span equals the units',
|
|
36
|
-
bound: 'the doubling span (algebraic generation from 2) is exactly the units, non-units outside — generation/containment, not rational (p,p) ⇒ algebraic',
|
|
37
|
-
outlet: 'https://www.claymath.org/millennium/hodge-conjecture/',
|
|
38
|
-
outletName: 'Clay Mathematics Institute — Hodge Conjecture' },
|
|
39
|
-
birch_swinnerton_dyer_vanishing: {
|
|
40
|
-
problem: 'Birch and Swinnerton-Dyer Conjecture',
|
|
41
|
-
name: 'Birch–Swinnerton-Dyer — a computed vanishing mod 9',
|
|
42
|
-
bound: 'the orbit and the units both sum to 0 mod 9 (27 ≡ 0) — a digit-sum vanishing, not the rank ↔ order-of-vanishing-of-L correspondence',
|
|
43
|
-
outlet: 'https://www.claymath.org/millennium/birch-and-swinnerton-dyer-conjecture/',
|
|
44
|
-
outletName: 'Clay Mathematics Institute — Birch and Swinnerton-Dyer Conjecture' },
|
|
45
|
-
poincare_single_closed_loop: {
|
|
46
|
-
problem: 'Poincaré Conjecture (resolved)',
|
|
47
|
-
name: 'Poincaré — one closed loop, no holes',
|
|
48
|
-
bound: "the sequence closes into a single simple loop of six distinct steps — not the 3-sphere characterization; Poincaré is Perelman's theorem (2003), not proved here",
|
|
49
|
-
outlet: 'https://www.claymath.org/millennium/poincare-conjecture/',
|
|
50
|
-
outletName: 'Clay Mathematics Institute — Poincaré Conjecture',
|
|
51
|
-
outlet2: 'https://arxiv.org/abs/math/0211159',
|
|
52
|
-
outlet2Name: 'Perelman, G. — The entropy formula for the Ricci flow (arXiv:math/0211159) — the resolution' },
|
|
53
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// play the game — the act of playing. Run next: a wave discovers decidable facts, proves them, ships
|
|
2
|
-
// them; the games and their receipts fold to one; every move is kept iff it computes, else drained.
|
|
3
|
-
import { toUuid } from '../../../0/index.ts'
|
|
4
|
-
export function report(): string {
|
|
5
|
-
let o = 'play the game — the act:\n\n'
|
|
6
|
-
o += ' play: run next → a wave discovers decidable facts → proves them → ships them.\n'
|
|
7
|
-
o += ' the games (Nim, Wythoff, chess, tic-tac-toe, …) and their receipts fold to one root.\n'
|
|
8
|
-
o += ' the rules: measure · gate · due process · receipts · one game — all playable, all honest.\n'
|
|
9
|
-
o += ' a move is kept iff it computes; an over-reach is drained with a case. play, honestly.\n'
|
|
10
|
-
o += ' address: ' + toUuid('play-the-game').slice(0, 13) + '…'
|
|
11
|
-
return o
|
|
12
|
-
}
|