Python Arnoldi迭代的Wiki示例仅适用于实矩阵?

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的虚部似乎有问题。有人知道为什么维基百科代码不能产生预期的结果吗 工作示例:

Arnoldi方法的示例提供了一个Python示例,该示例生成矩阵
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数组……我必须进行大量的整形,才能使类似的东西工作。你是怎么绕过它的?@user1559897
v
应该是一个大小为
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