RombergIntegrator.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.exception.NumberIsTooLargeException;
  19. import org.apache.commons.math4.core.jdkmath.JdkMath;

  20. /**
  21.  * Implements the <a href="http://mathworld.wolfram.com/RombergIntegration.html">
  22.  * Romberg Algorithm</a> for integration of real univariate functions. For
  23.  * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
  24.  * chapter 3.
  25.  * <p>
  26.  * Romberg integration employs k successive refinements of the trapezoid
  27.  * rule to remove error terms less than order O(N^(-2k)). Simpson's rule
  28.  * is a special case of k = 2.</p>
  29.  *
  30.  * @since 1.2
  31.  */
  32. public class RombergIntegrator extends BaseAbstractUnivariateIntegrator {

  33.     /** Maximal number of iterations for Romberg. */
  34.     public static final int ROMBERG_MAX_ITERATIONS_COUNT = 32;

  35.     /**
  36.      * Build a Romberg integrator with given accuracies and iterations counts.
  37.      * @param relativeAccuracy relative accuracy of the result
  38.      * @param absoluteAccuracy absolute accuracy of the result
  39.      * @param minimalIterationCount minimum number of iterations
  40.      * @param maximalIterationCount maximum number of iterations
  41.      * (must be less than or equal to {@link #ROMBERG_MAX_ITERATIONS_COUNT})
  42.      * @exception org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if minimal number of iterations
  43.      * is not strictly positive
  44.      * @exception org.apache.commons.math4.legacy.exception.NumberIsTooSmallException if maximal number of iterations
  45.      * is lesser than or equal to the minimal number of iterations
  46.      * @exception NumberIsTooLargeException if maximal number of iterations
  47.      * is greater than {@link #ROMBERG_MAX_ITERATIONS_COUNT}
  48.      */
  49.     public RombergIntegrator(final double relativeAccuracy,
  50.                              final double absoluteAccuracy,
  51.                              final int minimalIterationCount,
  52.                              final int maximalIterationCount) {
  53.         super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
  54.         if (maximalIterationCount > ROMBERG_MAX_ITERATIONS_COUNT) {
  55.             throw new NumberIsTooLargeException(maximalIterationCount,
  56.                                                 ROMBERG_MAX_ITERATIONS_COUNT, false);
  57.         }
  58.     }

  59.     /**
  60.      * Build a Romberg integrator with given iteration counts.
  61.      * @param minimalIterationCount minimum number of iterations
  62.      * @param maximalIterationCount maximum number of iterations
  63.      * (must be less than or equal to {@link #ROMBERG_MAX_ITERATIONS_COUNT})
  64.      * @exception org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if minimal number of iterations
  65.      * is not strictly positive
  66.      * @exception org.apache.commons.math4.legacy.exception.NumberIsTooSmallException if maximal number of iterations
  67.      * is lesser than or equal to the minimal number of iterations
  68.      * @exception NumberIsTooLargeException if maximal number of iterations
  69.      * is greater than {@link #ROMBERG_MAX_ITERATIONS_COUNT}
  70.      */
  71.     public RombergIntegrator(final int minimalIterationCount,
  72.                              final int maximalIterationCount) {
  73.         super(minimalIterationCount, maximalIterationCount);
  74.         if (maximalIterationCount > ROMBERG_MAX_ITERATIONS_COUNT) {
  75.             throw new NumberIsTooLargeException(maximalIterationCount,
  76.                                                 ROMBERG_MAX_ITERATIONS_COUNT, false);
  77.         }
  78.     }

  79.     /**
  80.      * Construct a Romberg integrator with default settings
  81.      * (max iteration count set to {@link #ROMBERG_MAX_ITERATIONS_COUNT}).
  82.      */
  83.     public RombergIntegrator() {
  84.         super(DEFAULT_MIN_ITERATIONS_COUNT, ROMBERG_MAX_ITERATIONS_COUNT);
  85.     }

  86.     /** {@inheritDoc} */
  87.     @Override
  88.     protected double doIntegrate() {
  89.         final int m = iterations.getMaximalCount() + 1;
  90.         double[] previousRow = new double[m];
  91.         double[] currentRow = new double[m];

  92.         TrapezoidIntegrator qtrap = new TrapezoidIntegrator();
  93.         currentRow[0] = qtrap.stage(this, 0);
  94.         iterations.increment();
  95.         double olds = currentRow[0];
  96.         while (true) {

  97.             final int i = iterations.getCount();

  98.             // switch rows
  99.             final double[] tmpRow = previousRow;
  100.             previousRow = currentRow;
  101.             currentRow = tmpRow;

  102.             currentRow[0] = qtrap.stage(this, i);
  103.             iterations.increment();
  104.             for (int j = 1; j <= i; j++) {
  105.                 // Richardson extrapolation coefficient
  106.                 final double r = (1L << (2 * j)) - 1;
  107.                 final double tIJm1 = currentRow[j - 1];
  108.                 currentRow[j] = tIJm1 + (tIJm1 - previousRow[j - 1]) / r;
  109.             }
  110.             final double s = currentRow[i];
  111.             if (i >= getMinimalIterationCount()) {
  112.                 final double delta  = JdkMath.abs(s - olds);
  113.                 final double rLimit = getRelativeAccuracy() * (JdkMath.abs(olds) + JdkMath.abs(s)) * 0.5;
  114.                 if (delta <= rLimit || delta <= getAbsoluteAccuracy()) {
  115.                     return s;
  116.                 }
  117.             }
  118.             olds = s;
  119.         }
  120.     }
  121. }