fit method

  1. @override
LevenbergMarquardtResult fit({
  1. required Vector<double> xs,
  2. required Vector<double> ys,
  3. double weight = 1.0,
  4. Vector<double>? weights,
})
override

Fits a list of data points to the configured model.

Implementation

@override
LevenbergMarquardtResult fit({
  required Vector<double> xs,
  required Vector<double> ys,
  double weight = 1.0,
  Vector<double>? weights,
}) {
  checkPoints(DataType.float, xs: xs, ys: ys, min: 2);

  weights ??=
      Vector<double>.constant(DataType.float, ys.count, value: weight);
  if (weights.count != xs.count) {
    throw ArgumentError.value(
        weights, 'weights', 'Expected ${xs.count} values.');
  }
  final squaredWeights =
      weights.map((i, v) => v * v, DataType.float).toVector();

  var parameters = initialValues.toVector();
  var error = _errorCalculation(parametrizedFunction.bind(parameters),
      x: xs, y: ys, squaredWeights: squaredWeights);
  var optimalError = error;
  var optimalParameters = parameters.toVector();
  var converged = error <= errorTolerance;
  var currentDamping = damping;

  var iteration = 0;
  for (; iteration < maxIterations && !converged; iteration++) {
    var previousError = error;

    final stepResult = _step(
      x: xs,
      y: ys,
      params: parameters,
      currentDamping: currentDamping,
      squaredWeights: squaredWeights,
    );
    final perturbations = stepResult.first;
    final jacobianWeightResidualError = stepResult.second;

    for (var k = 0; k < parameters.count; k++) {
      parameters[k] = (parameters[k] - perturbations.get(k, 0))
          .clamp(minValues[k], maxValues[k]);
    }

    error = _errorCalculation(
      parametrizedFunction.bind(parameters),
      x: xs,
      y: ys,
      squaredWeights: squaredWeights,
    );
    if (error.isNaN) break;

    if (error < optimalError - errorTolerance) {
      optimalError = error;
      optimalParameters = parameters.toVector();
    }

    var improvementMetric = (previousError - error) /
        (perturbations.transposed *
                (perturbations * currentDamping +
                    jacobianWeightResidualError))
            .get(0, 0);

    if (improvementMetric > improvementThreshold) {
      currentDamping = max(currentDamping / dampingStepDown, 1e-7);
    } else {
      currentDamping = min(currentDamping * dampingStepUp, 1e7);
    }

    converged = error <= errorTolerance;
  }

  return LevenbergMarquardtResult(
    parametrizedFunction.bind(optimalParameters),
    parameters: parametrizedFunction.toBindings(optimalParameters),
    error: optimalError,
    iterations: iteration,
  );
}