scijit.optimize.basinhopping¶
- scijit.optimize.basinhopping(func, x0, niter=100, T=1.0, stepsize=0.5, minimizer_kwargs=None, take_step=None, accept_test=None, callback=None, interval=50, disp=False, niter_success=None, rng=None, target_accept_rate=0.5, stepwise_factor=0.9, args=None, seed=None, xtol=0.0001, ftol=0.0001, gtol=1e-05)¶
Basin-hopping global optimization by random restarts.
Alternates a random displacement with a local minimization, keeping or rejecting each new basin by a Metropolis test.
Callback style A –
funcand the gradient are plain@njitfunctions passed as first-class arguments. No@cfunc, no.address.- Parameters:
- func@njit function
func(x, *args) -> float64 Objective.
- x0float64 array, shape (N,)
Starting point. Cast to float64 and copied.
- niterint, optional
Basin-hopping iterations. Default 100.
- Tfloat, optional
Metropolis temperature. Default 1.0.
T = 0makes beta infinite, so every uphill move is rejected.T < 0inverts the test.- stepsizefloat, optional
Initial random-displacement size. Default 0.5. Must be positive.
- minimizer_kwargsdict, optional
The local minimizer and its gradient.
'method'is one of'Nelder-Mead','Powell','BFGS'or'CG', defaulting to'BFGS';'jac'is a plain@njitgrad(x, *args) -> float64 array. Omitting'jac'under a gradient method uses forward differences. Inside@njitthe dict must be written as a LITERAL at the call site. See Notes.- take_step, accept_testNone
Accepted only at their defaults. See Notes.
- callbackcallable, optional
Called once on the initial quench and once per iteration, as
callback(x, f, accept)on the TRIAL point, and halts the run on a truthy return. Two spellings are served: a plain Python callable, and a numba@njitcallback(x, f, accept)returning a bool. See Notes.- intervalint, optional
Period of the step-size adaptation, in iterations. Default 50. The step is adapted whenever
nstep % interval == 0, so the sign carries no meaning.0raises.- dispbool, optional
Print the per-step lines, the step-size adaptation line, the new-global-minimum line and the local-minimization-failure warning. Default
False.- niter_successint or None, optional
Stop after this many consecutive iterations without improving the global minimum.
None(default) usesniter + 2, which the run can still reach when it breaks early. Every integer is a real threshold,-1included: it stops after the first iteration that does not improve the global minimum.- rngint or numpy.random.Generator, optional
Source of the displacement and Metropolis draws.
None(default) uses the internal xorshift64* generator; an integer builds anumpy.random.default_rngfor the call; aGeneratoris drawn from directly and its state advances. See Notes.- target_accept_ratefloat, optional
Acceptance rate the adaptive step size aims at. Default 0.5. Must lie in
(0, 1).- stepwise_factorfloat, optional
Multiplicative factor applied when adapting the step. Default 0.9. Must lie in
(0, 1).- argstuple or ndarray, optional
Extra parameters forwarded to func and to the gradient. A tuple is unpacked into separate arguments after x, so
args=(a, b)callsfunc(x, a, b). Its elements may be of any type a compiled call accepts, arrays and strings included.None(default) callsfunc(x). An ndarray or a list arrives as ONE argument instead,func(x, args). See Notes.- seedint, optional
BEYOND SCIPY. Seeds the internal xorshift64* generator, which is the rng at
Nonepath.None(default) draws fresh entropy per call, so two identical calls give different answers. See Notes.- xtol, ftolfloat, optional
Tolerances handed to
'Nelder-Mead'and'Powell'. Both 1e-4.- gtolfloat, optional
Gradient tolerance handed to
'BFGS'and'CG'. Default 1e-5.
- func@njit function
- Returns:
- resBasinhoppingResult
A namedtuple carrying
x,fun,nit,nfev,njev,minimization_failures,successandmessage.messageis a list holding one string, sores.message[0]is the sentence.njevis0under'Nelder-Mead'and'Powell'.successis the success flag of the local minimization that producedx.minimization_failurescounts the quench from x0 as well as the per-iteration ones.
- Raises:
- ValueError
A 2-D or empty x0,
niter < 0,stepsize <= 0, a target_accept_rate or stepwise_factor outside(0, 1), an unknown'method', a key in minimizer_kwargs other than'method'and'jac', take_step or accept_test away fromNone, a rng that is notNone, an integer or anumpy.random.Generator, or a callback that is a@cfunc, a raw function address or a non-callable.- ZeroDivisionError
interval == 0. interval divides the step counter.
See also
scipy.optimize.basinhoppingThe scipy routine this mirrors.
scijit.optimize.differential_evolutionPopulation-based, no start point.
scijit.optimize.bruteExhaustive grid search.
scijit.optimize.minimizeOne local minimization, no restarts.
Notes
minimizer_kwargs carries
'method'and'jac'only. scipy forwards the whole dict tominimize; here args, xtol, ftol and gtol are explicit arguments ofbasinhoppingitself.ADDITIVE: args is a top-level parameter. scipy publishes none, and raises
TypeErrorfor one. A tuple is unpacked into the objective’s argument list,func(x, *args); an ndarray or a list reaches func as ONE argument instead, because the arity of a compiled call is fixed when it compiles.Inside
@njitthe dict must be written as a LITERAL at the call site. A dict built elsewhere and passed in as a variable raisesTypingError: a literal is typed where it is written, carrying its keys and a callable value, while a variable has to be unboxed and a numba dict cannot hold a function.A Python callback is reached from compiled code through a module-level slot and a
numba.objmodeblock, so it takes the GIL and pays an interpreter round trip once per iteration. It is also notprange-safe, because the slot is module state that two concurrent runs share. Inside@njitonly the@njitspelling is accepted, since a Python callable cannot cross into compiled code as an argument. The@njitspelling must RETURN a bool; a Python one may returnNone, which scipy reads as no halt.NOT IMPLEMENTED: take_step and accept_test. Both are Python callables. Step taking, adaptation and acceptance reproduce scipy’s
RandomDisplacement+AdaptiveStepsize+Metropoliswith all their defaults, including consuming an RNG draw on downhill moves.UNAVAILABLE:
lowest_optimization_result. It is a nested result object whose field set varies with the local minimizer.ADDITIVE: njev is always present and is
0on the derivative-free minimizers. scipy carries the key only when the quench used a gradient, and can, because its result is a dict.With rng at
Nonethe draws come from an internal xorshift64* generator carried in a per-call state array. seed selects its stream andseed=Nonedraws a fresh one per call.DELIBERATELY DIFFERENT: an integer rng builds a
numpy.random.default_rng, which is PCG64. scipy’scheck_random_statemaps an integer to the legacyRandomState, which is MT19937 and which compiled code cannot hold, so the two explore differently at the same integer. AGeneratorpassed in is used directly, and its draws are numpy’s own.A rng at
Noneis safe to call from anumba.prangeloop, because the generator state is per-call. OneGeneratorSHARED across aprangeis not: 70,499 of 100,000 draws were distinct across 32 threads. An integer rng builds its generator inside the call, so it is per-call as well. A Python callback is notprange-safe either, and serializes the loop.https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.basinhopping.html
Examples
>>> import numpy as np >>> from numba import njit >>> from scijit.optimize import basinhopping >>> @njit ... def q(x): ... return (x[0] - 1.5) ** 2 + (x[1] + 0.5) ** 2 >>> @njit ... def run(): ... return basinhopping(q, np.array([2.0, 2.0]), 20) >>> res = run() >>> np.round(res.x, 4) array([ 1.5, -0.5]) >>> res.njev > 0 True