I have a python script where, as part of an evolutionary optimization algorithm, I'm evaluating partial derivatives many thousands of times. I've done a line by line profile, and this partial derivative calculation is taking up the majority of the run time. I'm using scipy.optimize.approx_fprime
to calculate the partial derivatives, and I tried to rewrite it in cython without much success.
The line by line profile is below. My cythonized version of scipy.optimize.approx_fprime
is simply called approx_fprime
.
Line # Hits Time Per Hit % Time Line Contents
==============================================================
84 @profile
100 1500 14889652 9926.4 25.3 df1 = approx_fprime(inp_nom,evaluate1,epsilon)
101 1500 14939889 9959.9 25.4 df2 = scipy.optimize.approx_fprime(inp_upp,evaluate1,epsilon)
Below is my cython file.
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False) # turn of bounds-checking for entire function
def approx_fprime(np.ndarray xk, f, double epsilon, *args):
# From scipy.optimize.approx_fprime
f0 = f(*((xk,) + args))
cdef np.ndarray grad = np.zeros((len(xk),), float)
cdef np.ndarray ei = np.zeros((len(xk),), float)
cdef np.ndarray d = epsilon * ei
for k in xrange(len(xk)):
ei[k] = 1.0
grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
ei[k] = 0.0
return grad
I've tried to put in all the relevant type declarations and ensure that it plays nicely with numpy. Ultimately, though, the proof is in the pudding, as they say. This version is just not really any faster than the scipy version. The function only has a few variables, so it's not a huge computation and there's probably only room for an incremental improvement in one iteration. However, the function gets called over and over because this is used in an evolutionary optimization algorithm, and so I'm expecting/hoping that an incremental performance gain multiplied many times over will have a big payoff.
Could a cython expert out there take a look at this code and help me figure out if I'm on the right track, or if this is just a fool's errand?
Thank you!