sympy: 'Transpose' object has no attribute tolist
Asked Answered
G

1

8

I'm trying to do some symbolic matrix calculations with sympy. My goal is to obtain a symbolic representation of the result of some matrix computations. I've run into some problems which I have boiled down to this simple example, in which I try to evaluate the result of a exponentiating a specified matrix and multiplying it by an arbitrary vector.

>>> 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'

In contrast, if I directly create the identity matrix and then multiply it by v, then there is no problem:

>>> I_ = sympy.eye(2)  # directly create the identity matrix
>>> I_ == I  # check the two matrices are equal
True
>>> I_ * v
v

One thing that I've noted is that the two identity matrices are of different classes:

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

I also found that calling the as_mutable() method provided a work-around.

>>> I.as_mutable() * v
v

Is it always necessary to put as_mutable() calls throughout one's linear algebra calculations? I'm guessing not, and that instead these errors suggest that I'm using the wrong strategy to solve my problem, but I can't figure out what the right strategy would be. Does anyone have any pointers?

I have read the documentation page on Immutable Matrices but I could still use some help understanding how their differences with standard mutable matrices are important here, and why some operations (e.g. sympy.exp) convert between these different classes.

Geis answered 23/8, 2015 at 21:3 Comment(1)
FYI, the bug is fixed in sympy's master branch now.Stopoff
S
4

I'd claim that this is a bug in Sympy:

In Python, you can overload the multiplication operator from both sides. A*B may internally be handled by either calling A.__mul__(B), or B.__rmul__(A). Python first calls A.__mul__, and if this method does not exist or returns NotImplemented, then Python tries B.__rmul__ automatically. SymPy instead uses a decorator called call_highest_priority to decide which of both implementations to use. It looks up the _op_priority of the involved classes and calls the function of the implementation with higher priority. The priorities in your case are 11 for v and I and 10.01 for I_, so I is preferred. Also, the base implementation of __mul__, which I uses, lacks the decorator.

Long story short, I*v ends up always calling I.__mul__, and __mul__ cannot handle MatrixSymbols but does not return NotImplemented either. v.__rmul__(I) works as expected.

The proper fix would be to capture the AttributeError in matrices.py and return NotImplemented, i.e.

try:
    blst = B.T.tolist()
except AttributeError:
    return NotImplemented

Python would then automatically fallback to __rmul__. The hack'ish fix would be to adjust _op_priority. Either way, you should file a bug report: If the error was by design (that is, if you accidentally tried something that's not supposed to work), then the error message would say so.

Stopoff answered 3/5, 2016 at 6:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.