Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make solver information, stats available programmatically rather than just printing #169

Open
OminousOmen opened this issue Jan 5, 2020 · 6 comments

Comments

@OminousOmen
Copy link

So first of all, thank you for Roots.jl! This is a feature request to have some way through the public and documented API for the primary functions, e.g., find_zero to have the solver return information about the solution process, such as the reason for termination (e.g., did we stop because of convergence of f or of x?) and the number of steps taken. Perhaps this could be done through a different function name or by supplying a mutable solution data object argument, etc.

@jverzani
Copy link
Member

jverzani commented Jan 5, 2020 via email

@OminousOmen
Copy link
Author

Try setting verbose=true. This gives a summary that I think you want.

Yes, completely agree that is the summary of interest, but the feature requested in this issue is to have a way to access that same information though code rather than only having it be printed to the user. That way, a function which calls the root-finder can make decisions based on this information.

@jverzani
Copy link
Member

jverzani commented Jan 6, 2020

Ohh, I see. It isn't documented, but the details are in the state variable, fed into find_zero(method, F, options, state, l), where l records the tracks. I guess if someone wanted to switch things based on the evaluation they would have to write a find_zero method, along the lines of the one written that switches to a bracketing method if a bracket is found. This isn't so simple to do. Do you have a use case in mind?

@OminousOmen
Copy link
Author

OminousOmen commented Jan 6, 2020

Do you have a use case in mind?

For my purposes, I'd be happy to just have this information returned at the end of the run, so I would know how many function evals were involved and what the reason was for the solver stopping. An illustrative example would be the ODESolution struct in DifferentialEquations.jl, which has, e.g. the destats field. This is why I was suggesting maybe another method name which could return a tuple containing the root value as well as a solution summary struct, or maybe taking an optional solution summary argument in find_zero that the solver could write to.

In my use case, I would be fine without intermediate access to state and l, otherwise I probably would just try to implement my own find_zero method as you suggest.

@jverzani
Copy link
Member

jverzani commented Jan 6, 2020

This can be done without much fuss:

julia> using Roots
[ Info: Precompiling Roots [f2b01f46-fcfa-551c-844a-d8ac1e96c665]

julia> M = Order1()
Roots.Secant()

julia> f(x) = x^5 - x - 1
f (generic function with 1 method)

julia> state = Roots.init_state(M, f, 1.0)
Roots.UnivariateZeroState{Float64,Float64}(1.0, 1.000006055491121, Float64[], -1.0, -0.9999757776688241, Float64[], 0, 2, false, false, false, false, "")

julia> options = Roots.init_options(M, state)
Roots.UnivariateZeroOptions{Float64,Float64,Float64,Float64}(2.220446049250313e-16, 2.220446049250313e-16, 8.881784197001252e-16, 8.881784197001252e-16, 40, 9223372036854775807, false)

julia> find_zero(M, f, options, state)
1.1673039782614187

julia> state
Roots.UnivariateZeroState{Float64,Float64}(1.1673039782614187, 1.1673039782614223, Float64[], 6.661338147750939e-16, 2.9976021664879227e-14, Float64[], 8, 10, false, false, true, false, "")

julia> fieldnames(typeof(state))
(:xn1, :xn0, :m, :fxn1, :fxn0, :fm, :steps, :fnevals, :stopped, :x_converged, :f_converged, :convergence_failed, :message)

A show method for the state object could be arranged to show what you want. (This would be an improvement to the show_trace function.) To keep track of the steps is also possible with a Tracks object. If desired, this could be wrapped up in a function call, e.g.:

function findzero(f, x, M)
   state = Roots.init_state(M, f, 1.0)
   options = Roots.init_options(M, state)
   xstar= find_zero(M, f, options, state)
   (xstar, state)
end

@KronosTheLate
Copy link
Contributor

Is this not possible by using a Tracks? See the documentation proposed in #275. If yes, this issue is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants