lmStep method
Levenberg-Marquardt step
Implementation
List<double> lmStep(List<double> params, List<List<double>> jac) {
List<double> newParams;
List<double> allDelta = List(npars);
allDelta.fillRange(0, npars, 0.0);
// jac = jacobian(params);
//print("jsfit 4900=${jac.length} ${jac[0].length}");
List<List<double>> jacTrans = numeric.transpose(jac);
//print("jsfit 4901=${jacTrans.length} ${jacTrans[0].length}");
List<List<double>> jtj = numeric.dotMM(jacTrans, jac);
//print("jsfit 4902=${jtj.length} ${jtj[0].length}");
List<List<double>> diag = diagonal(jtj);
//print("jsfit 4903=${diag.length} ${diag[0].length}");
List<double> cost_gradient = numeric.dotMV(jacTrans, residuals(params));
//print("jsfit 4904=${cost_gradient.length}");
List<List<double>> g = numeric.addMM(jtj, numeric.dotCM(lambda, diag));
// List<int> gdim = numeric.dim(g);
//TODO: Q R fact orization? this just sets any zero elements in the
// diagonals to be small but non-zero ( /100 is arbitrary, BG)
for (int i = 0; i < g.length; i++) {
if (g[i][i].abs() < epsilon / 100) {
g[i][i] = epsilon;
}
}
//print("jsfit 5000=${cost_gradient.length} ${g.length} ${g[0].length}");
List<List<double>> inverse = numeric.invMatrix(g);
//print("jsfit 5001=$cost_gradient ${inverse.length} ${inverse[0].length}");
List<double> delta = numeric.dotMV(inverse, cost_gradient);
//print("jsfit 5002=${cost_gradient.length}");
// console.log(delta);
//Patch in the fixed parameters. . .
for (int i = 0; i < free.length; i++) {
if (free[i]) {
allDelta[i] = delta[i];
}
}
// delta = numeric.mul(delta, 1.0)
newParams = numeric.addVV(params, allDelta);
// console.log(params, newParams, allDelta)
return newParams;
}