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    *      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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.analysis.integration;
23  
24  import org.hipparchus.exception.LocalizedCoreFormats;
25  import org.hipparchus.exception.MathIllegalArgumentException;
26  import org.hipparchus.exception.MathIllegalStateException;
27  import org.hipparchus.util.FastMath;
28  
29  /**
30   * Implements the <a href="http://mathworld.wolfram.com/TrapezoidalRule.html">
31   * Trapezoid Rule</a> for integration of real univariate functions. For
32   * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
33   * chapter 3.
34   * <p>
35   * The function should be integrable.</p>
36   *
37   */
38  public class TrapezoidIntegrator extends BaseAbstractUnivariateIntegrator {
39  
40      /** Maximum number of iterations for trapezoid. */
41      public static final int TRAPEZOID_MAX_ITERATIONS_COUNT = 64;
42  
43      /** Intermediate result. */
44      private double s;
45  
46      /**
47       * Build a trapezoid integrator with given accuracies and iterations counts.
48       * @param relativeAccuracy relative accuracy of the result
49       * @param absoluteAccuracy absolute accuracy of the result
50       * @param minimalIterationCount minimum number of iterations
51       * @param maximalIterationCount maximum number of iterations
52       * (must be less than or equal to {@link #TRAPEZOID_MAX_ITERATIONS_COUNT}
53       * @exception MathIllegalArgumentException if minimal number of iterations
54       * is not strictly positive
55       * @exception MathIllegalArgumentException if maximal number of iterations
56       * is lesser than or equal to the minimal number of iterations
57       * @exception MathIllegalArgumentException if maximal number of iterations
58       * is greater than {@link #TRAPEZOID_MAX_ITERATIONS_COUNT}
59       */
60      public TrapezoidIntegrator(final double relativeAccuracy,
61                                 final double absoluteAccuracy,
62                                 final int minimalIterationCount,
63                                 final int maximalIterationCount)
64          throws MathIllegalArgumentException {
65          super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
66          if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) {
67              throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
68                                                     maximalIterationCount, TRAPEZOID_MAX_ITERATIONS_COUNT);
69          }
70      }
71  
72      /**
73       * Build a trapezoid integrator with given iteration counts.
74       * @param minimalIterationCount minimum number of iterations
75       * @param maximalIterationCount maximum number of iterations
76       * (must be less than or equal to {@link #TRAPEZOID_MAX_ITERATIONS_COUNT}
77       * @exception MathIllegalArgumentException if minimal number of iterations
78       * is not strictly positive
79       * @exception MathIllegalArgumentException if maximal number of iterations
80       * is lesser than or equal to the minimal number of iterations
81       * @exception MathIllegalArgumentException if maximal number of iterations
82       * is greater than {@link #TRAPEZOID_MAX_ITERATIONS_COUNT}
83       */
84      public TrapezoidIntegrator(final int minimalIterationCount,
85                                 final int maximalIterationCount)
86          throws MathIllegalArgumentException {
87          super(minimalIterationCount, maximalIterationCount);
88          if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) {
89              throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE_BOUND_EXCLUDED,
90                                                     maximalIterationCount, TRAPEZOID_MAX_ITERATIONS_COUNT);
91          }
92      }
93  
94      /**
95       * Construct a trapezoid integrator with default settings.
96       * (max iteration count set to {@link #TRAPEZOID_MAX_ITERATIONS_COUNT})
97       */
98      public TrapezoidIntegrator() {
99          super(DEFAULT_MIN_ITERATIONS_COUNT, TRAPEZOID_MAX_ITERATIONS_COUNT);
100     }
101 
102     /**
103      * Compute the n-th stage integral of trapezoid rule. This function
104      * should only be called by API <code>integrate()</code> in the package.
105      * To save time it does not verify arguments - caller does.
106      * <p>
107      * The interval is divided equally into 2^n sections rather than an
108      * arbitrary m sections because this configuration can best utilize the
109      * already computed values.</p>
110      *
111      * @param baseIntegrator integrator holding integration parameters
112      * @param n the stage of 1/2 refinement, n = 0 is no refinement
113      * @return the value of n-th stage integral
114      * @throws MathIllegalStateException if the maximal number of evaluations
115      * is exceeded.
116      */
117     double stage(final BaseAbstractUnivariateIntegrator baseIntegrator, final int n)
118         throws MathIllegalStateException {
119 
120         if (n == 0) {
121             final double max = baseIntegrator.getMax();
122             final double min = baseIntegrator.getMin();
123             s = 0.5 * (max - min) *
124                       (baseIntegrator.computeObjectiveValue(min) +
125                        baseIntegrator.computeObjectiveValue(max));
126             return s;
127         } else {
128             final long np = 1L << (n-1);           // number of new points in this stage
129             double sum = 0;
130             final double max = baseIntegrator.getMax();
131             final double min = baseIntegrator.getMin();
132             // spacing between adjacent new points
133             final double spacing = (max - min) / np;
134             double x = min + 0.5 * spacing;    // the first new point
135             for (long i = 0; i < np; i++) {
136                 sum += baseIntegrator.computeObjectiveValue(x);
137                 x += spacing;
138             }
139             // add the new sum to previously calculated result
140             s = 0.5 * (s + sum * spacing);
141             return s;
142         }
143     }
144 
145     /** {@inheritDoc} */
146     @Override
147     protected double doIntegrate()
148         throws MathIllegalArgumentException, MathIllegalStateException {
149 
150         double oldt = stage(this, 0);
151         iterations.increment();
152         while (true) {
153             final int i = iterations.getCount();
154             final double t = stage(this, i);
155             if (i >= getMinimalIterationCount()) {
156                 final double delta = FastMath.abs(t - oldt);
157                 final double rLimit =
158                     getRelativeAccuracy() * (FastMath.abs(oldt) + FastMath.abs(t)) * 0.5;
159                 if ((delta <= rLimit) || (delta <= getAbsoluteAccuracy())) {
160                     return t;
161                 }
162             }
163             oldt = t;
164             iterations.increment();
165         }
166 
167     }
168 
169 }