Reputation: 454
So, I have this code
from __future__ import division, print_function
import sympy as sp
import numpy as np
from sympy.utilities.lambdify import *
u = np.random.uniform(4, 6, 500)
w, k = sp.symbols('w k')
f = sp.log((k - w) * sp.exp((k - w)**5))
l = sum(f.subs(dict(k=k)) for k in u)
And now I want to use l
as a function of w
. So I know of some options
z_lambdify = lambdify(w, l)
z_subs = lambda x: l.subs(w, x)
The first function gives an error
>>> z_lambdify(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <lambda>
OverflowError: math range error
>>> z_lambdify(4)
40.862695278600114
While the second gives answers
>>> z_subs(1)
11469.9130597554
>>> z_subs(4)
40.8626952786003
I would just use this, but it is very slow. Any way to get around this (fixing the lamdify error or a way of using l
as a function that is not so slow)?
Version: Python 2.7.6, NumPy 1.8.1, SymPy 0.7.4.1
Upvotes: 3
Views: 338
Reputation: 58985
The problem is that:
z_lambdify = lambdify(w, l)
tells the new function to perform the calculations using the built-in math
functions, which you can check running with cProfile.run('z_lambdify(1)')
; while doing z_subs(1)
calls sympy
functions. To get the same behavior you should tell lambdify()
to use the same module:
z_lambdify = lambdify(w, l, "sympy")
You should simplify your function already at its definition and then useNumPy
to perform the calculations much more efficiently. Using some simple algebra your function can be rewritten in a "non-overflowing" format as:
f = lambda k, w: np.log(k - w) + (k - w)**5
such that your desired answer can be achieved doing:
f(k=u, w=1).sum()
when you do f(k=u, w=1)
you get an array with the same shape of u
, where each value represents the result of the function evaluated with each value of u
. You can use this function to simultaneously evaluate f()
for different values of k
and w
, i.e. passing w
as another array with the same shape of u
instead of using a constant value.
Upvotes: 1