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.math.analysis.integration;
018
019 import org.apache.commons.math.analysis.UnivariateRealFunction;
020 import org.apache.commons.math.analysis.solvers.UnivariateRealSolverUtils;
021 import org.apache.commons.math.exception.MathIllegalArgumentException;
022 import org.apache.commons.math.exception.MaxCountExceededException;
023 import org.apache.commons.math.exception.NotStrictlyPositiveException;
024 import org.apache.commons.math.exception.NullArgumentException;
025 import org.apache.commons.math.exception.NumberIsTooSmallException;
026 import org.apache.commons.math.exception.TooManyEvaluationsException;
027 import org.apache.commons.math.util.Incrementor;
028 import org.apache.commons.math.util.MathUtils;
029
030 /**
031 * Provide a default implementation for several generic functions.
032 *
033 * @version $Id: UnivariateRealIntegratorImpl.java 1179926 2011-10-07 03:18:05Z psteitz $
034 * @since 1.2
035 */
036 public abstract class UnivariateRealIntegratorImpl implements UnivariateRealIntegrator {
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 /** Maximum absolute error. */
051 protected double absoluteAccuracy;
052
053 /** Maximum relative error. */
054 protected double relativeAccuracy;
055
056 /** minimum number of iterations */
057 protected int minimalIterationCount;
058
059 /** The iteration count. */
060 protected Incrementor iterations;
061
062 /** The functions evaluation count. */
063 protected Incrementor evaluations;
064
065 /** Function to integrate. */
066 protected UnivariateRealFunction function;
067
068 /** Lower bound for the interval. */
069 protected double min;
070
071 /** Upper bound for the interval. */
072 protected 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.math.util.MathUtils#SAFE_MIN MathUtils.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 UnivariateRealIntegratorImpl(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 UnivariateRealIntegratorImpl(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 UnivariateRealIntegratorImpl(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 * Compute the objective function value.
194 *
195 * @param point Point at which the objective function must be evaluated.
196 * @return the objective function value at specified point.
197 * @throws TooManyEvaluationsException if the maximal number of function
198 * evaluations is exceeded.
199 */
200 protected double computeObjectiveValue(final double point)
201 throws TooManyEvaluationsException {
202 try {
203 evaluations.incrementCount();
204 } catch (MaxCountExceededException e) {
205 throw new TooManyEvaluationsException(e.getMax());
206 }
207 return function.value(point);
208 }
209
210 /**
211 * Prepare for computation.
212 * Subclasses must call this method if they override any of the
213 * {@code solve} methods.
214 *
215 * @param maxEval Maximum number of evaluations.
216 * @param f the integrand function
217 * @param lower the min bound for the interval
218 * @param upper the upper bound for the interval
219 * @throws NullArgumentException if {@code f} is {@code null}.
220 * @throws MathIllegalArgumentException if {@code min >= max}.
221 */
222 protected void setup(final int maxEval,
223 final UnivariateRealFunction f,
224 final double lower, final double upper)
225 throws NullArgumentException, MathIllegalArgumentException {
226
227 // Checks.
228 MathUtils.checkNotNull(f);
229 UnivariateRealSolverUtils.verifyInterval(lower, upper);
230
231 // Reset.
232 this.min = lower;
233 this.max = upper;
234 function = f;
235 evaluations.setMaximalCount(maxEval);
236 evaluations.resetCount();
237 iterations.resetCount();
238
239 }
240
241 /** {@inheritDoc} */
242 public double integrate(final int maxEval, final UnivariateRealFunction f,
243 final double lower, final double upper)
244 throws TooManyEvaluationsException, MaxCountExceededException,
245 MathIllegalArgumentException, NullArgumentException {
246
247 // Initialization.
248 setup(maxEval, f, lower, upper);
249
250 // Perform computation.
251 return doIntegrate();
252
253 }
254
255 /**
256 * Method for implementing actual integration algorithms in derived
257 * classes.
258 *
259 * @return the root.
260 * @throws TooManyEvaluationsException if the maximal number of evaluations
261 * is exceeded.
262 * @throws MaxCountExceededException if the maximum iteration count is exceeded
263 * or the integrator detects convergence problems otherwise
264 */
265 protected abstract double doIntegrate()
266 throws TooManyEvaluationsException, MaxCountExceededException;
267
268 }