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/TrapezoidalRule.html"> 24 * Trapezoid Rule</a> for integration of real univariate functions. 25 * 26 * See <b>Introduction to Numerical Analysis</b>, ISBN 038795452X, chapter 3. 27 * 28 * <p> 29 * The function should be integrable. 30 * 31 * <p> 32 * <em>Caveat:</em> At each iteration, the algorithm refines the estimation by 33 * evaluating the function twice as many times as in the previous iteration; 34 * When specifying a {@link #integrate(int,UnivariateFunction,double,double) 35 * maximum number of function evaluations}, the caller must ensure that it 36 * is compatible with the {@link #TrapezoidIntegrator(int,int) requested 37 * minimal number of iterations}. 38 * 39 * @since 1.2 40 */ 41 public class TrapezoidIntegrator extends BaseAbstractUnivariateIntegrator { 42 /** Maximum number of iterations for trapezoid. */ 43 private static final int TRAPEZOID_MAX_ITERATIONS_COUNT = 30; 44 45 /** Intermediate result. */ 46 private double s; 47 48 /** 49 * Build a trapezoid integrator with given accuracies and iterations counts. 50 * @param relativeAccuracy relative accuracy of the result 51 * @param absoluteAccuracy absolute accuracy of the result 52 * @param minimalIterationCount minimum number of iterations 53 * @param maximalIterationCount maximum number of iterations 54 * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException 55 * if {@code minimalIterationCount <= 0}. 56 * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException 57 * if {@code maximalIterationCount < minimalIterationCount}. 58 * is lesser than or equal to the minimal number of iterations 59 * @throws NumberIsTooLargeException if {@code maximalIterationCount > 30}. 60 */ 61 public TrapezoidIntegrator(final double relativeAccuracy, 62 final double absoluteAccuracy, 63 final int minimalIterationCount, 64 final int maximalIterationCount) { 65 super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount); 66 if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) { 67 throw new NumberIsTooLargeException(maximalIterationCount, 68 TRAPEZOID_MAX_ITERATIONS_COUNT, false); 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 * @throws org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException 77 * if {@code minimalIterationCount <= 0}. 78 * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException 79 * if {@code maximalIterationCount < minimalIterationCount}. 80 * is lesser than or equal to the minimal number of iterations 81 * @throws NumberIsTooLargeException if {@code maximalIterationCount > 30}. 82 */ 83 public TrapezoidIntegrator(final int minimalIterationCount, 84 final int maximalIterationCount) { 85 super(minimalIterationCount, maximalIterationCount); 86 if (maximalIterationCount > TRAPEZOID_MAX_ITERATIONS_COUNT) { 87 throw new NumberIsTooLargeException(maximalIterationCount, 88 TRAPEZOID_MAX_ITERATIONS_COUNT, false); 89 } 90 } 91 92 /** 93 * Construct a trapezoid integrator with default settings. 94 */ 95 public TrapezoidIntegrator() { 96 super(DEFAULT_MIN_ITERATIONS_COUNT, TRAPEZOID_MAX_ITERATIONS_COUNT); 97 } 98 99 /** 100 * Compute the n-th stage integral of trapezoid rule. This function 101 * should only be called by API <code>integrate()</code> in the package. 102 * To save time it does not verify arguments - caller does. 103 * <p> 104 * The interval is divided equally into 2^n sections rather than an 105 * arbitrary m sections because this configuration can best utilize the 106 * already computed values.</p> 107 * 108 * @param baseIntegrator integrator holding integration parameters 109 * @param n the stage of 1/2 refinement, n = 0 is no refinement 110 * @return the value of n-th stage integral 111 * @throws org.apache.commons.math4.legacy.exception.TooManyEvaluationsException if the maximal number of evaluations 112 * is exceeded. 113 */ 114 double stage(final BaseAbstractUnivariateIntegrator baseIntegrator, final int n) { 115 if (n == 0) { 116 final double max = baseIntegrator.getMax(); 117 final double min = baseIntegrator.getMin(); 118 s = 0.5 * (max - min) * 119 (baseIntegrator.computeObjectiveValue(min) + 120 baseIntegrator.computeObjectiveValue(max)); 121 return s; 122 } else { 123 final long np = 1L << (n-1); // number of new points in this stage 124 double sum = 0; 125 final double max = baseIntegrator.getMax(); 126 final double min = baseIntegrator.getMin(); 127 // spacing between adjacent new points 128 final double spacing = (max - min) / np; 129 double x = min + 0.5 * spacing; // the first new point 130 for (long i = 0; i < np; i++) { 131 sum += baseIntegrator.computeObjectiveValue(x); 132 x += spacing; 133 } 134 // add the new sum to previously calculated result 135 s = 0.5 * (s + sum * spacing); 136 return s; 137 } 138 } 139 140 /** {@inheritDoc} */ 141 @Override 142 protected double doIntegrate() { 143 double oldt = stage(this, 0); 144 iterations.increment(); 145 while (true) { 146 final int i = iterations.getCount(); 147 final double t = stage(this, i); 148 if (i >= getMinimalIterationCount()) { 149 final double delta = JdkMath.abs(t - oldt); 150 final double rLimit = 151 getRelativeAccuracy() * (JdkMath.abs(oldt) + JdkMath.abs(t)) * 0.5; 152 if (delta <= rLimit || delta <= getAbsoluteAccuracy()) { 153 return t; 154 } 155 } 156 oldt = t; 157 iterations.increment(); 158 } 159 } 160 }