Recursive function does not return last value

Hi,
I wrote a custom algorithm to find the root of my equation (I know, there is much better out there, but my function is not differentiable and it s defined decreasing)

Anyway, this is the algorithm. I would like to return the last value of the ‘x’ which is my root. But I cannot!
It returns nothing.
Harnessing with it, I understood that it returns the first value of the first if statement it walks through, but why!? How can I return the last value. I can define a global variable and get it through that, but it is just wrong!

Thanks for help

## Assuming the function is monotonous decrescent
K = 0.
function _find_minimum!(;y0=10., n = 2.,  x::Real=20., ν::Real, model::Function)
    y = -4*x + 5
    # _compute_voltage(;model=ss,ν=ν, Kie=x)
    if abs(y0) > 0.001
        if sign(y0) ==sign(y)
            ## the solution is far ahead!
            x1 = x + sign(y0)*(2^n-1)
            _find_minimum!(y0=y, n=n, ν=ν, x=x1, model=model)
        end
        if sign(y0) != sign(y)
            ## you stepped through the solution, go back!
            x1 = x - sign(y)*(2^n-1)
            _find_minimum!(y0=y, n=n/2., ν=ν, x=x1, model=model)
        end
    else
        ## this works
        global K = x
        return x
    end
end

Incidentaly, you can find univariate solvers in

https://github.com/JuliaNLSolvers/Optim.jl

1 Like

All expressions in Julia have a value. For an if statement, that value is the value of the expression in whatever branch was taken (or nothing if no branch was taken):

julia> a = if 1 == 2
         "hello"
       else
         "world"
       end
"world"

julia> a
"world"

Likewise a function automatically returns the value of its last expression if you don’t have an explicit return:

julia> function foo()
         if 1 == 2
           "hello"
         else
           "world"
         end
       end
foo (generic function with 1 method)

julia> a = foo()
"world"

julia> a
"world"

You just need to do return _find_minimum(...) to ensure that the returned value from the last recursive call is propagated all the way out.

For a much simpler example, here’s a simple recursive function to compute a square root:

julia> function find_sqrt(x, guess)
         y = x / guess
         if y ≈ guess
           return guess
         else
           return find_sqrt(x, 0.5 * (guess + y))
         end
       end
find_sqrt (generic function with 1 method)

julia> find_sqrt(4, 1)
2.000000000000002

julia> find_sqrt(2, 1)
1.4142135623746899

2 Likes

Also note that I could have removed both return statements without changing the behavior of the function, since the function will implicitly return the value of the if block, and the value of that block will be the value of whatever branch was chosen:

julia> function find_sqrt(x, guess)
         y = x / guess
         if y ≈ guess
           guess
         else
           find_sqrt(x, 0.5 * (guess + y))
         end
       end
find_sqrt (generic function with 1 method)

julia> find_sqrt(9, 1)
3.000000001396984
2 Likes

Thanks for the clear explanation, although it is important to signal that the if branches need the else. Indeed, the same algorithm -with the complementary if statement - return nothing


function find_sqrt(x, guess)
         y = x / guess
         if y ≈ guess
           guess
       end
         if !(y ≈ guess)
           find_sqrt(x, 0.5 * (guess + y))
         end
       end