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