scijit.optimize.leastsq

scijit.optimize.leastsq(func, x0, args=(), Dfun=None, full_output=False, col_deriv=False, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=None, factor=100.0, diag=None, m=-1, validate=True)

Minimize the sum of squares of a set of residuals.

Wraps MINPACK’s lmdif, Levenberg-Marquardt with a forward-difference Jacobian, or lmder 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). The residual count is read from what it returns.

x0float or array_like

Initial parameter guess. A scalar, list or tuple is accepted. Any rank is FLATTENED.

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

Dfuncallable or None, optional

None (default) uses a forward-difference Jacobian (MINPACK lmdif). A plain @njit jac(x) -> (m, n) selects the analytic path (lmder); the iflag branch and MINPACK’s column-major layout are handled internally. Its shape must be (m, n), or (n, m) with col_deriv=True.

full_outputbool, optional

False (default) returns (x, ier). True returns (x, cov_x, infodict, mesg, ier). Must be a compile-time constant inside @njit: a literal, or left at its default.

col_derivbool, optional

A statement about Dfun, selecting a shape. False (default) reads jac(x) as (m, n); True reads it as (n, m). Ignored without Dfun. A runtime variable is fine.

ftolfloat, optional

Relative error desired in the sum of squares. Default 1.49012e-8.

xtolfloat, optional

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

gtolfloat, optional

Orthogonality desired between the residual vector and the Jacobian columns. Default 0.0.

maxfevint, optional

Maximum callback evaluations. 0 (default) means 200*(n+1), or 100*(n+1) when Dfun is given.

epsfcnfloat or None, optional

Forward-difference step. None (default) resolves to machine epsilon. Ignored on the Dfun path.

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 (mode = 1); a value selects mode = 2.

mint, optional

Number of residuals. -1 (default) reads it from the callback by calling it once. A value skips that call.

validatebool, optional

True (default) raises when the returned solution is degenerate. False reports the same conditions through ier instead. The separate check that the callback wrote fvec at all is always on.

Returns:
xndarray, shape (n,)

The solution, 1-D.

cov_xndarray of shape (n, n), or None

Only with full_output=True. (J^T J)^-1, NOT scaled by the residual variance. None when ier is outside {1, 2, 3, 4} or the triangular factor is singular.

infodictLsqInfo or LsqInfoJ

Only with full_output=True. Namedtuple with fields fvec, nfev, fjac, ipvt and qtf, plus njev after nfev on the Dfun path, reached as attributes. fjac has shape (n, m) and ipvt is 0-based.

mesgstr

Only with full_output=True. The message matching ier.

ierint

MINPACK’s status. 1 to 4 are the success set; 5 maxfev reached, 6 ftol too small, 7 xtol too small, 8 gtol too small. -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.

Raises:
TypeError

If MINPACK reports ier = 0, or if n exceeds m. Also if Dfun returns an array of the wrong shape, or if diag has fewer entries than x0.

ValueError

If func or Dfun is not a plain @njit function; if an args entry is neither a real number nor an array of real numbers; or, under validate=True, if the returned solution is degenerate.

See also

scipy.optimize.leastsq

The scipy routine this mirrors.

scijit.optimize.curve_fit

Fit a model to data, built on this.

scijit.optimize.root

method='lm' reaches the same driver.

scijit.optimize.lsq_linear

Bounded LINEAR least squares.

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 the evaluation this package makes before the solver runs to check that the callback writes fvec, and MINPACK’s own count. The call that reads the residual count off the callback, the calls the degenerate-solution check makes when the final residual is all zero, and the call Dfun costs for its shape check are not counted, so nfev is lower than the number of times the callback ran by between one and n + 2.

cov_x is None in the two cases scipy returns None. Its type is Optional(float64[:, :]), which numba unwraps with a runtime check: code that indexes it keeps working wherever the covariance exists, and gets a TypeError naming the array type where it does not.

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.

ier = 0 raises TypeError('Improper input parameters.'), scipy’s class and scipy’s text.

args=None raises. scipy reads it as the one-item tuple (None,) and calls f(x, None), and None is not a real number.

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.

cov_x is built by inverting the QR factor with a transcription of LAPACK dtrti2. Measured against scipy.linalg.lapack.dtrtri 2026-08-10, five random well-conditioned upper-triangular matrices at each of fourteen sizes: bit identical for n <= 16, worst RELATIVE difference 9.766e-13 at n = 32 and 6.194e-11 at n = 200, because the installed dtrtri blocks from n = 32.

validate has no scipy counterpart; its default reports a degenerate solution that scipy would return silently.

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

Examples

Fit a straight line to noisy measurements by minimizing its residuals. The data arrays are built once and reach the residual through args, so no array is rebuilt on an evaluation:

>>> import numpy as np
>>> from numba import njit
>>> from scijit.optimize import leastsq
>>> T = np.linspace(0.0, 4.0, 20)
>>> rng = np.random.default_rng(1)
>>> Y = 2.0 * T + 1.0 + rng.normal(0.0, 0.1, T.size)   # noisy line
>>> @njit
... def resid(p, t, y):
...     return y - (p[0] * t + p[1])
>>> @njit
... def run():
...     return leastsq(resid, np.array([0.0, 0.0]), args=(T, Y))
>>> p, ier = run()
>>> np.round(p, 3)
array([1.984, 1.037])
>>> ier in (1, 2, 3, 4)
True