Author: erans Date: Fri Aug 17 15:09:59 2012 New Revision: 1374308 URL: http://svn.apache.org/viewvc?rev=1374308&view=rev Log: Code cleanup: moved all computations to the constructor, allowing to make the class immutable.
Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optimization/fitting/HarmonicFitter.java commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/HarmonicFitterTest.java 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=1374308&r1=1374307&r2=1374308&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 Fri Aug 17 15:09:59 2012 @@ -177,20 +177,21 @@ public class HarmonicFitter extends Curv * number of measurements.</p> */ public static class ParameterGuesser { - /** Sampled observations. */ - private final WeightedObservedPoint[] observations; /** Amplitude. */ - private double a; + private final double a; /** Angular frequency. */ - private double omega; + private final double omega; /** Phase. */ - private double phi; + private final double phi; /** * Simple constructor. - * @param observations sampled observations - * @throws NumberIsTooSmallException if the sample is too short or if - * the first guess cannot be computed. + * + * @param observations Sampled observations. + * @throws NumberIsTooSmallException if the sample is too short. + * @throws ZeroException if the abscissa range is zero. + * @throws MathIllegalStateException when the guessing procedure cannot + * produce sensible results. */ public ParameterGuesser(WeightedObservedPoint[] observations) { if (observations.length < 4) { @@ -198,7 +199,13 @@ public class HarmonicFitter extends Curv observations.length, 4, true); } - this.observations = observations.clone(); + final WeightedObservedPoint[] sorted = sortObservations(observations); + + final double aOmega[] = guessAOmega(sorted); + a = aOmega[0]; + omega = aOmega[1]; + + phi = guessPhi(sorted); } /** @@ -212,16 +219,18 @@ public class HarmonicFitter extends Curv * </ul> */ public double[] guess() { - sortObservations(); - guessAOmega(); - guessPhi(); return new double[] { a, omega, phi }; } /** * Sort the observations with respect to the abscissa. + * + * @param unsorted Input observations. + * @return the input observations, sorted. */ - private void sortObservations() { + private WeightedObservedPoint[] sortObservations(WeightedObservedPoint[] unsorted) { + final WeightedObservedPoint[] observations = unsorted.clone(); + // 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. @@ -243,6 +252,8 @@ public class HarmonicFitter extends Curv curr = observations[j]; } } + + return observations; } /** @@ -250,11 +261,16 @@ public class HarmonicFitter extends Curv * This method assumes that the {@link #sortObservations()} method * has been called previously. * + * @param observations Observations, sorted w.r.t. abscissa. * @throws ZeroException if the abscissa range is zero. * @throws MathIllegalStateException when the guessing procedure cannot * produce sensible results. + * @return the guessed amplitude (at index 0) and circular frequency + * (at index 1). */ - private void guessAOmega() { + private double[] guessAOmega(WeightedObservedPoint[] observations) { + final double[] aOmega = new double[2]; + // initialize the sums for the linear model between the two integrals double sx2 = 0; double sy2 = 0; @@ -305,7 +321,7 @@ public class HarmonicFitter extends Curv if (xRange == 0) { throw new ZeroException(); } - omega = 2 * Math.PI / xRange; + aOmega[1] = 2 * Math.PI / xRange; double yMin = Double.POSITIVE_INFINITY; double yMax = Double.NEGATIVE_INFINITY; @@ -318,7 +334,7 @@ public class HarmonicFitter extends Curv yMax = y; } } - a = 0.5 * (yMax - yMin); + aOmega[0] = 0.5 * (yMax - yMin); } else { if (c2 == 0) { // In some ill-conditioned cases (cf. MATH-844), the guesser @@ -326,15 +342,20 @@ public class HarmonicFitter extends Curv throw new MathIllegalStateException(LocalizedFormats.ZERO_DENOMINATOR); } - a = FastMath.sqrt(c1 / c2); - omega = FastMath.sqrt(c2 / c3); + aOmega[0] = FastMath.sqrt(c1 / c2); + aOmega[1] = FastMath.sqrt(c2 / c3); } + + return aOmega; } /** * Estimate a first guess of the phase. + * + * @param observations Observations, sorted w.r.t. abscissa. + * @return the guessed phase. */ - private void guessPhi() { + private double guessPhi(WeightedObservedPoint[] observations) { // initialize the means double fcMean = 0; double fsMean = 0; @@ -356,7 +377,7 @@ public class HarmonicFitter extends Curv fsMean += omega * currentY * sine + currentYPrime * cosine; } - phi = FastMath.atan2(-fsMean, fcMean); + return FastMath.atan2(-fsMean, fcMean); } } } Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/HarmonicFitterTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/HarmonicFitterTest.java?rev=1374308&r1=1374307&r2=1374308&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/HarmonicFitterTest.java (original) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/optimization/fitting/HarmonicFitterTest.java Fri Aug 17 15:09:59 2012 @@ -191,14 +191,12 @@ public class HarmonicFitterTest { points[i] = new WeightedObservedPoint(1, i, y[i]); } - final HarmonicFitter.ParameterGuesser guesser - = new HarmonicFitter.ParameterGuesser(points); - // The guesser fails because the function is far from an harmonic // function: It is a triangular periodic function with amplitude 3 // and period 12, and all sample points are taken at integer abscissae // so function values all belong to the integer subset {-3, -2, -1, 0, // 1, 2, 3}. - guesser.guess(); + final HarmonicFitter.ParameterGuesser guesser + = new HarmonicFitter.ParameterGuesser(points); } }