<p dir="auto">According to the documentation, if a callback function is specified as a kwarg to the basinhopping function, this callback function should be called after every local minimum found.</p>
<blockquote>
<blockquote>
<blockquote>
<p dir="auto"><code class="notranslate">callback : callable, callback(x, f, accept), optional</code><br>
Callback function which will be called for all minima found. x and f are the coordinates and function value of the trial minimum, and accept is whether or not that minimum was accepted. This can be used, for example, to save the lowest N minima found. Also, callback can be used to specify a user defined stop criterion by optionally returning True to stop the basinhopping routine.</p>
</blockquote>
</blockquote>
</blockquote>
<p dir="auto">However, it is not called for the first minimum found. (The one that is found at 'basinhopping step 0').</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)
from scipy import optimize
import numpy as np

# Make some function to optimize. It prints its value for every function call.
r=np.random.rand(10)
def fun(x): 
    c=[rand[i]*np.sin(x)+rand[i+1]*np.cos(x) for i in range(len(rand)-1)]
    f=np.sum(c)+0.00000001*x**4
    print(f)
    return f

def callback(x,f,a): #This function should be called after EVERY local minimum obtained so also after the first local minimum. (This is the minimum obtained at step 0).
    print('CALLBACK', x,f,a)
    
sol=optimize.basinhopping(fun,[0.01],4,callback=callback,disp=True)

print(sol.fun)"><pre class="notranslate"><code class="notranslate">import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info)
from scipy import optimize
import numpy as np

# Make some function to optimize. It prints its value for every function call.
r=np.random.rand(10)
def fun(x): 
    c=[rand[i]*np.sin(x)+rand[i+1]*np.cos(x) for i in range(len(rand)-1)]
    f=np.sum(c)+0.00000001*x**4
    print(f)
    return f

def callback(x,f,a): #This function should be called after EVERY local minimum obtained so also after the first local minimum. (This is the minimum obtained at step 0).
    print('CALLBACK', x,f,a)
    
sol=optimize.basinhopping(fun,[0.01],4,callback=callback,disp=True)

