I did the following test. I applied the following patch:
diff --git a/sympy/core/add.py b/sympy/core/add.py
index d2cac9a..d5c3855 100644
--- a/sympy/core/add.py
+++ b/sympy/core/add.py
@@ -271,6 +271,9 @@ def as_coefficients_dict(a):
di.update(d)
return di
+ def eval_with_numpy(self, var, value):
+ return sum(i.eval_with_numpy(var, value) for i in self.args)
+
@cacheit
def as_coeff_add(self, *deps):
"""
diff --git a/sympy/functions/elementary/trigonometric.py
b/sympy/functions/elementary/trigonometric.py
index 70e9012..8c3f460 100644
--- a/sympy/functions/elementary/trigonometric.py
+++ b/sympy/functions/elementary/trigonometric.py
@@ -1,3 +1,5 @@
+import numpy
+
from sympy.core.add import Add
from sympy.core.numbers import Rational
from sympy.core.basic import C, sympify, cacheit
@@ -165,6 +167,11 @@ def inverse(self, argindex=1):
"""
return asin
+ def eval_with_numpy(self, var, value):
+ if self.args[0] != var:
+ raise NotImplementedError
+ return numpy.sin(value)
+
@classmethod
def eval(cls, arg):
if arg.is_Number:
@@ -401,6 +408,11 @@ def fdiff(self, argindex=1):
def inverse(self, argindex=1):
return acos
+ def eval_with_numpy(self, var, value):
+ if self.args[0] != var:
+ raise NotImplementedError
+ return numpy.cos(value)
+
@classmethod
def eval(cls, arg):
if arg.is_Number:
Then, I ran the following timings:
In [1]: a = sin(x) + cos(x)
In [3]: a.eval_with_numpy(x, 5)
Out[3]: -0.67526208919991215
In [4]: %timeit a.eval_with_numpy(x, 5)
10000 loops, best of 3: 58.5 us per loop
In [9]: import numpy
In [11]: b = lambdify(x, a, numpy)
In [13]: b(5)
Out[13]: -0.67526208919991215
In [12]: %timeit b(5)
100000 loops, best of 3: 9.64 us per loop
So you can see that the lambdify way is more than 6 times faster. The
interface I made up for the eval_with_numpy is very bad. A better one
would involve many more function calls and more complex logic, in
order too be correctly modular. Also, the numpy import would be
inside the functions, which would make it even slower.
6x speedup makes a big difference if you are going to make an
evaluation thousands or even millions of times.
It's not too hard to see why this happens. The eval_with_numpy way
involves logic, and three recursive function calls. The lambdify way
is just a fancy way of writing b = lambda x: numpy.sin(x) +
numpy.cos(x), which, like Ondrej noted, only involves two numpy
function calls and float addition.
Aaron Meurer