# Help with \`try\`ing different algorithms for root solving

**URL:** <https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832>\
**Category:** General Usage\
**Tags:** question, roots\
**Created:** [November 3, 2021, 12:14am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832 "2021-11-03T00:14:41Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:14am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/1 "2021-11-03T00:14:41Z")

</div>

I am trying to program a function that tries different root-finding algorithms depending on whether they succeed or not. How can I accomplish that? I programmed a prototype below, but it does not seem to work:

```julia
using Roots

algos = (Roots.Order0(), Roots.Order1())

function solveroots(f::F, init, algos) where F
    for alg in algos
        println("trying algorithm $alg")
        try
            root = Roots.find_zero(f, init, alg)
        catch
            @warn "Algorithm $alg errored, continue with another one"
        end
    end
    return root
end

f(x) = x^5 - x + 1/2

```

but this errors:

```julia
julia> solveroots(f, algos, 0.1)
trying algorithm Order0()
trying algorithm Secant()
ERROR: UndefVarError: root not defined

```

How can I get this done?

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:21am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/2 "2021-11-03T00:21:11Z")

</div>

This seems to work, I think there was a problem with the scope of the `for` loop.

```julia
function solveroots(f::F, init, algos) where F
    for alg in algos
        println("trying algorithm $alg")
        root = try
            Roots.find_zero(f, init, alg)
        catch
            @warn "Algorithm $alg errored, continue with another one"
        end
        return root
    end
end

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [November 3, 2021, 12:22am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/3 "2021-11-03T00:22:34Z")

</div>

You’re returning after the first iteration, whatever happened, is this what you want? But you’re right that the problem was the scope of `root`

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:23am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/4 "2021-11-03T00:23:22Z")

</div>

I want to return the result of the first algorithm that succeeds. How can I do that?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [November 3, 2021, 12:37am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/5 "2021-11-03T00:37:13Z")

</div>

Define `root` outside of the `for` loop to a guard value (e.g. `nothing`), assign the value of the `try` block to `root` (note that `@warn` returns `nothing`), if `root` is not `nothing` break out of the loop, return `root` at the end whatever it is (may be `nothing` if there are no working algorithms)

```julia
julia> function solveroots(f, init, algos)
           root = nothing
           for alg in algos
               println("trying algorithm $alg")
               root = try
                   Roots.find_zero(f, init, alg)
               catch
                   @warn "Algorithm $alg errored, continue with another one"
               end
               isnothing(root) || break
           end
           return root
       end
solveroots (generic function with 1 method)

julia> solveroots(f, 0.1, algos)
trying algorithm Order0()
0.5506065793341349

```

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:40am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/6 "2021-11-03T00:40:05Z")

</div>

Thank you! are there any concerns with performance because `root` will change from `nothing` to a `Float64` or inside the `for` loop using `try`-`catch`?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [November 3, 2021, 12:41am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/7 "2021-11-03T00:41:01Z")

</div>

The `try` block is concerning performance-wise to start with 🙂 And yes, the fact that `root` is changing value affects performance, but what would you like to do otherwise?

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:43am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/8 "2021-11-03T00:43:49Z")

</div>

Just wondering if there is a better way to do the same thing, ie try different algorithms and return the first one that works. If the problem was say in `Optim` I can use the returned `struct` to check for convergence, for example; but here `find_root` returns a float or throws an error and I am not familiar with handling errors.

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 12:52am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/9 "2021-11-03T00:52:37Z")

</div>

also, what about this:

```julia
function solveroots(f, init, algos)
    for alg in algos
        println("trying algorithm $alg")
        root = try
        Roots.find_zero(f, init, alg)
        catch
            @warn "Algorithm $alg errored, continue with another one"
        end
        isnothing(root) || return root
    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 3, 2021, 12:57am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/10 "2021-11-03T00:57:36Z")

</div>

Use the `solve` interface, which returns NaN when there is no convergence:

```julia
using Roots, ForwardDiff
f(x) = cbrt(x) * exp(-x^2); x0 = 0.1147
p = ZeroProblem((f, x-> ForwardDiff.derivative(f, x)), x0)
for M ∈ (Roots.LithBoonkkampIJzerman(1,1), Roots.LithBoonkkampIJzerman(2, 1))
       xstar = solve(p, M)
       !isnan(xstar) && return (M, xstar)
end

```

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [November 3, 2021, 1:01am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/11 "2021-11-03T01:01:58Z")

</div>

I’m not familiar with the Roots package, but I was wondering whether there was a way to use a non-throwing function, this looks definitely much better 🙂

---

<div class="post-metadata">

