evaluate multivariate expressions

353 views
Skip to first unread message

b45ch1

unread,
Jul 1, 2008, 7:30:53 AM7/1/08
to sympy
Hey,
I'd like to use Sympy to compute gradients and Hessians of real valued
functions.

I got this far:
#---------------------------------------------------------------------
#!/usr/bin/env python

from numpy import *
from sympy import *

N = 3
x = [Symbol('x%d'%n) for n in range(N)]

# define function f: R^N -> R
f = 1
for n in range(N):
f *= x[n]
print 'function=',f

# compute gradient
g = array([ diff(f,x[n]) for n in range(N)])
print 'gradient=',g

# compute Hessian
H = array([[diff(g[m],x[n]) for m in range(N)] for n in range(N)])

print 'Hessian=\n',H


# evaluating the Hessian at x = [0,1,2,3,...,N-1]
symdict = dict()
for n in range(N):
symdict[x[n]] = n
H1 = [[H[n,m].subs_dict(symdict).evalf() for n in range(N)] for m in
range(N)]

print H1
#---------------------------------------------------------------------


Now this is very awkward, and I'd like it to be reasonably fast since
I want to use the gradient and the Hessian for numerical computations.

Is there a better way?

I thought that there might be something like: convert an expression to
a Python function, since there is also the conversion to Latex and to
mathml.
I.e. similar to
#---------------------------------------------------------------------
from sympy import *
x,y,z = symbols('xy')
f = x*y + y*z
g = f.to_python_function()
print g([1.,2.,3.])
#---------------------------------------------------------------------


best regards,
Sebastian

Ondrej Certik

unread,
Jul 1, 2008, 9:03:30 AM7/1/08
to sy...@googlegroups.com
Hi Sebastian!

In the latest sympy, use just .subs() instead of subs_dict().

>
> print H1
> #---------------------------------------------------------------------

For the record, here is the output of the above script:

function= x0*x1*x2
gradient= [x1*x2 x0*x2 x0*x1]
Hessian=
[[0 x2 x1]
[x2 0 x0]
[x1 x0 0]]
[[0, 2, 1], [2, 0, 0], [1, 0, 0]]


>
>
> Now this is very awkward, and I'd like it to be reasonably fast since
> I want to use the gradient and the Hessian for numerical computations.

Evaluating the the Hessian is akward? Or computing it.

>
> Is there a better way?

Yes.

> I thought that there might be something like: convert an expression to
> a Python function, since there is also the conversion to Latex and to
> mathml.
> I.e. similar to
> #---------------------------------------------------------------------
> from sympy import *
> x,y,z = symbols('xy')
> f = x*y + y*z
> g = f.to_python_function()
> print g([1.,2.,3.])
> #---------------------------------------------------------------------

In fact, this is already implemented:

In [1]: f = x*y + y*z

In [2]: g = lambdify((x, y, z), f)

In [3]: print g(1, 2, 3)

Start ipython or isympy and do:

In [4]: lambdify?

to read the docstring. You can convert the expression to a python
function, or even to a function using numpy, see the docstring.


However, you don't just need an expression, but an array of
expressions. How do you think this should be handled? I.e. what the
interface should be? An array of python (lambda) functions? Or rather
one python (lambda) function returning an array? How should this
lambda funtion look like? Maybe like this:

def g(x1, x2, x3):
return array([x1, -x3, x2, ...])

This could be implemented in the lambdify function. Would you like to
give it a try? We'll help you with any questions you might have to
prepare a patch.

Thanks,
Ondrej

b45ch1

unread,
Jul 2, 2008, 12:29:51 PM7/2/08
to sympy
Hey Ondrej,

thanks for your quick reply :)
What I meant to say was: first defining a dictionary and then
substituting variables and then evaluating the expression is
inconvenient if the gradient resp. Hessian have to be recomputed
several times.
>
>
>
> > Is there a better way?
>
> Yes.
>
> > I thought that there might be something like: convert an expression to
> > a Python function, since there is also the conversion to Latex and to
> > mathml.
> > I.e. similar to
> > #---------------------------------------------------------------------
> > from sympy import *
> > x,y,z = symbols('xy')
> > f = x*y + y*z
> > g = f.to_python_function()
> > print g([1.,2.,3.])
> > #---------------------------------------------------------------------
>
> In fact, this is already implemented:
>
> In [1]: f = x*y + y*z
>
> In [2]: g = lambdify((x, y, z), f)

