Python Arnoldi迭代的Wiki示例仅适用于实矩阵?
Arnoldi方法的示例提供了一个Python示例,该示例生成矩阵Python Arnoldi迭代的Wiki示例仅适用于实矩阵?,python,matrix,wikipedia,complex-numbers,Python,Matrix,Wikipedia,Complex Numbers,Arnoldi方法的示例提供了一个Python示例,该示例生成矩阵a的Krylov子空间的基。假设,如果A是Hermitian(即,如果A==A.conj().T),则该算法生成的Hessenberg矩阵h是三对角的()。然而,当我在真实世界的厄米矩阵上使用Wikipedia代码时,Hessenberg矩阵根本不是三对角矩阵。当我对A的实部进行计算时(因此A==A.T),我得到了一个三对角Hessenberg矩阵,因此A的虚部似乎有问题。有人知道为什么维基百科代码不能产生预期的结果吗 工作示例:
a
的Krylov子空间的基。假设,如果A
是Hermitian(即,如果A==A.conj().T
),则该算法生成的Hessenberg矩阵h
是三对角的()。然而,当我在真实世界的厄米矩阵上使用Wikipedia代码时,Hessenberg矩阵根本不是三对角矩阵。当我对A
的实部进行计算时(因此A==A.T
),我得到了一个三对角Hessenberg矩阵,因此A
的虚部似乎有问题。有人知道为什么维基百科代码不能产生预期的结果吗
工作示例:
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import circulant
def arnoldi_iteration(A, b, n):
m = A.shape[0]
h = np.zeros((n + 1, n), dtype=np.complex)
Q = np.zeros((m, n + 1), dtype=np.complex)
q = b / np.linalg.norm(b) # Normalize the input vector
Q[:, 0] = q # Use it as the first Krylov vector
for k in range(n):
v = A.dot(q) # Generate a new candidate vector
for j in range(k + 1): # Subtract the projections on previous vectors
h[j, k] = np.dot(Q[:, j], v)
v = v - h[j, k] * Q[:, j]
h[k + 1, k] = np.linalg.norm(v)
eps = 1e-12 # If v is shorter than this threshold it is the zero vector
if h[k + 1, k] > eps: # Add the produced vector to the list, unless
q = v / h[k + 1, k] # the zero vector is produced.
Q[:, k + 1] = q
else: # If that happens, stop iterating.
return Q, h
return Q, h
# Construct matrix A
N = 2**4
I = np.eye(N)
k = np.fft.fftfreq(N, 1.0 / N) + 0.5
alpha = np.linspace(0.1, 1.0, N)*2e2
c = np.fft.fft(alpha) / N
C = circulant(c)
A = np.einsum("i, ij, j->ij", k, C, k)
# Show that A is Hermitian
print(np.allclose(A, A.conj().T))
# Arbitrary (random) initial vector
np.random.seed(0)
v = np.random.rand(N)
# Perform Arnoldi iteration with complex A
_, h = arnoldi_iteration(A, v, N)
# Perform Arnoldi iteration with real A
_, h2 = arnoldi_iteration(np.real(A), v, N)
# Plot results
plt.subplot(121)
plt.imshow(np.abs(h))
plt.title("Complex A")
plt.subplot(122)
plt.imshow(np.abs(h2))
plt.title("Real A")
plt.tight_layout()
plt.show()
结果:
浏览了一些会议演示幻灯片后,我意识到当
A
很复杂时,在某个时候Q
必须结合起来。下面发布了正确的算法,以供参考,并标记了代码更改(请注意,此更正也已提交到Wikipedia条目):
将numpy导入为np
def-arnoldi_迭代(A,b,n):
m=A.shape[0]
h=np.zero((n+1,n),dtype=np.complex)
Q=np.zero((m,n+1),dtype=np.complex)
q=b/np.linalg.norm(b)
Q[:,0]=Q
对于范围(n)内的k:
v=A.点(q)
对于范围(k+1)内的j:
h[j,k]=np.dot(Q[:,j].conj(),v)#eps:
q=v/h[k+1,k]
Q[:,k+1]=Q
其他:
返回Q,h
返回Q,h
只是好奇你是如何让v=v-h[j,k]*Q[:,j]在numpy上工作的?我将v作为2d数组,将h[j,k]*Q[:,j]作为1d数组……我必须进行大量的整形,才能使类似的东西工作。你是怎么绕过它的?@user1559897v
应该是一个大小为m
的一维向量。确保正确定义了b
(定义了q
的大小,定义了v=A.dot(q)
import numpy as np
def arnoldi_iteration(A, b, n):
m = A.shape[0]
h = np.zeros((n + 1, n), dtype=np.complex)
Q = np.zeros((m, n + 1), dtype=np.complex)
q = b / np.linalg.norm(b)
Q[:, 0] = q
for k in range(n):
v = A.dot(q)
for j in range(k + 1):
h[j, k] = np.dot(Q[:, j].conj(), v) # <-- Q needs conjugation!
v = v - h[j, k] * Q[:, j]
h[k + 1, k] = np.linalg.norm(v)
eps = 1e-12
if h[k + 1, k] > eps:
q = v / h[k + 1, k]
Q[:, k + 1] = q
else:
return Q, h
return Q, h