least_squares
result = least_squares("f", x0, lower=, upper=, max_iter=200, tol=1e-10)
Input: "f", x0, lower, upper, max_iter, tol · Output: result
What it is
Nonlinear least squares on a residual function you named, via Levenberg-Marquardt. "f" is a Str naming an already-defined function that takes a length-p parameter Vec and returns a residual Vec; x0 is the length-p initial guess Vec. lower=/upper= are optional length-p Vecs of box bounds (enforced by clamping every trial point before it is evaluated, rather than by penalty); max_iter= (default 200) caps the iteration count, tol= (default 1e-10) sets the convergence tolerance.
Overloads
One call shape — this function is not overloaded.
| Code | Input | Output | Description |
result = least_squares("f", x0, lower=, upper=, max_iter=200, tol=1e-10) | "f" Str or Vec"f" is a Str naming an already-defined function that takes a length-p parameter Vec and returns a residual Vec.x0 Vecx0 is the length-p initial guess Vec.lower Veclower=/upper= are optional length-p Vecs of box bounds (enforced by clamping every trial point before it is evaluated, rather than by penalty).upper Veclower=/upper= are optional length-p Vecs of box bounds (enforced by clamping every trial point before it is evaluated, rather than by penalty).max_iter — (default 200)max_iter= (default 200) caps the iteration count, tol= (default 1e-10) sets the convergence tolerance.tol — (default 1e-10)max_iter= (default 200) caps the iteration count, tol= (default 1e-10) sets the convergence tolerance. | Model —kind "least_squares"params Veclength-p Vec, the fitted parametersresidual Vecthe residual at the solutioncost scalar or Numscalar Numiterations scalar or Numscalar Numconverged —Boolp_values —two-sided, Student t on dof = n - pci matrixa (p, 2) matrix at level=, default 0.95bootstrap=N —with seed= | Returns a Model (kind "least_squares") with fields params (length-p Vec, the fitted parameters), residual (Vec, the residual at the solution), cost (scalar Num), iterations (scalar Num), and converged (Bool). Every fit also carries its parameter uncertainty (*added in v0.4.4*): stderr, cov, correlation, t, p_values (two-sided, Student t on dof = n - p), ci (a (p, 2) matrix at level=, default 0.95), dof, rmse, sigma, and note -- which says when there are no degrees of freedom (the statistics are then NaN) or a parameter is not identifiable from the data (stderr = inf). These are linearized at the solution (cov = s^2 (J^T J)^+): exact for a model linear in its parameters with independent normal errors, an approximation otherwise. bootstrap=N (with seed=) refits N residual resamples and adds bootstrap_stderr/bootstrap_ci -- when the two disagree, distrust the linearization. method= picks the solver: "lm" (Levenberg-Marquardt, default), "gauss_newton" (with step halving) or "gradient_descent" (backtracking; slow, and says converged = false rather than pretending). summary(fit) prints the table. A parameter sitting on an active lower=/upper= bound is flagged in at_bound: its linearized stderr does not hold there. |
Examples
From the documentation, and run by the build -- the output and the figure below are what the engine actually produced. Simplest first.
bounded = least_squares("resid", [1.0, 1.0], lower = [0.0, 0.01])
print("bounded tau {bounded.params[1]:.4f}")
bounded tau 0.3502
from from-zero
tau = 0.35
decay = 2.5 * exp(0 - t / tau) + 0.02 * randn(1000, seed = 2)
function resid(p)
return p[0] * exp(0 - t / p[1]) - decay
end function
fit = least_squares("resid", [1.0, 1.0])
print("amplitude {fit.params[0]:.4f} (true 2.5)")
print("tau {fit.params[1]:.4f} (true {tau})")
amplitude 2.4990 (true 2.5) tau 0.3502 (true 0.35)
from from-zero
How it works
least_squares(f, x0, [lower=], [upper=], [max_iter=], [tol=]) — nonlinear least squares on a RESIDUAL function. f(p) returns the vector to be driven toward zero, not a scalar and not a model evaluated against data. That is the contract curve_fit does not have and the one every fit in this lab needs: a weighting, a Kramers-Kronig penalty or a regularization term is just more entries in the residual. lower=/upper= are box bounds, enforced by clamping every trial point into the box before it is evaluated -- a negative capacitance evaluated once can put NaN through the whole residual, so the bound has to hold at evaluation time, not just at the solution. method=, level=, bootstrap=, seed= and the uncertainty parameter on an active bound is flagged in at_bound, since its linearized stderr does not hold there.
From the note above this builtin in the interpreter, where the reasoning was written down as it was built.