Python numpy可以用实数算法对斜对称矩阵进行对角化吗?
任何斜对称矩阵(A^T=-A)都可以转换为厄米矩阵(iA)并用复数对角化。但它是把它带入,并找到它的Eige值只使用真正的算术。这在numpy的任何地方都可以实现吗?让我们看看LAPACK库的功能。此例程计算任何实双精度平方矩阵的特征值。此外,此例程位于numpy库的python函数后面Python numpy可以用实数算法对斜对称矩阵进行对角化吗?,python,numpy,matrix,linear-algebra,lapack,Python,Numpy,Matrix,Linear Algebra,Lapack,任何斜对称矩阵(A^T=-A)都可以转换为厄米矩阵(iA)并用复数对角化。但它是把它带入,并找到它的Eige值只使用真正的算术。这在numpy的任何地方都可以实现吗?让我们看看LAPACK库的功能。此例程计算任何实双精度平方矩阵的特征值。此外,此例程位于numpy库的python函数后面 dgeev()使用的方法如中所述。它需要将矩阵A缩减为其S 任何实方阵A都可以表示为: A=QSQ^t 其中: Q是一个实正交矩阵:QQ^t=I S是实块上三角矩阵。S对角线上的块大小为1×1或2×2 事实
dgeev()
使用的方法如中所述。它需要将矩阵A
缩减为其S
任何实方阵A
都可以表示为:
A=QSQ^t
其中:
是一个实正交矩阵:Q
QQ^t=I
是实块上三角矩阵。S对角线上的块大小为1×1或2×2S
A
是斜对称的,那么这种分解似乎非常接近A
的A。此外,我们还可以看到,斜对称矩阵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
是通过特殊正交变换获得的块对角形式。另外,可以通过排列Q
的前两列来计算一个特殊的正交矩阵P
,并且通过改变S_{12}
和S_{21}
的符号来获得矩阵a
的另一种舒尔形式Sd
。实际上,A=PSdP^t
。然后,Sd
是通过特殊正交变换获得的a
的块对角形式
最后,即使应用于实数矩阵返回复数,也几乎不需要复杂的计算
如果您只想计算实Schur形式,请使用带有参数output='real'
的函数
只需一段代码来检查:
将numpy导入为np
将scipy.linalg作为la导入
a=np.random.rand(4,4)
a=a-np.转置(a)
打印“a=”
打印
#特征值
w、 v=np.linalg.eig(a)
打印“特征值”
打印w
打印“特征向量”
印刷品
#舒尔分解
#进口西皮
#打印scipy.version.version
t、 z=la.schur(a,output='real',lwork=None,overwrite\u a=True,sort=None,check\u finite=True)
打印“舒尔表格”
打印t
打印“正交矩阵”
打印z
<代码> > P>是的,您可以通过在产品的中间插入一个酉变换,从而得到
A=V*U*V^-1=V*T'*T*U*T'*T*V^{-1}
一旦你有了这个想法,你可以通过平铺来优化代码,但是让我们通过显式地形成T来用一种简单的方式来实现
如果矩阵大小为偶数,则所有块都是复数共轭体。否则我们得到一个零作为特征值。特征值保证有零实部,因此第一件事是清除噪声,然后排序,使零位于左上角(任意选择)
显然,我们也需要对特征向量矩阵重新排序,以保持其等价性
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))))
给出真值
。请注意,这是获得真实光谱分解的简单方法。有很多地方需要跟踪数值误差累积
示例输出
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. ]])
你为什么要那样?无论哪种方式,特征值都是相同的。
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. ]])