Checked it out. It's pretty much what I've been looking for. In my
version (sympy-0.5.8 ) it is
g = lambdify(f,(x,y,z))
by the way.


>
> In [3]: print g(1, 2, 3)
>
> Start ipython or isympy and do:
>
> In [4]: lambdify?
>
> to read the docstring. You can convert the expression to a python
> function, or even to a function using numpy, see the docstring.
>
> However, you don't just need an expression, but an array of
> expressions. How do you think this should be handled? I.e. what the
> interface should be? An array of python (lambda) functions? Or rather
> one python (lambda) function returning an array? How should this
> lambda funtion look like? Maybe like this:
>
> def g(x1, x2, x3):
> return array([x1, -x3, x2, ...])
>
> This could be implemented in the lambdify function. Would you like to
> give it a try? We'll help you with any questions you might have to
> prepare a patch.

Thanks for your trust :). I could do that.
But I won't have time for it until summer break (which is in three
weeks for me).
I guess I'd like it to have like this:
x,y,z = symbols('xyz')

v = [x,y,z]
f = [ x*y, y*z]
g = lambdify(f, v)
w = g([1,2,3]) # w = [2,6], i.e. list


v = [x,y,z]
f = array([ x*y, y*z])
g = lambdify(f, v)
w = g([1,2,3]) # w = array([2,6]), i.e. numpy.array


v = (x,y,z)
f = ( x*y, y*z)
g = lambdify(f, v)
w = g(1,2,3) # w = (2,6), i.e. tuple

I.e. the input of lambdify specifies what the lambda function g
expects as input and also what type it returns.

cheers,
Sebastian

Ondrej Certik

unread,
Jul 2, 2008, 12:50:06 PM7/2/08
to sy...@googlegroups.com

You use Ubuntu Hardy, right? :) You may fetch a newer package from
Intrepid, for example from here:

https://launchpad.net/ubuntu/intrepid/i386/python-sympy/0.5.15-1

or simply download the tarball from our site, you don't need to
install anything, just unpack it and that's it.


Yes, the lambda arguments order was changed to follow the same order
as in Python.


>
>
>>
>> In [3]: print g(1, 2, 3)
>>
>> Start ipython or isympy and do:
>>
>> In [4]: lambdify?
>>
>> to read the docstring. You can convert the expression to a python
>> function, or even to a function using numpy, see the docstring.
>>
>> However, you don't just need an expression, but an array of
>> expressions. How do you think this should be handled? I.e. what the
>> interface should be? An array of python (lambda) functions? Or rather
>> one python (lambda) function returning an array? How should this
>> lambda funtion look like? Maybe like this:
>>
>> def g(x1, x2, x3):
>> return array([x1, -x3, x2, ...])
>>
>> This could be implemented in the lambdify function. Would you like to
>> give it a try? We'll help you with any questions you might have to
>> prepare a patch.
>
> Thanks for your trust :). I could do that.
> But I won't have time for it until summer break (which is in three
> weeks for me).

No problem. I created an issue for this, see below, and if someone
finds time to fix it, it will be done, otherwise it will be waiting
for you. :)

> I guess I'd like it to have like this:
> x,y,z = symbols('xyz')
>
> v = [x,y,z]
> f = [ x*y, y*z]
> g = lambdify(f, v)
> w = g([1,2,3]) # w = [2,6], i.e. list
>
>
> v = [x,y,z]
> f = array([ x*y, y*z])
> g = lambdify(f, v)
> w = g([1,2,3]) # w = array([2,6]), i.e. numpy.array
>
>
> v = (x,y,z)
> f = ( x*y, y*z)
> g = lambdify(f, v)
> w = g(1,2,3) # w = (2,6), i.e. tuple
>
> I.e. the input of lambdify specifies what the lambda function g
> expects as input and also what type it returns.

Thanks for the input, it looks reasonable. I created an issue for this:

http://code.google.com/p/sympy/issues/detail?id=906

Ondrej

Reply all
Reply to author
Forward
0 new messages