系列:AI 如何做出数学发现(第 5 篇)
深度解读 OpenAI公开的GPT推演手稿《How the Ideas Came Together》,从失败路线、关键不变量与可复现实验出发,拆解 AI 参与数学发现的真实过程。涵盖球堆积、编码理论、复杂性、量子信息与极值组合,并严格区分发现笔记、正式证明、数值验证和形式化检查。
关键词:数学证明验证、AI 推理、单元测试、反例生成、符号计算、形式化证明
资源我已上传: How the Ideas Came Together:AI数学发现与证明路径重构手稿
前四篇分别出现了可行对象冲突、归一化边界、计算模型错配和全局 witness 不一致。本篇不再引入一条新的数学定理,而是把这些纠错动作整理成统一工作流:先让候选命题变得可攻击,再决定它是否值得投入完整证明、专家复核或形式化验证。
程序员看到 300 行没有测试的代码会不安,但面对 30 页推导,我们常常只做一件事:从头到尾再读一遍。问题是,人和模型在复读自己的论证时很容易沿用同一套错误假设。公式越流畅,越可能产生"应该没问题"的错觉。
数学当然不能被普通单元测试完全验证。有限样例通过,永远不能推出一个全称命题为真;浮点数一致,也不能替代误差界;CAS 输出 0,更没有检查你是否在合法区域里做了除法。
但反方向非常有价值:一个合法反例足以否定全称命题。 因此可以把研究工程中的许多纠错动作组织成 proof unit testing:先把候选命题、量词和假设注册下来,再用尽量独立的基线主动攻击它。
本文给出六类测试、一张断言卡和一个最小 claimcheck.py。配套程序刻意注册了四个错误命题和一个正向对照,运行结果是"找到 4 个反例;另 1 个仅在指定测试中未发现反例"。工具永远不会打印"证明通过"。
一、为什么"逐行读起来都对"仍可能整体错误
长证明常见的故障不是某一行明显算错,而是接口不匹配:
- 上一段证明"对每个对象存在 witness",下一段却使用同一个统一 witness;
- 一个公式对 circuit 成立,下一段把它当作 formula 的结论;
- 渐近式在 n → ∞ n\to\infty n→∞ 成立,却被代入小参数做严格上界;
- 独立抽样的方差被用于无放回抽样;
- 复分析核的总质量不是 1,却被当作概率分布取期望;
- CAS 在分母非零的隐含条件下化简,正文却忘了排除奇点。
这些错误都可能保持局部语法正确。单元测试要做的是把接口变成显式字段,然后从接口两端施压。
二、第一类:可行对象测试
这是成本最低、杀伤力最大的测试。
若候选定理声称 所有可行对象的目标值 ≤ U , \text{所有可行对象的目标值}\le U, 所有可行对象的目标值≤U,那就先找一个显式可行对象 x 0 x_0 x0,检查
value ( x 0 ) ≤ U . \operatorname{value}(x_0)\le U. value(x0)≤U.
若声称下界 L L L,则找一个显式构造作上界基线,检查 L L L 是否超过已实现方案。
本系列第 1 篇"码长为 8 的二元码"例子就是标准模板。错误 Jacobi 递推导出的编码上界为
72.571428571 ... , 72.571428571\ldots, 72.571428571...,而长度 8 的偶校验码有 128 个码字,并满足所需距离条件。无需理解整条谱证明,这一个可行对象就足以否定候选上界。
text
[FAIL] n=8 feasible-object check:
claimed upper bound=72.571428571;
even-parity code size=128
测试设计要点是先验独立:显式码应从定义直接验证,不要用待测递推本身判断它是否可行。
三、第二类:小参数穷举测试
很多命题在小规模可以直接枚举定义。设定义域 X n \mathcal X_n Xn 在 n ≤ n 0 n\le n_0 n≤n0 时足够小,可以比较:
definition_oracle ( x ) vs candidate_formula ( x ) . \text{definition\_oracle}(x) \quad\text{vs}\quad \text{candidate\_formula}(x). definition_oracle(x)vscandidate_formula(x).关键是枚举原定义,而不是枚举已经经过同一套可疑化简的模型。例如:
- 码论中枚举所有二进制向量并直接算 Hamming 距离;
- 图论中枚举边集并直接检查禁子图;
- 线性系统中枚举所有 syndrome coset,而不是只测试随机满秩矩阵;
- 小矩阵 Permanent 用排列定义求和,不调用待验证的递推。
第 4 篇 parity-lift 的正向对照就穷举了固定 3 × 4 3\times4 3×4 校验矩阵的所有 8 个 syndrome,再枚举二进制解和足够大的格点窗口。八个实例中都满足 min z ∈ Λ H ∥ u − z ∥ 2 2 = min { wt ( x ) : H x = b } . \min_{z\in\Lambda_H}\|u-z\|_2^2 =\min\{\operatorname{wt}(x):Hx=b\}. z∈ΛHmin∥u−z∥22=min{wt(x):Hx=b}.状态只能写成:
text
[PASS] small exhaustive positive control: all 8 syndromes agree
它增加可信度,却不是一般定理的证明。
四、第三类:边界与极限测试
边界是许多"差一个归一化"的错误集中地。建议至少覆盖:
- 参数最小值与最大值;
- 奇数/偶数、空集、单元素、零矩阵;
- 分母趋近 0、重根、零特征值;
- 概率趋近 0 或 1;
- 两个极限交换顺序;
- 归一化后的总质量。
球堆积 Mellin 路线中的调和测度给出一个很好的例子。某条边界的核总质量是
M σ = 1 − σ 2 , 0 < σ < 1 , M_\sigma=\frac{1-\sigma}{2}, \qquad0<\sigma<1, Mσ=21−σ,0<σ<1,而不是 1。若直接把未归一化核称为"概率密度",在 σ ↑ 1 \sigma\uparrow1 σ↑1 时会丢掉一个趋于 0、却参与主指数计算的因子。测试器选择 σ = 0.2 , 0.5 , 0.8 \sigma=0.2,0.5,0.8 σ=0.2,0.5,0.8,立即得到质量 0.4 , 0.25 , 0.1 0.4,0.25,0.1 0.4,0.25,0.1,从而否定"已归一化为概率测度"的候选命题。
边界测试不只代数代入。涉及极限时还应记录:哪个变量先趋于无穷?误差是否一致?支配函数是否依赖参数?端点是否仍在定义域?
五、第四类:依赖结构测试
相同的一维边缘分布,不代表联合结构相同。常见偷换包括:
- 有放回与无放回抽样;
- 独立随机变量与共享随机种子的变量;
- circuit 中共享子表达式与 formula 中复制子树;
- 对每个参数单独选择 witness 与预先固定一个 witness;
- 多个系数由同一变量生成,却被当作代数独立。
测试器注册了一个故意错误的命题:"无放回抽样可直接使用独立 Bernoulli 和的方差。"总体大小 N = 10 N=10 N=10,其中 K = 4 K=4 K=4 个成功项,抽取 n = 5 n=5 n=5 个。独立模型给出 n p ( 1 − p ) = 1.2 , n p(1-p)=1.2, np(1−p)=1.2,超几何分布则带有限总体修正: n p ( 1 − p ) N − n N − 1 = 2 3 . n p(1-p)\frac{N-n}{N-1}=\frac23. np(1−p)N−1N−n=32.两者期望相同、方差不同。只检查均值完全发现不了这个问题。
依赖测试的实用写法是给随机源和共享关系编号: X i = f i ( U , V i ) X_i=f_i(U,V_i) Xi=fi(U,Vi) 中哪些变量共享 U U U?抽样空间是 product measure、条件分布还是固定总数的 slice?图画清楚后,许多错误"独立性"会自己暴露。
六、第五类:量词测试
量词错误往往不会触发数值异常,却会让整条证明断裂。最常见的是 ∀ x ∃ y P ( x , y ) \forall x\ \exists y\ P(x,y) ∀x ∃y P(x,y)被误写成 ∃ y ∀ x P ( x , y ) . \exists y\ \forall x\ P(x,y). ∃y ∀x P(x,y).第 4 篇 GapCVP 归约中,每种 table type τ \tau τ 可以有自己的 good sample set P τ P_\tau Pτ: ∀ τ ∃ P τ . \forall\tau\ \exists P_\tau. ∀τ ∃Pτ.如果程序数据结构只允许一个全局 good_points,实现已经悄悄假设了更强命题。量词测试可以不做复杂计算,只需检查 witness 的生命周期:它在循环外构造还是循环内构造?是否依赖当前对象?进入下一段前依赖关系有没有被遗忘?
建议把自然语言"任选""存在""统一地""几乎处处""对充分大"全部翻译为带依赖的签名。例如:
text
good_set: TableType -> Set[Point]
与
text
good_set: Set[Point]
是两种完全不同的证明接口。
七、第六类:模型对照测试
同一对象放进不同模型,结论可能完全不同。模型测试不是比较两个数值,而是列出允许的操作:
| 维度 | 模型 A | 模型 B | 必查接口 |
|---|---|---|---|
| 代数计算 | circuit DAG | formula tree | 中间结果能否共享 |
| 除法 | division-free | valid division | 分母何处非零 |
| 量子策略 | tensor product | commuting operator | 状态空间与可交换条件 |
| 动力系统 | 连续/拓扑作用 | measurable action | witness 的正则性 |
| 概率 | 独立乘积 | 无放回/条件分布 | 协方差结构 |
审计 Permanent formula 的 valid-division 证明时,一个极小但致命的候选假设是:把一元 Möbius wrapper 的非零射影矩阵都当成可逆矩阵。反例是 ( 0 0 0 1 ) , \begin{pmatrix}0&0\\0&1\end{pmatrix}, (0001),
它非零且奇异,却表示合法常值映射 u ↦ 0 u\mapsto0 u↦0。测试器检查行列式为 0、分母恒为 1,立刻否定"每个有效非零 wrapper 都可逆"。

