scijit.optimize.fmin

scijit.optimize.fmin(func, x0, args=(), xtol=0.0001, ftol=0.0001, maxiter=None, maxfun=None, full_output=0, disp=1, retall=0, callback=None, initial_simplex=None)

Minimize a function using the Nelder-Mead simplex algorithm.

Derivative-free: only function values are used. Callable from Python and from inside @njit; both entries run the same compiled core.

Parameters:
funccallable

A plain @njit f(x, *args) -> value. No @cfunc, no .address.

x0array_like

Initial guess. Any rank is flattened.

argstuple or ndarray, optional

Extra parameters. A tuple is unpacked into separate arguments after x, so args=(a, b) calls func(x, a, b). Its elements may be of any type a compiled call accepts, arrays and strings included. Default (), which calls func(x). An ndarray or a list arrives as ONE argument instead, func(x, args). See Notes.

xtol, ftolfloat, optional

Absolute convergence tolerances on x and on f. Both must be met. Defaults 1e-4.

maxiter, maxfunint or None, optional

Iteration and evaluation budgets. None (default) means N*200 for BOTH, but supplying only ONE leaves the OTHER unbounded rather than at the default.

full_outputbool, optional

False (default) returns xopt. True returns (xopt, fopt, iter, funcalls, warnflag). Compile-time constant inside @njit: it selects the return type.

dispint, optional

1 (default) prints a summary on success and raises a RuntimeWarning on a limit. 0 is silent, and is what a prange sweep wants: see Notes.

retallbool, optional

Append allvecs to the return. Compile-time constant.

callbackcallable or None, optional

Called once per iteration as callback(xk), with a copy of the current iterate. A plain Python function may instead be written callback(intermediate_result) and is handed an object carrying x and fun. Raising StopIteration stops the run and returns the current best. From inside @njit the callback is an @njit callback(xk).

initial_simplexarray_like or None, optional

(N+1, N). Overrides the simplex built around x0; x0 is then used only for the length check.

Returns:
xoptndarray

The minimizer.

foptfloat

func(xopt). With full_output.

iterint

Iterations performed. With full_output.

funcallsint

Objective evaluations. With full_output.

warnflagint

0 converged, 1 maxfun reached, 2 maxiter reached. NOTE that fmin_cg and fmin_bfgs use a DIFFERENT table, where 1 means maxiter. With full_output.

allvecslist of ndarray

The best point after each iteration, iter entries of shape (N,), the last being xopt. With retall. The first is x0 unless an initial_simplex was given, in which case it is that simplex’s first row. From inside @njit this is a numba.typed.List.

Raises:
ValueError

If callback is neither None nor a callable nor an @njit function, or initial_simplex has a shape other than (N + 1, N).

See also

scipy.optimize.fmin

The scipy routine this mirrors.

scijit.optimize.fmin_powell

Derivative-free, direction-set.

scijit.optimize.fmin_bfgs

Uses a gradient, usually far fewer evaluations.

scijit.optimize.minimize_scalar

One variable.

Notes

Under retall, allvecs is a python list of 1-D arrays, as scipy’s is. From inside @njit it is a numba.typed.List of the same arrays.

args is unpacked into the objective’s argument list, func(x, *args), which is scipy’s contract. An ndarray or a list args reaches func as ONE argument instead. scipy accepts neither spelling at this name, so the one-argument form is additive and no scipy-shaped call reaches it.

full_output and retall must be compile-time literals inside @njit: they select the return type.

callback takes a plain Python function or an @njit function, and both halt on StopIteration. The Python spelling reaches the compiled core through a numba.objmode block over a module-level slot: it takes the GIL once per iteration, and two concurrent solves that both install one overwrite each other, so a prange loop over it serializes and is not reentrant.

Two differences from scipy follow from the compiled path. A plain Python callable cannot be an argument of a compiled function, so a call written inside @njit passes the @njit spelling and a Python one is refused by numba. And numba matches no exception class, except StopIteration being a TypingError on 0.66, so any exception raised inside an @njit callback stops the run the way StopIteration does, where scipy propagates it. A Python callback keeps scipy’s behaviour: only StopIteration halts, and anything else reaches the caller.

disp reproduces scipy’s summary and scipy’s warning, at scipy’s default, so a bare call writes to stdout and warns on a limit path. The warning takes the GIL through a numba.objmode block and the printing through Python’s stdout, so with disp set a prange loop over this routine still gives the right answer but serializes. disp=0 is the parallel path.

Pure @njit, so it is safe to call from a numba.prange loop with disp=0 and with callback left at None or given as an @njit function.

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

Examples

>>> import numpy as np
>>> from numba import njit
>>> from scijit.optimize import fmin
>>> @njit
... def rosen(x):
...     s = 0.0
...     for i in range(x.size - 1):
...         s += 100.0 * (x[i + 1] - x[i] ** 2) ** 2 + (1.0 - x[i]) ** 2
...     return s
>>> @njit
... def run():
...     return fmin(rosen, np.array([0.0, 0.0]), disp=0)
>>> np.round(run(), 4)
array([1., 1.])