cg迭代法(Conjugate gradient method)求解线性方程组
Author : zbzhen, Modified : Sat Sep 9 14:25:34 2023
矩阵A为满秩对称矩阵,求线性方程组
Ax=b
设x0=0, 如果非零向量组{P0,P1,P2,…}线性无关, 当k+1等于向量xk+1的维数时,则向量xk+1可写成
xk+1=j=0∑kαjPj
其中αj为待定标量系数. 或者可写成迭代格式
xk+1=xk+αkPk
记残差
rk=b−Axk
联立上面两式可得
rk+1=rk−αkAPk
或可改写成
APk=αk1(rk−rk+1)
接下来就是需要想办法找到合适的αk与Pk使得计算复杂度尽可能少
取P0=r0, 同时把Pk写成r0,r1,r2,⋯,rk的线性组合, 使得
PjTAPk=0,j=k.
也可写成递推格式,
Pk+1=rk+1+βkPk
可选取合适的βk使得
rkTrj=0,k=j.
于是联立上面四个等式,在上面倒数第二式左乘PkTA, 然后由正交性可得
βk=−PkTAPkPkTArk+1=−PkTAPkrk+1TAPk=−αkPkTAPkrk+1T(rk−rk+1)=αkPkTAPkrk+1Trk+1
最后就是αk的推导. 根据
PkTAPk=(rk+βk−1Pk−1)TAPk=rkTAPk=αk1rkT(rk−rk+1)=αk1rkTrk
即得
αk=PkTAPkrkTrk
进而得到
βk=rkTrkrk+1Trk+1
需要注意的是,上面的公式推导过程似乎并没有用到完全正交性, 只是用到了
Pk+1TAPk=rk+1Trk=0
但事实上, 根据两个递推公式(P0=r0)
Pk+1=rk+1+βkPk 与 rk+1=rk−αkAPk
可以得到完全正交公式PjTAPk=rkTrj=0,j=k
给定A,b,x0, 求出x=A−1b
初始化:r0=b−Ax0, P0=r0, k=0
如果没有收敛:
-
αk=PkTAPkrkTrk
-
xk+1=xk+αkPk
-
rk+1=rk−αkAPk
-
βk=rkTrkrk+1Trk+1
-
Pk+1=rk+1+βkPk
-
k←k+1
为了使得不重复计算APk以及rkTrk,因此算法可以优化为:
给定A,b,x0, 求出x=A−1b
初始化:r0=b−Ax0, P0=r0, k=0, s0=r0Tr0
如果没有收敛:
- dk=APk
- αk=PkTdksk
- xk+1=xk+αkPk
- rk+1=rk−αkdk
- sk+1=rk+1Trk+1
- Pk+1=rk+1+sksk+1Pk
- k←k+1
function x = conjgrad(A, b, x)
r = b - A * x;
p = r;
rsold = r' * r;
for i = 1:length(b)
Ap = A * p;
alpha = rsold / (p' * Ap);
x = x + alpha * p;
r = r - alpha * Ap;
rsnew = r' * r;
if sqrt(rsnew) < 1e-10
break
end
p = r + (rsnew / rsold) * p;
rsold = rsnew;
end
end
import numpy as np
def cg(A, b, x):
r = b - A @ x
p = r
rsold = r @ r
for i in range(len(b)):
Ap = A @ p
alpha = rsold / (p @ Ap)
x += alpha * p
r -= alpha * Ap
rsnew = r @ r
if np.sqrt(rsnew) < 1e-10:
break
p = r + (rsnew / rsold) * p
rsold = rsnew
print(np.sqrt(rsnew), i)
return x
def pcg(A, b, x, Minv):
r = b - A @ x
z = Minv @ r
p = z
rsold = z @ r
for i in range(len(b)):
Ap = A @ p
alpha = rsold / (p @ Ap)
x += alpha * p
r -= alpha * Ap
z = Minv @ r
rsnew = z @ r
if np.sqrt(rsnew) < 1e-10:
break
p = z + (rsnew / rsold) * p
rsold = rsnew
print(np.sqrt(rsnew), i)
return x