MATH-997
Gauss-Hermite quadrature scheme. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1500018 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3739de305d
commit
7fb87df294
|
@ -51,6 +51,14 @@ If the output is not quite correct, check for invisible trailing spaces!
|
||||||
</properties>
|
</properties>
|
||||||
<body>
|
<body>
|
||||||
<release version="x.y" date="TBD" description="TBD">
|
<release version="x.y" date="TBD" description="TBD">
|
||||||
|
<action dev="erans" type="add" issue="MATH-997">
|
||||||
|
Implemented Gauss-Hermite quadrature scheme (in package
|
||||||
|
"o.a.c.m.analysis.integration.gauss").
|
||||||
|
</action>
|
||||||
|
<action dev="erans" type="update" issue="MATH-995">
|
||||||
|
Documented limitation of "IterativeLegendreGaussIntegrator" (added
|
||||||
|
warning about potential wrong usage).
|
||||||
|
</action>
|
||||||
<action dev="erans" type="fix" issue="MATH-993">
|
<action dev="erans" type="fix" issue="MATH-993">
|
||||||
In "GaussNewtonOptimizer", check for convergence before updating the
|
In "GaussNewtonOptimizer", check for convergence before updating the
|
||||||
parameters estimation for the next iteration.
|
parameters estimation for the next iteration.
|
||||||
|
|
|
@ -107,4 +107,24 @@ public class GaussIntegrator {
|
||||||
public int getNumberOfPoints() {
|
public int getNumberOfPoints() {
|
||||||
return points.length;
|
return points.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the integration point at the given index.
|
||||||
|
* The index must be in the valid range but no check is performed.
|
||||||
|
*
|
||||||
|
* @return the integration point.
|
||||||
|
*/
|
||||||
|
public double getPoint(int index) {
|
||||||
|
return points[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight of the integration point at the given index.
|
||||||
|
* The index must be in the valid range but no check is performed.
|
||||||
|
*
|
||||||
|
* @return the weight.
|
||||||
|
*/
|
||||||
|
public double getWeight(int index) {
|
||||||
|
return weights[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ import java.math.BigDecimal;
|
||||||
|
|
||||||
import org.apache.commons.math3.exception.DimensionMismatchException;
|
import org.apache.commons.math3.exception.DimensionMismatchException;
|
||||||
import org.apache.commons.math3.exception.NotStrictlyPositiveException;
|
import org.apache.commons.math3.exception.NotStrictlyPositiveException;
|
||||||
|
import org.apache.commons.math3.analysis.BivariateFunction;
|
||||||
import org.apache.commons.math3.util.Pair;
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
import org.apache.commons.math3.util.FastMath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that provides different ways to compute the nodes and weights to be
|
* Class that provides different ways to compute the nodes and weights to be
|
||||||
|
@ -34,9 +36,12 @@ public class GaussIntegratorFactory {
|
||||||
private final BaseRuleFactory<Double> legendre = new LegendreRuleFactory();
|
private final BaseRuleFactory<Double> legendre = new LegendreRuleFactory();
|
||||||
/** Generator of Gauss-Legendre integrators. */
|
/** Generator of Gauss-Legendre integrators. */
|
||||||
private final BaseRuleFactory<BigDecimal> legendreHighPrecision = new LegendreHighPrecisionRuleFactory();
|
private final BaseRuleFactory<BigDecimal> legendreHighPrecision = new LegendreHighPrecisionRuleFactory();
|
||||||
|
/** Generator of Gauss-Hermite integrators. */
|
||||||
|
private final BaseRuleFactory<Double> hermite = new HermiteRuleFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an integrator of the given order, and whose call to the
|
* Creates a Gauss-Legendre integrator of the given order.
|
||||||
|
* The call to the
|
||||||
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
||||||
* integrate} method will perform an integration on the natural interval
|
* integrate} method will perform an integration on the natural interval
|
||||||
* {@code [-1 , 1]}.
|
* {@code [-1 , 1]}.
|
||||||
|
@ -49,7 +54,8 @@ public class GaussIntegratorFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an integrator of the given order, and whose call to the
|
* Creates a Gauss-Legendre integrator of the given order.
|
||||||
|
* The call to the
|
||||||
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
||||||
* integrate} method will perform an integration on the given interval.
|
* integrate} method will perform an integration on the given interval.
|
||||||
*
|
*
|
||||||
|
@ -68,7 +74,8 @@ public class GaussIntegratorFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an integrator of the given order, and whose call to the
|
* Creates a Gauss-Legendre integrator of the given order.
|
||||||
|
* The call to the
|
||||||
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
* {@link GaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
||||||
* integrate} method will perform an integration on the natural interval
|
* integrate} method will perform an integration on the natural interval
|
||||||
* {@code [-1 , 1]}.
|
* {@code [-1 , 1]}.
|
||||||
|
@ -101,6 +108,26 @@ public class GaussIntegratorFactory {
|
||||||
lowerBound, upperBound));
|
lowerBound, upperBound));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Gauss-Hermite integrator of the given order.
|
||||||
|
* The call to the
|
||||||
|
* {@link SymmetricGaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
||||||
|
* integrate} method will perform a weighted integration on the interval
|
||||||
|
* {@code [-&inf;, +&inf;]}: the computed value is the improper integral of
|
||||||
|
* <code>
|
||||||
|
* e<sup>-x<sup>2</sup></sup> f(x)
|
||||||
|
* </code>
|
||||||
|
* where {@code f(x)} is the function passed to the
|
||||||
|
* {@link SymmetricGaussIntegrator#integrate(org.apache.commons.math3.analysis.UnivariateFunction)
|
||||||
|
* integrate} method.
|
||||||
|
*
|
||||||
|
* @param numberOfPoints Order of the integration rule.
|
||||||
|
* @return a Gauss-Hermite integrator.
|
||||||
|
*/
|
||||||
|
public SymmetricGaussIntegrator hermite(int numberOfPoints) {
|
||||||
|
return new SymmetricGaussIntegrator(getRule(hermite, numberOfPoints));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param factory Integration rule factory.
|
* @param factory Integration rule factory.
|
||||||
* @param numberOfPoints Order of the integration rule.
|
* @param numberOfPoints Order of the integration rule.
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.analysis.integration.gauss;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.exception.DimensionMismatchException;
|
||||||
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
import org.apache.commons.math3.util.FastMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory that creates a
|
||||||
|
* <a href="http://en.wikipedia.org/wiki/Gauss-Hermite_quadrature">
|
||||||
|
* Gauss-type quadrature rule using Hermite polynomials</a>
|
||||||
|
* of the first kind.
|
||||||
|
* Such a quadrature rule allows the calculation of improper integrals
|
||||||
|
* of a function
|
||||||
|
* <code>
|
||||||
|
* f(x) e<sup>-x<sup>2</sup></sup>
|
||||||
|
* </code>
|
||||||
|
* <br/>
|
||||||
|
* Recurrence relation and weights computation follow
|
||||||
|
* <a href="http://en.wikipedia.org/wiki/Abramowitz_and_Stegun"
|
||||||
|
* Abramowitz and Stegun, 1964</a>.
|
||||||
|
* <br/>
|
||||||
|
* The coefficients of the standard Hermite polynomials grow very rapidly;
|
||||||
|
* in order to avoid overflows, each Hermite polynomial is normalized with
|
||||||
|
* respect to the underlying scalar product.
|
||||||
|
* The initial interval for the application of the bisection method is
|
||||||
|
* based on the roots of the previous Hermite polynomial (interlacing).
|
||||||
|
* Upper and lower bounds of these roots are provided by
|
||||||
|
* <quote>
|
||||||
|
* I. Krasikov,
|
||||||
|
* <em>Nonnegative quadratic forms and bounds on orthogonal polynomials</em>,
|
||||||
|
* Journal of Approximation theory <b>111</b>, 31-49
|
||||||
|
* </quote>
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class HermiteRuleFactory extends BaseRuleFactory<Double> {
|
||||||
|
/** π<sup>1/2</sup> */
|
||||||
|
private static final double SQRT_PI = 1.77245385090551602729;
|
||||||
|
/** π<sup>-1/4</sup> */
|
||||||
|
private static final double H0 = 7.5112554446494248286e-1;
|
||||||
|
/** π<sup>-1/4</sup> √2 */
|
||||||
|
private static final double H1 = 1.0622519320271969145;
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected Pair<Double[], Double[]> computeRule(int numberOfPoints)
|
||||||
|
throws DimensionMismatchException {
|
||||||
|
|
||||||
|
if (numberOfPoints == 1) {
|
||||||
|
// Break recursion.
|
||||||
|
return new Pair<Double[], Double[]>(new Double[] { 0d },
|
||||||
|
new Double[] { SQRT_PI });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get previous rule.
|
||||||
|
// If it has not been computed yet it will trigger a recursive call
|
||||||
|
// to this method.
|
||||||
|
final int lastNumPoints = numberOfPoints - 1;
|
||||||
|
final Double[] previousPoints = getRuleInternal(lastNumPoints).getFirst();
|
||||||
|
|
||||||
|
// Compute next rule.
|
||||||
|
final Double[] points = new Double[numberOfPoints];
|
||||||
|
final Double[] weights = new Double[numberOfPoints];
|
||||||
|
|
||||||
|
final double sqrtTwoTimesLastNumPoints = FastMath.sqrt(2 * lastNumPoints);
|
||||||
|
final double sqrtTwoTimesNumPoints = FastMath.sqrt(2 * numberOfPoints);
|
||||||
|
|
||||||
|
// Find i-th root of H[n+1] by bracketing.
|
||||||
|
final int iMax = numberOfPoints / 2;
|
||||||
|
for (int i = 0; i < iMax; i++) {
|
||||||
|
// Lower-bound of the interval.
|
||||||
|
double a = (i == 0) ? -sqrtTwoTimesLastNumPoints : previousPoints[i - 1].doubleValue();
|
||||||
|
// Upper-bound of the interval.
|
||||||
|
double b = (iMax == 1) ? -0.5 : previousPoints[i].doubleValue();
|
||||||
|
|
||||||
|
// H[j-1](a)
|
||||||
|
double hma = H0;
|
||||||
|
// H[j](a)
|
||||||
|
double ha = H1 * a;
|
||||||
|
// H[j-1](b)
|
||||||
|
double hmb = H0;
|
||||||
|
// H[j](b)
|
||||||
|
double hb = H1 * b;
|
||||||
|
for (int j = 1; j < numberOfPoints; j++) {
|
||||||
|
// Compute H[j+1](a) and H[j+1](b)
|
||||||
|
final double jp1 = j + 1;
|
||||||
|
final double s = FastMath.sqrt(2 / jp1);
|
||||||
|
final double sm = FastMath.sqrt(j / jp1);
|
||||||
|
final double hpa = s * a * ha - sm * hma;
|
||||||
|
final double hpb = s * b * hb - sm * hmb;
|
||||||
|
hma = ha;
|
||||||
|
ha = hpa;
|
||||||
|
hmb = hb;
|
||||||
|
hb = hpb;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now ha = H[n+1](a), and hma = H[n](a) (same holds for b).
|
||||||
|
// Middle of the interval.
|
||||||
|
double c = 0.5 * (a + b);
|
||||||
|
// P[j-1](c)
|
||||||
|
double hmc = H0;
|
||||||
|
// P[j](c)
|
||||||
|
double hc = H1 * c;
|
||||||
|
boolean done = false;
|
||||||
|
while (!done) {
|
||||||
|
done = b - a <= Math.ulp(c);
|
||||||
|
hmc = H0;
|
||||||
|
hc = H1 * c;
|
||||||
|
for (int j = 1; j < numberOfPoints; j++) {
|
||||||
|
// Compute H[j+1](c)
|
||||||
|
final double jp1 = j + 1;
|
||||||
|
final double s = FastMath.sqrt(2 / jp1);
|
||||||
|
final double sm = FastMath.sqrt(j / jp1);
|
||||||
|
final double hpc = s * c * hc - sm * hmc;
|
||||||
|
hmc = hc;
|
||||||
|
hc = hpc;
|
||||||
|
}
|
||||||
|
// Now h = H[n+1](c) and hm = H[n](c).
|
||||||
|
if (!done) {
|
||||||
|
if (ha * hc < 0) {
|
||||||
|
b = c;
|
||||||
|
hmb = hmc;
|
||||||
|
hb = hc;
|
||||||
|
} else {
|
||||||
|
a = c;
|
||||||
|
hma = hmc;
|
||||||
|
ha = hc;
|
||||||
|
}
|
||||||
|
c = 0.5 * (a + b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final double d = sqrtTwoTimesNumPoints * hmc;
|
||||||
|
final double w = 2 / (d * d);
|
||||||
|
|
||||||
|
points[i] = c;
|
||||||
|
weights[i] = w;
|
||||||
|
|
||||||
|
final int idx = lastNumPoints - i;
|
||||||
|
points[idx] = -c;
|
||||||
|
weights[idx] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If "numberOfPoints" is odd, 0 is a root.
|
||||||
|
// Note: as written, the test for oddness will work for negative
|
||||||
|
// integers too (although it is not necessary here), preventing
|
||||||
|
// a FindBugs warning.
|
||||||
|
if (numberOfPoints % 2 != 0) {
|
||||||
|
double hm = H0;
|
||||||
|
for (int j = 1; j < numberOfPoints; j += 2) {
|
||||||
|
final double jp1 = j + 1;
|
||||||
|
hm = -FastMath.sqrt(j / jp1) * hm;
|
||||||
|
}
|
||||||
|
final double d = sqrtTwoTimesNumPoints * hm;
|
||||||
|
final double w = 2 / (d * d);
|
||||||
|
|
||||||
|
points[iMax] = 0d;
|
||||||
|
weights[iMax] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<Double[], Double[]>(points, weights);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.analysis.integration.gauss;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||||
|
import org.apache.commons.math3.exception.DimensionMismatchException;
|
||||||
|
import org.apache.commons.math3.exception.NonMonotonicSequenceException;
|
||||||
|
import org.apache.commons.math3.util.MathArrays;
|
||||||
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class's implements {@link #integrate(UnivariateFunction) integrate}
|
||||||
|
* method assuming that the integral is symmetric about 0.
|
||||||
|
* This allows to reduce numerical errors.
|
||||||
|
*
|
||||||
|
* @since 3.3
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class SymmetricGaussIntegrator extends GaussIntegrator {
|
||||||
|
/**
|
||||||
|
* Creates an integrator from the given {@code points} and {@code weights}.
|
||||||
|
* The integration interval is defined by the first and last value of
|
||||||
|
* {@code points} which must be sorted in increasing order.
|
||||||
|
*
|
||||||
|
* @param points Integration points.
|
||||||
|
* @param weights Weights of the corresponding integration nodes.
|
||||||
|
* @throws NonMonotonicSequenceException if the {@code points} are not
|
||||||
|
* sorted in increasing order.
|
||||||
|
* @throws DimensionMismatchException if points and weights don't have the same length
|
||||||
|
*/
|
||||||
|
public SymmetricGaussIntegrator(double[] points,
|
||||||
|
double[] weights)
|
||||||
|
throws NonMonotonicSequenceException, DimensionMismatchException {
|
||||||
|
super(points, weights);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an integrator from the given pair of points (first element of
|
||||||
|
* the pair) and weights (second element of the pair.
|
||||||
|
*
|
||||||
|
* @param pointsAndWeights Integration points and corresponding weights.
|
||||||
|
* @throws NonMonotonicSequenceException if the {@code points} are not
|
||||||
|
* sorted in increasing order.
|
||||||
|
*
|
||||||
|
* @see #SymmetricGaussIntegrator(double[], double[])
|
||||||
|
*/
|
||||||
|
public SymmetricGaussIntegrator(Pair<double[], double[]> pointsAndWeights)
|
||||||
|
throws NonMonotonicSequenceException {
|
||||||
|
this(pointsAndWeights.getFirst(), pointsAndWeights.getSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public double integrate(UnivariateFunction f) {
|
||||||
|
final int ruleLength = getNumberOfPoints();
|
||||||
|
|
||||||
|
if (ruleLength == 1) {
|
||||||
|
return getWeight(0) * f.value(0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int iMax = ruleLength / 2;
|
||||||
|
double s = 0;
|
||||||
|
double c = 0;
|
||||||
|
for (int i = 0; i < iMax; i++) {
|
||||||
|
final double p = getPoint(i);
|
||||||
|
final double w = getWeight(i);
|
||||||
|
|
||||||
|
final double f1 = f.value(p);
|
||||||
|
final double f2 = f.value(-p);
|
||||||
|
|
||||||
|
final double y = w * (f1 + f2) - c;
|
||||||
|
final double t = s + y;
|
||||||
|
|
||||||
|
c = (t - s) - y;
|
||||||
|
s = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ruleLength % 2 == 1) {
|
||||||
|
final double w = getWeight(iMax);
|
||||||
|
|
||||||
|
final double y = w * f.value(0d) - c;
|
||||||
|
final double t = s + y;
|
||||||
|
|
||||||
|
c = (t - s) - y;
|
||||||
|
s = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.analysis.integration.gauss;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||||
|
import org.apache.commons.math3.analysis.function.Constant;
|
||||||
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for {@link GaussIntegrator} class.
|
||||||
|
*
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class GaussIntegratorTest {
|
||||||
|
@Test
|
||||||
|
public void testGetWeights() {
|
||||||
|
final double[] points = { 0, 1.2, 3.4 };
|
||||||
|
final double[] weights = { 9.8, 7.6, 5.4 };
|
||||||
|
|
||||||
|
final GaussIntegrator integrator
|
||||||
|
= new GaussIntegrator(new Pair<double[], double[]>(points, weights));
|
||||||
|
|
||||||
|
Assert.assertEquals(weights.length, integrator.getNumberOfPoints());
|
||||||
|
|
||||||
|
for (int i = 0; i < integrator.getNumberOfPoints(); i++) {
|
||||||
|
Assert.assertEquals(weights[i], integrator.getWeight(i), 0d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPoints() {
|
||||||
|
final double[] points = { 0, 1.2, 3.4 };
|
||||||
|
final double[] weights = { 9.8, 7.6, 5.4 };
|
||||||
|
|
||||||
|
final GaussIntegrator integrator
|
||||||
|
= new GaussIntegrator(new Pair<double[], double[]>(points, weights));
|
||||||
|
|
||||||
|
Assert.assertEquals(points.length, integrator.getNumberOfPoints());
|
||||||
|
|
||||||
|
for (int i = 0; i < integrator.getNumberOfPoints(); i++) {
|
||||||
|
Assert.assertEquals(points[i], integrator.getPoint(i), 0d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntegrate() {
|
||||||
|
final double[] points = { 0, 1, 2, 3, 4, 5 };
|
||||||
|
final double[] weights = { 1, 1, 1, 1, 1, 1 };
|
||||||
|
|
||||||
|
final GaussIntegrator integrator
|
||||||
|
= new GaussIntegrator(new Pair<double[], double[]>(points, weights));
|
||||||
|
|
||||||
|
final double val = 123.456;
|
||||||
|
final UnivariateFunction c = new Constant(val);
|
||||||
|
|
||||||
|
final double s = integrator.integrate(c);
|
||||||
|
Assert.assertEquals(points.length * val, s, 0d);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.analysis.integration.gauss;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
import org.apache.commons.math3.util.FastMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of the {@link HermiteRuleFactory}.
|
||||||
|
* This parameterized test extends the standard test for Gaussian quadrature
|
||||||
|
* rule, where each monomial is tested in turn.
|
||||||
|
* Parametrization allows to test automatically 0, 1, ... , {@link #MAX_NUM_POINTS}
|
||||||
|
* quadrature rules.
|
||||||
|
*
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
@RunWith(value=Parameterized.class)
|
||||||
|
public class HermiteParametricTest extends GaussianQuadratureAbstractTest {
|
||||||
|
private static final double SQRT_PI = FastMath.sqrt(Math.PI);
|
||||||
|
private static final GaussIntegratorFactory factory = new GaussIntegratorFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The highest order quadrature rule to be tested.
|
||||||
|
*/
|
||||||
|
public static final int MAX_NUM_POINTS = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of this test, with the specified number of nodes
|
||||||
|
* for the Gauss-Hermite quadrature rule.
|
||||||
|
*
|
||||||
|
* @param numberOfPoints Order of integration rule.
|
||||||
|
* @param maxDegree Maximum degree of monomials to be tested.
|
||||||
|
* @param eps Value of ε.
|
||||||
|
* @param numUlps Value of the maximum relative error (in ulps).
|
||||||
|
*/
|
||||||
|
public HermiteParametricTest(int numberOfPoints,
|
||||||
|
int maxDegree,
|
||||||
|
double eps,
|
||||||
|
double numUlps) {
|
||||||
|
super(factory.hermite(numberOfPoints),
|
||||||
|
maxDegree, eps, numUlps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collection of parameters to be passed to the constructor of
|
||||||
|
* this class.
|
||||||
|
* Gauss-Hermite quadrature rules of order 1, ..., {@link #MAX_NUM_POINTS}
|
||||||
|
* will be constructed.
|
||||||
|
*
|
||||||
|
* @return the collection of parameters for this parameterized test.
|
||||||
|
*/
|
||||||
|
@Parameters
|
||||||
|
public static Collection<Object[]> getParameters() {
|
||||||
|
final ArrayList<Object[]> parameters = new ArrayList<Object[]>();
|
||||||
|
for (int k = 1; k <= MAX_NUM_POINTS; k++) {
|
||||||
|
parameters.add(new Object[] { k, 2 * k - 1, Math.ulp(1d), 195 });
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getExpectedValue(final int n) {
|
||||||
|
if (n % 2 == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int iMax = n / 2;
|
||||||
|
double p = 1;
|
||||||
|
double q = 1;
|
||||||
|
for (int i = 0; i < iMax; i++) {
|
||||||
|
p *= 2 * i + 1;
|
||||||
|
q *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p / q * SQRT_PI;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* 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.math3.analysis.integration.gauss;
|
||||||
|
|
||||||
|
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||||
|
import org.apache.commons.math3.analysis.function.Gaussian;
|
||||||
|
import org.apache.commons.math3.distribution.RealDistribution;
|
||||||
|
import org.apache.commons.math3.distribution.NormalDistribution;
|
||||||
|
import org.apache.commons.math3.util.FastMath;
|
||||||
|
import org.apache.commons.math3.util.Pair;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test of the {@link HermiteRuleFactory}.
|
||||||
|
*
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class HermiteTest {
|
||||||
|
private static final GaussIntegratorFactory factory = new GaussIntegratorFactory();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalDistribution() {
|
||||||
|
final double oneOverSqrtPi = 1 / FastMath.sqrt(Math.PI);
|
||||||
|
|
||||||
|
final double mu = 12345.6789;
|
||||||
|
final double sigma = 987.654321;
|
||||||
|
// By defintion, Gauss-Hermite quadrature readily provides the
|
||||||
|
// integral of the normal distribution density.
|
||||||
|
final int numPoints = 1;
|
||||||
|
|
||||||
|
// Change of variable:
|
||||||
|
// y = (x - mu) / (sqrt(2) * sigma)
|
||||||
|
// such that the integrand
|
||||||
|
// N(x, mu, sigma)
|
||||||
|
// is transformed to
|
||||||
|
// f(y) * exp(-y^2)
|
||||||
|
final UnivariateFunction f = new UnivariateFunction() {
|
||||||
|
@Override
|
||||||
|
public double value(double y) {
|
||||||
|
return oneOverSqrtPi; // Constant function.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final GaussIntegrator integrator = factory.hermite(numPoints);
|
||||||
|
final double result = integrator.integrate(f);
|
||||||
|
final double expected = 1;
|
||||||
|
Assert.assertEquals(expected, result, Math.ulp(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalMean() {
|
||||||
|
final double sqrtTwo = FastMath.sqrt(2);
|
||||||
|
final double oneOverSqrtPi = 1 / FastMath.sqrt(Math.PI);
|
||||||
|
|
||||||
|
final double mu = 12345.6789;
|
||||||
|
final double sigma = 987.654321;
|
||||||
|
final int numPoints = 5;
|
||||||
|
|
||||||
|
// Change of variable:
|
||||||
|
// y = (x - mu) / (sqrt(2) * sigma)
|
||||||
|
// such that the integrand
|
||||||
|
// x * N(x, mu, sigma)
|
||||||
|
// is transformed to
|
||||||
|
// f(y) * exp(-y^2)
|
||||||
|
final UnivariateFunction f = new UnivariateFunction() {
|
||||||
|
@Override
|
||||||
|
public double value(double y) {
|
||||||
|
return oneOverSqrtPi * (sqrtTwo * sigma * y + mu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final GaussIntegrator integrator = factory.hermite(numPoints);
|
||||||
|
final double result = integrator.integrate(f);
|
||||||
|
final double expected = mu;
|
||||||
|
Assert.assertEquals(expected, result, Math.ulp(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalVariance() {
|
||||||
|
final double twoOverSqrtPi = 2 / FastMath.sqrt(Math.PI);
|
||||||
|
|
||||||
|
final double mu = 12345.6789;
|
||||||
|
final double sigma = 987.654321;
|
||||||
|
final double sigma2 = sigma * sigma;
|
||||||
|
final int numPoints = 5;
|
||||||
|
|
||||||
|
// Change of variable:
|
||||||
|
// y = (x - mu) / (sqrt(2) * sigma)
|
||||||
|
// such that the integrand
|
||||||
|
// (x - mu)^2 * N(x, mu, sigma)
|
||||||
|
// is transformed to
|
||||||
|
// f(y) * exp(-y^2)
|
||||||
|
final UnivariateFunction f = new UnivariateFunction() {
|
||||||
|
@Override
|
||||||
|
public double value(double y) {
|
||||||
|
return twoOverSqrtPi * sigma2 * y * y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final GaussIntegrator integrator = factory.hermite(numPoints);
|
||||||
|
final double result = integrator.integrate(f);
|
||||||
|
final double expected = sigma2;
|
||||||
|
Assert.assertEquals(expected, result, 10 * Math.ulp(expected));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue