我已经使用 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个数据仓库相关联。我们的约束是:
- 限制客户由一个数据中心提供服务
- 我们只会建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)