LOT · Lean Option Tree

Lean Check PipelineLean 检查流水线

How LOT checks machine-written Lean proofs, what each optimization of the trusted check removes, and how long a chain of obligations takes to check with and without them. Numbers are measured on the proof tree of The Hilbert–Smith conjecture in every finite dimension[1].

LOT 如何检查机器写出的 Lean 证明,可信检查的每项优化省掉了哪一部分,以及一条义务链在有无这些优化时各要查多久。数字来自 The Hilbert–Smith conjecture in every finite dimension[1] 这棵证明树的实测。

1Background背景

LOT (Lean Option Tree) proves a hard Lean 4[2] theorem by splitting it into a tree of frozen sub-theorems, called obligations. Many LLM agent sessions work on the tree at once: some try to prove an obligation directly, others split it into child statements plus a glue proof of the parent from them. Nothing is accepted on an agent's word. Every glue proof and every proof enters the tree only after a trusted check with the Lean-Eval checker[3]: the comparator[4], the independent nanoda kernel[5] and the Lean kernel itself. A visual tour of how LOT schedules this work is in [6].

LOT(Lean Option Tree)把一个困难的 Lean 4[2] 定理拆成一棵由冻结子定理(称为义务)组成的树。许多 LLM agent 会话同时在这棵树上工作:有的直接证明某个义务,有的把它拆成若干子命题,再写一个由子命题推出父命题的胶水证明。agent 自己说了不算:每个胶水证明和每个证明,都要先通过 Lean-Eval 检查器[3] 的可信检查才能进入树里,也就是 comparator[4]、独立的 nanoda 内核[5] 和 Lean 内核本身。LOT 如何调度这些工作,可以看 [6] 的可视化。

As trees grew to hundreds of obligations, checking rather than proving became the bottleneck. Our running example is the main theorem of The Hilbert–Smith conjecture in every finite dimension[1]. Its proof tree has 156 obligations; the root and the obligations below it that each have a single open child form a chain of 12 non-root levels. Every check on that chain re-verifies the same few very heavy proofs, about 11.5 hours per check with the original pipeline.

当一棵树长到几百个义务时,瓶颈从证明变成了检查。本文的例子是 The Hilbert–Smith conjecture in every finite dimension[1] 的主定理。它的证明树有 156 个义务;根和它下面各自只剩一个未完成子义务的那些义务连成一条链,共 12 个非根层。链上的每次检查都要重新验证同样几份非常重的证明,用原始流程每次约 11.5 小时。

2The original pipeline: one trusted check原始流程:一次可信检查

When Lean compiles a file[7], the kernel already checks every declaration before it is written to an .olean file. The trusted check trusts neither the elaborator nor the .olean files: it rebuilds in a sandbox, exports the whole environment as plain terms[8], has two independently written kernels re-check all of it, and finally confirms that the theorem's statement matches the frozen problem statement and that only permitted axioms are used. This is the validation procedure the Lean reference manual recommends for untrusted proofs[9].

Lean 编译时[7],每条声明在写进 .olean 文件之前就已经被内核检查过一次。可信检查不信任编译器和 .olean 文件:它在沙箱里重新编译,把整个环境导出成纯文本的项[8],交给两个独立实现的内核从头重查,最后核对定理命题与冻结的题面一致、只用了允许的公理。这正是 Lean 官方参考手册对不可信证明推荐的验证方式[9]。

Almost all the time goes into step ④. One node of the Hilbert–Smith tree[1] exports about 1.28 GB with 120,385 declarations, and the Lean kernel checks them one at a time on one thread. 0.1% of the declarations (120) take 60% of the time and 1% take 97%; the slowest single declaration takes 487 s. Mathlib's 93,000 constants check in under 1 ms at the median; the slow ones are all proofs written by our agents.