print(sol.fun)
</code></pre></div>
<p dir="auto">Output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="0.19.1 1.19.2 sys.version_info(major=3, minor=6, micro=9, releaselevel='final', serial=0)
[1.96831928]
[1.96831931]
[1.96831928]
[-0.92950861]
[-0.92950861]
[-0.92950857]
[2.85408366]
[2.85408366]
[2.85408365]
[-2.89631992]
[-2.89631992]
[-2.89631991]
[-1.50802259]
[-1.50802259]
[-1.50802263]
[-3.05249589]
[-3.05249589]
[-3.05249589]
[-3.05305485]
[-3.05305485]
[-3.05305485]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 0: f -3.05306
[-2.9563823]
[-2.95638231]
[-2.9563823]
[-2.66471613]
[-2.66471613]
[-2.6647161]
[-3.05304349]
[-3.05304349]
[-3.05304349]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 1: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
found new global minimum on step 1 with function value -3.05306
CALLBACK [-2.26143318] -3.053055041496532 True
[-2.74742421]
[-2.74742423]
[-2.74742421]
[-2.58877573]
[-2.58877573]
[-2.58877571]
[-3.05304702]
[-3.05304702]
[-3.05304702]
[-3.05305503]
[-3.05305503]
[-3.05305503]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 2: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
CALLBACK [-2.26143319] -3.053055041496532 True
[-2.89346177]
[-2.89346176]
[-2.89346177]
[-2.43156461]
[-2.43156461]
[-2.43156464]
[-3.05300591]
[-3.05300591]
[-3.05300591]
[-3.05305503]
[-3.05305503]
[-3.05305503]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 3: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
found new global minimum on step 3 with function value -3.05306
CALLBACK [-2.26143317] -3.053055041496533 True
[-2.96682236]
[-2.96682235]
[-2.96682236]
[-2.70485805]
[-2.70485805]
[-2.70485807]
[-3.05304677]
[-3.05304677]
[-3.05304677]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 4: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
CALLBACK [-2.26143318] -3.053055041496532 True
-3.053055041496533"><pre class="notranslate"><code class="notranslate">0.19.1 1.19.2 sys.version_info(major=3, minor=6, micro=9, releaselevel='final', serial=0)
[1.96831928]
[1.96831931]
[1.96831928]
[-0.92950861]
[-0.92950861]
[-0.92950857]
[2.85408366]
[2.85408366]
[2.85408365]
[-2.89631992]
[-2.89631992]
[-2.89631991]
[-1.50802259]
[-1.50802259]
[-1.50802263]
[-3.05249589]
[-3.05249589]
[-3.05249589]
[-3.05305485]
[-3.05305485]
[-3.05305485]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 0: f -3.05306
[-2.9563823]
[-2.95638231]
[-2.9563823]
[-2.66471613]
[-2.66471613]
[-2.6647161]
[-3.05304349]
[-3.05304349]
[-3.05304349]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 1: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
found new global minimum on step 1 with function value -3.05306
CALLBACK [-2.26143318] -3.053055041496532 True
[-2.74742421]
[-2.74742423]
[-2.74742421]
[-2.58877573]
[-2.58877573]
[-2.58877571]
[-3.05304702]
[-3.05304702]
[-3.05304702]
[-3.05305503]
[-3.05305503]
[-3.05305503]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 2: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
CALLBACK [-2.26143319] -3.053055041496532 True
[-2.89346177]
[-2.89346176]
[-2.89346177]
[-2.43156461]
[-2.43156461]
[-2.43156464]
[-3.05300591]
[-3.05300591]
[-3.05300591]
[-3.05305503]
[-3.05305503]
[-3.05305503]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 3: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
found new global minimum on step 3 with function value -3.05306
CALLBACK [-2.26143317] -3.053055041496533 True
[-2.96682236]
[-2.96682235]
[-2.96682236]
[-2.70485805]
[-2.70485805]
[-2.70485807]
[-3.05304677]
[-3.05304677]
[-3.05304677]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
[-3.05305504]
basinhopping step 4: f -3.05306 trial_f -3.05306 accepted 1  lowest_f -3.05306
CALLBACK [-2.26143318] -3.053055041496532 True
-3.053055041496533
</code></pre></div>
<p dir="auto">My issue is about ...</p>
<p dir="auto">As far as I understand, callback function is called when a local minima is found. When I use basinhopping global minimization algorithm, I have observed that the callback function is not called when local minima is found for initial guess. I have tried to reproduce this issue with the following example:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from scipy.optimize import basinhopping
import numpy as np

def func(x):
    print(&quot;Objective function count: &quot; + str(func.counter))
    func.counter += 1
    return np.random.rand(1)*1000

def callback_func(x, f, accepted):
    print(&quot;Callback count: &quot; + str(callback_func.counter))
    callback_func.counter += 1

func.counter = 0
callback_func.counter = 0    
x0 = 2000

minimizer_kwargs = {&quot;method&quot;: &quot;COBYLA&quot;, &quot;options&quot;:{&quot;maxiter&quot;: 1}}
optimizer = basinhopping(func, x0, minimizer_kwargs=minimizer_kwargs, niter=2, callback=callback_func)"><pre class="notranslate"><code class="notranslate">from scipy.optimize import basinhopping
import numpy as np

def func(x):
    print("Objective function count: " + str(func.counter))
    func.counter += 1
    return np.random.rand(1)*1000

def callback_func(x, f, accepted):
    print("Callback count: " + str(callback_func.counter))
    callback_func.counter += 1

func.counter = 0
callback_func.counter = 0    
x0 = 2000

minimizer_kwargs = {"method": "COBYLA", "options":{"maxiter": 1}}
optimizer = basinhopping(func, x0, minimizer_kwargs=minimizer_kwargs, niter=2, callback=callback_func)
</code></pre></div>
<p dir="auto">It produces following result:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Objective function count: 0
Objective function count: 1
Callback count: 0
Objective function count: 2
Callback count: 1"><pre class="notranslate"><code class="notranslate">Objective function count: 0
Objective function count: 1
Callback count: 0
Objective function count: 2
Callback count: 1
</code></pre></div>
<p dir="auto">For the above mentioned example, both callback function and the objective function should have been called thrice but callback is called only twice.</p>
<h4 dir="auto">Scipy/Numpy/Python version information:</h4>
 1.2.1 1.16.4 sys.version_info(major=3, minor=7, micro=4, releaselevel='final', serial=0)