NonlinearSolve Falsi algorithm: Unexpected ReturnCode

I’m observing unexpected behavior in SimpleNonlinearSolve/NonlinearSolve’s algorithm Falsi (an algorithm for finding roots of nonlinear functions). I expect Falsi to return a successful return code if it converged, and an unsuccessful one if it couldn’t.

Here is a MWE that contradicts this behavior: For f(x) = 1, Falsi shouldn’t be able to converge, and for f(x) = x, Falsi should converge with result x=0. Here, exactly the opposite happens:

using SimpleNonlinearSolve, SciMLBase.ReturnCode
np1 = IntervalNonlinearProblem((x, p) -> 1., (0., 1.))
sol1 = solve(np1, Falsi(); abstol=1e-10)
SciMLBase.successful_retcode(sol1)  # returns true (FloatingPointLimit)
np2 = IntervalNonlinearProblem((x, p) -> x, (-1., 1.))
sol2 = solve(np2, Falsi(); abstol=1e-10)
SciMLBase.successful_retcode(sol2)  # returns false (MaxIters)

Executed using SciMLBase v1.94.0 and SimpleNonlinearSolve v0.1.18.

Is there something I’m missing/misusing here? I guess I could check for sign(sol.left) == sign(sol.right) as a workaround to see if a root could be found.

Falsi is not always numerically stable. We are switching the defaults and recommendations towards ITP which should just be better.

using SimpleNonlinearSolve, SciMLBase.ReturnCode
np1 = IntervalNonlinearProblem((x, p) -> 1., (0., 1.))
sol1 = solve(np1, ITP(); abstol=1e-10)
SciMLBase.successful_retcode(sol1)  # returns true (FloatingPointLimit)

ITP mixes bisection and falsi to have the guarantees of Bisection but with the speedup potential of Falsi. See:

The docs haven’t updated with all of this yet, but I hope it does soon because it’ll be the best choice for almost all situations.

I think there’s still a bug here. Falsi should converge in 1 step for linear equations.

1 Like