Julia JuMP 确保非线性 objective 函数具有正确的函数签名以便自动微分正常工作?

Julia JuMP making sure nonlinear objective function has correct function signatures so that autodifferentiate works properly?

所以我写了一个最简单的例子来展示我想做什么。基本上我想解决一个具有多个变量的优化问题。当我尝试在 JuMP 中执行此操作时,我遇到了函数 obj 无法获取 forwardDiff 对象的问题。

我看了这里:它似乎与函数签名有关 : 。我在我的 obj 函数中这样做了,为了保险起见,我的子函数中也这样做了,但我仍然得到错误

 LoadError: MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag{JuMP.var"#110#112"{typeof(my_fun)},Float64},Float64,2})
Closest candidates are:
  Float64(::Real, ::RoundingMode) where T<:AbstractFloat at rounding.jl:200
  Float64(::T) where T<:Number at boot.jl:715
  Float64(::Int8) at float.jl:60

这还是不行。我觉得我的大部分代码都是正确的,只是发生了一些奇怪的事情,我必须清理一下,以便自动区分工作...

有什么建议吗?

using JuMP
using Ipopt
using LinearAlgebra

function obj(x::Array{<:Real,1})
    println(x)
    x1 = x[1]
    x2 = x[2]
    eye= Matrix{Float64}(I, 4, 4)
    obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
   println(obj_val)
   return obj_val
end

function mat_fun(var::T) where {T<:Real}
    eye= Matrix{Float64}(I, 2, 2)
    eye[2,2]=var
    return eye

end

m = Model(Ipopt.Optimizer)

my_fun(x...) = obj(collect(x))

@variable(m, 0<=x[1:2]<=2.0*pi)
register(m, :my_fun, 2, my_fun; autodiff = true)
@NLobjective(m, Min, my_fun(x...))

optimize!(m)

# retrieve the objective value, corresponding x values and the status
println(JuMP.value.(x))
println(JuMP.objective_value(m))
println(JuMP.termination_status(m))

我发现了问题: 在我的 mat_fun 中,return 的类型必须是“真实的”才能传播。在它是 Float64 之前,这与我猜想所有类型都必须是带有自动微分的 Real 的事实不一致。尽管 Float64 显然是 Real,但看起来继承并未保留,即您必须确保 returned 和输入的所有内容都是 Real 类型。

using JuMP
using Ipopt
using LinearAlgebra

function obj(x::AbstractVector{T}) where {T<:Real}
    println(x)
    x1 = x[1]
    x2 = x[2]
    eye= Matrix{Float64}(I, 4, 4)
    obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
   #println(obj_val)
   return obj_val
end

function mat_fun(var::T) where {T<:Real}
    eye= zeros(Real,(2,2))
    eye[2,2]=var
    return eye

end

m = Model(Ipopt.Optimizer)

my_fun(x...) = obj(collect(x))

@variable(m, 0<=x[1:2]<=2.0*pi)
register(m, :my_fun, 2, my_fun; autodiff = true)
@NLobjective(m, Min, my_fun(x...))

optimize!(m)

# retrieve the objective value, corresponding x values and the status
println(JuMP.value.(x))
println(JuMP.objective_value(m))
println(JuMP.termination_status(m))

改用

function obj(x::Vector{T}) where {T}
    println(x)
    x1 = x[1]
    x2 = x[2]
    eye= Matrix{T}(I, 4, 4)
    obj_val = tr(eye-kron(mat_fun(x1),mat_fun(x2)))
   println(obj_val)
   return obj_val
end

function mat_fun(var::T) where {T}
    eye= Matrix{T}(I, 2, 2)
    eye[2,2]=var
    return eye
end

基本上,在您看到 Float64 的任何地方,将其替换为传入参数中的类型。