    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
    018    package org.apache.commons.math.analysis.solvers;
    019
    020    import org.apache.commons.math.ConvergingAlgorithmImpl;
    021    import org.apache.commons.math.FunctionEvaluationException;
    022    import org.apache.commons.math.MathRuntimeException;
    023    import org.apache.commons.math.analysis.UnivariateRealFunction;
    024    import org.apache.commons.math.exception.util.LocalizedFormats;
    025    import org.apache.commons.math.ConvergenceException;
    026    import org.apache.commons.math.exception.NullArgumentException;
    027
    028    /**
    029     * Provide a default implementation for several functions useful to generic
    030     * solvers.
    031     *
    032     * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 f??vr. 2011) $
    033     * @deprecated in 2.2 (to be removed in 3.0).
    034     */
    035    @Deprecated
    036    public abstract class UnivariateRealSolverImpl
    037        extends ConvergingAlgorithmImpl implements UnivariateRealSolver {
    038
    039        /** Maximum error of function. */
    040        protected double functionValueAccuracy;
    041
    042        /** Default maximum error of function. */
    043        protected double defaultFunctionValueAccuracy;
    044
    045        /** Indicates where a root has been computed. */
    046        protected boolean resultComputed = false;
    047
    048        /** The last computed root. */
    049        protected double result;
    050
    051        /** Value of the function at the last computed result. */
    052        protected double functionValue;
    053
    054        /** The function to solve.
    055         * @deprecated as of 2.0 the function to solve is passed as an argument
    056         * to the {@link #solve(UnivariateRealFunction, double, double)} or
    057         * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
    058         * method. */
    059        @Deprecated
    060        protected UnivariateRealFunction f;
    061
    062        /**
    063         * Construct a solver with given iteration count and accuracy.
    064         *
    065         * @param f the function to solve.
    066         * @param defaultAbsoluteAccuracy maximum absolute error
    067         * @param defaultMaximalIterationCount maximum number of iterations
    068         * @throws IllegalArgumentException if f is null or the
    069         * defaultAbsoluteAccuracy is not valid
    070         * @deprecated as of 2.0 the function to solve is passed as an argument
    071         * to the {@link #solve(UnivariateRealFunction, double, double)} or
    072         * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
    073         * method.
    074         */
    075        @Deprecated
    076        protected UnivariateRealSolverImpl(final UnivariateRealFunction f,
    077                                           final int defaultMaximalIterationCount,
    078                                           final double defaultAbsoluteAccuracy) {
    079            super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
    080            if (f == null) {
    081                throw new NullArgumentException(LocalizedFormats.FUNCTION);
    082            }
    083            this.f = f;
    084            this.defaultFunctionValueAccuracy = 1.0e-15;
    085            this.functionValueAccuracy = defaultFunctionValueAccuracy;
    086        }
    087
    088        /**
    089         * Construct a solver with given iteration count and accuracy.
    090         *
    091         * @param defaultAbsoluteAccuracy maximum absolute error
    092         * @param defaultMaximalIterationCount maximum number of iterations
    093         * @throws IllegalArgumentException if f is null or the
    094         * defaultAbsoluteAccuracy is not valid
    095         */
    096        protected UnivariateRealSolverImpl(final int defaultMaximalIterationCount,
    097                                           final double defaultAbsoluteAccuracy) {
    098            super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
    099            this.defaultFunctionValueAccuracy = 1.0e-15;
    100            this.functionValueAccuracy = defaultFunctionValueAccuracy;
    101        }
    102
    103        /** Check if a result has been computed.
    104         * @exception IllegalStateException if no result has been computed
    105         */
    106        protected void checkResultComputed() throws IllegalStateException {
    107            if (!resultComputed) {
    108                throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_RESULT_AVAILABLE);
    109            }
    110        }
    111
    112        /** {@inheritDoc} */
    113        public double getResult() {
    114            checkResultComputed();
    115            return result;
    116        }
    117
    118        /** {@inheritDoc} */
    119        public double getFunctionValue() {
    120            checkResultComputed();
    121            return functionValue;
    122        }
    123
    124        /** {@inheritDoc} */
    125        public void setFunctionValueAccuracy(final double accuracy) {
    126            functionValueAccuracy = accuracy;
    127        }
    128
    129        /** {@inheritDoc} */
    130        public double getFunctionValueAccuracy() {
    131            return functionValueAccuracy;
    132        }
    133
    134        /** {@inheritDoc} */
    135        public void resetFunctionValueAccuracy() {
    136            functionValueAccuracy = defaultFunctionValueAccuracy;
    137        }
    138
    139        /**
    140         * Solve for a zero root in the given interval.
    141         * <p>A solver may require that the interval brackets a single zero root.
    142         * Solvers that do require bracketing should be able to handle the case
    143         * where one of the endpoints is itself a root.</p>
    144         *
    145         * @param function the function to solve.
    146         * @param min the lower bound for the interval.
    147         * @param max the upper bound for the interval.
    148         * @param maxEval Maximum number of evaluations.
    149         * @return a value where the function is zero
    150         * @throws ConvergenceException if the maximum iteration count is exceeded
    151         * or the solver detects convergence problems otherwise.
    152         * @throws FunctionEvaluationException if an error occurs evaluating the function
    153         * @throws IllegalArgumentException if min > max or the endpoints do not
    154         * satisfy the requirements specified by the solver
    155         * @since 2.2
    156         */
    157        public double solve(int maxEval, UnivariateRealFunction function, double min, double max)
    158            throws ConvergenceException, FunctionEvaluationException {
    159            throw MathRuntimeException.createUnsupportedOperationException(LocalizedFormats.NOT_OVERRIDEN);
    160        }
    161
    162        /**
    163         * Solve for a zero in the given interval, start at startValue.
    164         * <p>A solver may require that the interval brackets a single zero root.
    165         * Solvers that do require bracketing should be able to handle the case
    166         * where one of the endpoints is itself a root.</p>
    167         *
    168         * @param function the function to solve.
    169         * @param min the lower bound for the interval.
    170         * @param max the upper bound for the interval.
    171         * @param startValue the start value to use
    172         * @param maxEval Maximum number of evaluations.
    173         * @return a value where the function is zero
    174         * @throws ConvergenceException if the maximum iteration count is exceeded
    175         * or the solver detects convergence problems otherwise.
    176         * @throws FunctionEvaluationException if an error occurs evaluating the function
    177         * @throws IllegalArgumentException if min > max or the arguments do not
    178         * satisfy the requirements specified by the solver
    179         * @since 2.2
    180         */
    181        public double solve(int maxEval, UnivariateRealFunction function, double min, double max, double startValue)
    182            throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException {
    183            throw MathRuntimeException.createUnsupportedOperationException(LocalizedFormats.NOT_OVERRIDEN);
    184        }
    185
    186        /**
    187         * Convenience function for implementations.
    188         *
    189         * @param newResult the result to set
    190         * @param iterationCount the iteration count to set
    191         */
    192        protected final void setResult(final double newResult, final int iterationCount) {
    193            this.result         = newResult;
    194            this.iterationCount = iterationCount;
    195            this.resultComputed = true;
    196        }
    197
    198        /**
    199         * Convenience function for implementations.
    200         *
    201         * @param x the result to set
    202         * @param fx the result to set
    203         * @param iterationCount the iteration count to set
    204         */
    205        protected final void setResult(final double x, final double fx,
    206                                       final int iterationCount) {
    207            this.result         = x;
    208            this.functionValue  = fx;
    209            this.iterationCount = iterationCount;
    210            this.resultComputed = true;
    211        }
    212
    213        /**
    214         * Convenience function for implementations.
    215         */
    216        protected final void clearResult() {
    217            this.iterationCount = 0;
    218            this.resultComputed = false;
    219        }
    220
    221        /**
    222         * Returns true iff the function takes opposite signs at the endpoints.
    223         *
    224         * @param lower  the lower endpoint
    225         * @param upper  the upper endpoint
    226         * @param function the function
    227         * @return true if f(lower) * f(upper) < 0
    228         * @throws FunctionEvaluationException if an error occurs evaluating the function at the endpoints
    229         */
    230        protected boolean isBracketing(final double lower, final double upper,
    231                                       final UnivariateRealFunction function)
    232            throws FunctionEvaluationException {
    233            final double f1 = function.value(lower);
    234            final double f2 = function.value(upper);
    235            return (f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0);
    236        }
    237
    238        /**
    239         * Returns true if the arguments form a (strictly) increasing sequence
    240         *
    241         * @param start  first number
    242         * @param mid   second number
    243         * @param end  third number
    244         * @return true if the arguments form an increasing sequence
    245         */
    246        protected boolean isSequence(final double start, final double mid, final double end) {
    247            return (start < mid) && (mid < end);
    248        }
    249
    250        /**
    251         * Verifies that the endpoints specify an interval,
    252         * throws IllegalArgumentException if not
    253         *
    254         * @param lower  lower endpoint
    255         * @param upper upper endpoint
    256         * @throws IllegalArgumentException
    257         */
    258        protected void verifyInterval(final double lower, final double upper) {
    259            if (lower >= upper) {
    260                throw MathRuntimeException.createIllegalArgumentException(
    261                        LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
    262                        lower, upper);
    263            }
    264        }
    265
    266        /**
    267         * Verifies that <code>lower < initial < upper</code>
    268         * throws IllegalArgumentException if not
    269         *
    270         * @param lower  lower endpoint
    271         * @param initial initial value
    272         * @param upper upper endpoint
    273         * @throws IllegalArgumentException
    274         */
    275        protected void verifySequence(final double lower, final double initial, final double upper) {
    276            if (!isSequence(lower, initial, upper)) {
    277                throw MathRuntimeException.createIllegalArgumentException(
    278                        LocalizedFormats.INVALID_INTERVAL_INITIAL_VALUE_PARAMETERS,
    279                        lower, initial, upper);
    280            }
    281        }
    282
    283        /**
    284         * Verifies that the endpoints specify an interval and the function takes
    285         * opposite signs at the endpoints, throws IllegalArgumentException if not
    286         *
    287         * @param lower  lower endpoint
    288         * @param upper upper endpoint
    289         * @param function function
    290         * @throws IllegalArgumentException
    291         * @throws FunctionEvaluationException if an error occurs evaluating the function at the endpoints
    292         */
    293        protected void verifyBracketing(final double lower, final double upper,
    294                                        final UnivariateRealFunction function)
    295            throws FunctionEvaluationException {
    296
    297            verifyInterval(lower, upper);
    298            if (!isBracketing(lower, upper, function)) {
    299                throw MathRuntimeException.createIllegalArgumentException(
    300                        LocalizedFormats.SAME_SIGN_AT_ENDPOINTS,
    301                        lower, upper, function.value(lower), function.value(upper));
    302            }
    303        }
    304    }