How to return additional arguments when optimizing or finding a root

Hi All,
I am looking for some ideas about how others have often handled this issue. Often, I have to solve an optimization problem and then pass out return some additional arguments. In the MWE example below, y is the component to minimized. But I would also like to make a, b, c available outside of the function. How have you folks typically handled this.

using Optim
function test(x)
    x = x[]
    a = 1
    b = 2
    c = 3
    y = x^2 - 4
    #return y^2, a, b, c
    return y^2
end

optimize(x -> test(x), [0.5]).minimizer

Edit: was using "pass out arguments" which turned out to be confusing, now using the more accurate "return".

If your are passing an anonymous function already, why not use:

using Optim
function test(x)
    x = x[]
    a = 1
    b = 2
    c = 3
    y = x^2 - 4
    return y^2, a, b, c
    #return y^2
end

optimize(x -> test(x)[1], [0.5]).minimizer

Also note that x -> foo(x) can always just be written as foo.

1 Like

If you have a function test(x,a,b,c), then just do:

optimize(x -> test(x,a,b,c), [0.5]).minimizer

(This is “capturing” the values a,b,c in the closure x -> ... via lexical scoping.)

Or maybe I’m misunderstanding you. Do you want to pass a,b,c into test, or do you want to return them out of test (e.g. at the location of the optimum x)? As @abraemer says, one option for the latter is just to return additional values and then discard them during optimization; then, after optimization, you can call your function again with the optimum x and get the additional return values.

1 Like

Thanks @stevengj. Using “pass out” was indeed confusing. I meant
return.

Thanks this works too! For posterity here is an approach I have used previously.

using Optim
function test(x; run = "solve")
    x = x[]
    a = 1
    b = 2
    c = 3
    y = x^2 - 4
    return run == "solve" ?  y^2 : (y^2, a, b, c)
end

# Finding the solution run.
x = optimize(x -> test(x), [0.5]).minimizer

# the simulation run to return additional arguments. note that this simply MWE.
test(x; run = "simulate")

I would recommend against this because it is type-unstable and will slow things down considerably. Just returning extra values and discarding them at the call site should be efficient.

Thanks for the tip!