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    }