FieldLegendreRuleFactory.java
- /*
- * Licensed to the Hipparchus project under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The Hipparchus project 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
- *
- * https://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.hipparchus.analysis.integration.gauss;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.Field;
- import org.hipparchus.exception.MathIllegalArgumentException;
- import org.hipparchus.util.MathArrays;
- import org.hipparchus.util.Pair;
- /**
- * Factory that creates Gauss-type quadrature rule using Legendre polynomials.
- * In this implementation, the lower and upper bounds of the natural interval
- * of integration are -1 and 1, respectively.
- * The Legendre polynomials are evaluated using the recurrence relation
- * presented in <a href="http://en.wikipedia.org/wiki/Abramowitz_and_Stegun">
- * Abramowitz and Stegun, 1964</a>.
- *
- * @param <T> Type of the number used to represent the points and weights of
- * the quadrature rules.
- * @since 2.0
- */
- public class FieldLegendreRuleFactory<T extends CalculusFieldElement<T>> extends FieldAbstractRuleFactory<T> {
- /** Simple constructor
- * @param field field to which rule coefficients belong
- */
- public FieldLegendreRuleFactory(final Field<T> field) {
- super(field);
- }
- /** {@inheritDoc} */
- @Override
- public Pair<T[], T[]> computeRule(int numberOfPoints)
- throws MathIllegalArgumentException {
- final Field<T> field = getField();
- if (numberOfPoints == 1) {
- // Break recursion.
- final T[] points = MathArrays.buildArray(field, numberOfPoints);
- final T[] weights = MathArrays.buildArray(field, numberOfPoints);
- points[0] = field.getZero();
- weights[0] = field.getZero().newInstance(2);
- return new Pair<>(points, weights);
- }
- // find nodes as roots of Legendre polynomial
- final Legendre<T> p = new Legendre<>(numberOfPoints);
- final T[] points = findRoots(numberOfPoints, p::ratio);
- enforceSymmetry(points);
- // compute weights
- final T[] weights = MathArrays.buildArray(field, numberOfPoints);
- for (int i = 0; i <= numberOfPoints / 2; i++) {
- final T c = points[i];
- final T[] pKpKm1 = p.pNpNm1(c);
- final T d = pKpKm1[1].subtract(c.multiply(pKpKm1[0])).multiply(numberOfPoints);
- weights[i] = c.square().subtract(1).multiply(-2).divide(d.multiply(d));
- // symmetrical point
- final int idx = numberOfPoints - i - 1;
- weights[idx] = weights[i];
- }
- return new Pair<>(points, weights);
- }
- /** Legendre polynomial.
- * @param <T> Type of the field elements.
- */
- private static class Legendre<T extends CalculusFieldElement<T>> {
- /** Degree. */
- private int degree;
- /** Simple constructor.
- * @param degree polynomial degree
- */
- Legendre(int degree) {
- this.degree = degree;
- }
- /** Compute ratio P(x)/P'(x).
- * @param x point at which ratio must be computed
- * @return ratio P(x)/P'(x)
- */
- public T ratio(T x) {
- T pm = x.getField().getOne();
- T p = x;
- T d = x.getField().getOne();
- for (int n = 1; n < degree; n++) {
- // apply recurrence relations (n+1) Pₙ₊₁(x) = (2n+1) x Pₙ(x) - n Pₙ₋₁(x)
- // and P'ₙ₊₁(x) = (n+1) Pₙ(x) + x P'ₙ(x)
- final T pp = p.multiply(x.multiply(2 * n + 1)).subtract(pm.multiply(n)).divide(n + 1);
- d = p.multiply(n + 1).add(d.multiply(x));
- pm = p;
- p = pp;
- }
- return p.divide(d);
- }
- /** Compute Pₙ(x) and Pₙ₋₁(x).
- * @param x point at which polynomials are evaluated
- * @return array containing Pₙ(x) at index 0 and Pₙ₋₁(x) at index 1
- */
- private T[] pNpNm1(final T x) {
- T[] p = MathArrays.buildArray(x.getField(), 2);
- p[0] = x;
- p[1] = x.getField().getOne();
- for (int n = 1; n < degree; n++) {
- // apply recurrence relation (n+1) Pₙ₊₁(x) = (2n+1) x Pₙ(x) - n Pₙ₋₁(x)
- final T pp = p[0].multiply(x.multiply(2 * n + 1)).subtract(p[1].multiply(n)).divide(n + 1);
- p[1] = p[0];
- p[0] = pp;
- }
- return p;
- }
- }
- }