numpy对角线化是一个具有实数算术的斜对称矩阵?

时间:2016-08-01 20:41:20

标签: python numpy matrix linear-algebra lapack

任何偏斜对称矩阵( A ^ T = -A )都可以变成厄米特矩阵( iA < / strong>)并用复数对齐。但是also possible将它带入block-diagonal form with a special orthogonal transformation并仅使用真实算术找到它的eigevalues。这是在numpy的任何地方实现的吗?

2 个答案:

答案 0 :(得分:1)

我们来看看LAPACK librarie的dgeev()功能。该例程计算任何实际双精度方阵的特征值。此外,这个例程紧跟在numpy库的python函数numpy.linalg.eigvals()之后。

dgeev()中描述了A使用的方法。它需要将矩阵S缩减为documentation of LAPACK A

任何实矩阵A=QSQ^t都可表示为:

Q

其中:

  • QQ^t=I是一个真正的正交矩阵:S
  • A是一个实际的块上三角矩阵。 S对角线上的块大小为1×1或2×2。

实际上,如果A是偏对称的,那么这种分解似乎非常接近S的{​​{1}}。而且,真正看到偏斜对称矩阵A的Schur形式S是......偏斜对称的!

确实,让我们计算S^t=(Q^tAQ)^t S^t=Q^t(Q^tA)^t S^t=Q^tA^tQ S^t=Q^t(-A)Q S^t=-Q^tAQ S^t=-S 的转置:

Q

因此,如果det(Q)=1是特殊正交(S),则P是通过特殊正交变换获得的块对角线形式。否则,可以通过置换Q的前两列来计算特殊正交矩阵Sd,并通过改变符号来获得矩阵A的另一个Schur形式S_{12}S_{21}A=PSdP^t。确实,Sd。然后,A是通过特殊正交变换获得的output='real'的块对角线形式。

最后,即使应用于实数矩阵的real Schur form返回复数,也不会有很复杂的计算过程!

如果您只想计算真实的Schur表格,请使用带有参数import numpy as np import scipy.linalg as la a=np.random.rand(4,4) a=a-np.transpose(a) print "a= " print a #eigenvalue w, v =np.linalg.eig(a) print "eigenvalue " print w print "eigenvector " print v # Schur decomposition #import scipy #print scipy.version.version t,z=la.schur(a, output='real', lwork=None, overwrite_a=True, sort=None, check_finite=True) print "schur form " print t print "orthogonal matrix " print z 的函数 block diagonal form obtained by a special orthogonal transformation

只需要一段代码来检查:

catch

答案 1 :(得分:1)

是的,你可以通过在产品中间坚持单一转换来实现,因此我们得到了

  

A = V * U * V ^ -1 = V * T'* T * U * T'* T * V ^ { - 1}

一旦你明白了,你可以通过平铺事物来优化代码,但是让我们通过明确地形成T来实现天真的方式。

如果矩阵是偶数大小,则所有块都是复共轭。否则我们得到零作为特征值。特征值保证零实部,所以首先要清理噪声然后排序,使零点位于左上角(任意选择)。

n = 5
a = np.random.rand(n,n)
a=a-np.transpose(a)
[u,v] = np.linalg.eig(a)

perm = np.argsort(np.abs(np.imag(u)))
unew = 1j*np.imag(u[perm])

显然,我们需要对特征向量矩阵进行重新排序以保持等价。

vnew = v[:,perm]

到目前为止,我们除了在特征值分解中重新排序中间特征值矩阵之外什么也没做。现在我们从复杂的形式切换到实际的块对角形式。

首先,我们必须知道有多少零特征值

numblocks = np.flatnonzero(unew).size // 2
num_zeros = n - (2 * numblocks)

然后我们基本上,形成另一个单一的转换(这次复杂)并以同样的方式坚持

T = sp.linalg.block_diag(*[1.]*num_zeros,np.kron(1/np.sqrt(2)*np.eye(numblocks),np.array([[1.,1j],[1,-1j]])))

Eigs = np.real(T.conj().T.dot(np.diag(unew).dot(T)))
Evecs = np.real(vnew.dot(T))

这为您提供了新的实值分解。所以代码全部在一个地方

n = 5
a = np.random.rand(n,n)
a=a-np.transpose(a)
[u,v] = np.linalg.eig(a)

perm = np.argsort(np.abs(np.imag(u)))
unew = 1j*np.imag(u[perm])
vnew = v[perm,:]
numblocks = np.flatnonzero(unew).size // 2
num_zeros = n - (2 * numblocks)
T = sp.linalg.block_diag(*[1.]*num_zeros,np.kron(1/np.sqrt(2)*np.eye(numblocks),np.array([[1.,1j],[1,-1j]])))
Eigs = np.real(T.conj().T.dot(np.diag(unew).dot(T)))
Evecs = np.real(vnew.dot(T))
print(np.allclose(Evecs.dot(Eigs.dot(np.linalg.inv(Evecs))) - a,np.zeros((n,n))))

给出True。请注意,这是获得真实频谱分解的天真方式。有很多地方需要跟踪数值误差累积。

示例输出

Eigs
Out[379]: 
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        , -0.61882847,  0.        ,  0.        ],
       [ 0.        ,  0.61882847,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        , -1.05097581],
       [ 0.        ,  0.        ,  0.        ,  1.05097581,  0.        ]])

Evecs
Out[380]: 
array([[-0.15419078, -0.27710323, -0.39594838,  0.05427001, -0.51566173],
       [-0.22985364,  0.0834649 ,  0.23147553, -0.085043  , -0.74279915],
       [ 0.63465436,  0.49265672,  0.        ,  0.20226271, -0.38686576],
       [-0.02610706,  0.60684296, -0.17832525,  0.23822511,  0.18076858],
       [-0.14115513, -0.23511356,  0.08856671,  0.94454277,  0.        ]])