package org.spaceroots.mantissa.fitting;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.spaceroots.mantissa.estimation.*;

/** This class is the base class for all curve fitting classes in the package.

 * 

This class handles all common features of curve fitting like the * sample points handling. It declares two methods ({@link * #valueAt} and {@link #partial}) which should be implemented by * sub-classes to define the precise shape of the curve they * represent.

* @version $Id: AbstractCurveFitter.java 1709 2006-12-03 21:16:50Z luc $ * @author L. Maisonobe */ public abstract class AbstractCurveFitter implements EstimationProblem, Serializable { /** Simple constructor. * @param n number of coefficients in the underlying function * @param estimator estimator to use for the fitting */ protected AbstractCurveFitter(int n, Estimator estimator) { coefficients = new EstimatedParameter[n]; measurements = new ArrayList(); this.estimator = estimator; } /** Simple constructor. * @param coefficients first estimate of the coefficients. A * reference to this array is hold by the newly created object. Its * elements will be adjusted during the fitting process and they will * be set to the adjusted coefficients at the end. * @param estimator estimator to use for the fitting */ protected AbstractCurveFitter(EstimatedParameter[] coefficients, Estimator estimator) { this.coefficients = coefficients; measurements = new ArrayList(); this.estimator = estimator; } /** Add a weighted (x,y) pair to the sample. * @param weight weight of this pair in the fit * @param x abscissa * @param y ordinate, we have y = f (x) */ public void addWeightedPair(double weight, double x, double y) { measurements.add(new FitMeasurement(weight, x, y)); } /** Perform the fitting. *

This method compute the coefficients of the curve that best * fit the sample of weighted pairs previously given through calls * to the {@link #addWeightedPair addWeightedPair} method.

* @return coefficients of the curve * @exception EstimationException if the fitting is not possible * (for example if the sample has to few independant points) */ public double[] fit() throws EstimationException { // perform the fit estimator.estimate(this); // extract the coefficients double[] fittedCoefficients = new double[coefficients.length]; for (int i = 0; i < coefficients.length; ++i) { fittedCoefficients[i] = coefficients[i].getEstimate(); } return fittedCoefficients; } public WeightedMeasurement[] getMeasurements() { return (WeightedMeasurement[]) measurements.toArray(new FitMeasurement[measurements.size()]); } /** Get the unbound parameters of the problem. * For a curve fitting, none of the function coefficient is bound. * @return unbound parameters */ public EstimatedParameter[] getUnboundParameters() { return (EstimatedParameter[]) coefficients.clone(); } /** Get all the parameters of the problem. * @return parameters */ public EstimatedParameter[] getAllParameters() { return (EstimatedParameter[]) coefficients.clone(); } /** Utility method to sort the measurements with respect to the abscissa. *

This method is provided as a utility for derived classes. As * an example, the {@link HarmonicFitter} class needs it in order to * compute a first guess of the coefficients to initialize the * estimation algorithm.

*/ protected void sortMeasurements() { // Since the samples are almost always already sorted, this // method is implemented as an insertion sort that reorders the // elements in place. Insertion sort is very efficient in this case. FitMeasurement curr = (FitMeasurement) measurements.get(0); for (int j = 1; j < measurements.size (); ++j) { FitMeasurement prec = curr; curr = (FitMeasurement) measurements.get(j); if (curr.x < prec.x) { // the current element should be inserted closer to the beginning int i = j - 1; FitMeasurement mI = (FitMeasurement) measurements.get(i); while ((i >= 0) && (curr.x < mI.x)) { measurements.set(i + 1, mI); if (i-- != 0) { mI = (FitMeasurement) measurements.get(i); } else { mI = null; } } measurements.set(i + 1, curr); curr = (FitMeasurement) measurements.get(j); } } } /** Get the value of the function at x according to the current parameters value. * @param x abscissa at which the theoretical value is requested * @return theoretical value at x */ public abstract double valueAt(double x); /** Get the derivative of the function at x with respect to parameter p. * @param x abscissa at which the partial derivative is requested * @param p parameter with respect to which the derivative is requested * @return partial derivative */ public abstract double partial(double x, EstimatedParameter p); /** This class represents the fit measurements. * One measurement is a weighted pair (x, y), where y = f * (x) is the value of the function at x abscissa. This class * is an inner class because the methods related to the computation * of f values and derivative are proveded by the fitter * implementations. */ public class FitMeasurement extends WeightedMeasurement { /** Simple constructor. * @param weight weight of the measurement in the fitting process * @param x abscissa of the measurement * @param y ordinate of the measurement */ public FitMeasurement(double weight, double x, double y) { super(weight, y); this.x = x; } /** Get the value of the fitted function at x. * @return theoretical value at the measurement abscissa */ public double getTheoreticalValue() { return valueAt(x); } /** Partial derivative with respect to one function coefficient. * @param p parameter with respect to which the derivative is requested * @return partial derivative */ public double getPartial(EstimatedParameter p) { return partial(x, p); } /** Abscissa of the measurement. */ public final double x; private static final long serialVersionUID = -2682582852369995960L; } /** Coefficients of the function */ protected EstimatedParameter[] coefficients; /** Measurements vector */ protected List measurements; /** Estimator for the fitting problem. */ private Estimator estimator; }

Ads help maintain this website.