时间几乎全在第 ④ 步。Hilbert–Smith 证明树[1] 的一个节点导出约 1.28 GB、120,385 条声明,Lean 内核一条一条单线程检查:0.1% 的声明(120 条)占 60% 的时间,1% 占 97%;单条最慢 487 s。Mathlib 的 9.3 万个常量中位数不到 1 ms,慢的全是 agent 自己写的证明。

  1. Build: the check directory is assembled from the pristine problem files and the agent's submission files and statically scanned; then lake build[10] runs in a sandbox with no network and read-only dependencies. Modules compile in parallel along the import graph; each is parsed, macro-expanded and elaborated (tactics, type-class search, unification), and every declaration is checked by the kernel before it is written to an .olean file[7].
  2. Export: every constant in the solution's dependency closure (including the Mathlib constants it uses) is written as plain text[8]; the problem side is exported the same way. From here on only this text counts.
  3. nanoda: an independent type checker written in Rust[5] re-checks every exported declaration. It shares no code with Lean's kernel, so a bug in one kernel cannot let a wrong proof through both.
  4. Lean kernel replay[11]: the environment is rebuilt from empty, sending each declaration through Lean's C++ kernel in dependency order. Each step needs the environment left by the previous one, so the original is strictly serial.
  5. Compare[4]: each theorem's statement matches the frozen problem verbatim and every axiom it uses is on the allow-list (propext, Quot.sound, Classical.choice).
  1. 编译:用题目原件和 agent 提交的文件组装检查目录并做静态扫描,再在沙箱里跑 lake build[10](没有网络,依赖只读)。各模块按 import 依赖图并行编译:解析、宏展开、精化(策略执行、类型类搜索、合一),每条声明经内核检查后写入 .olean 文件[7]。
  2. 导出:把解答依赖闭包里的全部常量(包括用到的 Mathlib 常量)写成纯文本[8],题面一侧也同样导出。之后只认这份文本。
  3. nanoda:用 Rust 独立实现的类型检查器[5] 重查全部导出的声明。它和 Lean 内核不共用代码,一个内核的 bug 不会让两边同时放过错误证明。
  4. Lean 内核重放[11]:从空环境开始,按依赖顺序把每条声明重新送进 Lean 的 C++ 内核。每一步都要基于上一步留下的环境,所以原始实现严格单线程。
  5. 比对[4]:每个定理的命题与冻结题面逐字一致,用到的公理都在白名单里(propext、Quot.sound、Classical.choice)。

3Toggle the optimizations and see how long the chain takes打开或关闭优化,看整条链要查多久

The 12 non-root levels of the Hilbert–Smith chain[1], with all proofs written; the clock runs until every level is accepted. The root check is left out: by our rule it always runs the official pipeline above, unchanged.

Hilbert–Smith 链[1] 上的 12 个非根层,证明都已写好,从这一刻算到每层都被接受。根检查不算在内:按我们的规则,它永远原样走上面的官方流程。

Whole chain checked (wall clock)整条链查完(墙钟)
Check time (worker-hours)检查机时(worker·h)
One check (one level)单次检查(一层)

4Watch the chain get checked看整条链被检查

The same chain under each configuration, on one shared clock. A dashed circle is waiting, a filling circle is being checked (its color is the current step), a solid circle is accepted. A row named "Your toggles" appears when the toggles above match none of the presets.

同一条链在各种配置下的检查过程,共用一个时钟。虚线圈表示在等,环形填充表示正在检查(颜色是当前步骤),实心圈表示已接受。上面的开关组合不属于任何预设时,会多出一行“你的开关”。

t = 0.00 h

5Measured: every proved problem re-checked with parallel replay实测:用并行重放重检每一道已证题

Same verdicts. We re-ran the complete root check of every proof that LOT or our colleagues have produced, with the Lean kernel replayed in parallel. So far 18 of 18 re-checked proofs (of 48) give exactly the recorded serial result: the verdict, the exit code, the comparator's protocol lines in order, and the build output.

