View Javadoc
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  
19  import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
20  import org.apache.commons.math4.core.jdkmath.JdkMath;
21  
22  /**
23   * Implements the <a href="http://mathworld.wolfram.com/RombergIntegration.html">
24   * Romberg Algorithm</a> for integration of real univariate functions. For
25   * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
26   * chapter 3.
27   * <p>
28   * Romberg integration employs k successive refinements of the trapezoid
29   * rule to remove error terms less than order O(N^(-2k)). Simpson's rule
30   * is a special case of k = 2.</p>
31   *
32   * @since 1.2
33   */
34  public class RombergIntegrator extends BaseAbstractUnivariateIntegrator {
35  
36      /** Maximal number of iterations for Romberg. */
37      public static final int ROMBERG_MAX_ITERATIONS_COUNT = 32;
38  
39      /**
40       * Build a Romberg integrator with given accuracies and iterations counts.
41       * @param relativeAccuracy relative accuracy of the result
42       * @param absoluteAccuracy absolute accuracy of the result
43       * @param minimalIterationCount minimum number of iterations
44       * @param maximalIterationCount maximum number of iterations
45       * (must be less than or equal to {@link #ROMBERG_MAX_ITERATIONS_COUNT})
46       * @exception org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if minimal number of iterations
47       * is not strictly positive
48       * @exception org.apache.commons.math4.legacy.exception.NumberIsTooSmallException if maximal number of iterations
49       * is lesser than or equal to the minimal number of iterations
50       * @exception NumberIsTooLargeException if maximal number of iterations
51       * is greater than {@link #ROMBERG_MAX_ITERATIONS_COUNT}
52       */
53      public RombergIntegrator(final double relativeAccuracy,
54                               final double absoluteAccuracy,
55                               final int minimalIterationCount,
56                               final int maximalIterationCount) {
57          super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
58          if (maximalIterationCount > ROMBERG_MAX_ITERATIONS_COUNT) {
59              throw new NumberIsTooLargeException(maximalIterationCount,
60                                                  ROMBERG_MAX_ITERATIONS_COUNT, false);
61          }
62      }
63  
64      /**
65       * Build a Romberg integrator with given iteration counts.
66       * @param minimalIterationCount minimum number of iterations
67       * @param maximalIterationCount maximum number of iterations
68       * (must be less than or equal to {@link #ROMBERG_MAX_ITERATIONS_COUNT})
69       * @exception org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException if minimal number of iterations
70       * is not strictly positive
71       * @exception org.apache.commons.math4.legacy.exception.NumberIsTooSmallException if maximal number of iterations
72       * is lesser than or equal to the minimal number of iterations
73       * @exception NumberIsTooLargeException if maximal number of iterations
74       * is greater than {@link #ROMBERG_MAX_ITERATIONS_COUNT}
75       */
76      public RombergIntegrator(final int minimalIterationCount,
77                               final int maximalIterationCount) {
78          super(minimalIterationCount, maximalIterationCount);
79          if (maximalIterationCount > ROMBERG_MAX_ITERATIONS_COUNT) {
80              throw new NumberIsTooLargeException(maximalIterationCount,
81                                                  ROMBERG_MAX_ITERATIONS_COUNT, false);
82          }
83      }
84  
85      /**
86       * Construct a Romberg integrator with default settings
87       * (max iteration count set to {@link #ROMBERG_MAX_ITERATIONS_COUNT}).
88       */
89      public RombergIntegrator() {
90          super(DEFAULT_MIN_ITERATIONS_COUNT, ROMBERG_MAX_ITERATIONS_COUNT);
91      }
92  
93      /** {@inheritDoc} */
94      @Override
95      protected double doIntegrate() {
96          final int m = iterations.getMaximalCount() + 1;
97          double[] previousRow = new double[m];
98          double[] currentRow = new double[m];
99  
100         TrapezoidIntegrator qtrap = new TrapezoidIntegrator();
101         currentRow[0] = qtrap.stage(this, 0);
102         iterations.increment();
103         double olds = currentRow[0];
104         while (true) {
105 
106             final int i = iterations.getCount();
107 
108             // switch rows
109             final double[] tmpRow = previousRow;
110             previousRow = currentRow;
111             currentRow = tmpRow;
112 
113             currentRow[0] = qtrap.stage(this, i);
114             iterations.increment();
115             for (int j = 1; j <= i; j++) {
116                 // Richardson extrapolation coefficient
117                 final double r = (1L << (2 * j)) - 1;
118                 final double tIJm1 = currentRow[j - 1];
119                 currentRow[j] = tIJm1 + (tIJm1 - previousRow[j - 1]) / r;
120             }
121             final double s = currentRow[i];
122             if (i >= getMinimalIterationCount()) {
123                 final double delta  = JdkMath.abs(s - olds);
124                 final double rLimit = getRelativeAccuracy() * (JdkMath.abs(olds) + JdkMath.abs(s)) * 0.5;
125                 if (delta <= rLimit || delta <= getAbsoluteAccuracy()) {
126                     return s;
127                 }
128             }
129             olds = s;
130         }
131     }
132 }