/*
* Copyright (c) 2012 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.analysis.fitting;
import org.eclipse.dawnsci.analysis.api.fitting.functions.IFunction;
import org.eclipse.january.dataset.Dataset;
import org.eclipse.january.dataset.IDataset;
import uk.ac.diamond.scisoft.analysis.fitting.functions.AFunction;
import uk.ac.diamond.scisoft.analysis.fitting.functions.CompositeFunction;
import uk.ac.diamond.scisoft.analysis.fitting.functions.Gaussian;
import uk.ac.diamond.scisoft.analysis.fitting.functions.Offset;
import uk.ac.diamond.scisoft.analysis.fitting.functions.Polynomial;
import uk.ac.diamond.scisoft.analysis.optimize.ApacheOptimizer;
import uk.ac.diamond.scisoft.analysis.optimize.ApacheOptimizer.Optimizer;
import uk.ac.diamond.scisoft.analysis.optimize.ApachePolynomial;
import uk.ac.diamond.scisoft.analysis.optimize.GeneticAlg;
import uk.ac.diamond.scisoft.analysis.optimize.GradientDescent;
import uk.ac.diamond.scisoft.analysis.optimize.IOptimizer;
import uk.ac.diamond.scisoft.analysis.optimize.LeastSquares;
import uk.ac.diamond.scisoft.analysis.optimize.NelderMead;
public class Fitter {
private static final double simplexQuality = 1e-6;
public static double quality = 1e-4;
public static Long seed = null;
public static void simplexFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
simplexFit(simplexQuality, coords, yAxis, function);
}
public static void simplexFit(final double quality, final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new NelderMead(quality).optimize(coords, yAxis, function);
}
/**
* Run the Apache Nelder mead fitter
* @param coords
* @param yAxis
* @param function
* @throws Exception
*/
public static void ApacheNelderMeadFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new ApacheOptimizer(Optimizer.SIMPLEX_NM).optimize(coords, yAxis, function);
}
public static void ApacheMultiDirectionFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new ApacheOptimizer(Optimizer.SIMPLEX_MD).optimize(coords, yAxis, function);
}
public static void ApacheConjugateGradientFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new ApacheOptimizer(Optimizer.CONJUGATE_GRADIENT).optimize(coords, yAxis, function);
}
public static void GDFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
GDFit(quality, coords, yAxis, function);
}
public static void GDFit(final double quality, final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new GradientDescent(quality).optimize(coords, yAxis, function);
}
/**
* Genetic algorithm fitter
* @param coords
* @param yAxis
* @param function
* @throws Exception
*/
public static void geneticFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
geneticFit(quality, coords, yAxis, function);
}
/**
* Genetic algorithm fitter
* @param quality
* @param coords
* @param yAxis
* @param function
* @throws Exception
*/
public static void geneticFit(final double quality, final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new GeneticAlg(quality, seed).optimize(coords, yAxis, function);
}
/**
* Linear least squares fitter
* @param coords
* @param yAxis
* @param function
* @throws Exception
*/
public static void llsqFit(final Dataset[] coords, final Dataset yAxis, final IFunction function) throws Exception {
new LeastSquares(0).optimize(coords, yAxis, function);
}
/**
* Polynomial fitter
* @param coords
* @param yAxis
* @param rcond relative condition number used to limit singular values to use (try 1e-15)
* @param degree of polynomial
*/
public static Polynomial polyFit(final Dataset[] coords, final Dataset yAxis, final double rcond, final int degree) {
Polynomial polynomial = new Polynomial(degree);
polyFit(coords, yAxis, rcond, polynomial);
return polynomial;
}
/**
* Polynomial fitter
* @param coords
* @param yAxis
* @param rcond relative condition number used to limit singular values to use (try 1e-15)
* @param polynomial
*/
public static void polyFit(final Dataset[] coords, final Dataset yAxis, @SuppressWarnings("unused") final double rcond, final Polynomial polynomial) {
//determine polynomial order from number of parameters in polynomial
int polyOrder = polynomial.getNoOfParameters()-1;
double[] values = ApachePolynomial.polynomialFit(coords[0], yAxis, polyOrder);
//the polynomial object expects the coefficient array to be in the reverse order to the Apache answer
double[] flipped = values.clone();
for (int i = 0; i < flipped.length; i++)
flipped[flipped.length-1-i] = values[i];
polynomial.setParameterValues(flipped);
}
/**
* This function takes a pair of datasets and some other inputs, and then
* fits the function specified using the method specified.
*
* @param xAxis
* The dataset containing all the x values of the data
* @param yAxis
* The dataset containing all the y values of the data
* @param optimizer
* The optimiser which implements IOptimizer, which is to be used
* @param functions
* A list of functions which inherit from AFunction which are
* used to make up the function to be fit.
* @throws Exception
*/
public static CompositeFunction fit(IDataset xAxis, IDataset yAxis,
IOptimizer optimizer, IFunction... functions) throws Exception {
CompositeFunction comp = new CompositeFunction();
IDataset[] coords = new IDataset[] {xAxis};
for (int i = 0; i < functions.length; i++) {
comp.addFunction(functions[i]);
}
// call the optimisation routine
optimizer.optimize(coords, yAxis, comp);
return comp;
}
public static AFunction GaussianFit(Dataset data, Dataset axis) {
Gaussian gauss = new Gaussian(axis.min().doubleValue(),
axis.max().doubleValue(),
axis.peakToPeak().doubleValue(),
Math.abs(axis.peakToPeak().doubleValue() * data.peakToPeak().doubleValue()));
Offset offset = new Offset(data.min().doubleValue(), data.max().doubleValue());
CompositeFunction comp = new CompositeFunction();
comp.addFunction(gauss);
comp.addFunction(offset);
try {
geneticFit(new Dataset[] {axis}, data, comp);
} catch (Exception e) {
}
return comp;
}
public static NDGaussianFitResult NDGaussianSimpleFit(Dataset data, Dataset... axis) {
if (data.getRank() != axis.length) {
//TODO make this better
throw new IllegalArgumentException("Incorrect number of Axis");
}
int dims = axis.length;
// first resolve the problem into n 1D problems
AFunction[] results = new AFunction[dims];
for (int i = 0; i < dims; i++) {
Dataset flattened = data;
for (int j = 0; j < dims-1; j++) {
if (j < i) {
flattened = flattened.sum(0);
} else {
flattened = flattened.sum(1);
}
}
results[i] = GaussianFit(flattened, axis[i]);
}
return new NDGaussianFitResult(results);
}
}