Finding a local max/min of a function in Python

  • Context: Python 
  • Thread starter Thread starter Eclair_de_XII
  • Start date Start date
  • Tags Tags
    Function Local Python
Click For Summary

Discussion Overview

The discussion revolves around finding local maxima and minima of functions using Python, particularly focusing on algorithm design and implementation. Participants explore various methods and code implementations, including the use of NumPy for numerical evaluations.

Discussion Character

  • Technical explanation
  • Mathematical reasoning
  • Debate/contested

Main Points Raised

  • One participant outlines an algorithm for finding local maxima by dividing intervals and checking function values at midpoints.
  • Another participant questions the efficiency of the proposed algorithm, suggesting that it evaluates too many points and could be optimized by focusing on the neighborhood of the maximum value found.
  • Concerns are raised about the density of points generated by NumPy's linspace function, which may not capture the maximum value of the function accurately.
  • A different approach is proposed that avoids using NumPy, emphasizing a simpler method of checking neighboring points for maxima or minima.
  • Participants discuss the implications of constant functions and thin peaks on the algorithms, highlighting potential edge cases that could complicate the search for maxima.
  • There is a suggestion to utilize more advanced search techniques, such as ternary and Fibonacci search methods, for improved efficiency.

Areas of Agreement / Disagreement

Participants express differing opinions on the effectiveness and efficiency of the algorithms discussed. There is no consensus on a single optimal approach, and multiple competing views remain regarding the best method for finding local extrema.

Contextual Notes

Some participants note limitations in the algorithms related to the density of sampled points and the handling of edge cases, such as constant functions with sharp peaks. These aspects remain unresolved within the discussion.

Who May Find This Useful

Readers interested in numerical methods for optimization, algorithm design in Python, and those looking for insights into the challenges of finding local extrema in mathematical functions may find this discussion beneficial.

Eclair_de_XII
Messages
1,082
Reaction score
91
Okay, so my algorithm looks something like this:
====
1. Locate mid-point of the interval . This is our estimate of the local max.
2. Evaluate .
3. Divide the main interval into two subintervals: a left and right of equal length.
4. Check to see if there is a point in the interval such that . If there is, check, because the maximum is there.
5. Do the same for .
6. If there is not a point in either interval such that greater than the current iteration of , then set . This is the maximum.
====

Python:
from numpy import vectorize, linspace

def find_max(x0,xf,h,N=100):
    xm=(xf+x0)/2; f=vectorize(h)
    xleft=linspace(x0,xm,N); xright=linspace(xm,xf,N)
    if (f(xleft)-f(xm)>1E-16).any:
        return find_max(x0,xm,h,N)
    if (f(xright)-f(xm)>1E-16).any:
        return find_max(xm,xf,h,N)
    else:
        return xm

t=(-1,1,lambda x: x**2)
find_max(*t)

Edit: I saw what was wrong with my code. I forgot to put the () after the .any method.

[CODE lang="python" title="Final version."]from numpy import vectorize, linspace, pi,sin

def diff(f,x1,x2):
return f(x1)-f(x2)

def find_crt(x0,xf,h,N=100,local='max'):
local.lower()
assert local=='min' or local=='max'
xm=(xf+x0)/2; f=vectorize(h)
xleft=linspace(x0,xm,N); xright=linspace(xm,xf,N)
t1=[xleft,xm]; t2=[xright,xm]
if local=='min':
t1,t2=t1[::-1],t2[::-1]
if (diff(f,*t1)>=1E-16).any():
return find_crt(x0,xm,h,N)
if (diff(f,*t2)>=1E-16).any():
return find_crt(xm,xf,h,N)
else:
return xm[/CODE]

It's odd, though, that whenever I use this function for this somewhat messy, amateur module:

https://github.com/gchang12/scientific_programming/blob/master/inheritance

with the parameters (x0=-pi/2,xf=pi/2,h=cos,N=50), the module I made implementing it returns no minimum points, while the module here returns a point exponentially close to zero (which I should maybe work on fixing).
 
Last edited:
Technology news on Phys.org
Your post does not really contain a question (anymore?), so I am not sure if you are still looking for help with this. Anyway, what strikes me a bit odd about your algorithm is that you only divide the interval into two at each step, but to do that, you compute the function on all 2N points. After doing that, you could just look what point actually had the maximum value and then limit the search to the neighborhood of that point. Or, if you really want to split the interval into two step by step, you should be able to achieve this with just two evaluations of the function per step (at the neighboring points of you initial guess). Is there any particular reason for the algorithm you chose?
 
Dr.AbeNikIanEdL said:
I am not sure if you are still looking for help with this.

At this point, I am just wondering why it does not work in the module that imported the function.

Dr.AbeNikIanEdL said:
After doing that, you could just look what point actually had the maximum value and then limit the search to the neighborhood of that point.

