mir-optim
Optimization algorithms for D — nonlinear least-squares (Levenberg-Marquardt), L-BFGS, and trust-region methods. Works with ndslice, BetterC compatible.
📖 Full API reference → mir-optim.libmir.org — every module and symbol of
mir-optim, regenerated from current source.
mir-optim provides numerical optimization algorithms for D, focused on nonlinear least-squares problems common in data fitting, machine learning, and scientific computing.
GitHub: libmir/mir-optim · Last commit: May 2025
Install
dependency "mir-optim" version="~>2.0"
dependency "mir-algorithm" version="~>3.0"Nonlinear Least-Squares (Levenberg-Marquardt)
The primary use case: fit a model to data by minimizing the sum of squared residuals.
import mir.optim.least_squares;
import mir.ndslice;
// Fit y = a * exp(-b * x) to data points
void residuals(
Slice!(double*, 1) params, // [a, b]
Slice!(double*, 1) res, // output residuals
) @nogc nothrow {
double a = params[0], b = params[1];
foreach (i; 0 .. res.length)
res[i] = a * exp(-b * xdata[i]) - ydata[i];
}
auto result = levenbergMarquardt(
&residuals,
params0, // initial guess as ndslice
nResiduals,
);
if (result.success)
writeln("Fitted params: ", result.x);L-BFGS — general gradient-based optimization
For unconstrained minimization of smooth functions:
import mir.optim.lbfgs;
double objective(Slice!(double*, 1) x, Slice!(double*, 1) grad) @nogc nothrow {
// Rosenbrock function
double f = 0;
foreach (i; 0 .. x.length - 1) {
double t = x[i + 1] - x[i] * x[i];
f += 100 * t * t + (1 - x[i]) * (1 - x[i]);
grad[i] += -400 * x[i] * t - 2 * (1 - x[i]);
grad[i + 1] += 200 * t;
}
return f;
}
auto x0 = [-1.2, 1.0].sliced;
auto result = lbfgs(&objective, x0);Result types
mir-optim uses mir.algebraic.Variant for results:
auto r = levenbergMarquardt(...);
r.match!(
(LMSuccess s) => writeln("converged in ", s.iterations, " iters"),
(LMFailure f) => writeln("failed: ", f.reason),
);Jacobian — automatic vs manual
For least-squares, you can provide an analytical Jacobian for speed, or let mir-optim approximate it numerically:
// Numerical Jacobian (slower but easier)
auto result = levenbergMarquardt(&residuals, params0, nResiduals,
LMOptions(jacobiApproximation: true));
// Analytical Jacobian (faster)
void jacobian(
Slice!(double*, 1) params,
Slice!(double*, 2) J, // nResiduals × nParams
) @nogc nothrow { /* fill J */ }
auto result2 = levenbergMarquardt(&residuals, &jacobian, params0, nResiduals);Use cases
- Curve fitting (exponential, Gaussian, power law)
- Calibration of physical models
- Neural network training (small networks)
- Inverse kinematics
- Computer vision (bundle adjustment)
Related guides
mir-random
High-quality random number generation and statistical distributions for D. BetterC compatible, @nogc, with ndslice integration for filling arrays.
mir-ion
Fast ION binary and JSON serialization for D. Zero-copy parsing, automatic struct serialization via mir-core reflection, BetterC compatible read path.