结论一致。我们把 LOT 和同事证完的每一份证明都完整重跑了一次根检查,Lean 内核用并行重放。目前已重检的 18 份(共 48 份)中,18 份与当时的串行检查完全一致:结论、退出码、comparator 的检查记录(含顺序)和编译输出。

Faster checks. To compare speed under identical conditions we took six representative problems and, from each proved tree, the chain of intermediate theorems that closed together. Each chain was checked twice at the same time on two identical workers: once with Lean's original pipeline and once with all six optimizations on. Each problem has its own page with the measured run played back.

检查更快。为了在相同条件下比较速度,我们挑了 6 道代表题,从每棵已证树里取一条同时收口的中间定理链,在两台相同的 worker 上同时检查两遍:一遍用 Lean 原始流程,一遍打开全部 6 项优化。每道题有一个单独页面,回放实测的检查过程。

4-level chain4 层链
Pannwitz–Kuperberg quadrisecant theoremsmooth_knot_has_quadrisecant13.2 → 0.8 min · 15.95×Watch both checks →看两遍检查 →
3-level chain3 层链
Wang-Zahl: the three-dimensional Kakeya conjecturewang_zahl_kakeya_dimH11.9 → 3.2 min · 3.75×Watch both checks →看两遍检查 →
4-level chain4 层链
Direct summand theoremdirect_summandbeing measured测量中
10-level chain10 层链
Bochner–Riesz multipliers in three dimensionsopenai/math, family 078being measured测量中
5-level chain5 层链
Shafarevich’s theorem on solvable Galois groupsshafarevich_solvable_galoisbeing measured测量中
3-level chain3 层链
Differentiable sphere theoremsphere_theorem_differentiablebeing measured测量中

Measured on 2026-10-24; cards fill in as the remaining measurements finish.测于 2026-10-24;其余测量完成后补齐。

6Where the code is实现代码的位置

LOT is written in Python: a controller schedules agent sessions, and a gate runs every trusted check on dedicated check workers. The source is in the private repository humanfia/tree-flow, directory lot/; paths below are relative to it, and each optimization has a design note under lot/docs/.

LOT 用 Python 编写:控制器调度 agent 会话,网关在专用检查 worker 上执行每一次可信检查。源码在私有仓库 humanfia/tree-flow 的 lot/ 目录下,下表路径都相对于该目录;每项优化在 lot/docs/ 下都有设计说明。

Part部分Implemented实现日期Code代码Status状态
Trusted check and gate可信检查与网关Oct 7–13, 20262026-10-07 至 10-13trusted/, lean_option_tree/gate.py, lake.py, backbone.pyreleased已发布
Scheduling and infrastructure调度与基础设施local-disk checks Oct 12; pull-based workers Oct 13; sealed nodes first Oct 14; spill-over workers Oct 15, 2026本地盘检查 10-12;拉取式 worker 10-13;封卷节点优先 10-14;本机溢出 10-15(2026 年)lean_option_tree/workers.py, placement.py, nodepool.py, dockergate.pyreleased已发布
Build reuse编译产物复用library cache Oct 13; per-content reuse and deltas Oct 14, 2026库缓存 10-13;按内容复用与增量包 10-14(2026 年)lean_option_tree/backbone.py, refresher.pyreleased已发布
Parallel kernel replay并行内核重放Oct 23, 2026; in production Oct 242026-10-23;10-24 投入生产a fork of the comparator[4] plus a new trusted check script; lean_option_tree/checkerswitch.py, lake.pycomparator[4] 的分支加新的可信检查脚本;lean_option_tree/checkerswitch.py、lake.pyin production use, not yet released已在生产使用,尚未发布
Verified-constant ledger已验证常量账本Oct 13, 2026; local-worker fix Oct 232026-10-13;10-23 修复本机 workerlean_option_tree/ledger.py and the comparator fork 及 comparator 分支released已发布
Speculative level checking链上各层推测并行检查checking ahead Oct 17; one-step close Oct 19, 2026提前检查 10-17;一步收链 10-19(2026 年)lean_option_tree/prewarmdep.py, chains.py, chains_view.py, policy.py, rootonce.pyreleased已发布
One check per chain一链一检Oct 24, 20262026-10-24lean_option_tree/chainone.py and a new trusted check script 及新的可信检查脚本implemented, under review; new trees only已实现,评审中;只用于新树

