2

I have a piecewise mathematical function that needs to be evaluated a lot of times, as a subfunction in quad and curve_fit routines. In trying to improve the performance of my program, I found that a lot of time was spent in evaluating conditions in the if statements.

My function looks like :

def myfunc(x):
    if x < x0:
        return 0.
    elif x < x1:
        return func1(x)
    elif x < x2:
        return c2
    else:
        return 0.

def func1(x):
    return c1*((math.cos(x)/math.cos(x2))**2 - 1)**0.5

Is there a way to define the same function to reduce the function evaluation time?

note:

x0 < x1 < x2
c1, c2 are constants
SimonLR
  • 37
  • 1
  • 5
  • what are the values of x, x0, x1, x2? – Fredrik Pihl Sep 21 '17 at 21:06
  • what is the ordering of x0,x1,x2 – Jean-François Fabre Sep 21 '17 at 21:06
  • 4
    The function call overhead should dwarf these evaluations? How did you work out that the function _body_ is the bottleneck? Have you used `line_profiler`? – roganjosh Sep 21 '17 at 21:06
  • there are 4 cases, you need 4 tests... – Jean-François Fabre Sep 21 '17 at 21:11
  • @roganjosh : I used cProfile. `tottime` (which excludes subfunction calls) is a significant portion of `cumtime`. – SimonLR Sep 21 '17 at 21:12
  • maybe nested ternary would be faster... – Jean-François Fabre Sep 21 '17 at 21:15
  • Can you reduce your problem to barebones? I guess you're using something based on numpy/scipy in which case you should have no need to call a python function for something like this. If you're calling this function on an array then for sure the `numpy` tag would get you a vectorised approach. As it is, we don't have full context. – roganjosh Sep 21 '17 at 21:18
  • Depending on the value of x, x0, x1, x2, is it possible to use a dictionary/look-up-table? – Fredrik Pihl Sep 21 '17 at 21:30
  • 4
    You can't make a significant change in performance by changing the function's body, by only using pure python (Even if you can reduce the number of comparisons). But as you're stated, if the function is getting called many times or repeatedly, you can use memoizing by decorating your function with a [`functools.lru_cache()`](https://docs.python.org/3/library/functools.html#functools.lru_cache) function. Otherwise, as mentioned in other comment you'd better to use Numpy (if it's possible) or other high performance libraries as such. – Mazdak Sep 21 '17 at 21:30
  • @roganjosh : I added the definitions of `func1` and `func2`, which is a constant. I used `numpy.cos` before, but `math.cos` seems to be a lot faster. – SimonLR Sep 22 '17 at 12:28
  • @FredrikPihl : I had something like that in mind. I know it is possible if the choices are exact (for example `if a == 'hello': ...`). But I don't know how to do it with comparison tests on floats. – SimonLR Sep 22 '17 at 12:31

0 Answers0