Sympy, Numpy & unhashable type

579 views
Skip to first unread message

Mike Hull

unread,
Dec 17, 2010, 2:59:37 PM12/17/10
to sympy
Hi!
I hope you can help me or point me towards something useful!

I am working in Neuroscience, and I do a lot of curve fitting and
trying out to various formulae using scipy. [Also, the units in
neuroscience are messy, so I wanted to write a library to take care of
lots of the book keeping for me along the way -
http://packages.python.org/quantities/user/tutorial.html!]

at the moment, I am writing a function for the functions I want to
fit, then using scipy.optimise. however, this is not so neat and hard
to automatically document. (eg produce latex of the formulae)



My thoughts were:
- write an expression as a string, eg
- parse it with sympy to get a list of symbols out:

expr = sympy.S("gkbar * m * m * m * h")
symbols = [a for a in expr.atoms if a.is_Symbol() ]

the subsitute in numpy arrays so I could use them in fitting routines:
m = np.linspace(0,100,num=200)
h = np.sin(m)
gkbar = 14
expr.subs( {'m':m, 'h':h, 'gkbar':gkbar} )

gives me:
TypeError: unhashable type: 'numpy.ndarray'

is there a way I can evalute expressions when numpy arrays are given
as parameters



Many thanks for any input!

Mike

Renato Coutinho

unread,
Dec 18, 2010, 3:37:22 AM12/18/10
to sy...@googlegroups.com
Hello Mike,

On Fri, Dec 17, 2010 at 5:59 PM, Mike Hull <mikeh...@googlemail.com> wrote:
> My thoughts were:
> - write an expression as a string, eg
> - parse it with sympy to get a list of symbols out:
>
> expr = sympy.S("gkbar * m * m * m * h")
> symbols = [a for a in expr.atoms if a.is_Symbol() ]
>
> the subsitute in numpy arrays so I could use them in fitting routines:
> m = np.linspace(0,100,num=200)
> h = np.sin(m)
> gkbar = 14
> expr.subs( {'m':m, 'h':h, 'gkbar':gkbar} )
>
> gives me:
> TypeError: unhashable type: 'numpy.ndarray'
>
> is there a way I can evalute expressions when numpy arrays are given
> as parameters

As far as I know (and I don't know much, sorry), there's no way to
substitute a symbol with an array, only with a value or an expression.
But I came up with the following, if I understood correctly what you
are trying to do:

np.fromiter( ( expr.subs({'gkbar': gkbar, 'm': x, 'h': np.sin(x)}) for
x in m ) , np.float64)

that is, create a generator based on the array and pass it to numpy to
create the new array. I cheated a little and wrote h directly as a
function of m, but it wouldn't be hard to use indexes instead.

Hope it helps,

Renato

Mike Hull

unread,
Dec 18, 2010, 5:58:03 AM12/18/10
to sympy
Hi Renato,

Ah thats a shame.
I would be keen to use numpy functions, because for curve fitting you
typically have to run many iterations.
As I am really interested in 'simple functions': add/sub/multiply/div/
exponential,

Would it be complex to write a Visitor class that visited each .arg in
sympy objects, and then produced functors to perfom
the appropriate operation - hence calling all correct numpy operators?

I'd be grateful to here any advice/experience of somethign like
this.....

Thanks

Mike

Ondrej Certik

unread,
Dec 18, 2010, 6:25:15 AM12/18/10
to sy...@googlegroups.com
On Sat, Dec 18, 2010 at 2:58 AM, Mike Hull <mikeh...@googlemail.com> wrote:
> Hi Renato,
>
> Ah thats a shame.
> I would be keen to use numpy functions, because for curve fitting you
> typically have to run many iterations.
> As I am really interested in 'simple functions': add/sub/multiply/div/
> exponential,
>
> Would it be complex to write a Visitor class that visited each .arg in
> sympy objects, and then produced functors to perfom
> the appropriate operation - hence calling all correct numpy operators?
>
> I'd be grateful to here any advice/experience of somethign like
> this.....

Would lambdify do the job? Read it's docstring, e.g.:


>> f = lambdify((x,y), tan(x*y), "numpy")
>> f(1, 2)
-2.18503986326
>> from numpy import array
>> f(array([1, 2, 3]), array([2, 3, 5]))
[-2.18503986 -0.29100619 -0.8559934 ]


Ondrej

P.S. Can you please review this docstring improvement, that I just wrote?

https://github.com/sympy/sympy/pull/47

Bastian Weber

unread,
Dec 18, 2010, 6:26:41 AM12/18/10
to sy...@googlegroups.com
Hi Mike,

for me, this sounds like use case for sympy.lambdify.
I think you could do something like this:

In [27]: e = G*m*m*m*h

In [28]: e = e.subs(h, sin(m))

In [29]: f = lambdify((G, m), e, modules="numpy")

In [30]: f(r_[3,4,5], r_[0.1, 0.2, 0.3])
Out[30]: array([ 0.0002995 , 0.00635742, 0.03989523])

Regards,
bastian.

Mateusz Paprocki

unread,
Dec 18, 2010, 6:27:12 AM12/18/10
to sy...@googlegroups.com
Hi,

Substitution with non-sympy objects is not possible if those objects
aren't convertible to sympy objects. However, a sympy expression can
be converted to a native Python function and then one can use whatever
objects he likes, e.g.:

In [1]: import numpy as np

In [2]: var('m,h', commutative=False)
Out[2]: (m, h)

In [3]: var('gkbar')
Out[3]: gkbar

In [4]: expr = gkbar*m**3*h

In [5]: expr
Out[5]:
3
gkbar⋅m ⋅h

In [6]: _m = np.linspace(0,100,num=200)

In [7]: _h = np.sin(_m)

In [8]: _gkbar = 14

In [9]: f = lambdify((m, h, gkbar), expr, 'numpy')

In [10]: f(_m, _h, _gkbar)
Out[10]:
(...)

Later you can issue:

In [11]: latex(expr)
Out[11]: gkbar m^{3} h

and get latex output.

>
>
> Many thanks for any input!
>
> Mike
>

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

signature.asc
Reply all
Reply to author
Forward
0 new messages