The problem is that a function evaluated on an array generated with the numpy.linspace function might not necessarily contain the maximum value of the function. The array is not "dense" in the interval ##[x0,xf]##, to use the term very, very lightly.

Dr.AbeNikIanEdL said:
Or, if you really want to split the interval into two step by step, you should be able to achieve this with just two evaluations of the function per step (at the neighboring points of you initial guess).

That, I admit would be a much simpler solution than checking the arrays if there is a maximum value. Checking if the mid-point of the interval is greater than the mid-point of either the left or right sub-interval, then checking it, if is not, would be much more straight-forward.
 
Odd; I just reread what I wrote, and it sounds a lot like a proof I read for that Bolzano-Weierstrauss Theorem.
===
Anyway, I wrote some code again, without using the numpy module. Yeah, your way is better.

Python:
def find_crt2(x0,xf,f,local='max'):
    """This function finds the maximum of an interval [x0,xf] that contains exactly one minimum or maximum."""
    # Want to make sure end-user specifies valid response to type of critical point.
    # local.lower(); assert local=='min' or local=='max' # Nulled code because it does not distinguish between min/max.
    # Want to initialize mid-point of main interval, and mid-point of left and right sub-intervals.
    xm=(xf+x0)/2; xl=(x0+xm)/2; xr=(xm+xf)/2
    # Crucial to returning min or max, per request.
    arg1=[xm,xl]; arg2=[xm,xr]
    # If user seeks minimum, then order of terms in difference is reversed.
    #if local=='min':
    #    arg1=arg1[::-1]; arg2=arg2[::-1]
    # Check if mid-point of main interval is greater than mid-point of left sub-interval.
    if diff(f,*arg1)>1E-16:
        # If it is, then check right sub-interval [xm,xf] because the left sub-interval does not contain max.
        return find_crt2(xm,xf,f)
    elif diff(f,*arg2)>1E-16:
        return find_crt2(x0,xm,f)
    else:
        # Return mid-point of current interval. This ought to be the maximum of the function.
        return xm
 
Last edited:
Eclair_de_XII said:
The problem is that a function evaluated on an array generated with the numpy.linspace function might not necessarily contain the maximum value of the function. The array is not "dense" in the interval [x0,xf], to use the term very, very lightly.

Thats not what I said, I said, with new emphasis

Dr.AbeNikIanEdL said:
you could just look what point actually had the maximum value and then limit the search to the neighborhood of that point.

i.e. if the maximum of the discrete version is at ##x_i## (at least if that is not the start or end point), then ##\max{f}\in (x_{i-1}, x_{i+1})## (otherwise, there would be more then one local max in that interval).

Of course, you could always have a constant function plus a very thin peak that would probably be hard to resolve by either method...
 
Dr.AbeNikIanEdL said:
i.e. if the maximum of the discrete version is at (at least if that is not the start or end point), then ##\max f\in (x_{i-1},x_{i+1})## (otherwise, there would be more then one local max in that interval).

So something like this, I think?

Python:
def find_crt3(x0,xf,f,N=51):
    """This function searches an interval [x0,xf] containing exactly one minimum or maximum of a function f,
    and returns the critical point by recursively checking neighborhoods of estimated maximum."""
    f=vectorize(f); xinc=(xf-x0)/N # This will be the radius of the interval if recursion is necessary.
    xarr=linspace(x0,xf,N); yarr=f(xarr)
    ymax=max(yarr) # Setting the max y-value
    for x in xarr:
        if f(x)==ymax:
            xmax=x # Setting the corresponding x-value for max y-value
            break
    if abs(xmax-(xf+x0)/2)<=1E-16: # Assumed that local max occurs at mid-point of interval at final recursion.
        return xmax
    else: # Search in a neighborhood about the current point at which f is max.
        return find_crt3(xmax-xinc,xmax+xinc,f)

Dr.AbeNikIanEdL said:
constant function plus a very thin peak

So like a function that is doing a terrible impression of the dirac-delta relation.
 
Eclair_de_XII said:
So something like this, I think?

Kind of yeah. I think you can make better use of numpy functions to find the index there, but that's what I had in mind.With the "constant plus very thin peak" I was, in an extreme case, thinking of something like

Python:
def f(x):
    if x == 0.468: return 2.
    else: return 1.
 
  • Like
Likes   Reactions: Eclair_de_XII
Hopefully you have now had more lessons where you have learned about ternary (three-point) and Fibonnaci (golden section) search.
 

Similar threads

  • · Replies 15 ·
Replies
15
Views
2K
  • · Replies 3 ·
Replies
3
Views
3K
Replies
3
Views
4K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 6 ·
Replies
6
Views
3K
  • · Replies 6 ·
Replies
6
Views
2K
  • · Replies 6 ·
Replies
6
Views
2K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 0 ·
Replies
0
Views
2K
  • · Replies 4 ·
Replies
4
Views
3K