Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #106050 > unrolled thread

sympy

Started byPoul Riis <priisdk@gmail.com>
First post2016-03-30 04:17 -0700
Last post2016-03-31 23:26 +0100
Articles 16 — 9 participants

Back to article view | Back to comp.lang.python


Contents

  sympy Poul Riis <priisdk@gmail.com> - 2016-03-30 04:17 -0700
    Re: sympy Ben Finney <ben+python@benfinney.id.au> - 2016-03-30 22:29 +1100
    Re: sympy Ned Batchelder <ned@nedbatchelder.com> - 2016-03-30 04:39 -0700
    Re: sympy Steven D'Aprano <steve@pearwood.info> - 2016-03-30 23:56 +1100
      Re: sympy Poul Riis <priisdk@gmail.com> - 2016-03-30 08:23 -0700
        Re: sympy Robert Kern <robert.kern@gmail.com> - 2016-03-30 16:29 +0100
        Re: sympy Steven D'Aprano <steve@pearwood.info> - 2016-03-31 02:59 +1100
          Re: sympy Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2016-03-31 17:49 +1300
            Re: sympy Poul Riis <priisdk@gmail.com> - 2016-03-30 23:51 -0700
          Re: sympy Poul Riis <priisdk@gmail.com> - 2016-03-31 03:57 -0700
            Re: sympy Peter Otten <__peter__@web.de> - 2016-03-31 16:55 +0200
            Re: sympy Chris Angelico <rosuav@gmail.com> - 2016-04-01 04:05 +1100
            Re: sympy Peter Otten <__peter__@web.de> - 2016-03-31 19:51 +0200
            Re: sympy Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2016-03-31 19:59 +0100
    Re: sympy Poul Riis <priisdk@gmail.com> - 2016-03-31 14:33 -0700
      Re: sympy Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2016-03-31 23:26 +0100

#106050 — sympy

FromPoul Riis <priisdk@gmail.com>
Date2016-03-30 04:17 -0700
Subjectsympy
Message-ID<733f5f0d-9b4e-4023-897b-e1f2730c39cb@googlegroups.com>
Is it possible to transfer results from sympy to 'normal' python.

In the case below I think my intention is clear enough but it does not work as intended. How can it be done?

Poul Riis




from sympy import *
x=Symbol('x')
ftext=diff(1/(x**2+1),x)

def f(t):
    return ftext.subs(x,'t')

print(f(3))

[toc] | [next] | [standalone]


#106052

FromBen Finney <ben+python@benfinney.id.au>
Date2016-03-30 22:29 +1100
Message-ID<mailman.194.1459337388.28225.python-list@python.org>
In reply to#106050
Poul Riis <priisdk@gmail.com> writes:

> Is it possible to transfer results from sympy to 'normal' python.

Is Sympy not “normal Python”? What transfer are you intending?

> In the case below I think my intention is clear enough but it does not
> work as intended. How can it be done?

First: no, your intention is not clear. Please write idiomatic Python:
spaces around operators, names which describe the meaning. Follow the
coding style guide PEP 8 <URL:https://www.python.org/dev/peps/pep-0008/>.

Second: no, the intent is obscured because you are using ‘from sympy
import *’. This clobbers the global namespace, making it much more
difficult to tell which names come from a different namespace. Instead,
do ‘import sympy’ and qualify names ‘sympy.Symbol’, etc.

Third: if the code “does not work as intended”, then the answer can be
no better than “change it until it works as intended”. If you want more
detail, please provide more detail on what it *is* doing, and what you
think it *should* do instead.

