用Python找到矩阵特征多项式的零点

时间:2018-01-19 10:00:35

标签: python matlab numpy sympy eigenvalue

给定 N x N 对称矩阵C N x N 对角矩阵I,找到等式{{的解1}}。换句话说,要找到det(λI-C)=0的(广义)特征值。

我知道如何使用内置函数在MATLAB中解决这个问题:

第一路:

C

第二路:

function lambdas=eigenValues(C,I)
    syms x;
    lambdas=sort(roots(double(fliplr(coeffs(det(C-I*x))))));

但是,我需要使用Python。在NumPy和SymPy中有类似的功能,但是,根据文档(numpysympy),它们只需要一个矩阵 C 作为输入。但是,结果与Matlab产生的结果不同。而且,SymPy制作的符号解决方案也没有用。也许我做错了什么?如何找到解决方案?

实施例

  • MATLAB:

%INPUT

[V,D]=eig(C,I);

%RESULT

I =

     2     0     0
     0     6     0
     0     0     5
C =

     4     7     0
     7     8    -4
     0    -4     1

[v,d]=eig(C,I)
  • Python 3.5:

%INPUT

v =

    -0.3558   -0.3109   -0.5261
     0.2778    0.1344   -0.2673
     0.2383   -0.3737    0.0598


d =

       -0.7327    0         0
        0    0.4876         0
        0         0    3.7784

%RESULT

I=np.matrix([[2,0,0],
                 [0,6,0],
                 [0,0,5]])

C=np.matrix([[4,7,0],[7,8,-4],[0,-4,1]])


np.linalg.eigh(C)

3 个答案:

答案 0 :(得分:1)

至少如果I具有正对角线条目,您可以简单地解决转换后的系统:

# example problem
>>> A = np.random.random((3, 3))
>>> A = A.T @ A
>>> I = np.identity(3) * np.random.random((3,))

# transform 
>>> J = np.sqrt(np.einsum('ii->i', I))
>>> B = A / np.outer(J, J)

# solve
>>> eval_, evec = np.linalg.eigh(B)

# back transform result
>>> evec /= J[:, None]

# check
>>> A @ evec
array([[ -1.43653725e-02,   4.14643550e-01,  -2.42340866e+00],
       [ -1.75615960e-03,  -4.17347693e-01,  -8.19546081e-01],
       [  1.90178603e-02,   1.34837899e-01,  -1.69999003e+00]])
>>> eval_ * (I @ evec)
array([[ -1.43653725e-02,   4.14643550e-01,  -2.42340866e+00],
       [ -1.75615960e-03,  -4.17347693e-01,  -8.19546081e-01],
       [  1.90178603e-02,   1.34837899e-01,  -1.69999003e+00]])

OP的例子。重要提示:必须使用np.array ICnp.matrix将无效。

>>> I=np.array([[2,0,0],[0,6,0],[0,0,5]])
>>> C=np.array([[4,7,0],[7,8,-4],[0,-4,1]])
>>> 
>>> J = np.sqrt(np.einsum('ii->i', I))
>>> B = C / np.outer(J, J)
>>> eval_, evec = np.linalg.eigh(B)
>>> evec /= J[:, None]
>>> 
>>> evec
array([[-0.35578356, -0.31094779, -0.52605088],
       [ 0.27778714,  0.1343625 , -0.267297  ],
       [ 0.23826117, -0.37371199,  0.05975754]])
>>> eval_
array([-0.73271478,  0.48762792,  3.7784202 ])

如果I有正面和负面条目,请使用eig代替eigh,然后再将平方根转换为complex dtype

答案 1 :(得分:1)

与其他答案不同,我假设通过符号 I 表示单位矩阵, Ix = x

您要解决的问题 Cx =λIx,是所谓的标准特征值问题, 并且大多数特征值求解器解决了该格式中描述的问题,因此 Numpy函数具有签名eig(C)

如果您的 C 矩阵是对称矩阵,并且您的问题确实是一个标准的特征值问题,我建议使用numpy.linalg.eigh,这是针对此类问题进行优化的。 / p>

相反,如果你的问题确实是一个广义的特征值问题,例如,频率方程 Kx =ω²Mx你可以使用scipy.linalg.eigh,它支持那种类型的问题陈述对称矩阵。

eigvals, eigvecs = scipy.linalg.eigh(C, I)

关于特征值的差异,Numpy实现不对它们的排序提供保证,因此它可能只是一个不同的排序,但如果你的问题确实是一个普遍的问题( I 不是身份矩阵......)解决方案当然是不同的,你必须使用eigh的Scipy实现。

如果差异在特征向量内,请记住特征向量在任意比例因子中是已知的,并且再次排序可能是未定义的(但是,当然,它们的顺序与您具有特征值的顺序相同) ) - scipy.linalg.eigh的情况略有不同,因为在这种情况下,特征值被排序,特征向量相对于第二个矩阵参数(在您的示例中为 I )进行归一化。

Ps:scipy.linalg.eigh行为(即,排序的特征值和归一化的特征向量)非常方便 my 用例,我用它来解决标准的特征值问题。

答案 2 :(得分:0)

使用SymPy

>>> from sympy import *
>>> t = Symbol('t')
>>> D = diag(2,6,5)
>>> S = Matrix([[ 4, 7, 0],
                [ 7, 8,-4],
                [ 0,-4, 1]])
>>> (t*D - S).det()
60*t**3 - 212*t**2 - 77*t + 81

计算完全根:

>>> roots = solve(60*t**3 - 212*t**2 - 77*t + 81,t)
>>> roots
[53/45 + (-1/2 - sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3) + 14701/(8100*(-1/2 - sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)), 53/45 + 14701/(8100*(-1/2 + sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(312469/182250 + sqrt(797521629)*I/16200)**(1/3), 53/45 + 14701/(8100*(312469/182250 + sqrt(797521629)*I/16200)**(1/3)) + (312469/182250 + sqrt(797521629)*I/16200)**(1/3)]

计算根的浮点近似值:

>>> for r in roots:
...     r.evalf()
... 
0.487627918145732 + 0.e-22*I
-0.73271478047926 - 0.e-22*I
3.77842019566686 - 0.e-21*I

请注意,根是真实的。