scijit.optimize.toms748

scijit.optimize.toms748(f, a, b, args=(), k=1, xtol=2e-12, rtol=8.881784197001252e-16, maxiter=100, full_output=False, disp=True)

TOMS Algorithm 748 (Alefeld, Potra and Shi).

Bracketing method using inverse cubic and Newton-quadratic interpolation; asymptotically the fastest of the bracketers for a smooth f.

Callback style A: f is a plain @njit f(x) -> float.

Parameters:
f@njit function f(x) -> float

Continuous function whose root is wanted.

a, bfloat

Bracket endpoints. Unlike the other bracketers here, a < b is required, and ValueError otherwise. f(a) and f(b) must not have the same sign; if they do, ValueError is raised. Either endpoint being an exact root returns immediately.

argstuple, optional

Extra arguments for f, unpacked into every call as f(x, *args). A non-tuple is taken as a single extra argument. Default ().

kint, optional

Newton-quadratic steps per iteration, k >= 1. Default 1. Below 1 raises ValueError; a value at or above 1 that is not an integer raises TypeError; above 100 is clamped to 100 with a RuntimeWarning. k = 2 is asymptotically the most efficient choice on a four times continuously differentiable f.

xtolfloat, optional

Absolute tolerance, default 2e-12. Must be positive; ValueError otherwise.

rtolfloat, optional

Relative tolerance, default 4 * eps = 8.88e-16. The FLOOR here is eps = 2.22e-16, a quarter of the other bracketing solvers’. Below it, ValueError.

maxiterint, optional

Iteration cap. Default 100. maxiter < 1 raises ValueError.

full_outputbool, optional

False (default) returns the root alone. True returns (x, RootResults). Inside @njit it must be a compile-time constant; see Notes.

dispbool, optional

True (default) raises RuntimeError when the iteration limit is reached. False returns converged=False instead.

Returns:
xfloat

The estimated root, when full_output is False.

(x, res)tuple of (float, RootResults)

When full_output is True. res fields are reached by attribute, by index or by unpacking.

rootfloat

Root estimate.

iterationsint

Iterations used.

function_callsint

Evaluations of f. Counts every one, including the ones a solver discards. For newton() with derivatives it also counts the derivative evaluations.

convergedbool

True if a tolerance test was met before maxiter.

flagstr

'converged', or 'convergence error'.

methodstr

The method that produced the result, by name.

Raises:
ValueError

If a >= b; if either bound is not finite; if f returns a non-finite value at any iterate; if f(a) and f(b) have the same sign; if xtol <= 0; if rtol is below eps; if maxiter < 1; or if k < 1.

TypeError

If k is at least 1 and is not an integer.

RuntimeError

If maxiter is reached, unless disp=False.

numba.core.errors.TypingError

From inside @njit, if full_output is a runtime variable.

Warns:
RuntimeWarning

If k > 100, which is clamped to 100.

See also

scipy.optimize.toms748

The scipy routine this mirrors.

scijit.optimize.brentq

Fewer operations per iteration.

scijit.optimize.root_scalar

The bracketing methods behind a method argument.

Notes

full_output selects the RETURN SHAPE, and a compiled function has one return type per signature, so inside @njit the flag has to be readable when the call compiles. A literal, an omitted default and a module-level constant all are; a variable is not, and raises TypingError naming the constraint. From Python a runtime value is fine.

The result is a namedtuple, where scipy’s is a dict subclass. See RootResults.

This solver validates more than the other four bracketing routines, because scipy’s does: a non-finite bound, a non-finite value from f at any iterate, and maxiter < 1 are all rejected here and are not by bisect, brentq, brenth or ridder. The messages carry the offending values, as scipy’s do.

Write an integer power as a product. numba compiles x ** 3 to repeated multiplication where CPython calls pow, so an objective spelled that way is not the same function in the two languages, and the iteration sequence can then part company: measured on lambda x: x ** 3 - x - 2.0 over [1, 2] at k=3, function_calls is 8 here and 9 in scipy, at the same iterations and the same root. Spelled x * x * x the same call agrees on all three.

Pure @njit, prange-safe.

Examples

>>> from numba import njit
>>> from scijit.optimize import toms748
>>> @njit
... def f(x):
...     return x * x - 2.0
>>> @njit
... def run():
...     return toms748(f, 0.0, 2.0)
>>> round(run(), 12)
1.414213562373
>>> @njit
... def run_full():
...     return toms748(f, 0.0, 2.0, full_output=True)
>>> x, res = run_full()
>>> round(x, 12), res.converged, res.method
(1.414213562373, True, 'toms748')