package gdsc.smlm.fitting.nonlinear; import gdsc.core.utils.Maths; import gdsc.smlm.fitting.FunctionSolverType; import gdsc.smlm.fitting.LSEFunctionSolver; import gdsc.smlm.function.GradientFunction; /*----------------------------------------------------------------------------- * GDSC SMLM Software * * Copyright (C) 2017 Alex Herbert * Genome Damage and Stability Centre * University of Sussex, UK * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. *---------------------------------------------------------------------------*/ /** * Abstract class with utility methods for the LSEFunctionSolver interface. */ public abstract class LSEBaseFunctionSolver extends BaseFunctionSolver implements LSEFunctionSolver { protected double totalSumOfSquares = Double.NaN; /** * Default constructor * * @throws NullPointerException * if the function is null */ public LSEBaseFunctionSolver(GradientFunction f) { super(FunctionSolverType.LSE, f); } @Override protected void preProcess() { totalSumOfSquares = Double.NaN; } /** * Gets the total sum of squares. * * @param y * the y * @return the total sum of squares */ public static double getTotalSumOfSquares(double[] y) { double sx = 0, ssx = 0; for (int i = y.length; i-- > 0;) { sx += y[i]; ssx += y[i] * y[i]; } final double sumOfSquares = ssx - (sx * sx) / (y.length); return sumOfSquares; } /** * Compute the error * * @param value * @param noise * @param numberOfFittedPoints * @param numberOfFittedParameters * @return the error */ public static double getError(double value, double noise, int numberOfFittedPoints, int numberOfFittedParameters) { double error = value; // Divide by the uncertainty in the individual measurements yi to get the chi-squared if (noise > 0) { error /= numberOfFittedPoints * noise * noise; } // This updates the chi-squared value to the average error for a single fitted // point using the degrees of freedom (N-M)? // Note: This matches the mean squared error output from the MatLab fitting code. // If a noise estimate was provided for individual measurements then this will be the // reduced chi-square (see http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2892436/) if (numberOfFittedPoints > numberOfFittedParameters) error /= (numberOfFittedPoints - numberOfFittedParameters); else error = 0; return error; } /** * Update the total and residual sum-of-squares using the given data. * * @param y * The data * @param residuals * The fit residuals */ public void updateSumOfSquares(double[] y, double[] residuals) { totalSumOfSquares = getTotalSumOfSquares(y); value = 0; for (int i = y.length; i-- > 0;) { value += residuals[i] * residuals[i]; } } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.LSEFunctionSolver#getTotalSumOfSquares() */ public double getTotalSumOfSquares() { if (Double.isNaN(totalSumOfSquares) && lastY != null) { totalSumOfSquares = getTotalSumOfSquares(lastY); } return totalSumOfSquares; } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.LSEFunctionSolver#getResidualSumOfSquares() */ public double getResidualSumOfSquares() { return value; } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.LSEFunctionSolver#getCoefficientOfDetermination() */ public double getCoefficientOfDetermination() { return 1.0 - (value / totalSumOfSquares); } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.LSEFunctionSolver#getAdjustedCoefficientOfDetermination() */ public double getAdjustedCoefficientOfDetermination() { return Maths.getAdjustedCoefficientOfDetermination(value, totalSumOfSquares, getNumberOfFittedPoints(), getNumberOfFittedParameters()); } /* * (non-Javadoc) * * @see gdsc.smlm.fitting.LSEFunctionSolver#getMeanSquaredError() */ public double getMeanSquaredError() { return value / (getNumberOfFittedPoints() - getNumberOfFittedParameters()); } }