We are excited to announce v0.2 of the IntervalRootFinding.jl
package, which has been completely rewritten from scratch.
This package exports a function roots
that is guaranteed to find all roots of a given function \mathbb{R}^n \to \mathbb{R}^n in a given box X \subseteq \mathbb{R}^n (or tell you that it is unable to do so).
Functions are written with standard Julia syntax; no macros or other magic are required!
It is able to do this thanks to the power of interval arithmetic methods, based on the IntervalArithmetic.jl package. A generic “branch and prune” method is used to bisect space to look for roots.
As a flavour of what it can do, let’s find all the stationary points of the function f(x, y) = \sin(x) * \sin(y) in a box, by finding zeros of its gradient, i.e. vectors \mathbf{x} such that (\nabla f)(\mathbf{x}) = \mathbf{0}:
julia> using IntervalArithmetic, IntervalRootFinding
# define the function
julia> f(xx) = ( (x, y) = xx; sin(x) * sin(y) )
# obtain its gradient using the gradient operator ∇ exported by the package
julia> ∇f = ∇(f)
# calculate the roots of the gradient using the interval Newton method in the given box:
julia> rts = roots(∇f, (-5..6) × (-5..6), Newton, 1e-5)
25-element Array{IntervalRootFinding.Root{IntervalArithmetic.IntervalBox{2,Float64}},1}:
Root([4.71238, 4.71239] × [4.71238, 4.71239], :unique)
Root([4.71238, 4.71239] × [1.57079, 1.5708], :unique)
⋮
[output snipped]
This returns a vector of pairs (interval
, status
), stored in Root
objects, that specify the IntervalBox
(a Cartesian product of intervals) and the “status” of a root. In this case, the package is able to guarantee, using an interval version of the Newton method, that there exists a root within each of those intervals, and that it is unique. Furthermore, any region of \mathbb{R}^2 that is not included in one of those intervals has been definitively excluded from the search.
Now let’s find the midpoints of the intervals and plot them:
midpoints = mid.([root.interval for root in rts])
xs = first.(midpoints)
ys = last.(midpoints)
using Plots; plotlyjs()
surface(-5:0.1:6, -6:0.1:6, (x,y)->f([x,y]))
scatter!(xs, ys, f.(midpoints))
The result is the following image:
There are various usage examples in the README and in the examples.jl
file. The documentation is currently out of date.
Please test the package with your difficult root-finding problems and open issues!
Currently the implementations are somewhat basic. There is lots of information in the literature about how to improve such root finders; this would make a great GSoC project. Please contact the first author if you are interested.
David P. Sanders
Luis Benet