六类测试从不同方向攻击候选结论。覆盖面比同一种随机测试重复一万次更重要。
八、断言卡:先把待测命题结构化
一个可运行测试至少需要以下字段:
yaml
id: C03
claim: 有效除法公式中的每个非零一元包装矩阵都可逆
quantifiers: 对每条不含标记变量分支的有效一元链
assumptions:
- 矩阵按比例视为射影表示
baseline: 构造非零奇异矩阵并检查其有理映射是否有效
oracle: denominator_nonzero_on_domain && expression_defined
tolerance: exact
status: untested
我建议再补四项:
source:命题来自哪一页、哪条 lemma 或哪次模型输出;dependency:依赖哪些尚未确认的命题;domain_generator:怎样生成满足定义的对象;counterexample:失败时保存最小可复现实例。

测试、专家复核和形式化检查应分别记录;任何一条轴都不能被一个含混的
passed取代。
更稳妥的做法不是把所有证据压成一条线性状态机,而是维护三条状态轴: test_status ∈ { untested , tested-no-counterexample , counterexample-found } , review_status ∈ { not-reviewed , expert-reviewed } , formal_status ∈ { not-formalized , formally-checked } . \begin{aligned} \texttt{test\_status}&\in \{\texttt{untested},\texttt{tested-no-counterexample},\texttt{counterexample-found}\},\\ \texttt{review\_status}&\in \{\texttt{not-reviewed},\texttt{expert-reviewed}\},\\ \texttt{formal\_status}&\in \{\texttt{not-formalized},\texttt{formally-checked}\}. \end{aligned} test_statusreview_statusformal_status∈{untested,tested-no-counterexample,counterexample-found},∈{not-reviewed,expert-reviewed},∈{not-formalized,formally-checked}.
只要 test_status 记录了 counterexample-found,命题本身就进入 refuted;而 tested-no-counterexample 不会自动改变另外两条轴。专家复核能检查建模、意义和遗漏的假设,形式化系统检查已编码命题及其推导,两者覆盖范围不同,也不应互相覆盖。任何状态都不应被简写为 passed,否则传播到摘要和新闻稿时极易变成"已证明"。
九、数值测试必须携带误差模型
对浮点结果使用固定的 abs(a-b)<1e-9 并不专业。容差至少应考虑:
∣ f ^ − f ∣ ≤ E r o u n d + E t r u n c + E d i s c + E s t a t . |\widehat f-f| \le E_{\mathrm{round}}+E_{\mathrm{trunc}}+E_{\mathrm{disc}}+E_{\mathrm{stat}}. ∣f −f∣≤Eround+Etrunc+Edisc+Estat.
- 舍入误差与运算次数、条件数有关;
- 截断误差来自无穷级数或积分区间;
- 离散误差来自网格和步长;
- 随机误差需要置信区间或其他概率保证;固定 seed 只保证可复现,不能替代误差界。
矩阵特征值测试应检查残差 ∥ A v ^ − λ ^ v ^ ∥ , \|A\widehat v-\widehat\lambda\widehat v\|, ∥Av −λ v ∥,
而不只是记录库函数返回值;判断残差是否足够小还应考虑矩阵和向量的尺度。病态问题可用区间算术、多精度或有理重构。测试失败还应区分:候选命题被反例否定,还是数值误差预算不足以判定。
十、CAS 测试的边界:化简为零不等于推导合法
符号计算适合:
- 展开并比较有限多项式恒等式;
- 精确求小矩阵行列式和因式分解;
- 在显式假设下做消元;
- 生成小规模反例。
但 CAS 通常不会替你审计上下文。例如 x 2 − 1 x − 1 = x + 1 \frac{x^2-1}{x-1}=x+1 x−1x2−1=x+1作为有理函数,等式两边表示同一个元素;作为逐点求值的函数,等式只在共同定义域 x ≠ 1 x\ne1 x=1 上成立。若原命题包含 x = 1 x=1 x=1,右侧有定义而左侧没有。再如 sqrt(x^2)=x 需要实数域和 x ≥ 0 x\ge0 x≥0,在复数域或负实数上都不成立。
因此每个符号测试要记录 domain、nonzero assumptions 和 branch conventions。最稳妥的做法是让 CAS 负责代数内核,让独立代码负责生成满足定义域的测试点和检查前提。
十一、property-based testing:让程序寻找反例
例子测试由人指定输入;property-based testing 从定义生成大量对象,并在失败后缩小反例。一个数学对象生成器应先保证结构合法,再向候选性质施压:
python
for object in generate_valid_objects(seed):
assert definition_oracle(object)
if not candidate_claim(object):
save(shrink(object))
这里最容易犯的错误是生成器只覆盖"容易的正规对象"。例如随机矩阵几乎总满秩,永远测不到奇异边界;连续采样几乎不会命中重根;均匀随机图很少覆盖极端度序列。因此生成策略应混合:随机实例、边界实例、对称实例、退化实例和已知 extremizer。
测试预算也不应只写"随机 1000 次",而要写覆盖目标:所有 n ≤ 8 n\le8 n≤8、所有秩、所有奇偶类、所有分母零型、每个模型分支至少一个样例。
十二、claimcheck.py 的设计与输出
配套脚本把每条命题表示为:
python
Claim(
claim_id,
statement,
quantifiers,
assumptions,
baseline,
tests,
)
每个测试返回 Observation(name, passed, detail)。报告生成器有意只使用两个结论:
发现反例;指定测试未发现反例。
claimcheck.py完整Python代码如下:
python
"""A minimal claim-level testing harness for mathematical.
The tool searches only the explicitly registered finite test space. Therefore
its positive status is worded "no counterexample in specified tests", never
"proved". Run:
python -B 05_claimcheck.py
python -B 05_claimcheck.py --output ../reports/05-claimcheck-report.md
Dependency: NumPy (for the Jacobi eigenvalue test).
"""
from __future__ import annotations
import argparse
from dataclasses import dataclass
from itertools import product
import math
from pathlib import Path
from typing import Callable
import numpy as np
@dataclass(frozen=True)
class Observation:
name: str
passed: bool
detail: str
@dataclass(frozen=True)
class Claim:
claim_id: str
statement: str
quantifiers: str
assumptions: tuple[str, ...]
baseline: str
tests: tuple[Callable[[], Observation], ...]
def wrong_jacobi_bound() -> Observation:
n, k, ell, s = 8, 1, 7, 0.5
matrix = np.zeros((ell - k + 1, ell - k + 1))
for offset, j in enumerate(range(k, ell)):
coefficient = math.sqrt((j - k + 1) * (n - j - k)) / n
matrix[offset, offset + 1] = coefficient
matrix[offset + 1, offset] = coefficient
eigenvalue = float(np.linalg.eigvalsh(matrix)[-1])
dimension = sum(math.comb(n, j) for j in range(k, ell + 1))
multiplicity = math.comb(n, k) - math.comb(n, k - 1)
claimed_upper_bound = (1 - s) / (eigenvalue - s) * dimension / multiplicity
feasible_even_parity_code = 2 ** (n - 1)
passed = claimed_upper_bound + 1e-9 >= feasible_even_parity_code
return Observation(
"n=8 feasible-object check",
passed,
f"claimed upper bound={claimed_upper_bound:.9f}; "
f"even-parity code size={feasible_even_parity_code}",
)
def harmonic_mass_normalization() -> Observation:
sigmas = (0.2, 0.5, 0.8)
masses = tuple((1 - sigma) / 2 for sigma in sigmas)
passed = all(abs(mass - 1.0) < 1e-12 for mass in masses)
return Observation(
"boundary/limit normalization check",
passed,
"sigma -> actual total mass: "
+ ", ".join(f"{sigma:.1f}->{mass:.3f}" for sigma, mass in zip(sigmas, masses)),
)
def singular_projective_wrapper() -> Observation:
# [[0,0],[0,1]] is nonzero and singular, but represents u -> 0/1.
matrix = ((0, 0), (0, 1))
determinant = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]
nonzero = any(value != 0 for row in matrix for value in row)
denominator_at_samples = tuple(matrix[1][0] * u + matrix[1][1] for u in (-2, 0, 3))
represents_valid_map = nonzero and all(value != 0 for value in denominator_at_samples)
# The tested claim says every valid nonzero wrapper must be invertible.
passed = (not represents_valid_map) or determinant != 0
return Observation(
"model-comparison check",
passed,
f"matrix={matrix}; det={determinant}; valid constant map={represents_valid_map}",
)
def without_replacement_variance() -> Observation:
population, successes, draws = 10, 4, 5
p = successes / population
independent = draws * p * (1 - p)
actual = independent * (population - draws) / (population - 1)
passed = abs(independent - actual) < 1e-12
return Observation(
"dependency-structure check",
passed,
f"independent variance={independent:.6f}; "
f"without-replacement variance={actual:.6f}",
)
def exhaustive_parity_lift_control() -> Observation:
h = (
(1, 1, 0, 0),
(0, 1, 1, 0),
(0, 0, 1, 1),
)
def syndrome(x: tuple[int, ...]) -> tuple[int, ...]:
return tuple(sum(a * b for a, b in zip(row, x)) % 2 for row in h)
failures: list[str] = []
all_binary = list(product((0, 1), repeat=4))
lattice = [
z for z in product(range(-2, 3), repeat=4)
if syndrome(tuple(value % 2 for value in z)) == (0, 0, 0)
]
for b in product((0, 1), repeat=3):
solutions = [x for x in all_binary if syndrome(x) == b]
if not solutions:
continue
min_weight = min(sum(x) for x in solutions)
target = solutions[0]
min_distance = min(sum((u - z_i) ** 2 for u, z_i in zip(target, z)) for z in lattice)
if min_distance != min_weight:
failures.append(f"b={b}: weight={min_weight}, distance^2={min_distance}")
return Observation(
"small exhaustive positive control",
not failures,
"all 8 syndromes agree" if not failures else "; ".join(failures),
)
CLAIMS = (
Claim(
"C01",
"旧 Jacobi 系数给出的 LP 表达式是所有二元码大小的上界。",
"对所有 n,k,L,s 以及满足距离条件的二元码。",
("使用旧递推的非对称归一化", "Perron 根代入同一上界公式"),
"先构造满足条件的显式码,再比较声称的上界。",
(wrong_jacobi_bound,),
),
Claim(
"C02",
"Mellin 边界核对每个 0<sigma<1 都已经归一化为概率测度。",
"对所有 0<sigma<1。",
("未额外乘归一化常数",),
"直接积分边界密度并检查总质量。",
(harmonic_mass_normalization,),
),
Claim(
"C03",
"有效除法公式中的每个非零一元 Mobius 包装矩阵都可逆。",
"对每条不含被标记变量分支的有效一元链。",
("矩阵按比例视为射影表示",),
"构造非零奇异矩阵并检查它是否仍表示合法有理映射。",
(singular_projective_wrapper,),
),
Claim(
"C04",
"无放回抽样可以直接使用独立 Bernoulli 和的方差。",
"对任意总体大小、成功数和抽样数。",
("样本之间被当作独立",),
"与超几何分布的有限总体修正比较。",
(without_replacement_variance,),
),
Claim(
"C05",
"小型二进制 syndrome 的最小重量等于 parity-lift 的最小平方距离。",
"对固定 3x4 校验矩阵的所有可达 syndrome。",
("目标 u 满足 Hu=b", "格由 Hz=0 (mod 2) 定义"),
"穷举二进制向量和足够大的最近格点窗口。",
(exhaustive_parity_lift_control,),
),
)
def render_report() -> str:
lines = [
"# claimcheck 示例报告",
"",
"> 状态"指定测试未发现反例"只描述有限测试结果,不等于数学证明。",
"",
]
failed_claims = 0
for claim in CLAIMS:
observations = [test() for test in claim.tests]
passed = all(observation.passed for observation in observations)
if not passed:
failed_claims += 1
status = "指定测试未发现反例" if passed else "发现反例"
lines.extend(
[
f"## {claim.claim_id} --- {status}",
"",
f"- 命题:{claim.statement}",
f"- 量词:{claim.quantifiers}",
f"- 假设:{';'.join(claim.assumptions)}",
f"- 基线:{claim.baseline}",
"",
]
)
for observation in observations:
marker = "PASS" if observation.passed else "FAIL"
lines.append(f"- [{marker}] {observation.name}:{observation.detail}")
lines.append("")
lines.extend(
[
"## 汇总",
"",
f"- 注册命题:{len(CLAIMS)}",
f"- 发现反例:{failed_claims}",
f"- 指定测试未发现反例:{len(CLAIMS) - failed_claims}",
"- 证明状态:未由本工具判定",
"",
]
)
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--output", type=Path)
args = parser.parse_args()
report = render_report()
if args.output:
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(report, encoding="utf-8")
print(f"wrote {args.output}")
else:
print(report)
if __name__ == "__main__":
main()

