TrapezoidIntegrator.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/TrapezoidalRule.html">
  22.  * Trapezoid Rule</a> for integration of real univariate functions.
  23.  *
  24.  * See <b>Introduction to Numerical Analysis</b>, ISBN 038795452X, chapter 3.
  25.  *
  26.  * <p>
  27.  * The function should be integrable.
  28.  *
  29.  * <p>
  30.  * <em>Caveat:</em> At each iteration, the algorithm refines the estimation by
  31.  * evaluating the function twice as many times as in the previous iteration;
  32.  * When specifying a {@link #integrate(int,UnivariateFunction,double,double)
  33.  * maximum number of function evaluations}, the caller must ensure that it
  34.  * is compatible with the {@link #TrapezoidIntegrator(int,int) requested
  35.  * minimal number of iterations}.
  36.  *
  37.  * @since 1.2
  38.  */
  39. public class TrapezoidIntegrator extends BaseAbstractUnivariateIntegrator {
  40.     /** Maximum number of iterations for trapezoid. */
  41.     private static final int TRAPEZOID_MAX_ITERATIONS_COUNT = 30;

  42.     /** Intermediate result. */
  43.     private double s;

  44.     /**
  45.      * Build a trapezoid integrator with given accuracies and iterations counts.
  46.      * @param relativeAccuracy relative accuracy of the result
  47.      * @param absoluteAccuracy absolute accuracy of the result
  48.      * @param minimalIterationCount minimum number of iterations
  49.      * @param maximalIterationCount maximum number of iterations
  50.      * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
  51.      * if {@code minimalIterationCount <= 0}.
  52.      * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException
  53.      * if {@code maximalIterationCount < minimalIterationCount}.
  54.      * is lesser than or equal to the minimal number of iterations
  55.      * @throws NumberIsTooLargeException if {@code maximalIterationCount > 30}.
  56.      */
  57.     public TrapezoidIntegrator(final double relativeAccuracy,
  58.                                final double absoluteAccuracy,
  59.                                final int minimalIterationCount,
  60.                                final int maximalIterationCount) {
  61.         super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
  62.         if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) {
  63.             throw new NumberIsTooLargeException(maximalIterationCount,
  64.                                                 TRAPEZOID_MAX_ITERATIONS_COUNT, false);
  65.         }
  66.     }

  67.     /**
  68.      * Build a trapezoid integrator with given iteration counts.
  69.      * @param minimalIterationCount minimum number of iterations
  70.      * @param maximalIterationCount maximum number of iterations
  71.      * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException
  72.      * if {@code minimalIterationCount <= 0}.
  73.      * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException
  74.      * if {@code maximalIterationCount < minimalIterationCount}.
  75.      * is lesser than or equal to the minimal number of iterations
  76.      * @throws NumberIsTooLargeException if {@code maximalIterationCount > 30}.
  77.      */
  78.     public TrapezoidIntegrator(final int minimalIterationCount,
  79.                                final int maximalIterationCount) {
  80.         super(minimalIterationCount, maximalIterationCount);
  81.         if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) {
  82.             throw new NumberIsTooLargeException(maximalIterationCount,
  83.                                                 TRAPEZOID_MAX_ITERATIONS_COUNT, false);
  84.         }
  85.     }

  86.     /**
  87.      * Construct a trapezoid integrator with default settings.
  88.      */
  89.     public TrapezoidIntegrator() {
  90.         super(DEFAULT_MIN_ITERATIONS_COUNT, TRAPEZOID_MAX_ITERATIONS_COUNT);
  91.     }

  92.     /**
  93.      * Compute the n-th stage integral of trapezoid rule. This function
  94.      * should only be called by API <code>integrate()</code> in the package.
  95.      * To save time it does not verify arguments - caller does.
  96.      * <p>
  97.      * The interval is divided equally into 2^n sections rather than an
  98.      * arbitrary m sections because this configuration can best utilize the
  99.      * already computed values.</p>
  100.      *
  101.      * @param baseIntegrator integrator holding integration parameters
  102.      * @param n the stage of 1/2 refinement, n = 0 is no refinement
  103.      * @return the value of n-th stage integral
  104.      * @throws org.apache.commons.math4.legacy.exception.TooManyEvaluationsException if the maximal number of evaluations
  105.      * is exceeded.
  106.      */
  107.     double stage(final BaseAbstractUnivariateIntegrator baseIntegrator, final int n) {
  108.         if (n == 0) {
  109.             final double max = baseIntegrator.getMax();
  110.             final double min = baseIntegrator.getMin();
  111.             s = 0.5 * (max - min) *
  112.                       (baseIntegrator.computeObjectiveValue(min) +
  113.                        baseIntegrator.computeObjectiveValue(max));
  114.             return s;
  115.         } else {
  116.             final long np = 1L << (n-1);           // number of new points in this stage
  117.             double sum = 0;
  118.             final double max = baseIntegrator.getMax();
  119.             final double min = baseIntegrator.getMin();
  120.             // spacing between adjacent new points
  121.             final double spacing = (max - min) / np;
  122.             double x = min + 0.5 * spacing;    // the first new point
  123.             for (long i = 0; i < np; i++) {
  124.                 sum += baseIntegrator.computeObjectiveValue(x);
  125.                 x += spacing;
  126.             }
  127.             // add the new sum to previously calculated result
  128.             s = 0.5 * (s + sum * spacing);
  129.             return s;
  130.         }
  131.     }

  132.     /** {@inheritDoc} */
  133.     @Override
  134.     protected double doIntegrate() {
  135.         double oldt = stage(this, 0);
  136.         iterations.increment();
  137.         while (true) {
  138.             final int i = iterations.getCount();
  139.             final double t = stage(this, i);
  140.             if (i >= getMinimalIterationCount()) {
  141.                 final double delta = JdkMath.abs(t - oldt);
  142.                 final double rLimit =
  143.                     getRelativeAccuracy() * (JdkMath.abs(oldt) + JdkMath.abs(t)) * 0.5;
  144.                 if (delta <= rLimit || delta <= getAbsoluteAccuracy()) {
  145.                     return t;
  146.                 }
  147.             }
  148.             oldt = t;
  149.             iterations.increment();
  150.         }
  151.     }
  152. }