scijit.optimize.fsolve

scijit.optimize.fsolve(func, x0, args=(), fprime=None, full_output=False, col_deriv=0, xtol=1.49012e-08, maxfev=0, band=None, epsfcn=None, factor=100.0, diag=None, mode=-1, validate=True, keep_shape=False)

Find the roots of a system of nonlinear equations.

Wraps MINPACK’s hybrd, a modified Powell hybrid method, or hybrj when an analytic Jacobian is supplied.

Callable from Python and from inside @njit.

Parameters:
funccallable

A plain @njit f(x) -> residuals or f(x, args) -> residuals. The arity is detected, so the args form is used only when args is passed. The residual count must equal x0.size.

x0float or array_like

Initial guess. A scalar, list or tuple is accepted. Any rank is FLATTENED, so an (n, m) guess is one system of n*m variables rather than a batch.

argstuple, optional

Extra parameters, passed to the callback as f(x, *args), one per entry. Entries may be scalars or arrays and need not share a type. A non-tuple args is coerced to the ONE argument (args,).

fprimecallable or None, optional

None (default) uses a forward-difference Jacobian. A plain @njit jac(x) -> (n, n) selects the analytic path, with the iflag branch and MINPACK’s column-major layout handled internally.

full_outputbool, optional

False (default) returns x alone. True returns the 4-tuple. Compile-time constant inside @njit: a literal, or left at its default.

col_derivint, optional

A statement about fprime. 0 (default) reads jac(x) as J[i, j] = dF_i/dx_j; a nonzero value reads it as already transposed. Ignored without fprime. A runtime variable is fine.

xtolfloat, optional

Relative error desired in the solution. Default 1.49012e-8.

maxfevint, optional

Maximum callback evaluations. 0 (default) means 200*(n+1), or 100*(n+1) with fprime.

bandtuple of int or None, optional

(ml, mu), the sub- and super-diagonal counts of a banded Jacobian. None (default) treats it as dense.

epsfcnfloat or None, optional

Forward-difference step. None (default) resolves to machine epsilon.

factorfloat, optional

Initial step bound, in (0.1, 100). Default 100.

diagsequence or None, optional

Per-variable scale factors, all positive. An array, list or tuple. The first x0.size entries are used and any others ignored. None (default) lets MINPACK derive them from the Jacobian column norms.

modeint, optional

Scaling mode. 1 scales internally, 2 uses diag unchanged. -1 (default) resolves to 1 when diag is None and 2 otherwise. A runtime variable is fine: it does not change the return type.

validatebool, optional

True (default) raises when the returned solution is degenerate, and probes whether the callback reads past the end of args. False reports the degenerate conditions through ier instead and skips the read probe. The check that the callback wrote fvec, and the residual-count and Jacobian-shape checks, are always on. With full_output=False a validate=False failure is invisible, so pair the two.

keep_shapebool, optional

False (default) returns x 1-D. True reshapes it back to x0’s rank, which reads better for a field on a grid. Affects x only. Compile-time constant.

Returns:
xndarray

The solution, 1-D unless keep_shape=True.

infodictInfoDict or InfoDictJ

Only with full_output=True. Namedtuple with fields nfev, fjac, r, qtf and fvec, plus njev after nfev on the fprime path, reached as attributes or by name. All but nfev are meaningful only when ier == 1.

ierint

MINPACK’s status: 0 the arguments were rejected and the solver never ran, reachable only here since a bare call raises on it; 1 converged, 2 maxfev reached, 3 xtol too small, 4 and 5 not making progress. -1 and -2 are this package’s degenerate-solution codes, reachable only under validate=False: -1 the residual is identically zero, -2 the reported residual disagrees with a fresh evaluation at x.

mesgstr

The message matching ier.

Raises:
TypeError

If MINPACK reports ier = 0, meaning it rejected the arguments and never ran, so x would come back as x0. Raised only on a bare call: with full_output=True the status is returned as ier = 0 instead. Also if the residual count disagrees with x0.size, if fprime returns something other than an (n, n) array, or if diag has fewer entries than x0.

ValueError

If func or fprime is not a plain @njit function; if an args entry is neither a real number nor an array of real numbers; if the callback never wrote fvec; or, under validate=True, if the returned solution is degenerate or the callback read past the end of args.

See also

scipy.optimize.fsolve

The scipy routine this mirrors.

scijit.optimize.root

The same solvers behind a method argument.

scijit.optimize.leastsq

Least squares rather than a square system.

Notes

infodict is a namedtuple rather than a dict. info['nfev'], info.get('nfev'), info.keys(), info.values(), info.items() and 'nfev' in info all work, from Python and from inside @njit, and its field order is scipy’s key insertion order, so positional unpacking agrees too. Iterating it yields VALUES, where iterating a dict yields keys.

nfev counts every evaluation of func, including the ones this package makes before the solver runs: one to read the residual count off the callback, one to check that the callback writes fvec, and two more under validate=True for the read probe. scipy counts two of its own, so nfev is two higher than scipy’s on the forward-difference path at validate=True and equal to it on the other three. The evaluation fprime costs for its shape check is not counted, and scipy does not count its own either.

Each args entry must be a real number or an array of real numbers. A mixed tuple is served: (matrix, scale) reaches the callback as two separate parameters and returns [3., 3.] on the residual x - matrix.diagonal() * scale, which is what scipy returns on the same call. An entry of any other type raises, and args=None is one: scipy reads it as the one-item tuple (None,) and calls f(x, None).

Whether the callback reads past the end of args is recovered by probing it under validate=True. An overrun larger than 8 slots still escapes that probe.

A diag with fewer entries than x0 raises before the solver runs. scipy reads past the end of the array instead, and what MINPACK then does depends on the values that happen to follow it.

mode, validate and keep_shape have no scipy counterpart. Their defaults reproduce scipy: mode derives from diag exactly as scipy derives it, and keep_shape=False returns the flat x scipy returns.

Safe to call from a numba.prange loop. MINPACK reaches the callback through a Fortran module variable, which carries !$omp threadprivate and so resolves to one slot per thread.

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

Examples

>>> import numpy as np
>>> from numba import njit
>>> from scijit.optimize import fsolve
>>> @njit
... def f(x):
...     return np.array([x[0] + 0.5 * (x[0] - x[1]) ** 3 - 1.0,
...                      0.5 * (x[1] - x[0]) ** 3 + x[1]])
>>> @njit
... def run():
...     return fsolve(f, np.array([0.0, 0.0]))
>>> run()
array([0.8411639, 0.1588361])

Parameters reach the callback through args, splatted as func(x, *args):

>>> @njit
... def fa(x, c):
...     return np.array([x[0] ** 2 - c])
>>> @njit
... def run_args():
...     return fsolve(fa, np.array([1.0]), (2.0,))
>>> run_args()
array([1.41421356])

With full_output, which must be a literal inside @njit:

>>> @njit
... def run_full():
...     return fsolve(f, np.array([0.0, 0.0]), full_output=True)
>>> x, infodict, ier, mesg = run_full()
>>> ier, infodict.nfev
(1, 16)
>>> mesg
'The solution converged.'