报告保留命题、量词、假设、基线和反例数值;截图应来自实际生成的 Markdown,不应由图片模型伪造终端文本。
本次真实输出汇总为:
text
注册命题:5
发现反例:4
指定测试未发现反例:1
证明状态:未由本工具判定
四个失败分别击中可行对象、归一化边界、模型对照和依赖结构;正向对照穷举小型 parity-lift 的 8 个 syndrome。完整报告保存成 05-claimcheck-report.md。
markup
# claimcheck 示例报告
> 状态"指定测试未发现反例"只描述有限测试结果,不等于数学证明。
## C01 --- 发现反例
- 命题:旧 Jacobi 系数给出的 LP 表达式是所有二元码大小的上界。
- 量词:对所有 n,k,L,s 以及满足距离条件的二元码。
- 假设:使用旧递推的非对称归一化;Perron 根代入同一上界公式
- 基线:先构造满足条件的显式码,再比较声称的上界。
- [FAIL] n=8 feasible-object check:claimed upper bound=72.571428571; even-parity code size=128
## C02 --- 发现反例
- 命题:Mellin 边界核对每个 0<sigma<1 都已经归一化为概率测度。
- 量词:对所有 0<sigma<1。
- 假设:未额外乘归一化常数
- 基线:直接积分边界密度并检查总质量。
- [FAIL] boundary/limit normalization check:sigma -> actual total mass: 0.2->0.400, 0.5->0.250, 0.8->0.100
## C03 --- 发现反例
- 命题:有效除法公式中的每个非零一元 Mobius 包装矩阵都可逆。
- 量词:对每条不含被标记变量分支的有效一元链。
- 假设:矩阵按比例视为射影表示
- 基线:构造非零奇异矩阵并检查它是否仍表示合法有理映射。
- [FAIL] model-comparison check:matrix=((0, 0), (0, 1)); det=0; valid constant map=True
## C04 --- 发现反例
- 命题:无放回抽样可以直接使用独立 Bernoulli 和的方差。
- 量词:对任意总体大小、成功数和抽样数。
- 假设:样本之间被当作独立
- 基线:与超几何分布的有限总体修正比较。
- [FAIL] dependency-structure check:independent variance=1.200000; without-replacement variance=0.666667
## C05 --- 指定测试未发现反例
- 命题:小型二进制 syndrome 的最小重量等于 parity-lift 的最小平方距离。
- 量词:对固定 3x4 校验矩阵的所有可达 syndrome。
- 假设:目标 u 满足 Hu=b;格由 Hz=0 (mod 2) 定义
- 基线:穷举二进制向量和足够大的最近格点窗口。
- [PASS] small exhaustive positive control:all 8 syndromes agree
## 汇总
- 注册命题:5
- 发现反例:4
- 指定测试未发现反例:1
- 证明状态:未由本工具判定
运行方法:
bash
python -B draft/code/05_claimcheck.py
python -B draft/code/05_claimcheck.py --output draft/reports/05-claimcheck-report.md
依赖 Python 3.10+ 与 NumPy。
十三、把测试插入 AI 数学工作流
一个实际可用的顺序是:
- 候选生成:模型提出 lemma、递推或参数选择;
- 断言提取:把每个关键跳步写成带量词的 Claim;
- 定义 oracle:尽量从原定义实现独立基线;
- 快速否证:先跑可行对象、边界、小参数与退化实例;
- 误差审计:为数值和随机测试写明误差预算;
- 依赖审计:画出 witness、随机源和共享子表达式;
- 证明重写:将通过测试但尚未证明的命题交给人工推导;
- 独立审查:让另一位研究者或另一套系统从源定义检查;
- 形式化:对高价值核心 lemma 进入 Lean/Coq/Isabelle;
- 回归测试:证明修订后重跑所有历史反例。

