Does Roots.jl provide an API to obtain the trace of a root finding algorithm?

I only find that it can print out such information by the kwargs verbose=true. But how can I obtain this just like the Optim.jl which store all information in the returned value? I want to count the number of evaluations of my function called by each root finding algorithm.

Just increment a counter in your function. (You can use a local variable for the counter via a closure.)

2 Likes

Thanks! But what if I don’t want to modify my funciton (or the function is an external call to the C/C++ funciton?). Do you know any other root finding packages that keeps track of its iteration trace? Besides the number of evaluations, I’d also like to know the x and f(x) during each iteration.

“You can use a local variable for the counter via a closure.” means to do the following. You can use any function including a function which is an external call to the C function.

using Roots

function withcounter(f, n = 0)
    c = Ref(n)
    F(x...; y...) = (c[] += 1; f(x...; y...))
    getcounter() = c[]
    setcounter!(n) = c[] = n
    F, getcounter, setcounter!
end

f(x::Float64)::Float64 = @ccall sin(x::Float64)::Float64
@show f(1.0);
f(1.0) = 0.8414709848078965
F, getcounter, setcounter! = withcounter(x -> f(x) - 0.8414709848078965)
@show find_zero(F, 0.9)
@show getcounter();
find_zero(F, 0.9) = 1.0
getcounter() = 11
setcounter!(0)
@show find_zeros(F, 0, 2π)
@show getcounter();
find_zeros(F, 0, 2π) = [1.0, 2.141592653589793]
getcounter() = 1270
6 Likes

In addition to the suggested ways, the state object keeps track of this. It can be accessed different ways, here is one:

using Roots
Z = ZeroProblem(sin, (3,4))
prob = init(Z, Roots.Secant()); solve!(prob)
prob.state.fnevals # 7
3 Likes

This solution leads me to explore the source code of Roots.jl package. And what I find is the kwargs tracks which is exactly what I want! Thanks all!

To track the number of evaluations and all xs and fs, we just provide a Tracks instance to the kwargs, such as

using Roots
tracks = Roots.Tracks(Float64[], Float64[])
find_zero(sin, (3,4), Roots.FalsePosition(), tracks=tracks, verbose=true)

Then we can show the tracks

Roots.show_tracks(tracks, Roots.FalsePosition())