By playing with the tolerance, you can find all roots with the following code (using @Tamas_Papp’s definition of f
). I would say that interval methods are not overkill – which other method would be able to find all of these roots, and guarantee that they are indeed all of the roots in that box?
julia> rts = roots(f, IntervalBox(-100..100, 2), 1e-14)
114-element Array{IntervalRootFinding.Root{IntervalArithmetic.IntervalBox{2,Float64}},1}:
Root([0.0404036, 0.0404037] × [98.879, 98.8791], :unique)
Root([0.03142, 0.0314201] × [97.4523, 97.4524], :unique)
Root([0.0208864, 0.0208865] × [95.7767, 95.7768], :unique)
Root([0.0311381, 0.0311382] × [94.3102, 94.3103], :unique)
Root([0.0431404, 0.0431405] × [92.5903, 92.5904], :unique)
Root([0.033631, 0.0336311] × [91.1736, 91.1737], :unique)
Root([0.0223543, 0.0223544] × [89.4906, 89.4907], :unique)
Root([0.0333079, 0.033308] × [88.0313, 88.0314], :unique)
Root([0.0462746, 0.0462747] × [86.3007, 86.3008], :unique)
Root([0.0361763, 0.0361764] × [84.8955, 84.8956], :unique)
⋮
Root([-0.0345102, -0.0345101] × [-84.8923, -84.8922], :unique)
Root([-0.0231685, -0.0231684] × [-86.3475, -86.3474], :unique)
Root([-0.0348574, -0.0348573] × [-88.0346, -88.0345], :unique)
Root([-0.0446527, -0.0446526] × [-89.4457, -89.4456], :unique)
Root([-0.0321866, -0.0321865] × [-91.1708, -91.1707], :unique)
Root([-0.0215955, -0.0215954] × [-92.6338, -92.6337], :unique)
Root([-0.0324881, -0.032488] × [-94.313, -94.3129], :unique)
Root([-0.0417273, -0.0417272] × [-95.7348, -95.7347], :unique)
Root([-0.0301559, -0.0301558] × [-97.4499, -97.4498], :unique)
Root([-0.0202226, -0.0202225] × [-98.9197, -98.9196], :unique)
julia> all([rt.status for rt in rts] .== :unique)
true
By the way, for simpler functions you can even guarantee that you have found all (real) roots.
Using the master
branch of IntervalRootFinding.jl
, we have the following using an infinite initial box in 2D.
This is certainly impossible with any method that is not set-based.
julia> f(x, y) = SVector(x^2 + y^2 - 1, y - x)
f (generic function with 1 method)
julia> f(X) = f(X...)
f (generic function with 2 methods)
julia> rts = roots(f, IntervalBox(-∞..∞, 2))
2-element Array{IntervalRootFinding.Root{IntervalArithmetic.IntervalBox{2,Float64}},1}:
Root([0.707106, 0.707107] × [0.707106, 0.707107], :unique)
Root([-0.707107, -0.707106] × [-0.707107, -0.707106], :unique)