sympy: 'Transpose' 对象没有 tolist 属性

8

我正在尝试使用sympy进行一些符号矩阵计算,我的目标是获得某些矩阵计算结果的符号表示。在这个简单的例子中,我试图计算指定矩阵的幂并将其乘以任意向量,但遇到了一些问题。

>>> import sympy
>>> v = sympy.MatrixSymbol('v', 2, 1)
>>> Z = sympy.zeros(2, 2)  # create 2x2 zero matrix
>>> I = sympy.exp(Z)  # exponentiate zero matrix to get identity matrix
>>> I * v
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "sympy/matrices/matrices.py", line 507, in __mul__
    blst = B.T.tolist()
AttributeError: 'Transpose' object has no attribute 'tolist'

相比之下,如果我直接创建单位矩阵并将其乘以v,则不会出现问题:
>>> I_ = sympy.eye(2)  # directly create the identity matrix
>>> I_ == I  # check the two matrices are equal
True
>>> I_ * v
v

我注意到的一件事是两个单位矩阵属于不同的类:

>>> I.__class__
sympy.matrices.immutable.ImmutableMatrix
>>> I_.__class__
sympy.matrices.dense.MutableDenseMatrix

我也发现调用as_mutable()方法提供了一种解决方法。

>>> I.as_mutable() * v
v

在进行线性代数计算时是否总是需要使用`as_mutable()`调用?我猜想不一定,这些错误可能表明我正在使用错误的策略来解决问题,但我找不到正确的策略。有人能指点一下吗?
我已经阅读了关于不可变矩阵的文档页面,但我仍然需要一些帮助理解它们与标准可变矩阵的区别在这里的重要性,以及为什么一些操作(例如sympy.exp)会在这些不同的类之间进行转换。

FYI,该错误现在已经在sympy的主分支中修复。 - Phillip
1个回答

4
I'd claim that this is a bug in Sympy:
在Python中,您可以从两侧重载乘法运算符A*B 可能会通过调用 A.__mul__(B)B.__rmul__(A) 来进行内部处理。Python首先调用 A.__mul__,如果该方法不存在或返回NotImplemented,则Python会自动尝试B.__rmul__。相反,SymPy使用一个名为call_highest_priority的装饰器来决定使用哪个实现。它查找所涉及类的 _op_priority,并调用具有更高优先级的实现函数。 在您的情况下,vI的优先级为11,I_的优先级为10.01,因此首选I。此外,I使用的基本实现缺少装饰器__mul__
长话短说,I*v 最终总是调用 I.__mul__,而 __mul__ 无法处理 MatrixSymbol,但也没有返回 NotImplementedv.__rmul__(I) 的效果符合预期。
正确的修复方法应该是在 matrices.py 中捕获 AttributeError 并返回 NotImplemented,即:
try:
    blst = B.T.tolist()
except AttributeError:
    return NotImplemented

Python会自动回退到__rmul__。修复方法是调整_op_priority。无论哪种方式,您都应该提交错误报告:如果错误是设计问题(即,如果您意外尝试了不应该工作的东西),则错误消息将说明原因。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接