diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java')
-rw-r--r-- | src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java new file mode 100644 index 0000000..3186d6a --- /dev/null +++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.analysis.solvers; + +import org.apache.commons.math.ConvergenceException; +import org.apache.commons.math.FunctionEvaluationException; +import org.apache.commons.math.MathRuntimeException; +import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.exception.util.LocalizedFormats; +import org.apache.commons.math.exception.NullArgumentException; +import org.apache.commons.math.util.FastMath; + +/** + * Utility routines for {@link UnivariateRealSolver} objects. + * + * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $ + */ +public class UnivariateRealSolverUtils { + + /** + * Default constructor. + */ + private UnivariateRealSolverUtils() { + super(); + } + + /** + * Convenience method to find a zero of a univariate real function. A default + * solver is used. + * + * @param f the function. + * @param x0 the lower bound for the interval. + * @param x1 the upper bound for the interval. + * @return a value where the function is zero. + * @throws ConvergenceException if the iteration count was exceeded + * @throws FunctionEvaluationException if an error occurs evaluating the function + * @throws IllegalArgumentException if f is null or the endpoints do not + * specify a valid interval + */ + public static double solve(UnivariateRealFunction f, double x0, double x1) + throws ConvergenceException, FunctionEvaluationException { + setup(f); + return LazyHolder.FACTORY.newDefaultSolver().solve(f, x0, x1); + } + + /** + * Convenience method to find a zero of a univariate real function. A default + * solver is used. + * + * @param f the function + * @param x0 the lower bound for the interval + * @param x1 the upper bound for the interval + * @param absoluteAccuracy the accuracy to be used by the solver + * @return a value where the function is zero + * @throws ConvergenceException if the iteration count is exceeded + * @throws FunctionEvaluationException if an error occurs evaluating the function + * @throws IllegalArgumentException if f is null, the endpoints do not + * specify a valid interval, or the absoluteAccuracy is not valid for the + * default solver + */ + public static double solve(UnivariateRealFunction f, double x0, double x1, + double absoluteAccuracy) throws ConvergenceException, + FunctionEvaluationException { + + setup(f); + UnivariateRealSolver solver = LazyHolder.FACTORY.newDefaultSolver(); + solver.setAbsoluteAccuracy(absoluteAccuracy); + return solver.solve(f, x0, x1); + } + + /** + * This method attempts to find two values a and b satisfying <ul> + * <li> <code> lowerBound <= a < initial < b <= upperBound</code> </li> + * <li> <code> f(a) * f(b) < 0 </code></li> + * </ul> + * If f is continuous on <code>[a,b],</code> this means that <code>a</code> + * and <code>b</code> bracket a root of f. + * <p> + * The algorithm starts by setting + * <code>a := initial -1; b := initial +1,</code> examines the value of the + * function at <code>a</code> and <code>b</code> and keeps moving + * the endpoints out by one unit each time through a loop that terminates + * when one of the following happens: <ul> + * <li> <code> f(a) * f(b) < 0 </code> -- success!</li> + * <li> <code> a = lower </code> and <code> b = upper</code> + * -- ConvergenceException </li> + * <li> <code> Integer.MAX_VALUE</code> iterations elapse + * -- ConvergenceException </li> + * </ul></p> + * <p> + * <strong>Note: </strong> this method can take + * <code>Integer.MAX_VALUE</code> iterations to throw a + * <code>ConvergenceException.</code> Unless you are confident that there + * is a root between <code>lowerBound</code> and <code>upperBound</code> + * near <code>initial,</code> it is better to use + * {@link #bracket(UnivariateRealFunction, double, double, double, int)}, + * explicitly specifying the maximum number of iterations.</p> + * + * @param function the function + * @param initial initial midpoint of interval being expanded to + * bracket a root + * @param lowerBound lower bound (a is never lower than this value) + * @param upperBound upper bound (b never is greater than this + * value) + * @return a two element array holding {a, b} + * @throws ConvergenceException if a root can not be bracketted + * @throws FunctionEvaluationException if an error occurs evaluating the function + * @throws IllegalArgumentException if function is null, maximumIterations + * is not positive, or initial is not between lowerBound and upperBound + */ + public static double[] bracket(UnivariateRealFunction function, + double initial, double lowerBound, double upperBound) + throws ConvergenceException, FunctionEvaluationException { + return bracket( function, initial, lowerBound, upperBound, + Integer.MAX_VALUE ) ; + } + + /** + * This method attempts to find two values a and b satisfying <ul> + * <li> <code> lowerBound <= a < initial < b <= upperBound</code> </li> + * <li> <code> f(a) * f(b) <= 0 </code> </li> + * </ul> + * If f is continuous on <code>[a,b],</code> this means that <code>a</code> + * and <code>b</code> bracket a root of f. + * <p> + * The algorithm starts by setting + * <code>a := initial -1; b := initial +1,</code> examines the value of the + * function at <code>a</code> and <code>b</code> and keeps moving + * the endpoints out by one unit each time through a loop that terminates + * when one of the following happens: <ul> + * <li> <code> f(a) * f(b) <= 0 </code> -- success!</li> + * <li> <code> a = lower </code> and <code> b = upper</code> + * -- ConvergenceException </li> + * <li> <code> maximumIterations</code> iterations elapse + * -- ConvergenceException </li></ul></p> + * + * @param function the function + * @param initial initial midpoint of interval being expanded to + * bracket a root + * @param lowerBound lower bound (a is never lower than this value) + * @param upperBound upper bound (b never is greater than this + * value) + * @param maximumIterations maximum number of iterations to perform + * @return a two element array holding {a, b}. + * @throws ConvergenceException if the algorithm fails to find a and b + * satisfying the desired conditions + * @throws FunctionEvaluationException if an error occurs evaluating the function + * @throws IllegalArgumentException if function is null, maximumIterations + * is not positive, or initial is not between lowerBound and upperBound + */ + public static double[] bracket(UnivariateRealFunction function, + double initial, double lowerBound, double upperBound, + int maximumIterations) throws ConvergenceException, + FunctionEvaluationException { + + if (function == null) { + throw new NullArgumentException(LocalizedFormats.FUNCTION); + } + if (maximumIterations <= 0) { + throw MathRuntimeException.createIllegalArgumentException( + LocalizedFormats.INVALID_MAX_ITERATIONS, maximumIterations); + } + if (initial < lowerBound || initial > upperBound || lowerBound >= upperBound) { + throw MathRuntimeException.createIllegalArgumentException( + LocalizedFormats.INVALID_BRACKETING_PARAMETERS, + lowerBound, initial, upperBound); + } + double a = initial; + double b = initial; + double fa; + double fb; + int numIterations = 0 ; + + do { + a = FastMath.max(a - 1.0, lowerBound); + b = FastMath.min(b + 1.0, upperBound); + fa = function.value(a); + + fb = function.value(b); + numIterations++ ; + } while ((fa * fb > 0.0) && (numIterations < maximumIterations) && + ((a > lowerBound) || (b < upperBound))); + + if (fa * fb > 0.0 ) { + throw new ConvergenceException( + LocalizedFormats.FAILED_BRACKETING, + numIterations, maximumIterations, initial, + lowerBound, upperBound, a, b, fa, fb); + } + + return new double[]{a, b}; + } + + /** + * Compute the midpoint of two values. + * + * @param a first value. + * @param b second value. + * @return the midpoint. + */ + public static double midpoint(double a, double b) { + return (a + b) * .5; + } + + /** + * Checks to see if f is null, throwing IllegalArgumentException if so. + * @param f input function + * @throws IllegalArgumentException if f is null + */ + private static void setup(UnivariateRealFunction f) { + if (f == null) { + throw new NullArgumentException(LocalizedFormats.FUNCTION); + } + } + + // CHECKSTYLE: stop HideUtilityClassConstructor + /** Holder for the factory. + * <p>We use here the Initialization On Demand Holder Idiom.</p> + */ + private static class LazyHolder { + /** Cached solver factory */ + private static final UnivariateRealSolverFactory FACTORY = UnivariateRealSolverFactory.newInstance(); + } + // CHECKSTYLE: resume HideUtilityClassConstructor + +} |