np.linalg.eig为同一矩阵提供不同的特征向量 [英] np.linalg.eig gives different eigenvectors for the same matrix

查看:72
本文介绍了np.linalg.eig为同一矩阵提供不同的特征向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下内容基于Python 3.7.6.

我正在尝试使用名为PySCF的软件包来解决简单的计算化学问题.其中一项计算涉及对称为Fock矩阵的2D数组的评估.PySCF使用函数get_fock()[

至此,输入矩阵可能有所不同.但是当我们检查正交性 C @ C.T〜I 时,我会说它违反了eig的陈述.

 plt.subplot(121),plt.imshow(C @ C.T),plt.title('$ C C ^ T $')plt.subplot(122),plt.imshow(C0 @ C0.T),plt.title('$ C_0 C_0 ^ T $') 

如果可以重现故障,这些库将在许多地方使用,这将是一个重要的发现(BUG).

我测试了上面关于2至10维随机矩阵的断言,并且以上两个条件在 1e-10 的容差内都是有效的.可以和F的结构相提并论吗?还尝试了使用F0并产生很小的附加噪声数千次,并且效果很好.

The following is based on Python 3.7.6.

I am trying to use a package called PySCF for simple computational chemistry problems. One of the calculations involves the evaluation of a 2D array called the Fock matrix. PySCF generates this using the function get_fock() [1, 2]. For one of my test cases, the Fock matrix evaluates to

F = [[ 2. -1.  0.  0.  0. -1.]
 [-1.  2. -1.  0.  0.  0.]
 [ 0. -1.  2. -1.  0.  0.]
 [ 0.  0. -1.  2. -1.  0.]
 [ 0.  0.  0. -1.  2. -1.]
 [-1.  0.  0.  0. -1.  2.]]

I tried to find the eigenvalues and eigenvectors for this matrix using energies, C = np.linalg.eig(F), which gives the following matrix of eigenvectors:

C = [[-0.40824829  0.57735027  0.40824829  0.57735027  0.2468088   0.08939109]
 [ 0.40824829 -0.28867513  0.40824829  0.28867513 -0.57541553 -0.44927503]
 [-0.40824829 -0.28867513  0.40824829 -0.28867513  0.32860673 -0.53866612]
 [ 0.40824829  0.57735027  0.40824829 -0.57735027  0.2468088  -0.08939109]
 [-0.40824829 -0.28867513  0.40824829 -0.28867513 -0.57541553  0.44927503]
 [ 0.40824829 -0.28867513  0.40824829  0.28867513  0.32860673  0.53866612]]

However, np.matmul(np.matmul(C.T,F),C) should then return a diagonal matrix whose elements are the eigenvalues of F. This is not what happens, but I should note that the correct eigenvalues (verified separately) of F are indeed stored in energies.

I then assigned another matrix F0 exactly the same elements as F (this time, hard-coded into the script). In this case, np.linalg.eig(F0) actually gave me a different eigenvector matrix:

C0 = [[ 0.23192061  0.41790651 -0.52112089 -0.23192061  0.52112089 -0.41790651]
 [-0.41790651 -0.52112089  0.23192061 -0.41790651  0.23192061 -0.52112089]
 [ 0.52112089  0.23192061  0.41790651 -0.52112089 -0.41790651 -0.23192061]
 [-0.52112089  0.23192061 -0.41790651 -0.52112089 -0.41790651  0.23192061]
 [ 0.41790651 -0.52112089 -0.23192061 -0.41790651  0.23192061  0.52112089]
 [-0.23192061  0.41790651  0.52112089 -0.23192061  0.52112089  0.41790651]]

To make sure I'm not insane, I checked the type of F and F0: <class 'numpy.ndarray'> in both cases. I also printed out F-F0 which is just a 0-matrix as expected. I have pasted my script below, which is an adaptation of one of the PySCF example scripts [3].

import numpy as np
from numpy import zeros, matrix
from pyscf import gto, scf, ao2mo, cc, tools

hubbard_U = 2.
hubbard_t = 1.

mol = gto.M(verbose=4)
n = n_basis = 6
mol.nelectron = 12
mol.verbose = 9
mol.incore_anyway = True

h1 = np.zeros((n,n))
for i in range(n-1):
    h1[i,i+1] = h1[i+1,i] = -hubbard_t # -ve Hubbard t
h1[n-1,0] = h1[0,n-1] = -hubbard_t # periodicity

eri = np.zeros((n,n,n,n))
for i in range(n):
    eri[i,i,i,i] = hubbard_U # Hubbard U

mf = scf.RHF(mol)
mf.conv_tol = 1e-8
mf.get_hcore = lambda *args: h1
mf.get_ovlp = lambda *args: np.eye(n)
mf._eri = ao2mo.restore(8, eri, n)
mf.kernel(np.ones((n, n)))

F = np.copy(mf.get_fock())

print('F =')
print(F)
energies, C = np.linalg.eig(F)
print('\nC =', C)
F0 = [[2., -1.,  0.,  0.,  0.,  0.],
 [-1., 2., -1.,  0.,  0.,  0.],
 [ 0., -1., 2., -1.,  0.,  0.],
 [ 0.,  0., -1., 2., -1.,  0.],
 [ 0.,  0.,  0., -1., 2., -1.],
 [ 0.,  0.,  0.,  0., -1., 2.]]
print('\nF - F0 =', F-F0)

energies0, C0 = np.linalg.eig(F0)
print('\nC0 =', C0)

How is it that the exact same matrix can give two completely different sets of eigenvectors? If there were some kind of simple unitary transformation going on, this should not affect the np.matmul(np.matmul(C.T,F),C) relation (mentioned above) for a real-valued matrix. I am completely lost here and can't help but think that I am missing something very fundamental. Any help would be appreciated.

解决方案

Well, your matrix is symmetric, so it is guaranteed to be diagonalizable, with some V.T @ F @ V, with V an orthogonal matrix. The matrix V is unique up to permutation and multiplications by -1 of the columns. (Or rotations over the subspaces corresponding to the same eigenvalues, that is not the case here since you have distinct eigen vectors).

The documentation of numpy.linalg.eig says that the right-eigenvalues do not have a guaranteed order and that the eigenvectors have unit length. This gives us two sanity checks.

        D, W = np.linalg.eig(F)
        assert(np.all(np.abs( W @ W.T - np.eye(W.shape[0])) < tol))
        assert(np.all(np.abs( F @ W - W @ np.diag(D)) < tol))

I checked your two matrices, and indeed C0 is an eigenvector matrix for F, while C is not.

plt.subplot(121), plt.imshow(C.T @ F0 @ C), plt.title('$C^T F C$')
plt.subplot(122), plt.imshow(C0.T @ F0 @ C0), plt.title('$C_0 F C_0$')

To this point it could be the case that the input matrix was different. But when we check for the orthogonality C @ C.T ~ I I would say that it violates the statements of eig.


plt.subplot(121), plt.imshow(C @ C.T), plt.title('$C C^T$')
plt.subplot(122), plt.imshow(C0 @ C0.T), plt.title('$C_0 C_0^T$')

These libraries are used in many places if you can reproduce the failure this would be an important (BUG) finding.

I tested the assertions above for random matrices of dimension 2 to 10 and the two conditions above are valid within a tolerance of 1e-10. Could be somethign with the structure of F? also tried with your F0 with a small additive noise thousands of times and it works.

这篇关于np.linalg.eig为同一矩阵提供不同的特征向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