Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sympy: 'Transpose' object has no attribute tolist

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.

like image 603
Patrick Kaifosh Avatar asked Aug 23 '15 21:08

Patrick Kaifosh


1 Answers

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.

like image 182
Phillip Avatar answered Nov 16 '22 06:11

Phillip