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.analysis.UnivariateFunction; 20 import org.apache.commons.math4.legacy.analysis.integration.gauss.GaussIntegrator; 21 import org.apache.commons.math4.legacy.analysis.integration.gauss.GaussIntegratorFactory; 22 import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; 23 import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException; 24 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; 25 import org.apache.commons.math4.core.jdkmath.JdkMath; 26 27 /** 28 * This algorithm divides the integration interval into equally-sized 29 * sub-interval and on each of them performs a 30 * <a href="http://mathworld.wolfram.com/Legendre-GaussQuadrature.html"> 31 * Legendre-Gauss</a> quadrature. 32 * Because of its <em>non-adaptive</em> nature, this algorithm can 33 * converge to a wrong value for the integral (for example, if the 34 * function is significantly different from zero toward the ends of the 35 * integration interval). 36 * In particular, a change of variables aimed at estimating integrals 37 * over infinite intervals as proposed 38 * <a href="http://en.wikipedia.org/w/index.php?title=Numerical_integration#Integrals_over_infinite_intervals"> 39 * here</a> should be avoided when using this class. 40 * 41 * @since 3.1 42 */ 43 44 public class IterativeLegendreGaussIntegrator 45 extends BaseAbstractUnivariateIntegrator { 46 /** Factory that computes the points and weights. */ 47 private static final GaussIntegratorFactory FACTORY 48 = new GaussIntegratorFactory(); 49 /** Number of integration points (per interval). */ 50 private final int numberOfPoints; 51 52 /** 53 * Builds an integrator with given accuracies and iterations counts. 54 * 55 * @param n Number of integration points. 56 * @param relativeAccuracy Relative accuracy of the result. 57 * @param absoluteAccuracy Absolute accuracy of the result. 58 * @param minimalIterationCount Minimum number of iterations. 59 * @param maximalIterationCount Maximum number of iterations. 60 * @throws NotStrictlyPositiveException if minimal number of iterations 61 * or number of points are not strictly positive. 62 * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException 63 * if the maximal number of iterations is smaller than or equal to the 64 * minimal number of iterations. 65 */ 66 public IterativeLegendreGaussIntegrator(final int n, 67 final double relativeAccuracy, 68 final double absoluteAccuracy, 69 final int minimalIterationCount, 70 final int maximalIterationCount) { 71 super(relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount); 72 if (n <= 0) { 73 throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_POINTS, n); 74 } 75 numberOfPoints = n; 76 } 77 78 /** 79 * Builds an integrator with given accuracies. 80 * 81 * @param n Number of integration points. 82 * @param relativeAccuracy Relative accuracy of the result. 83 * @param absoluteAccuracy Absolute accuracy of the result. 84 * @throws NotStrictlyPositiveException if {@code n < 1}. 85 */ 86 public IterativeLegendreGaussIntegrator(final int n, 87 final double relativeAccuracy, 88 final double absoluteAccuracy) { 89 this(n, relativeAccuracy, absoluteAccuracy, 90 DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT); 91 } 92 93 /** 94 * Builds an integrator with given iteration counts. 95 * 96 * @param n Number of integration points. 97 * @param minimalIterationCount Minimum number of iterations. 98 * @param maximalIterationCount Maximum number of iterations. 99 * @throws NotStrictlyPositiveException if minimal number of iterations 100 * is not strictly positive. 101 * @throws org.apache.commons.math4.legacy.exception.NumberIsTooSmallException 102 * if the maximal number of iterations is smaller than or equal to the 103 * minimal number of iterations. 104 * @throws NotStrictlyPositiveException if {@code n < 1}. 105 */ 106 public IterativeLegendreGaussIntegrator(final int n, 107 final int minimalIterationCount, 108 final int maximalIterationCount) { 109 this(n, DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY, 110 minimalIterationCount, maximalIterationCount); 111 } 112 113 /** {@inheritDoc} */ 114 @Override 115 protected double doIntegrate() { 116 // Compute first estimate with a single step. 117 double oldt = stage(1); 118 119 int n = 2; 120 while (true) { 121 // Improve integral with a larger number of steps. 122 final double t = stage(n); 123 124 // Estimate the error. 125 final double delta = JdkMath.abs(t - oldt); 126 final double limit = 127 JdkMath.max(getAbsoluteAccuracy(), 128 getRelativeAccuracy() * (JdkMath.abs(oldt) + JdkMath.abs(t)) * 0.5); 129 130 // check convergence 131 if (iterations.getCount() + 1 >= getMinimalIterationCount() && 132 delta <= limit) { 133 return t; 134 } 135 136 // Prepare next iteration. 137 final double ratio = JdkMath.min(4, JdkMath.pow(delta / limit, 0.5 / numberOfPoints)); 138 n = JdkMath.max((int) (ratio * n), n + 1); 139 oldt = t; 140 iterations.increment(); 141 } 142 } 143 144 /** 145 * Compute the n-th stage integral. 146 * 147 * @param n Number of steps. 148 * @return the value of n-th stage integral. 149 * @throws TooManyEvaluationsException if the maximum number of evaluations 150 * is exceeded. 151 */ 152 private double stage(final int n) 153 throws TooManyEvaluationsException { 154 // Function to be integrated is stored in the base class. 155 final UnivariateFunction f = new UnivariateFunction() { 156 /** {@inheritDoc} */ 157 @Override 158 public double value(double x) { 159 return computeObjectiveValue(x); 160 } 161 }; 162 163 final double min = getMin(); 164 final double max = getMax(); 165 final double step = (max - min) / n; 166 167 double sum = 0; 168 for (int i = 0; i < n; i++) { 169 // Integrate over each sub-interval [a, b]. 170 final double a = min + i * step; 171 final double b = a + step; 172 final GaussIntegrator g = FACTORY.legendreHighPrecision(numberOfPoints, a, b); 173 sum += g.integrate(f); 174 } 175 176 return sum; 177 } 178 }