-- 
 \       “I bet one legend that keeps recurring throughout history, in |
  `\              every culture, is the story of Popeye.” —Jack Handey |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#106053

FromNed Batchelder <ned@nedbatchelder.com>
Date2016-03-30 04:39 -0700
Message-ID<7a86698a-866f-4dc1-8ef7-80bde8afd6f6@googlegroups.com>
In reply to#106050
On Wednesday, March 30, 2016 at 7:17:33 AM UTC-4, Poul Riis wrote:
> Is it possible to transfer results from sympy to 'normal' python.

Poul, welcome to the group.

> In the case below I think my intention is clear enough but it does not work as intended. How can it be done?
> 
> from sympy import *
> x=Symbol('x')
> ftext=diff(1/(x**2+1),x)
> 
> def f(t):
>     return ftext.subs(x,'t')
> 
> print(f(3))

You'd be surprised how hard it is to understand what someone else thinks
a small chunk of code should do. :)

Even if we can work out what this was meant to do, it will be easier to help
if you are explicit about the outcome you are getting, and how that differs
from the outcome you want.

--Ned.

[toc] | [prev] | [next] | [standalone]


#106064

FromSteven D'Aprano <steve@pearwood.info>
Date2016-03-30 23:56 +1100
Message-ID<56fbcd01$0$1599$c3e8da3$5496439d@news.astraweb.com>
In reply to#106050
On Wed, 30 Mar 2016 10:17 pm, Poul Riis wrote:

> Is it possible to transfer results from sympy to 'normal' python.
> 
> In the case below I think my intention is clear enough but it does not
> work as intended. How can it be done?

How can what be done? Unfortunately, we're not able to read your mind. We
can read your code, and can see what your code does, but how are we
supposed to know what it is supposed to do?


> from sympy import *
> x=Symbol('x')
> ftext=diff(1/(x**2+1),x)
> 
> def f(t):
>     return ftext.subs(x,'t')
> 
> print(f(3))

This code seems to work perfectly to me. You differentiate an expression,
then substitute the 'x' variable for 't':

-2*t/(t**2 + 1)**2

What were you expecting?




-- 
Steven

[toc] | [prev] | [next] | [standalone]


#106083

FromPoul Riis <priisdk@gmail.com>
Date2016-03-30 08:23 -0700
Message-ID<99b7cf43-50ff-4de7-8de0-e324658682bf@googlegroups.com>
In reply to#106064
What I intend to do is to let sympy find the derivative of some welldefined function and next define the foundation derivative as a normal function so that I can calculate numerical values or even make a graph.

[toc] | [prev] | [next] | [standalone]


#106084

FromRobert Kern <robert.kern@gmail.com>
Date2016-03-30 16:29 +0100
Message-ID<mailman.212.1459351804.28225.python-list@python.org>
In reply to#106083
On 2016-03-30 16:23, Poul Riis wrote:
> What I intend to do is to let sympy find the derivative of some welldefined function and next define the foundation derivative as a normal function so that I can calculate numerical values or even make a graph.

http://docs.sympy.org/dev/modules/utilities/lambdify.html#sympy.utilities.lambdify.lambdify

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
  that is made terrible by our own mad attempt to interpret it as though it had
  an underlying truth."
   -- Umberto Eco

[toc] | [prev] | [next] | [standalone]


#106090

FromSteven D'Aprano <steve@pearwood.info>
Date2016-03-31 02:59 +1100
Message-ID<56fbf7e7$0$1591$c3e8da3$5496439d@news.astraweb.com>
In reply to#106083
On Thu, 31 Mar 2016 02:23 am, Poul Riis wrote:

> What I intend to do is to let sympy find the derivative of some
> welldefined function and next define the foundation derivative as a normal
> function so that I can calculate numerical values or even make a graph.


I'm glad you explained what you *actually* wanted, because I was going to
guess that you wanted to evaluate the derivative at x = 3:


py> ftext.evalf(subs={x:3})
-0.0600000000000000



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#106123

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2016-03-31 17:49 +1300
Message-ID<dm3oicFpmg4U1@mid.individual.net>
In reply to#106090
Steven D'Aprano wrote:
> On Thu, 31 Mar 2016 02:23 am, Poul Riis wrote:
> 
>>What I intend to do is to let sympy find the derivative of some
>>welldefined function and next define the foundation derivative as a normal
>>function
> 
> py> ftext.evalf(subs={x:3})
> -0.0600000000000000

Given all that, it looks like you want

def f(t):
   return ftext.evalf(subs={x:t})

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#106136

FromPoul Riis <priisdk@gmail.com>
Date2016-03-30 23:51 -0700
Message-ID<98f57610-bd25-4d00-b095-703360a79fa1@googlegroups.com>
In reply to#106123
Den torsdag den 31. marts 2016 kl. 06.49.34 UTC+2 skrev Gregory Ewing:
> Steven D'Aprano wrote:
> > On Thu, 31 Mar 2016 02:23 am, Poul Riis wrote:
> > 
> >>What I intend to do is to let sympy find the derivative of some
> >>welldefined function and next define the foundation derivative as a normal
> >>function
> > 
> > py> ftext.evalf(subs={x:3})
> > -0.0600000000000000
> 
> Given all that, it looks like you want
> 
> def f(t):
>    return ftext.evalf(subs={x:t})
> 
> -- 
> Greg

Oh, yes, that works! Thank you!

Poul Riis

[toc] | [prev] | [next] | [standalone]


#106144

FromPoul Riis <priisdk@gmail.com>
Date2016-03-31 03:57 -0700
Message-ID<244e1277-e105-4419-a449-7f2012c6d78e@googlegroups.com>
In reply to#106090
Den onsdag den 30. marts 2016 kl. 17.59.49 UTC+2 skrev Steven D'Aprano:
> On Thu, 31 Mar 2016 02:23 am, Poul Riis wrote:
> 
> > What I intend to do is to let sympy find the derivative of some
> > welldefined function and next define the foundation derivative as a normal
> > function so that I can calculate numerical values or even make a graph.
> 
> 
> I'm glad you explained what you *actually* wanted, because I was going to
> guess that you wanted to evaluate the derivative at x = 3:
> 
> 
> py> ftext.evalf(subs={x:3})
> -0.0600000000000000
> 
> 
> 
> -- 
> Steven

... However, the sympy way seems to be about 70 times slower than using the derivative calculated 'by hand' (try the example below).
Can it be done in a more efficient way?

Poul Riis



from sympy import *
from time import *
x=Symbol('x')
ftext=diff(sin(x),x)

def fmsympy(t): 
   return ftext.evalf(subs={x:t})

def fm(t):
    return cos(t)

nloop=10000
tstart=time()
# nloop evaluations with sympy
for i in range(0,nloop):
    a=fmsympy(1)
dt1=time()-tstart

# nloop evaluations without sympy
tstart=time()
for i in range(0,nloop):
    a=fm(1)
dt2=time()-tstart

print(nloop,' evaluations with sympy   : dt1 =',dt1)
print(nloop,' evaluations without sympy: dt2 =',dt2)

[toc] | [prev] | [next] | [standalone]


#106164

FromPeter Otten <__peter__@web.de>
Date2016-03-31 16:55 +0200
Message-ID<mailman.264.1459436170.28225.python-list@python.org>
In reply to#106144
Poul Riis wrote:

> Den onsdag den 30. marts 2016 kl. 17.59.49 UTC+2 skrev Steven D'Aprano:
>> On Thu, 31 Mar 2016 02:23 am, Poul Riis wrote:
>> 
>> > What I intend to do is to let sympy find the derivative of some
>> > welldefined function and next define the foundation derivative as a
>> > normal function so that I can calculate numerical values or even make a
>> > graph.
>> 
>> 
>> I'm glad you explained what you *actually* wanted, because I was going to
>> guess that you wanted to evaluate the derivative at x = 3:
>> 
>> 
>> py> ftext.evalf(subs={x:3})
>> -0.0600000000000000
>> 
>> 
>> 
>> --
>> Steven
> 
> ... However, the sympy way seems to be about 70 times slower than using
> the derivative calculated 'by hand' (try the example below). Can it be
> done in a more efficient way?

Hm, the two functions fmsympy() and fm() do not return the same value:

$ python -i sympy_diff.py 
10000  evaluations with sympy   : dt1 = 0.7178411483764648
10000  evaluations without sympy: dt2 = 0.10177111625671387
>>> fm(42)
cos(42)
>>> fmsympy(42)
-0.399985314988351

What's the point of that benchmark?

> Poul Riis
> 
> 
> 
> from sympy import *
> from time import *
> x=Symbol('x')
> ftext=diff(sin(x),x)
> 
> def fmsympy(t):
>    return ftext.evalf(subs={x:t})
> 
> def fm(t):
>     return cos(t)
> 
> nloop=10000
> tstart=time()
> # nloop evaluations with sympy
> for i in range(0,nloop):
>     a=fmsympy(1)
> dt1=time()-tstart
> 
> # nloop evaluations without sympy
> tstart=time()
> for i in range(0,nloop):
>     a=fm(1)
> dt2=time()-tstart
> 
> print(nloop,' evaluations with sympy   : dt1 =',dt1)
> print(nloop,' evaluations without sympy: dt2 =',dt2)

[toc] | [prev] | [next] | [standalone]


#106175

FromChris Angelico <rosuav@gmail.com>
Date2016-04-01 04:05 +1100
Message-ID<mailman.272.1459443911.28225.python-list@python.org>
In reply to#106144
On Fri, Apr 1, 2016 at 1:55 AM, Peter Otten <__peter__@web.de> wrote:
> Hm, the two functions fmsympy() and fm() do not return the same value:
>
> $ python -i sympy_diff.py
> 10000  evaluations with sympy   : dt1 = 0.7178411483764648
> 10000  evaluations without sympy: dt2 = 0.10177111625671387
>>>> fm(42)
> cos(42)
>>>> fmsympy(42)
> -0.399985314988351
>

Maybe not, but that's simply because one of them is completely
evaluated. The cosine of 42 radians is indeed -0.4ish.

>>> math.cos(42)
-0.39998531498835127

ChrisA

[toc] | [prev] | [next] | [standalone]


#106178

FromPeter Otten <__peter__@web.de>
Date2016-03-31 19:51 +0200
Message-ID<mailman.275.1459446733.28225.python-list@python.org>
In reply to#106144
Chris Angelico wrote:

> On Fri, Apr 1, 2016 at 1:55 AM, Peter Otten <__peter__@web.de> wrote:
>> Hm, the two functions fmsympy() and fm() do not return the same value:
>>
>> $ python -i sympy_diff.py
>> 10000  evaluations with sympy   : dt1 = 0.7178411483764648
>> 10000  evaluations without sympy: dt2 = 0.10177111625671387
>>>>> fm(42)
>> cos(42)
>>>>> fmsympy(42)
>> -0.399985314988351
>>
> 
> Maybe not, but that's simply because one of them is completely
> evaluated. The cosine of 42 radians is indeed -0.4ish.
> 
>>>> math.cos(42)
> -0.39998531498835127

My guess was that the OP fell into the trap that he himself carefully set up 
with the star import, and accidentally used sympy.cos() where he wanted to 
invoke math.cos().

The fix would actually increase the speed difference -- but first make it 
right, then, maybe, fast.

Adding another storey to the tower of guesses, Robert Kern has probably 
already provided the answer ;)

[toc] | [prev] | [next] | [standalone]


#106179

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2016-03-31 19:59 +0100
Message-ID<mailman.276.1459450793.28225.python-list@python.org>
In reply to#106144
On 31 March 2016 at 11:57, Poul Riis <priisdk@gmail.com> wrote:
>
> ... However, the sympy way seems to be about 70 times slower than using the derivative calculated 'by hand' (try the example below).
> Can it be done in a more efficient way?
>
> Poul Riis
>
>
>
> from sympy import *
> from time import *
> x=Symbol('x')
> ftext=diff(sin(x),x)
>
> def fmsympy(t):
>    return ftext.evalf(subs={x:t})
>
> def fm(t):
>     return cos(t)

I think you have misunderstood what is going on here. Let's actually
try those two methods out:

$ isympy
IPython console for SymPy 0.7.5 (Python 2.7.9-64-bit) (ground types: gmpy)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)

Documentation can be found at http://www.sympy.org

In [1]: ftext = diff(sin(x), x)

In [2]: ftext
Out[2]: cos(x)

In [3]: ftext.evalf(subs={x:1})
Out[3]: 0.540302305868140

In [4]: cos(1)
Out[4]: cos(1)

So the first version (your fmsympy) takes the symbolic expression
cos(x) represented as a sympy expression tree and substitutes 1 for x
(which requires walking the tree to look fo all occurrences of x).
Then it evaluates the result to 15 decimal digits of precision using
the pure Python mpmath multiprecision math library. To prove that it's
not really a float calculation let's increase the precision:

In [5]: ftext.evalf(subs={x:1}, n=100)
Out[5]: 0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893

Your second version (fm) makes a sympy expression using the cos
function from sympy and the argument 1. This creates a symbolic sympy
expression cos(1) and returns that. It doesn't do any evaluation of
the expression to get the digits of the actual numeric answer.

So I'm not surprised that the two operations take different amounts of
time. One doesn't evaluate the expression and the other does using a
slow multiprecision library. Also note though that sympy uses a cache
to accelerate repeated calculations so if you time it doing the exact
same thing repeatedly in a loop then you may just be measuring
cache-hit performance for two different inputs rather than actual
evaluation time.

If you want to see one that's a lot faster use the cos function from
the math module:

In [9]: from math import cos

In [10]: cos(1)
Out[10]: 0.540302305868

This calculates cos(1) using IEEE 64-bit binary floating point
(Python's float type) with hardware acceleration from your processor's
FPU instructions. This should be a lot faster then either substituting
into symbolic expressions in sympy or evaluating trignometric
functions with mpmath.

Generally I would use sympy in order to derive the mathematical
expressions that I want to compute. However if I then want to evaluate
the expressions many times in a loop with different input numbers for
example then I would rewrite the expression without using sympy. Sympy
has code generation capabilities to automate this but you seemed to be
confused about basic sympy usage right now so I wouldn't recommend
them without knowing more about what you're trying to do.

--
Oscar

[toc] | [prev] | [next] | [standalone]


#106183

FromPoul Riis <priisdk@gmail.com>
Date2016-03-31 14:33 -0700
Message-ID<9c8497d9-f158-4f94-9a9f-39d6cb63850c@googlegroups.com>
In reply to#106050
Den onsdag den 30. marts 2016 kl. 13.17.33 UTC+2 skrev Poul Riis:
> Is it possible to transfer results from sympy to 'normal' python.
> 
> In the case below I think my intention is clear enough but it does not work as intended. How can it be done?
> 
> Poul Riis
> 
> 
> 
> 
> from sympy import *
> x=Symbol('x')
> ftext=diff(1/(x**2+1),x)
> 
> def f(t):
>     return ftext.subs(x,'t')
> 
> print(f(3))

Well, cos(1) should have been cos(1.0) (which forces numerical evaluation, try example below).
I am just trying to implement one little thing that all CAS tools can do in a few lines, namely finding the derivative of a given function followed by evalution of numerical values, something like:
define(fm(x),diff(f(x),x))
fm(1.0)

Sympy can find the derivative, and once that has been completed I would expect that there is some way to find numerical values just as fast as if the derivative had been given 'by hand'. But how exactly?


Poul Riis


from sympy import *
from time import *
x=Symbol('x')
ftext=diff(sin(x),x)

def fmsympy(t): 
   return ftext.evalf(subs={x:t})

def fm(t):
    return cos(t)

nloop=10000
tstart=time()
for i in range(0,nloop):
    a=fmsympy(1)
dt1=time()-tstart
print(a)
tstart=time()
for i in range(0,nloop):
    a=fm(1.0)
dt2=time()-tstart
print(a)

print(nloop,' evaluations with sympy   : dt1 =',dt1)
print(nloop,' evaluations without sympy: dt2 =',dt2)

[toc] | [prev] | [next] | [standalone]


#106185

FromOscar Benjamin <oscar.j.benjamin@gmail.com>
Date2016-03-31 23:26 +0100
Message-ID<mailman.283.1459463216.28225.python-list@python.org>
In reply to#106183
On 31 March 2016 at 22:33, Poul Riis <priisdk@gmail.com> wrote:
> Den onsdag den 30. marts 2016 kl. 13.17.33 UTC+2 skrev Poul Riis:
>> Is it possible to transfer results from sympy to 'normal' python.
>>
>> In the case below I think my intention is clear enough but it does not work as intended. How can it be done?
>>
>> Poul Riis
>>
>> from sympy import *
>> x=Symbol('x')
>> ftext=diff(1/(x**2+1),x)
>>
>> def f(t):
>>     return ftext.subs(x,'t')
>>
>> print(f(3))
>
> Well, cos(1) should have been cos(1.0) (which forces numerical evaluation, try example below).
> I am just trying to implement one little thing that all CAS tools can do in a few lines, namely finding the derivative of a given function followed by evalution of numerical values, something like:
> define(fm(x),diff(f(x),x))
> fm(1.0)
>
> Sympy can find the derivative, and once that has been completed I would expect that there is some way to find numerical values just as fast as if the derivative had been given 'by hand'. But how exactly?

I assume that you're responding to me (even though your post is a
reply to yourself).

Robert Kern already answered this question earlier in the thread:

$ isympy
IPython console for SymPy 0.7.5 (Python 2.7.9-64-bit) (ground types: gmpy)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)

Documentation can be found at http://www.sympy.org

In [1]: f = lambdify(x, sin(x).diff(x))

In [2]: f
Out[2]: <function numpy.<lambda>>

In [3]: f(1)
Out[3]: 0.540302305868


We can pull apart this function f returned here:

In [4]: import dis

In [5]: dis.dis(f)
  1           0 LOAD_GLOBAL              0 (cos)
              3 LOAD_FAST                0 (x)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE

In [6]: f.func_globals['cos']
Out[6]: <function math.cos>

So the function f returned by lambdify uses math.cos which is the
64-bit float function I mentioned earlier (i.e. the faster one). You
can pass an int in and it will be coerced to float. You should find
that the performance of f is as good as lambda x: math.cos(x).

So lambdify takes an expression and a sequence of symbols and
generates a function whose arguments are substituted for the sequence
of symbols. The return value of the function is the result of
substituting the arguments for the symbols in the expression. I think
this is what you asked for.

--
Oscar

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web