7References参考文献

  1. OpenAI. The Hilbert–Smith conjecture in every finite dimension. OpenAI mathematics release, paper family 304, September 2026. github.com/openai/math
  2. L. de Moura and S. Ullrich. The Lean 4 Theorem Prover and Programming Language. In Automated Deduction – CADE 28, LNCS 12699, pp. 625–635. Springer, 2021.
  3. Lean-Eval: a benchmark of research-level Lean problems and its trusted checker. github.com/leanprover/lean-eval
  4. Lean FRO. comparator: checks that a solution proves the stated theorem with permitted axioms only. github.com/leanprover/comparator
  5. nanoda: an independent type checker for Lean 4, written in Rust. github.com/ammkrn/nanoda_lib
  6. LOT visualizer: an animated tour of how LOT schedules proof work. lyken17.github.io/lot-viz
  7. Lean FRO. The Lean Language Reference, §2 "Elaboration and Compilation" (parsing, macro expansion, elaboration, the kernel). lean-lang.org/doc/reference/latest/Elaboration-and-Compilation
  8. lean4export: plain-text export of Lean 4 environments. github.com/leanprover/lean4export
  9. Lean FRO. The Lean Language Reference, "Validating a Lean Proof". lean-lang.org/doc/reference/latest/ValidatingProofs
  10. Lean FRO. The Lean Language Reference, "Lake" (the Lean build tool). lean-lang.org/doc/reference/latest/Build-Tools-and-Distribution/Lake
  11. Type Checking in Lean 4: the kernel, its trust model and the export format. ammkrn.github.io/type_checking_in_lean4
  12. OpenAI. openai/math: research preprints with Lean formalizations, September 2026. github.com/openai/math
Model assumptions and measurements模型假设与实测数据

All times are measured on the Hilbert–Smith tree[1] unless noted. Build from scratch 3.03 h (5,533 modules on 16 cores; 10,920 s measured for 5,521 of them); with build reuse 1–2 min (we use 2 min). Export and parse 3 min (estimate). nanoda 46 min; serial Lean replay 7.34 h (26,422 s); parallel kernel replay 53 min with 16 threads and nanoda running at the same time, its verified output byte-identical to the serial run. Ledger: on another large proof tree the kernel phase was 85% shorter and 93.1% of constants were skipped, with 7/7 spot checks identical; in the model it only helps checks that start after another check has finished (an inference, not a measurement). Closing a chain level by level adds 0.05–0.2 h per level (we use 0.1 h). Before the scheduling work a check waited 16–20 min to start at the median (we use 18 min), afterwards about 8 s. At most 4 chain levels are checked at once. One check per chain is in development; its time is modeled as one check of the top level's closure.

除特别说明外,时间都在 Hilbert–Smith 证明树[1] 上实测。从头编译 3.03 h(16 核 5,533 个模块,实测 10,920 s 编到 5,521 个);复用后 1–2 min(模型取 2 min)。导出与解析 3 min(估计)。nanoda 46 min;Lean 串行重放 7.34 h(26,422 s);并行内核重放 16 线程、nanoda 同时运行共 53 min,验证输出与串行逐字节一致。账本:在另一棵大证明树上内核阶段缩短 85%,跳过 93.1% 的常量,抽查 7/7 一致;模型中它只对在别的检查完成后才开跑的检查有效(推算,非实测)。逐层收链每层多等 0.05–0.2 h(模型取 0.1 h)。调度优化前检查开跑前的等待中位数 16–20 min(模型取 18 min),优化后约 8 s。链上最多 4 层同时检查。一链一检在开发中,用时按一次顶层闭包的检查估算。