mirror of
https://github.com/ANL-CEEESA/MIPLearn.jl.git
synced 2025-12-06 16:38:51 -06:00
Implement lazy callbacks
This commit is contained in:
@@ -9,6 +9,8 @@ using MathOptInterface
|
||||
using TimerOutputs
|
||||
const MOI = MathOptInterface
|
||||
|
||||
import JuMP: value
|
||||
|
||||
mutable struct JuMPSolverData
|
||||
optimizer_factory::Any
|
||||
varname_to_var::Dict{String,VariableRef}
|
||||
@@ -19,6 +21,7 @@ mutable struct JuMPSolverData
|
||||
solution::Dict{JuMP.VariableRef,Float64}
|
||||
reduced_costs::Vector{Float64}
|
||||
dual_values::Dict{JuMP.ConstraintRef,Float64}
|
||||
cb_data::Any
|
||||
end
|
||||
|
||||
|
||||
@@ -175,10 +178,25 @@ function remove_constraints(data::JuMPSolverData, names::Vector{String})::Nothin
|
||||
end
|
||||
|
||||
|
||||
function solve(data::JuMPSolverData; tee::Bool = false, iteration_cb = nothing)
|
||||
function solve(
|
||||
data::JuMPSolverData;
|
||||
tee::Bool = false,
|
||||
iteration_cb = nothing,
|
||||
lazy_cb = nothing,
|
||||
)
|
||||
model = data.model
|
||||
wallclock_time = 0
|
||||
log = ""
|
||||
|
||||
if lazy_cb !== nothing
|
||||
function lazy_cb_wrapper(cb_data)
|
||||
data.cb_data = cb_data
|
||||
lazy_cb(nothing, nothing)
|
||||
data.cb_data = nothing
|
||||
end
|
||||
MOI.set(model, MOI.LazyConstraintCallback(), lazy_cb_wrapper)
|
||||
end
|
||||
|
||||
while true
|
||||
wallclock_time += @elapsed begin
|
||||
log *= _optimize_and_capture_output!(model, tee = tee)
|
||||
@@ -189,6 +207,7 @@ function solve(data::JuMPSolverData; tee::Bool = false, iteration_cb = nothing)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if is_infeasible(data)
|
||||
data.solution = Dict()
|
||||
primal_bound = nothing
|
||||
@@ -452,6 +471,7 @@ function __init_JuMPSolver__()
|
||||
Dict(), # solution
|
||||
[], # reduced_costs
|
||||
Dict(), # dual_values
|
||||
nothing, # cb_data
|
||||
)
|
||||
end
|
||||
|
||||
@@ -555,12 +575,27 @@ function __init_JuMPSolver__()
|
||||
iteration_cb = nothing,
|
||||
lazy_cb = nothing,
|
||||
user_cut_cb = nothing,
|
||||
) = solve(self.data, tee = tee, iteration_cb = iteration_cb)
|
||||
) = solve(self.data, tee = tee, iteration_cb = iteration_cb, lazy_cb = lazy_cb)
|
||||
|
||||
solve_lp(self; tee = false) = solve_lp(self.data, tee = tee)
|
||||
end
|
||||
copy!(JuMPSolver, Class)
|
||||
end
|
||||
|
||||
function value(solver::JuMPSolverData, var::VariableRef)
|
||||
if solver.cb_data !== nothing
|
||||
return JuMP.callback_value(solver.cb_data, var)
|
||||
else
|
||||
return JuMP.value(var)
|
||||
end
|
||||
end
|
||||
|
||||
export JuMPSolver
|
||||
function submit(solver::JuMPSolverData, con::AbstractConstraint, name::String = "")
|
||||
if solver.cb_data !== nothing
|
||||
MOI.submit(solver.model, MOI.LazyConstraint(solver.cb_data), con)
|
||||
else
|
||||
JuMP.add_constraint(solver.model, con, name)
|
||||
end
|
||||
end
|
||||
|
||||
export JuMPSolver, submit
|
||||
|
||||
@@ -53,6 +53,13 @@ function set_category!(c::ConstraintRef, category::String)::Nothing
|
||||
return
|
||||
end
|
||||
|
||||
function set_lazy_callback!(model::Model, find_cb::Function, enforce_cb::Function)::Nothing
|
||||
ext = init_miplearn_ext(model)
|
||||
ext["lazy_find_cb"] = find_cb
|
||||
ext["lazy_enforce_cb"] = enforce_cb
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
macro feature(obj, features)
|
||||
quote
|
||||
@@ -67,6 +74,12 @@ macro category(obj, category)
|
||||
end
|
||||
end
|
||||
|
||||
macro lazycb(obj, find_cb, enforce_cb)
|
||||
quote
|
||||
set_lazy_callback!($(esc(obj)), $(esc(find_cb)), $(esc(enforce_cb)))
|
||||
end
|
||||
end
|
||||
|
||||
function _get_and_check_name(obj)
|
||||
n = name(obj)
|
||||
length(n) > 0 || error(
|
||||
@@ -77,4 +90,4 @@ function _get_and_check_name(obj)
|
||||
end
|
||||
|
||||
|
||||
export @feature, @category
|
||||
export @feature, @category, @lazycb
|
||||
|
||||
Reference in New Issue
Block a user