-
-
Notifications
You must be signed in to change notification settings - Fork 425
Expand file tree
/
Copy pathcallbacks.jl
More file actions
147 lines (119 loc) · 4.59 KB
/
Copy pathcallbacks.jl
File metadata and controls
147 lines (119 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Copyright 2017, Iain Dunning, Joey Huchette, Miles Lubin, and contributors
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
#############################################################################
# JuMP
# An algebraic modeling language for Julia
# See https://github.com/jump-dev/JuMP.jl
#############################################################################
"""
callback_node_status(cb_data, model::GenericModel)
Return an [`MOI.CallbackNodeStatusCode`](@ref) enum, indicating if the current
primal solution available from [`callback_value`](@ref) is integer feasible.
## Example
```julia
julia> import Gurobi
julia> model = Model(Gurobi.Optimizer);
julia> set_silent(model)
julia> @variable(model, x <= 10, Int);
julia> @objective(model, Max, x);
julia> function my_callback_function(cb_data, cb_where)
status = callback_node_status(cb_data, model)
if status == MOI.CALLBACK_NODE_STATUS_INTEGER
println("Status is: ", status)
end
return
end
my_callback_function (generic function with 1 method)
julia> set_attribute(model, Gurobi.CallbackFunction(), my_callback_function)
julia> optimize!(model)
Status is: CALLBACK_NODE_STATUS_INTEGER
```
"""
function callback_node_status(cb_data, model::GenericModel)
# TODO(odow):
# MOI defines `is_set_by_optimize(::CallbackNodeStatus) = true`.
# This causes problems for JuMP because it checks the termination_status to
# see if optimize! has been called. Solutions are:
# 1) defining is_set_by_optimize = false
# 2) adding a flag to JuMP to store whether it is in a callback
# 3) adding IN_OPTIMIZE to termination_status for callbacks
# Once this is resolved, we can replace the current function with:
# MOI.get(model, MOI.CallbackNodeStatus(cb_data))
return MOI.get(backend(model), MOI.CallbackNodeStatus(cb_data))
end
"""
callback_value(cb_data, x::GenericVariableRef)
callback_value(cb_data, x::Union{GenericAffExpr,GenericQuadExpr})
Return the primal solution of `x` inside a callback.
`cb_data` is the argument to the callback function, and the type is dependent on
the solver.
Use [`callback_node_status`](@ref) to check whether a solution is available.
## Example
```julia
julia> import Gurobi
julia> model = Model(Gurobi.Optimizer);
julia> set_silent(model)
julia> @variable(model, x <= 10, Int);
julia> @objective(model, Max, x);
julia> function my_callback_function(cb_data, cb_where)
status = callback_node_status(cb_data, model)
if status == MOI.CALLBACK_NODE_STATUS_INTEGER
Gurobi.load_callback_variable_primal(cb_data, cb_where)
println("Solution is: ", callback_value(cb_data, x))
end
return
end
my_callback_function (generic function with 1 method)
julia> set_attribute(model, Gurobi.CallbackFunction(), my_callback_function)
julia> optimize!(model)
Solution is: 10.0
```
"""
function callback_value(cb_data, x::GenericVariableRef)
# TODO(odow):
# MOI defines `is_set_by_optimize(::CallbackVariablePrimal) = true`.
# This causes problems for JuMP because it checks the termination_status to
# see if optimize! has been called. Solutions are:
# 1) defining is_set_by_optimize = false
# 2) adding a flag to JuMP to store whether it is in a callback
# 3) adding IN_OPTIMIZE to termination_status for callbacks
# Once this is resolved, we can replace the current function with:
# MOI.get(owner_model(x), MOI.CallbackVariablePrimal(cb_data), x)
return MOI.get(
backend(owner_model(x)),
MOI.CallbackVariablePrimal(cb_data),
index(x),
)
end
function callback_value(cb_data, expr::Union{GenericAffExpr,GenericQuadExpr})
return value(expr) do x
return callback_value(cb_data, x)
end
end
function MOI.submit(
model::GenericModel,
cb::MOI.LazyConstraint,
con::ScalarConstraint,
)
f = moi_function(model, con.func)
return MOI.submit(backend(model), cb, f, con.set)
end
function MOI.submit(model::GenericModel, cb::MOI.UserCut, con::ScalarConstraint)
f = moi_function(model, con.func)
return MOI.submit(backend(model), cb, f, con.set)
end
function MOI.submit(
model::GenericModel{T},
cb::MOI.HeuristicSolution,
variables::Vector{GenericVariableRef{T}},
values::Vector{<:Real},
) where {T}
return MOI.submit(
backend(model),
cb,
index.(variables),
convert(Vector{T}, values),
)
end