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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.analysis.integration;

  22. import org.hipparchus.analysis.UnivariateFunction;
  23. import org.hipparchus.analysis.integration.gauss.GaussIntegrator;
  24. import org.hipparchus.analysis.integration.gauss.GaussIntegratorFactory;
  25. import org.hipparchus.exception.LocalizedCoreFormats;
  26. import org.hipparchus.exception.MathIllegalArgumentException;
  27. import org.hipparchus.exception.MathIllegalStateException;
  28. import org.hipparchus.util.FastMath;

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

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

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

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

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

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     protected double doIntegrate()
  113.         throws MathIllegalArgumentException, MathIllegalStateException {
  114.         // Compute first estimate with a single step.
  115.         double oldt = stage(1);

  116.         int n = 2;
  117.         while (true) {
  118.             // Improve integral with a larger number of steps.
  119.             final double t = stage(n);

  120.             // Estimate the error.
  121.             final double delta = FastMath.abs(t - oldt);
  122.             final double limit =
  123.                 FastMath.max(getAbsoluteAccuracy(),
  124.                              getRelativeAccuracy() * (FastMath.abs(oldt) + FastMath.abs(t)) * 0.5);

  125.             // check convergence
  126.             if (iterations.getCount() + 1 >= getMinimalIterationCount() &&
  127.                 delta <= limit) {
  128.                 return t;
  129.             }

  130.             // Prepare next iteration.
  131.             final double ratio = FastMath.min(4, FastMath.pow(delta / limit, 0.5 / numberOfPoints));
  132.             n = FastMath.max((int) (ratio * n), n + 1);
  133.             oldt = t;
  134.             iterations.increment();
  135.         }
  136.     }

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

  156.         final double min = getMin();
  157.         final double max = getMax();
  158.         final double step = (max - min) / n;

  159.         double sum = 0;
  160.         for (int i = 0; i < n; i++) {
  161.             // Integrate over each sub-interval [a, b].
  162.             final double a = min + i * step;
  163.             final double b = a + step;
  164.             final GaussIntegrator g = FACTORY.legendreHighPrecision(numberOfPoints, a, b);
  165.             sum += g.integrate(f);
  166.         }

  167.         return sum;
  168.     }
  169. }