我正在分析一些代码,cProfile报告几乎所有的时间花在<string>:1(<lambda>)
上。这是什么意思?
这是cProfile的输出:
10182 function calls in 191.365 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
727 187.331 0.258 187.331 0.258 <string>:1(<lambda>)
1 0.000 0.000 191.365 191.365 <string>:1(<module>)
727 0.791 0.001 0.837 0.001 function_base.py:822(gradient)
727 0.003 0.000 0.031 0.000 numeric.py:65(zeros_like)
1 0.000 0.000 191.365 191.365 ode.py:316(integrate)
1 2.447 2.447 191.365 191.365 ode.py:685(run)
1454 0.376 0.000 1.213 0.001 useful.py:117(q_powers_opr)
727 0.296 0.000 188.918 0.260 useful.py:95(dWave)
1454 0.001 0.000 0.001 0.000 {len}
727 0.001 0.000 0.001 0.000 {method 'append' of 'list' objects}
727 0.013 0.000 0.013 0.000 {method 'astype' of 'numpy.ndarray' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
727 0.024 0.000 0.024 0.000 {method 'fill' of 'numpy.ndarray'objects}
727 0.004 0.000 0.004 0.000 {numpy.core.multiarray.empty_like}
727 0.001 0.000 0.001 0.000 {range}
727 0.078 0.000 1.291 0.002 {sum}
以下是分析代码:
import useful
import numpy as np
import sympy as sp
import cProfile
u=sp.Symbol('u')
q=sp.Symbol('q')
x_0=sp.Symbol('x_0')
p_0=sp.Symbol('p_0')
w=sp.Symbol('w')
L_u=sp.Lambda(u,u**4/4-5*u**2/2)
V_q=sp.Lambda(q,10*q)
sys=useful.system(L_u)
pAxis=np.linspace(-60+0j,60,10000)
pWave=useful.numpify(useful.gaussian_wavefunction.subs({x_0:5,p_0:0,w:1}))(pAxis)
pWave_t=sys.time_evolve(pWave,pAxis,V_q)
print "Starting Integration"
cProfile.run("pWave2=pWave_t.integrate(0.2)")
这里有用。实际上可以做任何事情:
import numpy as np
import sympy as sp
import functools
from scipy import integrate
from itertools import *
u=sp.Symbol('u')
q=sp.Symbol('q')
p=sp.Symbol('p')
w=sp.Symbol('w')
x_0=sp.Symbol('x_0')
p_0=sp.Symbol('p_0')
hStep=sp.Lambda(p,(1+sp.sign(p))/2)
gaussian_wavefunction=sp.Lambda(p,(2*sp.pi*w**2)**(-sp.Rational(1,4))*\
sp.exp(-sp.I*x_0*p)*sp.exp(-(p-p_0)**2/(4*w**2)))
class system:
def __init__(self,K_u):
"""
This function accepts a definition of kinetic energy in terms of
velocity (u). Lagrangeans with cross terms between u and q are at the
moment outside the scope of this program; this may change.
"""
#This file will use the convention {function}_{input variables}
#I can't figure out how to allow parameterization of the lagrangean,
# so I won't for now.
self.p_u=sp.Lambda(u,sp.diff(K_u(u),u))
u_crit=sp.solve(sp.diff(self.p_u(u),u))
self.p_crit=map(self.p_u,u_crit)
n_p_crit=sorted([complex(sp.N(p_crit))
for p_crit in self.p_crit],key=lambda x: x.real)
#print n_p_crit
self.H_u=sp.Lambda(u,sp.expand(self.p_u(u)*u-K_u(u)))
self.u_p=[sp.Lambda(p,u_p_i) for u_p_i in sp.solve(self.p_u(u)-p,u)]
#This will fail horribly if there is only one critical point;
# really you shouldn't be using it in that case, though, so..
test_points=[2*n_p_crit[0]-n_p_crit[1]] #Left of the leftmost point
test_points+=[(p_1+p_2)/2 for (p_1,p_2) in
izip(n_p_crit[:-1],n_p_crit[1:])] #average of every pair of points
test_points+=[2*n_p_crit[-1]-n_p_crit[-2]]#Right of the rightmost point
def slopeSign(f):
#Given a symbolic function f, returns a numerical function over the
# same domain, which gives the sign of the slope of f.
def out(x):
deriv=sp.diff(f(p),p).subs(p,x)#Note this is still sympified
return int(np.sign(complex(deriv).real))
return out
#Note that the below is a generator. A streight list will not close
# arround u_p_i, and they'll all reference the last one. Annoying,
# although a generator is better for this job anyway.
n_orientation_p=(slopeSign(u_p_i) for u_p_i in self.u_p)
orientation=[[n_orientation_p_i(point)
for point in test_points] for n_orientation_p_i in n_orientation_p]
#The following determines the validity of u(p) in each region for each
# velocity functuion
valid=[[-0.0001<complex(u_p_i(point)).imag<0.0001
for point in test_points] for u_p_i in self.u_p ]
step=[sp.Lambda(p,hStep(n_p_crit[0]-p))]
step+=[sp.Lambda(p,hStep(p-p_1)*hStep(p_2-p))
for (p_1,p_2) in izip(n_p_crit[:-1],n_p_crit[1:])]
step+=[sp.Lambda(p,hStep(p-n_p_crit[-1]))]
#The effective factors are functions of p, valued at -1,0,or 1, that
# are multiplied by the various possible functions of p based on
# functions of u (see H_eff_p for example)
def signedSteps(sign,nonzero):
for (step_i,sign_i,nonzero_i) in izip(step,sign,nonzero):
yield step_i(p)*sign_i*int(nonzero_i)
def eff_factor(orientation_i,valid_i):
return sp.Lambda(p,sum(signedSteps(orientation_i,valid_i)))
self.eff_factors_p=[eff_factor(orientation_i,valid_i)
for (orientation_i,valid_i) in izip(orientation,valid)]
self.H_eff_p=self.effective_function(self.H_u)
#a system will have the following:
#p_u,H_u,u_p,H_p,eff_factors_p,H_eff_p
def effective_function(self,f_u):
f_p=[sp.Lambda(p,sp.expand(f_u(u_p_i(p)))) for u_p_i in self.u_p]
#The above is a list of functions in terms of p.
return sp.Lambda(p,sum(f_p_i(p)*eff_factors_p_i(p)\
for (f_p_i,eff_factors_p_i) in izip(f_p,self.eff_factors_p)))
def time_evolve(self,pWave,pAxis,V_q=0):
H_eff_p_n=numpify(self.H_eff_p)
if V_q==0:
return pWave*np.exp(-(0+1j)*t*H_eff_p_n(pAxis))
else:
try:
#[-2::-1] gives the coeffs in order q^1,q^2,q^3...
V_q_coeffs=V_q(q).as_poly().all_coeffs()[-2::-1]
V_q_coeffs=map(complex,V_q_coeffs)#De-sympifies the coeffs
except TypeError, te:#Not everything is a polynomial...
print "Nonpolynomial potentials are not supported"
raise
if (np.abs(np.diff(pAxis,2))<0.0001).all():
spacing=pAxis[1]-pAxis[0]
else:
spacing=np.gradient(pAxis)
print spacing
def dWave(t,pWave,pAxis):
dWave=-(0+1j)*H_eff_p_n(pAxis)*pWave
dWave+=-(0+1j)*sum(q_powers_opr(pWave,V_q_coeffs,spacing))
"""
def dWave(pWave,H_eff_p_n,V_q_coeffs,pAxis,spacing):
dWave=np.empty_like(pWave)
dWave[1::2]=-H_eff_p_n(pAxis)*pWave[::2]
dWave[::2]=H_eff_p_n(pAxis)*pWave[1::2]
vWave=sum(q_powers_opr(pWave,V_q_coeffs,spacing))
dWave[1::2]=-vWave[::2]
dWave[::2]=vWave[1::2]
del vWave
"""
return dWave
ode=integrate.ode(dWave)
ode.set_integrator('zvode')
ode.set_f_params(pAxis)
ode.set_initial_value(pWave)
#ode.set_f_params(H_eff_p_n,V_q_coeffs,pAxis,spacing)
return ode
#integrate.odeint(dWave,pWave,[0,t],
# args=(H_eff_p_n,V_q_coeffs,spacing))
def q_powers_opr(wave,coeffs,spacing):
#nextWave=np.empty_like(wave)
for c in coeffs:
yield c*(0+1j)*np.gradient(wave)/spacing
"""
nextWave[1::2]=c*np.gradient(wave[::2])/spacing
nextWave[::2]=-c*np.gradient(wave[1::2])/spacing
wave=nextWave
"""
def numpify(func):
try:
return map(numpify,func)
except TypeError, te:#If there is only one function
return sp.lambdify(func.variables,func(*func.variables),"numpy")
def niceIfft(pAxis,pWave):
pRange=pAxis[-1]-pAxis[0]
p0=pAxis[0]
length=np.size(pAxis)
xRange=2*np.pi*length/pRange
xAxis=np.linspace(-xRange/2,xRange/2,length)
iAxis=np.arange(length)
xWave=(1/np.sqrt(2*np.pi)*pRange*np.fft.ifftshift(np.fft.ifft(pWave))*
np.exp(2*np.pi*(0+1j)*(-p0)/pRange*iAxis))
return (xAxis,xWave)
答案 0 :(得分:1)
我认为问题是你的numpify
功能。它用于创建H_eff_p_n
,这是dWave
调用的唯一一个未在输出中明确命名的函数。我不知道lambdify
是如何工作的,但它必须以某种方式通过exec
字符串创建一个lambda函数。当然,lambda
是匿名的!
>>> (lambda x: x).func_name
'<lambda>'
我刚看到你的评论;一个简单的解决方法是简单地使用def
。如... ...
H_eff_p_n_lambda=numpify(self.H_eff_p)
def H_eff_p_n(*args, **kwargs):
return H_eff_p_n_lambda(*args, **kwargs)
这不会表现得那么好,但它至少会明确(通过cumtime
)哪个lambda变慢。我认为修改__name__
或func_name
属性可能有所帮助,但它对我不起作用。
仔细查看profile
的来源(我假设它与此处的cProfile
大致相同),似乎profile
使用的函数名称不是来自{ {1}},而是来自func.func_code.co_name
,这是只读的!因此,给lambda命名用于分析目的可能很难。