MATH-514
Removed "ParametricGaussianFunction" (superseded by "Gaussian.Parametric" in package "analysis.function"). git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1072207 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
04bbc3fccf
commit
f2e551b8de
|
@ -43,7 +43,6 @@ import org.apache.commons.math.exception.NullArgumentException;
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @see GaussianDerivativeFunction
|
* @see GaussianDerivativeFunction
|
||||||
* @see ParametricGaussianFunction
|
|
||||||
* @since 2.2
|
* @since 2.2
|
||||||
* @version $Revision$ $Date$
|
* @version $Revision$ $Date$
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.exception.DimensionMismatchException;
|
|
||||||
import org.apache.commons.math.exception.util.LocalizedFormats;
|
|
||||||
import org.apache.commons.math.exception.ZeroException;
|
|
||||||
import org.apache.commons.math.exception.NullArgumentException;
|
|
||||||
import org.apache.commons.math.analysis.ParametricUnivariateRealFunction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Gaussian function. Specifically:
|
|
||||||
* <p>
|
|
||||||
* {@code f(x) = a + b*exp(-((x - c)^2 / (2*d^2)))}
|
|
||||||
* <p>
|
|
||||||
* The parameters have the following meaning:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code a} is a constant offset that shifts {@code f(x)} up or down
|
|
||||||
* <li>{@code b} is the height of the peak
|
|
||||||
* <li>{@code c} is the position of the center of the peak
|
|
||||||
* <li>{@code d} is related to the FWHM by {@code FWHM = 2*sqrt(2*ln(2))*d}
|
|
||||||
* </ul>
|
|
||||||
* Notation key:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code x^n}: {@code x} raised to the power of {@code n}
|
|
||||||
* <li>{@code exp(x)}: e<sup>x</sup>
|
|
||||||
* <li>{@code sqrt(x)}: square root of {@code x}
|
|
||||||
* <li>{@code ln(x)}: natural logarithm of {@code x}
|
|
||||||
* </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 ParametricUnivariateRealFunction, Serializable {
|
|
||||||
/** Serializable version Id. */
|
|
||||||
private static final long serialVersionUID = -3875578602503903233L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes value of function {@code f(x)} for the specified {@code x} and
|
|
||||||
* parameters {@code a}, {@code b}, {@code c}, and {@code d}.
|
|
||||||
*
|
|
||||||
* @param x Value at which to compute the function.
|
|
||||||
* @return {@code f(x)}.
|
|
||||||
* @param parameters Values of {@code a}, {@code b}, {@code c}, and {@code d}.
|
|
||||||
* @throws NullArgumentException if {@code parameters} is {@code null}.
|
|
||||||
* @throws DimensionMismatchException if the size of {@code parameters} is
|
|
||||||
* not 4.
|
|
||||||
* @throws ZeroException if {@code parameters[3]} is 0.
|
|
||||||
*/
|
|
||||||
public double value(double x, double[] parameters) {
|
|
||||||
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, {@code a}, {@code b}, {@code c}, and {@code d},
|
|
||||||
* are considered the variables, not {@code x}. That is, instead of
|
|
||||||
* computing the gradient vector for the function {@code f(x)} (which would
|
|
||||||
* just be the derivative of {@code f(x)} with respect to {@code x} since
|
|
||||||
* it's a one-dimensional function), computes the gradient vector for the
|
|
||||||
* function {@code f(a, b, c, d) = a + b*exp(-((x - c)^2 / (2*d^2)))}
|
|
||||||
* treating the specified {@code x} as a constant.
|
|
||||||
* <p>
|
|
||||||
* The components of the computed gradient vector are the partial
|
|
||||||
* derivatives of {@code f(a, b, c, d)} with respect to each variable.
|
|
||||||
* That is, the partial derivative of {@code f(a, b, c, d)} with respect to
|
|
||||||
* {@code a}, the partial derivative of {@code f(a, b, c, d)} with respect
|
|
||||||
* to {@code b}, the partial derivative of {@code f(a, b, c, d)} with
|
|
||||||
* respect to {@code c}, and the partial derivative of {@code f(a, b, c,
|
|
||||||
* d)} with respect to {@code d}.
|
|
||||||
*
|
|
||||||
* @param x Value to be used as constant in {@code f(x, a, b, c, d)}.
|
|
||||||
* @param parameters Values of {@code a}, {@code b}, {@code c}, and {@code d}.
|
|
||||||
* @return the gradient vector of {@code f(a, b, c, d)}.
|
|
||||||
* @throws NullArgumentException if {@code parameters} is {@code null}.
|
|
||||||
* @throws DimensionMismatchException if the size of {@code parameters} is
|
|
||||||
* not 4.
|
|
||||||
* @throws ZeroException if {@code parameters[3]} is 0.
|
|
||||||
*/
|
|
||||||
public double[] gradient(double x, double[] parameters) {
|
|
||||||
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} and {@code gradient} methods.
|
|
||||||
*
|
|
||||||
* @param parameters Values of {@code a}, {@code b}, {@code c}, and {@code d}.
|
|
||||||
* @throws NullArgumentException if {@code parameters} is {@code null}.
|
|
||||||
* @throws DimensionMismatchException if the size of {@code parameters} is
|
|
||||||
* not 4.
|
|
||||||
* @throws ZeroException if {@code parameters[3]} is 0.
|
|
||||||
*/
|
|
||||||
private void validateParameters(double[] parameters) {
|
|
||||||
if (parameters == null) {
|
|
||||||
throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
|
|
||||||
}
|
|
||||||
if (parameters.length != 4) {
|
|
||||||
throw new DimensionMismatchException(4, parameters.length);
|
|
||||||
}
|
|
||||||
if (parameters[3] == 0) {
|
|
||||||
throw new ZeroException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,6 +52,10 @@ The <action> type attribute can be add,update,fix,remove.
|
||||||
If the output is not quite correct, check for invisible trailing spaces!
|
If the output is not quite correct, check for invisible trailing spaces!
|
||||||
-->
|
-->
|
||||||
<release version="3.0" date="TBD" description="TBD">
|
<release version="3.0" date="TBD" description="TBD">
|
||||||
|
<action dev="erans" type="fix" issue="MATH-514">
|
||||||
|
Removed "ParametricGaussianFunction" (in package "optimization.fitting");
|
||||||
|
functionality moved to class "Gaussian" (in package "analysis.function").
|
||||||
|
</action>
|
||||||
<action dev="erans" type="update" issue="MATH-512" due-to="Ole Ersoy">
|
<action dev="erans" type="update" issue="MATH-512" due-to="Ole Ersoy">
|
||||||
Refactored "GaussianFitter" (in package "optimization.fitting").
|
Refactored "GaussianFitter" (in package "optimization.fitting").
|
||||||
The class now really fits a Gaussian function (whereas previously it was
|
The class now really fits a Gaussian function (whereas previously it was
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.exception.MathUserException;
|
|
||||||
import org.apache.commons.math.exception.ZeroException;
|
|
||||||
import org.apache.commons.math.exception.MathIllegalArgumentException;
|
|
||||||
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 MathUserException in the event of a test case error
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testFit01()
|
|
||||||
throws OptimizationException, MathUserException {
|
|
||||||
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 MathUserException in the event of a test case error
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testFit02()
|
|
||||||
throws OptimizationException, MathUserException {
|
|
||||||
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 MathUserException in the event of a test case error
|
|
||||||
*/
|
|
||||||
@Test(expected=MathIllegalArgumentException.class)
|
|
||||||
public void testValue01() throws MathUserException {
|
|
||||||
ParametricGaussianFunction f = new ParametricGaussianFunction();
|
|
||||||
f.value(0.0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameters array length is not 4.
|
|
||||||
*
|
|
||||||
* @throws MathUserException in the event of a test case error
|
|
||||||
*/
|
|
||||||
@Test(expected=MathIllegalArgumentException.class)
|
|
||||||
public void testValue02() throws MathUserException {
|
|
||||||
ParametricGaussianFunction f = new ParametricGaussianFunction();
|
|
||||||
f.value(0.0, new double[] {0.0, 1.0});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parameters d is 0.
|
|
||||||
*
|
|
||||||
* @throws MathUserException in the event of a test case error
|
|
||||||
*/
|
|
||||||
@Test(expected=ZeroException.class)
|
|
||||||
public void testValue03() throws MathUserException {
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue