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.math4.legacy.analysis.integration; 018 019import org.apache.commons.math4.legacy.analysis.UnivariateFunction; 020import org.apache.commons.math4.legacy.analysis.solvers.UnivariateSolverUtils; 021import org.apache.commons.math4.legacy.exception.NullArgumentException; 022import org.apache.commons.math4.legacy.exception.MaxCountExceededException; 023import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; 024import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException; 025import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException; 026import org.apache.commons.math4.legacy.core.IntegerSequence; 027 028/** 029 * Provide a default implementation for several generic functions. 030 * 031 * @since 1.2 032 */ 033public abstract class BaseAbstractUnivariateIntegrator implements UnivariateIntegrator { 034 035 /** Default absolute accuracy. */ 036 public static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0e-15; 037 038 /** Default relative accuracy. */ 039 public static final double DEFAULT_RELATIVE_ACCURACY = 1.0e-6; 040 041 /** Default minimal iteration count. */ 042 public static final int DEFAULT_MIN_ITERATIONS_COUNT = 3; 043 044 /** Default maximal iteration count. */ 045 public static final int DEFAULT_MAX_ITERATIONS_COUNT = Integer.MAX_VALUE; 046 047 /** The iteration count. */ 048 protected IntegerSequence.Incrementor iterations; 049 050 /** Maximum absolute error. */ 051 private final double absoluteAccuracy; 052 053 /** Maximum relative error. */ 054 private final double relativeAccuracy; 055 056 /** minimum number of iterations. */ 057 private final int minimalIterationCount; 058 /** maximum number of iterations. */ 059 private final int maximalIterationCount; 060 061 /** The functions evaluation count. */ 062 private IntegerSequence.Incrementor evaluations; 063 064 /** Function to integrate. */ 065 private UnivariateFunction function; 066 067 /** Lower bound for the interval. */ 068 private double min; 069 070 /** Upper bound for the interval. */ 071 private double max; 072 073 /** 074 * Construct an integrator with given accuracies and iteration counts. 075 * <p> 076 * The meanings of the various parameters are: 077 * <ul> 078 * <li>relative accuracy: 079 * this is used to stop iterations if the absolute accuracy can't be 080 * achieved due to large values or short mantissa length. If this 081 * should be the primary criterion for convergence rather then a 082 * safety measure, set the absolute accuracy to a ridiculously small value, 083 * like {@link org.apache.commons.numbers.core.Precision#SAFE_MIN Precision.SAFE_MIN}.</li> 084 * <li>absolute accuracy: 085 * The default is usually chosen so that results in the interval 086 * -10..-0.1 and +0.1..+10 can be found with a reasonable accuracy. If the 087 * expected absolute value of your results is of much smaller magnitude, set 088 * this to a smaller value.</li> 089 * <li>minimum number of iterations: 090 * minimal iteration is needed to avoid false early convergence, e.g. 091 * the sample points happen to be zeroes of the function. Users can 092 * use the default value or choose one that they see as appropriate.</li> 093 * <li>maximum number of iterations: 094 * usually a high iteration count indicates convergence problems. However, 095 * the "reasonable value" varies widely for different algorithms. Users are 096 * advised to use the default value supplied by the algorithm.</li> 097 * </ul> 098 * 099 * @param relativeAccuracy relative accuracy of the result 100 * @param absoluteAccuracy absolute accuracy of the result 101 * @param minimalIterationCount minimum number of iterations 102 * @param maximalIterationCount maximum number of iterations 103 * @exception NotStrictlyPositiveException if minimal number of iterations 104 * is not strictly positive 105 * @exception NumberIsTooSmallException if maximal number of iterations 106 * is lesser than or equal to the minimal number of iterations 107 */ 108 protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy, 109 final double absoluteAccuracy, 110 final int minimalIterationCount, 111 final int maximalIterationCount) { 112 // accuracy settings 113 this.relativeAccuracy = relativeAccuracy; 114 this.absoluteAccuracy = absoluteAccuracy; 115 116 // iterations count settings 117 if (minimalIterationCount <= 0) { 118 throw new NotStrictlyPositiveException(minimalIterationCount); 119 } 120 if (maximalIterationCount <= minimalIterationCount) { 121 throw new NumberIsTooSmallException(maximalIterationCount, minimalIterationCount, false); 122 } 123 this.minimalIterationCount = minimalIterationCount; 124 this.maximalIterationCount = maximalIterationCount; 125 } 126 127 /** 128 * Construct an integrator with given accuracies. 129 * @param relativeAccuracy relative accuracy of the result 130 * @param absoluteAccuracy absolute accuracy of the result 131 */ 132 protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy, 133 final double absoluteAccuracy) { 134 this(relativeAccuracy, absoluteAccuracy, 135 DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT); 136 } 137 138 /** 139 * Construct an integrator with given iteration counts. 140 * @param minimalIterationCount minimum number of iterations 141 * @param maximalIterationCount maximum number of iterations 142 * @exception NotStrictlyPositiveException if minimal number of iterations 143 * is not strictly positive 144 * @exception NumberIsTooSmallException if maximal number of iterations 145 * is lesser than or equal to the minimal number of iterations 146 */ 147 protected BaseAbstractUnivariateIntegrator(final int minimalIterationCount, 148 final int maximalIterationCount) { 149 this(DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY, 150 minimalIterationCount, maximalIterationCount); 151 } 152 153 /** {@inheritDoc} */ 154 @Override 155 public double getRelativeAccuracy() { 156 return relativeAccuracy; 157 } 158 159 /** {@inheritDoc} */ 160 @Override 161 public double getAbsoluteAccuracy() { 162 return absoluteAccuracy; 163 } 164 165 /** {@inheritDoc} */ 166 @Override 167 public int getMinimalIterationCount() { 168 return minimalIterationCount; 169 } 170 171 /** {@inheritDoc} */ 172 @Override 173 public int getMaximalIterationCount() { 174 return iterations.getMaximalCount(); 175 } 176 177 /** {@inheritDoc} */ 178 @Override 179 public int getEvaluations() { 180 return evaluations.getCount(); 181 } 182 183 /** {@inheritDoc} */ 184 @Override 185 public int getIterations() { 186 return iterations.getCount(); 187 } 188 189 /** 190 * @return the lower bound. 191 */ 192 protected double getMin() { 193 return min; 194 } 195 /** 196 * @return the upper bound. 197 */ 198 protected double getMax() { 199 return max; 200 } 201 202 /** 203 * Compute the objective function value. 204 * 205 * @param point Point at which the objective function must be evaluated. 206 * @return the objective function value at specified point. 207 * @throws TooManyEvaluationsException if the maximal number of function 208 * evaluations is exceeded. 209 */ 210 protected double computeObjectiveValue(final double point) { 211 try { 212 evaluations.increment(); 213 } catch (MaxCountExceededException e) { 214 throw new TooManyEvaluationsException(e.getMax()); 215 } 216 return function.value(point); 217 } 218 219 /** 220 * Prepare for computation. 221 * Subclasses must call this method if they the {@code integrate} method. 222 * 223 * @param maxEval Maximum number of evaluations. 224 * @param f the integrand function 225 * @param lower the min bound for the interval 226 * @param upper the upper bound for the interval 227 * @throws NullArgumentException if {@code f} is {@code null}. 228 * @throws org.apache.commons.math4.legacy.exception.MathIllegalArgumentException 229 * if {@code min >= max}. 230 */ 231 protected void setup(final int maxEval, 232 final UnivariateFunction f, 233 final double lower, final double upper) { 234 235 // Checks. 236 NullArgumentException.check(f); 237 UnivariateSolverUtils.verifyInterval(lower, upper); 238 239 // Reset. 240 min = lower; 241 max = upper; 242 function = f; 243 iterations = IntegerSequence.Incrementor.create() 244 .withMaximalCount(maximalIterationCount); 245 evaluations = IntegerSequence.Incrementor.create() 246 .withMaximalCount(maxEval); 247 } 248 249 /** {@inheritDoc} */ 250 @Override 251 public double integrate(final int maxEval, final UnivariateFunction f, 252 final double lower, final double upper) { 253 254 // Initialization. 255 setup(maxEval, f, lower, upper); 256 257 // Perform computation. 258 return doIntegrate(); 259 } 260 261 /** 262 * Method for implementing actual integration algorithms in derived 263 * classes. 264 * 265 * @return the root. 266 * @throws TooManyEvaluationsException if the maximal number of evaluations 267 * is exceeded. 268 * @throws MaxCountExceededException if the maximum iteration count is exceeded 269 * or the integrator detects convergence problems otherwise 270 */ 271 protected abstract double doIntegrate() ; 272}