我的 GMRES 实施有什么问题?
What's wrong with my GMRES implementation?
我正在尝试在 Jupyter Notebook 中实现 GMRES,即(如果您不知道):
这是我的代码:
import numpy as np
def GMRes(A, b, x0, e, nmax_iter, restart=None):
r = b - np.asarray(np.dot(A, x0)).reshape(-1)
x = []
q = [0] * (nmax_iter)
x.append(r)
q[0] = r / np.linalg.norm(r)
h = np.zeros((nmax_iter + 1, nmax_iter))
for k in range(nmax_iter):
y = np.asarray(np.dot(A, q[k])).reshape(-1)
for j in range(k):
h[j, k] = np.dot(q[j], y)
y = y - h[j, k] * q[j]
h[k + 1, k] = np.linalg.norm(y)
if (h[k + 1, k] != 0 and k != nmax_iter - 1):
q[k + 1] = y / h[k + 1, k]
b = np.zeros(nmax_iter + 1)
b[0] = np.linalg.norm(r)
result = np.linalg.lstsq(h, b)[0]
x.append(np.dot(np.asarray(q).transpose(), result) + x0)
return x
按照我的说法应该是正确的,但是当我执行的时候:
A = np.matrix('1 1; 3 -4')
b = np.array([3, 2])
x0 = np.array([1, 2])
e = 0
nmax_iter = 5
x = GMRes(A, b, x0, e, nmax_iter)
print(x)
注意:目前e
什么都不做。
我明白了:
[array([0, 7]), array([ 1., 2.]), array([ 1.35945946, 0.56216216]), array([ 1.73194463, 0.80759216]), array([ 2.01712479, 0.96133459]), array([ 2.01621042, 0.95180204])]
x[k]
应该接近(32/7, -11/7)
,因为这是结果,但它却接近(2, 1)
,我做错了什么?
我认为算法给出了正确的结果。
您正在尝试求解 Ax=b,其中:

如果您尝试手动找到解决方案,您要解决的矩阵运算等同于可以使用替换解决的系统。

如果您尝试解决它,您会发现解决方案是:

这与您的算法给出的解决方案相同。
您可以使用 scipy 中已有的 GMRES 实现仔细检查:
import scipy.sparse.linalg as spla
import numpy as np
A = np.matrix('1 1; 3 -4')
b = np.array([3, 2])
x0 = np.array([1, 2])
spla.gmres(A,b,x0)
输出
array([ 2., 1.])
请注意,此算法正在收敛到正确的结果,但速度太慢。收敛的 GMRES 迭代的最大次数不应超过矩阵 A 的维数。如果矩阵 A 的维数为 n,则第 (n+1) 个 Arnoldi 向量应为零,例如我们应该能够用 n 个 Arnoldi 向量完全跨越 Krylov space。我只应用以下补丁,一切都应该正常工作:
- for k in range(nmax_iter):
+ for k in range(min(nmax_iter, A.shape[0])):
y = np.asarray(np.dot(A, q[k])).reshape(-1)
- for j in range(k):
+ for j in range(k + 1):
解向量序列应该是:
[array([ 1. , 0.35294118]), array([ 2., 1.])]
例如我们收敛于我们预期的两次迭代,因为 n = 2.
我正在尝试在 Jupyter Notebook 中实现 GMRES,即(如果您不知道):
这是我的代码:
import numpy as np
def GMRes(A, b, x0, e, nmax_iter, restart=None):
r = b - np.asarray(np.dot(A, x0)).reshape(-1)
x = []
q = [0] * (nmax_iter)
x.append(r)
q[0] = r / np.linalg.norm(r)
h = np.zeros((nmax_iter + 1, nmax_iter))
for k in range(nmax_iter):
y = np.asarray(np.dot(A, q[k])).reshape(-1)
for j in range(k):
h[j, k] = np.dot(q[j], y)
y = y - h[j, k] * q[j]
h[k + 1, k] = np.linalg.norm(y)
if (h[k + 1, k] != 0 and k != nmax_iter - 1):
q[k + 1] = y / h[k + 1, k]
b = np.zeros(nmax_iter + 1)
b[0] = np.linalg.norm(r)
result = np.linalg.lstsq(h, b)[0]
x.append(np.dot(np.asarray(q).transpose(), result) + x0)
return x
按照我的说法应该是正确的,但是当我执行的时候:
A = np.matrix('1 1; 3 -4')
b = np.array([3, 2])
x0 = np.array([1, 2])
e = 0
nmax_iter = 5
x = GMRes(A, b, x0, e, nmax_iter)
print(x)
注意:目前e
什么都不做。
我明白了:
[array([0, 7]), array([ 1., 2.]), array([ 1.35945946, 0.56216216]), array([ 1.73194463, 0.80759216]), array([ 2.01712479, 0.96133459]), array([ 2.01621042, 0.95180204])]
x[k]
应该接近(32/7, -11/7)
,因为这是结果,但它却接近(2, 1)
,我做错了什么?
我认为算法给出了正确的结果。
您正在尝试求解 Ax=b,其中:
如果您尝试手动找到解决方案,您要解决的矩阵运算等同于可以使用替换解决的系统。
如果您尝试解决它,您会发现解决方案是:
这与您的算法给出的解决方案相同。
您可以使用 scipy 中已有的 GMRES 实现仔细检查:
import scipy.sparse.linalg as spla
import numpy as np
A = np.matrix('1 1; 3 -4')
b = np.array([3, 2])
x0 = np.array([1, 2])
spla.gmres(A,b,x0)
输出
array([ 2., 1.])
请注意,此算法正在收敛到正确的结果,但速度太慢。收敛的 GMRES 迭代的最大次数不应超过矩阵 A 的维数。如果矩阵 A 的维数为 n,则第 (n+1) 个 Arnoldi 向量应为零,例如我们应该能够用 n 个 Arnoldi 向量完全跨越 Krylov space。我只应用以下补丁,一切都应该正常工作:
- for k in range(nmax_iter):
+ for k in range(min(nmax_iter, A.shape[0])):
y = np.asarray(np.dot(A, q[k])).reshape(-1)
- for j in range(k):
+ for j in range(k + 1):
解向量序列应该是:
[array([ 1. , 0.35294118]), array([ 2., 1.])]
例如我们收敛于我们预期的两次迭代,因为 n = 2.