IterativeLegendreGaussIntegrator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math4.legacy.analysis.integration;

  18. import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
  19. import org.apache.commons.math4.legacy.analysis.integration.gauss.GaussIntegrator;
  20. import org.apache.commons.math4.legacy.analysis.integration.gauss.GaussIntegratorFactory;
  21. import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
  22. import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException;
  23. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  24. import org.apache.commons.math4.core.jdkmath.JdkMath;

  25. /**
  26.  * This algorithm divides the integration interval into equally-sized
  27.  * sub-interval and on each of them performs a
  28.  * <a href="http://mathworld.wolfram.com/Legendre-GaussQuadrature.html">
  29.  * Legendre-Gauss</a> quadrature.
  30.  * Because of its <em>non-adaptive</em> nature, this algorithm can
  31.  * converge to a wrong value for the integral (for example, if the
  32.  * function is significantly different from zero toward the ends of the
  33.  * integration interval).
  34.  * In particular, a change of variables aimed at estimating integrals
  35.  * over infinite intervals as proposed
  36.  * <a href="http://en.wikipedia.org/w/index.php?title=Numerical_integration#Integrals_over_infinite_intervals">
  37.  *  here</a> should be avoided when using this class.
  38.  *
  39.  * @since 3.1
  40.  */

  41. public class IterativeLegendreGaussIntegrator
  42.     extends BaseAbstractUnivariateIntegrator {
  43.     /** Factory that computes the points and weights. */
  44.     private static final GaussIntegratorFactory FACTORY
  45.         = new GaussIntegratorFactory();
  46.     /** Number of integration points (per interval). */
  47.     private final int numberOfPoints;

  48.     /**
  49.      * Builds an integrator with given accuracies and iterations counts.
  50.      *
  51.      * @param n Number of integration points.
  52.      * @param relativeAccuracy Relative accuracy of the result.
  53.      * @param absoluteAccuracy Absolute accuracy of the result.
  54.      * @param minimalIterationCount Minimum number of iterations.
  55.      * @param maximalIterationCount Maximum number of iterations.
  56.      * @throws NotStrictlyPositiveException if minimal number of iterations
  57.      * or number of points are not strictly positive.
  58.      * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException
  59.      * if the maximal number of iterations is smaller than or equal to the
  60.      * minimal number of iterations.
  61.      */
  62.     public IterativeLegendreGaussIntegrator(final int n,
  63.                                             final double relativeAccuracy,
  64.                                             final double absoluteAccuracy,
  65.                                             final int minimalIterationCount,
  66.                                             final int maximalIterationCount) {
  67.         super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
  68.         if (n <= 0) {
  69.             throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_POINTS, n);
  70.         }
  71.        numberOfPoints = n;
  72.     }

  73.     /**
  74.      * Builds an integrator with given accuracies.
  75.      *
  76.      * @param n Number of integration points.
  77.      * @param relativeAccuracy Relative accuracy of the result.
  78.      * @param absoluteAccuracy Absolute accuracy of the result.
  79.      * @throws NotStrictlyPositiveException if {@code n < 1}.
  80.      */
  81.     public IterativeLegendreGaussIntegrator(final int n,
  82.                                             final double relativeAccuracy,
  83.                                             final double absoluteAccuracy) {
  84.         this(n, relativeAccuracy, absoluteAccuracy,
  85.              DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT);
  86.     }

  87.     /**
  88.      * Builds an integrator with given iteration counts.
  89.      *
  90.      * @param n Number of integration points.
  91.      * @param minimalIterationCount Minimum number of iterations.
  92.      * @param maximalIterationCount Maximum number of iterations.
  93.      * @throws NotStrictlyPositiveException if minimal number of iterations
  94.      * is not strictly positive.
  95.      * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException
  96.      * if the maximal number of iterations is smaller than or equal to the
  97.      * minimal number of iterations.
  98.      * @throws NotStrictlyPositiveException if {@code n < 1}.
  99.      */
  100.     public IterativeLegendreGaussIntegrator(final int n,
  101.                                             final int minimalIterationCount,
  102.                                             final int maximalIterationCount) {
  103.         this(n, DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY,
  104.              minimalIterationCount, maximalIterationCount);
  105.     }

  106.     /** {@inheritDoc} */
  107.     @Override
  108.     protected double doIntegrate() {
  109.         // Compute first estimate with a single step.
  110.         double oldt = stage(1);

  111.         int n = 2;
  112.         while (true) {
  113.             // Improve integral with a larger number of steps.
  114.             final double t = stage(n);

  115.             // Estimate the error.
  116.             final double delta = JdkMath.abs(t - oldt);
  117.             final double limit =
  118.                 JdkMath.max(getAbsoluteAccuracy(),
  119.                              getRelativeAccuracy() * (JdkMath.abs(oldt) + JdkMath.abs(t)) * 0.5);

  120.             // check convergence
  121.             if (iterations.getCount() + 1 >= getMinimalIterationCount() &&
  122.                 delta <= limit) {
  123.                 return t;
  124.             }

  125.             // Prepare next iteration.
  126.             final double ratio = JdkMath.min(4, JdkMath.pow(delta / limit, 0.5 / numberOfPoints));
  127.             n = JdkMath.max((int) (ratio * n), n + 1);
  128.             oldt = t;
  129.             iterations.increment();
  130.         }
  131.     }

  132.     /**
  133.      * Compute the n-th stage integral.
  134.      *
  135.      * @param n Number of steps.
  136.      * @return the value of n-th stage integral.
  137.      * @throws TooManyEvaluationsException if the maximum number of evaluations
  138.      * is exceeded.
  139.      */
  140.     private double stage(final int n)
  141.         throws TooManyEvaluationsException {
  142.         // Function to be integrated is stored in the base class.
  143.         final UnivariateFunction f = new UnivariateFunction() {
  144.                 /** {@inheritDoc} */
  145.                 @Override
  146.                 public double value(double x) {
  147.                     return computeObjectiveValue(x);
  148.                 }
  149.             };

  150.         final double min = getMin();
  151.         final double max = getMax();
  152.         final double step = (max - min) / n;

  153.         double sum = 0;
  154.         for (int i = 0; i < n; i++) {
  155.             // Integrate over each sub-interval [a, b].
  156.             final double a = min + i * step;
  157.             final double b = a + step;
  158.             final GaussIntegrator g = FACTORY.legendreHighPrecision(numberOfPoints, a, b);
  159.             sum += g.integrate(f);
  160.         }

  161.         return sum;
  162.     }
  163. }