Files
lean-bench/textbook
claude-bot 79c728567a Fix 10 failing goodman-1.6 statements based on Lean compiler diagnostics
All 21 statements in datasets/goodman-1.6.jsonl now elaborate cleanly
(verified locally via check_statements.py, 11/21 passing before this
change). Fixes applied, one per failing id:

- goodman-1-6-7: single-binder existential-unique over a pair (qr : ZxZ)
  instead of the invalid two-binder 'exists unique' form.
- goodman-1-6-10: rewrote set-builder notation to the explicit
  {v | exists a b, v = ...} form.
- goodman-1-6-11: replaced 'let d := ... in ...' with the required
  semicolon form 'let d := ...; ...', and added the missing Nat-to-Int
  casts on d.
- goodman-1-6-17: added explicit Nat-to-Int coercions on the three
  divisibility relations.
- goodman-1-6-18: changed p from Z to N (Nat.Prime requires N), added
  casts, and replaced the nonexistent Int.Coprime with IsCoprime.
- goodman-1-6-19: changed p from Z to N and added the matching casts.
- goodman-1-6-20: changed p from Z to N, added casts, and fixed the
  quantifier structure so the prime-divides-product hypothesis is not
  nested inside the per-element forall.
- goodman-1-6-23: replaced the Fin n literal comparison 'j = 0' (which
  needs a NeZero instance) with 'j.val = 0'.
- goodman-1-6-24: replaced the invalid bare '(*)' operator section with
  '(fun x y => x * y)'-equivalent '(. * .)', and replaced the
  nonexistent GCD.gcd with an explicit existential statement of the gcd
  property (divides every element; every common divisor divides it).
- goodman-1-6-26: replaced the nonexistent Int.Coprime with IsCoprime.

Also corrected the three parallel hallucinated Mathlib refs in
textbook/goodman-1.6.definitions.json (Int.Coprime, GCD.gcd,
Int.PairwiseCoprime -> IsCoprime, null with notes, and
List.Pairwise IsCoprime respectively), since the Lean compiler confirms
none of the original names exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vbLFFJiHSZqGZHEkjvG5x
2026-09-18 16:50:34 +00:00
..

Textbook formalization pipeline

把一本教科书(目前是 Goodman, Algebra: Abstract and Concrete)里正文的 Theorem/Proposition/Lemma/Corollary 转成 lean-bench 能跑的任务 JSONL,配套 Definition 清单(优先复用 Mathlib,Mathlib 没有的才手写),再由 lean-agent 在 一个真正带 Mathlib 的 Lean 项目里验证/证明。这条流水线本身不跑 Lean,也不联网 以外没有第三方依赖。

