超松弛迭代法
超松弛迭代法(successive over-relaxation,SOR)在 Gauss–Seidel 的逐分量修正上乘一个松弛参数。参数为一时回到 GS;大于一时沿当前坐标的修正方向多走一些,小于一时少走一些。能否加速取决于矩阵及参数,过大的超调会使迭代不收敛。
一次超调的具体数值
对系统 、,精确解为 。取松弛参数 ,按先 后 的顺序更新: 从零开始,第一轮为 ,第二轮为 。第二轮超过精确值并不自动意味着发散;收敛应看全局误差或残差,而不是每个分量是否一直从同一侧接近。
一般逐分量公式
对 ,设对角元非零。先利用新下三角、旧上三角形成当前坐标的 GS 值,再与旧值组合: 若 ,迭代矩阵是 它由三角求解应用,不需显式形成逆。对所有初值收敛等价于 。Netlib 的 SOR 章节说明了松弛参数、谱与收敛条件。[1]
对称正定情形的完整收敛论证
若 实对称正定,二次能量 严格凸且水平集有界。某个坐标更新前的残量记为 ,其中已经包含当前轮此前的更新。SOR 位移为 。精确展开能量变化: 当 ,每次坐标更新都下降能量。能量有下界,所以各坐标所遇残量的平方总和有限,残量趋零,坐标位移也趋零。迭代有聚点;因一整轮位移趋零,聚点同时满足每个坐标的残量为零,即 。正定性使该解唯一,所有聚点相同,因此整个序列收敛。
这个证明同时表明范围的作用。若 ,能量下降量为零。主例从零开始依次得到 ,三轮循环不收敛。更一般地,,若所有特征值模都小于一,必须有 ,因此实参数 也是收敛的必要范围;对非正定矩阵,它不再是充分条件。
本例的最优参数与适用范围
主例的迭代矩阵为 其迹为 ,行列式为 。特征根从实数合并为共轭对的临界点由 给出,在 内得到 临界点后两根互为共轭,模为 并随参数增加;临界点前的较大实根下降,故此处达到最小谱半径 。参数一的谱半径为 ,所以本例有明显改善。一般最优参数依赖矩阵结构,某些 Poisson 网格公式有额外排序与结构条件,不能照搬为所有 SPD 系统的公式。
有解变式取对角系统,误差每轮乘 。此时最优值是一,一步到解;任何超松弛都没有帮助。它说明“越大越快”不成立,最优参数来自具体耦合结构。
可运行的正定矩阵实现
代码以 NumPy 检查实对称正定性,并使用 ;从零出发,以真实残差验收,返回近似与轮数,不修改输入。一次 Cholesky 检查成本约 ,稠密每轮更新为 ,矩阵存储为 。若大稀疏问题的正定性已由模型保证,通常不为检查而额外做完整稠密分解。
import numpy as np
def sor(A, b, omega=1.2, tol=1e-12, maxiter=1000):
A, b = np.array(A, dtype=float, copy=True), np.array(b, dtype=float, copy=True)
if b.ndim != 1 or not b.size or A.shape != (b.size, b.size):
raise ValueError("square matrix matching b required")
if not np.isfinite(A).all() or not np.isfinite(b).all() or not np.array_equal(A, A.T):
raise ValueError("finite symmetric data required")
if not np.isfinite(omega) or not 0 < omega < 2 or not np.isfinite(tol) or tol <= 0:
raise ValueError("0 < omega < 2 and positive tolerance required")
if not isinstance(maxiter, int) or maxiter < 0:
raise ValueError("nonnegative integer iteration limit required")
np.linalg.cholesky(A)
x = np.zeros_like(b); target = tol*max(1.0, np.linalg.norm(b, np.inf))
for k in range(maxiter+1):
if np.linalg.norm(b-A@x, np.inf) <= target:
return x, k
if k == maxiter:
break
old = x.copy()
for i in range(b.size):
gs = (b[i]-A[i, :i]@x[:i]-A[i, i+1:]@old[i+1:])/A[i, i]
x[i] = (1-omega)*old[i]+omega*gs
if not np.isfinite(x).all():
raise ArithmeticError("nonfinite SOR iterate")
raise RuntimeError("true residual did not reach tolerance")
print(sor([[2, -1], [-1, 2]], [1, 1])) # near [1, 1]
print(sor([[2, -1], [-1, 2]], [1, 1], 8-4*np.sqrt(3)))参考资料
- ↑ Richard Barrett et al. Templates for the Solution of Linear Systems,Successive Overrelaxation。