Calling local variables from Julia functions (optimize)

Viewed 63

I am dealing with a nested optimization problem in Julia 1.7.3. In particular, I need to optimize a function (say f1) that, in turn, depends on the optimization result of another function (say f2). Here is a minimal example to illustrate my problem

using Optim

function f2(x::Float64, y::Float64) 
    return (x^2 - x - y)^2
end

function f1(y::Float64) 
    x₁ = optimize(x -> f2(x,y), -10, 10).minimizer
    return (y*x₁ - 0.5)^2
end

To get the optimizer of f1, I do

y₁ = optimize(y -> f1(y), -10, 10).minimizer

To get the optimizer of f2, I do

x₁ = optimize(x -> f2(x,y₁), -10, 10).minimizer

However, this last step seems very inefficient because it requires an extra optimization call. The optimizer of f2 is indeed already computed while optimizing f1 (i.e., x₁). Is there a way to retrieve x₁ without an extra optimization step (e.g., saving x₁ during the last iteration step of f1)?

Note: one option is to merge the two optimization problems and simultaneously optimize the objective function with respect to x and y. However, I cannot follow this approach in the actual application I am dealing with.

1 Answers

You may store x₁ in a mutable struct, e.g.

using Optim

mutable struct Minimizer{T}
    x::T
    y::T
end

function f2(x::Float64, y::Float64)
    return (x^2 - x - y)^2
end

function f1!(m::Minimizer, y::Float64)
    x₁ = optimize(x -> f2(x,y), -10, 10).minimizer
    m.x = x₁
    return (y*x₁ - 0.5)^2
end

M = Minimizer(NaN, NaN)
M.y = optimize(y -> f1!(M, y), -10, 10).minimizer
@show M
# M = Minimizer{Float64}(1.2971565074975993, 0.3854585027525779)

Related