Functor usage for Optim.jl

Dear Community,

I got a question about functor usage with Optim.jl.

I’m currently writing a Julian package for biological modeling. To organize parameters of the biological process, I chose function-like object (functor) for development. However, I found functor type is somehow not supported with Optim.jl though it belongs to Any type and works like function.

Here is my sample code of Optim.optimize with the input of functor type. I got MethodError due to using the functor type with Optim.jl.

Is there a reason why functor can not work like a function in this situation?

Code


# Code for finding the minimum of y-function within (0.1,0.2)
using Optim
using Test

struct y
    p
end

function (s::y)(x)
    return x*s.p
end

model = y(1.0)
model2(x;p=1.0) = x*p

@show  model(2.0)
@show  model2(2.0)

@test typeof(y) <: Any # Because Optim.jl accepts :Any object

Optim.optimize(model, 0.1, 0.2); # MethodError
Optim.optimize(model2, 0.1, 0.2); # Pass

REPL result

However, it seems like functor is not supported in Optim.jl

julia> using Optim

julia> using Test

julia> struct y
           p
       end

julia> function (s::y)(x)
           return x*s.p
       end

julia> model = y(1.0)
y(1.0)

julia> model2(x;p=1.0) = x*p
model2 (generic function with 1 method)

julia> @show  model(2.0)
model(2.0) = 2.0
2.0

julia> @show  model2(2.0)
model2(2.0) = 2.0
2.0

julia> @test typeof(y) <: Any # Because Optim.jl accepts :Any object
Test Passed

julia> Optim.optimize(model, 0.1, 0.2);
ERROR: MethodError: no method matching optimize(::y, ::Float64, ::Float64)
Closest candidates are:
  optimize(::Any, ::Number, ::Number, ::AbstractArray{T,N} where N; kwargs...) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:156
  optimize(::Any, ::Number, ::Number, ::AbstractArray{T,N} where N, ::Optim.AbstractConstrainedOptimizer) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:160
  optimize(::Any, ::Number, ::Number, ::AbstractArray{T,N} where N, ::Optim.AbstractConstrainedOptimizer, ::Optim.Options; kwargs...) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:160
  ...
Stacktrace:
 [1] top-level scope at none:1

julia> Optim.optimize(model2, 0.1, 0.2);

julia> 

Thank you for reading this question.

I wonder if this fits your purpose

# using anonymous function
Optim.optimize(x->model(x), 0.1, 0.2)

# or
m = x -> model(x)
Optim.optimize(m, 0.1, 0.2)
2 Likes

It looks like that the multivariate interface does not restrict to Function, but the univariate one does. See

https://github.com/JuliaNLSolvers/Optim.jl/blob/431a5f97f814f9df17b24fe429fcc7b9af3c9577/src/univariate/optimize/interface.jl#L2

I don’t think this is necessary — please check if there is an existing issue and open one if there isn’t. In the meantime, @liuyxpp’s workaround using a closure should help.

2 Likes

Yeah that’s not intended, it should have been removed a long time ago. I’ll remove it. You can you the solution above until I tag a new version. Thanks for bringing this up

2 Likes

This solved my question. The functor type is not supported in univariate analysis of Optim.jl
I’ve extended my functor to multivariate input, and it works with Optim.jl now.
Here is my code:

using Optim

"Model parameter"
struct y
  p
end

"Univariable Functor"
function (s::y)(x)
  return x*s.p
end

"Multivariable Functor with array input"
function (s::y)(x_v)
  return x_v[1]*s.p
end


model = y(1.0)

Optim.optimize(model, -1, 2, [1.]) #PASS
Optim.optimize(model, -1, 2, 1.) #ERROR

REPL output

julia> using Optim

julia> "Model parameter"
       struct y
         p
       end
y

julia> "Univariable Functor"
       function (s::y)(x)
         return x*s.p
       end
y

julia> "Multivariable Functor with array input"
       function (s::y)(x_v)
         return x_v[1]*s.p
       end
y

julia> model = y(1.0);

julia> Optim.optimize(model, -1, 2, [1.]); #PASS

julia> Optim.optimize(model, -1, 2, 1.); #ERROR
ERROR: MethodError: no method matching optimize(::y, ::Int64, ::Int64, ::Float64)
Closest candidates are:
  optimize(::Any, ::Any, ::Number, ::Number, ::AbstractArray{T,N} where N, ::Optim.Options; kwargs...) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:164
  optimize(::Any, ::Number, ::Number, ::AbstractArray{T,N} where N; kwargs...) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:156
  optimize(::Any, ::Number, ::Number, ::AbstractArray{T,N} where N, ::Optim.AbstractConstrainedOptimizer) where T at /Users/stevenchiu/.julia/packages/Optim/TNmSw/src/multivariate/solvers/constrained/fminbox.jl:160
  ...
Stacktrace:
 [1] top-level scope at none:1

julia> 

Thank you! @Tamas_Papp and @liuyxpp

1 Like