Author: erans Date: Sun Jun 10 15:12:57 2012 New Revision: 1348613 URL: http://svn.apache.org/viewvc?rev=1348613&view=rev Log: MATH-804 Parameterized "CurveFitter" with the type of the fitting function. Updated subclasses "PolynomialFitter", "HarmonicFitter", "GaussianFitter" accordingly.
Modified: commons/proper/math/trunk/src/changes/changes.xml commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/CurveFitter.java commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/GaussianFitter.java commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/PolynomialFitter.java commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/PolynomialFitterTest.java Modified: commons/proper/math/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/changes/changes.xml?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/changes/changes.xml (original) +++ commons/proper/math/trunk/src/changes/changes.xml Sun Jun 10 15:12:57 2012 @@ -52,6 +52,11 @@ If the output is not quite correct, chec <body> <release version="3.1" date="TBD" description=" "> + <action dev="erans" type="fix" issue="MATH-804"> + Parameterized "CurveFitter" class (package "o.a.c.m.optimization.fitting") + with the type of the fitting function. Updated subclasses "PolynomialFitter", + "HarmonicFitter", "GaussianFitter". + </action> <action dev="luc" type="fix" issue="MATH-801"> Fixed a problem when building rotations from two pairs of vectors. In very rare cases, due to numerical inaccuracies the computed quaternion was not normalized (some examples Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/CurveFitter.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/CurveFitter.java?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/CurveFitter.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/CurveFitter.java Sun Jun 10 15:12:57 2012 @@ -27,7 +27,8 @@ import org.apache.commons.math3.optimiza import org.apache.commons.math3.optimization.PointVectorValuePair; /** Fitter for parametric univariate real functions y = f(x). - * <p>When a univariate real function y = f(x) does depend on some + * <br/> + * When a univariate real function y = f(x) does depend on some * unknown parameters p<sub>0</sub>, p<sub>1</sub> ... p<sub>n-1</sub>, * this class can be used to find these parameters. It does this * by <em>fitting</em> the curve so it remains very close to a set of @@ -35,11 +36,14 @@ import org.apache.commons.math3.optimiza * y<sub>1</sub>) ... (x<sub>k-1</sub>, y<sub>k-1</sub>). This fitting * is done by finding the parameters values that minimizes the objective * function ∑(y<sub>i</sub>-f(x<sub>i</sub>))<sup>2</sup>. This is - * really a least squares problem.</p> + * really a least squares problem. + * + * @param <T> Function to use for the fit. + * * @version $Id$ * @since 2.0 */ -public class CurveFitter { +public class CurveFitter<T extends ParametricUnivariateFunction> { /** Optimizer to use for the fitting. */ private final DifferentiableMultivariateVectorOptimizer optimizer; /** Observed points. */ @@ -120,7 +124,7 @@ public class CurveFitter { * @throws org.apache.commons.math3.exception.DimensionMismatchException * if the start point dimension is wrong. */ - public double[] fit(final ParametricUnivariateFunction f, final double[] initialGuess) { + public double[] fit(T f, final double[] initialGuess) { return fit(Integer.MAX_VALUE, f, initialGuess); } @@ -141,7 +145,7 @@ public class CurveFitter { * if the start point dimension is wrong. * @since 3.0 */ - public double[] fit(int maxEval, final ParametricUnivariateFunction f, + public double[] fit(int maxEval, T f, final double[] initialGuess) { // prepare least squares problem double[] target = new double[observations.size()]; Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/GaussianFitter.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/GaussianFitter.java?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/GaussianFitter.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/GaussianFitter.java Sun Jun 10 15:12:57 2012 @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.Comparator; import org.apache.commons.math3.analysis.function.Gaussian; -import org.apache.commons.math3.analysis.ParametricUnivariateFunction; import org.apache.commons.math3.exception.NullArgumentException; import org.apache.commons.math3.exception.NumberIsTooSmallException; import org.apache.commons.math3.exception.OutOfRangeException; @@ -58,7 +57,7 @@ import org.apache.commons.math3.optimiza * @since 2.2 * @version $Id$ */ -public class GaussianFitter extends CurveFitter { +public class GaussianFitter extends CurveFitter<Gaussian.Parametric> { /** * Constructs an instance using the specified optimizer. * @@ -82,13 +81,11 @@ public class GaussianFitter extends Curv * @since 3.0 */ public double[] fit(double[] initialGuess) { - final ParametricUnivariateFunction f = new ParametricUnivariateFunction() { - private final ParametricUnivariateFunction g = new Gaussian.Parametric(); - + final Gaussian.Parametric f = new Gaussian.Parametric() { public double value(double x, double ... p) { double v = Double.POSITIVE_INFINITY; try { - v = g.value(x, p); + v = super.value(x, p); } catch (NotStrictlyPositiveException e) { // Do nothing. } @@ -100,7 +97,7 @@ public class GaussianFitter extends Curv Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY }; try { - v = g.gradient(x, p); + v = super.gradient(x, p); } catch (NotStrictlyPositiveException e) { // Do nothing. } Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java Sun Jun 10 15:12:57 2012 @@ -36,7 +36,7 @@ import org.apache.commons.math3.util.Fas * @version $Id$ * @since 2.0 */ -public class HarmonicFitter extends CurveFitter { +public class HarmonicFitter extends CurveFitter<HarmonicOscillator.Parametric> { /** * Simple constructor. * @param optimizer Optimizer to use for the fitting. Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/PolynomialFitter.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/PolynomialFitter.java?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/PolynomialFitter.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/PolynomialFitter.java Sun Jun 10 15:12:57 2012 @@ -20,22 +20,18 @@ package org.apache.commons.math3.optimiz import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; import org.apache.commons.math3.optimization.DifferentiableMultivariateVectorOptimizer; -/** This class implements a curve fitting specialized for polynomials. - * <p>Polynomial fitting is a very simple case of curve fitting. The - * estimated coefficients are the polynomial coefficients. They are - * searched by a least square estimator.</p> +/** + * Polynomial fitting is a very simple case of {@link CurveFitter curve fitting}. + * The estimated coefficients are the polynomial coefficients (see the + * {@link #fit(double[]) fit} method). + * * @version $Id$ * @since 2.0 - * - * @deprecated Since 3.1 (to be removed in 4.0, see <a href="https://issues.apache.org/jira/browse/MATH-800">MATH-800</a>). - * Please use {@link CurveFitter} directly, by passing an instance of - * {@link org.apache.commons.math3.analysis.polynomials.PolynomialFunction.Parametric PolynomialFunction.Parametric} - * as an argument to the - * {@link CurveFitter#fit(int,org.apache.commons.math3.analysis.ParametricUnivariateFunction,double[]) fit} - * method. */ -public class PolynomialFitter extends CurveFitter { - /** Polynomial degree. */ +public class PolynomialFitter extends CurveFitter<PolynomialFunction.Parametric> { + /** Polynomial degree. + * @deprecated + */ private final int degree; /** @@ -45,6 +41,8 @@ public class PolynomialFitter extends Cu * * @param degree Maximal degree of the polynomial. * @param optimizer Optimizer to use for the fitting. + * @deprecated Since 3.1 (to be removed in 4.0). Please use + * {@link #PolynomialFitter(DifferentiableMultivariateVectorOptimizer)} instead. */ public PolynomialFitter(int degree, final DifferentiableMultivariateVectorOptimizer optimizer) { super(optimizer); @@ -52,13 +50,38 @@ public class PolynomialFitter extends Cu } /** + * Simple constructor. + * + * @param optimizer Optimizer to use for the fitting. + */ + public PolynomialFitter(DifferentiableMultivariateVectorOptimizer optimizer) { + super(optimizer); + degree = -1; // To avoid compilation error until the instance variable is removed. + } + + /** * Get the polynomial fitting the weighted (x, y) points. * * @return the coefficients of the polynomial that best fits the observed points. * @throws org.apache.commons.math3.exception.ConvergenceException * if the algorithm failed to converge. + * @deprecated Since 3.1 (to be removed in 4.0). Please use {@link #fit(double[])} instead. */ public double[] fit() { return fit(new PolynomialFunction.Parametric(), new double[degree + 1]); } + + /** + * Get the coefficients of the polynomial fitting the weighted data points. + * The degree of the fitting polynomial is {@code guess.length - 1}. + * + * @param guess First guess for the coefficients. They must be sorted in + * increasing order of the polynomial's degree. + * @return the coefficients of the polynomial that best fits the observed points. + * @throws org.apache.commons.math3.exception.ConvergenceException + * if the algorithm failed to converge. + */ + public double[] fit(double[] guess) { + return fit(new PolynomialFunction.Parametric(), guess); + } } Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/PolynomialFitterTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/PolynomialFitterTest.java?rev=1348613&r1=1348612&r2=1348613&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/PolynomialFitterTest.java (original) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/PolynomialFitterTest.java Sun Jun 10 15:12:57 2012 @@ -43,7 +43,7 @@ public class PolynomialFitterTest { rng.reSeed(64925784252L); final LevenbergMarquardtOptimizer optim = new LevenbergMarquardtOptimizer(); - final CurveFitter fitter = new CurveFitter(optim); + final PolynomialFitter fitter = new PolynomialFitter(optim); final double[] coeff = { 12.9, -3.4, 2.1 }; // 12.9 - 3.4 x + 2.1 x^2 final PolynomialFunction f = new PolynomialFunction(coeff); @@ -54,8 +54,7 @@ public class PolynomialFitterTest { } // Start fit from initial guesses that are far from the optimal values. - final double[] best = fitter.fit(new PolynomialFunction.Parametric(), - new double[] { -1e-20, 3e15, -5e25 }); + final double[] best = fitter.fit(new double[] { -1e-20, 3e15, -5e25 }); TestUtils.assertEquals("best != coeff", coeff, best, 1e-12); } @@ -66,15 +65,13 @@ public class PolynomialFitterTest { for (int degree = 1; degree < 10; ++degree) { PolynomialFunction p = buildRandomPolynomial(degree, randomizer); - CurveFitter fitter = new CurveFitter(new LevenbergMarquardtOptimizer()); + PolynomialFitter fitter = new PolynomialFitter(new LevenbergMarquardtOptimizer()); for (int i = 0; i <= degree; ++i) { fitter.addObservedPoint(1.0, i, p.value(i)); } final double[] init = new double[degree + 1]; - PolynomialFunction fitted = new PolynomialFunction(fitter.fit(Integer.MAX_VALUE, - new PolynomialFunction.Parametric(), - init)); + PolynomialFunction fitted = new PolynomialFunction(fitter.fit(init)); for (double x = -1.0; x < 1.0; x += 0.01) { double error = FastMath.abs(p.value(x) - fitted.value(x)) / @@ -91,16 +88,14 @@ public class PolynomialFitterTest { for (int degree = 0; degree < 10; ++degree) { PolynomialFunction p = buildRandomPolynomial(degree, randomizer); - CurveFitter fitter = new CurveFitter(new LevenbergMarquardtOptimizer()); + PolynomialFitter fitter = new PolynomialFitter(new LevenbergMarquardtOptimizer()); for (double x = -1.0; x < 1.0; x += 0.01) { fitter.addObservedPoint(1.0, x, p.value(x) + 0.1 * randomizer.nextGaussian()); } final double[] init = new double[degree + 1]; - PolynomialFunction fitted = new PolynomialFunction(fitter.fit(Integer.MAX_VALUE, - new PolynomialFunction.Parametric(), - init)); + PolynomialFunction fitted = new PolynomialFunction(fitter.fit(init)); for (double x = -1.0; x < 1.0; x += 0.01) { double error = FastMath.abs(p.value(x) - fitted.value(x)) / @@ -130,7 +125,7 @@ public class PolynomialFitterTest { for (int degree = 0; degree < 10; ++degree) { PolynomialFunction p = buildRandomPolynomial(degree, randomizer); - CurveFitter fitter = new CurveFitter(optimizer); + PolynomialFitter fitter = new PolynomialFitter(optimizer); // reusing the same point over and over again does not bring // information, the problem cannot be solved in this case for @@ -142,9 +137,7 @@ public class PolynomialFitterTest { try { final double[] init = new double[degree + 1]; - fitter.fit(Integer.MAX_VALUE, - new PolynomialFunction.Parametric(), - init); + fitter.fit(init); Assert.assertTrue(solvable || (degree == 0)); } catch(ConvergenceException e) { Assert.assertTrue((! solvable) && (degree > 0));