问题描述
在 Gurobi 和 JuMP 0.21 中,有关如何通过回调访问变量的详细记录here:
using JuMP,Gurobi,Test
model = direct_model(Gurobi.Optimizer())
@variable(model,0 <= x <= 2.5,Int)
@variable(model,0 <= y <= 2.5,Int)
@objective(model,Max,y)
cb_calls = Cint[]
function my_callback_function(cb_data,cb_where::Cint)
# You can reference variables outside the function as normal
push!(cb_calls,cb_where)
# You can select where the callback is run
if cb_where != GRB_CB_MIPSOL && cb_where != GRB_CB_MIPNODE
return
end
# You can query a callback attribute using GRBcbget
if cb_where == GRB_CB_MIPNODE
resultP = Ref{Cint}()
GRBcbget(cb_data,cb_where,GRB_CB_MIPNODE_STATUS,resultP)
if resultP[] != GRB_OPTIMAL
return # Solution is something other than optimal.
end
end
# Before querying `callback_value`,you must call:
Gurobi.load_callback_variable_primal(cb_data,cb_where)
x_val = callback_value(cb_data,x)
y_val = callback_value(cb_data,y)
# You can submit solver-independent MathOptInterface attributes such as
# lazy constraints,user-cuts,and heuristic solutions.
if y_val - x_val > 1 + 1e-6
con = @build_constraint(y - x <= 1)
MOI.submit(model,MOI.LazyConstraint(cb_data),con)
elseif y_val + x_val > 3 + 1e-6
con = @build_constraint(y + x <= 3)
MOI.submit(model,con)
end
if rand() < 0.1
# You can terminate the callback as follows:
GRBterminate(backend(model))
end
return
end
# You _must_ set this parameter if using lazy constraints.
MOI.set(model,MOI.RawParameter("LazyConstraints"),1)
MOI.set(model,Gurobi.CallbackFunction(),my_callback_function)
optimize!(model)
@test termination_status(model) == MOI.OPTIMAL
@test primal_status(model) == MOI.FEASIBLE_POINT
@test value(x) == 1
@test value(y) == 2
即,您将使用 x_val = callback_value(cb_data,x)
。但是,当您有一个特定索引不是从 1 开始的变量数组时,您应该怎么做,即我的变量不在向量中,但由于以下原因声明:
@variable(m,x[i=1:n,j=i+1:n],Bin)
我是否应该在 x
的两个维度上使用双循环访问 callback_value
并多次调用 j
?如果是这样,row_number()
的索引将不相同,不是吗?
解决方法
使用广播:
x_val = callback_value.(Ref(cb_data),x)
或者在需要该值时调用 callback_value(cb_data,x[i,j])
。
例如:
using JuMP,Gurobi
model = Model(Gurobi.Optimizer)
@variable(model,0 <= x[i=1:3,j=i+1:3] <= 2.5,Int)
function my_callback_function(cb_data)
x_val = callback_value.(Ref(cb_data),x)
display(x_val)
for i=1:3,j=i+1:3
con = @build_constraint(x[i,j] <= floor(Int,x_val[i,j]))
MOI.submit(model,MOI.LazyConstraint(cb_data),con)
end
end
MOI.set(model,MOI.LazyConstraintCallback(),my_callback_function)
optimize!(model)
收益
julia> optimize!(model)
Gurobi Optimizer version 9.1.0 build v9.1.0rc0 (mac64)
Thread count: 4 physical cores,8 logical processors,using up to 8 threads
Optimize a model with 0 rows,3 columns and 0 nonzeros
Model fingerprint: 0x5d543c3a
Variable types: 0 continuous,3 integer (0 binary)
Coefficient statistics:
Matrix range [0e+00,0e+00]
Objective range [0e+00,0e+00]
Bounds range [2e+00,2e+00]
RHS range [0e+00,0e+00]
JuMP.Containers.SparseAxisArray{Float64,2,Tuple{Int64,Int64}} with 3 entries:
[1,2] = -0.0
[2,3] = -0.0
[1,3] = -0.0
JuMP.Containers.SparseAxisArray{Float64,2] = 2.0
[2,3] = 2.0
[1,3] = 2.0
JuMP.Containers.SparseAxisArray{Float64,3] = -0.0
Presolve time: 0.00s
Presolved: 0 rows,3 columns,0 nonzeros
Variable types: 0 continuous,3 integer (0 binary)
JuMP.Containers.SparseAxisArray{Float64,3] = -0.0
Found heuristic solution: objective 0.0000000
Explored 0 nodes (0 simplex iterations) in 0.14 seconds
Thread count was 8 (of 8 available processors)
Solution count 1: 0
Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00,best bound 0.000000000000e+00,gap 0.0000%
User-callback calls 31,time in user-callback 0.14 sec