diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/BaseSecantSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/BaseSecantSolver.java index c781a9011..034752553 100644 --- a/src/main/java/org/apache/commons/math/analysis/solvers/BaseSecantSolver.java +++ b/src/main/java/org/apache/commons/math/analysis/solvers/BaseSecantSolver.java @@ -19,6 +19,7 @@ package org.apache.commons.math.analysis.solvers; import org.apache.commons.math.util.FastMath; import org.apache.commons.math.analysis.UnivariateRealFunction; +import org.apache.commons.math.exception.ConvergenceException; import org.apache.commons.math.exception.MathInternalError; /** @@ -61,8 +62,8 @@ public abstract class BaseSecantSolver /** * Construct a solver. * - * @param absoluteAccuracy absolute accuracy - * @param method Secant-based root-finding method to use + * @param absoluteAccuracy Absolute accuracy. + * @param method Secant-based root-finding method to use. */ protected BaseSecantSolver(final double absoluteAccuracy, final Method method) { super(absoluteAccuracy); @@ -73,9 +74,9 @@ public abstract class BaseSecantSolver /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy - * @param method Secant-based root-finding method to use + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. + * @param method Secant-based root-finding method to use. */ protected BaseSecantSolver(final double relativeAccuracy, final double absoluteAccuracy, @@ -183,7 +184,11 @@ public abstract class BaseSecantSolver f0 *= f1 / (f1 + fx); break; case REGULA_FALSI: - // Nothing. + // Detect early that algorithm is stuck, instead of waiting + // for the maximum number of iterations to be exceeded. + if (x == x1) { + throw new ConvergenceException(); + } break; default: // Should never happen. diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/IllinoisSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/IllinoisSolver.java index ede0c2792..47c340c01 100644 --- a/src/main/java/org/apache/commons/math/analysis/solvers/IllinoisSolver.java +++ b/src/main/java/org/apache/commons/math/analysis/solvers/IllinoisSolver.java @@ -26,7 +26,9 @@ package org.apache.commons.math.analysis.solvers; *
Like the Regula Falsi method, convergence is guaranteed by * maintaining a bracketed solution. The Illinois method however, * should converge much faster than the original Regula Falsi - * method.
+ * method. Furthermore, this implementation of the Illinois method + * should not suffer from the same implementation issues as the Regula + * Falsi method, which may fail to convergence in certain cases. * *The Illinois method assumes that the function is continuous, * but not necessarily smooth.
@@ -49,7 +51,7 @@ public class IllinoisSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param absoluteAccuracy absolute accuracy + * @param absoluteAccuracy Absolute accuracy. */ public IllinoisSolver(final double absoluteAccuracy) { super(absoluteAccuracy, Method.ILLINOIS); @@ -58,8 +60,8 @@ public class IllinoisSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. */ public IllinoisSolver(final double relativeAccuracy, final double absoluteAccuracy) { @@ -69,8 +71,8 @@ public class IllinoisSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. * @param functionValueAccuracy Maximum function value error. */ public IllinoisSolver(final double relativeAccuracy, @@ -78,5 +80,4 @@ public class IllinoisSolver extends BaseSecantSolver { final double functionValueAccuracy) { super(relativeAccuracy, absoluteAccuracy, functionValueAccuracy, Method.PEGASUS); } - } diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/PegasusSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/PegasusSolver.java index 08fb0c7d0..457c9580d 100644 --- a/src/main/java/org/apache/commons/math/analysis/solvers/PegasusSolver.java +++ b/src/main/java/org/apache/commons/math/analysis/solvers/PegasusSolver.java @@ -24,10 +24,13 @@ package org.apache.commons.math.analysis.solvers; * *Like the Regula Falsi method, convergence is guaranteed by * maintaining a bracketed solution. The Pegasus method however, - * should converge much faster than the original Regula Falsi method. - * Furthermore, it should converge faster than the - * {@link IllinoisSolver Illinois} method, another - * Regula Falsi-based method.
+ * should converge much faster than the original Regula Falsi + * method. Furthermore, this implementation of the Pegasus method + * should not suffer from the same implementation issues as the Regula + * Falsi method, which may fail to convergence in certain cases. Also, + * the Pegasus method should converge faster than the + * {@link IllinoisSolver Illinois} method, another Regula + * Falsi-based method. * *The Pegasus method assumes that the function is continuous, * but not necessarily smooth.
@@ -50,7 +53,7 @@ public class PegasusSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param absoluteAccuracy absolute accuracy + * @param absoluteAccuracy Absolute accuracy. */ public PegasusSolver(final double absoluteAccuracy) { super(absoluteAccuracy, Method.PEGASUS); @@ -59,8 +62,8 @@ public class PegasusSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. */ public PegasusSolver(final double relativeAccuracy, final double absoluteAccuracy) { @@ -70,8 +73,8 @@ public class PegasusSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. * @param functionValueAccuracy Maximum function value error. */ public PegasusSolver(final double relativeAccuracy, @@ -79,5 +82,4 @@ public class PegasusSolver extends BaseSecantSolver { final double functionValueAccuracy) { super(relativeAccuracy, absoluteAccuracy, functionValueAccuracy, Method.PEGASUS); } - } diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolver.java index 89c50dfd0..71224a0da 100644 --- a/src/main/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolver.java +++ b/src/main/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolver.java @@ -17,13 +17,30 @@ package org.apache.commons.math.analysis.solvers; - /** * Implements the Regula Falsi or False position method for * root-finding (approximating a zero of a univariate real function). It is a - * modified {@link SecantSolver Secant} method. Unlike the - * Secant method, convergence is guaranteed by maintaining a - * bracketed solution. + * modified {@link SecantSolver Secant} method. + * + *The Regula Falsi method is included for completeness, for + * testing purposes, for educational purposes, for comparison to other + * algorithms, etc. It is however not intended to be used + * for actual problems, as one of the bounds often remains fixed, resulting + * in very slow convergence. Instead, one of the well-known modified + * Regula Falsi algorithms can be used ({@link IllinoisSolver + * Illinois} or {@link PegasusSolver Pegasus}). These two + * algorithms solve the fundamental issues of the original Regula + * Falsi algorithm, and greatly out-performs it for most, if not all, + * (practical) functions. + * + *
Unlike the Secant method, the Regula Falsi guarantees + * convergence, by maintaining a bracketed solution. Note however, that due to + * the finite/limited precision of Java's {@link Double double} type, which is + * used in this implementation, the algorithm may get stuck in a situation + * where it no longer makes any progress. Such cases are detected and result + * in a {@code ConvergenceException} exception being thrown. In other words, + * the algorithm theoretically guarantees convergence, but the implementation + * does not.
* *The Regula Falsi method assumes that the function is continuous, * but not necessarily smooth.
@@ -46,7 +63,7 @@ public class RegulaFalsiSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param absoluteAccuracy absolute accuracy + * @param absoluteAccuracy Absolute accuracy. */ public RegulaFalsiSolver(final double absoluteAccuracy) { super(absoluteAccuracy, Method.REGULA_FALSI); @@ -55,8 +72,8 @@ public class RegulaFalsiSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. */ public RegulaFalsiSolver(final double relativeAccuracy, final double absoluteAccuracy) { @@ -66,8 +83,8 @@ public class RegulaFalsiSolver extends BaseSecantSolver { /** * Construct a solver. * - * @param relativeAccuracy relative accuracy - * @param absoluteAccuracy absolute accuracy + * @param relativeAccuracy Relative accuracy. + * @param absoluteAccuracy Absolute accuracy. * @param functionValueAccuracy Maximum function value error. */ public RegulaFalsiSolver(final double relativeAccuracy, diff --git a/src/test/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolverTest.java b/src/test/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolverTest.java index fea0abcc8..db098975f 100644 --- a/src/test/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolverTest.java +++ b/src/test/java/org/apache/commons/math/analysis/solvers/RegulaFalsiSolverTest.java @@ -18,7 +18,7 @@ package org.apache.commons.math.analysis.solvers; import org.apache.commons.math.analysis.UnivariateRealFunction; -import org.apache.commons.math.exception.TooManyEvaluationsException; +import org.apache.commons.math.exception.ConvergenceException; import org.junit.Test; import org.junit.Assert; @@ -41,7 +41,7 @@ public final class RegulaFalsiSolverTest extends BaseSecantSolverAbstractTest { return new int[] {3, 7, 8, 19, 18, 11, 67, 55, 288, 151, -1}; } - @Test(expected=TooManyEvaluationsException.class) + @Test(expected=ConvergenceException.class) public void testIssue631() { final UnivariateRealFunction f = new UnivariateRealFunction() { /** {@inheritDoc} */