calculate method
Implementation
@override
Point calculate(List<Beacon> beacons) {
_function.adjustParameters(beacons);
Vector initialGuess = _function.computeInitialGuess(beacons);
_jacobian = reshape(
_jacobian,
List.filled(
_function.numFunctions(), List.filled(initialGuess.length, 0)));
_initialCost = _calculateCost(initialGuess);
double previousCost = _initialCost;
double lambda = _initialLambda;
/// Recompute the Jacobian in this iteration or not
bool computeHessian = true;
Vector optimized = Vector.fromList(initialGuess.toList());
for (int i = 0; i < _maxIterations; i++) {
if (computeHessian) {
// Compute some variables based on the gradient
_computeGradientAndHessian(optimized);
computeHessian = false;
Matrix gTest =
_gradient.mapElements((element) => element.abs() > _gtol ? 1 : 0);
bool converged = gTest.sum() == 0;
if (converged) {
_finalCost = previousCost;
return Point.vector(optimized);
}
}
Matrix lambdaIdentity =
Matrix.diagonal(Vector.filled(_hessian.columnsNum, lambda).toList());
_hessian = _hessian + lambdaIdentity;
/// in some cases h can be a singular matrix, meaning its determinant equals 0
/// and the equation cannot be solved "conventionally"
/// Premature but usable return of [parameters]
try {
_negativeStep = Matrix.fromList(
matrixSolve(matrixToList(_hessian), matrixToList(_gradient)));
} catch (error) {
return Point.vector(optimized);
}
// compute the candidate parameters
Vector candidate = optimized - _negativeStep;
double cost = _calculateCost(candidate);
// if the candidate parameters produced better results, use them instead
if (cost <= previousCost) {
computeHessian = true;
optimized = Vector.fromList(candidate.toList());
// check for convergence
// ftol <= (cost(k) - cost(k+1))/cost(k)
bool converged = _ftol * previousCost >= previousCost - cost;
previousCost = cost;
lambda /= 10.0;
if (converged) {
_finalCost = previousCost;
Point.vector(optimized);
}
} else {
lambda *= 10.0;
}
}
_finalCost = previousCost;
return Point.vector(optimized);
}