convert sympy.Matrix to list of lists of python standard types or numpy array

4,779 views
Skip to first unread message

a.lwtzky

unread,
Nov 1, 2011, 12:36:02 PM11/1/11
to sympy
Dear everyone,

I was wondering if there is a function in sympy that converts a
sympy.Matrix to a list of lists of python standard types. For example
if you have
>>> m = matrices.Matrix([[2,0],[0,2]])

it would be nice to have a function <f> that returns:
>>> res = <f>(m)
[[2,0],[0,2]]
>>> type(res)
list
>>> type(res[0][0])
int # or float or whatever seems appropriate.

as an alternative: return a 2D numpy array of integers/floats... But
this brings probably unnecessary dependencies to numpy. And if the
user really wants to have a numpy.array, he/she could just use
np.asarray(res).

I spent a couple of hours in order to find a (simple) solution for
this.
A similar idea was presented here:
http://weekinpse.wordpress.com/2010/01/06/how-to-convert-a-sympy-matrix-to-numpy-array/
This subject has already been discussed in sympy IRC channel with
ronan (thanks again).

-> Motivation - Use case
I would like to use numpy and sympy in the same project. Use sympy to
solve a ODE system symbolically, get its jacobian, the jacobian's
eigenvectors at a critical point and so on. Then use this information
to plot it (with matplotlib) together with other functions, further
investigate it's properties (for example integrate it numerically with
numpy - plot the trajectories) and so on.

-> suggestions
It doesn't seem to be too bad implementing something like this. The
solution of hdahlol can be found at the link (see above).
ronan thought about something like:
def <f>(m):
arr = np.asarray(map(int, m.mat)) # or float...
arr.shape = m.shape
return arr

But both of us agreed that using m.mat is pretty ugly at this point.
And it does explicitly take use of numpy. Of course there is a way to
copy value by value - but this might result in terribly slow code
without benefit.

In case a value can't be converted to standard types (for example a
variable x) the function could just throw an exception or leave the
sympy.object in the list and let the user care about this case.

I would really appreciate help in this question.

Thanks, Andy

Mateusz Paprocki

unread,
Nov 1, 2011, 1:10:23 PM11/1/11
to sy...@googlegroups.com
Hi,

On 1 November 2011 09:36, a.lwtzky <a.lw...@googlemail.com> wrote:
Dear everyone,

I was wondering if there is a function in sympy that converts a
sympy.Matrix to a list of lists of python standard types. For example
if you have
>>> m = matrices.Matrix([[2,0],[0,2]])

it would be nice to have a function <f> that returns:
>>> res = <f>(m)
[[2,0],[0,2]]
>>> type(res)
list
>>> type(res[0][0])
int # or float or whatever seems appropriate.

as an alternative: return a 2D numpy array of integers/floats... But
this brings probably unnecessary dependencies to numpy. And if the
user really wants to have a numpy.array, he/she could just use
np.asarray(res).

You can create an array from a matrix and convert a matrix to a list of lists, e.g.:

In [1]: import numpy as np

In [2]: a = Matrix([[1, 2], [3, 4]])

In [3]: a
Out[3]: 
⎡1  2⎤
⎢    ⎥
⎣3  4⎦

In [4]: a.tolist()
Out[4]: [[1, 2], [3, 4]]

In [5]: np.array(a)
Out[5]: 
 [[1 2]
 [3 4]]

This is for git version of SymPy, but should work for older versions too.
 

--
You received this message because you are subscribed to the Google Groups "sympy" group.
To post to this group, send email to sy...@googlegroups.com.
To unsubscribe from this group, send email to sympy+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sympy?hl=en.


Mateusz

a.lwtzky

unread,
Nov 1, 2011, 2:26:42 PM11/1/11
to sympy
Hi Mateusz,
True, but the dtype of this numpy array is object, which is unsuitable
e.g. for numerical ODE solver.
Try:
In [1] : a = Matrix([[1, 2], [3, 4]])
In [2]: type(a.tolist()[0][0])
Out[13]: <class 'sympy.core.numbers.One'>

same with the numpy array:
array([[1, 2],
[3, 4]], dtype=object)

I've got the pypy version of sympy which is 0.7.1. Has the behavior
anything changed here?

Thanks for your help anyway,
Andy

On 1 Nov., 18:10, Mateusz Paprocki <matt...@gmail.com> wrote:
> Hi,
>
> >http://weekinpse.wordpress.com/2010/01/06/how-to-convert-a-sympy-matr...

Mateusz Paprocki

unread,
Nov 1, 2011, 2:36:19 PM11/1/11
to sy...@googlegroups.com
Hi,

On 1 November 2011 11:26, a.lwtzky <a.lw...@googlemail.com> wrote:
Hi Mateusz,
True, but the dtype of this numpy array is object, which is unsuitable
e.g. for numerical ODE solver.
Try:
In [1] : a = Matrix([[1, 2], [3, 4]])
In [2]: type(a.tolist()[0][0])
Out[13]: <class 'sympy.core.numbers.One'>

same with the numpy array:
array([[1, 2],
      [3, 4]], dtype=object)

This is correct behavior. I you want to get a minimal dtype (some sort of int) then a quick hack is to use lambdify(), e.g.:

In [1]: a = Matrix([[1, 2], [3, 4]])

In [2]: f = lambdify((), a, 'numpy')

In [3]: f()
Out[3]: 
 [[1 2]
 [3 4]]

In [4]: _.dtype
Out[4]: int64

f is a zero argument Python's native lambda with NumPy's data types.

