0
votes

Posted in the Julia Discourse forum

I programmed a saddle-finding function using Optim. It works fairly well, but when I try to use box optimization, it gives me a methods error. What is the problem?

This works:

using Optim

function saddle2(f::Function, initx, inity)
    # function is assumed to be f(xmin, ymax)
    ymax = similar(inity)
    function fx(x)
        optymax = optimize(y -> -f(vcat(x, y)), inity, NelderMead())
        ymax = Optim.minimizer(optymax)
        return -Optim.minimum(optymax)
    end
    optxmin = optimize(fx, repeat([0.0], 6), initx, NelderMead())
    xmin = Optim.minimizer(optxmin)
    return (f(vcat(xmin, ymax)), xmin, ymax)
end

saddle2(Lsaddle, repeat([0.5], 6), repeat([0.5], 12)) # works!

This doesn’t work:

using Optim

function saddle(f::Function, initx, inity)
    # function is assumed to be f(xmin, ymax)
    ymax = similar(inity)
    function fx(x)
        optymax = optimize(y -> -f(vcat(x, y)), repeat([0.0], 12), repeat([Y], 12), inity, Fminbox(NelderMead()))
        ymax = Optim.minimizer(optymax)
        return -Optim.minimum(optymax)
    end
    optxmin = optimize(fx, repeat([0.0], 6), repeat([1.0], 6), initx, Fminbox(NelderMead()))
    xmin = Optim.minimizer(optxmin)
    return (f(vcat(xmin, ymax)), xmin, ymax)
end

saddle(Lsaddle, repeat([0.5], 6), repeat([0.5], 12)) # doesn't work:

MethodError: no method matching optimize(::getfield(Main, Symbol("##3#5")){Array{Float64,1},typeof(Lsaddle)}, ::Array{Float64,1}, ::Array{Int64,1}, ::Array{Float64,1}, ::Fminbox{NelderMead{Optim.AffineSimplexer,Optim.AdaptiveParameters},Float64,getfield(Optim, Symbol("##46#48"))})
Closest candidates are:
  optimize(::Any, ::AbstractArray{T<:AbstractFloat,N} where N, !Matched::AbstractArray{T<:AbstractFloat,N} where N, ::AbstractArray{T<:AbstractFloat,N} where N, ::Fminbox) where T<:AbstractFloat at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:163
  optimize(::Any, ::AbstractArray{T<:AbstractFloat,N} where N, !Matched::AbstractArray{T<:AbstractFloat,N} where N, ::AbstractArray{T<:AbstractFloat,N} where N, ::Fminbox, !Matched::Any; inplace, autodiff) where T<:AbstractFloat at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:163
  optimize(::Any, ::AbstractArray, ::AbstractArray, ::AbstractArray, !Matched::SAMIN) at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/samin.jl:60
  ...

Stacktrace:
 [1] (::getfield(Main, Symbol("#fx#4")){typeof(Lsaddle),Array{Float64,1}})(::Array{Float64,1}) at ./In[9]:5
 [2] finite_difference_gradient! at /Users/amrods/.julia/packages/DiffEqDiffTools/visbP/src/gradients.jl:282 [inlined]
 [3] (::getfield(NLSolversBase, Symbol("#g!#15")){getfield(Main, Symbol("#fx#4")){typeof(Lsaddle),Array{Float64,1}},DiffEqDiffTools.GradientCache{Nothing,Nothing,Nothing,Val{:central},Float64,Val{true}}})(::Array{Float64,1}, ::Array{Float64,1}) at /Users/amrods/.julia/packages/NLSolversBase/KG9Ie/src/objective_types/oncedifferentiable.jl:56
 [4] gradient!!(::OnceDifferentiable{Float64,Array{Float64,1},Array{Float64,1}}, ::Array{Float64,1}) at /Users/amrods/.julia/packages/NLSolversBase/KG9Ie/src/interface.jl:63
 [5] optimize(::OnceDifferentiable{Float64,Array{Float64,1},Array{Float64,1}}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Fminbox{NelderMead{Optim.AffineSimplexer,Optim.AdaptiveParameters},Float64,getfield(Optim, Symbol("##46#48"))}, ::Optim.Options{Float64,Nothing}) at /Users/amrods/.julia/packages/NLSolversBase/KG9Ie/src/interface.jl:51
 [6] #optimize#53 at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:164 [inlined]
 [7] optimize at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:163 [inlined] (repeats 2 times)
 [8] saddle(::typeof(Lsaddle), ::Array{Float64,1}, ::Array{Float64,1}) at ./In[9]:9
 [9] top-level scope at In[13]:1
