Added Jacobi orthogonal polynomials.

JIRA: MATH-687

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1180092 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2011-10-07 16:31:04 +00:00
parent ca133d8940
commit 461c45aa7d
4 changed files with 149 additions and 7 deletions

View File

@ -17,6 +17,9 @@
package org.apache.commons.math.analysis.polynomials;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.math.fraction.BigFraction;
import org.apache.commons.math.util.FastMath;
@ -31,16 +34,19 @@ import org.apache.commons.math.util.MathUtils;
public class PolynomialsUtils {
/** Coefficients for Chebyshev polynomials. */
private static final ArrayList<BigFraction> CHEBYSHEV_COEFFICIENTS;
private static final List<BigFraction> CHEBYSHEV_COEFFICIENTS;
/** Coefficients for Hermite polynomials. */
private static final ArrayList<BigFraction> HERMITE_COEFFICIENTS;
private static final List<BigFraction> HERMITE_COEFFICIENTS;
/** Coefficients for Laguerre polynomials. */
private static final ArrayList<BigFraction> LAGUERRE_COEFFICIENTS;
private static final List<BigFraction> LAGUERRE_COEFFICIENTS;
/** Coefficients for Legendre polynomials. */
private static final ArrayList<BigFraction> LEGENDRE_COEFFICIENTS;
private static final List<BigFraction> LEGENDRE_COEFFICIENTS;
/** Coefficients for Jacobi polynomials. */
private static final Map<JacobiKey, List<BigFraction>> JACOBI_COEFFICIENTS;
static {
@ -72,6 +78,9 @@ public class PolynomialsUtils {
LEGENDRE_COEFFICIENTS.add(BigFraction.ZERO);
LEGENDRE_COEFFICIENTS.add(BigFraction.ONE);
// initialize map for Jacobi polynomials
JACOBI_COEFFICIENTS = new HashMap<JacobiKey, List<BigFraction>>();
}
/**
@ -185,6 +194,91 @@ public class PolynomialsUtils {
});
}
/**
* Create a Jacobi polynomial.
* <p><a href="http://mathworld.wolfram.com/JacobiPolynomial.html">Jacobi
* polynomials</a> are orthogonal polynomials.
* They can be defined by the following recurrence relations:
* <pre>
* P<sub>0</sub><sup>vw</sup>(X) = 1
* P<sub>-1</sub><sup>vw</sup>(X) = 0
* 2k(k + v + w)(2k + v + w - 2) P<sub>k</sub><sup>vw</sup>(X) =
* (2k + v + w - 1)[(2k + v + w)(2k + v + w - 2) X + v<sup>2</sup> - w<sup>2</sup>] P<sub>k-1</sub><sup>vw</sup>(X)
* - 2(k + v - 1)(k + w - 1)(2k + v + w) P<sub>k-2</sub><sup>vw</sup>(X)
* </pre></p>
* @param degree degree of the polynomial
* @param v first exponent
* @param w second exponent
* @return Jacobi polynomial of specified degree
*/
public static PolynomialFunction createJacobiPolynomial(final int degree, final int v, final int w) {
// select the appropriate list
final JacobiKey key = new JacobiKey(v, w);
if (!JACOBI_COEFFICIENTS.containsKey(key)) {
// allocate a new list for v, w
final List<BigFraction> list = new ArrayList<BigFraction>();
JACOBI_COEFFICIENTS.put(key, list);
// Pv,w,0(x) = 1;
list.add(BigFraction.ONE);
// P1(x) = (v - w) / 2 + (2 + v + w) * X / 2
list.add(new BigFraction(v - w, 2));
list.add(new BigFraction(2 + v + w, 2));
}
return buildPolynomial(degree, JACOBI_COEFFICIENTS.get(key),
new RecurrenceCoefficientsGenerator() {
/** {@inheritDoc} */
public BigFraction[] generate(int k) {
k++;
final int kvw = k + v + w;
final int twoKvw = kvw + k;
final int twoKvwM1 = twoKvw - 1;
final int twoKvwM2 = twoKvw - 2;
final int den = 2 * k * kvw * twoKvwM2;
return new BigFraction[] {
new BigFraction(twoKvwM1 * (v * v - w * w), den),
new BigFraction(twoKvwM1 * twoKvw * twoKvwM2, den),
new BigFraction(2 * (k + v - 1) * (k + w - 1) * twoKvw, den)
};
}
});
}
/** Inner class for Jacobi polynomials keys. */
private static class JacobiKey {
/** First exponent. */
private final int v;
/** Second exponent. */
private final int w;
/** Simple constructor.
* @param v first exponent
* @param w second exponent
*/
public JacobiKey(final int v, final int w) {
this.v = v;
this.w = w;
}
/** Get hash code.
* @return hash code
*/
public int hashCode() {
return (v << 16) ^ w;
}
}
/**
* Compute the coefficients of the polynomial <code>P<sub>s</sub>(x)</code>
* whose values at point {@code x} will be the same as the those from the
@ -247,7 +341,7 @@ public class PolynomialsUtils {
* @return coefficients array
*/
private static PolynomialFunction buildPolynomial(final int degree,
final ArrayList<BigFraction> coefficients,
final List<BigFraction> coefficients,
final RecurrenceCoefficientsGenerator generator) {
final int maxDegree = (int) FastMath.floor(FastMath.sqrt(2 * coefficients.size())) - 1;
@ -285,7 +379,7 @@ public class PolynomialsUtils {
*/
private static void computeUpToDegree(final int degree, final int maxDegree,
final RecurrenceCoefficientsGenerator generator,
final ArrayList<BigFraction> coefficients) {
final List<BigFraction> coefficients) {
int startK = (maxDegree - 1) * maxDegree / 2;
for (int k = maxDegree; k < degree; ++k) {

View File

@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces!
-->
<release version="3.0" date="TBD" description="TBD">
<action dev="luc" type="add" issue="MATH-687" due-to="Romain di Costanzo">
Added Jacobi polynomials.
</action>
<action dev="erans" type="add" issue="MATH-683" due-to="Romain di Costanzo">
Added "shift" method to compute the coefficients of a new polynomial
whose values are the same as those of another polynomial but computed

View File

@ -522,7 +522,7 @@ System.out println("f(" + interpolationX + ") = " + interpolatedY);</source>
coefficients arrays. The
<a href="../apidocs/org/apache/commons/math/analysis/polynomials/PolynomialsUtils.html">
PolynomialsUtils</a> utility class provides static factory methods to build
Chebyshev, Hermite, Lagrange and Legendre polynomials. Coefficients are
Chebyshev, Hermite, Jacobi, Laguerre and Legendre polynomials. Coefficients are
computed using exact fractions so these factory methods can build polynomials
up to any degree.
</p>

View File

@ -19,6 +19,7 @@ package org.apache.commons.math.analysis.polynomials;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.analysis.integration.LegendreGaussIntegrator;
import org.apache.commons.math.util.FastMath;
import org.apache.commons.math.util.MathUtils;
import org.junit.Assert;
import org.junit.Test;
@ -272,6 +273,50 @@ public class PolynomialsUtilsTest {
}
}
@Test
public void testJacobiLegendre() {
for (int i = 0; i < 10; ++i) {
PolynomialFunction legendre = PolynomialsUtils.createLegendrePolynomial(i);
PolynomialFunction jacobi = PolynomialsUtils.createJacobiPolynomial(i, 0, 0);
checkNullPolynomial(legendre.subtract(jacobi));
}
}
@Test
public void testJacobiEvaluationAt1() {
for (int v = 0; v < 10; ++v) {
for (int w = 0; w < 10; ++w) {
for (int i = 0; i < 10; ++i) {
PolynomialFunction jacobi = PolynomialsUtils.createJacobiPolynomial(i, v, w);
double binomial = MathUtils.binomialCoefficient(v + i, i);
Assert.assertTrue(MathUtils.equals(binomial, jacobi.value(1.0), 1));
}
}
}
}
@Test
public void testJacobiOrthogonality() {
for (int v = 0; v < 5; ++v) {
for (int w = v; w < 5; ++w) {
final int vv = v;
final int ww = w;
UnivariateRealFunction weight = new UnivariateRealFunction() {
public double value(double x) {
return FastMath.pow(1 - x, vv) * FastMath.pow(1 + x, ww);
}
};
for (int i = 0; i < 10; ++i) {
PolynomialFunction pi = PolynomialsUtils.createJacobiPolynomial(i, v, w);
for (int j = 0; j <= i; ++j) {
PolynomialFunction pj = PolynomialsUtils.createJacobiPolynomial(j, v, w);
checkOrthogonality(pi, pj, weight, -1, 1, 0.1, 1.0e-12);
}
}
}
}
}
@Test
public void testShift() {
// f1(x) = 1 + x + 2 x^2