julia - 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个数据仓库相关联。我们的约束是:
- 限制客户由一个数据中心提供服务
- 我们只会建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)
解决方案
如果要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)
通过这种方式,您最终得到了一个线性模型(并且,在您的情况下,您甚至不需要瞻博网络)
推荐阅读
- reactjs - React-Select Async loadOptions - 获取失败数据
- kubernetes - 我在 kubernetes 服务 yaml 上收到错误消息“map”,预期为“string”
- db2 - 使用弱类型游标变量返回结果集
- android - 向用户显示firebase存储项目url是否可以?
- spring - Spring boot:实例化Spring java配置类
- jquery - 在汉堡菜单上单击太快会反转 fadeToggle 效果
- python-3.x - 如何在 python 中使用 Simple ITK 仅更改 Dicom 文件的数组
- javascript - JS HTTP 发布 YAML
- excel - 如何索引匹配唯一值?
- javascript - 如何为可溢出的 div 中始终可见的 thead 和 tbody 添加边框