MidPointIntegrator.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.numbers.core.ArithmeticUtils;
  19. import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
  20. import org.apache.commons.math4.core.jdkmath.JdkMath;

  21. /**
  22.  * Implements the <a href="https://en.wikipedia.org/wiki/Riemann_sum#Midpoint_rule">
  23.  * Midpoint Rule</a> for integration of real univariate functions. For
  24.  * reference, see <b>Numerical Mathematics</b>, ISBN 0387989595,
  25.  * chapter 9.2.
  26.  * <p>
  27.  * The function should be integrable.</p>
  28.  *
  29.  * @since 3.3
  30.  */
  31. public class MidPointIntegrator extends BaseAbstractUnivariateIntegrator {

  32.     /** Maximum number of iterations for midpoint. 39 = floor(log_3(2^63)), the
  33.      * maximum number of triplings allowed before exceeding 64-bit bounds.
  34.      */
  35.     private static final int MIDPOINT_MAX_ITERATIONS_COUNT = 39;

  36.     /**
  37.      * Build a midpoint integrator with given accuracies and iterations counts.
  38.      * @param relativeAccuracy relative accuracy of the result
  39.      * @param absoluteAccuracy absolute accuracy of the result
  40.      * @param minimalIterationCount minimum number of iterations
  41.      * @param maximalIterationCount maximum number of iterations
  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 39.
  48.      */
  49.     public MidPointIntegrator(final double relativeAccuracy,
  50.                               final double absoluteAccuracy,
  51.                               final int minimalIterationCount,
  52.                               final int maximalIterationCount) {
  53.         super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
  54.         if (maximalIterationCount > MIDPOINT_MAX_ITERATIONS_COUNT) {
  55.             throw new NumberIsTooLargeException(maximalIterationCount,
  56.                                                 MIDPOINT_MAX_ITERATIONS_COUNT, false);
  57.         }
  58.     }

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

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

  85.     /**
  86.      * Compute the n-th stage integral of midpoint rule.
  87.      * This function should only be called by API <code>integrate()</code> in the package.
  88.      * To save time it does not verify arguments - caller does.
  89.      * <p>
  90.      * The interval is divided equally into 3^n sections rather than an
  91.      * arbitrary m sections because this configuration can best utilize the
  92.      * already computed values.</p>
  93.      *
  94.      * @param n the stage of 1/3 refinement. Must be larger than 0.
  95.      * @param previousStageResult Result from the previous call to the
  96.      * {@code stage} method.
  97.      * @param min Lower bound of the integration interval.
  98.      * @param diffMaxMin Difference between the lower bound and upper bound
  99.      * of the integration interval.
  100.      * @return the value of n-th stage integral
  101.      * @throws org.apache.commons.math4.legacy.exception.TooManyEvaluationsException if the maximal number of evaluations
  102.      * is exceeded.
  103.      */
  104.     private double stage(final int n,
  105.                          double previousStageResult,
  106.                          double min,
  107.                          double diffMaxMin) {
  108.         // number of points in the previous stage. This stage will contribute
  109.         // 2*3^{n-1} more points.
  110.         final long np = ArithmeticUtils.pow(3L, n - 1);
  111.         double sum = 0;

  112.         // spacing between adjacent new points
  113.         final double spacing = diffMaxMin / np;
  114.         final double leftOffset = spacing / 6;
  115.         final double rightOffset = 5 * leftOffset;

  116.         double x = min;
  117.         for (long i = 0; i < np; i++) {
  118.             // The first and second new points are located at the new midpoints
  119.             // generated when each previous integration slice is split into 3.
  120.             //
  121.             // |--------x--------|
  122.             // |--x--|--x--|--x--|
  123.             sum += computeObjectiveValue(x + leftOffset);
  124.             sum += computeObjectiveValue(x + rightOffset);
  125.             x += spacing;
  126.         }
  127.         // add the new sum to previously calculated result
  128.         return (previousStageResult + sum * spacing) / 3.0;
  129.     }


  130.     /** {@inheritDoc} */
  131.     @Override
  132.     protected double doIntegrate() {
  133.         final double min = getMin();
  134.         final double diff = getMax() - min;
  135.         final double midPoint = min + 0.5 * diff;

  136.         double oldt = diff * computeObjectiveValue(midPoint);

  137.         while (true) {
  138.             iterations.increment();
  139.             final int i = iterations.getCount();
  140.             final double t = stage(i, oldt, min, diff);
  141.             if (i >= getMinimalIterationCount()) {
  142.                 final double delta = JdkMath.abs(t - oldt);
  143.                 final double rLimit =
  144.                         getRelativeAccuracy() * (JdkMath.abs(oldt) + JdkMath.abs(t)) * 0.5;
  145.                 if (delta <= rLimit || delta <= getAbsoluteAccuracy()) {
  146.                     return t;
  147.                 }
  148.             }
  149.             oldt = t;
  150.         }
  151.     }
  152. }