这条流水线不做什么

  • 不产出证明。生成的只是待证命题(statement 字段),证明留给 lean-agent/lean-bench 去跑。
  • 不在 Cowork 沙盒里验证 Lean 语句能不能通过类型检查——沙盒里没有装 Lean/Lake/Mathlib(架构也不兼容:本机 ~/.elan 下是 macOS 二进制,沙盒是 Linux VM,跑不了),所以 check_statements.py 必须在你本机、且是一个已经 lake exe cache get 过的 Mathlib 项目里跑,见下面"本机环境准备"。
  • 不会把教科书 PDF 或者大段原文提取结果提交进 git——.gitignore 里已经排除 了 *.pdf 和 textbook/*.txt,这些是版权内容,只应该留在你本机。只有代码、 生成的最终数据集(短的 Lean 语句 + 自己改写的简短英文释义)会进仓库。

用法

1. 从 PDF 提取一章的版式文本

pdftotext -layout -f <起始pdf页码> -l <结束pdf页码> uiowa-algebra.pdf textbook/chapterNN_layout.txt

页码用 pdfinfo/pypdf 先核对——书里印的页码和 PDF 物理页码不是一回事(前 面有目录、序言)。

2. 切出一个 section,列出带编号的条目清单

python3 textbook/extract_section.py textbook/chapterNN_layout.txt \
  --start-heading "1.6. Divisibility in the Integers" \
  --end-heading "1.7. Modular Arithmetic" \
  --section-prefix "1.6." \
  --out-text textbook/section_1_6.txt \
  --out-index textbook/section_1_6.index.json

--start-heading/--end-heading 必须和版式文本里独占一行的章节标题逐字 一致(提取时打印出的书本身的标题行);--end-heading 留空就切到文件末尾。 输出的 index JSON 是这个 section 里所有 Theorem/Proposition/Lemma/ Corollary/Definition N.N.N 开头的条目清单(自动去重了跨页重复的标签),用来 让下一步的 LLM 不漏项、不编项目。

3. 用 LLM 把 section 形式化成候选 Lean 语句

export DASHSCOPE_API_KEY=...            # 或者写进 lean-bench/.env(已 gitignore)
python3 textbook/formalize.py \
  textbook/section_1_6.txt textbook/section_1_6.index.json \
  --model qwen-max --base-url https://dashscope.aliyuncs.com/compatible-mode/v1 \
  --out-dataset datasets/goodman-1.6.jsonl \
  --out-definitions textbook/goodman-1.6.definitions.json \
  --out-excluded textbook/goodman-1.6.excluded.jsonl

模型会为每条 Theorem/Proposition/Lemma/Corollary 产出一个 Lean 4 命题 (statement)、需要的 prelude(通常就是 import Mathlib)、一句自己改写 的英文释义,以及用到的 Mathlib 标识符列表;为每条相关的 Definition 产出一个 清单条目——如果 Mathlib 已经有对应概念(mathlib_ref 非空)就不写 Lean 代 码,只有 Mathlib 没有的概念才会给出手写的 def。判断这条目根本没法形式化 (纯计算题、内容太模糊/被 PDF 提取污染到读不出原意)的条目,会带着 include_in_bench: false 和原因单独写进 --out-excluded,不会进真正的数据 集,但也不会被静默丢弃——都留痕方便你复核。

源 PDF 的数学符号提取质量很差(≡、∈、上下标经常丢失或乱码),这一步依赖模 型自己对标准教材内容的知识去猜测/还原真实含义,不是逐字翻译提取出来的文 本。所以生成的候选语句必须经过下一步验证,不能直接信。

4. 在你本机验证候选语句能不能通过类型检查

见下面"本机环境准备"先搭好一个带 Mathlib 的 Lake 项目,然后:

python3 textbook/check_statements.py datasets/goodman-1.6.jsonl \
  --lean-project /path/to/your/mathlib-project \
  --lean-command '["lake","env","lean"]' \
  --report textbook/goodman-1.6.elab-report.jsonl

这一步只检查"这句 Lean 能不能通过类型检查"(用 sorry 占位),不检查证明 是否存在、也不检查是否忠实于原书——分别对应两件不同的事:语法/引用是否正 确,跟数学内容是否正确。失败的条目(FAIL)要么是模型编造了不存在的 Mathlib 标识符,要么是语句本身写错了,需要你告诉我具体哪条、Lean 报的什么 错,我再改。

5. 用 lean-agent/lean-bench 真正证明

lean-bench datasets/goodman-1.6.jsonl --output results/goodman-1.6-001 \
  --lean-project /path/to/your/mathlib-project --lean-command '["lake","env","lean"]' \
  --model ... --base-url ...

6. 把证出来的定理组装成一份可复用的库文件

python3 textbook/build_library.py datasets/goodman-1.6.jsonl \
  results/goodman-1.6-001/results.jsonl --out lib/Chapter01Section06.lean

只有这次跑真的证出来的定理(results.jsonl 里 success: true)才会被收进 去,直接复用验证时确认过的那个证明,不会引入新的证明风险。后续章节要用这些 已证定理时,import 这份文件——注意这只是把已证结果攒成一个文件,不是一个真 正的 Lake 包/模块边界。

本机环境准备:一个带 Mathlib 的 Lake 项目

Cowork 这边的沙盒没有 Lean,check_statements.py 和真正跑 lean-agent/ lean-bench 都需要在你本机(或者别的有 Lean 的环境)完成。如果还没有这样一 个项目:

cd ~/ProjectResearch   # 随便一个地方
lake +leanprover/lean4:v4.33.1 new mathlib-bench math
cd mathlib-bench
lake exe cache get     # 下载 Mathlib 预编译缓存,比从源码编译快得多
lake build

之后 --lean-project 就指到 mathlib-bench 这个目录,--lean-command 用 '["lake","env","lean"]'。

反馈循环

我(claude-bot)在 ProjectResearch 里生成/修改数据集和代码 → 提交并 push 到 Zayden-Jung/lean-bench(用 claude-bot 的 token) → 你在本机 git pull → 跑 check_statements.py / lean-bench → 把失败的条目 id 和 Lean 报的错发 给我 → 我改完再 push。不需要额外工具,就是正常的 git 往返。