**Author:** ![StevenSiew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevensiew/32/218393_2.png) [@StevenSiew](https://discourse.julialang.org/u/StevenSiew)\
**Post date:** [November 3, 2021, 1:11am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/12 "2021-11-03T01:11:13Z")

</div>

If you want to try several different algo in parallel and only return the first one that succeed. Then use the find treasure parallel algorithmn below.

Proof of concept below

```julia
using Base.Threads
struct WorkDetail
    tid::Int64
    data::Vector{Float64}
end

@show rawdata = rand(10)
NumOfThreads = 4
chunksize = length(rawdata) ÷ NumOfThreads
WorkDetailArray = WorkDetail[]
for t = 1:NumOfThreads
    if t < NumOfThreads
        push!( WorkDetailArray, WorkDetail(t, rawdata[chunksize*(t-1)+1:chunksize*(t)+1-1]) )
    else
        push!( WorkDetailArray, WorkDetail(t, rawdata[chunksize*(t-1)+1:length(rawdata)]) )
    end
end
@show WorkDetailArray

Completed = Bool[false for _ = 1:NumOfThreads]
Accepted = Bool[false for _ = 1:NumOfThreads]
Success = Bool[false for _ = 1:NumOfThreads]

WorkTask(t) = begin
    result = nothing
    for c = 1:length(WorkDetailArray[t].data)
        println("Thread $(t), Working with data = $(WorkDetailArray[t].data[c])")
        sleep((NumOfThreads - t + 1) * rand())
        FoundTreasureBool = rand() < 0.20
        if FoundTreasureBool
            Success[t] = true
            result = WorkDetailArray[t].data[c]
            break
        else
            # We have not found the Treasure
            # now check if others have
            # and stop working if they did
            if any(Success)
                break
            end
        end
    end
    "Signal that this thread has completed"
    Completed[t] = true
    println("Thread $(t) completion has been signaled")
    return result
end

Workers = Task[]
for t = 1:NumOfThreads
    push!(Workers, Threads.@spawn WorkTask(t))
    println("Thread $(t) has been spawned")
end

# while Accepted contains at least one element which is false
treasurefound = false
while ! all(Accepted) && ! treasurefound
    for t = 1:length(Workers)
        if xor(Completed[t],Accepted[t])
            println("Thread $(t) completion has been accepted")
            "Mark that controller has accepted the thread completion"
            Accepted[t] = true
            "Check if the worker is successful in finding the treasure"
            if Success[t]
                treasure = Threads.fetch(Workers[t])
                println("Thread $(t) has found treasure! Its value is ",treasure)
                global treasurefound = true
                break
            else
                Threads.wait(Workers[t])
            end
        end
    end
    sleep(0.05) # Sleep for 50 milisecond
end
# Now wait for any remainging worker
while ! all(Accepted)
    for t = 1:length(Workers)
        if xor(Completed[t],Accepted[t])
            println("Thread $(t) completion has been accepted")
            "Mark that controller has accepted the thread completion"
            Accepted[t] = true
            Threads.wait(Workers[t])
        end
    end
    sleep(0.05) # Sleep for 50 milisecond
end
println("Done")
exit()

```

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 1:17am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/13 "2021-11-03T01:17:10Z")

</div>

I played with the `solve` interface a little, but the documentation on `ZeroProblem` is very terse:  
[https://docs.juliahub.com/Roots/o0Xsi/1.3.5/reference/#Roots.ZeroProblem](https://docs.juliahub.com/Roots/o0Xsi/1.3.5/reference/#Roots.ZeroProblem)

For example, these fail:

```julia
using Roots
using ForwardDiff

f(x) = x^5 - x + 1/2

p1 = ZeroProblem((f, x-> ForwardDiff.derivative(f, x)), 0.1)
p2 = ZeroProblem(f, 0.1)

solve(p1, Order0())
solve(p2, Order0())

```

and I couldn’t figure out why.

---

<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 3, 2021, 1:48am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/14 "2021-11-03T01:48:33Z")

</div>

Yes, Order0 is a special hybrid algorithm which doesn’t fit into that interface. (Maybe it should, if you think so, please open an issue.)

---

<div class="post-metadata">

**Author:** ![amrods](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amrods/32/2543_2.png) [@amrods](https://discourse.julialang.org/u/amrods)\
**Post date:** [November 3, 2021, 1:54am UTC](https://discourse.julialang.org/t/help-with-try-ing-different-algorithms-for-root-solving/70832/15 "2021-11-03T01:54:07Z")

</div>

Done:  
[https://github.com/JuliaMath/Roots.jl/issues/255](https://github.com/JuliaMath/Roots.jl/issues/255)
