scijit.optimize.bisect

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

Bisection root-finder.

Callback style A: f is a plain @njit function taking one float and returning one float. No @cfunc, no .address, and with an args tuple beside it:

@njit
def f(x):
    return x * x - 2.0

root = bisect(f, 0.0, 2.0)
root, res = bisect(f, 0.0, 2.0, full_output=True)
Parameters:
f@njit function f(x) -> float

Continuous function whose root is wanted.

a, bfloat

Bracket endpoints. 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 with iterations = 0.

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 ().

xtolfloat, optional

Absolute tolerance on the bracket width. Default 2e-12. Must be positive; ValueError otherwise.

rtolfloat, optional

Relative tolerance; convergence when |dm| < xtol + rtol * |x|. Default 4 * eps = 8.88e-16, which is also its floor. A smaller value raises ValueError.

maxiterint, optional

Iteration cap. Default 100. Negative 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, with root set to the left endpoint of the surviving bracket.

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

Best estimate of the root.

iterationsint

Iterations used.

function_callsint

Evaluations of f. Counts every one, including the ones a solver discards.

convergedbool

True if a tolerance test was met before maxiter. Only ever False under disp=False.

flagstr

'converged', or 'convergence error'.

methodstr

The method that produced the result, by name.

Raises:
ValueError

If f(a) and f(b) have the same sign, so the interval is not known to bracket a root; if a or b is infinite and the sign test passes; if f returns NaN at any iterate; if xtol <= 0; if rtol is below 4 * eps; or if maxiter < 0.

RuntimeError

If maxiter is reached, unless disp=False.

numba.core.errors.TypingError

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

See also

scipy.optimize.bisect

The scipy routine this mirrors.

scijit.optimize.brentq

Faster on a well-behaved function; the usual choice.

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.

iterations is 0 when a or b is an exact root. scipy’s C returns before assigning that field and reports an indeterminate value read from uninitialised memory.

An infinite a or b that passes the sign test raises ValueError. scipy has no such check and runs to maxiter: measured on scipy 1.18, bisect(f, 0.0, inf) on x * x - 2 reports RuntimeError: Failed to converge after 100 iterations. An infinite endpoint that fails the sign test, is an exact root, or at which f returns NaN reaches the same outcome here as in scipy.

Bisection uses only the SIGN of f, so no derivative or curvature estimate can mislead it, and the bracket halves every step: at most log2((b - a) / xtol) iterations. It is the slowest of the bracketing methods; prefer brentq() unless f is badly behaved.

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.bisect.html

Examples

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