What is the best way to convert a SymPy matrix to a numpy array/matrix
Asked Answered
S

5

45

I am not sure if the approach I've been using in sympy to convert a MutableDenseMatrix to a numpy.array or numpy.matrix is a good current practice.

I have a symbolic matrix like:

g = sympy.Matrix( [[   x,  2*x,  3*x,  4*x,  5*x,  6*x,  7*x,  8*x,   9*x,  10*x],
                   [x**2, x**3, x**4, x**5, x**6, x**7, x**8, x**9, x**10, x**11]] )

and I am converting to a numpy.array doing:

g_func = lambda val: numpy.array( g.subs( {x:val} ).tolist(), dtype=float )

where I get an array for a given value of x.

Is there a better built-in solution in SymPy to do that?

Thank you!

Schoolbook answered 12/6, 2013 at 15:48 Comment(3)
Most of this question is answered here #10679343 - I know it is not exactly the same question but it gives all that is necessary to know about numpy/sympy interoperability.Aristate
thank you! feel fee to prepare an answer, because I think this is the best approach for my case too...Schoolbook
Yes, use lambdify (I'm too lazy to write it up to an answer right now).Flinty
S
16

This answer is based on the advices from Krastanov and asmeurer. This little snippet uses sympy.lambdify:

from sympy import lambdify
from sympy.abc import x, y

g = sympy.Matrix([[   x,  2*x,  3*x,  4*x,  5*x,  6*x,  7*x,  8*x,   9*x,  10*x],
                  [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]])
s = (x, y)
g_func = lambdify(s, g, modules='numpy')

where g is your expression containing all symbols grouped in s.

If modules='numpy' is used the output of function g_func will be a np.ndarray object:

g_func(2, 3)
#array([[     2,      4,      6,      8,     10,     12,     14,     16,       18,     20],
#       [     9,     27,     81,    243,    729,   2187,   6561,  19683,    59049, 177147]])

g_func(2, y)
#array([[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
#       [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]], dtype=object)

If modules='sympy' the output is a sympy.Matrix object.

g_func = lambdify(vars, g, modules='sympy')
g_func(2, 3)
#Matrix([[2,  4,  6,   8,  10,   12,   14,    16,    18,     20],
#        [9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147]])

g_func(2, y)
#Matrix([[   2,    4,    6,    8,   10,   12,   14,   16,    18,    20],
#        [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]])
Schoolbook answered 19/6, 2013 at 15:38 Comment(0)
E
49

This looks like the most straightforward:

np.array(g).astype(np.float64)

If you skip the astype method, numpy will create a matrix of type 'object', which won't work with common array operations.

Evangelist answered 27/5, 2016 at 20:38 Comment(1)
It works. And np.array(g, dtype=np.float64) will not.Philip
S
16

This answer is based on the advices from Krastanov and asmeurer. This little snippet uses sympy.lambdify:

from sympy import lambdify
from sympy.abc import x, y

g = sympy.Matrix([[   x,  2*x,  3*x,  4*x,  5*x,  6*x,  7*x,  8*x,   9*x,  10*x],
                  [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]])
s = (x, y)
g_func = lambdify(s, g, modules='numpy')

where g is your expression containing all symbols grouped in s.

If modules='numpy' is used the output of function g_func will be a np.ndarray object:

g_func(2, 3)
#array([[     2,      4,      6,      8,     10,     12,     14,     16,       18,     20],
#       [     9,     27,     81,    243,    729,   2187,   6561,  19683,    59049, 177147]])

g_func(2, y)
#array([[2, 4, 6, 8, 10, 12, 14, 16, 18, 20],
#       [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]], dtype=object)

If modules='sympy' the output is a sympy.Matrix object.

g_func = lambdify(vars, g, modules='sympy')
g_func(2, 3)
#Matrix([[2,  4,  6,   8,  10,   12,   14,    16,    18,     20],
#        [9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147]])

g_func(2, y)
#Matrix([[   2,    4,    6,    8,   10,   12,   14,   16,    18,    20],
#        [y**2, y**3, y**4, y**5, y**6, y**7, y**8, y**9, y**10, y**11]])
Schoolbook answered 19/6, 2013 at 15:38 Comment(0)
P
8
 numpy.array(SympyMatrix.tolist()).astype(numpy.float64)

The native tolist method to makes the sympy matrix into something nestedly indexed

numpy.array can cast something nestedly indexed into arrays

.astype(float64) will cast numbers of the array into the default numpy float type, which will work with arbitrary numpy matrix manipulation functions.

As an additional note - it is worth mentioning that by casting to numpy you loose the ability to do matrix operations while keeping sympy variables and expressions along for the ride.

EDIT: The point of my additional note, is that upon casting to numpy.array, you loose the ability to have a variable anywhere in your matrix. All your matrix elements must be numbers already before you cast or everything will break.

Podagra answered 13/11, 2015 at 21:33 Comment(0)
M
7

From the SymPy-0.7.6.1_mpmath_ matrix docs, the tolist() method exists:

Finally, it is possible to convert a matrix to a nested list. This is very useful, as most Python libraries involving matrices or arrays (namely NumPy or SymPy) support this format:

B.tolist()
Maness answered 20/7, 2015 at 5:25 Comment(1)
mpmath.matrices.matrices.tolist() returns a list of mpmath.ctx_mp_python.mpf so you will still need to cast it, but IMO this isn't what the OP is asking for, since they want a function that produces numpy arrays, which is what the accepted answer does.Biafra
B
6

Sympy now provides the sympy.matrix2numpy function:

sympy.matrix2numpy(g)
# array([[x, 2*x, 3*x, 4*x, 5*x, 6*x, 7*x, 8*x, 9*x, 10*x],
#       [x**2, x**3, x**4, x**5, x**6, x**7, x**8, x**9, x**10, x**11]],
#      dtype=object)

To perform substitution for a specific value of x:

g_func = lambda val: sympy.matrix2numpy(g.subs(x, val), dtype=float)
g_func(1)
# array([[ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10.],
#        [ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.]])

This approach is particularly useful for converting a numeric Sympy matrix to a numpy array:

M = sympy.Matrix([[123,456],[789, 123]])
sympy.matrix2numpy(M, dtype=int)
# array([[123, 456],
#       [789, 123]])
Bartholomeus answered 17/8, 2023 at 8:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.