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.math3.analysis.integration; 18 19 import org.apache.commons.math3.analysis.UnivariateFunction; 20 import org.apache.commons.math3.analysis.solvers.UnivariateSolverUtils; 21 import org.apache.commons.math3.exception.MathIllegalArgumentException; 22 import org.apache.commons.math3.exception.MaxCountExceededException; 23 import org.apache.commons.math3.exception.NotStrictlyPositiveException; 24 import org.apache.commons.math3.exception.NullArgumentException; 25 import org.apache.commons.math3.exception.NumberIsTooSmallException; 26 import org.apache.commons.math3.exception.TooManyEvaluationsException; 27 import org.apache.commons.math3.util.IntegerSequence; 28 import org.apache.commons.math3.util.MathUtils; 29 30 /** 31 * Provide a default implementation for several generic functions. 32 * 33 * @since 1.2 34 */ 35 public abstract class BaseAbstractUnivariateIntegrator implements UnivariateIntegrator { 36 37 /** Default absolute accuracy. */ 38 public static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0e-15; 39 40 /** Default relative accuracy. */ 41 public static final double DEFAULT_RELATIVE_ACCURACY = 1.0e-6; 42 43 /** Default minimal iteration count. */ 44 public static final int DEFAULT_MIN_ITERATIONS_COUNT = 3; 45 46 /** Default maximal iteration count. */ 47 public static final int DEFAULT_MAX_ITERATIONS_COUNT = Integer.MAX_VALUE; 48 49 /** The iteration count. 50 * @deprecated as of 3.6, this field has been replaced with {@link #incrementCount()} 51 */ 52 @Deprecated 53 protected org.apache.commons.math3.util.Incrementor iterations; 54 55 /** The iteration count. */ 56 private IntegerSequence.Incrementor count; 57 58 /** Maximum absolute error. */ 59 private final double absoluteAccuracy; 60 61 /** Maximum relative error. */ 62 private final double relativeAccuracy; 63 64 /** minimum number of iterations */ 65 private final int minimalIterationCount; 66 67 /** The functions evaluation count. */ 68 private IntegerSequence.Incrementor evaluations; 69 70 /** Function to integrate. */ 71 private UnivariateFunction function; 72 73 /** Lower bound for the interval. */ 74 private double min; 75 76 /** Upper bound for the interval. */ 77 private double max; 78 79 /** 80 * Construct an integrator with given accuracies and iteration counts. 81 * <p> 82 * The meanings of the various parameters are: 83 * <ul> 84 * <li>relative accuracy: 85 * this is used to stop iterations if the absolute accuracy can't be 86 * achieved due to large values or short mantissa length. If this 87 * should be the primary criterion for convergence rather then a 88 * safety measure, set the absolute accuracy to a ridiculously small value, 89 * like {@link org.apache.commons.math3.util.Precision#SAFE_MIN Precision.SAFE_MIN}.</li> 90 * <li>absolute accuracy: 91 * The default is usually chosen so that results in the interval 92 * -10..-0.1 and +0.1..+10 can be found with a reasonable accuracy. If the 93 * expected absolute value of your results is of much smaller magnitude, set 94 * this to a smaller value.</li> 95 * <li>minimum number of iterations: 96 * minimal iteration is needed to avoid false early convergence, e.g. 97 * the sample points happen to be zeroes of the function. Users can 98 * use the default value or choose one that they see as appropriate.</li> 99 * <li>maximum number of iterations: 100 * usually a high iteration count indicates convergence problems. However, 101 * the "reasonable value" varies widely for different algorithms. Users are 102 * advised to use the default value supplied by the algorithm.</li> 103 * </ul> 104 * 105 * @param relativeAccuracy relative accuracy of the result 106 * @param absoluteAccuracy absolute accuracy of the result 107 * @param minimalIterationCount minimum number of iterations 108 * @param maximalIterationCount maximum number of iterations 109 * @exception NotStrictlyPositiveException if minimal number of iterations 110 * is not strictly positive 111 * @exception NumberIsTooSmallException if maximal number of iterations 112 * is lesser than or equal to the minimal number of iterations 113 */ BaseAbstractUnivariateIntegrator(final double relativeAccuracy, final double absoluteAccuracy, final int minimalIterationCount, final int maximalIterationCount)114 protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy, 115 final double absoluteAccuracy, 116 final int minimalIterationCount, 117 final int maximalIterationCount) 118 throws NotStrictlyPositiveException, NumberIsTooSmallException { 119 120 // accuracy settings 121 this.relativeAccuracy = relativeAccuracy; 122 this.absoluteAccuracy = absoluteAccuracy; 123 124 // iterations count settings 125 if (minimalIterationCount <= 0) { 126 throw new NotStrictlyPositiveException(minimalIterationCount); 127 } 128 if (maximalIterationCount <= minimalIterationCount) { 129 throw new NumberIsTooSmallException(maximalIterationCount, minimalIterationCount, false); 130 } 131 this.minimalIterationCount = minimalIterationCount; 132 this.count = IntegerSequence.Incrementor.create().withMaximalCount(maximalIterationCount); 133 134 @SuppressWarnings("deprecation") 135 org.apache.commons.math3.util.Incrementor wrapped = 136 org.apache.commons.math3.util.Incrementor.wrap(count); 137 this.iterations = wrapped; 138 139 // prepare evaluations counter, but do not set it yet 140 evaluations = IntegerSequence.Incrementor.create(); 141 142 } 143 144 /** 145 * Construct an integrator with given accuracies. 146 * @param relativeAccuracy relative accuracy of the result 147 * @param absoluteAccuracy absolute accuracy of the result 148 */ BaseAbstractUnivariateIntegrator(final double relativeAccuracy, final double absoluteAccuracy)149 protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy, 150 final double absoluteAccuracy) { 151 this(relativeAccuracy, absoluteAccuracy, 152 DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT); 153 } 154 155 /** 156 * Construct an integrator with given iteration counts. 157 * @param minimalIterationCount minimum number of iterations 158 * @param maximalIterationCount maximum number of iterations 159 * @exception NotStrictlyPositiveException if minimal number of iterations 160 * is not strictly positive 161 * @exception NumberIsTooSmallException if maximal number of iterations 162 * is lesser than or equal to the minimal number of iterations 163 */ BaseAbstractUnivariateIntegrator(final int minimalIterationCount, final int maximalIterationCount)164 protected BaseAbstractUnivariateIntegrator(final int minimalIterationCount, 165 final int maximalIterationCount) 166 throws NotStrictlyPositiveException, NumberIsTooSmallException { 167 this(DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY, 168 minimalIterationCount, maximalIterationCount); 169 } 170 171 /** {@inheritDoc} */ getRelativeAccuracy()172 public double getRelativeAccuracy() { 173 return relativeAccuracy; 174 } 175 176 /** {@inheritDoc} */ getAbsoluteAccuracy()177 public double getAbsoluteAccuracy() { 178 return absoluteAccuracy; 179 } 180 181 /** {@inheritDoc} */ getMinimalIterationCount()182 public int getMinimalIterationCount() { 183 return minimalIterationCount; 184 } 185 186 /** {@inheritDoc} */ getMaximalIterationCount()187 public int getMaximalIterationCount() { 188 return count.getMaximalCount(); 189 } 190 191 /** {@inheritDoc} */ getEvaluations()192 public int getEvaluations() { 193 return evaluations.getCount(); 194 } 195 196 /** {@inheritDoc} */ getIterations()197 public int getIterations() { 198 return count.getCount(); 199 } 200 201 /** Increment the number of iterations. 202 * @exception MaxCountExceededException if the number of iterations 203 * exceeds the allowed maximum number 204 */ incrementCount()205 protected void incrementCount() throws MaxCountExceededException { 206 count.increment(); 207 } 208 209 /** 210 * @return the lower bound. 211 */ getMin()212 protected double getMin() { 213 return min; 214 } 215 /** 216 * @return the upper bound. 217 */ getMax()218 protected double getMax() { 219 return max; 220 } 221 222 /** 223 * Compute the objective function value. 224 * 225 * @param point Point at which the objective function must be evaluated. 226 * @return the objective function value at specified point. 227 * @throws TooManyEvaluationsException if the maximal number of function 228 * evaluations is exceeded. 229 */ computeObjectiveValue(final double point)230 protected double computeObjectiveValue(final double point) 231 throws TooManyEvaluationsException { 232 try { 233 evaluations.increment(); 234 } catch (MaxCountExceededException e) { 235 throw new TooManyEvaluationsException(e.getMax()); 236 } 237 return function.value(point); 238 } 239 240 /** 241 * Prepare for computation. 242 * Subclasses must call this method if they override any of the 243 * {@code solve} methods. 244 * 245 * @param maxEval Maximum number of evaluations. 246 * @param f the integrand function 247 * @param lower the min bound for the interval 248 * @param upper the upper bound for the interval 249 * @throws NullArgumentException if {@code f} is {@code null}. 250 * @throws MathIllegalArgumentException if {@code min >= max}. 251 */ setup(final int maxEval, final UnivariateFunction f, final double lower, final double upper)252 protected void setup(final int maxEval, 253 final UnivariateFunction f, 254 final double lower, final double upper) 255 throws NullArgumentException, MathIllegalArgumentException { 256 257 // Checks. 258 MathUtils.checkNotNull(f); 259 UnivariateSolverUtils.verifyInterval(lower, upper); 260 261 // Reset. 262 min = lower; 263 max = upper; 264 function = f; 265 evaluations = evaluations.withMaximalCount(maxEval).withStart(0); 266 count = count.withStart(0); 267 268 } 269 270 /** {@inheritDoc} */ integrate(final int maxEval, final UnivariateFunction f, final double lower, final double upper)271 public double integrate(final int maxEval, final UnivariateFunction f, 272 final double lower, final double upper) 273 throws TooManyEvaluationsException, MaxCountExceededException, 274 MathIllegalArgumentException, NullArgumentException { 275 276 // Initialization. 277 setup(maxEval, f, lower, upper); 278 279 // Perform computation. 280 return doIntegrate(); 281 282 } 283 284 /** 285 * Method for implementing actual integration algorithms in derived 286 * classes. 287 * 288 * @return the root. 289 * @throws TooManyEvaluationsException if the maximal number of evaluations 290 * is exceeded. 291 * @throws MaxCountExceededException if the maximum iteration count is exceeded 292 * or the integrator detects convergence problems otherwise 293 */ doIntegrate()294 protected abstract double doIntegrate() 295 throws TooManyEvaluationsException, MaxCountExceededException; 296 297 } 298