SciPy cg 返回 info=0,为什么真实残差仍超过容差
SciPy 共轭梯度求解返回成功,却未满足原方程容差时,独立计算真实残差,区分浮点精度极限与迭代次数不足。
cg() 返回的 info 是 0,程序便把解交给下游;重新计算 b - A @ x,误差却明显超过设置的 rtol。当矩阵尺度差异大、所求容差接近浮点运算能够达到的精度时,这种“返回成功但方程验收失败”需要单独处理。
这里针对 SciPy 共轭梯度法的递推残差路径。SciPy 1.18.1 的正式实现根据内部更新的残差决定收敛;2026 年 10 月的开发版本仍有真实残差大于容差、info=0 的记录。不能据此断言每个 info=0 都不可靠,也不能把所有迭代求解器视为使用同一种终止条件。
在接受解的位置检查原方程
cg 要求系数矩阵为厄米正定,实数情形即对称正定。先保留同一次求解的 A、b、初始值与容差;不满足数学前提时,应先改选适当的求解方法。下面是已有 NumPy 向量和矩阵的验收片段:
import numpy as np
from scipy.sparse.linalg import cg
rtol = 1e-8
atol = 0.0
x, info = cg(A, b, rtol=rtol, atol=atol, maxiter=500)
residual_norm = np.linalg.norm(b - A @ x)
threshold = max(rtol * np.linalg.norm(b), atol)
accepted = info == 0 and np.isfinite(residual_norm) and residual_norm <= threshold
A 和 b 换成原任务的数据,不要为了检查重新生成一套随机矩阵。对于 LinearOperator,A @ x 会再执行一次矩阵向量乘法,应把这项成本计入任务预算。零右端项不宜直接除以 norm(b);使用上述绝对阈值公式可避免这个除零问题。
返回码与验收结果都要保存。若 accepted 为假,阻止这份解进入要求该容差的后续计算,不要把它改标为收敛,也不要只截断日志中的小数位。
为什么追加 maxiter 可能无效
迭代过程用递推公式更新残差,浮点舍入会让它逐渐偏离重新计算的 b - A @ x。内部残差已经很小时,真实残差仍可能停在与机器精度、矩阵尺度和解的尺度有关的水平。此时提前判断成功,就不会继续用完新增的迭代预算。
记录矩阵和右端项的量级、工作 dtype、预条件器及初始值。若精度要求超过这组计算所能支持的范围,需要评估缩放、预条件、工作精度或求解策略;这些选择可能改变成本和收敛行为,不能随意放宽 rtol 让验收变绿。容差调整应来自任务的误差要求。
gmres 等接口有各自的数学条件与停止实现。切换方法可以作为有依据的对照,但换一种方法返回数值仍须验收原方程。把旧 x 重新当作初始值也不保证一定改善,反复重启应有次数上限,并记录真实残差是否下降。
这个问题与自定义算子缺少 _xp 的初始化异常不同:这里运算已经完成,失败的是数值结果是否达到约定。复查要覆盖原来的困难矩阵和一组可验证的小规模对照,比较真实残差及后续量,而不只检查 info。保留原依赖和输入记录,后续更换正式版本时仍用同一验收规则。


