Curve fitting
The Nautilus.CurveFit module provides a single export:
lm_scalar_1param, a Levenberg-Marquardt optimizer for single-parameter
curve fitting.
lm_scalar_1param
Section titled “lm_scalar_1param”Signature:
lm_scalar_1param( model: f32 -> f32 -> f32, // model(x, theta) -> predicted y dmodel: f32 -> f32 -> f32, // dmodel(x, theta) -> d(predicted_y)/d(theta) xs: tensor[n, f32], // input data points ys: tensor[n, f32], // observed y-values theta0: f32, // initial parameter guess lambda0: f32, // initial damping factor tol: f32, // convergence tolerance on |delta_theta| max_iters: int64 // iteration cap) -> f32 // fitted thetaThe optimizer iterates the damped Gauss-Newton update:
theta_next = theta + (J^T J * (1 + lambda))^{-1} * J^T rwhere J is the Jacobian (here a scalar dmodel(x, theta) per data point)
and r is the residual vector y - model(x, theta). Convergence is
declared when |theta_next - theta| < tol. Returns NaN for empty data.
Example: fitting a linear model
Section titled “Example: fitting a linear model”import Nautilus.CurveFit (lm_scalar_1param)
def linear_model(x: f32, theta: f32) -> f32 = mul(theta, x)def linear_dmodel(x: f32, theta: f32) -> f32 = x
def fit_slope[n](xs: tensor[n, f32], ys: tensor[n, f32]) -> f32 = lm_scalar_1param( linear_model, linear_dmodel, xs, ys, cast(0.0, f32), // initial guess cast(0.01, f32), // damping cast(1.0e-8, f32), // tolerance cast(100, int64) // max iterations )For a dataset generated by y = 2*x + noise, this converges to
approximately 2.0.
Limitations
Section titled “Limitations”- Single parameter only. Multi-parameter Levenberg-Marquardt (using
inv_2x2/inv_3x3for the normal equations) is structurally possible but not yet exported. - The caller must supply the analytical derivative
dmodel. There is no automatic differentiation fallback in this function. - The damping factor
lambda0is held constant (no adaptive lambda scheduling as in full LM implementations).