【问题标题】:Problem with finding the inverse of a matrix in python在python中找到矩阵的逆问题
【发布时间】:2021-10-18 01:05:30
【问题描述】:

我正在尝试计算雅可比矩阵的逆矩阵。我使用 sympy 计算了雅可比行列式。但是,现在当我尝试 inv 矩阵时,我得到了一个我不明白的错误。如果有人可以帮助我,那就太好了

import numpy as py
from numpy.linalg import inv
from sympy import Matrix
import warnings

def f1(y1, y2, y3, y1_old, dt):
    return y1_old + (-0.04*y1 + 10**4*y2*y3)*dt

def f2(y1, y2, y3, y2_old, dt):
    return y2_old + (0.04*y1 - 10**4*y2*y3 - (3.10**7)*(y2**2))*dt

def f3(y1, y2, y3, y3_old, dt):
    return y3_old + ((3.10**7)*(y2**2))*dt

def j(y1,y2,y3):
    a = Matrix(('-0.04*y1 + 10**4*y2*y3','0.04*y1 - 10**4*y2*y3 - (3.10**7)* 
    (y2**2)','(3.10^7)*(y2**2)')).jacobian(('y1', 'y2', 'y3'))
    a = str(a)
    a = eval(a)
    return a

warnings.filterwarnings("ignore", category=DeprecationWarning)

y_old = py.zeros((3,1))
y_old[0] = 1

#Guess values for the implicit variable
y_guess = 2*py.ones((3,1))

#New values - assumed initially
y_new = py.ones((3,1))

F = py.copy(y_new)

start_time = 0
end_time = 10
dt = 0.01
nt = py.arange(start_time,end_time,dt)

error = 9e9
tol = 1e-10
alpha = 0.8
#for i in range(0,len(nt)):

#while error>tol:

jac = j(y_guess[0],y_guess[1],y_guess[2])

F[0] = f1(y_guess[0],y_guess[1],y_guess[2], y_old[0], dt)
F[1] = f2(y_guess[0],y_guess[1],y_guess[2], y_old[1], dt)
F[2] = f3(y_guess[0],y_guess[1],y_guess[2], y_old[2], dt)

j = inv(jac)#error

这是我得到的错误:

enter image description here

【问题讨论】:

  • that 有帮助吗?
  • 不要使用 eval 原因在这些情况下可能效率低下。 sympy 也可以计算非符号数学,因此 j 函数也可以是:def j(y1, y2, y3): return Matrix((-0.04*y1 + 10**4*y2*y3, 0.04*y1 - 10**4*y2*y3 - (3.10**7)* (y2**2), (3.10^7)*(y2**2))).jacobian((y1, y2, y3))(从计算中删除字符串)
  • 这行得通,但它不会计算导数 wrt 数。也就是说,我不能用值代替变量 y1、y2 和 y3。
  • 对于我们这些无法运行您的代码的人来说,显示jac 将是礼貌的做法。我猜它是 object dtype,可能包含 sympy 符号。或ragged(因为你关闭了警告)

标签: python sympy


【解决方案1】:

这里有很多问题。首先不要关闭警告:它们的存在是有原因的。您应该看到的警告是:

sympy/matrices/repmatrix.py:102: SymPyDeprecationWarning: 

non-Expr objects in a Matrix has been deprecated since SymPy 1.9. Use
list of lists, TableForm or some other data structure instead. See
https://github.com/sympy/sympy/issues/21497 for more info.

  deprecated_since_version="1.9"

看到该警告是因为您将 SymPy 矩阵的某些元素设置为 NumPy 数组,因此您的矩阵看起来像

In [2]: jac
Out[2]: 
⎡-0.04     [20000.0]      [20000.0] ⎤
⎢                                   ⎥
⎢0.04   [-31005.0456444]  [-20000.0]⎥
⎢                                   ⎥
⎣  0    [11005.0456444]       0     ⎦

将来类似的事情会立即引发异常。该警告是一种礼貌的提醒,您应该更改您的代码,否则它将不适用于 SymPy 的未来版本。

在您更好地了解 SymPy 和 NumPy 各自的功能之前,我建议您只使用其中一个,而不是将它们混合在一起。

你有像3.10^7 这样的数字,我认为它应该是30000000.0,但实际上应该写成3e73*10**7

在 SymPy 中执行此操作的正常方法是:

In [9]: y1, y2, y3 = symbols('y1, y2, y3')

In [10]: a = Matrix([-0.04*y1 + 10**4*y2*y3, 0.04*y1 - 10**4*y2*y3 - 3e7*y2**2, 3e7*y2**2])

In [11]: a
Out[11]: 
⎡        -0.04⋅y₁ + 10000⋅y₂⋅y₃        ⎤
⎢                                      ⎥
⎢                       2              ⎥
⎢0.04⋅y₁ - 30000000.0⋅y₂  - 10000⋅y₂⋅y₃⎥
⎢                                      ⎥
⎢                         2            ⎥
⎣            30000000.0⋅y₂             ⎦

In [12]: jac = a.jacobian([y1, y2, y3])

In [13]: jac
Out[13]: 
⎡-0.04          10000⋅y₃           10000⋅y₂ ⎤
⎢                                           ⎥
⎢0.04   -60000000.0⋅y₂ - 10000⋅y₃  -10000⋅y₂⎥
⎢                                           ⎥
⎣  0          60000000.0⋅y₂            0    ⎦

然后,如果您想要逆矩阵,您可以使用jac.inv() 方法,以便 SymPy 可以计算矩阵的逆矩阵。或者,您可以将值替换为符号,然后转换为 NumPy 数组并使用 NumPy 的 inv 函数。

无论哪种方式,您都会遇到问题,因为对于符号 y1y2y3 的所有可能值,矩阵都是奇异的:

In [14]: jac.det()
Out[14]: 0

In [15]: jac.inv()
---------------------------------------------------------------------------
NonInvertibleMatrixError

很容易看到行总和为零,因此矩阵没有满秩。

【讨论】:

    【解决方案2】:

    显示问题的另一种方式,没有sympy 漂亮的打印

    In [5]: jac = j(y_guess[0],y_guess[1],y_guess[2])
    In [6]: jac
    Out[6]: 
    Matrix([
    [-0.04,        [20000.0],  [20000.0]],
    [ 0.04, [-31005.0456444], [-20000.0]],
    [    0,  [11005.0456444],          0]])
    

    numpy inv 适用于数值数组。由于jac 中混合了列表和标量,结果是一个对象 dtype 数组。

    In [7]: np.array(jac)
    Out[7]: 
    array([[-0.0400000000000000, [20000.0], [20000.0]],
           [0.0400000000000000, [-31005.0456444], [-20000.0]],
           [0, [11005.0456444], 0]], dtype=object)
    
    In [8]: np.linalg.inv(_)
    Traceback (most recent call last):
      File "<ipython-input-8-61bbaec16d5b>", line 1, in <module>
        np.linalg.inv(_)
      File "<__array_function__ internals>", line 5, in inv
      File "/usr/local/lib/python3.8/dist-packages/numpy/linalg/linalg.py", line 545, in inv
        ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
    TypeError: No loop matching the specified signature and casting was found for ufunc inv
    

    我不知道您是否可以清理 jac 公式,使其不使用标量和列表的混合。无论如何,很明显混合使用sympynumpy 不适合新手,尤其是如果他忽略了检查中间变量。

    清理多余的[]:

    In [14]: M = np.array([[-0.0400000000000000, 20000.0, 20000.0],
        ...:        [0.0400000000000000, -31005.0456444, -20000.0],
        ...:        [0, 11005.0456444, 0]])
        ...: 
        ...: 
    In [15]: M
    Out[15]: 
    array([[-4.00000000e-02,  2.00000000e+04,  2.00000000e+04],
           [ 4.00000000e-02, -3.10050456e+04, -2.00000000e+04],
           [ 0.00000000e+00,  1.10050456e+04,  0.00000000e+00]])
    

    这确实可以运行,但出现不同的错误:

    In [16]: np.linalg.inv(M)
    ....
    LinAlgError: Singular matrix
    

    y_guess 是一个 (3,1) 数组,因此在评估 j 时传递 (1,) 数组:

    In [17]: y_guess
    Out[17]: 
    array([[2.],
           [2.],
           [2.]])
    

    如果我们将标量传递给j,则生成的矩阵没有额外的括号:

    In [18]: j(2,2,2)
    Matrix([[-0.04*y1 + 10000*y2*y3], [0.04*y1 - 2751.2614111*y2**2 - 10000*y2*y3], [2751.2614111*y2**2]])
    Matrix([[-0.0400000000000000, 10000*y3, 10000*y2], [0.0400000000000000, -5502.5228222*y2 - 10000*y3, -10000*y2], [0, 5502.5228222*y2, 0]])
    Out[18]: 
    Matrix([
    [-0.04,          20000,  20000],
    [ 0.04, -31005.0456444, -20000],
    [    0,  11005.0456444,      0]])
    

    现在可以创建np.linalg 可以使用的数值数组

    In [20]: np.array(j(2,2,2),float)
    Out[20]: 
    array([[-4.00000000e-02,  2.00000000e+04,  2.00000000e+04],
           [ 4.00000000e-02, -3.10050456e+04, -2.00000000e+04],
           [ 0.00000000e+00,  1.10050456e+04,  0.00000000e+00]])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-20
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多