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    }