np.linalg.eig 对同一个矩阵给出不同的特征向量
np.linalg.eig gives different eigenvectors for the same matrix
以下内容基于Python3.7.6.
我正在尝试使用名为 PySCF 的软件包来解决简单的计算化学问题。其中一项计算涉及对称为 Fock 矩阵的二维数组的评估。 PySCF 使用函数 get_fock() [1, 2] 生成它。对于我的一个测试用例,Fock 矩阵的计算结果为
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.]]
我尝试使用 energies, C = np.linalg.eig(F)
找到该矩阵的特征值和特征向量,它给出了以下特征向量矩阵:
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]]
然而,np.matmul(np.matmul(C.T,F),C)
应该 return 一个对角矩阵,其元素是 F
的特征值。这不是发生的事情,但我应该注意到 F
的 正确的特征值 (单独验证)确实存储在 energies
.
中
然后我分配了另一个矩阵 F0
与 F
完全相同的元素(这次,硬编码到脚本中)。在这种情况下,np.linalg.eig(F0)
实际上给了我一个不同的特征向量矩阵:
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]]
为了确保我没有发疯,我检查了 type
of F
和 F0
: <class 'numpy.ndarray'>
这两种情况。我还打印出 F-F0
,这只是一个预期的 0 矩阵。我在下面粘贴了我的脚本,它改编自 PySCF 示例脚本之一 [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)
同一个矩阵怎么会给出两组完全不同的特征向量呢? 如果正在进行某种简单的酉变换,这应该不会影响实值矩阵的 np.matmul(np.matmul(C.T,F),C)
关系(上面提到的)。 我完全迷失在这里并且不禁认为我错过了一些非常基本的东西。任何帮助将不胜感激。
嗯,你的矩阵是对称的,所以它保证是可对角化的,有一些V.T @ F @ V
,有V
一个正交矩阵。矩阵 V
在排列和乘以 -1
列时是唯一的。 (或者在对应于相同特征值的子空间上旋转,这里不是这种情况,因为你有不同的特征向量)。
numpy.linalg.eig 的文档说右特征值没有保证的顺序,特征向量有单位长度。这给了我们两个完整性检查。
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))
我检查了你的两个矩阵,确实 C0
是 F
的特征向量矩阵,而 C
不是。
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$')
到目前为止,输入矩阵可能不同。但是当我们检查正交性时 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 和一个小的加性噪声试了数千次,它起作用了。
以下内容基于Python3.7.6.
我正在尝试使用名为 PySCF 的软件包来解决简单的计算化学问题。其中一项计算涉及对称为 Fock 矩阵的二维数组的评估。 PySCF 使用函数 get_fock() [1, 2] 生成它。对于我的一个测试用例,Fock 矩阵的计算结果为
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.]]
我尝试使用 energies, C = np.linalg.eig(F)
找到该矩阵的特征值和特征向量,它给出了以下特征向量矩阵:
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]]
然而,np.matmul(np.matmul(C.T,F),C)
应该 return 一个对角矩阵,其元素是 F
的特征值。这不是发生的事情,但我应该注意到 F
的 正确的特征值 (单独验证)确实存储在 energies
.
然后我分配了另一个矩阵 F0
与 F
完全相同的元素(这次,硬编码到脚本中)。在这种情况下,np.linalg.eig(F0)
实际上给了我一个不同的特征向量矩阵:
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]]
为了确保我没有发疯,我检查了 type
of F
和 F0
: <class 'numpy.ndarray'>
这两种情况。我还打印出 F-F0
,这只是一个预期的 0 矩阵。我在下面粘贴了我的脚本,它改编自 PySCF 示例脚本之一 [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)
同一个矩阵怎么会给出两组完全不同的特征向量呢? 如果正在进行某种简单的酉变换,这应该不会影响实值矩阵的 np.matmul(np.matmul(C.T,F),C)
关系(上面提到的)。 我完全迷失在这里并且不禁认为我错过了一些非常基本的东西。任何帮助将不胜感激。
嗯,你的矩阵是对称的,所以它保证是可对角化的,有一些V.T @ F @ V
,有V
一个正交矩阵。矩阵 V
在排列和乘以 -1
列时是唯一的。 (或者在对应于相同特征值的子空间上旋转,这里不是这种情况,因为你有不同的特征向量)。
numpy.linalg.eig 的文档说右特征值没有保证的顺序,特征向量有单位长度。这给了我们两个完整性检查。
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))
我检查了你的两个矩阵,确实 C0
是 F
的特征向量矩阵,而 C
不是。
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$')
到目前为止,输入矩阵可能不同。但是当我们检查正交性时 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 和一个小的加性噪声试了数千次,它起作用了。