    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    }