图 05-5 从下到上通常意味着单次检查成本和形式严格性提高,不代表所有问题都存在统一的可信度排序;专家审查与形式化验证覆盖不同风险。
测试特别适合作为"前置过滤器":它能在专家花数天读证明前,用几秒到几分钟淘汰明显错误路线。形式化证明则位于另一端,要求完整定义、lemma 库和可信内核。中间仍需要数学家的概念判断:为什么这个不变量正确?哪些情况应当分开?证明是否回答了原问题?
十四、发布数学结果前的最小检查表
- 命题的所有量词是否写出,渐近变量和极限顺序是否明确?
- 是否有显式可行对象或已知基线可做 sanity check?
- 小参数测试是否直接按定义,而非复用候选公式?
- 是否覆盖空、零、奇异、重根、端点和最低维数?
- 随机量是否真的独立,witness 是否允许依赖当前对象?
- circuit/formula、离散/连续、tensor/commuting 等模型有没有混用?
- 数值结论是否携带条件数、截断和统计误差?
- CAS 使用了哪些非零、实数域或分支假设?
- 报告是否区分"发现反例""未发现反例""人工证明""形式化证明"?
- 修订后的命题是否重新运行旧反例作为回归测试?
结语:测试的目标不是证明,而是让错误更便宜
Proof unit testing 不会把数学研究变成普通软件工程。无限对象、全称量词和概念创新决定了证明仍需要演绎论证。但测试能改变错误的成本结构:让一个模型错误在 2 × 2 2\times2 2×2 奇异矩阵上暴露,而不是藏到 40 页末尾;让一个上界错误被码长为 8 的显式码击穿,而不是等同行评审;让量词依赖进入数据结构,而不是只留在作者脑中。
对 AI 生成的数学尤其如此。模型很擅长延续局部模式,也因此可能把一个错误接口延续得异常流畅。最有效的补偿不是要求它"再仔细想想",而是给结论安排独立、具体、可运行的否证通道。---
证据边界
Walkthrough:六类测试综合了前四篇中的失败路线与反例模式;分类本身是本文的研究工程整理,不是原 PDF 中的一条定理。Paper:过程监督、形式化验证和 property-based testing 的参考资料提供方法背景,但不推出"测试可以证明任意数学命题"。Computation:claimcheck.py的 5 条命题与输出已在本地运行;正向结果只覆盖脚本注册的有限测试集。Formal/Review:指定测试未发现反例不蕴含命题为真;形式化验证与专家审查分别记录,不能由 NumPy、CAS 或随机测试替代。
参考资料
- How the Ideas Came Together(OpenAI,PDF)
- Our First Proof submissions(OpenAI)
- Lightman et al.: Let's Verify Step by Step(arXiv)
- Lean 4 Documentation
- [Hypothesis: Property-Based Testing for Python
手稿部分相关页面截图:





