# Query status of the solution when using Roots

**URL:** <https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328>\
**Category:** Numerics\
**Tags:** question, optimization, roots, numerics\
**Created:** [November 17, 2020, 8:49pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328 "2020-11-17T20:49:04Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![optimist](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/optimist/32/14797_2.png) [@optimist](https://discourse.julialang.org/u/optimist)\
**Post date:** [November 17, 2020, 8:49pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328/1 "2020-11-17T20:49:05Z")

</div>

**Edited to make it more specific**  
I would like to query status of the solution when using the Roots package, before the function returns an answer. I can see in the source code of “find\_zero.jl” that it has some functionality `state.convergence_failed = true` and also a function `assess_convergence(method::Any, state::UnivariateZeroState{T,S}, options) where {T,S}` , but there is no documentation on how to use it. I have given a MWE and my attempts at resolving it below.

My questions is:  
_ **How to query the status of the solution before it returns a value? e.g. I would like to use the Schroder method first, and if it fails to converge then it should switch to Halley method. If the roots are complex or the algorithm fails to converge then it should return NaN.** _

```julia
using Roots
function root_func(c;guess=0.01,max_evals=100)
    t = collect(0:length(c)-1)
    f(x) = sum(@views c[i]/(1+x)^t[i] for i in 1:length(c))
    #find derivatives of f(x)
    df(x) = sum(@views -t[i]*c[i]/(1+x)^(t[i]+1) for i in 1:length(c))
    ddf(x) = sum(@views (t[i]^2+t[i])*c[i]/(1+x)^(t[i]+2) for i in 1:length(c))
    return find_zero((f,df,ddf),guess,Roots.Schroder();maxevals=max_evals)
end

```

_Example usage:_  
`root_func([-100,10,100,1,1]`

My attempts at checking status of the solution before switching methods or returning a value are given here:

```julia
using Roots
function root_func(c;guess=0.01,max_evals=100)
    t = collect(0:length(c)-1)
    f(x) = sum(@views c[i]/(1+x)^t[i] for i in 1:length(c))
    #find derivatives of f(x)
    df(x) = sum(@views -t[i]*c[i]/(1+x)^(t[i]+1) for i in 1:length(c))
    ddf(x) = sum(@views (t[i]^2+t[i])*c[i]/(1+x)^(t[i]+2) for i in 1:length(c))
    r = find_zero((f,df,ddf),guess,Roots.Schroder();maxevals=max_evals)
    if r.convergence_failed = false
       return r
    end
    r = find_zero((f,df,ddf),guess,Roots.Halley();maxevals=max_evals)
    if r.convergence_failed = false
       return r
     else return NaN
   end
end

```

---

<div class="post-metadata">

**Author:** ![j\_verzani](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j_verzani/32/8551_2.png) [@j\_verzani](https://discourse.julialang.org/u/j_verzani)\
**Post date:** [November 18, 2020, 2:26pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328/2 "2020-11-18T14:26:35Z")

</div>

The part of the code to modify would be the method here [https://github.com/JuliaMath/Roots.jl/blob/master/src/find\_zero.jl#L796](https://github.com/JuliaMath/Roots.jl/blob/master/src/find_zero.jl#L796) which implements an algorithm that checks if a bracket has occurred in which case the method is switched. For your interest, you would call `update_state`, check the conditions you wanted and if you want to switch, you would switch the method, update the `state` and continue with `update_state` until convergence or failure to converge. One caveat, I forget how much support there is for complex zeros, if I recall correctly that is limited to a few methods.

---

<div class="post-metadata">

**Author:** ![optimist](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/optimist/32/14797_2.png) [@optimist](https://discourse.julialang.org/u/optimist)\
**Post date:** [November 18, 2020, 4:07pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328/3 "2020-11-18T16:07:47Z")

</div>

Thanks. Do I necessarily have to modify the source code of “find\_zero.jl” for this? This is difficult for me as I am new to Julia.

All I want from my function is to switch from Schroder to Halley when it fails to converge rather than returning an error. And if Halley’s method also fails to converge than it should just return NaN rather than an error message.

---

<div class="post-metadata">

**Author:** ![j\_verzani](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/j_verzani/32/8551_2.png) [@j\_verzani](https://discourse.julialang.org/u/j_verzani)\
**Post date:** [November 18, 2020, 6:28pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328/4 "2020-11-18T18:28:22Z")

</div>

This could be done along these lines (using a internal form of `find_zero` which returns NaN instead of an error):

```julia
using Roots
using ForwardDiff
D(f) = x -> ForwardDiff.derivative(f, float(x))

f(x) = (x^2+1)*(x-1)*(x-2)
a = 1.5

F = Roots.callable_function((f, D(f), D(D(f))))
M = Roots.Schroder()
state = Roots.init_state(M, F, a)
options = Roots.init_options(M, state)

val = find_zero(M, F, options, state)

if isnan(val)
    M = Roots.Halley()
    state = Roots.init_state(M, F, a)
    val = find_zero(M, F, options, state)
end

val

```

In this case, I’m not sure what functions will not satisfy Schroder, but will satisfy Halley, but presumably you know of one or two.

---

<div class="post-metadata">

**Author:** ![optimist](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/optimist/32/14797_2.png) [@optimist](https://discourse.julialang.org/u/optimist)\
**Post date:** [November 18, 2020, 7:08pm UTC](https://discourse.julialang.org/t/query-status-of-the-solution-when-using-roots/50328/5 "2020-11-18T19:08:51Z")

</div>

Thank you! This solves my problem.

> [@j\_verzani](#):
>
> I’m not sure what functions will not satisfy Schroder, but will satisfy Halley

Schroder’s method fails for `root_func([10,10]` but Halley’s method would work using the code in the original post, though I am not sure if this a good example

> [@optimist](#):
>
> ```julia
> function root_func(c;guess=0.01,max_evals=100)
> t = collect(0:length(c)-1)
> f(x) = sum(@views c[i]/(1+x)^t[i] for i in 1:length(c))
> #find derivatives of f(x)
> df(x) = sum(@views -t[i]*c[i]/(1+x)^(t[i]+1) for i in 1:length(c))
> ddf(x) = sum(@views (t[i]^2+t[i])*c[i]/(1+x)^(t[i]+2) for i in 1:length(c))
> return find_zero((f,df,ddf),guess,Roots.Schroder();maxevals=max_evals)
> end
> 
> ```