Downcasting should work and would be a preferred solution, but it fails due to a bug in SymPy:

In [5]: import numpy as np

In [6]: b = np.array(a)

In [7]: b.astype(int)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/mateusz/repo/git/sympy/<ipython-input-7-523ae7d433be> in <module>()
----> 1 b.astype(int)

TypeError: long() argument must be a string or a number, not 'Integer'

For some reason NumPy uses long() when int dtype is give and currently in SymPy:

In [8]: int(Integer(10))
Out[8]: 10

In [9]: long(Integer(10))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/mateusz/repo/git/sympy/<ipython-input-9-5db2e38df86b> in <module>()
----> 1 long(Integer(10))

TypeError: long() argument must be a string or a number, not 'Integer'

Mateusz

a.lwtzky

unread,
Nov 1, 2011, 3:27:24 PM11/1/11
to sympy
Hi Mateusz,

the second solution is exactly what I was looking for.
Actually, I tried that as well but ran in the same type error.
Unfortunately I only tried it with integers, so I gave up hope that it
works like this.
Anyway, what's still confusing me is:
>>> a = Matrix([[1., 2.], [3., 4.]])
>>> b = np.array(a, dtype=float)
---------------------------------------------------------------------------
TypeError Traceback (most recent call
last)

/home/andy/<ipython console> in <module>()

TypeError: __array__() takes exactly 1 argument (2 given)

I expected it to do exactly the same as array()&astype(), but that's
obviously wrong. It would be awesome, if it works like that.

Is the bug with the Integers in sympy known? Or should I file a bug
report for this?

Thank you very much for your help so far. I don't know if this is in
the scope of sympy, but it would be nice to have a nice interface to
numpy at this point.

Cheers, Andy


On 1 Nov., 19:36, Mateusz Paprocki <matt...@gmail.com> wrote:
> Hi,
>

Aaron Meurer

unread,
Nov 1, 2011, 7:28:39 PM11/1/11
to sy...@googlegroups.com
On Tue, Nov 1, 2011 at 1:27 PM, a.lwtzky <a.lw...@googlemail.com> wrote:
> Hi Mateusz,
>
> the second solution is exactly what I was looking for.
> Actually, I tried that as well but ran in the same type error.
> Unfortunately I only tried it with integers, so I gave up hope that it
> works like this.
> Anyway, what's still confusing me is:
>>>> a = Matrix([[1., 2.], [3., 4.]])
>>>> b = np.array(a, dtype=float)
> ---------------------------------------------------------------------------
> TypeError                                 Traceback (most recent call
> last)
>
> /home/andy/<ipython console> in <module>()
>
> TypeError: __array__() takes exactly 1 argument (2 given)
>
> I expected it to do exactly the same as array()&astype(), but that's
> obviously wrong. It would be awesome, if it works like that.
>
> Is the bug with the Integers in sympy known? Or should I file a bug
> report for this?

I didn't find an issue for it. It should be very easy to fix. We
just need to define __long__ on Number, which is similar to __int__
except it casts the result to a long first.

>
> Thank you very much for your help so far. I don't know if this is in
> the scope of sympy, but it would be nice to have a nice interface to
> numpy at this point.

This is within the scope to some degree. This is why we have
functions like lambdify() for example.

Aaron Meurer

Mateusz Paprocki

unread,
Nov 1, 2011, 7:37:24 PM11/1/11
to sy...@googlegroups.com
Hi,

On 1 November 2011 16:28, Aaron Meurer <asme...@gmail.com> wrote:
On Tue, Nov 1, 2011 at 1:27 PM, a.lwtzky <a.lw...@googlemail.com> wrote:
> Hi Mateusz,
>
> the second solution is exactly what I was looking for.
> Actually, I tried that as well but ran in the same type error.
> Unfortunately I only tried it with integers, so I gave up hope that it
> works like this.
> Anyway, what's still confusing me is:
>>>> a = Matrix([[1., 2.], [3., 4.]])
>>>> b = np.array(a, dtype=float)
> ---------------------------------------------------------------------------
> TypeError                                 Traceback (most recent call
> last)
>
> /home/andy/<ipython console> in <module>()
>
> TypeError: __array__() takes exactly 1 argument (2 given)
>
> I expected it to do exactly the same as array()&astype(), but that's
> obviously wrong. It would be awesome, if it works like that.
>
> Is the bug with the Integers in sympy known? Or should I file a bug
> report for this?

I didn't find an issue for it.  It should be very easy to fix.  We
just need to define __long__ on Number, which is similar to __int__
except it casts the result to a long first.

Yes, that's pretty simple. I wonder why such simple thing doesn't work in SymPy.

Mateusz

Aaron Meurer

unread,
Nov 1, 2011, 7:45:57 PM11/1/11
to sy...@googlegroups.com
>> > Is the bug with the Integers in sympy known? Or should I file a bug
>> > report for this?
>>
>> I didn't find an issue for it.  It should be very easy to fix.  We
>> just need to define __long__ on Number, which is similar to __int__
>> except it casts the result to a long first.
>
> Yes, that's pretty simple. I wonder why such simple thing doesn't work in
> SymPy.
>

Well, it's happened several times now that some simple thing like this
doesn't work because we don't have some __method__ from
http://docs.python.org/reference/datamodel.html implemented in Basic,
Expr, or whatever relevant subclass. So I created
http://code.google.com/p/sympy/issues/detail?id=2817 for this.

I marked it for Code-In, but if you want to fix it, Andy, that would
also be great.

Aaron Meurer

Reply all
Reply to author
Forward
0 new messages