1

1 Answers

1
votes

The problem is that in your code Y is an Int not Float64. Most probably you have written something like Y = 1 and you should have written Y = 1.0.

If you have no influence how Y is defined then write:

optimize(y -> -f(vcat(x, y)), repeat([0.0], 12), repeat(Float64[Y], 12), inity, Fminbox(NelderMead()))

or

optimize(y -> -f(vcat(x, y)), repeat([0.0], 12), fill(Float64(Y), 12), inity, Fminbox(NelderMead()))

I it would be easier to diagnose the problem if you posted a fully reproducible code.

EDIT

You can trace this problem in the following way. Read the error message:

MethodError: no method matching optimize(::getfield(Main, Symbol("##3#5")){Array{Float64,1},typeof(Lsaddle)}, ::Array{Float64,1}, ::Array{Int64,1}, ::Array{Float64,1}, ::Fminbox{NelderMead{Optim.AffineSimplexer,Optim.AdaptiveParameters},Float64,getfield(Optim, Symbol("##46#48"))})
Closest candidates are:
  optimize(::Any, ::AbstractArray{T<:AbstractFloat,N} where N, !Matched::AbstractArray{T<:AbstractFloat,N} where N, ::AbstractArray{T<:AbstractFloat,N} where N, ::Fminbox) where T<:AbstractFloat at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:163
  optimize(::Any, ::AbstractArray{T<:AbstractFloat,N} where N, !Matched::AbstractArray{T<:AbstractFloat,N} where N, ::AbstractArray{T<:AbstractFloat,N} where N, ::Fminbox, !Matched::Any; inplace, autodiff) where T<:AbstractFloat at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/fminbox.jl:163
  optimize(::Any, ::AbstractArray, ::AbstractArray, ::AbstractArray, !Matched::SAMIN) at /Users/amrods/.julia/packages/Optim/ULNLZ/src/multivariate/solvers/constrained/samin.jl:60
  ...

and you see that you can suspect that optimize for Fminbox accepts only arrays of AbstractFloat. To be sure run:

julia> methodswith(Fminbox, supertypes=true)
[1] summary(F::Fminbox) in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:117
[2] optimize(df::OnceDifferentiable, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:175
[3] optimize(df::OnceDifferentiable, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox, options) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:175
[4] optimize(df::OnceDifferentiable, l::Array{T,N} where N, u::Array{T,N} where N, F::Fminbox{O,T,P} where P where T) where {T<:AbstractFloat, O<:AbstractOptimizer} in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\deprecate.jl:67
[5] optimize(f, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:163
[6] optimize(f, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox, options) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:163
[7] optimize(f, g, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:150
[8] optimize(f, g, l::AbstractArray{T,N} where N, u::AbstractArray{T,N} where N, initial_x::AbstractArray{T,N} where N, F::Fminbox, options) where T<:AbstractFloat in Optim at C:\Users\bogum\.julia\packages\Optim\ULNLZ\src\multivariate\solvers\constrained\fminbox.jl:150

and you are sure that all optimize methods that accept Fminbox require AbstractFloat. In theory such auto-promotion you ask could be possible, but as you can see it is not implemented, so you just have to remember to pass AbstractFloat arguments to optimize.

Julia, by default, does not perform automatic promotion like this. Here is a minimal example:

julia> f(x::Vector{Float64}) = x
f (generic function with 1 method)

julia> f([1,2,3])
ERROR: MethodError: no method matching f(::Array{Int64,1})
Closest candidates are:
  f(::Array{Float64,1}) at REPL[9]:1
Stacktrace:
 [1] top-level scope at none:0