commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From l..@apache.org
Subject svn commit: r980938 - in /commons/proper/math/trunk: ./ src/main/java/org/apache/commons/math/exception/ src/main/java/org/apache/commons/math/optimization/fitting/ src/main/java/org/apache/commons/math/util/ src/main/resources/META-INF/localization/ s...
Date Fri, 30 Jul 2010 20:16:18 GMT
Author: luc
Date: Fri Jul 30 20:16:18 2010
New Revision: 980938

URL: http://svn.apache.org/viewvc?rev=980938&view=rev
Log:
Added support for Gaussian curve fitting
JIRA: MATH-400

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java   (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java   (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java   (with props)
Modified:
    commons/proper/math/trunk/checkstyle.xml
    commons/proper/math/trunk/pom.xml
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/LocalizedFormats.java
    commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties
    commons/proper/math/trunk/src/site/xdoc/changes.xml

Modified: commons/proper/math/trunk/checkstyle.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/checkstyle.xml?rev=980938&r1=980937&r2=980938&view=diff
==============================================================================
--- commons/proper/math/trunk/checkstyle.xml (original)
+++ commons/proper/math/trunk/checkstyle.xml Fri Jul 30 20:16:18 2010
@@ -150,6 +150,11 @@
 
   <!-- Setup special comments to suppress specific checks from source files -->
   <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CHECKSTYLE\: stop JavadocVariable"/>
+    <property name="onCommentFormat"  value="CHECKSTYLE\: resume JavadocVariable"/>
+    <property name="checkFormat"      value="JavadocVariable"/>
+  </module>
+  <module name="SuppressionCommentFilter">
     <property name="offCommentFormat" value="CHECKSTYLE\: stop JavadocMethodCheck"/>
     <property name="onCommentFormat"  value="CHECKSTYLE\: resume JavadocMethodCheck"/>
     <property name="checkFormat"      value="JavadocMethodCheck"/>

Modified: commons/proper/math/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/pom.xml?rev=980938&r1=980937&r2=980938&view=diff
==============================================================================
--- commons/proper/math/trunk/pom.xml (original)
+++ commons/proper/math/trunk/pom.xml Fri Jul 30 20:16:18 2010
@@ -182,6 +182,9 @@
       <name>Benjamin McCann</name>
     </contributor>
     <contributor>
+      <name>J. Lewis Muir</name>
+    </contributor>
+    <contributor>
       <name>Fredrik Norin</name>
     </contributor>
     <contributor>

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math.exception;
+
+import org.apache.commons.math.util.Localizable;
+import org.apache.commons.math.util.LocalizedFormats;
+
+/**
+ * Exception to be thrown when zero is provided where it is not allowed.
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class ZeroNotAllowedException extends MathIllegalNumberException {
+
+    /** Serializable version identifier */
+    private static final long serialVersionUID = -1960874856936000015L;
+
+    /**
+     * Construct the exception.
+     */
+    public ZeroNotAllowedException() {
+        this(null);
+    }
+
+    /**
+     * Construct the exception with a specific context.
+     *
+     * @param specific Specific contexte pattern .
+     */
+    public ZeroNotAllowedException(Localizable specific) {
+        super(specific, LocalizedFormats.ZERO_NOT_ALLOWED, 0);
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/ZeroNotAllowedException.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.ZeroNotAllowedException;
+import org.apache.commons.math.util.LocalizedFormats;
+
+/**
+ * The derivative of {@link GaussianFunction}.  Specifically:
+ * <p>
+ * <tt>f'(x) = (-b / (d^2)) * (x - c) * exp(-((x - c)^2) / (2*(d^2)))</tt>
+ * <p>
+ * Notation key:
+ * <ul>
+ * <li><tt>x^n</tt>: <tt>x</tt> raised to the power of <tt>n</tt>
+ * <li><tt>exp(x)</tt>: <i>e</i><tt>^x</tt>
+ * </ul>
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class GaussianDerivativeFunction implements UnivariateRealFunction, Serializable {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = -6500229089670174766L;
+
+    /** Parameter b of this function. */
+    private final double b;
+
+    /** Parameter c of this function. */
+    private final double c;
+
+    /** Square of the parameter d of this function. */
+    private final double d2;
+
+    /**
+     * Constructs an instance with the specified parameters.
+     *
+     * @param b <tt>b</tt> parameter value
+     * @param c <tt>c</tt> parameter value
+     * @param d <tt>d</tt> parameter value
+     *
+     * @throws IllegalArgumentException if <code>d</code> is 0
+     */
+    public GaussianDerivativeFunction(double b, double c, double d) {
+        if (d == 0.0) {
+            throw new ZeroNotAllowedException();
+        }
+        this.b = b;
+        this.c = c;
+        this.d2 = d * d;
+    }
+
+    /**
+     * Constructs an instance with the specified parameters.
+     *
+     * @param parameters <tt>b</tt>, <tt>c</tt>, and <tt>d</tt> parameter values
+     *
+     * @throws IllegalArgumentException if <code>parameters</code> is null,
+     *         <code>parameters</code> length is not 3, or if
+     *         <code>parameters[2]</code> is 0
+     */
+    public GaussianDerivativeFunction(double[] parameters) {
+        if (parameters == null) {
+            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NULL_INPUT_ARRAY);
+        }
+        if (parameters.length != 3) {
+            throw new DimensionMismatchException(3, parameters.length);
+        }
+        if (parameters[2] == 0.0) {
+            throw new ZeroNotAllowedException();
+        }
+        this.b = parameters[0];
+        this.c = parameters[1];
+        this.d2 = parameters[2] * parameters[2];
+    }
+
+    /** {@inheritDoc} */
+    public double value(double x) throws FunctionEvaluationException {
+        final double xMc = x - c;
+        return (-b / d2) * xMc * Math.exp(-(xMc * xMc) / (2.0 * d2));
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianDerivativeFunction.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.optimization.
+       DifferentiableMultivariateVectorialOptimizer;
+import org.apache.commons.math.optimization.OptimizationException;
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+import org.apache.commons.math.optimization.fitting.WeightedObservedPoint;
+
+/**
+ * Fits points to a Gaussian function (that is, a {@link GaussianFunction}).
+ * <p>
+ * Usage example:
+ * <pre>
+ *   GaussianFitter fitter = new GaussianFitter(
+ *     new LevenbergMarquardtOptimizer());
+ *   fitter.addObservedPoint(4.0254623,  531026.0);
+ *   fitter.addObservedPoint(4.03128248, 984167.0);
+ *   fitter.addObservedPoint(4.03839603, 1887233.0);
+ *   fitter.addObservedPoint(4.04421621, 2687152.0);
+ *   fitter.addObservedPoint(4.05132976, 3461228.0);
+ *   fitter.addObservedPoint(4.05326982, 3580526.0);
+ *   fitter.addObservedPoint(4.05779662, 3439750.0);
+ *   fitter.addObservedPoint(4.0636168,  2877648.0);
+ *   fitter.addObservedPoint(4.06943698, 2175960.0);
+ *   fitter.addObservedPoint(4.07525716, 1447024.0);
+ *   fitter.addObservedPoint(4.08237071, 717104.0);
+ *   fitter.addObservedPoint(4.08366408, 620014.0);
+ *  GaussianFunction fitFunction = fitter.fit();
+ * </pre>
+ *
+ * @see ParametricGaussianFunction
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class GaussianFitter {
+
+    /** Fitter used for fitting. */
+    private final CurveFitter fitter;
+
+    /**
+     * Constructs an instance using the specified optimizer.
+     *
+     * @param optimizer optimizer to use for the fitting
+     */
+    public GaussianFitter(DifferentiableMultivariateVectorialOptimizer optimizer) {
+        fitter = new CurveFitter(optimizer);
+    }
+
+    /**
+     * Adds point (<code>x</code>, <code>y</code>) to list of observed points
+     * with a weight of 1.0.
+     *
+     * @param x <tt>x</tt> point value
+     * @param y <tt>y</tt> point value
+     */
+    public void addObservedPoint(double x, double y) {
+        addObservedPoint(1.0, x, y);
+    }
+
+    /**
+     * Adds point (<code>x</code>, <code>y</code>) to list of observed points
+     * with a weight of <code>weight</code>.
+     *
+     * @param weight weight assigned to point
+     * @param x <tt>x</tt> point value
+     * @param y <tt>y</tt> point value
+     */
+    public void addObservedPoint(double weight, double x, double y) {
+        fitter.addObservedPoint(weight, x, y);
+    }
+
+    /**
+     * Fits Gaussian function to the observed points.
+     *
+     * @return Gaussian function best fitting the observed points
+     *
+     * @throws FunctionEvaluationException if <code>CurveFitter.fit</code>
+     *         throws it
+     * @throws OptimizationException if <code>CurveFitter.fit</code> throws it
+     * @throws IllegalArgumentException if <code>CurveFitter.fit</code> throws
+     *         it
+     *
+     * @see CurveFitter
+     */
+    public GaussianFunction fit()
+        throws FunctionEvaluationException, OptimizationException {
+        return new GaussianFunction(fitter.fit(new ParametricGaussianFunction(),
+                                               createParametersGuesser(fitter.getObservations()).guess()));
+    }
+
+    /**
+     * Factory method to create a <code>GaussianParametersGuesser</code>
+     * instance initialized with the specified observations.
+     *
+     * @param observations points used to initialize the created
+     *        <code>GaussianParametersGuesser</code> instance
+     *
+     * @return new <code>GaussianParametersGuesser</code> instance
+     */
+    protected GaussianParametersGuesser createParametersGuesser(WeightedObservedPoint[] observations) {
+        return new GaussianParametersGuesser(observations);
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFitter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.ZeroNotAllowedException;
+import org.apache.commons.math.util.LocalizedFormats;
+
+/**
+ * A Gaussian function.  Specifically:
+ * <p>
+ * <tt>f(x) = a + b*exp(-((x - c)^2 / (2*d^2)))</tt>
+ * <p>
+ * Notation key:
+ * <ul>
+ * <li><tt>x^n</tt>: <tt>x</tt> raised to the power of <tt>n</tt>
+ * <li><tt>exp(x)</tt>: <i>e</i><tt>^x</tt>
+ * </ul>
+ * References:
+ * <ul>
+ * <li><a href="http://en.wikipedia.org/wiki/Gaussian_function">Wikipedia:
+ *   Gaussian function</a>
+ * </ul>
+ *
+ * @see GaussianDerivativeFunction
+ * @see ParametricGaussianFunction
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class GaussianFunction implements DifferentiableUnivariateRealFunction, Serializable {
+
+    /** Serializable version identifier. */
+    private static final long serialVersionUID = -3195385616125629512L;
+
+    /** Parameter a of this function. */
+    private final double a;
+
+    /** Parameter b of this function. */
+    private final double b;
+
+    /** Parameter c of this function. */
+    private final double c;
+
+    /** Parameter d of this function. */
+    private final double d;
+
+    /**
+     * Constructs an instance with the specified parameters.
+     *
+     * @param a <tt>a</tt> parameter value
+     * @param b <tt>b</tt> parameter value
+     * @param c <tt>c</tt> parameter value
+     * @param d <tt>d</tt> parameter value
+     *
+     * @throws IllegalArgumentException if <code>d</code> is 0
+     */
+    public GaussianFunction(double a, double b, double c, double d) {
+        if (d == 0.0) {
+            throw new ZeroNotAllowedException();
+        }
+        this.a = a;
+        this.b = b;
+        this.c = c;
+        this.d = d;
+    }
+
+    /**
+     * Constructs an instance with the specified parameters.
+     *
+     * @param parameters <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and <tt>d</tt>
+     *        parameter values
+     *
+     * @throws IllegalArgumentException if <code>parameters</code> is null,
+     *         <code>parameters</code> length is not 4, or if
+     *         <code>parameters[3]</code> is 0
+     */
+    public GaussianFunction(double[] parameters) {
+        if (parameters == null) {
+            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NULL_INPUT_ARRAY);
+        }
+        if (parameters.length != 4) {
+            throw new DimensionMismatchException(4, parameters.length);
+        }
+        if (parameters[3] == 0.0) {
+            throw new ZeroNotAllowedException();
+        }
+        this.a = parameters[0];
+        this.b = parameters[1];
+        this.c = parameters[2];
+        this.d = parameters[3];
+    }
+
+    /** {@inheritDoc} */
+    public UnivariateRealFunction derivative() {
+        return new GaussianDerivativeFunction(b, c, d);
+    }
+
+    /** {@inheritDoc} */
+    public double value(double x) throws FunctionEvaluationException {
+        final double xMc = x - c;
+        return a + b * Math.exp(-xMc * xMc / (2.0 * (d * d)));
+    }
+
+    /**
+     * Gets <tt>a</tt> parameter value.
+     *
+     * @return <tt>a</tt> parameter value
+     */
+    public double getA() {
+        return a;
+    }
+
+    /**
+     * Gets <tt>b</tt> parameter value.
+     *
+     * @return <tt>b</tt> parameter value
+     */
+    public double getB() {
+        return b;
+    }
+
+    /**
+     * Gets <tt>c</tt> parameter value.
+     *
+     * @return <tt>c</tt> parameter value
+     */
+    public double getC() {
+        return c;
+    }
+
+    /**
+     * Gets <tt>d</tt> parameter value.
+     *
+     * @return <tt>d</tt> parameter value
+     */
+    public double getD() {
+        return d;
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianFunction.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.exception.NumberIsTooSmallException;
+import org.apache.commons.math.exception.OutOfRangeException;
+import org.apache.commons.math.exception.ZeroNotAllowedException;
+import org.apache.commons.math.util.LocalizedFormats;
+
+/**
+ * Guesses the parameters (<tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and <tt>d</tt>)
+ * of a {@link ParametricGaussianFunction} based on the specified observed
+ * points.
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class GaussianParametersGuesser {
+
+    /** Observed points. */
+    private final WeightedObservedPoint[] observations;
+
+    /** Resulting guessed parameters. */
+    private double[] parameters;
+
+    /**
+     * Constructs instance with the specified observed points.
+     *
+     * @param observations observed points upon which should base guess
+     */
+    public GaussianParametersGuesser(WeightedObservedPoint[] observations) {
+        if (observations == null) {
+            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NULL_INPUT_ARRAY);
+        }
+        if (observations.length < 3) {
+            throw new NumberIsTooSmallException(observations.length, 3, true);
+        }
+        this.observations = observations.clone();
+    }
+
+    /**
+     * Guesses the parameters based on the observed points.
+     *
+     * @return guessed parameters array <code>{a, b, c, d}</code>
+     */
+    public double[] guess() {
+        if (parameters == null) {
+            parameters = basicGuess(observations);
+        }
+        return parameters.clone();
+    }
+
+    /**
+     * Guesses the parameters based on the specified observed points.
+     *
+     * @param points observed points upon which should base guess
+     *
+     * @return guessed parameters array <code>{a, b, c, d}</code>
+     */
+    private double[] basicGuess(WeightedObservedPoint[] points) {
+        Arrays.sort(points, createWeightedObservedPointComparator());
+        double[] params = new double[4];
+
+        int minYIdx = findMinY(points);
+        params[0] = points[minYIdx].getY();
+
+        int maxYIdx = findMaxY(points);
+        params[1] = points[maxYIdx].getY();
+        params[2] = points[maxYIdx].getX();
+
+        double fwhmApprox;
+        try {
+            double halfY = params[0] + ((params[1] - params[0]) / 2.0);
+            double fwhmX1 = interpolateXAtY(points, maxYIdx, -1, halfY);
+            double fwhmX2 = interpolateXAtY(points, maxYIdx, +1, halfY);
+            fwhmApprox = fwhmX2 - fwhmX1;
+        } catch (OutOfRangeException e) {
+            fwhmApprox = points[points.length - 1].getX() - points[0].getX();
+        }
+        params[3] = fwhmApprox / (2.0 * Math.sqrt(2.0 * Math.log(2.0)));
+
+        return params;
+    }
+
+    /**
+     * Finds index of point in specified points with the smallest Y.
+     *
+     * @param points points to search
+     *
+     * @return index in specified points array
+     */
+    private int findMinY(WeightedObservedPoint[] points) {
+        int minYIdx = 0;
+        for (int i = 1; i < points.length; i++) {
+            if (points[i].getY() < points[minYIdx].getY()) {
+                minYIdx = i;
+            }
+        }
+        return minYIdx;
+    }
+
+    /**
+     * Finds index of point in specified points with the largest Y.
+     *
+     * @param points points to search
+     *
+     * @return index in specified points array
+     */
+    private int findMaxY(WeightedObservedPoint[] points) {
+        int maxYIdx = 0;
+        for (int i = 1; i < points.length; i++) {
+            if (points[i].getY() > points[maxYIdx].getY()) {
+                maxYIdx = i;
+            }
+        }
+        return maxYIdx;
+    }
+
+    /**
+     * Interpolates using the specified points to determine X at the specified
+     * Y.
+     *
+     * @param points points to use for interpolation
+     * @param startIdx index within points from which to start search for
+     *        interpolation bounds points
+     * @param idxStep index step for search for interpolation bounds points
+     * @param y Y value for which X should be determined
+     *
+     * @return value of X at the specified Y
+     *
+     * @throws IllegalArgumentException if idxStep is 0
+     * @throws OutOfRangeException if specified <code>y</code> is not within the
+     *         range of the specified <code>points</code>
+     */
+    private double interpolateXAtY(WeightedObservedPoint[] points,
+                                   int startIdx, int idxStep, double y) throws OutOfRangeException {
+        if (idxStep == 0) {
+            throw new ZeroNotAllowedException();
+        }
+        WeightedObservedPoint[] twoPoints = getInterpolationPointsForY(points, startIdx, idxStep, y);
+        WeightedObservedPoint pointA = twoPoints[0];
+        WeightedObservedPoint pointB = twoPoints[1];
+        if (pointA.getY() == y) {
+            return pointA.getX();
+        }
+        if (pointB.getY() == y) {
+            return pointB.getX();
+        }
+        return pointA.getX() +
+               (((y - pointA.getY()) * (pointB.getX() - pointA.getX())) / (pointB.getY() - pointA.getY()));
+    }
+
+    /**
+     * Gets the two bounding interpolation points from the specified points
+     * suitable for determining X at the specified Y.
+     *
+     * @param points points to use for interpolation
+     * @param startIdx index within points from which to start search for
+     *        interpolation bounds points
+     * @param idxStep index step for search for interpolation bounds points
+     * @param y Y value for which X should be determined
+     *
+     * @return array containing two points suitable for determining X at the
+     *         specified Y
+     *
+     * @throws IllegalArgumentException if idxStep is 0
+     * @throws OutOfRangeException if specified <code>y</code> is not within the
+     *         range of the specified <code>points</code>
+     */
+    private WeightedObservedPoint[] getInterpolationPointsForY(WeightedObservedPoint[] points,
+                                                               int startIdx, int idxStep, double y)
+        throws OutOfRangeException {
+        if (idxStep == 0) {
+            throw new ZeroNotAllowedException();
+        }
+        for (int i = startIdx;
+             (idxStep < 0) ? (i + idxStep >= 0) : (i + idxStep < points.length);
+             i += idxStep) {
+            if (isBetween(y, points[i].getY(), points[i + idxStep].getY())) {
+                return (idxStep < 0) ?
+                       new WeightedObservedPoint[] { points[i + idxStep], points[i] } :
+                       new WeightedObservedPoint[] { points[i], points[i + idxStep] };
+            }
+        }
+
+        double minY = Double.POSITIVE_INFINITY;
+        double maxY = Double.NEGATIVE_INFINITY;
+        for (final WeightedObservedPoint point : points) {
+            minY = Math.min(minY, point.getY());
+            maxY = Math.max(maxY, point.getY());
+        }
+        throw new OutOfRangeException(y, minY, maxY);
+
+    }
+
+    /**
+     * Determines whether a value is between two other values.
+     *
+     * @param value value to determine whether is between <code>boundary1</code>
+     *        and <code>boundary2</code>
+     * @param boundary1 one end of the range
+     * @param boundary2 other end of the range
+     *
+     * @return true if <code>value</code> is between <code>boundary1</code> and
+     *         <code>boundary2</code> (inclusive); false otherwise
+     */
+    private boolean isBetween(double value, double boundary1, double boundary2) {
+        return (value >= boundary1 && value <= boundary2) ||
+               (value >= boundary2 && value <= boundary1);
+    }
+
+    /**
+     * Factory method creating <code>Comparator</code> for comparing
+     * <code>WeightedObservedPoint</code> instances.
+     *
+     * @return new <code>Comparator</code> instance
+     */
+    private Comparator<WeightedObservedPoint> createWeightedObservedPointComparator() {
+        return new Comparator<WeightedObservedPoint>() {
+            public int compare(WeightedObservedPoint p1, WeightedObservedPoint p2) {
+                if (p1 == null && p2 == null) {
+                    return 0;
+                }
+                if (p1 == null) {
+                    return -1;
+                }
+                if (p2 == null) {
+                    return 1;
+                }
+                if (p1.getX() < p2.getX()) {
+                    return -1;
+                }
+                if (p1.getX() > p2.getX()) {
+                    return 1;
+                }
+                if (p1.getY() < p2.getY()) {
+                    return -1;
+                }
+                if (p1.getY() > p2.getY()) {
+                    return 1;
+                }
+                if (p1.getWeight() < p2.getWeight()) {
+                    return -1;
+                }
+                if (p1.getWeight() > p2.getWeight()) {
+                    return 1;
+                }
+                return 0;
+            }
+        };
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/GaussianParametersGuesser.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.ZeroNotAllowedException;
+import org.apache.commons.math.optimization.fitting.ParametricRealFunction;
+import org.apache.commons.math.util.LocalizedFormats;
+
+/**
+ * A Gaussian function.  Specifically:
+ * <p>
+ * <tt>f(x) = a + b*exp(-((x - c)^2 / (2*d^2)))</tt>
+ * <p>
+ * The parameters have the following meaning:
+ * <ul>
+ * <li><tt>a</tt> is a constant offset that shifts <tt>f(x)</tt> up or down
+ * <li><tt>b</tt> is the height of the peak
+ * <li><tt>c</tt> is the position of the center of the peak
+ * <li><tt>d</tt> is related to the FWHM by <tt>FWHM = 2*sqrt(2*ln(2))*d</tt>
+ * </ul>
+ * Notation key:
+ * <ul>
+ * <li><tt>x^n</tt>: <tt>x</tt> raised to the power of <tt>n</tt>
+ * <li><tt>exp(x)</tt>: <i>e</i><tt>^x</tt>
+ * <li><tt>sqrt(x)</tt>: the square root of <tt>x</tt>
+ * <li><tt>ln(x)</tt>: the natural logarithm of <tt>x</tt>
+ * </ul>
+ * References:
+ * <ul>
+ * <li><a href="http://en.wikipedia.org/wiki/Gaussian_function">Wikipedia:
+ *   Gaussian function</a>
+ * </ul>
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class ParametricGaussianFunction implements ParametricRealFunction, Serializable {
+
+    /** Serializable version Id. */
+    private static final long serialVersionUID = -3875578602503903233L;
+
+    /**
+     * Constructs an instance.
+     */
+    public ParametricGaussianFunction() {
+    }
+
+    /**
+     * Computes value of function <tt>f(x)</tt> for the specified <tt>x</tt> and
+     * parameters <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and <tt>d</tt>.
+     *
+     * @param x <tt>x</tt> value
+     * @param parameters values of <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and
+     *        <tt>d</tt>
+     *
+     * @return value of <tt>f(x)</tt> evaluated at <tt>x</tt> with the specified
+     *         parameters
+     *
+     * @throws IllegalArgumentException if <code>parameters</code> is invalid as
+     *         determined by {@link #validateParameters(double[])}
+     * @throws FunctionEvaluationException if <code>parameters</code> values are
+     *         invalid as determined by {@link #validateParameters(double[])}
+     */
+    public double value(double x, double[] parameters) throws FunctionEvaluationException {
+        validateParameters(parameters);
+        final double a = parameters[0];
+        final double b = parameters[1];
+        final double c = parameters[2];
+        final double d = parameters[3];
+        final double xMc = x - c;
+        return a + b * Math.exp(-xMc * xMc / (2.0 * (d * d)));
+    }
+
+    /**
+     * Computes the gradient vector for a four variable version of the function
+     * where the parameters, <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and <tt>d</tt>,
+     * are considered the variables, not <tt>x</tt>.  That is, instead of
+     * computing the gradient vector for the function <tt>f(x)</tt> (which would
+     * just be the derivative of <tt>f(x)</tt> with respect to <tt>x</tt> since
+     * it's a one-dimensional function), computes the gradient vector for the
+     * function <tt>f(a, b, c, d) = a + b*exp(-((x - c)^2 / (2*d^2)))</tt>
+     * treating the specified <tt>x</tt> as a constant.
+     * <p>
+     * The components of the computed gradient vector are the partial
+     * derivatives of <tt>f(a, b, c, d)</tt> with respect to each variable.
+     * That is, the partial derivative of <tt>f(a, b, c, d)</tt> with respect to
+     * <tt>a</tt>, the partial derivative of <tt>f(a, b, c, d)</tt> with respect
+     * to <tt>b</tt>, the partial derivative of <tt>f(a, b, c, d)</tt> with
+     * respect to <tt>c</tt>, and the partial derivative of <tt>f(a, b, c,
+     * d)</tt> with respect to <tt>d</tt>.
+     *
+     * @param x <tt>x</tt> value to be used as constant in <tt>f(a, b, c,
+     *        d)</tt>
+     * @param parameters values of <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and
+     *        <tt>d</tt> for computation of gradient vector of <tt>f(a, b, c,
+     *        d)</tt>
+     *
+     * @return gradient vector of <tt>f(a, b, c, d)</tt>
+     *
+     * @throws IllegalArgumentException if <code>parameters</code> is invalid as
+     *         determined by {@link #validateParameters(double[])}
+     * @throws FunctionEvaluationException if <code>parameters</code> values are
+     *         invalid as determined by {@link #validateParameters(double[])}
+     */
+    public double[] gradient(double x, double[] parameters) throws FunctionEvaluationException {
+
+        validateParameters(parameters);
+        final double b = parameters[1];
+        final double c = parameters[2];
+        final double d = parameters[3];
+
+        final double xMc  = x - c;
+        final double d2   = d * d;
+        final double exp  = Math.exp(-xMc * xMc / (2 * d2));
+        final double f    = b * exp * xMc / d2;
+
+        return new double[] { 1.0, exp, f, f * xMc / d };
+
+    }
+
+    /**
+     * Validates parameters to ensure they are appropriate for the evaluation of
+     * the <code>value</code> and <code>gradient</code> methods.
+     *
+     * @param parameters values of <tt>a</tt>, <tt>b</tt>, <tt>c</tt>, and
+     *        <tt>d</tt>
+     *
+     * @throws IllegalArgumentException if <code>parameters</code> is
+     *         <code>null</code> or if <code>parameters</code> does not have
+     *         length == 4
+     * @throws FunctionEvaluationException if <code>parameters[3]</code>
+     *         (<tt>d</tt>) is 0
+     */
+    private void validateParameters(double[] parameters) throws FunctionEvaluationException {
+        if (parameters == null) {
+            throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NULL_INPUT_ARRAY);
+        }
+        if (parameters.length != 4) {
+            throw new DimensionMismatchException(4, parameters.length);
+        }
+        if (parameters[3] == 0.0) {
+            throw new ZeroNotAllowedException();
+        }
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunction.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/LocalizedFormats.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/LocalizedFormats.java?rev=980938&r1=980937&r2=980938&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/LocalizedFormats.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/util/LocalizedFormats.java Fri Jul 30 20:16:18 2010
@@ -40,6 +40,7 @@ import java.util.ResourceBundle;
 public enum LocalizedFormats implements Localizable {
 
     // CHECKSTYLE: stop MultipleVariableDeclarations
+    // CHECKSTYLE: stop JavadocVariable
 
     ARGUMENT_OUTSIDE_DOMAIN("Argument {0} outside domain [{1} ; {2}]"),
     ARRAY_SIZES_SHOULD_HAVE_DIFFERENCE_1("array sizes should have difference 1 ({0} != {1} + 1)"),
@@ -290,8 +291,10 @@ public enum LocalizedFormats implements 
     ZERO_FRACTION_TO_DIVIDE_BY("the fraction to divide by must not be zero: {0}/{1}"),
     ZERO_NORM("zero norm"),
     ZERO_NORM_FOR_ROTATION_AXIS("zero norm for rotation axis"),
-    ZERO_NORM_FOR_ROTATION_DEFINING_VECTOR("zero norm for rotation defining vector");
+    ZERO_NORM_FOR_ROTATION_DEFINING_VECTOR("zero norm for rotation defining vector"),
+    ZERO_NOT_ALLOWED("zero not allowed here");
 
+    // CHECKSTYLE: resume JavadocVariable
     // CHECKSTYLE: resume MultipleVariableDeclarations
 
 

Modified: commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties?rev=980938&r1=980937&r2=980938&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties (original)
+++ commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties Fri Jul 30 20:16:18 2010
@@ -263,3 +263,4 @@ ZERO_FRACTION_TO_DIVIDE_BY = division pa
 ZERO_NORM = norme nulle
 ZERO_NORM_FOR_ROTATION_AXIS = norme nulle pour un axe de rotation
 ZERO_NORM_FOR_ROTATION_DEFINING_VECTOR = norme nulle pour un axe de d\u00e9finition de rotation
+ZERO_NOT_ALLOWED = la valeur z\u00e9ro n''est pas autoris\u00e9e ici

Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=980938&r1=980937&r2=980938&view=diff
==============================================================================
--- commons/proper/math/trunk/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/trunk/src/site/xdoc/changes.xml Fri Jul 30 20:16:18 2010
@@ -52,6 +52,9 @@ The <action> type attribute can be add,u
     If the output is not quite correct, check for invisible trailing spaces!
      -->
     <release version="2.2" date="TBD" description="TBD">
+      <action dev="luc" type="add" issue="MATH-400" due-to="J. Lewis Muir">
+        Added support for Gaussian curve fitting.
+      </action>
       <action dev="erans" type="update" issue="MATH-397">
         Modified "AbstractUnivariateRealOptimizer" to make it more similar to
         "BaseAbstractScalarOptimizer".

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.optimization.OptimizationException;
+import org.apache.commons.math.optimization.general.
+       LevenbergMarquardtOptimizer;
+import org.junit.Test;
+
+/**
+ * Tests {@link GaussianFitter}.
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class GaussianFitterTest {
+    /** Good data. */
+    protected static final double[][] DATASET1 = new double[][] {
+        {4.0254623,  531026.0},
+        {4.02804905, 664002.0},
+        {4.02934242, 787079.0},
+        {4.03128248, 984167.0},
+        {4.03386923, 1294546.0},
+        {4.03580929, 1560230.0},
+        {4.03839603, 1887233.0},
+        {4.0396894,  2113240.0},
+        {4.04162946, 2375211.0},
+        {4.04421621, 2687152.0},
+        {4.04550958, 2862644.0},
+        {4.04744964, 3078898.0},
+        {4.05003639, 3327238.0},
+        {4.05132976, 3461228.0},
+        {4.05326982, 3580526.0},
+        {4.05585657, 3576946.0},
+        {4.05779662, 3439750.0},
+        {4.06038337, 3220296.0},
+        {4.06167674, 3070073.0},
+        {4.0636168,  2877648.0},
+        {4.06620355, 2595848.0},
+        {4.06749692, 2390157.0},
+        {4.06943698, 2175960.0},
+        {4.07202373, 1895104.0},
+        {4.0733171,  1687576.0},
+        {4.07525716, 1447024.0},
+        {4.0778439,  1130879.0},
+        {4.07978396, 904900.0},
+        {4.08237071, 717104.0},
+        {4.08366408, 620014.0}
+    };
+    /** Poor data: right of peak not symmetric with left of peak. */
+    protected static final double[][] DATASET2 = new double[][] {
+        {-20.15,   1523.0},
+        {-19.65,   1566.0},
+        {-19.15,   1592.0},
+        {-18.65,   1927.0},
+        {-18.15,   3089.0},
+        {-17.65,   6068.0},
+        {-17.15,  14239.0},
+        {-16.65,  34124.0},
+        {-16.15,  64097.0},
+        {-15.65, 110352.0},
+        {-15.15, 164742.0},
+        {-14.65, 209499.0},
+        {-14.15, 267274.0},
+        {-13.65, 283290.0},
+        {-13.15, 275363.0},
+        {-12.65, 258014.0},
+        {-12.15, 225000.0},
+        {-11.65, 200000.0},
+        {-11.15, 190000.0},
+        {-10.65, 185000.0},
+        {-10.15, 180000.0},
+        { -9.65, 179000.0},
+        { -9.15, 178000.0},
+        { -8.65, 177000.0},
+        { -8.15, 176000.0},
+        { -7.65, 175000.0},
+        { -7.15, 174000.0},
+        { -6.65, 173000.0},
+        { -6.15, 172000.0},
+        { -5.65, 171000.0},
+        { -5.15, 170000.0}
+    };
+    /** Poor data: long tails. */
+    protected static final double[][] DATASET3 = new double[][] {
+        {-90.15,   1513.0},
+        {-80.15,   1514.0},
+        {-70.15,   1513.0},
+        {-60.15,   1514.0},
+        {-50.15,   1513.0},
+        {-40.15,   1514.0},
+        {-30.15,   1513.0},
+        {-20.15,   1523.0},
+        {-19.65,   1566.0},
+        {-19.15,   1592.0},
+        {-18.65,   1927.0},
+        {-18.15,   3089.0},
+        {-17.65,   6068.0},
+        {-17.15,  14239.0},
+        {-16.65,  34124.0},
+        {-16.15,  64097.0},
+        {-15.65, 110352.0},
+        {-15.15, 164742.0},
+        {-14.65, 209499.0},
+        {-14.15, 267274.0},
+        {-13.65, 283290.0},
+        {-13.15, 275363.0},
+        {-12.65, 258014.0},
+        {-12.15, 214073.0},
+        {-11.65, 182244.0},
+        {-11.15, 136419.0},
+        {-10.65,  97823.0},
+        {-10.15,  58930.0},
+        { -9.65,  35404.0},
+        { -9.15,  16120.0},
+        { -8.65,   9823.0},
+        { -8.15,   5064.0},
+        { -7.65,   2575.0},
+        { -7.15,   1642.0},
+        { -6.65,   1101.0},
+        { -6.15,    812.0},
+        { -5.65,    690.0},
+        { -5.15,    565.0},
+        {  5.15,    564.0},
+        { 15.15,    565.0},
+        { 25.15,    564.0},
+        { 35.15,    565.0},
+        { 45.15,    564.0},
+        { 55.15,    565.0},
+        { 65.15,    564.0},
+        { 75.15,    565.0}
+    };
+    /** Poor data: right of peak is missing. */
+    protected static final double[][] DATASET4 = new double[][] {
+        {-20.15,   1523.0},
+        {-19.65,   1566.0},
+        {-19.15,   1592.0},
+        {-18.65,   1927.0},
+        {-18.15,   3089.0},
+        {-17.65,   6068.0},
+        {-17.15,  14239.0},
+        {-16.65,  34124.0},
+        {-16.15,  64097.0},
+        {-15.65, 110352.0},
+        {-15.15, 164742.0},
+        {-14.65, 209499.0},
+        {-14.15, 267274.0},
+        {-13.65, 283290.0}
+    };
+    /** Good data, but few points. */
+    protected static final double[][] DATASET5 = new double[][] {
+        {4.0254623,  531026.0},
+        {4.03128248, 984167.0},
+        {4.03839603, 1887233.0},
+        {4.04421621, 2687152.0},
+        {4.05132976, 3461228.0},
+        {4.05326982, 3580526.0},
+        {4.05779662, 3439750.0},
+        {4.0636168,  2877648.0},
+        {4.06943698, 2175960.0},
+        {4.07525716, 1447024.0},
+        {4.08237071, 717104.0},
+        {4.08366408, 620014.0}
+    };
+
+    /**
+     * Basic.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit01()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(DATASET1, fitter);
+        GaussianFunction fitFunction = fitter.fit();
+        assertEquals(99200.86969833552, fitFunction.getA(), 1e-4);
+        assertEquals(3410515.285208688, fitFunction.getB(), 1e-4);
+        assertEquals(4.054928275302832, fitFunction.getC(), 1e-4);
+        assertEquals(0.014609868872574, fitFunction.getD(), 1e-4);
+    }
+
+    /**
+     * Zero points is not enough observed points.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testFit02()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        fitter.fit();
+    }
+
+    /**
+     * Two points is not enough observed points.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testFit03()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(new double[][] {
+            {4.0254623,  531026.0},
+            {4.02804905, 664002.0}},
+            fitter);
+        fitter.fit();
+    }
+
+    /**
+     * Poor data: right of peak not symmetric with left of peak.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit04()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(DATASET2, fitter);
+        GaussianFunction fitFunction = fitter.fit();
+        assertEquals(-256534.689445631, fitFunction.getA(), 1e-4);
+        assertEquals(481328.2181530679, fitFunction.getB(), 1e-4);
+        assertEquals(-10.5217226891099, fitFunction.getC(), 1e-4);
+        assertEquals(-7.64248239366800, fitFunction.getD(), 1e-4);
+    }
+
+    /**
+     * Poor data: long tails.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit05()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(DATASET3, fitter);
+        GaussianFunction fitFunction = fitter.fit();
+        assertEquals(491.6310079258938, fitFunction.getA(), 1e-4);
+        assertEquals(283508.6800413632, fitFunction.getB(), 1e-4);
+        assertEquals(-13.2966857238057, fitFunction.getC(), 1e-4);
+        assertEquals(1.725590356962981, fitFunction.getD(), 1e-4);
+    }
+
+    /**
+     * Poor data: right of peak is missing.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit06()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(DATASET4, fitter);
+        GaussianFunction fitFunction = fitter.fit();
+        assertEquals(530.3649792355617, fitFunction.getA(), 1e-4);
+        assertEquals(284517.0835567514, fitFunction.getB(), 1e-4);
+        assertEquals(-13.5355534565105, fitFunction.getC(), 1e-4);
+        assertEquals(1.512353018625465, fitFunction.getD(), 1e-4);
+    }
+
+    /**
+     * Basic with smaller dataset.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit07()
+    throws OptimizationException, FunctionEvaluationException {
+        GaussianFitter fitter = new GaussianFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToGaussianFitter(DATASET5, fitter);
+        GaussianFunction fitFunction = fitter.fit();
+        assertEquals(176748.1400947575, fitFunction.getA(), 1e-4);
+        assertEquals(3361537.018813906, fitFunction.getB(), 1e-4);
+        assertEquals(4.054949992747176, fitFunction.getC(), 1e-4);
+        assertEquals(0.014192380137002, fitFunction.getD(), 1e-4);
+    }
+
+    /**
+     * Adds the specified points to specified <code>GaussianFitter</code>
+     * instance.
+     *
+     * @param points data points where first dimension is a point index and
+     *        second dimension is an array of length two representing the point
+     *        with the first value corresponding to X and the second value
+     *        corresponding to Y
+     * @param fitter fitter to which the points in <code>points</code> should be
+     *        added as observed points
+     */
+    protected static void addDatasetToGaussianFitter(double[][] points,
+                                                     GaussianFitter fitter) {
+        for (int i = 0; i < points.length; i++) {
+            fitter.addObservedPoint(points[i][0], points[i][1]);
+        }
+    }
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/GaussianFitterTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java?rev=980938&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java Fri Jul 30 20:16:18 2010
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.optimization.fitting;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.exception.ZeroNotAllowedException;
+import org.apache.commons.math.optimization.OptimizationException;
+import org.apache.commons.math.optimization.fitting.CurveFitter;
+import org.apache.commons.math.optimization.general.
+       LevenbergMarquardtOptimizer;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests {@link ParametricGaussianFunction}.
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public class ParametricGaussianFunctionTest {
+    /** Dataset 1 used by some test cases. */
+    protected static final double[][] DATASET1 = new double[][] {
+        {4.0254623,  531026.0},
+        {4.02804905, 664002.0},
+        {4.02934242, 787079.0},
+        {4.03128248, 984167.0},
+        {4.03386923, 1294546.0},
+        {4.03580929, 1560230.0},
+        {4.03839603, 1887233.0},
+        {4.0396894,  2113240.0},
+        {4.04162946, 2375211.0},
+        {4.04421621, 2687152.0},
+        {4.04550958, 2862644.0},
+        {4.04744964, 3078898.0},
+        {4.05003639, 3327238.0},
+        {4.05132976, 3461228.0},
+        {4.05326982, 3580526.0},
+        {4.05585657, 3576946.0},
+        {4.05779662, 3439750.0},
+        {4.06038337, 3220296.0},
+        {4.06167674, 3070073.0},
+        {4.0636168,  2877648.0},
+        {4.06620355, 2595848.0},
+        {4.06749692, 2390157.0},
+        {4.06943698, 2175960.0},
+        {4.07202373, 1895104.0},
+        {4.0733171,  1687576.0},
+        {4.07525716, 1447024.0},
+        {4.0778439,  1130879.0},
+        {4.07978396, 904900.0},
+        {4.08237071, 717104.0},
+        {4.08366408, 620014.0}
+    };
+
+    /**
+     * Using not-so-good initial parameters.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit01()
+    throws OptimizationException, FunctionEvaluationException {
+        CurveFitter fitter = new CurveFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToCurveFitter(DATASET1, fitter);
+        double[] parameters = fitter.fit(new ParametricGaussianFunction(),
+                                         new double[] {8.64753e3, 3.483323e6, 4.06322, 1.946857e-2});
+        assertEquals(99200.94715858076, parameters[0], 1e-4);
+        assertEquals(3410515.221897707, parameters[1], 1e-4);
+        assertEquals(4.054928275257894, parameters[2], 1e-4);
+        assertEquals(0.014609868499860, parameters[3], 1e-4);
+    }
+
+    /**
+     * Using eye-balled guesses for initial parameters.
+     *
+     * @throws OptimizationException in the event of a test case error
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test
+    public void testFit02()
+    throws OptimizationException, FunctionEvaluationException {
+        CurveFitter fitter = new CurveFitter(new LevenbergMarquardtOptimizer());
+        addDatasetToCurveFitter(DATASET1, fitter);
+        double[] parameters = fitter.fit(new ParametricGaussianFunction(),
+                                         new double[] {500000.0, 3500000.0, 4.055, 0.025479654});
+        assertEquals(99200.81836264656, parameters[0], 1e-4);
+        assertEquals(3410515.327151986, parameters[1], 1e-4);
+        assertEquals(4.054928275377392, parameters[2], 1e-4);
+        assertEquals(0.014609869119806, parameters[3], 1e-4);
+    }
+
+    /**
+     * The parameters array is null.
+     *
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testValue01() throws FunctionEvaluationException {
+        ParametricGaussianFunction f = new ParametricGaussianFunction();
+        f.value(0.0, null);
+    }
+
+    /**
+     * The parameters array length is not 4.
+     *
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test(expected=IllegalArgumentException.class)
+    public void testValue02() throws FunctionEvaluationException {
+        ParametricGaussianFunction f = new ParametricGaussianFunction();
+        f.value(0.0, new double[] {0.0, 1.0});
+    }
+
+    /**
+     * The parameters d is 0.
+     *
+     * @throws FunctionEvaluationException in the event of a test case error
+     */
+    @Test(expected=ZeroNotAllowedException.class)
+    public void testValue03() throws FunctionEvaluationException {
+        ParametricGaussianFunction f = new ParametricGaussianFunction();
+        f.value(0.0, new double[] {0.0, 1.0, 1.0, 0.0});
+    }
+
+    /**
+     * Adds the specified points to specified <code>CurveFitter</code> instance.
+     *
+     * @param points data points where first dimension is a point index and
+     *        second dimension is an array of length two representing the point
+     *        with the first value corresponding to X and the second value
+     *        corresponding to Y
+     * @param fitter fitter to which the points in <code>points</code> should be
+     *        added as observed points
+     */
+    protected static void addDatasetToCurveFitter(double[][] points,
+                                                  CurveFitter fitter) {
+        for (int i = 0; i < points.length; i++) {
+            fitter.addObservedPoint(points[i][0], points[i][1]);
+        }
+    }
+}

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/optimization/fitting/ParametricGaussianFunctionTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision



Mime
View raw message