1

I'm trying to optimize some python code, which uses scipy.optimize.root for rootfinding.

cProfile tells me that most of the time the programm is evaluating the function called by optimize.root: e.g. for a total execution time of 80s, 58s are spend on lineSphericalDist to which fun contributes 54s (and about 215 000 calls):

Fri Aug  8 21:09:32 2014    profile2

         12796193 function calls (12617458 primitive calls) in 82.707 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.005    0.005   82.710   82.710 BilliardsNumpyClass.py:6(<module>)
        1    0.033    0.033   64.155   64.155 BilliardsNumpyClass.py:446(traceAll)
      100    1.094    0.011   63.549    0.635 BilliardsNumpyClass.py:404(trace)
    91333    7.226    0.000   58.804    0.001 BilliardsNumpyClass.py:244(lineSphericalDist)
   214667   49.436    0.000   54.325    0.000 BilliardsNumpyClass.py:591(fun)
    ...

Here the optimize.root call somehwere in trace:

    ...
            res = optimize.root(self.lineSphericalDist, [tguess], args=(t0, a0), method='lm')
    ...

The function contains of some basic trigonometric functions:

    def lineSphericalDist(self, tt, t0, a0):
        x0,y0,vnn = self.fun(t0)[0:3]
        beta = np.pi + t0 + a0 - vnn

        l = np.sin(beta - t0)/np.sin(beta - tt)

        x2,y2 = self.fun(tt)[0:2]
        return np.sqrt(x0**2+y0**2)*l-np.sqrt(x2**2+y2**2)

In the easiest case fun is:

    def fun(self,t):
        return self.r*np.cos(t),self.r*np.sin(t),np.pi/2.,np.mod(t+np.pi/2., np.pi*2.)

Is there a way to speed this up (tguess is already a pretty good starting value) ? Am I doing something wrong? e.g. is it a good idea to return multiple values the way I do it in fun ?

1
  • the bottleneck in this case seems to be the function trace(), therefore you should find alternatives to optimize.root() in order to get a speed improvement... Commented Aug 8, 2014 at 20:16

1 Answer 1

2

If I understand well your a0 and t0 are not part of the optimization, you only optimize over tt. However, inside lineSphericalDist, you call self.fun(t0). You could precompute that quantity outside of lineSphericalDist, that would halve the number of calls to self.fun...

You could also compute beta, and np.sin(beta - t0), and np.sqrt(x0**2 + y0**2) outside lineSphericalDist, leaving only the bits that really depend on tt inside lineSphericalDist.

Lastly, why does self.fun compute 4 values if only 3 or 2 are used? This is your bottleneck function, make it compute only what's strictly necessary...

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.