sympy

Oscar Benjamin oscar.j.benjamin at gmail.com
Thu Mar 31 14:59:31 EDT 2016


On 31 March 2016 at 11:57, Poul Riis <priisdk at 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



More information about the Python-list mailing list