diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math3/analysis/solvers/SecantSolver.java')
-rw-r--r-- | src/main/java/org/apache/commons/math3/analysis/solvers/SecantSolver.java | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/analysis/solvers/SecantSolver.java b/src/main/java/org/apache/commons/math3/analysis/solvers/SecantSolver.java new file mode 100644 index 0000000..d866cf8 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/analysis/solvers/SecantSolver.java @@ -0,0 +1,135 @@ +/* + * 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.math3.analysis.solvers; + +import org.apache.commons.math3.util.FastMath; +import org.apache.commons.math3.exception.NoBracketingException; +import org.apache.commons.math3.exception.TooManyEvaluationsException; + +/** + * Implements the <em>Secant</em> method for root-finding (approximating a + * zero of a univariate real function). The solution that is maintained is + * not bracketed, and as such convergence is not guaranteed. + * + * <p>Implementation based on the following article: M. Dowell and P. Jarratt, + * <em>A modified regula falsi method for computing the root of an + * equation</em>, BIT Numerical Mathematics, volume 11, number 2, + * pages 168-174, Springer, 1971.</p> + * + * <p>Note that since release 3.0 this class implements the actual + * <em>Secant</em> algorithm, and not a modified one. As such, the 3.0 version + * is not backwards compatible with previous versions. To use an algorithm + * similar to the pre-3.0 releases, use the + * {@link IllinoisSolver <em>Illinois</em>} algorithm or the + * {@link PegasusSolver <em>Pegasus</em>} algorithm.</p> + * + */ +public class SecantSolver extends AbstractUnivariateSolver { + + /** Default absolute accuracy. */ + protected static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6; + + /** Construct a solver with default accuracy (1e-6). */ + public SecantSolver() { + super(DEFAULT_ABSOLUTE_ACCURACY); + } + + /** + * Construct a solver. + * + * @param absoluteAccuracy absolute accuracy + */ + public SecantSolver(final double absoluteAccuracy) { + super(absoluteAccuracy); + } + + /** + * Construct a solver. + * + * @param relativeAccuracy relative accuracy + * @param absoluteAccuracy absolute accuracy + */ + public SecantSolver(final double relativeAccuracy, + final double absoluteAccuracy) { + super(relativeAccuracy, absoluteAccuracy); + } + + /** {@inheritDoc} */ + @Override + protected final double doSolve() + throws TooManyEvaluationsException, + NoBracketingException { + // Get initial solution + double x0 = getMin(); + double x1 = getMax(); + double f0 = computeObjectiveValue(x0); + double f1 = computeObjectiveValue(x1); + + // If one of the bounds is the exact root, return it. Since these are + // not under-approximations or over-approximations, we can return them + // regardless of the allowed solutions. + if (f0 == 0.0) { + return x0; + } + if (f1 == 0.0) { + return x1; + } + + // Verify bracketing of initial solution. + verifyBracketing(x0, x1); + + // Get accuracies. + final double ftol = getFunctionValueAccuracy(); + final double atol = getAbsoluteAccuracy(); + final double rtol = getRelativeAccuracy(); + + // Keep finding better approximations. + while (true) { + // Calculate the next approximation. + final double x = x1 - ((f1 * (x1 - x0)) / (f1 - f0)); + final double fx = computeObjectiveValue(x); + + // If the new approximation is the exact root, return it. Since + // this is not an under-approximation or an over-approximation, + // we can return it regardless of the allowed solutions. + if (fx == 0.0) { + return x; + } + + // Update the bounds with the new approximation. + x0 = x1; + f0 = f1; + x1 = x; + f1 = fx; + + // If the function value of the last approximation is too small, + // given the function value accuracy, then we can't get closer to + // the root than we already are. + if (FastMath.abs(f1) <= ftol) { + return x1; + } + + // If the current interval is within the given accuracies, we + // are satisfied with the current approximation. + if (FastMath.abs(x1 - x0) < FastMath.max(rtol * FastMath.abs(x1), atol)) { + return x1; + } + } + } + +} |