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