UNPKG

ml-levenberg-marquardt

Version:
54 lines 2.6 kB
import checkOptions from "./check_options.js"; import errorCalculation from "./error_calculation.js"; import step from "./step.js"; /** * Curve fitting algorithm * @param data - Array of points to fit in the format [x1, x2, ... ], [y1, y2, ... ] * @param parameterizedFunction - Takes an array of parameters and returns a function with the independent variable as its sole argument * @param options - Options object */ export function levenbergMarquardt(data, parameterizedFunction, options) { const checkedOptions = checkOptions(data, options); const { checkTimeout, minValues, maxValues, parameters, weightSquare, dampingStepUp, dampingStepDown, maxIterations, errorTolerance, centralDifference, gradientDifference, improvementThreshold, } = checkedOptions; let damping = checkedOptions.damping; let error = errorCalculation(data, parameters, parameterizedFunction, weightSquare); let optimalError = error; let optimalParameters = parameters.slice(); let converged = error <= errorTolerance; let iteration = 0; for (; iteration < maxIterations && !converged; iteration++) { const previousError = error; const { perturbations, jacobianWeightResidualError } = step(data, parameters, damping, gradientDifference, parameterizedFunction, centralDifference, weightSquare); for (let k = 0; k < parameters.length; k++) { parameters[k] = Math.min(Math.max(minValues[k], parameters[k] - perturbations.get(k, 0)), maxValues[k]); } error = errorCalculation(data, parameters, parameterizedFunction, weightSquare); if (isNaN(error)) break; if (error < optimalError - errorTolerance) { optimalError = error; optimalParameters = parameters.slice(); } const improvementMetric = (previousError - error) / perturbations .transpose() .mmul(perturbations.mul(damping).add(jacobianWeightResidualError)) .get(0, 0); if (improvementMetric > improvementThreshold) { damping = Math.max(damping / dampingStepDown, 1e-7); } else { damping = Math.min(damping * dampingStepUp, 1e7); } if (checkTimeout()) { throw new Error(`The execution time is over to ${options.timeout} seconds`); } converged = error <= errorTolerance; } return { parameterValues: optimalParameters, parameterError: optimalError, iterations: iteration, }; } //# sourceMappingURL=levenberg_marquardt.js.map