scijit.optimize.bracket

scijit.optimize.bracket(func, xa=0.0, xb=1.0, args=(), grow_limit=110.0, maxiter=1000)

Bracket a minimum of func.

Searches downhill from two initial points and returns three points that bracket a minimum, with the objective value at each.

Callback style A: func is a plain @njit function taking one float and returning one float:

@njit
def f(x):
    return 10 * x ** 2 + 3 * x + 5

xa, xb, xc, fa, fb, fc, funcalls = bracket(f, 0.1, 1.0)
Parameters:
func@njit function func(x) -> float

Objective to bracket.

xa, xbfloat, optional

Initial points, 0.0 and 1.0 by default. They set the direction of the search and need not contain a minimum.

argstuple, optional

Extra arguments for func, unpacked into every call as func(x, *args). Must be a tuple; anything else raises TypeError. Default ().

grow_limitfloat, optional

Cap on how far one step may move the bracket, as a multiple of the current interval xc - xb. Default 110.0.

maxiterint, optional

Iteration cap on the search. Default 1000.

Returns:
xa, xb, xcfloat

The three bracket points, ordered xa < xb < xc or xc < xb < xa.

fa, fb, fcfloat

func at those three points.

funcallsint

Evaluations of func made.

Raises:
RuntimeError

If no valid bracket is found. The subclass on that exit is scijit.optimize._scalar.BracketError; if the iteration limit is reached first the class is RuntimeError itself.

TypeError

If args is not a tuple.

See also

scipy.optimize.bracket

The scipy routine this mirrors.

scijit.optimize.brent

Minimises from a bracket found this way.

scijit.optimize.golden

The same search behind a golden-section fit.

Notes

A valid bracket is three strictly ordered finite points with fb <= fa and fb <= fc, one of the two strict. The three returned points satisfy that, so a minimum lies inside them.

BracketError is a RuntimeError subclass, so except RuntimeError catches both exits and catches scipy’s too. scipy publishes the class only as the private scipy.optimize._optimize.BracketError, so this package leaves it unexported as well.

scipy attaches the seven values reached at the failure to the BracketError as e.data. A numba exception carries no payload, so the values are unavailable here.

The six point and value returns are Python float. scipy returns numpy.float64, and numpy.int64 for xa and xb when both initial points are integers, which follows from its np.asarray([xa, xb]). Neither type boxes out of compiled code.

Pure @njit, no state and no callback slot, so it is safe to call from a numba.prange loop.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.bracket.html

Examples

Both initial points sit to the right of the minimum, so the third is found to the left:

>>> from numba import njit
>>> from scijit.optimize import bracket
>>> @njit
... def f(x):
...     return 10 * x ** 2 + 3 * x + 5
>>> @njit
... def run():
...     return bracket(f, 0.1, 1.0)
>>> run()
(1.0, 0.1, -1.3562306, 18.0, 5.4, 19.3249226037636, 3)