首页 > 解决方案 > Juniper 使用 Ipopt 和 Cbc 对 MINLP 进行优化,约束包括最大和最小错误:LoadError: AssertionError: length(x) == d.len

问题描述

我已经使用 Juniper 解决了 MINLP 问题,该问题模仿了使用 Ipopt 和 Cbc 进行数据中心分配的设施位置问题,并注册了一个评估最大值的函数,如下所示

f(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = maximum(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)

optimizer = Juniper.Optimizer nl_solver= optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0) mip_solver = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0) model = Model(optimizer_with_attributes(optimizer, "nl_solver"=>nl_solver, "mip_solver"=>mip_solver, "registered_functions" => [
                Juniper.register(:f, 10, f; autodiff=true)
            ]))

JuMP.register(model,:f, 10, f; autodiff=true)

这里的决策变量是 allocation[i,j],它是一个二进制矩阵,指示j个客户分支是否将与i个数据仓库相关联。我们的约束是:

  1. 限制客户由一个数据中心提供服务
  2. 我们只会建3个数据中心
  3. 我们对与距离相关的客户分支机构有最低延迟要求

运行优化后,我们在运行该方法时收到以下错误optimize!

ERROR: LoadError: AssertionError: length(x) == d.len Stacktrace: [1] eval_objective(::JuMP._UserFunctionEvaluator, ::SubArray{Float64,1,Array{Float64,1},Tuple{UnitRange{Int64}},true}) at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\nlp.jl:1168 [2] eval_and_check_return_type(::Function, ::Type{T} where T, ::JuMP._UserFunctionEvaluator, ::Vararg{Any,N} where N) at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\_Derivatives\forward.jl:5 [3] forward_eval(::Array{Float64,1}, ::Array{Float64,1}, ::Array{JuMP._Derivatives.NodeData,1}, ::SparseArrays.SparseMatrixCSC{Bool,Int64}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::JuMP._Derivatives.UserOperatorRegistry) at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\_Derivatives\forward.jl:163 [4] _forward_eval_all(::NLPEvaluator, ::Array{Float64,1}) at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\nlp.jl:503 [5] macro expansion at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\nlp.jl:571 [inlined] [6] macro expansion at .\timing.jl:233 [inlined] [7] eval_constraint(::NLPEvaluator, ::SubArray{Float64,1,Array{Float64,1},Tuple{UnitRange{Int64}},true}, ::Array{Float64,1}) at C:\Users\oswel\.julia\packages\JuMP\qhoVb\src\nlp.jl:569 [8] eval_constraint(::Ipopt.Optimizer, ::Array{Float64,1}, ::Array{Float64,1}) at C:\Users\oswel\.julia\packages\Ipopt\P1XLY\src\MOI_wrapper.jl:1113 [9] (::Ipopt.var"#eval_g_cb#48"{Ipopt.Optimizer})(::Array{Float64,1}, ::Array{Float64,1}) at C:\Users\oswel\.julia\packages\Ipopt\P1XLY\src\MOI_wrapper.jl:1305 [10] eval_g_wrapper(::Int32, ::Ptr{Float64}, ::Int32, ::Int32, ::Ptr{Float64}, ::Ptr{Nothing}) at C:\Users\oswel\.julia\packages\Ipopt\P1XLY\src\Ipopt.jl:202 [11] solveProblem(::IpoptProblem) at C:\Users\oswel\.julia\packages\Ipopt\P1XLY\src\Ipopt.jl:513 [12] optimize!(::Ipopt.Optimizer) at C:\Users\oswel\.julia\packages\Ipopt\P1XLY\src\MOI_wrapper.jl:1441

我们不知道为什么会发生这种情况或如何解决它。

我们的代码如下所示:

f(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) = maximum(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)

optimizer = Juniper.Optimizer
nl_solver= optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0)
mip_solver = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
model = Model(optimizer_with_attributes(optimizer, "nl_solver"=>nl_solver, "mip_solver"=>mip_solver, "registered_functions" => [
                Juniper.register(:f, 10, f; autodiff=true)
            ]))

JuMP.register(model,:f, 10, f; autodiff=true)


###################################
# variables

dist_to_branches = rand(1:400, (5,10))
Latency_branches = rand(1:80, (1,10))                                           # branches latency requirements                     (10x1)
distance_to_latency = 0.1


@variable(model, allocation[1:5,1:10], Bin )    # allocation of each branch to a certain datacenter

################################
# Constraints

# maximum each data center serves 6 locations
for i in 1:5
    @constraint(model, sum(allocation[i,j] for j in 1:10) <= 6)
end

# each branch is served by only one data center
for j in 1:10
    @constraint(model, sum(allocation[i,j] for i in 1:5) == 1)
end

# only 3 datacenters can be built

@NLconstraint(model, sum( f( allocation[i,1] , allocation[i,2] , allocation[i,3] , allocation[i,4] , allocation[i,5] , allocation[i,6] , allocation[i,8] , allocation[i,9] , allocation[i,10]) for i in 1:5) == 3 )


# constraint for latency
for j in 1:10
    @constraint(model, distance_to_latency * sum(allocation[i,j] * dist_to_branches[i,j] for i in 1:5) <=  Latency_branches[j])
end

######################
# objective


@objective(model, Min, sum( sum(allocation[i,j] * dist_to_branches[i,j] for i in 1:5) for j in 1:10))
optimize!(model)

标签: julianonlinear-optimization

解决方案


如果要maximum在优化模型中使用,则需要引入代理变量并使模型线性化。

假设您有:

m=Model(Cbc.Optimizer)
@variable(m, 4 <= x <= 10)
@variable(m, 3 <= y <= 12)

你现在不写:

@objective(m, Min, max(x,y))

而不是你引入一个代理变量:

@variable(m, z)
@constraint(m, z >= x)
@constraint(m, z >= y)
@objective(m, Min, z)

通过这种方式,您最终得到了一个线性模型(并且,在您的情况下,您甚至不需要瞻博网络)


推荐阅读