001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.math3.analysis.integration; 018 019import org.apache.commons.math3.analysis.UnivariateFunction; 020import org.apache.commons.math3.analysis.solvers.UnivariateSolverUtils; 021import org.apache.commons.math3.exception.MathIllegalArgumentException; 022import org.apache.commons.math3.exception.MaxCountExceededException; 023import org.apache.commons.math3.exception.NotStrictlyPositiveException; 024import org.apache.commons.math3.exception.NullArgumentException; 025import org.apache.commons.math3.exception.NumberIsTooSmallException; 026import org.apache.commons.math3.exception.TooManyEvaluationsException; 027import org.apache.commons.math3.util.IntegerSequence; 028import org.apache.commons.math3.util.MathUtils; 029 030/** 031 * Provide a default implementation for several generic functions. 032 * 033 * @since 1.2 034 */ 035public abstract class BaseAbstractUnivariateIntegrator implements UnivariateIntegrator { 036 037 /** Default absolute accuracy. */ 038 public static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0e-15; 039 040 /** Default relative accuracy. */ 041 public static final double DEFAULT_RELATIVE_ACCURACY = 1.0e-6; 042 043 /** Default minimal iteration count. */ 044 public static final int DEFAULT_MIN_ITERATIONS_COUNT = 3; 045 046 /** Default maximal iteration count. */ 047 public static final int DEFAULT_MAX_ITERATIONS_COUNT = Integer.MAX_VALUE; 048 049 /** The iteration count. 050 * @deprecated as of 3.6, this field has been replaced with {@link #incrementCount()} 051 */ 052 @Deprecated 053 protected org.apache.commons.math3.util.Incrementor iterations; 054 055 /** The iteration count. */ 056 private IntegerSequence.Incrementor count; 057 058 /** Maximum absolute error. */ 059 private final double absoluteAccuracy; 060 061 /** Maximum relative error. */ 062 private final double relativeAccuracy; 063 064 /** minimum number of iterations */ 065 private final int minimalIterationCount; 066 067 /** The functions evaluation count. */ 068 private IntegerSequence.Incrementor evaluations; 069 070 /** Function to integrate. */ 071 private UnivariateFunction function; 072 073 /** Lower bound for the interval. */ 074 private double min; 075 076 /** Upper bound for the interval. */ 077 private double max; 078 079 /** 080 * Construct an integrator with given accuracies and iteration counts. 081 * <p> 082 * The meanings of the various parameters are: 083 * <ul> 084 * <li>relative accuracy: 085 * this is used to stop iterations if the absolute accuracy can't be 086 * achieved due to large values or short mantissa length. If this 087 * should be the primary criterion for convergence rather then a 088 * safety measure, set the absolute accuracy to a ridiculously small value, 089 * like {@link org.apache.commons.math3.util.Precision#SAFE_MIN Precision.SAFE_MIN}.</li> 090 * <li>absolute accuracy: 091 * The default is usually chosen so that results in the interval 092 * -10..-0.1 and +0.1..+10 can be found with a reasonable accuracy. If the 093 * expected absolute value of your results is of much smaller magnitude, set 094 * this to a smaller value.</li> 095 * <li>minimum number of iterations: 096 * minimal iteration is needed to avoid false early convergence, e.g. 097 * the sample points happen to be zeroes of the function. Users can 098 * use the default value or choose one that they see as appropriate.</li> 099 * <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 */ 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 */ 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 */ 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} */ 172 public double getRelativeAccuracy() { 173 return relativeAccuracy; 174 } 175 176 /** {@inheritDoc} */ 177 public double getAbsoluteAccuracy() { 178 return absoluteAccuracy; 179 } 180 181 /** {@inheritDoc} */ 182 public int getMinimalIterationCount() { 183 return minimalIterationCount; 184 } 185 186 /** {@inheritDoc} */ 187 public int getMaximalIterationCount() { 188 return count.getMaximalCount(); 189 } 190 191 /** {@inheritDoc} */ 192 public int getEvaluations() { 193 return evaluations.getCount(); 194 } 195 196 /** {@inheritDoc} */ 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 */ 205 protected void incrementCount() throws MaxCountExceededException { 206 count.increment(); 207 } 208 209 /** 210 * @return the lower bound. 211 */ 212 protected double getMin() { 213 return min; 214 } 215 /** 216 * @return the upper bound. 217 */ 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 */ 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 */ 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} */ 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 */ 294 protected abstract double doIntegrate() 295 throws TooManyEvaluationsException, MaxCountExceededException; 296 297}